Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 Apr 2009 01:08:58 +0000 (18:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 Apr 2009 01:11:41 +0000 (18:11 -0700)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (120 commits)
  cx231xx: Convert to snd_card_create()
  V4L/DVB (11440): PWC: fix build error when CONFIG_INPUT=m
  V4L/DVB (11439): UVC: uvc_status_cleanup(): undefined reference to `input_unregister_device'
  V4L/DVB (11438): au0828: fix Kconfig dependance
  V4L/DVB (11437): pvrusb2: Drop client_register/unregister stubs
  V4L/DVB (11436): radio-mr800: convert to to v4l2_device
  V4L/DVB (11435): dsbr100 radio: convert to to v4l2_device
  V4L/DVB: zr364xx: remove unused #include <version.h>
  V4L/DVB: usbvision: remove unused #include <version.h>
  V4L/DVB (11427): gspca - m5602: Minor cleanups
  V4L/DVB (11426): gspca - m5602: Don't touch hflip/vflip register on Read/Modify/Write
  V4L/DVB (11425): gspca - m5602: Move the vflip quirk to probe stage.
  V4L/DVB (11424): gspca - m5602-ov9650: Use the local ctrl cache. Adjust image on vflip.
  V4L/DVB (11423): gspca - m5602-ov9650: Add a disconnect hook, setup a ctrl cache ctrl.
  V4L/DVB (11422): gspca - m5602-ov9650: Replace a magic constant with a define
  V4L/DVB (11421): gspca - m5602-ov9650: Synthesize modesetting.
  V4L/DVB (11420): gspca - m5602: Improve error handling in the ov9650 driver
  V4L/DVB (11419): gspca - m5602-ov9650: Don't read exposure data from COM1.
  V4L/DVB (11418): gspca - m5602-ov9650: Auto white balancing is on by default
  V4L/DVB (11417): gspca - m5602-ov9650: Autogain is on by default
  ...

200 files changed:
Documentation/video4linux/pxa_camera.txt [new file with mode: 0644]
Documentation/video4linux/v4l2-framework.txt
MAINTAINERS
arch/arm/mach-mx1/Makefile
arch/arm/mach-mx1/devices.c
arch/arm/mach-mx1/ksym_mx1.c [new file with mode: 0644]
arch/arm/mach-mx1/mx1_camera_fiq.S [new file with mode: 0644]
arch/arm/mach-mx3/clock.c
arch/arm/plat-mxc/include/mach/memory.h
arch/arm/plat-mxc/include/mach/mx1_camera.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/ce6230.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/lgs8gxx.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gxx.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gxx_priv.h [new file with mode: 0644]
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/au0828/Kconfig
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/au0828/au0828-reg.h
drivers/media/video/au0828/au0828-video.c
drivers/media/video/au0828/au0828.h
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cafe_ccic.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-gpio.c
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-video.c
drivers/media/video/cx231xx/Kconfig [new file with mode: 0644]
drivers/media/video/cx231xx/Makefile [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-audio.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-avcore.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-cards.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-conf-reg.h [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-core.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-dvb.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-i2c.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-input.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-pcb-cfg.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-pcb-cfg.h [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-reg.h [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-vbi.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-vbi.h [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx-video.c [new file with mode: 0644]
drivers/media/video/cx231xx/cx231xx.h [new file with mode: 0644]
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/Makefile
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/m5602/m5602_sensor.h
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-routing.c
drivers/media/video/ks0127.c
drivers/media/video/m52790.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h
drivers/media/video/msp3400-kthreads.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9t031.c
drivers/media/video/mx1_camera.c [new file with mode: 0644]
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/ov772x.c
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.c
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
drivers/media/video/pvrusb2/pvrusb2-wm8775.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7110.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa717x.c
drivers/media/video/saa7185.c
drivers/media/video/saa7191.c
drivers/media/video/soc_camera.c
drivers/media/video/tda9840.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp5150.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/Kconfig
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c [deleted file]
drivers/media/video/vino.c
drivers/media/video/vp27smpx.c
drivers/media/video/vpx3220.c
drivers/media/video/w9968cf.c
drivers/media/video/w9968cf.h
drivers/media/video/wm8775.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_device.c
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zr364xx.c
include/linux/i2c-id.h
include/linux/videodev2.h
include/media/msp3400.h
include/media/ov772x.h
include/media/saa7146.h
include/media/tvaudio.h
include/media/v4l2-common.h
include/media/v4l2-i2c-drv-legacy.h [deleted file]
include/media/v4l2-i2c-drv.h
include/media/v4l2-subdev.h

diff --git a/Documentation/video4linux/pxa_camera.txt b/Documentation/video4linux/pxa_camera.txt
new file mode 100644 (file)
index 0000000..b1137f9
--- /dev/null
@@ -0,0 +1,125 @@
+                              PXA-Camera Host Driver
+                              ======================
+
+Constraints
+-----------
+  a) Image size for YUV422P format
+     All YUV422P images are enforced to have width x height % 16 = 0.
+     This is due to DMA constraints, which transfers only planes of 8 byte
+     multiples.
+
+
+Global video workflow
+---------------------
+  a) QCI stopped
+     Initialy, the QCI interface is stopped.
+     When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts.
+
+  b) QCI started
+     More buffers can be queued while the QCI is started without halting the
+     capture.  The new buffers are "appended" at the tail of the DMA chain, and
+     smoothly captured one frame after the other.
+
+     Once a buffer is filled in the QCI interface, it is marked as "DONE" and
+     removed from the active buffers list. It can be then requeud or dequeued by
+     userland application.
+
+     Once the last buffer is filled in, the QCI interface stops.
+
+
+DMA usage
+---------
+  a) DMA flow
+     - first buffer queued for capture
+       Once a first buffer is queued for capture, the QCI is started, but data
+       transfer is not started. On "End Of Frame" interrupt, the irq handler
+       starts the DMA chain.
+     - capture of one videobuffer
+       The DMA chain starts transfering data into videobuffer RAM pages.
+       When all pages are transfered, the DMA irq is raised on "ENDINTR" status
+     - finishing one videobuffer
+       The DMA irq handler marks the videobuffer as "done", and removes it from
+       the active running queue
+       Meanwhile, the next videobuffer (if there is one), is transfered by DMA
+     - finishing the last videobuffer
+       On the DMA irq of the last videobuffer, the QCI is stopped.
+
+  b) DMA prepared buffer will have this structure
+
+     +------------+-----+---------------+-----------------+
+     | desc-sg[0] | ... | desc-sg[last] | finisher/linker |
+     +------------+-----+---------------+-----------------+
+
+     This structure is pointed by dma->sg_cpu.
+     The descriptors are used as follows :
+      - desc-sg[i]: i-th descriptor, transfering the i-th sg
+        element to the video buffer scatter gather
+      - finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
+      - linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0
+
+     For the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N],
+     "f" stands for finisher and "l" for linker.
+     A typical running chain is :
+
+         Videobuffer 1         Videobuffer 2
+     +---------+----+---+  +----+----+----+---+
+     | d0 | .. | dN | l |  | d0 | .. | dN | f |
+     +---------+----+-|-+  ^----+----+----+---+
+                      |    |
+                      +----+
+
+     After the chaining is finished, the chain looks like :
+
+         Videobuffer 1         Videobuffer 2         Videobuffer 3
+     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
+     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
+     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
+                      |    |                |    |
+                      +----+                +----+
+                                           new_link
+
+  c) DMA hot chaining timeslice issue
+
+     As DMA chaining is done while DMA _is_ running, the linking may be done
+     while the DMA jumps from one Videobuffer to another. On the schema, that
+     would be a problem if the following sequence is encountered :
+
+      - DMA chain is Videobuffer1 + Videobuffer2
+      - pxa_videobuf_queue() is called to queue Videobuffer3
+      - DMA controller finishes Videobuffer2, and DMA stops
+      =>
+         Videobuffer 1         Videobuffer 2
+     +---------+----+---+  +----+----+----+---+
+     | d0 | .. | dN | l |  | d0 | .. | dN | f |
+     +---------+----+-|-+  ^----+----+----+-^-+
+                      |    |                |
+                      +----+                +-- DMA DDADR loads DDADR_STOP
+
+      - pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is
+        replaced by a "linker" to Videobuffer3 (creation of new_link)
+      - pxa_videobuf_queue() finishes
+      - the DMA irq handler is called, which terminates Videobuffer2
+      - Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!)
+
+         Videobuffer 1         Videobuffer 2         Videobuffer 3
+     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
+     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
+     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
+                      |    |                |    |
+                      +----+                +----+
+                                           new_link
+                                          DMA DDADR still is DDADR_STOP
+
+      - pxa_camera_check_link_miss() is called
+        This checks if the DMA is finished and a buffer is still on the
+        pcdev->capture list. If that's the case, the capture will be restarted,
+        and Videobuffer3 is scheduled on DMA chain.
+      - the DMA irq handler finishes
+
+     Note: if DMA stops just after pxa_camera_check_link_miss() reads DDADR()
+     value, we have the guarantee that the DMA irq handler will be called back
+     when the DMA will finish the buffer, and pxa_camera_check_link_miss() will
+     be called again, to reschedule Videobuffer3.
+
+--
+Author: Robert Jarzmik <robert.jarzmik@free.fr>
index a311773..854808b 100644 (file)
@@ -90,7 +90,7 @@ up before calling v4l2_device_register then it will be untouched. If dev is
 NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
-usb_device or platform_device. It is rare for dev to be NULL, but it happens
+usb_interface or platform_device. It is rare for dev to be NULL, but it happens
 with ISA devices or when one device creates multiple PCI devices, thus making
 it impossible to associate v4l2_dev with a particular parent.
 
@@ -351,17 +351,6 @@ And this to go from an i2c_client to a v4l2_subdev struct:
 
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-Finally you need to make a command function to make driver->command()
-call the right subdev_ops functions:
-
-static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
-       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
-}
-
-If driver->command is never used then you can leave this out. Eventually the
-driver->command usage should be removed from v4l.
-
 Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
 is called. This will unregister the sub-device from the bridge driver. It is
 safe to call this even if the sub-device was never registered.
@@ -375,14 +364,12 @@ from the remove() callback ensures that this is always done correctly.
 
 The bridge driver also has some helper functions it can use:
 
-struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36);
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter,
+              "module_foo", "chipid", 0x36);
 
 This loads the given module (can be NULL if no module needs to be loaded) and
 calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
-If all goes well, then it registers the subdev with the v4l2_device. It gets
-the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
-to call i2c_set_adapdata(adapter, v4l2_device) when you setup the i2c_adapter
-in your driver.
+If all goes well, then it registers the subdev with the v4l2_device.
 
 You can also use v4l2_i2c_new_probed_subdev() which is very similar to
 v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
index 9673cd2..914f283 100644 (file)
@@ -1544,7 +1544,6 @@ S:        Maintained
 DVB SUBSYSTEM AND DRIVERS
 P:     LinuxTV.org Project
 M:     linux-media@vger.kernel.org
-L:     linux-dvb@linuxtv.org (subscription required)
 W:     http://linuxtv.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 S:     Maintained
index 82f1309..7f86fe0 100644 (file)
@@ -6,6 +6,9 @@
 
 obj-y                  += generic.o clock.o devices.o
 
+# Support for CMOS sensor interface
+obj-$(CONFIG_MX1_VIDEO)        += ksym_mx1.o mx1_camera_fiq.o
+
 # Specific board support
 obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
 obj-$(CONFIG_MACH_SCB9328) += scb9328.o
\ No newline at end of file
index 97f42d9..76d1ffb 100644 (file)
@@ -44,7 +44,7 @@ static struct resource imx_csi_resources[] = {
 static u64 imx_csi_dmamask = 0xffffffffUL;
 
 struct platform_device imx_csi_device = {
-       .name           = "imx-csi",
+       .name           = "mx1-camera",
        .id             = 0, /* This is used to put cameras on this interface */
        .dev            = {
                .dma_mask = &imx_csi_dmamask,
diff --git a/arch/arm/mach-mx1/ksym_mx1.c b/arch/arm/mach-mx1/ksym_mx1.c
new file mode 100644 (file)
index 0000000..b09ee12
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Exported ksyms of ARCH_MX1
+ *
+ * Copyright (C) 2008, Darius Augulis <augulis.darius@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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include <mach/mx1_camera.h>
+
+/* IMX camera FIQ handler */
+EXPORT_SYMBOL(mx1_camera_sof_fiq_start);
+EXPORT_SYMBOL(mx1_camera_sof_fiq_end);
diff --git a/arch/arm/mach-mx1/mx1_camera_fiq.S b/arch/arm/mach-mx1/mx1_camera_fiq.S
new file mode 100644 (file)
index 0000000..9c69aa6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ *  Based on linux/arch/arm/lib/floppydma.S
+ *      Copyright (C) 1995, 1996 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>
+
+               .text
+               .global mx1_camera_sof_fiq_end
+               .global mx1_camera_sof_fiq_start
+mx1_camera_sof_fiq_start:
+               @ enable dma
+               ldr     r12, [r9]
+               orr     r12, r12, #0x00000001
+               str     r12, [r9]
+               @ unmask DMA interrupt
+               ldr     r12, [r8]
+               bic     r12, r12, r13
+               str     r12, [r8]
+               @ disable SOF interrupt
+               ldr     r12, [r10]
+               bic     r12, r12, #0x00010000
+               str     r12, [r10]
+               @ clear SOF flag
+               mov     r12, #0x00010000
+               str     r12, [r11]
+               @ return from FIQ
+               subs    pc, lr, #4
+mx1_camera_sof_fiq_end:
index ca46f48..9957a11 100644 (file)
@@ -533,7 +533,7 @@ static struct clk_lookup lookups[] __initdata = {
        _REGISTER_CLOCK(NULL, "kpp", kpp_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
-       _REGISTER_CLOCK("mx3-camera.0", "csi", csi_clk)
+       _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
        _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
        _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
index e0783e6..eca37d0 100644 (file)
 #define PHYS_OFFSET            UL(0x80000000)
 #endif
 
+#if defined(CONFIG_MX1_VIDEO)
+/*
+ * Increase size of DMA-consistent memory region.
+ * This is required for i.MX camera driver to capture at least four VGA frames.
+ */
+#define CONSISTENT_DMA_SIZE SZ_4M
+#endif /* CONFIG_MX1_VIDEO */
+
 #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mx1_camera.h b/arch/arm/plat-mxc/include/mach/mx1_camera.h
new file mode 100644 (file)
index 0000000..4fd6c70
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * mx1_camera.h - i.MX1/i.MXL camera driver header file
+ *
+ * Copyright (c) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA camera.h file:
+ * Copyright (C) 2003, Intel Corporation
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+#define MX1_CAMERA_DATA_HIGH   1
+#define MX1_CAMERA_PCLK_RISING 2
+#define MX1_CAMERA_VSYNC_HIGH  4
+
+extern unsigned char mx1_camera_sof_fiq_start, mx1_camera_sof_fiq_end;
+
+/**
+ * struct mx1_camera_pdata - i.MX1/i.MXL camera platform data
+ * @mclk_10khz:        master clock frequency in 10kHz units
+ * @flags:     MX1 camera platform flags
+ */
+struct mx1_camera_pdata {
+       unsigned long mclk_10khz;
+       unsigned long flags;
+};
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
index 6103caa..60955a7 100644 (file)
@@ -294,7 +294,7 @@ config DVB_USB_DTV5100
 
 config DVB_USB_AF9015
        tristate "Afatech AF9015 DVB-T USB2.0 support"
-       depends on DVB_USB && EXPERIMENTAL
+       depends on DVB_USB
        select DVB_AF9013
        select DVB_PLL              if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
@@ -309,6 +309,6 @@ config DVB_USB_CE6230
        tristate "Intel CE6230 DVB-T USB2.0 support"
        depends on DVB_USB && EXPERIMENTAL
        select DVB_ZL10353
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
index f0ba8b0..53bfc8e 100644 (file)
@@ -782,17 +782,14 @@ static int af9015_read_config(struct usb_device *udev)
                                  ARRAY_SIZE(af9015_ir_table_leadtek);
                                break;
                        case USB_VID_VISIONPLUS:
-                               if (udev->descriptor.idProduct ==
-                               cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
-                                       af9015_properties[i].rc_key_map =
-                                         af9015_rc_keys_twinhan;
-                                       af9015_properties[i].rc_key_map_size =
-                                         ARRAY_SIZE(af9015_rc_keys_twinhan);
-                                       af9015_config.ir_table =
-                                         af9015_ir_table_twinhan;
-                                       af9015_config.ir_table_size =
-                                         ARRAY_SIZE(af9015_ir_table_twinhan);
-                               }
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_twinhan;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_twinhan);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_twinhan;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_twinhan);
                                break;
                        case USB_VID_KWORLD_2:
                                /* TODO: use correct rc keys */
@@ -833,6 +830,16 @@ static int af9015_read_config(struct usb_device *udev)
                                          af9015_ir_table_msi;
                                        af9015_config.ir_table_size =
                                          ARRAY_SIZE(af9015_ir_table_msi);
+                               } else if (udev->descriptor.idProduct ==
+                                       cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_trekstor;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_trekstor);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_trekstor;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_trekstor);
                                }
                                break;
                        case USB_VID_AVERMEDIA:
@@ -981,6 +988,21 @@ 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. */
+       if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
+           le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
+               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].tuner_if = 4570;
+       }
+
        return ret;
 }
 
@@ -1237,6 +1259,9 @@ static struct usb_device_id af9015_usb_table[] = {
 /* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
+       {USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1401,7 +1426,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 7,
+               .num_device_descs = 9,
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1437,7 +1462,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .name = "KWorld USB DVB-T TV Stick II " \
                                        "(VS-DVB-T 395U)",
                                .cold_ids = {&af9015_usb_table[16],
-                                            &af9015_usb_table[17], NULL},
+                                            &af9015_usb_table[17],
+                                            &af9015_usb_table[18], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "TrekStor DVB-T USB Stick",
+                               .cold_ids = {&af9015_usb_table[19], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "AverMedia AVerTV Volar Black HD " \
+                                       "(A850)",
+                               .cold_ids = {&af9015_usb_table[20], NULL},
                                .warm_ids = {NULL},
                        },
                }
index 00e2571..8d81a17 100644 (file)
 
 #define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
 
-#define AF9015_GPIO_ON (1 << 0)
-#define AF9015_GPIO_EN (1 << 1)
-#define AF9015_GPIO_O  (1 << 2)
-#define AF9015_GPIO_I  (1 << 3)
-
-#define AF9015_GPIO_TUNER_ON  (AF9015_GPIO_ON|AF9015_GPIO_EN)
-#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O)
-
 struct req_t {
        u8  cmd;       /* [0] */
        /*  seq */     /* [1] */
@@ -120,11 +112,11 @@ struct af9015_config {
 
 enum af9015_remote {
        AF9015_REMOTE_NONE                    = 0,
-       AF9015_REMOTE_A_LINK_DTU_M,
+/* 1 */        AF9015_REMOTE_A_LINK_DTU_M,
        AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
        AF9015_REMOTE_MYGICTV_U718,
        AF9015_REMOTE_DIGITTRADE_DVB_T,
-       AF9015_REMOTE_AVERMEDIA_KS,
+/* 5 */        AF9015_REMOTE_AVERMEDIA_KS,
 };
 
 /* Leadtek WinFast DTV Dongle Gold */
@@ -691,4 +683,67 @@ static u8 af9015_ir_table_digittrade[] = {
        0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
 };
 
+/* TREKSTOR DVB-T USB Stick */
+static struct dvb_usb_rc_key af9015_rc_keys_trekstor[] = {
+       { 0x07, 0x04, KEY_AGAIN },              /* Home */
+       { 0x07, 0x05, KEY_MUTE },               /* Mute */
+       { 0x07, 0x06, KEY_UP },                 /* Up */
+       { 0x07, 0x07, KEY_DOWN },               /* Down */
+       { 0x07, 0x09, KEY_RIGHT },              /* Right */
+       { 0x07, 0x0a, KEY_ENTER },              /* OK */
+       { 0x07, 0x0b, KEY_FASTFORWARD },        /* Fast forward */
+       { 0x07, 0x0c, KEY_REWIND },             /* Rewind */
+       { 0x07, 0x0d, KEY_PLAY },               /* Play/Pause */
+       { 0x07, 0x0e, KEY_VOLUMEUP },           /* Volume + */
+       { 0x07, 0x0f, KEY_VOLUMEDOWN },         /* Volume - */
+       { 0x07, 0x10, KEY_RECORD },             /* Record */
+       { 0x07, 0x11, KEY_STOP },               /* Stop */
+       { 0x07, 0x12, KEY_ZOOM },               /* TV */
+       { 0x07, 0x13, KEY_EPG },                /* Info/EPG */
+       { 0x07, 0x14, KEY_CHANNELDOWN },        /* Channel - */
+       { 0x07, 0x15, KEY_CHANNELUP },          /* Channel + */
+       { 0x07, 0x1e, KEY_1 },
+       { 0x07, 0x1f, KEY_2 },
+       { 0x07, 0x20, KEY_3 },
+       { 0x07, 0x21, KEY_4 },
+       { 0x07, 0x22, KEY_5 },
+       { 0x07, 0x23, KEY_6 },
+       { 0x07, 0x24, KEY_7 },
+       { 0x07, 0x25, KEY_8 },
+       { 0x07, 0x26, KEY_9 },
+       { 0x07, 0x08, KEY_LEFT },               /* LEFT */
+       { 0x07, 0x27, KEY_0 },
+};
+
+static u8 af9015_ir_table_trekstor[] = {
+       0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
+       0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
+       0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
+       0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
+       0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
+       0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
+       0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
+       0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
+       0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
+       0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
+       0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
+       0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
+       0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
+       0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
+       0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
+       0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
+       0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
+       0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
+       0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
+       0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
+       0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
+       0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
+       0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
+       0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
+       0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
+       0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
+       0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
+       0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
+};
+
 #endif
index 5862820..52badc0 100644 (file)
@@ -250,6 +250,7 @@ static int ce6230_probe(struct usb_interface *intf,
 
 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);
@@ -284,13 +285,18 @@ static struct dvb_usb_device_properties ce6230_properties = {
 
        .i2c_algo = &ce6230_i2c_algo,
 
-       .num_device_descs = 1,
+       .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},
+               },
        }
 };
 
index dc7ea21..f506c74 100644 (file)
@@ -65,6 +65,7 @@
 #define USB_PID_AFATECH_AF9005                         0x9020
 #define USB_PID_AFATECH_AF9015_9015                    0x9015
 #define USB_PID_AFATECH_AF9015_9016                    0x9016
+#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_KWORLD_399U                            0xe399
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_395U_2                          0xe39b
+#define USB_PID_KWORLD_395U_3                          0xe395
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #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_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
index 12f7730..32526f1 100644 (file)
@@ -151,7 +151,7 @@ static void debug_fcp(const u8 *data, int length)
                subunit_type = data[1] >> 3;
                subunit_id = data[1] & 7;
                op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
-               printk(KERN_INFO "%ssu=%x.%x l=%zu: %-8s - %s\n",
+               printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
                       prefix, subunit_type, subunit_id, length,
                       debug_fcp_ctype(data[0]),
                       debug_fcp_opcode(op, data, length));
index a486a7f..23e4cff 100644 (file)
@@ -513,6 +513,13 @@ config DVB_LGS8GL5
        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
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DMB-TH tuner module. Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
index 65a336a..bc2b00a 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
 obj-$(CONFIG_DVB_AF9013) += af9013.o
 obj-$(CONFIG_DVB_CX24116) += cx24116.o
index d63e152..9e9a755 100644 (file)
@@ -652,7 +652,7 @@ static int au8522_reset(struct v4l2_subdev *sd, u32 val)
 }
 
 static int au8522_s_video_routing(struct v4l2_subdev *sd,
-                                 const struct v4l2_routing *route)
+                                       u32 input, u32 output, u32 config)
 {
        struct au8522_state *state = to_state(sd);
 
@@ -663,11 +663,11 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
           closed), and then came back to analog mode */
        au8522_writereg(state, 0x106, 1);
 
-       if (route->input == AU8522_COMPOSITE_CH1) {
+       if (input == AU8522_COMPOSITE_CH1) {
                au8522_setup_cvbs_mode(state);
-       } else if (route->input == AU8522_SVIDEO_CH13) {
+       } else if (input == AU8522_SVIDEO_CH13) {
                au8522_setup_svideo_mode(state);
-       } else if (route->input == AU8522_COMPOSITE_CH4_SIF) {
+       } else if (input == AU8522_COMPOSITE_CH4_SIF) {
                au8522_setup_cvbs_tuner_mode(state);
        } else {
                printk(KERN_ERR "au8522 mode not currently supported\n");
@@ -677,10 +677,10 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
 }
 
 static int au8522_s_audio_routing(struct v4l2_subdev *sd,
-                                 const struct v4l2_routing *route)
+                                       u32 input, u32 output, u32 config)
 {
        struct au8522_state *state = to_state(sd);
-       set_audio_input(state, route->input);
+       set_audio_input(state, input);
        return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
new file mode 100644 (file)
index 0000000..f9785df
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ *    Support for Legend Silicon DMB-TH demodulator
+ *    LGS8913, LGS8GL5
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007,2008 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 "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;
+
+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:off).");
+
+/* 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 (reg >= 0xC0)
+               msg.addr += 0x02;
+
+       if (debug >= 2)
+               printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
+                       __func__, reg, data);
+
+       ret = i2c_transfer(priv->i2c, &msg, 1);
+
+       if (ret != 1)
+               dprintk(KERN_DEBUG "%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 (reg >= 0xC0)
+               dev_addr += 0x02;
+       msg[1].addr =  msg[0].addr = dev_addr;
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret != 2) {
+               dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
+                       __func__, reg, ret);
+               return -1;
+       }
+
+       *p_data = b1[0];
+       if (debug >= 2)
+               printk(KERN_DEBUG "%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 lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
+{
+       const struct lgs8gxx_config *config = priv->config;
+       u8 if_conf;
+
+       if_conf = 0x10; /* AGC output on; */
+
+       if_conf |=
+               ((config->ext_adc) ? 0x80 : 0x00) |
+               ((config->if_neg_center) ? 0x04 : 0x00) |
+               ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
+               ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) |
+               ((config->ext_adc && 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 *= (u64)1 << 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);
+
+       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_set_mode_auto(struct lgs8gxx_state *priv)
+{
+       u8 t;
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+               lgs8gxx_write_reg(priv, 0xC6, 0x01);
+
+       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 (priv->config->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);
+       }
+
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+               /* 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)
+{
+       int ret = 0;
+       u8 t;
+
+       /* 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);
+
+       ret = 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;
+
+       ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+       if (ret != 0)
+               return ret;
+
+       *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+       return 0;
+}
+
+static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
+                                         u8 *finished)
+{
+       int ret = 0;
+       u8 t;
+
+       ret = lgs8gxx_read_reg(priv, 0xA4, &t);
+       if (ret != 0)
+               return ret;
+
+       *finished = ((t & 0x3) == 0x1) ? 1 : 0;
+
+       return 0;
+}
+
+static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
+{
+       int err;
+       u8 ad_fini = 0;
+
+       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");
+       lgs8gxx_write_reg(priv, 0x04, gi);
+       lgs8gxx_soft_reset(priv);
+       msleep(50);
+       err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
+       if (err != 0)
+               return err;
+       if (ad_fini) {
+               err = lgs8gxx_is_locked(priv, locked);
+               if (err != 0)
+                       return err;
+       }
+
+       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);
+       /* 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, &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, &locked);
+                       if (err)
+                               goto out;
+                       if (locked)
+                               goto locked;
+               }
+               tmp_gi = GI_595;
+               err = lgs8gxx_autolock_gi(priv, GI_595, &locked);
+               if (err)
+                       goto out;
+               if (locked)
+                       goto locked;
+       }
+
+locked:
+       if ((err == 0) && (locked == 1)) {
+               u8 t;
+
+               lgs8gxx_read_reg(priv, 0xA2, &t);
+               *detected_param = t;
+
+               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");
+       }
+
+       /* Apply detected parameters */
+       if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+               u8 inter_leave_len = detected_param & TIM_MASK ;
+               inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40;
+               detected_param &= CF_MASK | SC_MASK  | LGS_FEC_MASK;
+               detected_param |= inter_leave_len;
+       }
+       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;
+
+       ret = lgs8gxx_read_reg(priv, 0xC2, &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, 0xC2, t);
+       if (ret != 0)
+               return ret;
+
+       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 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);
+
+       /* 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);
+       if (config->prod != LGS8GXX_PROD_LGS8913)
+               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, 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 dvb_frontend_parameters *fe_params)
+{
+       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, fe_params);
+               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 dvb_frontend_parameters *fe_params)
+{
+       struct lgs8gxx_state *priv = fe->demodulator_priv;
+       u8 t;
+
+       dprintk("%s\n", __func__);
+
+       /* TODO: get real readings from device */
+       /* inversion status */
+       fe_params->inversion = INVERSION_OFF;
+
+       /* bandwidth */
+       fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+
+
+       lgs8gxx_read_reg(priv, 0x7D, &t);
+       fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+       fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+
+       /* constellation */
+       switch (t & SC_MASK) {
+       case SC_QAM64:
+               fe_params->u.ofdm.constellation = QAM_64;
+               break;
+       case SC_QAM32:
+               fe_params->u.ofdm.constellation = QAM_32;
+               break;
+       case SC_QAM16:
+               fe_params->u.ofdm.constellation = QAM_16;
+               break;
+       case SC_QAM4:
+       case SC_QAM4NR:
+               fe_params->u.ofdm.constellation = QPSK;
+               break;
+       default:
+               fe_params->u.ofdm.constellation = QAM_64;
+       }
+
+       /* transmission mode */
+       fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+
+       /* guard interval */
+       fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+
+       /* hierarchy */
+       fe_params->u.ofdm.hierarchy_information = 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;
+
+       dprintk("%s\n", __func__);
+
+       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;
+
+       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 as 50\n");
+                       *signal = 0x32;
+               } 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 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
+               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;
+
+       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 int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct lgs8gxx_state *priv = fe->demodulator_priv;
+       u8 r0, r1, r2, r3;
+       u32 total_cnt, err_cnt;
+
+       dprintk("%s\n", __func__);
+
+       lgs8gxx_write_reg(priv, 0xc6, 0x01);
+       lgs8gxx_write_reg(priv, 0xc6, 0x41);
+       lgs8gxx_write_reg(priv, 0xc6, 0x01);
+
+       msleep(200);
+
+       lgs8gxx_write_reg(priv, 0xc6, 0x81);
+       lgs8gxx_read_reg(priv, 0xd0, &r0);
+       lgs8gxx_read_reg(priv, 0xd1, &r1);
+       lgs8gxx_read_reg(priv, 0xd2, &r2);
+       lgs8gxx_read_reg(priv, 0xd3, &r3);
+       total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
+       lgs8gxx_read_reg(priv, 0xd4, &r0);
+       lgs8gxx_read_reg(priv, 0xd5, &r1);
+       lgs8gxx_read_reg(priv, 0xd6, &r2);
+       lgs8gxx_read_reg(priv, 0xd7, &r3);
+       err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
+       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 = {
+       .info = {
+               .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
+               .type = FE_OFDM,
+               .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;
+
+       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");
diff --git a/drivers/media/dvb/frontends/lgs8gxx.h b/drivers/media/dvb/frontends/lgs8gxx.h
new file mode 100644 (file)
index 0000000..321d366
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *    Support for Legend Silicon DMB-TH demodulator
+ *    LGS8913, LGS8GL5
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007,2008 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
+
+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;
+
+       /* 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 (file)
index 0000000..9776d30
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *    Support for Legend Silicon DMB-TH demodulator
+ *    LGS8913, LGS8GL5
+ *    experimental support LGS8G42, LGS8G52
+ *
+ *    Copyright (C) 2007,2008 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 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         0x00  /* Time Interleave Length = 720 */
+#define TIM_MIDDLE     0x20   /* 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
index cc54ed4..6135762 100644 (file)
@@ -33,6 +33,9 @@
 
  History:
 
+ Version 0.45:
+       Converted to v4l2_device.
+
  Version 0.44:
        Add suspend/resume functions, fix unplug of device,
        a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
@@ -88,7 +91,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
 
  */
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.44"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-/* HINT: the disabled controls are only here to satify kradio and such apps */
-       {       .id             = V4L2_CID_AUDIO_VOLUME,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_BALANCE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_BASS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_TREBLE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_LOUDNESS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-};
+#define DRIVER_VERSION "v0.45"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -167,6 +139,8 @@ module_param(radio_nr, int, 0);
 struct dsbr100_device {
        struct usb_device *usbdev;
        struct video_device videodev;
+       struct v4l2_device v4l2_dev;
+
        u8 *transfer_buffer;
        struct mutex lock;      /* buffer locking */
        int curfreq;
@@ -384,6 +358,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
        mutex_unlock(&radio->lock);
 
        video_unregister_device(&radio->videodev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
 }
 
 
@@ -479,14 +454,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
        }
+
        return -EINVAL;
 }
 
@@ -656,6 +628,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 {
        struct dsbr100_device *radio = videodev_to_radio(videodev);
 
+       v4l2_device_unregister(&radio->v4l2_dev);
        kfree(radio->transfer_buffer);
        kfree(radio);
 }
@@ -683,22 +656,15 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-/* V4L2 interface */
-static struct video_device dsbr100_videodev_data = {
-       .name           = "D-Link DSB-R 100",
-       .fops           = &usb_dsbr100_fops,
-       .ioctl_ops      = &usb_dsbr100_ioctl_ops,
-       .release        = usb_dsbr100_video_device_release,
-};
-
 /* check if the device is present and register with v4l and usb if it is */
 static int usb_dsbr100_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        struct dsbr100_device *radio;
+       struct v4l2_device *v4l2_dev;
        int retval;
 
-       radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
+       radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
 
        if (!radio)
                return -ENOMEM;
@@ -710,17 +676,35 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
+       v4l2_dev = &radio->v4l2_dev;
+
+       retval = v4l2_device_register(&intf->dev, v4l2_dev);
+       if (retval < 0) {
+               v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
+               kfree(radio->transfer_buffer);
+               kfree(radio);
+               return retval;
+       }
+
+       strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
+       radio->videodev.v4l2_dev = v4l2_dev;
+       radio->videodev.fops = &usb_dsbr100_fops;
+       radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
+       radio->videodev.release = usb_dsbr100_video_device_release;
+
        mutex_init(&radio->lock);
-       radio->videodev = dsbr100_videodev_data;
 
        radio->removed = 0;
        radio->users = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN * FREQ_MUL;
+
        video_set_drvdata(&radio->videodev, radio);
+
        retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
        if (retval < 0) {
-               dev_err(&intf->dev, "couldn't register video device\n");
+               v4l2_err(v4l2_dev, "couldn't register video device\n");
+               v4l2_device_unregister(v4l2_dev);
                kfree(radio->transfer_buffer);
                kfree(radio);
                return -EIO;
index ac82e33..35edee0 100644 (file)
@@ -355,20 +355,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int rtrack_open(struct file *file)
-{
-       return 0;
-}
-
-static int rtrack_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations rtrack_fops = {
        .owner          = THIS_MODULE,
-       .open           = rtrack_open,
-       .release        = rtrack_release,
        .ioctl          = video_ioctl2,
 };
 
index 49299f7..8daf809 100644 (file)
@@ -318,20 +318,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int aztech_open(struct file *file)
-{
-       return 0;
-}
-
-static int aztech_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations aztech_fops = {
        .owner          = THIS_MODULE,
-       .open           = aztech_open,
-       .release        = aztech_release,
        .ioctl          = video_ioctl2,
 };
 
index 09265d2..c3f579d 100644 (file)
@@ -356,20 +356,8 @@ static struct pci_device_id gemtek_pci_id[] =
 
 MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
 
-static int gemtek_pci_open(struct file *file)
-{
-       return 0;
-}
-
-static int gemtek_pci_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations gemtek_pci_fops = {
        .owner          = THIS_MODULE,
-       .open           = gemtek_pci_open,
-       .release        = gemtek_pci_release,
        .ioctl          = video_ioctl2,
 };
 
index 1504644..73985f6 100644 (file)
@@ -375,20 +375,9 @@ static int gemtek_probe(struct gemtek *gt)
 /*
  * Video 4 Linux stuff.
  */
-static int gemtek_open(struct file *file)
-{
-       return 0;
-}
-
-static int gemtek_release(struct file *file)
-{
-       return 0;
-}
 
 static const struct v4l2_file_operations gemtek_fops = {
        .owner          = THIS_MODULE,
-       .open           = gemtek_open,
-       .release        = gemtek_release,
        .ioctl          = video_ioctl2,
 };
 
index 01a6d22..64d737c 100644 (file)
@@ -292,20 +292,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int maestro_open(struct file *file)
-{
-       return 0;
-}
-
-static int maestro_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations maestro_fops = {
        .owner          = THIS_MODULE,
-       .open           = maestro_open,
-       .release        = maestro_release,
        .ioctl          = video_ioctl2,
 };
 
index 2606f0b..3da51fe 100644 (file)
@@ -339,20 +339,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int maxiradio_open(struct file *file)
-{
-       return 0;
-}
-
-static int maxiradio_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations maxiradio_fops = {
        .owner          = THIS_MODULE,
-       .open           = maxiradio_open,
-       .release        = maxiradio_release,
        .ioctl          = video_ioctl2,
 };
 
index ded25bf..cab19d0 100644 (file)
@@ -43,6 +43,7 @@
  *                     Douglas Schilling Landgraf <dougsland@gmail.com> and
  *                     David Ellingsworth <david@identd.dyndns.org>
  *                     for discussion, help and support.
+ * Version 0.11:       Converted to v4l2_device.
  *
  * Many things to do:
  *     - Correct power managment of device (suspend & resume)
@@ -59,7 +60,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO */
@@ -67,8 +68,8 @@
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
-#define DRIVER_VERSION "0.10"
-#define RADIO_VERSION KERNEL_VERSION(0, 1, 0)
+#define DRIVER_VERSION "0.11"
+#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -113,38 +114,6 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "Radio Nr");
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-/* HINT: the disabled controls are only here to satify kradio and such apps */
-       {       .id             = V4L2_CID_AUDIO_VOLUME,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_BALANCE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_BASS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_TREBLE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_LOUDNESS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-};
-
 static int usb_amradio_probe(struct usb_interface *intf,
                             const struct usb_device_id *id);
 static void usb_amradio_disconnect(struct usb_interface *intf);
@@ -159,6 +128,7 @@ struct amradio_device {
        /* reference to USB and video device */
        struct usb_device *usbdev;
        struct video_device *videodev;
+       struct v4l2_device v4l2_dev;
 
        unsigned char *buffer;
        struct mutex lock;      /* buffer locking */
@@ -329,6 +299,7 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        video_unregister_device(radio->videodev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
 }
 
 /* vidioc_querycap - query device capabilities */
@@ -463,14 +434,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 static int vidioc_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return 0;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
        }
+
        return -EINVAL;
 }
 
@@ -671,34 +639,29 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
-static void usb_amradio_device_release(struct video_device *videodev)
+static void usb_amradio_video_device_release(struct video_device *videodev)
 {
        struct amradio_device *radio = video_get_drvdata(videodev);
 
        /* we call v4l to free radio->videodev */
        video_device_release(videodev);
 
+       v4l2_device_unregister(&radio->v4l2_dev);
+
        /* free rest memory */
        kfree(radio->buffer);
        kfree(radio);
 }
 
-/* V4L2 interface */
-static struct video_device amradio_videodev_template = {
-       .name           = "AverMedia MR 800 USB FM Radio",
-       .fops           = &usb_amradio_fops,
-       .ioctl_ops      = &usb_amradio_ioctl_ops,
-       .release        = usb_amradio_device_release,
-};
-
 /* check if the device is present and register with v4l and usb if it is */
 static int usb_amradio_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        struct amradio_device *radio;
+       struct v4l2_device *v4l2_dev;
        int retval;
 
-       radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
+       radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
 
        if (!radio) {
                dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
@@ -713,6 +676,15 @@ static int usb_amradio_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
+       v4l2_dev = &radio->v4l2_dev;
+       retval = v4l2_device_register(&intf->dev, v4l2_dev);
+       if (retval < 0) {
+               dev_err(&intf->dev, "couldn't register v4l2_device\n");
+               kfree(radio->buffer);
+               kfree(radio);
+               return retval;
+       }
+
        radio->videodev = video_device_alloc();
 
        if (!radio->videodev) {
@@ -722,8 +694,11 @@ static int usb_amradio_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
-       memcpy(radio->videodev, &amradio_videodev_template,
-               sizeof(amradio_videodev_template));
+       strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name));
+       radio->videodev->v4l2_dev = v4l2_dev;
+       radio->videodev->fops = &usb_amradio_fops;
+       radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops;
+       radio->videodev->release = usb_amradio_video_device_release;
 
        radio->removed = 0;
        radio->users = 0;
@@ -734,10 +709,12 @@ static int usb_amradio_probe(struct usb_interface *intf,
        mutex_init(&radio->lock);
 
        video_set_drvdata(radio->videodev, radio);
+
        retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
        if (retval < 0) {
                dev_err(&intf->dev, "could not register video device\n");
                video_device_release(radio->videodev);
+               v4l2_device_unregister(v4l2_dev);
                kfree(radio->buffer);
                kfree(radio);
                return -EIO;
index d1e6b01..9cb193f 100644 (file)
@@ -260,20 +260,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int rtrack2_open(struct file *file)
-{
-       return 0;
-}
-
-static int rtrack2_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations rtrack2_fops = {
        .owner          = THIS_MODULE,
-       .open           = rtrack2_open,
-       .release        = rtrack2_release,
        .ioctl          = video_ioctl2,
 };
 
index f4784f0..1dba8f0 100644 (file)
@@ -260,20 +260,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int fmi_open(struct file *file)
-{
-       return 0;
-}
-
-static int fmi_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations fmi_fops = {
        .owner          = THIS_MODULE,
-       .open           = fmi_open,
-       .release        = fmi_release,
        .ioctl          = video_ioctl2,
 };
 
index 0ba9d88..c09ca86 100644 (file)
@@ -377,20 +377,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int fmr2_open(struct file *file)
-{
-       return 0;
-}
-
-static int fmr2_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations fmr2_fops = {
        .owner          = THIS_MODULE,
-       .open           = fmr2_open,
-       .release        = fmr2_release,
        .ioctl          = video_ioctl2,
 };
 
index 713e242..92c2977 100644 (file)
@@ -1686,7 +1686,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        /* show some infos about the specific si470x device */
        if (si470x_get_all_registers(radio) < 0) {
                retval = -EIO;
-               goto err_all;
+               goto err_video;
        }
        printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
                        radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -1694,7 +1694,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        /* get software and hardware versions */
        if (si470x_get_scratch_page_versions(radio) < 0) {
                retval = -EIO;
-               goto err_all;
+               goto err_video;
        }
        printk(KERN_INFO DRIVER_NAME
                        ": software version %d, hardware version %d\n",
@@ -1727,7 +1727,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
        if (!radio->buffer) {
                retval = -EIO;
-               goto err_all;
+               goto err_video;
        }
 
        /* rds buffer configuration */
@@ -1749,8 +1749,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
 
        return 0;
 err_all:
-       video_device_release(radio->videodev);
        kfree(radio->buffer);
+err_video:
+       video_device_release(radio->videodev);
 err_radio:
        kfree(radio);
 err_initial:
index 5b007f5..699db9a 100644 (file)
@@ -332,20 +332,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int terratec_open(struct file *file)
-{
-       return 0;
-}
-
-static int terratec_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations terratec_fops = {
        .owner          = THIS_MODULE,
-       .open           = terratec_open,
-       .release        = terratec_release,
        .ioctl          = video_ioctl2,
 };
 
index d1be649..6f9ecc3 100644 (file)
@@ -338,20 +338,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int trust_open(struct file *file)
-{
-       return 0;
-}
-
-static int trust_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations trust_fops = {
        .owner          = THIS_MODULE,
-       .open           = trust_open,
-       .release        = trust_release,
        .ioctl          = video_ioctl2,
 };
 
index 92d923c..3a98f13 100644 (file)
@@ -314,20 +314,8 @@ static int vidioc_log_status(struct file *file, void *priv)
        return 0;
 }
 
-static int typhoon_open(struct file *file)
-{
-       return 0;
-}
-
-static int typhoon_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations typhoon_fops = {
        .owner          = THIS_MODULE,
-       .open           = typhoon_open,
-       .release        = typhoon_release,
        .ioctl          = video_ioctl2,
 };
 
index 1f85f20..80e98b6 100644 (file)
@@ -370,21 +370,9 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return a->index ? -EINVAL : 0;
 }
 
-static int zoltrix_open(struct file *file)
-{
-       return 0;
-}
-
-static int zoltrix_release(struct file *file)
-{
-       return 0;
-}
-
 static const struct v4l2_file_operations zoltrix_fops =
 {
        .owner          = THIS_MODULE,
-       .open           = zoltrix_open,
-       .release        = zoltrix_release,
        .ioctl          = video_ioctl2,
 };
 
index 76bad58..9d48da2 100644 (file)
@@ -746,6 +746,18 @@ config SOC_CAMERA_OV772X
        help
          This is a ov772x camera driver
 
+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 VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
@@ -795,6 +807,8 @@ source "drivers/media/video/hdpvr/Kconfig"
 
 source "drivers/media/video/em28xx/Kconfig"
 
+source "drivers/media/video/cx231xx/Kconfig"
+
 source "drivers/media/video/usbvision/Kconfig"
 
 source "drivers/media/video/usbvideo/Kconfig"
@@ -904,5 +918,4 @@ config USB_S2255
          This driver can be compiled as a module, called s2255drv.
 
 endif # V4L_USB_DRIVERS
-
 endif # VIDEO_CAPTURE_DRIVERS
index b904674..3f1a035 100644 (file)
@@ -10,7 +10,7 @@ stkwebcam-objs        :=      stk-webcam.o stk-sensor.o
 
 omap2cam-objs  :=      omap24xxcam.o omap24xxcam-dma.o
 
-videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
+videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 ifeq ($(CONFIG_COMPAT),y)
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
@@ -133,6 +134,7 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_MX1)                        += mx1_camera.o
 obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
index 873c30a..97b0034 100644 (file)
@@ -219,18 +219,19 @@ static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
        return 0;
 }
 
-static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+static int adv7170_s_routing(struct v4l2_subdev *sd,
+                            u32 input, u32 output, u32 config)
 {
        struct adv7170 *encoder = to_adv7170(sd);
 
-       /* RJ: route->input = 0: input is from decoder
-          route->input = 1: input is from ZR36060
-          route->input = 2: color bar */
+       /* 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",
-                       route->input == 0 ? "decoder" : "ZR36060");
+                       input == 0 ? "decoder" : "ZR36060");
 
-       switch (route->input) {
+       switch (input) {
        case 0:
                adv7170_write(sd, 0x01, 0x20);
                adv7170_write(sd, 0x08, TR1CAPT);       /* TR1 */
@@ -250,11 +251,11 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
                break;
 
        default:
-               v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
+               v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
                return -EINVAL;
        }
-       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
-       encoder->input = route->input;
+       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
+       encoder->input = input;
        return 0;
 }
 
index ff12103..cf8c06c 100644 (file)
@@ -237,15 +237,16 @@ static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
        return 0;
 }
 
-static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+static int adv7175_s_routing(struct v4l2_subdev *sd,
+                            u32 input, u32 output, u32 config)
 {
        struct adv7175 *encoder = to_adv7175(sd);
 
-       /* RJ: route->input = 0: input is from decoder
-          route->input = 1: input is from ZR36060
-          route->input = 2: color bar */
+       /* RJ: input = 0: input is from decoder
+          input = 1: input is from ZR36060
+          input = 2: color bar */
 
-       switch (route->input) {
+       switch (input) {
        case 0:
                adv7175_write(sd, 0x01, 0x00);
 
@@ -288,11 +289,11 @@ static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
                break;
 
        default:
-               v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
+               v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
                return -EINVAL;
        }
-       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
-       encoder->input = route->input;
+       v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
+       encoder->input = input;
        return 0;
 }
 
index 05cdf49..0c3a5ba 100644 (file)
@@ -4,6 +4,7 @@ config VIDEO_AU0828
        depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
        select I2C_ALGOBIT
        select VIDEO_TVEEPROM
+       select VIDEOBUF_VMALLOC
        select DVB_AU8522 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
index 1aabaa7..053bbe8 100644 (file)
@@ -46,6 +46,7 @@ struct au0828_board au0828_boards[] = {
                .name   = "Hauppauge HVR850",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
+               .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
                .input = {
                        {
                                .type = AU0828_VMUX_TELEVISION,
@@ -70,6 +71,13 @@ struct au0828_board au0828_boards[] = {
                .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_30KHZ,
                .input = {
                        {
                                .type = AU0828_VMUX_TELEVISION,
@@ -94,16 +102,19 @@ struct au0828_board au0828_boards[] = {
                .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,
        },
 };
 
@@ -200,8 +211,8 @@ void au0828_card_setup(struct au0828_dev *dev)
                /* 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->i2c_adap, "au8522", "au8522",
-                                        0x8e >> 1);
+               sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+                               "au8522", "au8522", 0x8e >> 1);
                if (sd == NULL)
                        printk(KERN_ERR "analog subdev registration failed\n");
        }
@@ -209,8 +220,8 @@ void au0828_card_setup(struct au0828_dev *dev)
        /* Setup tuners */
        if (dev->board.tuner_type != TUNER_ABSENT) {
                /* Load the tuner module, which does the attach */
-               sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "tuner", "tuner",
-                                        dev->board.tuner_addr);
+               sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+                               "tuner", "tuner", dev->board.tuner_addr);
                if (sd == NULL)
                        printk(KERN_ERR "tuner subdev registration fail\n");
 
index 8c761d1..4cee0b9 100644 (file)
@@ -36,8 +36,6 @@ int au0828_debug;
 module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
-static atomic_t au0828_instance = ATOMIC_INIT(0);
-
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 
@@ -169,7 +167,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
 static int au0828_usb_probe(struct usb_interface *interface,
        const struct usb_device_id *id)
 {
-       int ifnum, retval, i;
+       int ifnum, retval;
        struct au0828_dev *dev;
        struct usb_device *usbdev = interface_to_usbdev(interface);
 
@@ -197,10 +195,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
        usb_set_intfdata(interface, dev);
 
        /* Create the v4l2_device */
-       i = atomic_inc_return(&au0828_instance) - 1;
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d",
-                "au0828", i);
-       retval = v4l2_device_register(&dev->usbdev->dev, &dev->v4l2_dev);
+       retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
        if (retval) {
                printk(KERN_ERR "%s() v4l2_device_register failed\n",
                       __func__);
index f9a958d..13e4943 100644 (file)
@@ -39,13 +39,15 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 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, REG_201) & 0x08 ? 0 : 1;
+       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, REG_201) & 0x02 ? 0 : 1;
+       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)
@@ -67,7 +69,8 @@ static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
 static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
 {
        struct au0828_dev *dev = i2c_adap->algo_data;
-       return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
+       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)
@@ -89,7 +92,8 @@ static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
 static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
 {
        struct au0828_dev *dev = i2c_adap->algo_data;
-       return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
+       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)
@@ -111,7 +115,8 @@ static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
 static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
 {
        struct au0828_dev *dev = i2c_adap->algo_data;
-       return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
+       return au0828_read(dev, AU0828_I2C_STATUS_201) &
+               AU0828_I2C_STATUS_BUSY ? 1 : 0;
 }
 
 static int i2c_wait_done(struct i2c_adapter *i2c_adap)
@@ -139,19 +144,14 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
        dprintk(4, "%s()\n", __func__);
 
-       au0828_write(dev, REG_2FF, 0x01);
+       au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
 
-       /* FIXME: There is a problem with i2c communications with xc5000 that
-          requires us to slow down the i2c clock until we have a better
-          strategy (such as using the secondary i2c bus to do firmware
-          loading */
-       if ((msg->addr << 1) == 0xc2)
-               au0828_write(dev, REG_202, 0x40);
-       else
-               au0828_write(dev, REG_202, 0x07);
+       /* 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, REG_203, msg->addr << 1);
+       au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
 
        dprintk(4, "SEND: %02x\n", msg->addr);
 
@@ -163,7 +163,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
                   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, REG_200, 0x20);
+               au0828_write(dev, AU0828_I2C_TRIGGER_200,
+                            AU0828_I2C_TRIGGER_READ);
+
                if (!i2c_wait_done(i2c_adap))
                        return -EIO;
 
@@ -177,7 +179,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
                dprintk(4, " %02x\n", msg->buf[i]);
 
-               au0828_write(dev, REG_205, msg->buf[i]);
+               au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
 
                strobe++;
                i++;
@@ -186,9 +188,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
                        /* Strobe the byte into the bus */
                        if (i < msg->len)
-                               au0828_write(dev, REG_200, 0x41);
+                               au0828_write(dev, AU0828_I2C_TRIGGER_200,
+                                            AU0828_I2C_TRIGGER_WRITE |
+                                            AU0828_I2C_TRIGGER_HOLD);
                        else
-                               au0828_write(dev, REG_200, 0x01);
+                               au0828_write(dev, AU0828_I2C_TRIGGER_200,
+                                            AU0828_I2C_TRIGGER_WRITE);
 
                        /* Reset strobe trigger */
                        strobe = 0;
@@ -216,25 +221,22 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 
        dprintk(4, "%s()\n", __func__);
 
-       au0828_write(dev, REG_2FF, 0x01);
+       au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
 
-       /* FIXME: There is a problem with i2c communications with xc5000 that
-          requires us to slow down the i2c clock until we have a better
-          strategy (such as using the secondary i2c bus to do firmware
-          loading */
-       if ((msg->addr << 1) == 0xc2)
-               au0828_write(dev, REG_202, 0x40);
-       else
-               au0828_write(dev, REG_202, 0x07);
+       /* 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, REG_203, msg->addr << 1);
+       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, REG_200, 0x20);
+               au0828_write(dev, AU0828_I2C_TRIGGER_200,
+                            AU0828_I2C_TRIGGER_READ);
+
                if (i2c_wait_read_ack(i2c_adap))
                        return -EIO;
                return 0;
@@ -245,14 +247,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
                i++;
 
                if (i < msg->len)
-                       au0828_write(dev, REG_200, 0x60);
+                       au0828_write(dev, AU0828_I2C_TRIGGER_200,
+                                    AU0828_I2C_TRIGGER_READ |
+                                    AU0828_I2C_TRIGGER_HOLD);
                else
-                       au0828_write(dev, REG_200, 0x20);
+                       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, REG_209) & 0xff;
+               msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
+                       0xff;
 
                dprintk(4, " %02x\n", msg->buf[i-1]);
        }
index b15e4a3..c39f3d2 100644 (file)
 #define AU0828_SENSORCTRL_100 0x100
 #define AU0828_SENSORCTRL_VBI_103 0x103
 
-#define REG_200 0x200
-#define REG_201 0x201
-#define REG_202 0x202
-#define REG_203 0x203
-#define REG_205 0x205
-#define REG_209 0x209
-#define REG_2FF 0x2ff
+/* 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
index f7ad495..27bedc6 100644 (file)
@@ -1100,7 +1100,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
           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, tuner, s_std, *norm);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
        return 0;
 }
 
@@ -1154,7 +1154,6 @@ 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;
-       struct v4l2_routing route;
 
        dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
                index);
@@ -1180,9 +1179,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
                break;
        }
 
-       route.input = AUVI_INPUT(index).vmux;
-       route.output = 0;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, &route);
+       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;
@@ -1205,8 +1203,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
                }
        }
 
-       route.input = AUVI_INPUT(index).amux;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, &route);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+                       AUVI_INPUT(index).amux, 0, 0);
        return 0;
 }
 
index 6ed1a61..b977915 100644 (file)
@@ -81,6 +81,7 @@ 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];
 
 };
index df4516d..f9330e3 100644 (file)
@@ -292,21 +292,22 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
        return 0;
 }
 
-static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+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", route->input);
+       v4l2_dbg(1, debug, sd, "set input %x\n", input);
 
-       if (route->input < 0 || route->input > 7)
+       if (input < 0 || input > 7)
                return -EINVAL;
 
        if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
                v4l2_err(sd, "no notify found!\n");
 
-       if (decoder->input != route->input) {
+       if (decoder->input != input) {
                v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
-               decoder->input = route->input;
+               decoder->input = input;
                /* select mode */
                if (decoder->input == 0) {
                        bt819_setbit(decoder, 0x0b, 6, 0);
@@ -444,9 +445,6 @@ static const struct v4l2_subdev_core_ops bt819_core_ops = {
        .g_ctrl = bt819_g_ctrl,
        .s_ctrl = bt819_s_ctrl,
        .queryctrl = bt819_queryctrl,
-};
-
-static const struct v4l2_subdev_tuner_ops bt819_tuner_ops = {
        .s_std = bt819_s_std,
 };
 
@@ -459,7 +457,6 @@ static const struct v4l2_subdev_video_ops bt819_video_ops = {
 
 static const struct v4l2_subdev_ops bt819_ops = {
        .core = &bt819_core_ops,
-       .tuner = &bt819_tuner_ops,
        .video = &bt819_video_ops,
 };
 
index 78db395..d0b4d49 100644 (file)
@@ -142,16 +142,17 @@ static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
        return 0;
 }
 
-static int bt856_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+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", route->input);
+       v4l2_dbg(1, debug, sd, "set input %d\n", input);
 
        /* We only have video bus.
-        * route->input= 0: input is from bt819
-        * route->input= 1: input is from ZR36060 */
-       switch (route->input) {
+        * 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);
index 350cae4..af7e3a5 100644 (file)
@@ -99,7 +99,8 @@ static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
        return 0;
 }
 
-static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+static int bt866_s_routing(struct v4l2_subdev *sd,
+                          u32 input, u32 output, u32 config)
 {
        static const __u8 init[] = {
                0xc8, 0xcc, /* CRSCALE */
@@ -137,7 +138,7 @@ static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
 
        val = encoder->reg[0xdc];
 
-       if (route->input == 0)
+       if (input == 0)
                val |= 0x40; /* CBSWAP */
        else
                val &= ~0x40; /* !CBSWAP */
@@ -145,15 +146,15 @@ static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *ro
        bt866_write(encoder, 0xdc, val);
 
        val = encoder->reg[0xcc];
-       if (route->input == 2)
+       if (input == 2)
                val |= 0x01; /* OSDBAR */
        else
                val &= ~0x01; /* !OSDBAR */
        bt866_write(encoder, 0xcc, val);
 
-       v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
+       v4l2_dbg(1, debug, sd, "set input %d\n", input);
 
-       switch (route->input) {
+       switch (input) {
        case 0:
        case 1:
        case 2:
index b9c3ba5..fdb4adf 100644 (file)
@@ -3324,17 +3324,6 @@ void __devinit bttv_init_card1(struct bttv *btv)
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-       static const unsigned short tvaudio_addrs[] = {
-               I2C_ADDR_TDA8425   >> 1,
-               I2C_ADDR_TEA6300   >> 1,
-               I2C_ADDR_TEA6420   >> 1,
-               I2C_ADDR_TDA9840   >> 1,
-               I2C_ADDR_TDA985x_L >> 1,
-               I2C_ADDR_TDA985x_H >> 1,
-               I2C_ADDR_TDA9874   >> 1,
-               I2C_ADDR_PIC16C54  >> 1,
-               I2C_CLIENT_END
-       };
        int addr=ADDR_UNSET;
 
        btv->tuner_type = UNSET;
@@ -3512,12 +3501,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
 
                /* Load tuner module before issuing tuner config call! */
                if (bttv_tvcards[btv->c.type].has_radio)
-                       v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_RADIO));
-               v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
-                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
-               v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
-                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+                       v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tuner", "tuner",
+                               v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
 
                tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
                tun_setup.type = btv->tuner_type;
@@ -3570,8 +3562,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
                };
                struct v4l2_subdev *sd;
 
-               sd = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "saa6588", "saa6588", addrs);
+               sd = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                       &btv->c.i2c_adap, "saa6588", "saa6588", addrs);
                btv->has_saa6588 = (sd != NULL);
        }
 
@@ -3595,8 +3587,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        I2C_CLIENT_END
                };
 
-               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "msp3400", "msp3400", addrs);
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                       &btv->c.i2c_adap, "msp3400", "msp3400", addrs);
                if (btv->sd_msp34xx)
                        return;
                goto no_audio;
@@ -3609,16 +3601,16 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        I2C_CLIENT_END
                };
 
-               if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "tda7432", "tda7432", addrs))
+               if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tda7432", "tda7432", addrs))
                        return;
                goto no_audio;
        }
 
        case 3: {
                /* The user specified that we should probe for tvaudio */
-               btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "tvaudio", "tvaudio", tvaudio_addrs);
+               btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                       &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
                if (btv->sd_tvaudio)
                        return;
                goto no_audio;
@@ -3637,21 +3629,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
           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) {
-               static const unsigned short addrs[] = {
-                       I2C_ADDR_MSP3400 >> 1,
-                       I2C_CLIENT_END
-               };
-
-               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "msp3400", "msp3400", addrs);
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
+                       &btv->c.i2c_adap, "msp3400", "msp3400",
+                       I2C_ADDR_MSP3400 >> 1);
        } else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
-               static const unsigned short addrs[] = {
-                       I2C_ADDR_MSP3400_ALT >> 1,
-                       I2C_CLIENT_END
-               };
-
-               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "msp3400", "msp3400", addrs);
+               btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
+                       &btv->c.i2c_adap, "msp3400", "msp3400",
+                       I2C_ADDR_MSP3400_ALT >> 1);
        }
 
        /* If we found a msp34xx, then we're done. */
@@ -3665,14 +3649,14 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        I2C_CLIENT_END
                };
 
-               if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                               "tda7432", "tda7432", addrs))
+               if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+                               &btv->c.i2c_adap, "tda7432", "tda7432", addrs))
                        return;
        }
 
        /* Now see if we can find one of the tvaudio devices. */
-       btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
-                       "tvaudio", "tvaudio", tvaudio_addrs);
+       btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+               &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
        if (btv->sd_tvaudio)
                return;
 
index 7a8ca0d..74f619d 100644 (file)
@@ -1198,7 +1198,7 @@ audio_mux(struct bttv *btv, int input, int mute)
        ctrl.value = btv->mute;
        bttv_call_all(btv, core, s_ctrl, &ctrl);
        if (btv->sd_msp34xx) {
-               struct v4l2_routing route;
+               u32 in;
 
                /* Note: the inputs tuner/radio/extern/intern are translated
                   to msp routings. This assumes common behavior for all msp3400
@@ -1207,11 +1207,11 @@ audio_mux(struct bttv *btv, int input, int mute)
                   For now this is sufficient. */
                switch (input) {
                case TVAUDIO_INPUT_RADIO:
-                       route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                       in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
                                    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
                        break;
                case TVAUDIO_INPUT_EXTERN:
-                       route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+                       in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
                                    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
                        break;
                case TVAUDIO_INPUT_INTERN:
@@ -1220,7 +1220,7 @@ audio_mux(struct bttv *btv, int input, int mute)
                           input is the BTTV_BOARD_AVERMEDIA98. I wonder how
                           that was tested. My guess is that the whole INTERN
                           input does not work. */
-                       route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                       in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
                                    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
                        break;
                case TVAUDIO_INPUT_TUNER:
@@ -1229,21 +1229,18 @@ audio_mux(struct bttv *btv, int input, int mute)
                           is the only difference between the VOODOOTV_FM
                           and VOODOOTV_200 */
                        if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
-                               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+                               in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
                                        MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
                        else
-                               route.input = MSP_INPUT_DEFAULT;
+                               in = MSP_INPUT_DEFAULT;
                        break;
                }
-               route.output = MSP_OUTPUT_DEFAULT;
-               v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, &route);
+               v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
+                              in, MSP_OUTPUT_DEFAULT, 0);
        }
        if (btv->sd_tvaudio) {
-               struct v4l2_routing route;
-
-               route.input = input;
-               route.output = 0;
-               v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, &route);
+               v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
+                               input, 0, 0);
        }
        return 0;
 }
@@ -1329,7 +1326,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
                break;
        }
        id = tvnorm->v4l2_id;
-       bttv_call_all(btv, tuner, s_std, id);
+       bttv_call_all(btv, core, s_std, id);
 
        return 0;
 }
index 9649848..a1d0e9c 100644 (file)
@@ -26,7 +26,7 @@
 #define _BTTVP_H_
 
 #include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18)
 
 #include <linux/types.h>
 #include <linux/wait.h>
index 7abe94d..5f58272 100644 (file)
@@ -1954,7 +1954,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                goto out_freeirq;
 
        cam->sensor_addr = 0x42;
-       cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter,
+       cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
                        "ov7670", "ov7670", cam->sensor_addr);
        if (cam->sensor == NULL) {
                ret = -ENODEV;
index 9714059..57dc170 100644 (file)
@@ -53,14 +53,15 @@ static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs5345_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+static int cs5345_s_routing(struct v4l2_subdev *sd,
+                           u32 input, u32 output, u32 config)
 {
-       if ((route->input & 0xf) > 6) {
-               v4l2_err(sd, "Invalid input %d.\n", route->input);
+       if ((input & 0xf) > 6) {
+               v4l2_err(sd, "Invalid input %d.\n", input);
                return -EINVAL;
        }
-       cs5345_write(sd, 0x09, route->input & 0xf);
-       cs5345_write(sd, 0x05, route->input & 0xf0);
+       cs5345_write(sd, 0x09, input & 0xf);
+       cs5345_write(sd, 0x05, input & 0xf0);
        return 0;
 }
 
index 5aeb066..80bca8d 100644 (file)
@@ -58,17 +58,18 @@ static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+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 (route->input > 2) {
-               v4l2_err(sd, "Invalid input %d.\n", route->input);
+       if (input > 2) {
+               v4l2_err(sd, "Invalid input %d.\n", input);
                return -EINVAL;
        }
-       cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
+       cs53l32a_write(sd, 0x01, 0x01 + (input << 4));
        return 0;
 }
 
index bb5c516..1519e91 100644 (file)
@@ -33,7 +33,6 @@
 int cx18_audio_set_io(struct cx18 *cx)
 {
        const struct cx18_card_audio_input *in;
-       struct v4l2_routing route;
        u32 val;
        int err;
 
@@ -44,13 +43,11 @@ int cx18_audio_set_io(struct cx18 *cx)
                in = &cx->card->audio_inputs[cx->audio_input];
 
        /* handle muxer chips */
-       route.input = in->muxer_input;
-       route.output = 0;
-       v4l2_subdev_call(cx->sd_extmux, audio, s_routing, &route);
+       v4l2_subdev_call(cx->sd_extmux, audio, s_routing,
+                       in->audio_input, 0, 0);
 
-       route.input = in->audio_input;
        err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl,
-                              audio, s_routing, &route);
+                              audio, s_routing, in->audio_input, 0, 0);
        if (err)
                return err;
 
index f4dd9d7..cf2bd88 100644 (file)
@@ -203,43 +203,42 @@ static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
 
 static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx18_av_state *state = to_cx18_av_state(sd);
        struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       switch (val) {
-       case CX18_AV_INIT_PLLS:
-               /*
-                * 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.
-                */
+       /*
+        * 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  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);
+       /* 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);
+       /* 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);
-               break;
+       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+       return 0;
+}
 
-       case CX18_AV_INIT_NORMAL:
-       default:
-               if (!state->is_initialized) {
-                       /* initialize on first use */
-                       state->is_initialized = 1;
-                       cx18_av_initialize(cx);
-               }
-               break;
+static int cx18_av_load_fw(struct v4l2_subdev *sd)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       if (!state->is_initialized) {
+               /* initialize on first use */
+               state->is_initialized = 1;
+               cx18_av_initialize(cx);
        }
        return 0;
 }
@@ -548,19 +547,19 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 }
 
 static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
-                                  const struct v4l2_routing *route)
+                                  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, route->input, state->aud_input);
+       return set_input(cx, input, state->aud_input);
 }
 
 static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
-                                  const struct v4l2_routing *route)
+                                  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, route->input);
+       return set_input(cx, state->vid_input, input);
 }
 
 static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
@@ -1185,10 +1184,12 @@ 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,
        .init = cx18_av_init,
+       .load_fw = cx18_av_load_fw,
        .reset = cx18_av_reset,
        .queryctrl = cx18_av_queryctrl,
        .g_ctrl = cx18_av_g_ctrl,
        .s_ctrl = cx18_av_s_ctrl,
+       .s_std = cx18_av_s_std,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = cx18_av_g_register,
        .s_register = cx18_av_s_register,
@@ -1200,7 +1201,6 @@ static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
        .s_frequency = cx18_av_s_frequency,
        .g_tuner = cx18_av_g_tuner,
        .s_tuner = cx18_av_s_tuner,
-       .s_std = cx18_av_s_std,
 };
 
 static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
index c458120..9b84a0c 100644 (file)
@@ -328,11 +328,6 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
        return container_of(sd, struct cx18_av_state, sd);
 }
 
-enum cx18_av_subdev_init_arg {
-       CX18_AV_INIT_NORMAL = 0,
-       CX18_AV_INIT_PLLS = 1,
-};
-
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c                                                         */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
index 210c68a..49b1c3d 100644 (file)
@@ -810,7 +810,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
                CX18_ERR("Could not register A/V decoder subdevice\n");
                goto free_map;
        }
-       cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
+       cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0);
 
        /* Initialize GPIO Reset Controller to do chip resets during i2c init */
        if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
@@ -1028,7 +1028,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
        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, init, (u32) CX18_AV_INIT_NORMAL);
+       v4l2_subdev_call(cx->sd_av, core, load_fw);
 
        vf.tuner = 0;
        vf.type = V4L2_TUNER_ANALOG_TV;
index 4d7d6d5..b3889c0 100644 (file)
@@ -608,7 +608,7 @@ int cx18_v4l2_close(struct file *filp)
                /* 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, tuner, s_std, cx->std);
+               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) {
index 5518d14..86a204b 100644 (file)
@@ -156,12 +156,12 @@ static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
 }
 
 static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
-                                  const struct v4l2_routing *route)
+                                  u32 input, u32 output, u32 config)
 {
        struct cx18 *cx = v4l2_get_subdevdata(sd);
        u32 data;
 
-       switch (route->input) {
+       switch (input) {
        case 0:
                data = cx->card->gpio_audio_input.tuner;
                break;
@@ -180,10 +180,10 @@ static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
 
 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_std = gpiomux_s_std,
        .s_radio = gpiomux_s_radio,
 };
 
index d092643..b9b7064 100644 (file)
@@ -100,16 +100,16 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
 
        if (hw == CX18_HW_TUNER) {
                /* special tuner group handling */
-               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
-                                               cx->card_i2c->radio);
+               sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
+                               adap, mod, type, cx->card_i2c->radio);
                if (sd != NULL)
                        sd->grp_id = hw;
-               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
-                                               cx->card_i2c->demod);
+               sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
+                               adap, mod, type, cx->card_i2c->demod);
                if (sd != NULL)
                        sd->grp_id = hw;
-               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
-                                               cx->card_i2c->tv);
+               sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
+                               adap, mod, type, cx->card_i2c->tv);
                if (sd != NULL)
                        sd->grp_id = hw;
                return sd != NULL ? 0 : -1;
@@ -120,7 +120,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
                return -1;
 
        /* It's an I2C device other than an analog tuner */
-       sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
+       sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
        if (sd != NULL)
                sd->grp_id = hw;
        return sd != NULL ? 0 : -1;
index e4c9e3d..d7b1921 100644 (file)
@@ -705,7 +705,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
                        (unsigned long long) cx->std);
 
        /* Tuner */
-       cx18_call_all(cx, tuner, s_std, cx->std);
+       cx18_call_all(cx, core, s_std, cx->std);
        return 0;
 }
 
@@ -926,16 +926,6 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
        switch (cmd) {
-       case VIDIOC_INT_S_AUDIO_ROUTING: {
-               struct v4l2_routing *route = arg;
-
-               CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
-                       route->input, route->output);
-               cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing,
-                            route);
-               break;
-       }
-
        case VIDIOC_INT_RESET: {
                u32 val = *(u32 *)arg;
 
index 6fdaded..6dc84aa 100644 (file)
 
 void cx18_video_set_io(struct cx18 *cx)
 {
-       struct v4l2_routing route;
        int inp = cx->active_input;
-       u32 type;
 
-       route.input = cx->card->video_inputs[inp].video_input;
-       route.output = 0;
-       v4l2_subdev_call(cx->sd_av, video, s_routing, &route);
-
-       type = cx->card->video_inputs[inp].video_type;
-
-       if (type == CX18_CARD_INPUT_VID_TUNER)
-               route.input = 0;  /* Tuner */
-       else if (type < CX18_CARD_INPUT_COMPOSITE1)
-               route.input = 2;  /* S-Video */
-       else
-               route.input = 1;  /* Composite */
+       v4l2_subdev_call(cx->sd_av, video, s_routing,
+                       cx->card->video_inputs[inp].video_input, 0, 0);
 }
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
new file mode 100644 (file)
index 0000000..9115654
--- /dev/null
@@ -0,0 +1,35 @@
+config VIDEO_CX231XX
+       tristate "Conexant cx231xx USB video capture support"
+       depends on VIDEO_DEV && I2C && INPUT
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_IR
+       select VIDEOBUF_VMALLOC
+       select VIDEO_CX25840
+       select VIDEO_CX231XX_ALSA
+
+       ---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_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
+       select VIDEOBUF_DVB
+       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
+       ---help---
+        This adds support for DVB cards based on the
+        Conexant cx231xx chips.
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
new file mode 100644 (file)
index 0000000..755dd0c
--- /dev/null
@@ -0,0 +1,14 @@
+cx231xx-objs     := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
+                   cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.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
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
new file mode 100644 (file)
index 0000000..7793d60
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ *  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 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;
+
+       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 (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 int cx231xx_init_audio_isoc(struct cx231xx *dev)
+{
+       int i, errCode;
+       int sb_size;
+
+       cx231xx_info("%s: Starting AUDIO transfers\n", __func__);
+
+       sb_size = CX231XX_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_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_NUM_AUDIO_PACKETS;
+               urb->transfer_buffer_length = sb_size;
+
+               for (j = k = 0; j < CX231XX_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_cmd(struct cx231xx *dev, int cmd, int arg)
+{
+       dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
+               "stop" : "start");
+
+       switch (cmd) {
+       case CX231XX_CAPTURE_STREAM_EN:
+               if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
+                       dev->adev.capture_stream = STREAM_ON;
+                       cx231xx_init_audio_isoc(dev);
+               } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
+                       dev->adev.capture_stream = STREAM_OFF;
+                       cx231xx_isoc_audio_deinit(dev);
+               } else {
+                       cx231xx_errdev("An underrun very likely occurred. "
+                                      "Ignoring it.\n");
+               }
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+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;
+       }
+
+       /* Sets volume, mute, etc */
+       dev->mute = 0;
+
+       /* set alternate setting for audio interface */
+       /* 1 - 48000 samples per sec */
+       ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+       if (ret < 0) {
+               cx231xx_errdev("failed to set alternate setting !\n");
+
+               return ret;
+       }
+
+       /* inform hardware to start streaming */
+       ret = cx231xx_capture_start(dev, 1, Audio);
+
+       runtime->hw = snd_cx231xx_hw_capture;
+
+       mutex_lock(&dev->lock);
+       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");
+
+       /* 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");
+
+               return ret;
+       }
+
+       /* inform hardware to start streaming */
+       ret = cx231xx_capture_start(dev, 0, Audio);
+
+       dev->mute = 1;
+       mutex_lock(&dev->lock);
+       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");
+               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0);
+       }
+       return 0;
+}
+
+static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *hw_params)
+{
+       unsigned int channels, rate, format;
+       int ret;
+
+       dprintk("Setting capture parameters\n");
+
+       ret = snd_pcm_alloc_vmalloc_buffer(substream,
+                                          params_buffer_bytes(hw_params));
+       format = params_format(hw_params);
+       rate = params_rate(hw_params);
+       channels = params_channels(hw_params);
+
+       /* 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 */
+       return 0;
+}
+
+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 (dev->adev.capture_stream == STREAM_ON)
+               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+
+       return 0;
+}
+
+static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
+                                      int cmd)
+{
+       struct cx231xx *dev = snd_pcm_substream_chip(substream);
+       int retval;
+
+       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
+               "start" : "stop");
+
+       spin_lock(&dev->adev.slock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN,
+                           CX231XX_START_AUDIO);
+               retval = 0;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+               retval = 0;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+       spin_unlock(&dev->adev.slock);
+       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");
+       strcpy(card->driver, "Conexant cx231xx Audio");
+       strcpy(card->shortname, "Cx231xx Audio");
+       strcpy(card->longname, "Conexant cx231xx Audio");
+
+       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/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
new file mode 100644 (file)
index 0000000..1be3881
--- /dev/null
@@ -0,0 +1,2581 @@
+/*
+   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/version.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "cx231xx.h"
+
+/******************************************************************************
+                       -: BLOCK ARRANGEMENT :-
+       I2S block ----------------------|
+       [I2S audio]                     |
+                                       |
+       Analog Front End --> Direct IF -|-> Cx25840 --> Audio
+       [video & audio]                 |   [Audio]
+                                       |
+                                       |-> Cx25840 --> Video
+                                           [Video]
+
+*******************************************************************************/
+
+/******************************************************************************
+ *                    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:
+               /* SetupAFEforLowIF();  */
+               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_RDE_250:
+       case CX231XX_BOARD_CNXT_RDU_250:
+               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_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;
+                       }
+               }
+               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 vip 1.1 output mode */
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       OUT_CTRL1,
+                                                       FLD_OUT_MODE,
+                                                       OUT_MODE_VIP11);
+
+               /* 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:
+               switch (dev->model) {
+               case CX231XX_BOARD_CNXT_RDE_250:
+               case CX231XX_BOARD_CNXT_RDU_250:
+                       /* 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 vip 1.1 output mode */
+                       status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       OUT_CTRL1, FLD_OUT_MODE,
+                                                       OUT_MODE_VIP11);
+
+                       /* 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;
+               default:
+                       /* 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 vip 1.1 output mode */
+                       status = cx231xx_read_modify_write_i2c_dword(dev,
+                                               VID_BLK_I2C_ADDRESS,
+                                               OUT_CTRL1, FLD_OUT_MODE,
+                                               OUT_MODE_VIP11);
+
+                       /* 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);
+
+                       value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2;
+
+                       status = vid_blk_write_word(dev, AFE_CTRL, value);
+                       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;
+}
+
+/*
+ * 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,
+                                                       0x1E6000);
+               status = cx231xx_read_modify_write_i2c_dword(dev,
+                                                       VID_BLK_I2C_ADDRESS,
+                                                       VERT_TIM_CTRL,
+                                                       FLD_V656BLANK_CNT,
+                                                       0x1E000000);
+
+               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, 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, 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_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, 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:
+
+               /* 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);
+               switch (dev->model) {
+               case CX231XX_BOARD_CNXT_RDE_250:
+               case CX231XX_BOARD_CNXT_RDU_250:
+                       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;
+               default:
+                       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;
+}
+
+/* Set resolution of the video */
+int cx231xx_resolution_set(struct cx231xx *dev)
+{
+       int width, height;
+       u32 hscale, vscale;
+       int status = 0;
+
+       width = dev->width;
+       height = dev->height;
+
+       get_scale(dev, width, height, &hscale, &vscale);
+
+       /* set horzontal scale */
+       status = vid_blk_write_word(dev, HSCALE_CTRL, hscale);
+
+       /* set vertical scale */
+       status = vid_blk_write_word(dev, VSCALE_CTRL, vscale);
+
+       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_for_tuner(struct cx231xx *dev, u8 I2CIndex)
+{
+       u8 value[4] = { 0, 0, 0, 0 };
+       int status = 0;
+
+       cx231xx_info("Changing the i2c port for tuner to %d\n", I2CIndex);
+
+       status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+                                      PWR_CTL_EN, value, 4);
+       if (status < 0)
+               return status;
+
+       if (I2CIndex == I2C_1) {
+               if (value[0] & I2C_DEMOD_EN) {
+                       value[0] &= ~I2C_DEMOD_EN;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                                  PWR_CTL_EN, value, 4);
+               }
+       } else {
+               if (!(value[0] & I2C_DEMOD_EN)) {
+                       value[0] |= I2C_DEMOD_EN;
+                       status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                                                  PWR_CTL_EN, value, 4);
+               }
+       }
+
+       return status;
+
+}
+
+/******************************************************************************
+ *                 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_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_RDE_250:
+       case CX231XX_BOARD_CNXT_RDU_250:
+               func_mode = 0x03;
+               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,
+                                      &