Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Nov 2013 23:08:02 +0000 (15:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Nov 2013 23:08:02 +0000 (15:08 -0800)
Pull media updates from Mauro Carvalho Chehab:
 "This series include:
   - a new Remote Controller driver for ST SoC with the corresponding DT
     bindings
   - a new frontend (cx24117)
   - a new I2C camera flash driver (lm3560)
   - a new mem2mem driver for TI SoC (ti-vpe)
   - support for Raphael r828d added to r820t driver
   - some improvements on buffer allocation at VB2 core
   - usual driver fixes and improvements

  PS this time, we have a smaller number of patches.  While it is hard
  to pinpoint to the reasons, I believe that it is mainly due to:

   1) there are several patch series ready, but depending on DT review.
      I decided to grant some extra time for DT maintainers to look on
      it, as they're expecting to have more time with the changes agreed
      during ARM mini-summit and KS.  If they can't review in time for
      3.14, I'll review myself and apply for the next merge window.

   2) I suspect that having both LinuxCon EU and LinuxCon NA happening
      during the same merge window affected the development
      productivity, as several core media developers participated on
      both events"

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (151 commits)
  [media] media: st-rc: Add ST remote control driver
  [media] gpio-ir-recv: Include linux/of.h header
  [media] tvp7002: Include linux/of.h header
  [media] tvp514x: Include linux/of.h header
  [media] ths8200: Include linux/of.h header
  [media] adv7343: Include linux/of.h header
  [media] v4l: Fix typo in v4l2_subdev_get_try_crop()
  [media] media: i2c: add driver for dual LED Flash, lm3560
  [media] rtl28xxu: add 15f4:0131 Astrometa DVB-T2
  [media] rtl28xxu: add RTL2832P + R828D support
  [media] rtl2832: add new tuner R828D
  [media] r820t: add support for R828D
  [media] media/i2c: ths8200: fix build failure with gcc 4.5.4
  [media] Add support for KWorld UB435-Q V2
  [media] staging/media: fix msi3101 build errors
  [media] ddbridge: Remove casting the return value which is a void pointer
  [media] ngene: Remove casting the return value which is a void pointer
  [media] dm1105: remove unneeded not-null test
  [media] sh_mobile_ceu_camera: remove deprecated IRQF_DISABLED
  [media] media: rcar_vin: Add preliminary r8a7790 support
  ...

181 files changed:
Documentation/devicetree/bindings/media/st-rc.txt [new file with mode: 0644]
drivers/media/common/b2c2/flexcop-sram.c
drivers/media/common/saa7146/saa7146_core.c
drivers/media/common/siano/smscoreapi.c
drivers/media/common/siano/smsdvb-main.c
drivers/media/dvb-core/dvb_demux.c
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/cx24110.c
drivers/media/dvb-frontends/cx24117.c [new file with mode: 0644]
drivers/media/dvb-frontends/cx24117.h [new file with mode: 0644]
drivers/media/dvb-frontends/cx24123.c
drivers/media/dvb-frontends/cxd2820r_core.c
drivers/media/dvb-frontends/dib9000.c
drivers/media/dvb-frontends/drxd_hard.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/rtl2832.c
drivers/media/dvb-frontends/rtl2832.h
drivers/media/dvb-frontends/tda8083.c
drivers/media/dvb-frontends/ts2020.c
drivers/media/dvb-frontends/ts2020.h
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/adv7343.c
drivers/media/i2c/lm3560.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/imx074.c
drivers/media/i2c/soc_camera/ov9640.c
drivers/media/i2c/ths8200.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp7002.c
drivers/media/pci/b2c2/flexcop-pci.c
drivers/media/pci/bt8xx/bt878.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx23885/Kconfig
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-input.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885.h
drivers/media/pci/cx25821/cx25821-cards.c
drivers/media/pci/cx25821/cx25821-medusa-video.c
drivers/media/pci/cx25821/cx25821-medusa-video.h
drivers/media/pci/cx25821/cx25821-video-upstream.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/cx88/cx88-mpeg.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/mantis/mantis_pci.c
drivers/media/pci/meye/meye.c
drivers/media/pci/ngene/ngene-core.c
drivers/media/pci/pluto2/pluto2.c
drivers/media/pci/pt1/pt1.c
drivers/media/pci/saa7134/saa7134-alsa.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/zoran/zoran_card.c
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/coda.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/exynos-gsc/gsc-core.h
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/fimc-isp.c
drivers/media/platform/m2m-deinterlace.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mmp-driver.c
drivers/media/platform/mem2mem_testdev.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
drivers/media/platform/s5p-tv/mixer_grp_layer.c
drivers/media/platform/s5p-tv/mixer_vp_layer.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/ti-vpe/Makefile [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpdma.c [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpdma.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpdma_priv.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpe.c [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpe_regs.h [new file with mode: 0644]
drivers/media/platform/timblogiw.c
drivers/media/radio/radio-keene.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si4713-i2c.c
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/gpio-ir-recv.c
drivers/media/rc/ir-rx51.c
drivers/media/rc/st_rc.c [new file with mode: 0644]
drivers/media/rc/winbond-cir.c
drivers/media/tuners/fc0012.c
drivers/media/tuners/fc0013.c
drivers/media/tuners/r820t.c
drivers/media/tuners/tuner-xc2028.c
drivers/media/usb/b2c2/flexcop-usb.c
drivers/media/usb/cpia2/cpia2_usb.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.h
drivers/media/usb/dvb-usb/az6027.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/em28xx/em28xx-camera.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/gspca/conex.c
drivers/media/usb/gspca/cpia1.c
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/gspca.h
drivers/media/usb/gspca/jeilinj.c
drivers/media/usb/gspca/jl2005bcd.c
drivers/media/usb/gspca/m5602/m5602_mt9m111.c
drivers/media/usb/gspca/mars.c
drivers/media/usb/gspca/mr97310a.c
drivers/media/usb/gspca/nw80x.c
drivers/media/usb/gspca/ov519.c
drivers/media/usb/gspca/ov534.c
drivers/media/usb/gspca/ov534_9.c
drivers/media/usb/gspca/pac207.c
drivers/media/usb/gspca/pac7311.c
drivers/media/usb/gspca/se401.c
drivers/media/usb/gspca/sn9c20x.c
drivers/media/usb/gspca/sonixb.c
drivers/media/usb/gspca/sonixj.c
drivers/media/usb/gspca/spca1528.c
drivers/media/usb/gspca/spca500.c
drivers/media/usb/gspca/sq905c.c
drivers/media/usb/gspca/sq930x.c
drivers/media/usb/gspca/stk014.c
drivers/media/usb/gspca/stk1135.c
drivers/media/usb/gspca/stv06xx/stv06xx.c
drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/usb/gspca/sunplus.c
drivers/media/usb/gspca/topro.c
drivers/media/usb/gspca/tv8532.c
drivers/media/usb/gspca/vicam.c
drivers/media/usb/gspca/w996Xcf.c
drivers/media/usb/gspca/xirlink_cit.c
drivers/media/usb/gspca/zc3xx.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/siano/smsusb.c
drivers/media/usb/tlg2300/pd-main.c
drivers/media/usb/ttusb-dec/ttusb_dec.c
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/v4l2-core/tuner-core.c
drivers/media/v4l2-core/v4l2-clk.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-dma-sg.c
drivers/staging/media/lirc/TODO
drivers/staging/media/lirc/lirc_bt829.c
drivers/staging/media/msi3101/Kconfig
drivers/staging/media/solo6x10/solo6x10-disp.c
drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
drivers/staging/media/solo6x10/solo6x10.h
include/media/lm3560.h [new file with mode: 0644]
include/media/soc_camera.h
include/media/v4l2-clk.h
include/media/v4l2-common.h
include/media/v4l2-ctrls.h
include/media/v4l2-fh.h
include/media/v4l2-subdev.h
include/media/videobuf2-core.h
include/media/videobuf2-dma-sg.h
include/uapi/linux/v4l2-controls.h

diff --git a/Documentation/devicetree/bindings/media/st-rc.txt b/Documentation/devicetree/bindings/media/st-rc.txt
new file mode 100644 (file)
index 0000000..05c432d
--- /dev/null
@@ -0,0 +1,29 @@
+Device-Tree bindings for ST IRB IP
+
+Required properties:
+       - compatible: Should contain "st,comms-irb".
+       - reg: Base physical address of the controller and length of memory
+         mapped region.
+       - interrupts: interrupt-specifier for the sole interrupt generated by
+         the device. The interrupt specifier format depends on the interrupt
+         controller parent.
+       - rx-mode: can be "infrared" or "uhf". This property specifies the L1
+         protocol used for receiving remote control signals. rx-mode should
+         be present iff the rx pins are wired up.
+       - tx-mode: should be "infrared". This property specifies the L1
+         protocol used for transmitting remote control signals. tx-mode should
+         be present iff the tx pins are wired up.
+
+Optional properties:
+       - pinctrl-names, pinctrl-0: the pincontrol settings to configure muxing
+         properly for IRB pins.
+       - clocks : phandle with clock-specifier pair for IRB.
+
+Example node:
+
+       rc: rc@fe518000 {
+               compatible      = "st,comms-irb";
+               reg             = <0xfe518000 0x234>;
+               interrupts      = <0 203 0>;
+               rx-mode         = "infrared";
+       };
index f2199e4..185c285 100644 (file)
@@ -85,7 +85,7 @@ static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *
                while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
                        mdelay(1);
                        retries--;
-               };
+               }
 
                if (retries == 0)
                        printk("%s: SRAM timeout\n", __func__);
@@ -110,7 +110,7 @@ static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf,
                while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
                        mdelay(1);
                        retries--;
-               };
+               }
 
                if (retries == 0)
                        printk("%s: SRAM timeout\n", __func__);
@@ -122,7 +122,7 @@ static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf,
                while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
                        mdelay(1);
                        retries--;
-               };
+               }
 
                if (retries == 0)
                        printk("%s: SRAM timeout\n", __func__);
index bb6ee51..34b0d0d 100644 (file)
@@ -411,7 +411,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        saa7146_write(dev, MC2, 0xf8000000);
 
        /* request an interrupt for the saa7146 */
-       err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
+       err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED,
                          dev->name, dev);
        if (err < 0) {
                ERR("request_irq() failed\n");
@@ -524,8 +524,6 @@ static void saa7146_remove_one(struct pci_dev *pdev)
        DEB_EE("dev:%p\n", dev);
 
        dev->ext->detach(dev);
-       /* Zero the PCI drvdata after use. */
-       pci_set_drvdata(pdev, NULL);
 
        /* shut down all video dma transfers */
        saa7146_write(dev, MC1, 0x00ff0000);
index a142f79..050984c 100644 (file)
@@ -922,8 +922,8 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
        u32 i, *ptr;
        u8 *payload = firmware->payload;
        int rc = 0;
-       firmware->start_address = le32_to_cpu(firmware->start_address);
-       firmware->length = le32_to_cpu(firmware->length);
+       firmware->start_address = le32_to_cpup((__le32 *)&firmware->start_address);
+       firmware->length = le32_to_cpup((__le32 *)&firmware->length);
 
        mem_address = firmware->start_address;
 
@@ -982,7 +982,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
        if (rc < 0)
                goto exit_fw_download;
 
-       sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
+       sms_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
                calc_checksum);
        SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ,
                        sizeof(msg->x_msg_header) +
@@ -1562,7 +1562,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
                {
                        struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
 
-                       sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
+                       sms_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
                                validity->msg_data[0]);
                        complete(&coredev->data_validity_done);
                        break;
index 63676a8..85151ef 100644 (file)
@@ -44,14 +44,14 @@ module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
 
-u32 sms_to_guard_interval_table[] = {
+static u32 sms_to_guard_interval_table[] = {
        [0] = GUARD_INTERVAL_1_32,
        [1] = GUARD_INTERVAL_1_16,
        [2] = GUARD_INTERVAL_1_8,
        [3] = GUARD_INTERVAL_1_4,
 };
 
-u32 sms_to_code_rate_table[] = {
+static u32 sms_to_code_rate_table[] = {
        [0] = FEC_1_2,
        [1] = FEC_2_3,
        [2] = FEC_3_4,
@@ -60,14 +60,14 @@ u32 sms_to_code_rate_table[] = {
 };
 
 
-u32 sms_to_hierarchy_table[] = {
+static u32 sms_to_hierarchy_table[] = {
        [0] = HIERARCHY_NONE,
        [1] = HIERARCHY_1,
        [2] = HIERARCHY_2,
        [3] = HIERARCHY_4,
 };
 
-u32 sms_to_modulation_table[] = {
+static u32 sms_to_modulation_table[] = {
        [0] = QPSK,
        [1] = QAM_16,
        [2] = QAM_64,
index 3485655..58de441 100644 (file)
@@ -476,7 +476,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
                              size_t count)
 {
-       spin_lock(&demux->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&demux->lock, flags);
 
        while (count--) {
                if (buf[0] == 0x47)
@@ -484,7 +486,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
                buf += 188;
        }
 
-       spin_unlock(&demux->lock);
+       spin_unlock_irqrestore(&demux->lock, flags);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
@@ -519,8 +521,9 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
 {
        int p = 0, i, j;
        const u8 *q;
+       unsigned long flags;
 
-       spin_lock(&demux->lock);
+       spin_lock_irqsave(&demux->lock, flags);
 
        if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
                i = demux->tsbufp;
@@ -564,7 +567,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
        }
 
 bailout:
-       spin_unlock(&demux->lock);
+       spin_unlock_irqrestore(&demux->lock, flags);
 }
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@@ -581,11 +584,13 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
 void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-       spin_lock(&demux->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&demux->lock, flags);
 
        demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
 
-       spin_unlock(&demux->lock);
+       spin_unlock_irqrestore(&demux->lock, flags);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
 
index 0e2ec6f..bddbab4 100644 (file)
@@ -200,6 +200,13 @@ config DVB_CX24116
        help
          A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
 
+config DVB_CX24117
+       tristate "Conexant CX24117 based"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
 config DVB_SI21XX
        tristate "Silicon Labs SI21XX based"
        depends on DVB_CORE && I2C
index cebc0fa..f9cb43d 100644 (file)
@@ -76,6 +76,7 @@ obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
 obj-$(CONFIG_DVB_AF9013) += af9013.o
 obj-$(CONFIG_DVB_CX24116) += cx24116.o
+obj-$(CONFIG_DVB_CX24117) += cx24117.o
 obj-$(CONFIG_DVB_SI21XX) += si21xx.o
 obj-$(CONFIG_DVB_STV0288) += stv0288.o
 obj-$(CONFIG_DVB_STB6000) += stb6000.o
index 0cd6927..95b981c 100644 (file)
@@ -378,7 +378,7 @@ static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
                return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
        default:
                return -EINVAL;
-       };
+       }
 }
 
 static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c
new file mode 100644 (file)
index 0000000..476b422
--- /dev/null
@@ -0,0 +1,1650 @@
+/*
+    Conexant cx24117/cx24132 - Dual DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2013 Luis Alves <ljalvs@gmail.com>
+       July, 6th 2013
+           First release based on cx24116 driver by:
+           Steven Toth and Georg Acher, Darron Broad, Igor Liplianin
+           Cards currently supported:
+               TBS6980 - Dual DVBS/S2 PCIe card
+               TBS6981 - Dual DVBS/S2 PCIe card
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "tuner-i2c.h"
+#include "dvb_frontend.h"
+#include "cx24117.h"
+
+
+#define CX24117_DEFAULT_FIRMWARE "dvb-fe-cx24117.fw"
+#define CX24117_SEARCH_RANGE_KHZ 5000
+
+/* known registers */
+#define CX24117_REG_COMMAND      (0x00)      /* command buffer */
+#define CX24117_REG_EXECUTE      (0x1f)      /* execute command */
+
+#define CX24117_REG_FREQ3_0      (0x34)      /* frequency */
+#define CX24117_REG_FREQ2_0      (0x35)
+#define CX24117_REG_FREQ1_0      (0x36)
+#define CX24117_REG_STATE0       (0x39)
+#define CX24117_REG_SSTATUS0     (0x3a)      /* demod0 signal high / status */
+#define CX24117_REG_SIGNAL0      (0x3b)
+#define CX24117_REG_FREQ5_0      (0x3c)      /* +-freq */
+#define CX24117_REG_FREQ6_0      (0x3d)
+#define CX24117_REG_SRATE2_0     (0x3e)      /* +- 1000 * srate */
+#define CX24117_REG_SRATE1_0     (0x3f)
+#define CX24117_REG_QUALITY2_0   (0x40)
+#define CX24117_REG_QUALITY1_0   (0x41)
+
+#define CX24117_REG_BER4_0       (0x47)
+#define CX24117_REG_BER3_0       (0x48)
+#define CX24117_REG_BER2_0       (0x49)
+#define CX24117_REG_BER1_0       (0x4a)
+#define CX24117_REG_DVBS_UCB2_0  (0x4b)
+#define CX24117_REG_DVBS_UCB1_0  (0x4c)
+#define CX24117_REG_DVBS2_UCB2_0 (0x50)
+#define CX24117_REG_DVBS2_UCB1_0 (0x51)
+#define CX24117_REG_QSTATUS0     (0x93)
+#define CX24117_REG_CLKDIV0      (0xe6)
+#define CX24117_REG_RATEDIV0     (0xf0)
+
+
+#define CX24117_REG_FREQ3_1      (0x55)      /* frequency */
+#define CX24117_REG_FREQ2_1      (0x56)
+#define CX24117_REG_FREQ1_1      (0x57)
+#define CX24117_REG_STATE1       (0x5a)
+#define CX24117_REG_SSTATUS1     (0x5b)      /* demod1 signal high / status */
+#define CX24117_REG_SIGNAL1      (0x5c)
+#define CX24117_REG_FREQ5_1      (0x5d)      /* +- freq */
+#define CX24117_REG_FREQ4_1      (0x5e)
+#define CX24117_REG_SRATE2_1     (0x5f)
+#define CX24117_REG_SRATE1_1     (0x60)
+#define CX24117_REG_QUALITY2_1   (0x61)
+#define CX24117_REG_QUALITY1_1   (0x62)
+#define CX24117_REG_BER4_1       (0x68)
+#define CX24117_REG_BER3_1       (0x69)
+#define CX24117_REG_BER2_1       (0x6a)
+#define CX24117_REG_BER1_1       (0x6b)
+#define CX24117_REG_DVBS_UCB2_1  (0x6c)
+#define CX24117_REG_DVBS_UCB1_1  (0x6d)
+#define CX24117_REG_DVBS2_UCB2_1 (0x71)
+#define CX24117_REG_DVBS2_UCB1_1 (0x72)
+#define CX24117_REG_QSTATUS1     (0x9f)
+#define CX24117_REG_CLKDIV1      (0xe7)
+#define CX24117_REG_RATEDIV1     (0xf1)
+
+
+/* arg buffer size */
+#define CX24117_ARGLEN       (0x1e)
+
+/* rolloff */
+#define CX24117_ROLLOFF_020  (0x00)
+#define CX24117_ROLLOFF_025  (0x01)
+#define CX24117_ROLLOFF_035  (0x02)
+
+/* pilot bit */
+#define CX24117_PILOT_OFF    (0x00)
+#define CX24117_PILOT_ON     (0x40)
+#define CX24117_PILOT_AUTO   (0x80)
+
+/* signal status */
+#define CX24117_HAS_SIGNAL   (0x01)
+#define CX24117_HAS_CARRIER  (0x02)
+#define CX24117_HAS_VITERBI  (0x04)
+#define CX24117_HAS_SYNCLOCK (0x08)
+#define CX24117_STATUS_MASK  (0x0f)
+#define CX24117_SIGNAL_MASK  (0xc0)
+
+
+/* arg offset for DiSEqC */
+#define CX24117_DISEQC_DEMOD  (1)
+#define CX24117_DISEQC_BURST  (2)
+#define CX24117_DISEQC_ARG3_2 (3)   /* unknown value=2 */
+#define CX24117_DISEQC_ARG4_0 (4)   /* unknown value=0 */
+#define CX24117_DISEQC_ARG5_0 (5)   /* unknown value=0 */
+#define CX24117_DISEQC_MSGLEN (6)
+#define CX24117_DISEQC_MSGOFS (7)
+
+/* DiSEqC burst */
+#define CX24117_DISEQC_MINI_A (0)
+#define CX24117_DISEQC_MINI_B (1)
+
+
+#define CX24117_PNE    (0) /* 0 disabled / 2 enabled */
+#define CX24117_OCC    (1) /* 0 disabled / 1 enabled */
+
+
+enum cmds {
+       CMD_SET_VCO     = 0x10,
+       CMD_TUNEREQUEST = 0x11,
+       CMD_MPEGCONFIG  = 0x13,
+       CMD_TUNERINIT   = 0x14,
+       CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
+       CMD_LNBDCLEVEL  = 0x22,
+       CMD_SET_TONE    = 0x23,
+       CMD_UPDFWVERS   = 0x35,
+       CMD_TUNERSLEEP  = 0x36,
+};
+
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(cx24117_list_mutex);
+
+/* The Demod/Tuner can't easily provide these, we cache them */
+struct cx24117_tuning {
+       u32 frequency;
+       u32 symbol_rate;
+       fe_spectral_inversion_t inversion;
+       fe_code_rate_t fec;
+
+       fe_delivery_system_t delsys;
+       fe_modulation_t modulation;
+       fe_pilot_t pilot;
+       fe_rolloff_t rolloff;
+
+       /* Demod values */
+       u8 fec_val;
+       u8 fec_mask;
+       u8 inversion_val;
+       u8 pilot_val;
+       u8 rolloff_val;
+};
+
+/* Basic commands that are sent to the firmware */
+struct cx24117_cmd {
+       u8 len;
+       u8 args[CX24117_ARGLEN];
+};
+
+/* common to both fe's */
+struct cx24117_priv {
+       u8 demod_address;
+       struct i2c_adapter *i2c;
+       u8 skip_fw_load;
+       struct mutex fe_lock;
+
+       /* Used for sharing this struct between demods */
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+};
+
+/* one per each fe */
+struct cx24117_state {
+       struct cx24117_priv *priv;
+       struct dvb_frontend frontend;
+
+       struct cx24117_tuning dcur;
+       struct cx24117_tuning dnxt;
+       struct cx24117_cmd dsec_cmd;
+
+       int demod;
+};
+
+/* modfec (modulation and FEC) lookup table */
+/* Check cx24116.c for a detailed description of each field */
+static struct cx24117_modfec {
+       fe_delivery_system_t delivery_system;
+       fe_modulation_t modulation;
+       fe_code_rate_t fec;
+       u8 mask;        /* In DVBS mode this is used to autodetect */
+       u8 val;         /* Passed to the firmware to indicate mode selection */
+} cx24117_modfec_modes[] = {
+       /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
+
+       /*mod   fec       mask  val */
+       { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
+       { SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
+       { SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
+       { SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
+       { SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
+       { SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
+       { SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
+       { SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
+       { SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
+       { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
+       /* NBC-QPSK */
+       { SYS_DVBS2, QPSK, FEC_NONE, 0x00, 0x00 },
+       { SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
+       { SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
+       { SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
+       { SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
+       { SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
+       { SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
+       { SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
+       { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
+       { SYS_DVBS2, QPSK, FEC_AUTO, 0x00, 0x00 },
+       /* 8PSK */
+       { SYS_DVBS2, PSK_8, FEC_NONE, 0x00, 0x00 },
+       { SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
+       { SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
+       { SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
+       { SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
+       { SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
+       { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
+       { SYS_DVBS2, PSK_8, FEC_AUTO, 0x00, 0x00 },
+       /*
+        * 'val' can be found in the FECSTATUS register when tuning.
+        * FECSTATUS will give the actual FEC in use if tuning was successful.
+        */
+};
+
+
+static int cx24117_writereg(struct cx24117_state *state, u8 reg, u8 data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->priv->demod_address,
+               .flags = 0, .buf = buf, .len = 2 };
+       int ret;
+
+       dev_dbg(&state->priv->i2c->dev,
+                       "%s() demod%d i2c wr @0x%02x=0x%02x\n",
+                       __func__, state->demod, reg, data);
+
+       ret = i2c_transfer(state->priv->i2c, &msg, 1);
+       if (ret < 0) {
+               dev_warn(&state->priv->i2c->dev,
+                       "%s: demod%d i2c wr err(%i) @0x%02x=0x%02x\n",
+                       KBUILD_MODNAME, state->demod, ret, reg, data);
+               return ret;
+       }
+       return 0;
+}
+
+static int cx24117_writecmd(struct cx24117_state *state,
+       struct cx24117_cmd *cmd)
+{
+       struct i2c_msg msg;
+       u8 buf[CX24117_ARGLEN+1];
+       int ret;
+
+       dev_dbg(&state->priv->i2c->dev,
+                       "%s() demod%d i2c wr cmd len=%d\n",
+                       __func__, state->demod, cmd->len);
+
+       buf[0] = CX24117_REG_COMMAND;
+       memcpy(&buf[1], cmd->args, cmd->len);
+
+       msg.addr = state->priv->demod_address;
+       msg.flags = 0;
+       msg.len = cmd->len+1;
+       msg.buf = buf;
+       ret = i2c_transfer(state->priv->i2c, &msg, 1);
+       if (ret < 0) {
+               dev_warn(&state->priv->i2c->dev,
+                       "%s: demod%d i2c wr cmd err(%i) len=%d\n",
+                       KBUILD_MODNAME, state->demod, ret, cmd->len);
+               return ret;
+       }
+       return 0;
+}
+
+static int cx24117_readreg(struct cx24117_state *state, u8 reg)
+{
+       int ret;
+       u8 recv = 0;
+       struct i2c_msg msg[] = {
+               { .addr = state->priv->demod_address, .flags = 0,
+                       .buf = &reg, .len = 1 },
+               { .addr = state->priv->demod_address, .flags = I2C_M_RD,
+                       .buf = &recv, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->priv->i2c, msg, 2);
+       if (ret < 0) {
+               dev_warn(&state->priv->i2c->dev,
+                       "%s: demod%d i2c rd err(%d) @0x%x\n",
+                       KBUILD_MODNAME, state->demod, ret, reg);
+               return ret;
+       }
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d i2c rd @0x%02x=0x%02x\n",
+               __func__, state->demod, reg, recv);
+
+       return recv;
+}
+
+static int cx24117_readregN(struct cx24117_state *state,
+       u8 reg, u8 *buf, int len)
+{
+       int ret;
+       struct i2c_msg msg[] = {
+               { .addr = state->priv->demod_address, .flags = 0,
+                       .buf = &reg, .len = 1 },
+               { .addr = state->priv->demod_address, .flags = I2C_M_RD,
+                       .buf = buf, .len = len }
+       };
+
+       ret = i2c_transfer(state->priv->i2c, msg, 2);
+       if (ret < 0) {
+               dev_warn(&state->priv->i2c->dev,
+                       "%s: demod%d i2c rd err(%d) @0x%x\n",
+                       KBUILD_MODNAME, state->demod, ret, reg);
+               return ret;
+       }
+       return 0;
+}
+
+static int cx24117_set_inversion(struct cx24117_state *state,
+       fe_spectral_inversion_t inversion)
+{
+       dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
+               __func__, inversion, state->demod);
+
+       switch (inversion) {
+       case INVERSION_OFF:
+               state->dnxt.inversion_val = 0x00;
+               break;
+       case INVERSION_ON:
+               state->dnxt.inversion_val = 0x04;
+               break;
+       case INVERSION_AUTO:
+               state->dnxt.inversion_val = 0x0C;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       state->dnxt.inversion = inversion;
+
+       return 0;
+}
+
+static int cx24117_lookup_fecmod(struct cx24117_state *state,
+       fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
+{
+       int i, ret = -EINVAL;
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s(demod(0x%02x,0x%02x) demod%d\n",
+               __func__, m, f, state->demod);
+
+       for (i = 0; i < ARRAY_SIZE(cx24117_modfec_modes); i++) {
+               if ((d == cx24117_modfec_modes[i].delivery_system) &&
+                       (m == cx24117_modfec_modes[i].modulation) &&
+                       (f == cx24117_modfec_modes[i].fec)) {
+                               ret = i;
+                               break;
+                       }
+       }
+
+       return ret;
+}
+
+static int cx24117_set_fec(struct cx24117_state *state,
+       fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
+{
+       int ret;
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s(0x%02x,0x%02x) demod%d\n",
+               __func__, mod, fec, state->demod);
+
+       ret = cx24117_lookup_fecmod(state, delsys, mod, fec);
+       if (ret < 0)
+               return ret;
+
+       state->dnxt.fec = fec;
+       state->dnxt.fec_val = cx24117_modfec_modes[ret].val;
+       state->dnxt.fec_mask = cx24117_modfec_modes[ret].mask;
+       dev_dbg(&state->priv->i2c->dev,
+               "%s() demod%d mask/val = 0x%02x/0x%02x\n", __func__,
+               state->demod, state->dnxt.fec_mask, state->dnxt.fec_val);
+
+       return 0;
+}
+
+static int cx24117_set_symbolrate(struct cx24117_state *state, u32 rate)
+{
+       dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
+               __func__, rate, state->demod);
+
+       state->dnxt.symbol_rate = rate;
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s() demod%d symbol_rate = %d\n",
+               __func__, state->demod, rate);
+
+       return 0;
+}
+
+static int cx24117_load_firmware(struct dvb_frontend *fe,
+       const struct firmware *fw);
+
+static int cx24117_firmware_ondemand(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       const struct firmware *fw;
+       int ret = 0;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d skip_fw_load=%d\n",
+               __func__, state->demod, state->priv->skip_fw_load);
+
+       if (state->priv->skip_fw_load)
+               return 0;
+
+       /* check if firmware if already running */
+       if (cx24117_readreg(state, 0xeb) != 0xa) {
+               /* Load firmware */
+               /* request the firmware, this will block until loaded */
+               dev_dbg(&state->priv->i2c->dev,
+                       "%s: Waiting for firmware upload (%s)...\n",
+                       __func__, CX24117_DEFAULT_FIRMWARE);
+               ret = request_firmware(&fw, CX24117_DEFAULT_FIRMWARE,
+                       state->priv->i2c->dev.parent);
+               dev_dbg(&state->priv->i2c->dev,
+                       "%s: Waiting for firmware upload(2)...\n", __func__);
+               if (ret) {
+                       dev_err(&state->priv->i2c->dev,
+                               "%s: No firmware uploaded "
+                               "(timeout or file not found?)\n", __func__);
+                       return ret;
+               }
+
+               /* Make sure we don't recurse back through here
+                * during loading */
+               state->priv->skip_fw_load = 1;
+
+               ret = cx24117_load_firmware(fe, fw);
+               if (ret)
+                       dev_err(&state->priv->i2c->dev,
+                               "%s: Writing firmware failed\n", __func__);
+               release_firmware(fw);
+
+               dev_info(&state->priv->i2c->dev,
+                       "%s: Firmware upload %s\n", __func__,
+                       ret == 0 ? "complete" : "failed");
+
+               /* Ensure firmware is always loaded if required */
+               state->priv->skip_fw_load = 0;
+       }
+
+       return ret;
+}
+
+/* Take a basic firmware command structure, format it
+ * and forward it for processing
+ */
+static int cx24117_cmd_execute_nolock(struct dvb_frontend *fe,
+       struct cx24117_cmd *cmd)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int i, ret;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
+               __func__, state->demod);
+
+       /* Load the firmware if required */
+       ret = cx24117_firmware_ondemand(fe);
+       if (ret != 0)
+               return ret;
+
+       /* Write the command */
+       cx24117_writecmd(state, cmd);
+
+       /* Start execution and wait for cmd to terminate */
+       cx24117_writereg(state, CX24117_REG_EXECUTE, 0x01);
+       i = 0;
+       while (cx24117_readreg(state, CX24117_REG_EXECUTE)) {
+               msleep(20);
+               if (i++ > 40) {
+                       /* Avoid looping forever if the firmware does
+                               not respond */
+                       dev_warn(&state->priv->i2c->dev,
+                               "%s() Firmware not responding\n", __func__);
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+static int cx24117_cmd_execute(struct dvb_frontend *fe, struct cx24117_cmd *cmd)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int ret;
+
+       mutex_lock(&state->priv->fe_lock);
+       ret = cx24117_cmd_execute_nolock(fe, cmd);
+       mutex_unlock(&state->priv->fe_lock);
+
+       return ret;
+}
+
+static int cx24117_load_firmware(struct dvb_frontend *fe,
+       const struct firmware *fw)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+       int i, ret;
+       unsigned char vers[4];
+
+       struct i2c_msg msg;
+       u8 *buf;
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s() demod%d FW is %zu bytes (%02x %02x .. %02x %02x)\n",
+               __func__, state->demod, fw->size, fw->data[0], fw->data[1],
+               fw->data[fw->size - 2], fw->data[fw->size - 1]);
+
+       cx24117_writereg(state, 0xea, 0x00);
+       cx24117_writereg(state, 0xea, 0x01);
+       cx24117_writereg(state, 0xea, 0x00);
+
+       cx24117_writereg(state, 0xce, 0x92);
+
+       cx24117_writereg(state, 0xfb, 0x00);
+       cx24117_writereg(state, 0xfc, 0x00);
+
+       cx24117_writereg(state, 0xc3, 0x04);
+       cx24117_writereg(state, 0xc4, 0x04);
+
+       cx24117_writereg(state, 0xce, 0x00);
+       cx24117_writereg(state, 0xcf, 0x00);
+
+       cx24117_writereg(state, 0xea, 0x00);
+       cx24117_writereg(state, 0xeb, 0x0c);
+       cx24117_writereg(state, 0xec, 0x06);
+       cx24117_writereg(state, 0xed, 0x05);
+       cx24117_writereg(state, 0xee, 0x03);
+       cx24117_writereg(state, 0xef, 0x05);
+
+       cx24117_writereg(state, 0xf3, 0x03);
+       cx24117_writereg(state, 0xf4, 0x44);
+
+       cx24117_writereg(state, CX24117_REG_RATEDIV0, 0x04);
+       cx24117_writereg(state, CX24117_REG_CLKDIV0, 0x02);
+
+       cx24117_writereg(state, CX24117_REG_RATEDIV1, 0x04);
+       cx24117_writereg(state, CX24117_REG_CLKDIV1, 0x02);
+
+       cx24117_writereg(state, 0xf2, 0x04);
+       cx24117_writereg(state, 0xe8, 0x02);
+       cx24117_writereg(state, 0xea, 0x01);
+       cx24117_writereg(state, 0xc8, 0x00);
+       cx24117_writereg(state, 0xc9, 0x00);
+       cx24117_writereg(state, 0xca, 0x00);
+       cx24117_writereg(state, 0xcb, 0x00);
+       cx24117_writereg(state, 0xcc, 0x00);
+       cx24117_writereg(state, 0xcd, 0x00);
+       cx24117_writereg(state, 0xe4, 0x03);
+       cx24117_writereg(state, 0xeb, 0x0a);
+
+       cx24117_writereg(state, 0xfb, 0x00);
+       cx24117_writereg(state, 0xe0, 0x76);
+       cx24117_writereg(state, 0xf7, 0x81);
+       cx24117_writereg(state, 0xf8, 0x00);
+       cx24117_writereg(state, 0xf9, 0x00);
+
+       buf = kmalloc(fw->size + 1, GFP_KERNEL);
+       if (buf == NULL) {
+               state->priv->skip_fw_load = 0;
+               return -ENOMEM;
+       }
+
+       /* fw upload reg */
+       buf[0] = 0xfa;
+       memcpy(&buf[1], fw->data, fw->size);
+
+       /* prepare i2c message to send */
+       msg.addr = state->priv->demod_address;
+       msg.flags = 0;
+       msg.len = fw->size + 1;
+       msg.buf = buf;
+
+       /* send fw */
+       ret = i2c_transfer(state->priv->i2c, &msg, 1);
+       if (ret < 0)
+               return ret;
+
+       kfree(buf);
+
+       cx24117_writereg(state, 0xf7, 0x0c);
+       cx24117_writereg(state, 0xe0, 0x00);
+
+       /* CMD 1B */
+       cmd.args[0] = 0x1b;
+       cmd.args[1] = 0x00;
+       cmd.args[2] = 0x01;
+       cmd.args[3] = 0x00;
+       cmd.len = 4;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto error;
+
+       /* CMD 10 */
+       cmd.args[0] = CMD_SET_VCO;
+       cmd.args[1] = 0x06;
+       cmd.args[2] = 0x2b;
+       cmd.args[3] = 0xd8;
+       cmd.args[4] = 0xa5;
+       cmd.args[5] = 0xee;
+       cmd.args[6] = 0x03;
+       cmd.args[7] = 0x9d;
+       cmd.args[8] = 0xfc;
+       cmd.args[9] = 0x06;
+       cmd.args[10] = 0x02;
+       cmd.args[11] = 0x9d;
+       cmd.args[12] = 0xfc;
+       cmd.len = 13;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto error;
+
+       /* CMD 15 */
+       cmd.args[0] = 0x15;
+       cmd.args[1] = 0x00;
+       cmd.args[2] = 0x01;
+       cmd.args[3] = 0x00;
+       cmd.args[4] = 0x00;
+       cmd.args[5] = 0x01;
+       cmd.args[6] = 0x01;
+       cmd.args[7] = 0x01;
+       cmd.args[8] = 0x00;
+       cmd.args[9] = 0x05;
+       cmd.args[10] = 0x02;
+       cmd.args[11] = 0x02;
+       cmd.args[12] = 0x00;
+       cmd.len = 13;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto error;
+
+       /* CMD 13 */
+       cmd.args[0] = CMD_MPEGCONFIG;
+       cmd.args[1] = 0x00;
+       cmd.args[2] = 0x00;
+       cmd.args[3] = 0x00;
+       cmd.args[4] = 0x01;
+       cmd.args[5] = 0x00;
+       cmd.len = 6;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto error;
+
+       /* CMD 14 */
+       for (i = 0; i < 2; i++) {
+               cmd.args[0] = CMD_TUNERINIT;
+               cmd.args[1] = (u8) i;
+               cmd.args[2] = 0x00;
+               cmd.args[3] = 0x05;
+               cmd.args[4] = 0x00;
+               cmd.args[5] = 0x00;
+               cmd.args[6] = 0x55;
+               cmd.args[7] = 0x00;
+               cmd.len = 8;
+               ret = cx24117_cmd_execute_nolock(fe, &cmd);
+               if (ret != 0)
+                       goto error;
+       }
+
+       cx24117_writereg(state, 0xce, 0xc0);
+       cx24117_writereg(state, 0xcf, 0x00);
+       cx24117_writereg(state, 0xe5, 0x04);
+
+       /* Firmware CMD 35: Get firmware version */
+       cmd.args[0] = CMD_UPDFWVERS;
+       cmd.len = 2;
+       for (i = 0; i < 4; i++) {
+               cmd.args[1] = i;
+               ret = cx24117_cmd_execute_nolock(fe, &cmd);
+               if (ret != 0)
+                       goto error;
+               vers[i] = cx24117_readreg(state, 0x33);
+       }
+       dev_info(&state->priv->i2c->dev,
+               "%s: FW version %i.%i.%i.%i\n", __func__,
+               vers[0], vers[1], vers[2], vers[3]);
+       return 0;
+error:
+       state->priv->skip_fw_load = 0;
+       dev_err(&state->priv->i2c->dev, "%s() Error running FW.\n", __func__);
+       return ret;
+}
+
+static int cx24117_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int lock;
+
+       lock = cx24117_readreg(state,
+               (state->demod == 0) ? CX24117_REG_SSTATUS0 :
+                                     CX24117_REG_SSTATUS1) &
+               CX24117_STATUS_MASK;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d status = 0x%02x\n",
+               __func__, state->demod, lock);
+
+       *status = 0;
+
+       if (lock & CX24117_HAS_SIGNAL)
+               *status |= FE_HAS_SIGNAL;
+       if (lock & CX24117_HAS_CARRIER)
+               *status |= FE_HAS_CARRIER;
+       if (lock & CX24117_HAS_VITERBI)
+               *status |= FE_HAS_VITERBI;
+       if (lock & CX24117_HAS_SYNCLOCK)
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int cx24117_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int ret;
+       u8 buf[4];
+       u8 base_reg = (state->demod == 0) ?
+                       CX24117_REG_BER4_0 :
+                       CX24117_REG_BER4_1;
+
+       ret = cx24117_readregN(state, base_reg, buf, 4);
+       if (ret != 0)
+               return ret;
+
+       *ber = (buf[0] << 24) | (buf[1] << 16) |
+               (buf[1] << 8) | buf[0];
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d ber=0x%04x\n",
+               __func__, state->demod, *ber);
+
+       return 0;
+}
+
+static int cx24117_read_signal_strength(struct dvb_frontend *fe,
+       u16 *signal_strength)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+       int ret;
+       u16 sig_reading;
+       u8 buf[2];
+       u8 reg = (state->demod == 0) ?
+               CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1;
+
+       /* Firmware CMD 1A */
+       cmd.args[0] = 0x1a;
+       cmd.args[1] = (u8) state->demod;
+       cmd.len = 2;
+       ret = cx24117_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       ret = cx24117_readregN(state, reg, buf, 2);
+       if (ret != 0)
+               return ret;
+       sig_reading = ((buf[0] & CX24117_SIGNAL_MASK) << 2) | buf[1];
+
+       *signal_strength = -100 * sig_reading + 94324;
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s() demod%d raw / cooked = 0x%04x / 0x%04x\n",
+               __func__, state->demod, sig_reading, *signal_strength);
+
+       return 0;
+}
+
+static int cx24117_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int ret;
+       u8 buf[2];
+       u8 reg = (state->demod == 0) ?
+               CX24117_REG_QUALITY2_0 : CX24117_REG_QUALITY2_1;
+
+       ret = cx24117_readregN(state, reg, buf, 2);
+       if (ret != 0)
+               return ret;
+
+       *snr = (buf[0] << 8) | buf[1];
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s() demod%d snr = 0x%04x\n",
+               __func__, state->demod, *snr);
+
+       return ret;
+}
+
+static int cx24117_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       fe_delivery_system_t delsys = fe->dtv_property_cache.delivery_system;
+       int ret;
+       u8 buf[2];
+       u8 reg = (state->demod == 0) ?
+               CX24117_REG_DVBS_UCB2_0 :
+               CX24117_REG_DVBS_UCB2_1;
+
+       switch (delsys) {
+       case SYS_DVBS:
+               break;
+       case SYS_DVBS2:
+               reg += (CX24117_REG_DVBS2_UCB2_0 - CX24117_REG_DVBS_UCB2_0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = cx24117_readregN(state, reg, buf, 2);
+       if (ret != 0)
+               return ret;
+       *ucblocks = (buf[0] << 8) | buf[1];
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d ucb=0x%04x\n",
+               __func__, state->demod, *ucblocks);
+
+       return 0;
+}
+
+/* Overwrite the current tuning params, we are about to tune */
+static void cx24117_clone_params(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       state->dcur = state->dnxt;
+}
+
+/* Wait for LNB */
+static int cx24117_wait_for_lnb(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int i;
+       u8 val, reg = (state->demod == 0) ? CX24117_REG_QSTATUS0 :
+                                           CX24117_REG_QSTATUS1;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d qstatus = 0x%02x\n",
+               __func__, state->demod, cx24117_readreg(state, reg));
+
+       /* Wait for up to 300 ms */
+       for (i = 0; i < 10; i++) {
+               val = cx24117_readreg(state, reg) & 0x01;
+               if (val != 0)
+                       return 0;
+               msleep(30);
+       }
+
+       dev_warn(&state->priv->i2c->dev, "%s: demod%d LNB not ready\n",
+               KBUILD_MODNAME, state->demod);
+
+       return -ETIMEDOUT; /* -EBUSY ? */
+}
+
+static int cx24117_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+       int ret;
+       u8 reg = (state->demod == 0) ? 0x10 : 0x20;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d %s\n",
+               __func__, state->demod,
+               voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+               voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" :
+               "SEC_VOLTAGE_OFF");
+
+       /* CMD 32 */
+       cmd.args[0] = 0x32;
+       cmd.args[1] = reg;
+       cmd.args[2] = reg;
+       cmd.len = 3;
+       ret = cx24117_cmd_execute(fe, &cmd);
+       if (ret)
+               return ret;
+
+       if ((voltage == SEC_VOLTAGE_13) ||
+           (voltage == SEC_VOLTAGE_18)) {
+               /* CMD 33 */
+               cmd.args[0] = 0x33;
+               cmd.args[1] = reg;
+               cmd.args[2] = reg;
+               cmd.len = 3;
+               ret = cx24117_cmd_execute(fe, &cmd);
+               if (ret != 0)
+                       return ret;
+
+               ret = cx24117_wait_for_lnb(fe);
+               if (ret != 0)
+                       return ret;
+
+               /* Wait for voltage/min repeat delay */
+               msleep(100);
+
+               /* CMD 22 - CMD_LNBDCLEVEL */
+               cmd.args[0] = CMD_LNBDCLEVEL;
+               cmd.args[1] = state->demod ? 0 : 1;
+               cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
+               cmd.len = 3;
+
+               /* Min delay time before DiSEqC send */
+               msleep(20);
+       } else {
+               cmd.args[0] = 0x33;
+               cmd.args[1] = 0x00;
+               cmd.args[2] = reg;
+               cmd.len = 3;
+       }
+
+       return cx24117_cmd_execute(fe, &cmd);
+}
+
+static int cx24117_set_tone(struct dvb_frontend *fe,
+       fe_sec_tone_mode_t tone)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+       int ret;
+
+       dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
+               __func__, state->demod, tone);
+       if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+               dev_warn(&state->priv->i2c->dev, "%s: demod%d invalid tone=%d\n",
+                       KBUILD_MODNAME, state->demod, tone);
+               return -EINVAL;
+       }
+
+       /* Wait for LNB ready */
+       ret = cx24117_wait_for_lnb(fe);
+       if (ret != 0)
+               return ret;
+
+       /* Min delay time after DiSEqC send */
+       msleep(20);
+
+       /* Set the tone */
+       /* CMD 23 - CMD_SET_TONE */
+       cmd.args[0] = CMD_SET_TONE;
+       cmd.args[1] = (state->demod ? 0 : 1);
+       cmd.args[2] = 0x00;
+       cmd.args[3] = 0x00;
+       cmd.len = 5;
+       switch (tone) {
+       case SEC_TONE_ON:
+               cmd.args[4] = 0x01;
+               break;
+       case SEC_TONE_OFF:
+               cmd.args[4] = 0x00;
+               break;
+       }
+
+       msleep(20);
+
+       return cx24117_cmd_execute(fe, &cmd);
+}
+
+/* Initialise DiSEqC */
+static int cx24117_diseqc_init(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+
+       /* Prepare a DiSEqC command */
+       state->dsec_cmd.args[0] = CMD_LNBSEND;
+
+       /* demod */
+       state->dsec_cmd.args[CX24117_DISEQC_DEMOD] = state->demod ? 0 : 1;
+
+       /* DiSEqC burst */
+       state->dsec_cmd.args[CX24117_DISEQC_BURST] = CX24117_DISEQC_MINI_A;
+
+       /* Unknown */
+       state->dsec_cmd.args[CX24117_DISEQC_ARG3_2] = 0x02;
+       state->dsec_cmd.args[CX24117_DISEQC_ARG4_0] = 0x00;
+
+       /* Continuation flag? */
+       state->dsec_cmd.args[CX24117_DISEQC_ARG5_0] = 0x00;
+
+       /* DiSEqC message length */
+       state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] = 0x00;
+
+       /* Command length */
+       state->dsec_cmd.len = 7;
+
+       return 0;
+}
+
+/* Send DiSEqC message */
+static int cx24117_send_diseqc_msg(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *d)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       int i, ret;
+
+       /* Dump DiSEqC message */
+       dev_dbg(&state->priv->i2c->dev, "%s: demod %d (",
+               __func__, state->demod);
+       for (i = 0; i < d->msg_len; i++)
+               dev_dbg(&state->priv->i2c->dev, "0x%02x ", d->msg[i]);
+       dev_dbg(&state->priv->i2c->dev, ")\n");
+
+       /* Validate length */
+       if (d->msg_len > 15)
+               return -EINVAL;
+
+       /* DiSEqC message */
+       for (i = 0; i < d->msg_len; i++)
+               state->dsec_cmd.args[CX24117_DISEQC_MSGOFS + i] = d->msg[i];
+
+       /* DiSEqC message length */
+       state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] = d->msg_len;
+
+       /* Command length */
+       state->dsec_cmd.len = CX24117_DISEQC_MSGOFS +
+               state->dsec_cmd.args[CX24117_DISEQC_MSGLEN];
+
+       /*
+        * Message is sent with derived else cached burst
+        *
+        * WRITE PORT GROUP COMMAND 38
+        *
+        * 0/A/A: E0 10 38 F0..F3
+        * 1/B/B: E0 10 38 F4..F7
+        * 2/C/A: E0 10 38 F8..FB
+        * 3/D/B: E0 10 38 FC..FF
+        *
+        * databyte[3]= 8421:8421
+        *              ABCD:WXYZ
+        *              CLR :SET
+        *
+        *              WX= PORT SELECT 0..3    (X=TONEBURST)
+        *              Y = VOLTAGE             (0=13V, 1=18V)
+        *              Z = BAND                (0=LOW, 1=HIGH(22K))
+        */
+       if (d->msg_len >= 4 && d->msg[2] == 0x38)
+               state->dsec_cmd.args[CX24117_DISEQC_BURST] =
+                       ((d->msg[3] & 4) >> 2);
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d burst=%d\n",
+               __func__, state->demod,
+               state->dsec_cmd.args[CX24117_DISEQC_BURST]);
+
+       /* Wait for LNB ready */
+       ret = cx24117_wait_for_lnb(fe);
+       if (ret != 0)
+               return ret;
+
+       /* Wait for voltage/min repeat delay */
+       msleep(100);
+
+       /* Command */
+       ret = cx24117_cmd_execute(fe, &state->dsec_cmd);
+       if (ret != 0)
+               return ret;
+       /*
+        * Wait for send
+        *
+        * Eutelsat spec:
+        * >15ms delay          + (XXX determine if FW does this, see set_tone)
+        *  13.5ms per byte     +
+        * >15ms delay          +
+        *  12.5ms burst        +
+        * >15ms delay            (XXX determine if FW does this, see set_tone)
+        */
+       msleep((state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] << 4) + 60);
+
+       return 0;
+}
+
+/* Send DiSEqC burst */
+static int cx24117_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t burst)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+
+       dev_dbg(&state->priv->i2c->dev, "%s(%d) demod=%d\n",
+               __func__, burst, state->demod);
+
+       /* DiSEqC burst */
+       if (burst == SEC_MINI_A)
+               state->dsec_cmd.args[CX24117_DISEQC_BURST] =
+                       CX24117_DISEQC_MINI_A;
+       else if (burst == SEC_MINI_B)
+               state->dsec_cmd.args[CX24117_DISEQC_BURST] =
+                       CX24117_DISEQC_MINI_B;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int cx24117_get_priv(struct cx24117_priv **priv,
+       struct i2c_adapter *i2c, u8 client_address)
+{
+       int ret;
+
+       mutex_lock(&cx24117_list_mutex);
+       ret = hybrid_tuner_request_state(struct cx24117_priv, (*priv),
+               hybrid_tuner_instance_list, i2c, client_address, "cx24117");
+       mutex_unlock(&cx24117_list_mutex);
+
+       return ret;
+}
+
+static void cx24117_release_priv(struct cx24117_priv *priv)
+{
+       mutex_lock(&cx24117_list_mutex);
+       if (priv != NULL)
+               hybrid_tuner_release_state(priv);
+       mutex_unlock(&cx24117_list_mutex);
+}
+
+static void cx24117_release(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       dev_dbg(&state->priv->i2c->dev, "%s demod%d\n",
+               __func__, state->demod);
+       cx24117_release_priv(state->priv);
+       kfree(state);
+}
+
+static struct dvb_frontend_ops cx24117_ops;
+
+struct dvb_frontend *cx24117_attach(const struct cx24117_config *config,
+       struct i2c_adapter *i2c)
+{
+       struct cx24117_state *state = NULL;
+       struct cx24117_priv *priv = NULL;
+       int demod = 0;
+
+       /* get the common data struct for both demods */
+       demod = cx24117_get_priv(&priv, i2c, config->demod_address);
+
+       switch (demod) {
+       case 0:
+               dev_err(&state->priv->i2c->dev,
+                       "%s: Error attaching frontend %d\n",
+                       KBUILD_MODNAME, demod);
+               goto error1;
+               break;
+       case 1:
+               /* new priv instance */
+               priv->i2c = i2c;
+               priv->demod_address = config->demod_address;
+               mutex_init(&priv->fe_lock);
+               break;
+       default:
+               /* existing priv instance */
+               break;
+       }
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct cx24117_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error2;
+
+       state->demod = demod - 1;
+       state->priv = priv;
+
+       /* test i2c bus for ack */
+       if (demod == 0) {
+               if (cx24117_readreg(state, 0x00) < 0)
+                       goto error3;
+       }
+
+       dev_info(&state->priv->i2c->dev,
+               "%s: Attaching frontend %d\n",
+               KBUILD_MODNAME, state->demod);
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &cx24117_ops,
+               sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error3:
+       kfree(state);
+error2:
+       cx24117_release_priv(priv);
+error1:
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(cx24117_attach);
+
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int cx24117_initfe(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+       int ret;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
+               __func__, state->demod);
+
+       mutex_lock(&state->priv->fe_lock);
+
+       /* Firmware CMD 36: Power config */
+       cmd.args[0] = CMD_TUNERSLEEP;
+       cmd.args[1] = (state->demod ? 1 : 0);
+       cmd.args[2] = 0;
+       cmd.len = 3;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto exit;
+
+       ret = cx24117_diseqc_init(fe);
+       if (ret != 0)
+               goto exit;
+
+       /* CMD 3C */
+       cmd.args[0] = 0x3c;
+       cmd.args[1] = (state->demod ? 1 : 0);
+       cmd.args[2] = 0x10;
+       cmd.args[3] = 0x10;
+       cmd.len = 4;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto exit;
+
+       /* CMD 34 */
+       cmd.args[0] = 0x34;
+       cmd.args[1] = (state->demod ? 1 : 0);
+       cmd.args[2] = CX24117_OCC;
+       cmd.len = 3;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
+
+exit:
+       mutex_unlock(&state->priv->fe_lock);
+
+       return ret;
+}
+
+/*
+ * Put device to sleep
+ */
+static int cx24117_sleep(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct cx24117_cmd cmd;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
+               __func__, state->demod);
+
+       /* Firmware CMD 36: Power config */
+       cmd.args[0] = CMD_TUNERSLEEP;
+       cmd.args[1] = (state->demod ? 1 : 0);
+       cmd.args[2] = 1;
+       cmd.len = 3;
+       return cx24117_cmd_execute(fe, &cmd);
+}
+
+/* dvb-core told us to tune, the tv property cache will be complete,
+ * it's safe for is to pull values and use them for tuning purposes.
+ */
+static int cx24117_set_frontend(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct cx24117_cmd cmd;
+       fe_status_t tunerstat;
+       int i, status, ret, retune = 1;
+       u8 reg_clkdiv, reg_ratediv;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
+               __func__, state->demod);
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               dev_dbg(&state->priv->i2c->dev, "%s() demod%d DVB-S\n",
+                       __func__, state->demod);
+
+               /* Only QPSK is supported for DVB-S */
+               if (c->modulation != QPSK) {
+                       dev_dbg(&state->priv->i2c->dev,
+                               "%s() demod%d unsupported modulation (%d)\n",
+                               __func__, state->demod, c->modulation);
+                       return -EINVAL;
+               }
+
+               /* Pilot doesn't exist in DVB-S, turn bit off */
+               state->dnxt.pilot_val = CX24117_PILOT_OFF;
+
+               /* DVB-S only supports 0.35 */
+               state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
+               break;
+
+       case SYS_DVBS2:
+               dev_dbg(&state->priv->i2c->dev, "%s() demod%d DVB-S2\n",
+                       __func__, state->demod);
+
+               /*
+                * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+                * but not hardware auto detection
+                */
+               if (c->modulation != PSK_8 && c->modulation != QPSK) {
+                       dev_dbg(&state->priv->i2c->dev,
+                               "%s() demod%d unsupported modulation (%d)\n",
+                               __func__, state->demod, c->modulation);
+                       return -EOPNOTSUPP;
+               }
+
+               switch (c->pilot) {
+               case PILOT_AUTO:
+                       state->dnxt.pilot_val = CX24117_PILOT_AUTO;
+                       break;
+               case PILOT_OFF:
+                       state->dnxt.pilot_val = CX24117_PILOT_OFF;
+                       break;
+               case PILOT_ON:
+                       state->dnxt.pilot_val = CX24117_PILOT_ON;
+                       break;
+               default:
+                       dev_dbg(&state->priv->i2c->dev,
+                               "%s() demod%d unsupported pilot mode (%d)\n",
+                               __func__, state->demod, c->pilot);
+                       return -EOPNOTSUPP;
+               }
+
+               switch (c->rolloff) {
+               case ROLLOFF_20:
+                       state->dnxt.rolloff_val = CX24117_ROLLOFF_020;
+                       break;
+               case ROLLOFF_25:
+                       state->dnxt.rolloff_val = CX24117_ROLLOFF_025;
+                       break;
+               case ROLLOFF_35:
+                       state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
+                       break;
+               case ROLLOFF_AUTO:
+                       state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
+                       /* soft-auto rolloff */
+                       retune = 3;
+                       break;
+               default:
+                       dev_warn(&state->priv->i2c->dev,
+                               "%s: demod%d unsupported rolloff (%d)\n",
+                               KBUILD_MODNAME, state->demod, c->rolloff);
+                       return -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               dev_warn(&state->priv->i2c->dev,
+                       "%s: demod %d unsupported delivery system (%d)\n",
+                       KBUILD_MODNAME, state->demod, c->delivery_system);
+               return -EINVAL;
+       }
+
+       state->dnxt.delsys = c->delivery_system;
+       state->dnxt.modulation = c->modulation;
+       state->dnxt.frequency = c->frequency;
+       state->dnxt.pilot = c->pilot;
+       state->dnxt.rolloff = c->rolloff;
+
+       ret = cx24117_set_inversion(state, c->inversion);
+       if (ret !=  0)
+               return ret;
+
+       ret = cx24117_set_fec(state,
+               c->delivery_system, c->modulation, c->fec_inner);
+       if (ret !=  0)
+               return ret;
+
+       ret = cx24117_set_symbolrate(state, c->symbol_rate);
+       if (ret !=  0)
+               return ret;
+
+       /* discard the 'current' tuning parameters and prepare to tune */
+       cx24117_clone_params(fe);
+
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: delsys      = %d\n", __func__, state->dcur.delsys);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: modulation  = %d\n", __func__, state->dcur.modulation);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: frequency   = %d\n", __func__, state->dcur.frequency);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: pilot       = %d (val = 0x%02x)\n", __func__,
+               state->dcur.pilot, state->dcur.pilot_val);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: retune      = %d\n", __func__, retune);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: rolloff     = %d (val = 0x%02x)\n", __func__,
+               state->dcur.rolloff, state->dcur.rolloff_val);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
+               state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
+       dev_dbg(&state->priv->i2c->dev,
+               "%s: Inversion   = %d (val = 0x%02x)\n", __func__,
+               state->dcur.inversion, state->dcur.inversion_val);
+
+       /* Prepare a tune request */
+       cmd.args[0] = CMD_TUNEREQUEST;
+
+       /* demod */
+       cmd.args[1] = state->demod;
+
+       /* Frequency */
+       cmd.args[2] = (state->dcur.frequency & 0xff0000) >> 16;
+       cmd.args[3] = (state->dcur.frequency & 0x00ff00) >> 8;
+       cmd.args[4] = (state->dcur.frequency & 0x0000ff);
+
+       /* Symbol Rate */
+       cmd.args[5] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
+       cmd.args[6] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
+
+       /* Automatic Inversion */
+       cmd.args[7] = state->dcur.inversion_val;
+
+       /* Modulation / FEC / Pilot */
+       cmd.args[8] = state->dcur.fec_val | state->dcur.pilot_val;
+
+       cmd.args[9] = CX24117_SEARCH_RANGE_KHZ >> 8;
+       cmd.args[10] = CX24117_SEARCH_RANGE_KHZ & 0xff;
+
+       cmd.args[11] = state->dcur.rolloff_val;
+       cmd.args[12] = state->dcur.fec_mask;
+
+       if (state->dcur.symbol_rate > 30000000) {
+               reg_ratediv = 0x04;
+               reg_clkdiv = 0x02;
+       } else if (state->dcur.symbol_rate > 10000000) {
+               reg_ratediv = 0x06;
+               reg_clkdiv = 0x03;
+       } else {
+               reg_ratediv = 0x0a;
+               reg_clkdiv = 0x05;
+       }
+
+       cmd.args[13] = reg_ratediv;
+       cmd.args[14] = reg_clkdiv;
+
+       cx24117_writereg(state, (state->demod == 0) ?
+               CX24117_REG_CLKDIV0 : CX24117_REG_CLKDIV1, reg_clkdiv);
+       cx24117_writereg(state, (state->demod == 0) ?
+               CX24117_REG_RATEDIV0 : CX24117_REG_RATEDIV1, reg_ratediv);
+
+       cmd.args[15] = CX24117_PNE;
+       cmd.len = 16;
+
+       do {
+               /* Reset status register */
+               status = cx24117_readreg(state, (state->demod == 0) ?
+                       CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1) &
+                       CX24117_SIGNAL_MASK;
+
+               dev_dbg(&state->priv->i2c->dev,
+                       "%s() demod%d status_setfe = %02x\n",
+                       __func__, state->demod, status);
+
+               cx24117_writereg(state, (state->demod == 0) ?
+                       CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1, status);
+
+               /* Tune */
+               ret = cx24117_cmd_execute(fe, &cmd);
+               if (ret != 0)
+                       break;
+
+               /*
+                * Wait for up to 500 ms before retrying
+                *
+                * If we are able to tune then generally it occurs within 100ms.
+                * If it takes longer, try a different rolloff setting.
+                */
+               for (i = 0; i < 50; i++) {
+                       cx24117_read_status(fe, &tunerstat);
+                       status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
+                       if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+                               dev_dbg(&state->priv->i2c->dev,
+                                       "%s() demod%d tuned\n",
+                                       __func__, state->demod);
+                               return 0;
+                       }
+                       msleep(20);
+               }
+
+               dev_dbg(&state->priv->i2c->dev, "%s() demod%d not tuned\n",
+                       __func__, state->demod);
+
+               /* try next rolloff value */
+               if (state->dcur.rolloff == 3)
+                       cmd.args[11]--;
+
+       } while (--retune);
+       return -EINVAL;
+}
+
+static int cx24117_tune(struct dvb_frontend *fe, bool re_tune,
+       unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+
+       dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
+               __func__, state->demod);
+
+       *delay = HZ / 5;
+       if (re_tune) {
+               int ret = cx24117_set_frontend(fe);
+               if (ret)
+                       return ret;
+       }
+       return cx24117_read_status(fe, status);
+}
+
+static int cx24117_get_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_HW;
+}
+
+static int cx24117_get_frontend(struct dvb_frontend *fe)
+{
+       struct cx24117_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct cx24117_cmd cmd;
+       u8 reg, st, inv;
+       int ret, idx;
+       unsigned int freq;
+       short srate_os, freq_os;
+
+       u8 buf[0x1f-4];
+
+       cmd.args[0] = 0x1c;
+       cmd.args[1] = (u8) state->demod;
+       cmd.len = 2;
+       ret = cx24117_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       /* read all required regs at once */
+       reg = (state->demod == 0) ? CX24117_REG_FREQ3_0 : CX24117_REG_FREQ3_1;
+       ret = cx24117_readregN(state, reg, buf, 0x1f-4);
+       if (ret != 0)
+               return ret;
+
+       st = buf[5];
+
+       /* get spectral inversion */
+       inv = (((state->demod == 0) ? ~st : st) >> 6) & 1;
+       if (inv == 0)
+               c->inversion = INVERSION_OFF;
+       else
+               c->inversion = INVERSION_ON;
+
+       /* modulation and fec */
+       idx = st & 0x3f;
+       if (c->delivery_system == SYS_DVBS2) {
+               if (idx > 11)
+                       idx += 9;
+               else
+                       idx += 7;
+       }
+
+       c->modulation = cx24117_modfec_modes[idx].modulation;
+       c->fec_inner = cx24117_modfec_modes[idx].fec;
+
+       /* frequency */
+       freq = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+       freq_os = (buf[8] << 8) | buf[9];
+       c->frequency = freq + freq_os;
+
+       /* symbol rate */
+       srate_os = (buf[10] << 8) | buf[11];
+       c->symbol_rate = -1000 * srate_os + state->dcur.symbol_rate;
+       return 0;
+}
+
+static struct dvb_frontend_ops cx24117_ops = {
+       .delsys = { SYS_DVBS, SYS_DVBS2 },
+       .info = {
+               .name = "Conexant CX24117/CX24132",
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+               .frequency_tolerance = 5000,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_2G_MODULATION |
+                       FE_CAN_QPSK | FE_CAN_RECOVER
+       },
+
+       .release = cx24117_release,
+
+       .init = cx24117_initfe,
+       .sleep = cx24117_sleep,
+       .read_status = cx24117_read_status,
+       .read_ber = cx24117_read_ber,
+       .read_signal_strength = cx24117_read_signal_strength,
+       .read_snr = cx24117_read_snr,
+       .read_ucblocks = cx24117_read_ucblocks,
+       .set_tone = cx24117_set_tone,
+       .set_voltage = cx24117_set_voltage,
+       .diseqc_send_master_cmd = cx24117_send_diseqc_msg,
+       .diseqc_send_burst = cx24117_diseqc_send_burst,
+       .get_frontend_algo = cx24117_get_algo,
+       .tune = cx24117_tune,
+
+       .set_frontend = cx24117_set_frontend,
+       .get_frontend = cx24117_get_frontend,
+};
+
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24117/cx24132 hardware");
+MODULE_AUTHOR("Luis Alves (ljalvs@gmail.com)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.1");
+MODULE_FIRMWARE(CX24117_DEFAULT_FIRMWARE);
+
diff --git a/drivers/media/dvb-frontends/cx24117.h b/drivers/media/dvb-frontends/cx24117.h
new file mode 100644 (file)
index 0000000..4e59e95
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    Conexant cx24117/cx24132 - Dual DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2013 Luis Alves <ljalvs@gmail.com>
+       (based on cx24116.h by Steven Toth)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24117_H
+#define CX24117_H
+
+#include <linux/kconfig.h>
+#include <linux/dvb/frontend.h>
+
+struct cx24117_config {
+       /* the demodulator's i2c address */
+       u8 demod_address;
+};
+
+#if IS_ENABLED(CONFIG_DVB_CX24117)
+extern struct dvb_frontend *cx24117_attach(
+       const struct cx24117_config *config,
+       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *cx24117_attach(
+       const struct cx24117_config *config,
+       struct i2c_adapter *i2c)
+{
+       dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* CX24117_H */
index a771da3..72fb583 100644 (file)
@@ -739,7 +739,7 @@ static int cx24123_set_voltage(struct dvb_frontend *fe,
                return 0;
        default:
                return -EINVAL;
-       };
+       }
 
        return 0;
 }
index 7ca5c69..d9eeeb1 100644 (file)
@@ -31,7 +31,7 @@ static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
                {
                        .addr = i2c,
                        .flags = 0,
-                       .len = sizeof(buf),
+                       .len = len + 1,
                        .buf = buf,
                }
        };
@@ -65,7 +65,7 @@ static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
                }, {
                        .addr = i2c,
                        .flags = I2C_M_RD,
-                       .len = sizeof(buf),
+                       .len = len,
                        .buf = buf,
                }
        };
index 6201c59..e540cfb 100644 (file)
@@ -649,9 +649,9 @@ static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 si
        b[2 * (size - 2) - 1] = '\0';   /* Bullet proof the buffer */
        if (*b == '~') {
                b++;
-               dprintk(b);
+               dprintk("%s", b);
        } else
-               dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : "<emtpy>");
+               dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : "<empty>");
        return 1;
 }
 
index 9a21347..959ae36 100644 (file)
 #define DRX_I2C_MODEFLAGS     0xC0
 #define DRX_I2C_FLAGS         0xF0
 
-#ifndef SIZEOF_ARRAY
-#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
-#endif
-
 #define DEFAULT_LOCK_TIMEOUT    1100
 
 #define DRX_CHANNEL_AUTO 0
@@ -1018,7 +1014,7 @@ static int HI_CfgCommand(struct drxd_state *state)
                status = Write16(state, HI_RA_RAM_SRV_CMD__A,
                                 HI_RA_RAM_SRV_CMD_CONFIG, 0);
        else
-               status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0);
+               status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, NULL);
        mutex_unlock(&state->mutex);
        return status;
 }
@@ -1039,7 +1035,7 @@ static int HI_ResetCommand(struct drxd_state *state)
        status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
                         HI_RA_RAM_SRV_RST_KEY_ACT, 0);
        if (status == 0)
-               status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0);
+               status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, NULL);
        mutex_unlock(&state->mutex);
        msleep(1);
        return status;
@@ -2837,7 +2833,7 @@ static int drxd_init(struct dvb_frontend *fe)
        int err = 0;
 
 /*     if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
-       return DRXD_init(state, 0, 0);
+       return DRXD_init(state, NULL, 0);
 
        err = DRXD_init(state, state->fw->data, state->fw->size);
        release_firmware(state->fw);
@@ -2973,7 +2969,7 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
 
        mutex_init(&state->mutex);
 
-       if (Read16(state, 0, 0, 0) < 0)
+       if (Read16(state, 0, NULL, 0) < 0)
                goto error;
 
        state->frontend.ops = drxd_ops;
index 082014d..d416c15 100644 (file)
@@ -1083,7 +1083,7 @@ static int hi_cfg_command(struct drxk_state *state)
                         SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
        if (status < 0)
                goto error;
-       status = hi_command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+       status = hi_command(state, SIO_HI_RA_RAM_CMD_CONFIG, NULL);
        if (status < 0)
                goto error;
 
@@ -2781,7 +2781,7 @@ static int ConfigureI2CBridge(struct drxk_state *state, bool b_enable_bridge)
                        goto error;
        }
 
-       status = hi_command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+       status = hi_command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, NULL);
 
 error:
        if (status < 0)
index facb848..a95dfe0 100644 (file)
@@ -489,6 +489,7 @@ static int rtl2832_init(struct dvb_frontend *fe)
                init = rtl2832_tuner_init_e4000;
                break;
        case RTL2832_TUNER_R820T:
+       case RTL2832_TUNER_R828D:
                len = ARRAY_SIZE(rtl2832_tuner_init_r820t);
                init = rtl2832_tuner_init_r820t;
                break;
index 91b2dcf..2cfbb6a 100644 (file)
@@ -53,6 +53,7 @@ struct rtl2832_config {
 #define RTL2832_TUNER_E4000     0x27
 #define RTL2832_TUNER_FC0013    0x29
 #define RTL2832_TUNER_R820T    0x2a
+#define RTL2832_TUNER_R828D    0x2b
        u8 tuner;
 };
 
index 9d08350..69e62f4 100644 (file)
@@ -189,7 +189,7 @@ static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t ton
                return tda8083_writereg (state, 0x29, 0x80);
        default:
                return -EINVAL;
-       };
+       }
 }
 
 static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
@@ -201,7 +201,7 @@ static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t vo
                return tda8083_writereg (state, 0x20, 0x11);
        default:
                return -EINVAL;
-       };
+       }
 }
 
 static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst)
index ad7ad85..9aba044 100644 (file)
@@ -31,6 +31,7 @@ struct ts2020_priv {
        struct i2c_adapter *i2c;
        u8 clk_out_div;
        u32 frequency;
+       u32 frequency_div;
 };
 
 static int ts2020_release(struct dvb_frontend *fe)
@@ -193,7 +194,7 @@ static int ts2020_set_params(struct dvb_frontend *fe)
        u8 lo = 0x01, div4 = 0x0;
 
        /* Calculate frequency divider */
-       if (frequency < 1060000) {
+       if (frequency < priv->frequency_div) {
                lo |= 0x10;
                div4 = 0x1;
                ndiv = (frequency * 14 * 4) / TS2020_XTAL_FREQ;
@@ -340,8 +341,12 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
        priv->i2c_address = config->tuner_address;
        priv->i2c = i2c;
        priv->clk_out_div = config->clk_out_div;
+       priv->frequency_div = config->frequency_div;
        fe->tuner_priv = priv;
 
+       if (!priv->frequency_div)
+               priv->frequency_div = 1060000;
+
        /* Wake Up the tuner */
        if ((0x03 & ts2020_readreg(fe, 0x00)) == 0x00) {
                ts2020_writereg(fe, 0x00, 0x01);
index 5bcb9a7..b2fe6bb 100644 (file)
@@ -28,6 +28,7 @@
 struct ts2020_config {
        u8 tuner_address;
        u8 clk_out_div;
+       u32 frequency_div;
 };
 
 #if IS_ENABLED(CONFIG_DVB_TS2020)
index cbc9ee9..842654d 100644 (file)
@@ -621,6 +621,15 @@ config VIDEO_AS3645A
          This is a driver for the AS3645A and LM3555 flash controllers. It has
          build in control for flash, torch and indicator LEDs.
 
+config VIDEO_LM3560
+       tristate "LM3560 dual flash driver support"
+       depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       depends on MEDIA_CAMERA_SUPPORT
+       select REGMAP_I2C
+       ---help---
+         This is a driver for the lm3560 dual flash controllers. It controls
+         flash, torch LEDs.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
index 9f462df..e03f177 100644 (file)
@@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_S5K4ECGX)  += s5k4ecgx.o
 obj-$(CONFIG_VIDEO_S5C73M3)    += s5c73m3/
 obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
 obj-$(CONFIG_VIDEO_AS3645A)    += as3645a.o
+obj-$(CONFIG_VIDEO_LM3560)     += lm3560.o
 obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
 obj-$(CONFIG_VIDEO_AK881X)             += ak881x.o
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
index aeb56c5..d4e15a6 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/videodev2.h>
 #include <linux/uaccess.h>
+#include <linux/of.h>
 
 #include <media/adv7343.h>
 #include <media/v4l2-async.h>
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
new file mode 100644 (file)
index 0000000..3317a9a
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * drivers/media/i2c/lm3560.c
+ * General device driver for TI lm3560, FLASH LED Driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ *                     Ldd-Mlp <ldd-mlp@list.ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+#include <media/lm3560.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+/* registers definitions */
+#define REG_ENABLE             0x10
+#define REG_TORCH_BR   0xa0
+#define REG_FLASH_BR   0xb0
+#define REG_FLASH_TOUT 0xc0
+#define REG_FLAG               0xd0
+#define REG_CONFIG1            0xe0
+
+/* Fault Mask */
+#define FAULT_TIMEOUT  (1<<0)
+#define FAULT_OVERTEMP (1<<1)
+#define FAULT_SHORT_CIRCUIT    (1<<2)
+
+enum led_enable {
+       MODE_SHDN = 0x0,
+       MODE_TORCH = 0x2,
+       MODE_FLASH = 0x3,
+};
+
+/* struct lm3560_flash
+ *
+ * @pdata: platform data
+ * @regmap: reg. map for i2c
+ * @lock: muxtex for serial access.
+ * @led_mode: V4L2 LED mode
+ * @ctrls_led: V4L2 contols
+ * @subdev_led: V4L2 subdev
+ */
+struct lm3560_flash {
+       struct device *dev;
+       struct lm3560_platform_data *pdata;
+       struct regmap *regmap;
+       struct mutex lock;
+
+       enum v4l2_flash_led_mode led_mode;
+       struct v4l2_ctrl_handler ctrls_led[LM3560_LED_MAX];
+       struct v4l2_subdev subdev_led[LM3560_LED_MAX];
+};
+
+#define to_lm3560_flash(_ctrl, _no)    \
+       container_of(_ctrl->handler, struct lm3560_flash, ctrls_led[_no])
+
+/* enable mode control */
+static int lm3560_mode_ctrl(struct lm3560_flash *flash)
+{
+       int rval = -EINVAL;
+
+       switch (flash->led_mode) {
+       case V4L2_FLASH_LED_MODE_NONE:
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_ENABLE, 0x03, MODE_SHDN);
+               break;
+       case V4L2_FLASH_LED_MODE_TORCH:
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_ENABLE, 0x03, MODE_TORCH);
+               break;
+       case V4L2_FLASH_LED_MODE_FLASH:
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_ENABLE, 0x03, MODE_FLASH);
+               break;
+       }
+       return rval;
+}
+
+/* led1/2  enable/disable */
+static int lm3560_enable_ctrl(struct lm3560_flash *flash,
+                             enum lm3560_led_id led_no, bool on)
+{
+       int rval;
+
+       if (led_no == LM3560_LED0) {
+               if (on == true)
+                       rval = regmap_update_bits(flash->regmap,
+                                                 REG_ENABLE, 0x08, 0x08);
+               else
+                       rval = regmap_update_bits(flash->regmap,
+                                                 REG_ENABLE, 0x08, 0x00);
+       } else {
+               if (on == true)
+                       rval = regmap_update_bits(flash->regmap,
+                                                 REG_ENABLE, 0x10, 0x10);
+               else
+                       rval = regmap_update_bits(flash->regmap,
+                                                 REG_ENABLE, 0x10, 0x00);
+       }
+       return rval;
+}
+
+/* torch1/2 brightness control */
+static int lm3560_torch_brt_ctrl(struct lm3560_flash *flash,
+                                enum lm3560_led_id led_no, unsigned int brt)
+{
+       int rval;
+       u8 br_bits;
+
+       if (brt < LM3560_TORCH_BRT_MIN)
+               return lm3560_enable_ctrl(flash, led_no, false);
+       else
+               rval = lm3560_enable_ctrl(flash, led_no, true);
+
+       br_bits = LM3560_TORCH_BRT_uA_TO_REG(brt);
+       if (led_no == LM3560_LED0)
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_TORCH_BR, 0x07, br_bits);
+       else
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_TORCH_BR, 0x38, br_bits << 3);
+
+       return rval;
+}
+
+/* flash1/2 brightness control */
+static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
+                                enum lm3560_led_id led_no, unsigned int brt)
+{
+       int rval;
+       u8 br_bits;
+
+       if (brt < LM3560_FLASH_BRT_MIN)
+               return lm3560_enable_ctrl(flash, led_no, false);
+       else
+               rval = lm3560_enable_ctrl(flash, led_no, true);
+
+       br_bits = LM3560_FLASH_BRT_uA_TO_REG(brt);
+       if (led_no == LM3560_LED0)
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_FLASH_BR, 0x0f, br_bits);
+       else
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_FLASH_BR, 0xf0, br_bits << 4);
+
+       return rval;
+}
+
+/* V4L2 controls  */
+static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
+{
+       struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
+
+       mutex_lock(&flash->lock);
+
+       if (ctrl->id == V4L2_CID_FLASH_FAULT) {
+               int rval;
+               s32 fault = 0;
+               unsigned int reg_val;
+               rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
+               if (rval < 0)
+                       return rval;
+               if (rval & FAULT_SHORT_CIRCUIT)
+                       fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+               if (rval & FAULT_OVERTEMP)
+                       fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+               if (rval & FAULT_TIMEOUT)
+                       fault |= V4L2_FLASH_FAULT_TIMEOUT;
+               ctrl->cur.val = fault;
+               return 0;
+       }
+
+       mutex_unlock(&flash->lock);
+       return -EINVAL;
+}
+
+static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
+{
+       struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
+       u8 tout_bits;
+       int rval = -EINVAL;
+
+       mutex_lock(&flash->lock);
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_LED_MODE:
+               flash->led_mode = ctrl->val;
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       rval = lm3560_mode_ctrl(flash);
+               break;
+
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_CONFIG1, 0x04, (ctrl->val) << 2);
+               if (rval < 0)
+                       goto err_out;
+               break;
+
+       case V4L2_CID_FLASH_STROBE:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       return -EBUSY;
+               flash->led_mode = V4L2_FLASH_LED_MODE_FLASH;
+               rval = lm3560_mode_ctrl(flash);
+               break;
+
+       case V4L2_CID_FLASH_STROBE_STOP:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       return -EBUSY;
+               flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+               rval = lm3560_mode_ctrl(flash);
+               break;
+
+       case V4L2_CID_FLASH_TIMEOUT:
+               tout_bits = LM3560_FLASH_TOUT_ms_TO_REG(ctrl->val);
+               rval = regmap_update_bits(flash->regmap,
+                                         REG_FLASH_TOUT, 0x1f, tout_bits);
+               break;
+
+       case V4L2_CID_FLASH_INTENSITY:
+               rval = lm3560_flash_brt_ctrl(flash, led_no, ctrl->val);
+               break;
+
+       case V4L2_CID_FLASH_TORCH_INTENSITY:
+               rval = lm3560_torch_brt_ctrl(flash, led_no, ctrl->val);
+               break;
+       }
+
+       mutex_unlock(&flash->lock);
+err_out:
+       return rval;
+}
+
+static int lm3560_led1_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return lm3560_get_ctrl(ctrl, LM3560_LED1);
+}
+
+static int lm3560_led1_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return lm3560_set_ctrl(ctrl, LM3560_LED1);
+}
+
+static int lm3560_led0_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return lm3560_get_ctrl(ctrl, LM3560_LED0);
+}
+
+static int lm3560_led0_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return lm3560_set_ctrl(ctrl, LM3560_LED0);
+}
+
+static const struct v4l2_ctrl_ops lm3560_led_ctrl_ops[LM3560_LED_MAX] = {
+       [LM3560_LED0] = {
+                        .g_volatile_ctrl = lm3560_led0_get_ctrl,
+                        .s_ctrl = lm3560_led0_set_ctrl,
+                        },
+       [LM3560_LED1] = {
+                        .g_volatile_ctrl = lm3560_led1_get_ctrl,
+                        .s_ctrl = lm3560_led1_set_ctrl,
+                        }
+};
+
+static int lm3560_init_controls(struct lm3560_flash *flash,
+                               enum lm3560_led_id led_no)
+{
+       struct v4l2_ctrl *fault;
+       u32 max_flash_brt = flash->pdata->max_flash_brt[led_no];
+       u32 max_torch_brt = flash->pdata->max_torch_brt[led_no];
+       struct v4l2_ctrl_handler *hdl = &flash->ctrls_led[led_no];
+       const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no];
+
+       v4l2_ctrl_handler_init(hdl, 8);
+       /* flash mode */
+       v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
+                              V4L2_FLASH_LED_MODE_TORCH, ~0x7,
+                              V4L2_FLASH_LED_MODE_NONE);
+       flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+
+       /* flash source */
+       v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE,
+                              0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+       /* flash strobe */
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+       /* flash strobe stop */
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+
+       /* flash strobe timeout */
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,
+                         LM3560_FLASH_TOUT_MIN,
+                         flash->pdata->max_flash_timeout,
+                         LM3560_FLASH_TOUT_STEP,
+                         flash->pdata->max_flash_timeout);
+
+       /* flash brt */
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY,
+                         LM3560_FLASH_BRT_MIN, max_flash_brt,
+                         LM3560_FLASH_BRT_STEP, max_flash_brt);
+
+       /* torch brt */
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY,
+                         LM3560_TORCH_BRT_MIN, max_torch_brt,
+                         LM3560_TORCH_BRT_STEP, max_torch_brt);
+
+       /* fault */
+       fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,
+                                 V4L2_FLASH_FAULT_OVER_VOLTAGE
+                                 | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+                                 | V4L2_FLASH_FAULT_SHORT_CIRCUIT
+                                 | V4L2_FLASH_FAULT_TIMEOUT, 0, 0);
+       if (fault != NULL)
+               fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+       if (hdl->error)
+               return hdl->error;
+
+       flash->subdev_led[led_no].ctrl_handler = hdl;
+       return 0;
+}
+
+/* initialize device */
+static const struct v4l2_subdev_ops lm3560_ops = {
+       .core = NULL,
+};
+
+static const struct regmap_config lm3560_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xFF,
+};
+
+static int lm3560_subdev_init(struct lm3560_flash *flash,
+                             enum lm3560_led_id led_no, char *led_name)
+{
+       struct i2c_client *client = to_i2c_client(flash->dev);
+       int rval;
+
+       v4l2_i2c_subdev_init(&flash->subdev_led[led_no], client, &lm3560_ops);
+       flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       strcpy(flash->subdev_led[led_no].name, led_name);
+       rval = lm3560_init_controls(flash, led_no);
+       if (rval)
+               goto err_out;
+       rval = media_entity_init(&flash->subdev_led[led_no].entity, 0, NULL, 0);
+       if (rval < 0)
+               goto err_out;
+       flash->subdev_led[led_no].entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+       return rval;
+
+err_out:
+       v4l2_ctrl_handler_free(&flash->ctrls_led[led_no]);
+       return rval;
+}
+
+static int lm3560_init_device(struct lm3560_flash *flash)
+{
+       int rval;
+       unsigned int reg_val;
+
+       /* set peak current */
+       rval = regmap_update_bits(flash->regmap,
+                                 REG_FLASH_TOUT, 0x60, flash->pdata->peak);
+       if (rval < 0)
+               return rval;
+       /* output disable */
+       flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+       rval = lm3560_mode_ctrl(flash);
+       if (rval < 0)
+               return rval;
+       /* Reset faults */
+       rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
+       return rval;
+}
+
+static int lm3560_probe(struct i2c_client *client,
+                       const struct i2c_device_id *devid)
+{
+       struct lm3560_flash *flash;
+       struct lm3560_platform_data *pdata = dev_get_platdata(&client->dev);
+       int rval;
+
+       flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
+       if (flash == NULL)
+               return -ENOMEM;
+
+       flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap);
+       if (IS_ERR(flash->regmap)) {
+               rval = PTR_ERR(flash->regmap);
+               return rval;
+       }
+
+       /* if there is no platform data, use chip default value */
+       if (pdata == NULL) {
+               pdata =
+                   kzalloc(sizeof(struct lm3560_platform_data), GFP_KERNEL);
+               if (pdata == NULL)
+                       return -ENODEV;
+               pdata->peak = LM3560_PEAK_3600mA;
+               pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
+               /* led 1 */
+               pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX;
+               pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX;
+               /* led 2 */
+               pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX;
+               pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX;
+       }
+       flash->pdata = pdata;
+       flash->dev = &client->dev;
+       mutex_init(&flash->lock);
+
+       rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
+       if (rval < 0)
+               return rval;
+
+       rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
+       if (rval < 0)
+               return rval;
+
+       rval = lm3560_init_device(flash);
+       if (rval < 0)
+               return rval;
+
+       return 0;
+}
+
+static int lm3560_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct lm3560_flash *flash = container_of(subdev, struct lm3560_flash,
+                                                 subdev_led[LM3560_LED_MAX]);
+       unsigned int i;
+
+       for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {
+               v4l2_device_unregister_subdev(&flash->subdev_led[i]);
+               v4l2_ctrl_handler_free(&flash->ctrls_led[i]);
+               media_entity_cleanup(&flash->subdev_led[i].entity);
+       }
+
+       return 0;
+}
+
+static const struct i2c_device_id lm3560_id_table[] = {
+       {LM3560_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3560_id_table);
+
+static struct i2c_driver lm3560_i2c_driver = {
+       .driver = {
+                  .name = LM3560_NAME,
+                  .pm = NULL,
+                  },
+       .probe = lm3560_probe,
+       .remove = lm3560_remove,
+       .id_table = lm3560_id_table,
+};
+
+module_i2c_driver(lm3560_i2c_driver);
+
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
+MODULE_DESCRIPTION("Texas Instruments LM3560 LED flash driver");
+MODULE_LICENSE("GPL");
index 1d384a3..5b91593 100644 (file)
@@ -451,7 +451,9 @@ static int imx074_probe(struct i2c_client *client,
        if (ret < 0)
                goto eprobe;
 
-       return v4l2_async_register_subdev(&priv->subdev);
+       ret = v4l2_async_register_subdev(&priv->subdev);
+       if (!ret)
+               return 0;
 
 epwrinit:
 eprobe:
index e968c3f..bc74224 100644 (file)
@@ -371,7 +371,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
                alt->com13      = OV9640_COM13_RGB_AVG;
                alt->com15      = OV9640_COM15_RGB_565;
                break;
-       };
+       }
 }
 
 /* Setup registers according to resolution and color encoding */
index d9f65d7..04139ee 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/v4l2-dv-timings.h>
 
 #include <media/v4l2-dv-timings.h>
index 91f3dd4..83d85df 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <linux/v4l2-mediabus.h>
+#include <linux/of.h>
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
index 24a08fa..912e1cc 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/v4l2-dv-timings.h>
 #include <media/tvp7002.h>
 #include <media/v4l2-async.h>
index 447afbd..8b5e0b3 100644 (file)
@@ -319,7 +319,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
 
 err_pci_iounmap:
        pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-       pci_set_drvdata(fc_pci->pdev, NULL);
 err_pci_release_regions:
        pci_release_regions(fc_pci->pdev);
 err_pci_disable_device:
@@ -332,7 +331,6 @@ static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
        if (fc_pci->init_state & FC_PCI_INIT) {
                free_irq(fc_pci->pdev->irq, fc_pci);
                pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-               pci_set_drvdata(fc_pci->pdev, NULL);
                pci_release_regions(fc_pci->pdev);
                pci_disable_device(fc_pci->pdev);
        }
index 66eb0ba..d0c281f 100644 (file)
@@ -488,8 +488,7 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
        btwrite(0, BT848_INT_MASK);
 
        result = request_irq(bt->irq, bt878_irq,
-                            IRQF_SHARED | IRQF_DISABLED, "bt878",
-                            (void *) bt);
+                            IRQF_SHARED, "bt878", (void *) bt);
        if (result == -EINVAL) {
                printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
                       bt878_num);
@@ -563,7 +562,6 @@ static void bt878_remove(struct pci_dev *pci_dev)
        bt->shutdown = 1;
        bt878_mem_free(bt);
 
-       pci_set_drvdata(pci_dev, NULL);
        pci_disable_device(pci_dev);
        return;
 }
index c6532de..a3b1ee9 100644 (file)
@@ -4086,7 +4086,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
        /* disable irqs, register irq handler */
        btwrite(0, BT848_INT_MASK);
        result = request_irq(btv->c.pci->irq, bttv_irq,
-           IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
+           IRQF_SHARED, btv->c.v4l2_dev.name, (void *)btv);
        if (result < 0) {
                pr_err("%d: can't get IRQ %d\n",
                       bttv_num, btv->c.pci->irq);
index 004d8ac..ff72320 100644 (file)
@@ -1031,8 +1031,7 @@ static int cx18_probe(struct pci_dev *pci_dev,
 
        /* Register IRQ */
        retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
-                            IRQF_SHARED | IRQF_DISABLED,
-                            cx->v4l2_dev.name, (void *)cx);
+                            IRQF_SHARED, cx->v4l2_dev.name, (void *)cx);
        if (retval) {
                CX18_ERR("Failed to register irq %d\n", retval);
                goto free_i2c;
index 5104c80..d1dcb1d 100644 (file)
@@ -23,6 +23,7 @@ config VIDEO_CX23885
        select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_CX24117 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
index 6a71a96..79f20c8 100644 (file)
@@ -223,6 +223,39 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Leadtek Winfast PxDVR3200 H",
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200] = {
+               .name           = "Leadtek Winfast PxPVR2200",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+               .tuner_bus      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   = CX25840_VIN2_CH1 |
+                                 CX25840_VIN5_CH2,
+                       .amux   = CX25840_AUDIO8,
+                       .gpio0  = 0x704040,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_COMPOSITE1,
+                       .amux   = CX25840_AUDIO7,
+                       .gpio0  = 0x704040,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   = CX25840_SVIDEO_LUMA3 |
+                                 CX25840_SVIDEO_CHROMA4,
+                       .amux   = CX25840_AUDIO7,
+                       .gpio0  = 0x704040,
+               }, {
+                       .type   = CX23885_VMUX_COMPONENT,
+                       .vmux   = CX25840_VIN7_CH1 |
+                                 CX25840_VIN6_CH2 |
+                                 CX25840_VIN8_CH3 |
+                                 CX25840_COMPONENT_ON,
+                       .amux   = CX25840_AUDIO7,
+                       .gpio0  = 0x704040,
+               } },
+       },
        [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
                .name           = "Leadtek Winfast PxDVR3200 H XC4000",
                .porta          = CX23885_ANALOG_VIDEO,
@@ -259,6 +292,16 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "TurboSight TBS 6920",
                .portb          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_TBS_6980] = {
+               .name           = "TurboSight TBS 6980",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_TBS_6981] = {
+               .name           = "TurboSight TBS 6981",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
        [CX23885_BOARD_TEVII_S470] = {
                .name           = "TeVii S470",
                .portb          = CX23885_MPEG_DVB,
@@ -686,6 +729,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6681,
                .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6f21,
+               .card      = CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200,
        }, {
                .subvendor = 0x107d,
                .subdevice = 0x6f39,
@@ -698,6 +745,14 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x6920,
                .subdevice = 0x8888,
                .card      = CX23885_BOARD_TBS_6920,
+       }, {
+               .subvendor = 0x6980,
+               .subdevice = 0x8888,
+               .card      = CX23885_BOARD_TBS_6980,
+       }, {
+               .subvendor = 0x6981,
+               .subdevice = 0x8888,
+               .card      = CX23885_BOARD_TBS_6981,
        }, {
                .subvendor = 0xd470,
                .subdevice = 0x9022,
@@ -1023,6 +1078,35 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
                        dev->name, tv.model);
 }
 
+/* Some TBS cards require initing a chip using a bitbanged SPI attached
+   to the cx23885 gpio's. If this chip doesn't get init'ed the demod
+   doesn't respond to any command. */
+static void tbs_card_init(struct cx23885_dev *dev)
+{
+       int i;
+       const u8 buf[] = {
+               0xe0, 0x06, 0x66, 0x33, 0x65,
+               0x01, 0x17, 0x06, 0xde};
+
+       switch (dev->board) {
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
+               cx_set(GP0_IO, 0x00070007);
+               usleep_range(1000, 10000);
+               cx_clear(GP0_IO, 2);
+               usleep_range(1000, 10000);
+               for (i = 0; i < 9 * 8; i++) {
+                       cx_clear(GP0_IO, 7);
+                       usleep_range(1000, 10000);
+                       cx_set(GP0_IO,
+                               ((buf[i >> 3] >> (7 - (i & 7))) & 1) | 4);
+                       usleep_range(1000, 10000);
+               }
+               cx_set(GP0_IO, 7);
+               break;
+       }
+}
+
 int cx23885_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct cx23885_tsport *port = priv;
@@ -1043,6 +1127,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
@@ -1208,6 +1293,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x000f000f);
                break;
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
@@ -1225,6 +1311,8 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x00040004);
                break;
        case CX23885_BOARD_TBS_6920:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
        case CX23885_BOARD_PROF_8000:
                cx_write(MC417_CTL, 0x00000036);
                cx_write(MC417_OEN, 0x00001000);
@@ -1473,6 +1561,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_MYGICA_X8507:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                if (!enable_885_ir)
                        break;
                dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
@@ -1516,6 +1606,8 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_MYGICA_X8507:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
                /* sd_ir is a duplicate pointer to the AV Core, just clear it */
                dev->sd_ir = NULL;
@@ -1561,6 +1653,8 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_MYGICA_X8507:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                if (dev->sd_ir)
                        cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
                break;
@@ -1676,6 +1770,16 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
+               ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               tbs_card_init(dev);
+               break;
        case CX23885_BOARD_MYGICA_X8506:
        case CX23885_BOARD_MAGICPRO_PROHDTVE2:
        case CX23885_BOARD_MYGICA_X8507:
@@ -1704,6 +1808,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
@@ -1733,6 +1838,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
@@ -1752,6 +1858,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_MYGICA_X8507:
        case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_AVERMEDIA_HC81R:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
index 9f63d93..edcd79d 100644 (file)
@@ -2129,7 +2129,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        }
 
        err = request_irq(pci_dev->irq, cx23885_irq,
-                         IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+                         IRQF_SHARED, dev->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n",
                       dev->name, pci_dev->irq);
index 971e4ff..0549205 100644 (file)
@@ -51,6 +51,7 @@
 #include "stv6110.h"
 #include "lnbh24.h"
 #include "cx24116.h"
+#include "cx24117.h"
 #include "cimax2.h"
 #include "lgs8gxx.h"
 #include "netup-eeprom.h"
@@ -461,6 +462,10 @@ static struct cx24116_config tbs_cx24116_config = {
        .demod_address = 0x55,
 };
 
+static struct cx24117_config tbs_cx24117_config = {
+       .demod_address = 0x55,
+};
+
 static struct ds3000_config tevii_ds3000_config = {
        .demod_address = 0x68,
 };
@@ -1044,6 +1049,25 @@ static int dvb_register(struct cx23885_tsport *port)
                        fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
 
                break;
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
+               i2c_bus = &dev->i2c_bus[1];
+
+               switch (port->nr) {
+               /* PORT B */
+               case 1:
+                       fe0->dvb.frontend = dvb_attach(cx24117_attach,
+                                       &tbs_cx24117_config,
+                                       &i2c_bus->i2c_adap);
+                       break;
+               /* PORT C */
+               case 2:
+                       fe0->dvb.frontend = dvb_attach(cx24117_attach,
+                                       &tbs_cx24117_config,
+                                       &i2c_bus->i2c_adap);
+                       break;
+               }
+               break;
        case CX23885_BOARD_TEVII_S470:
                i2c_bus = &dev->i2c_bus[1];
 
index 7875dfb..8a49e7c 100644 (file)
@@ -90,6 +90,8 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_MYGICA_X8507:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                /*
                 * The only boards we handle right now.  However other boards
                 * using the CX2388x integrated IR controller should be similar
@@ -168,6 +170,8 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
                break;
        case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
                /*
                 * The IR controller on this board only returns pulse widths.
                 * Any other mode setting will fail to set up the device.
@@ -298,6 +302,14 @@ int cx23885_input_init(struct cx23885_dev *dev)
                /* A guess at the remote */
                rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
                break;
+       case CX23885_BOARD_TBS_6980:
+       case CX23885_BOARD_TBS_6981:
+               /* Integrated CX23885 IR controller */
+               driver_type = RC_DRIVER_IR_RAW;
+               allowed_protos = RC_BIT_ALL;
+               /* A guess at the remote */
+               rc_map = RC_MAP_TBS_NEC;
+               break;
        default:
                return -ENODEV;
        }
index 1616868..7891f34 100644 (file)
@@ -1865,7 +1865,8 @@ int cx23885_video_register(struct cx23885_dev *dev)
 
                        v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
 
-                       if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) {
+                       if ((dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) ||
+                           (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200)) {
                                struct xc2028_ctrl ctrl = {
                                        .fname = XC2028_DEFAULT_FIRMWARE,
                                        .max_len = 64
index 038caf5..0fa4048 100644 (file)
@@ -93,6 +93,9 @@
 #define CX23885_BOARD_PROF_8000                37
 #define CX23885_BOARD_HAUPPAUGE_HVR4400        38
 #define CX23885_BOARD_AVERMEDIA_HC81R          39
+#define CX23885_BOARD_TBS_6981                 40
+#define CX23885_BOARD_TBS_6980                 41
+#define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
index 3b409fe..f2ebc98 100644 (file)
@@ -45,5 +45,3 @@ struct cx25821_board cx25821_boards[] = {
        },
 
 };
-
-const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards);
index 22fa044..43bdfa4 100644 (file)
@@ -438,7 +438,7 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
                decoder_count = decoder_select + 1;
        } else {
                decoder = 0;
-               decoder_count = _num_decoders;
+               decoder_count = dev->_max_num_decoders;
        }
 
        switch (width) {
@@ -506,8 +506,6 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
                break;
        }
 
-       _display_field_cnt[decoder] = duration;
-
        /* update hardware */
        fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp);
 
@@ -667,8 +665,6 @@ int medusa_video_init(struct cx25821_dev *dev)
        int ret_val = 0;
        int i = 0;
 
-       _num_decoders = dev->_max_num_decoders;
-
        /* disable Auto source selection on all video decoders */
        value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
        value &= 0xFFFFF0FF;
@@ -685,8 +681,14 @@ int medusa_video_init(struct cx25821_dev *dev)
        if (ret_val < 0)
                goto error;
 
-       for (i = 0; i < _num_decoders; i++)
-               medusa_set_decoderduration(dev, i, _display_field_cnt[i]);
+       /*
+        * FIXME: due to a coding bug the duration was always 0. It's
+        * likely that it really should be something else, but due to the
+        * lack of documentation I have no idea what it should be. For
+        * now just fill in 0 as the duration.
+        */
+       for (i = 0; i < dev->_max_num_decoders; i++)
+               medusa_set_decoderduration(dev, i, 0);
 
        /* Select monitor as DENC A input, power up the DAC */
        value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp);
@@ -717,7 +719,7 @@ int medusa_video_init(struct cx25821_dev *dev)
        /* Turn on all of the data out and control output pins. */
        value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp);
        value &= 0xFEF0FE00;
-       if (_num_decoders == MAX_DECODERS) {
+       if (dev->_max_num_decoders == MAX_DECODERS) {
                /*
                 * Note: The octal board does not support control pins(bit16-19)
                 * These bits are ignored in the octal board.
index 6175e09..8bf602f 100644 (file)
 #define CONTRAST_DEFAULT                5000
 #define HUE_DEFAULT                     5000
 
-unsigned short _num_decoders;
-unsigned short _num_cameras;
-
-unsigned int _video_standard;
-int _display_field_cnt[MAX_DECODERS];
-
 #endif
index 88ffef4..1f43be0 100644 (file)
@@ -159,10 +159,10 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_channel *chan, __le32
                 * For the upstream video channel, the risc engine will enable
                 * the FIFO. */
                if (fifo_enable && line == 3) {
-                       *(rp++) = RISC_WRITECR;
-                       *(rp++) = sram_ch->dma_ctl;
-                       *(rp++) = FLD_VID_FIFO_EN;
-                       *(rp++) = 0x00000001;
+                       *(rp++) = cpu_to_le32(RISC_WRITECR);
+                       *(rp++) = cpu_to_le32(sram_ch->dma_ctl);
+                       *(rp++) = cpu_to_le32(FLD_VID_FIFO_EN);
+                       *(rp++) = cpu_to_le32(0x00000001);
                }
        }
 
index aba5b1c..400eb1c 100644 (file)
@@ -834,7 +834,7 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
 
        /* get irq */
        err = request_irq(chip->pci->irq, cx8801_irq,
-                         IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip);
+                         IRQF_SHARED, chip->core->name, chip);
        if (err < 0) {
                dprintk(0, "%s: can't get IRQ %d\n",
                       chip->core->name, chip->pci->irq);
@@ -935,8 +935,6 @@ static void cx88_audio_finidev(struct pci_dev *pci)
 
        snd_card_free((void *)card);
 
-       pci_set_drvdata(pci, NULL);
-
        devno--;
 }
 
@@ -951,27 +949,4 @@ static struct pci_driver cx88_audio_pci_driver = {
        .remove   = cx88_audio_finidev,
 };
 
-/****************************************************************************
-                               LINUX MODULE INIT
- ****************************************************************************/
-
-/*
- * module init
- */
-static int __init cx88_audio_init(void)
-{
-       printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
-              CX88_VERSION);
-       return pci_register_driver(&cx88_audio_pci_driver);
-}
-
-/*
- * module remove
- */
-static void __exit cx88_audio_fini(void)
-{
-       pci_unregister_driver(&cx88_audio_pci_driver);
-}
-
-module_init(cx88_audio_init);
-module_exit(cx88_audio_fini);
+module_pci_driver(cx88_audio_pci_driver);
index 2d3507e..74b7b86 100644 (file)
@@ -499,7 +499,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
 
        /* get irq */
        err = request_irq(dev->pci->irq, cx8802_irq,
-                         IRQF_SHARED | IRQF_DISABLED, dev->core->name, dev);
+                         IRQF_SHARED, dev->core->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n",
                       dev->core->name, dev->pci->irq);
@@ -520,7 +520,6 @@ static void cx8802_fini_common(struct cx8802_dev *dev)
 
        /* unregister stuff */
        free_irq(dev->pci->irq, dev);
-       pci_set_drvdata(dev->pci, NULL);
 
        /* free memory */
        btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
@@ -903,20 +902,8 @@ static struct pci_driver cx8802_pci_driver = {
        .remove   = cx8802_remove,
 };
 
-static int __init cx8802_init(void)
-{
-       printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n",
-              CX88_VERSION);
-       return pci_register_driver(&cx8802_pci_driver);
-}
-
-static void __exit cx8802_fini(void)
-{
-       pci_unregister_driver(&cx8802_pci_driver);
-}
+module_pci_driver(cx8802_pci_driver);
 
-module_init(cx8802_init);
-module_exit(cx8802_fini);
 EXPORT_SYMBOL(cx8802_buf_prepare);
 EXPORT_SYMBOL(cx8802_buf_queue);
 EXPORT_SYMBOL(cx8802_cancel_buffers);
index ecf21d9..ed8cb90 100644 (file)
@@ -1738,7 +1738,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
 
        /* get irq */
        err = request_irq(pci_dev->irq, cx8800_irq,
-                         IRQF_SHARED | IRQF_DISABLED, core->name, dev);
+                         IRQF_SHARED, core->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s/0: can't get IRQ %d\n",
                       core->name,pci_dev->irq);
@@ -1922,7 +1922,6 @@ static void cx8800_finidev(struct pci_dev *pci_dev)
 
        free_irq(pci_dev->irq, dev);
        cx8800_unregister_video(dev);
-       pci_set_drvdata(pci_dev, NULL);
 
        /* free memory */
        btcx_riscmem_free(dev->pci,&dev->vidq.stopper);
@@ -2039,17 +2038,4 @@ static struct pci_driver cx8800_pci_driver = {
 #endif
 };
 
-static int __init cx8800_init(void)
-{
-       printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n",
-              CX88_VERSION);
-       return pci_register_driver(&cx8800_pci_driver);
-}
-
-static void __exit cx8800_fini(void)
-{
-       pci_unregister_driver(&cx8800_pci_driver);
-}
-
-module_init(cx8800_init);
-module_exit(cx8800_fini);
+module_pci_driver(cx8800_pci_driver);
index 36e3452..9375f30 100644 (file)
@@ -1544,7 +1544,7 @@ static void ddb_unmap(struct ddb *dev)
 
 static void ddb_remove(struct pci_dev *pdev)
 {
-       struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
+       struct ddb *dev = pci_get_drvdata(pdev);
 
        ddb_ports_detach(dev);
        ddb_i2c_release(dev);
index ab797fe..e60ac35 100644 (file)
@@ -1178,7 +1178,6 @@ err_pci_release_regions:
 err_pci_disable_device:
        pci_disable_device(pdev);
 err_kfree:
-       pci_set_drvdata(pdev, NULL);
        kfree(dev);
        return ret;
 }
@@ -1202,8 +1201,7 @@ static void dm1105_remove(struct pci_dev *pdev)
        dvb_dmxdev_release(&dev->dmxdev);
        dvb_dmx_release(dvbdemux);
        dvb_unregister_adapter(dvb_adapter);
-       if (&dev->i2c_adap)
-               i2c_del_adapter(&dev->i2c_adap);
+       i2c_del_adapter(&dev->i2c_adap);
 
        dm1105_hw_exit(dev);
        synchronize_irq(pdev->irq);
@@ -1211,7 +1209,6 @@ static void dm1105_remove(struct pci_dev *pdev)
        pci_iounmap(pdev, dev->io_mem);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
        dm1105_devcount--;
        kfree(dev);
 }
index c08ae3e..802642d 100644 (file)
@@ -1261,7 +1261,7 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 
        /* Register IRQ */
        retval = request_irq(itv->pdev->irq, ivtv_irq_handler,
-            IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv);
+            IRQF_SHARED, itv->v4l2_dev.name, (void *)itv);
        if (retval) {
                IVTV_ERR("Failed to register irq %d\n", retval);
                goto free_i2c;
index a846036..9e89e04 100644 (file)
@@ -143,7 +143,6 @@ fail1:
 
 fail0:
        dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
-       pci_set_drvdata(pdev, NULL);
        return ret;
 }
 EXPORT_SYMBOL_GPL(mantis_pci_init);
@@ -161,7 +160,6 @@ void mantis_pci_exit(struct mantis_pci *mantis)
        }
 
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 }
 EXPORT_SYMBOL_GPL(mantis_pci_exit);
 
index 2381b05..54d5c82 100644 (file)
@@ -1698,7 +1698,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 
        meye.mchip_irq = pcidev->irq;
        if (request_irq(meye.mchip_irq, meye_irq,
-                       IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) {
+                       IRQF_SHARED, "meye", meye_irq)) {
                v4l2_err(v4l2_dev, "request_irq failed\n");
                goto outreqirq;
        }
index 37ebc42..970e833 100644 (file)
@@ -1622,7 +1622,7 @@ static void ngene_unlink(struct ngene *dev)
 
 void ngene_shutdown(struct pci_dev *pdev)
 {
-       struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+       struct ngene *dev = pci_get_drvdata(pdev);
 
        if (!dev || !shutdown_workaround)
                return;
@@ -1648,7 +1648,6 @@ void ngene_remove(struct pci_dev *pdev)
                cxd_detach(dev);
        ngene_stop(dev);
        ngene_release_buffers(dev);
-       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 }
 
@@ -1702,6 +1701,5 @@ fail1:
        ngene_release_buffers(dev);
 fail0:
        pci_disable_device(pci_dev);
-       pci_set_drvdata(pci_dev, NULL);
        return stat;
 }
index 4938285..8164d74 100644 (file)
@@ -736,7 +736,6 @@ err_pci_release_regions:
 err_pci_disable_device:
        pci_disable_device(pdev);
 err_kfree:
-       pci_set_drvdata(pdev, NULL);
        kfree(pluto);
        goto out;
 }
@@ -765,7 +764,6 @@ static void pluto2_remove(struct pci_dev *pdev)
        pci_iounmap(pdev, pluto->io_mem);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
        kfree(pluto);
 }
 
index 75ce142..db887b0 100644 (file)
@@ -1076,7 +1076,6 @@ static void pt1_remove(struct pci_dev *pdev)
        pt1_update_power(pt1);
        pt1_cleanup_adapters(pt1);
        i2c_del_adapter(&pt1->i2c_adap);
-       pci_set_drvdata(pdev, NULL);
        kfree(pt1);
        pci_iounmap(pdev, regs);
        pci_release_regions(pdev);
@@ -1198,7 +1197,6 @@ err_i2c_del_adapter:
 err_pt1_cleanup_adapters:
        pt1_cleanup_adapters(pt1);
 err_kfree:
-       pci_set_drvdata(pdev, NULL);
        kfree(pt1);
 err_pci_iounmap:
        pci_iounmap(pdev, regs);
index dbcdfbf..dd67c8a 100644 (file)
@@ -1096,7 +1096,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
 
 
        err = request_irq(dev->pci->irq, saa7134_alsa_irq,
-                               IRQF_SHARED | IRQF_DISABLED, dev->name,
+                               IRQF_SHARED, dev->name,
                                (void*) &dev->dmasound);
 
        if (err < 0) {
index 45f0aca..27d7ee7 100644 (file)
@@ -992,7 +992,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
 
        /* get irq */
        err = request_irq(pci_dev->irq, saa7134_irq,
-                         IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+                         IRQF_SHARED, dev->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n",
                       dev->name,pci_dev->irq);
index d37ee37..57ef545 100644 (file)
@@ -1232,7 +1232,7 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
        }
 
        err = request_irq(pci_dev->irq, saa7164_irq,
-               IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+               IRQF_SHARED, dev->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
                        pci_dev->irq);
@@ -1439,7 +1439,6 @@ static void saa7164_finidev(struct pci_dev *pci_dev)
 
        /* unregister stuff */
        free_irq(pci_dev->irq, dev);
-       pci_set_drvdata(pci_dev, NULL);
 
        mutex_lock(&devlist);
        list_del(&dev->devlist);
index 923d59a..cec5b75 100644 (file)
@@ -1293,7 +1293,7 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        result = request_irq(zr->pci_dev->irq, zoran_irq,
-                            IRQF_SHARED | IRQF_DISABLED, ZR_DEVNAME(zr), zr);
+                            IRQF_SHARED, ZR_DEVNAME(zr), zr);
        if (result < 0) {
                if (result == -EINVAL) {
                        dprintk(1,
index eb70dda..d7f0249 100644 (file)
@@ -143,6 +143,7 @@ if V4L_MEM2MEM_DRIVERS
 config VIDEO_CODA
        tristate "Chips&Media Coda multi-standard codec IP"
        depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC
+       select SRAM
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        ---help---
@@ -212,7 +213,7 @@ config VIDEO_SH_VEU
 
 config VIDEO_RENESAS_VSP1
        tristate "Renesas VSP1 Video Processing Engine"
-       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a V4L2 driver for the Renesas VSP1 video processing engine.
@@ -220,6 +221,22 @@ config VIDEO_RENESAS_VSP1
          To compile this driver as a module, choose M here: the module
          will be called vsp1.
 
+config VIDEO_TI_VPE
+       tristate "TI VPE (Video Processing Engine) driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       default n
+       ---help---
+         Support for the TI VPE(Video Processing Engine) block
+         found on DRA7XX SoC.
+
+config VIDEO_TI_VPE_DEBUG
+       bool "VPE debug messages"
+       depends on VIDEO_TI_VPE
+       ---help---
+         Enable debug messages on VPE driver.
+
 endif # V4L_MEM2MEM_DRIVERS
 
 menuconfig V4L_TEST_DRIVERS
index 4e4da48..1348ba1 100644 (file)
@@ -22,6 +22,8 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 
 obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 
+obj-$(CONFIG_VIDEO_TI_VPE)             += ti-vpe/
+
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP)                += mx2_emmaprp.o
 obj-$(CONFIG_VIDEO_CODA)               += coda.o
 
index 4993610..bd72fb9 100644 (file)
@@ -39,7 +39,7 @@
 
 #define CODA_NAME              "coda"
 
-#define CODA_MAX_INSTANCES     4
+#define CODADX6_MAX_INSTANCES  4
 
 #define CODA_FMO_BUF_SIZE      32
 #define CODADX6_WORK_BUF_SIZE  (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
@@ -54,8 +54,6 @@
 
 #define CODA_MAX_FRAMEBUFFERS  8
 
-#define MAX_W          8192
-#define MAX_H          8192
 #define CODA_MAX_FRAME_SIZE    0x100000
 #define FMO_SLICE_SAVE_BUF_SIZE         (32)
 #define CODA_DEFAULT_GAMMA             4096
@@ -394,14 +392,57 @@ static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
        return &codecs[k];
 }
 
+static void coda_get_max_dimensions(struct coda_dev *dev,
+                                   struct coda_codec *codec,
+                                   int *max_w, int *max_h)
+{
+       struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       unsigned int w, h;
+       int k;
+
+       if (codec) {
+               w = codec->max_w;
+               h = codec->max_h;
+       } else {
+               for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
+                       w = max(w, codecs[k].max_w);
+                       h = max(h, codecs[k].max_h);
+               }
+       }
+
+       if (max_w)
+               *max_w = w;
+       if (max_h)
+               *max_h = h;
+}
+
+static char *coda_product_name(int product)
+{
+       static char buf[9];
+
+       switch (product) {
+       case CODA_DX6:
+               return "CodaDx6";
+       case CODA_7541:
+               return "CODA7541";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", product);
+               return buf;
+       }
+}
+
 /*
  * V4L2 ioctl() operations.
  */
-static int vidioc_querycap(struct file *file, void *priv,
-                          struct v4l2_capability *cap)
+static int coda_querycap(struct file *file, void *priv,
+                        struct v4l2_capability *cap)
 {
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
        strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
-       strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
+       strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
+               sizeof(cap->card));
        strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
        /*
         * This is only a mem-to-mem video device. The capture and output
@@ -457,6 +498,8 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
                fmt = &formats[i];
                strlcpy(f->description, fmt->name, sizeof(f->description));
                f->pixelformat = fmt->fourcc;
+               if (!coda_format_is_yuv(fmt->fourcc))
+                       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
                return 0;
        }
 
@@ -464,8 +507,8 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
        return -EINVAL;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
-                                  struct v4l2_fmtdesc *f)
+static int coda_enum_fmt_vid_cap(struct file *file, void *priv,
+                                struct v4l2_fmtdesc *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        struct vb2_queue *src_vq;
@@ -483,13 +526,14 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
        return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
 }
 
-static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-                                  struct v4l2_fmtdesc *f)
+static int coda_enum_fmt_vid_out(struct file *file, void *priv,
+                                struct v4l2_fmtdesc *f)
 {
        return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
 }
 
-static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+static int coda_g_fmt(struct file *file, void *priv,
+                     struct v4l2_format *f)
 {
        struct vb2_queue *vq;
        struct coda_q_data *q_data;
@@ -516,8 +560,11 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        return 0;
 }
 
-static int vidioc_try_fmt(struct coda_codec *codec, struct v4l2_format *f)
+static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
+                       struct v4l2_format *f)
 {
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data;
        unsigned int max_w, max_h;
        enum v4l2_field field;
 
@@ -531,32 +578,48 @@ static int vidioc_try_fmt(struct coda_codec *codec, struct v4l2_format *f)
         * if any of the dimensions is unsupported */
        f->fmt.pix.field = field;
 
-       if (codec) {
-               max_w = codec->max_w;
-               max_h = codec->max_h;
-       } else {
-               max_w = MAX_W;
-               max_h = MAX_H;
+       coda_get_max_dimensions(dev, codec, &max_w, &max_h);
+       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
+                             &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
+                             S_ALIGN);
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
+               break;
+       default:
+               q_data = get_q_data(ctx, f->type);
+               f->fmt.pix.pixelformat = q_data->fourcc;
        }
-       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w,
-                             W_ALIGN, &f->fmt.pix.height,
-                             MIN_H, max_h, H_ALIGN, S_ALIGN);
 
-       if (coda_format_is_yuv(f->fmt.pix.pixelformat)) {
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
                /* Frame stride must be multiple of 8 */
                f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 8);
                f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
                                        f->fmt.pix.height * 3 / 2;
-       } else { /*encoded formats h.264/mpeg4 */
+               break;
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
                f->fmt.pix.bytesperline = 0;
                f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+               break;
+       default:
+               BUG();
        }
 
+       f->fmt.pix.priv = 0;
+
        return 0;
 }
 
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-                                 struct v4l2_format *f)
+static int coda_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        struct coda_codec *codec;
@@ -584,7 +647,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.colorspace = ctx->colorspace;
 
-       ret = vidioc_try_fmt(codec, f);
+       ret = coda_try_fmt(ctx, codec, f);
        if (ret < 0)
                return ret;
 
@@ -600,8 +663,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
-                                 struct v4l2_format *f)
+static int coda_try_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        struct coda_codec *codec;
@@ -613,10 +676,10 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
        if (!f->fmt.pix.colorspace)
                f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 
-       return vidioc_try_fmt(codec, f);
+       return coda_try_fmt(ctx, codec, f);
 }
 
-static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
 {
        struct coda_q_data *q_data;
        struct vb2_queue *vq;
@@ -646,61 +709,62 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
        return 0;
 }
 
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
+static int coda_s_fmt_vid_cap(struct file *file, void *priv,
+                             struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        int ret;
 
-       ret = vidioc_try_fmt_vid_cap(file, priv, f);
+       ret = coda_try_fmt_vid_cap(file, priv, f);
        if (ret)
                return ret;
 
-       return vidioc_s_fmt(ctx, f);
+       return coda_s_fmt(ctx, f);
 }
 
-static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
-                               struct v4l2_format *f)
+static int coda_s_fmt_vid_out(struct file *file, void *priv,
+                             struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        int ret;
 
-       ret = vidioc_try_fmt_vid_out(file, priv, f);
+       ret = coda_try_fmt_vid_out(file, priv, f);
        if (ret)
                return ret;
 
-       ret = vidioc_s_fmt(ctx, f);
+       ret = coda_s_fmt(ctx, f);
        if (ret)
                ctx->colorspace = f->fmt.pix.colorspace;
 
        return ret;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *reqbufs)
+static int coda_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *reqbufs)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
 
-static int vidioc_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
+static int coda_querybuf(struct file *file, void *priv,
+                        struct v4l2_buffer *buf)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 }
 
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+static int coda_qbuf(struct file *file, void *priv,
+                    struct v4l2_buffer *buf)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
 
-static int vidioc_expbuf(struct file *file, void *priv,
-                        struct v4l2_exportbuffer *eb)
+static int coda_expbuf(struct file *file, void *priv,
+                      struct v4l2_exportbuffer *eb)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
@@ -718,7 +782,8 @@ static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
                (buf->sequence == (ctx->qsequence - 1)));
 }
 
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+static int coda_dqbuf(struct file *file, void *priv,
+                     struct v4l2_buffer *buf)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        int ret;
@@ -738,24 +803,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
        return ret;
 }
 
-static int vidioc_create_bufs(struct file *file, void *priv,
-                             struct v4l2_create_buffers *create)
+static int coda_create_bufs(struct file *file, void *priv,
+                           struct v4l2_create_buffers *create)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create);
 }
 
-static int vidioc_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type type)
+static int coda_streamon(struct file *file, void *priv,
+                        enum v4l2_buf_type type)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 }
 
-static int vidioc_streamoff(struct file *file, void *priv,
-                           enum v4l2_buf_type type)
+static int coda_streamoff(struct file *file, void *priv,
+                         enum v4l2_buf_type type)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        int ret;
@@ -772,23 +837,34 @@ static int vidioc_streamoff(struct file *file, void *priv,
        return ret;
 }
 
-static int vidioc_decoder_cmd(struct file *file, void *fh,
-                             struct v4l2_decoder_cmd *dc)
+static int coda_try_decoder_cmd(struct file *file, void *fh,
+                               struct v4l2_decoder_cmd *dc)
 {
-       struct coda_ctx *ctx = fh_to_ctx(fh);
-
        if (dc->cmd != V4L2_DEC_CMD_STOP)
                return -EINVAL;
 
-       if ((dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) ||
-           (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY))
+       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
                return -EINVAL;
 
-       if (dc->stop.pts != 0)
+       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
                return -EINVAL;
 
+       return 0;
+}
+
+static int coda_decoder_cmd(struct file *file, void *fh,
+                           struct v4l2_decoder_cmd *dc)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       int ret;
+
+       ret = coda_try_decoder_cmd(file, fh, dc);
+       if (ret < 0)
+               return ret;
+
+       /* Ignore decoder stop command silently in encoder context */
        if (ctx->inst_type != CODA_INST_DECODER)
-               return -EINVAL;
+               return 0;
 
        /* Set the strem-end flag on this context */
        ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
@@ -796,8 +872,8 @@ static int vidioc_decoder_cmd(struct file *file, void *fh,
        return 0;
 }
 
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
-                                 const struct v4l2_event_subscription *sub)
+static int coda_subscribe_event(struct v4l2_fh *fh,
+                               const struct v4l2_event_subscription *sub)
 {
        switch (sub->type) {
        case V4L2_EVENT_EOS:
@@ -808,32 +884,33 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
 }
 
 static const struct v4l2_ioctl_ops coda_ioctl_ops = {
-       .vidioc_querycap        = vidioc_querycap,
+       .vidioc_querycap        = coda_querycap,
 
-       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap   = vidioc_g_fmt,
-       .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = coda_g_fmt,
+       .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = coda_s_fmt_vid_cap,
 
-       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
-       .vidioc_g_fmt_vid_out   = vidioc_g_fmt,
-       .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
-       .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out   = coda_g_fmt,
+       .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = coda_s_fmt_vid_out,
 
-       .vidioc_reqbufs         = vidioc_reqbufs,
-       .vidioc_querybuf        = vidioc_querybuf,
+       .vidioc_reqbufs         = coda_reqbufs,
+       .vidioc_querybuf        = coda_querybuf,
 
-       .vidioc_qbuf            = vidioc_qbuf,
-       .vidioc_expbuf          = vidioc_expbuf,
-       .vidioc_dqbuf           = vidioc_dqbuf,
-       .vidioc_create_bufs     = vidioc_create_bufs,
+       .vidioc_qbuf            = coda_qbuf,
+       .vidioc_expbuf          = coda_expbuf,
+       .vidioc_dqbuf           = coda_dqbuf,
+       .vidioc_create_bufs     = coda_create_bufs,
 
-       .vidioc_streamon        = vidioc_streamon,
-       .vidioc_streamoff       = vidioc_streamoff,
+       .vidioc_streamon        = coda_streamon,
+       .vidioc_streamoff       = coda_streamoff,
 
-       .vidioc_decoder_cmd     = vidioc_decoder_cmd,
+       .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
+       .vidioc_decoder_cmd     = coda_decoder_cmd,
 
-       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_subscribe_event = coda_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
@@ -1928,8 +2005,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        if (!(ctx->streamon_out & ctx->streamon_cap))
                return 0;
 
-       /* Allow device_run with no buffers queued and after streamoff */
-       v4l2_m2m_set_src_buffered(ctx->m2m_ctx, true);
+       /* Allow decoder device_run with no new buffers queued */
+       if (ctx->inst_type == CODA_INST_DECODER)
+               v4l2_m2m_set_src_buffered(ctx->m2m_ctx, true);
 
        ctx->gopcounter = ctx->params.gop_size - 1;
        buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
@@ -2071,10 +2149,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        coda_setup_iram(ctx);
 
        if (dst_fourcc == V4L2_PIX_FMT_H264) {
-               value  = (FMO_SLICE_SAVE_BUF_SIZE << 7);
-               value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET;
-               value |=  0 & CODA_FMOPARAM_SLICENUM_MASK;
                if (dev->devtype->product == CODA_DX6) {
+                       value = FMO_SLICE_SAVE_BUF_SIZE << 7;
                        coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
                } else {
                        coda_write(dev, ctx->iram_info.search_ram_paddr,
@@ -2371,7 +2447,13 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
 
 static int coda_next_free_instance(struct coda_dev *dev)
 {
-       return ffz(dev->instance_mask);
+       int idx = ffz(dev->instance_mask);
+
+       if ((idx < 0) ||
+           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
+               return -EBUSY;
+
+       return idx;
 }
 
 static int coda_open(struct file *file)
@@ -2386,8 +2468,8 @@ static int coda_open(struct file *file)
                return -ENOMEM;
 
        idx = coda_next_free_instance(dev);
-       if (idx >= CODA_MAX_INSTANCES) {
-               ret = -EBUSY;
+       if (idx < 0) {
+               ret = idx;
                goto err_coda_max;
        }
        set_bit(idx, &dev->instance_mask);
@@ -2719,7 +2801,6 @@ static void coda_finish_encode(struct coda_ctx *ctx)
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
        /* Get results from the coda */
-       coda_read(dev, CODA_RET_ENC_PIC_TYPE);
        start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
        wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
 
@@ -2739,7 +2820,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
        coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
        coda_read(dev, CODA_RET_ENC_PIC_FLAG);
 
-       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+       if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
                dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
                dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
        } else {
@@ -2861,21 +2942,6 @@ static bool coda_firmware_supported(u32 vernum)
        return false;
 }
 
-static char *coda_product_name(int product)
-{
-       static char buf[9];
-
-       switch (product) {
-       case CODA_DX6:
-               return "CodaDx6";
-       case CODA_7541:
-               return "CODA7541";
-       default:
-               snprintf(buf, sizeof(buf), "(0x%04x)", product);
-               return buf;
-       }
-}
-
 static int coda_hw_init(struct coda_dev *dev)
 {
        u16 product, major, minor, release;
index 04609cc..eac472b 100644 (file)
@@ -1785,7 +1785,7 @@ static int vpbe_display_probe(struct platform_device *pdev)
        }
 
        irq = res->start;
-       err = devm_request_irq(&pdev->dev, irq, venc_isr, IRQF_DISABLED,
+       err = devm_request_irq(&pdev->dev, irq, venc_isr, 0,
                               VPBE_DISPLAY_DRIVER, disp_dev);
        if (err) {
                v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
index 9360909..d762246 100644 (file)
@@ -688,7 +688,7 @@ static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
        frame_format = ccdc_dev->hw_ops.get_frame_format();
        if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
                return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
-                                   IRQF_DISABLED, "vpfe_capture1",
+                                   0, "vpfe_capture1",
                                    vpfe_dev);
        }
        return 0;
@@ -1863,7 +1863,7 @@ static int vpfe_probe(struct platform_device *pdev)
        }
        vpfe_dev->ccdc_irq1 = res1->start;
 
-       ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+       ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0,
                          "vpfe_capture0", vpfe_dev);
 
        if (0 != ret) {
index 1089834..52ac5e6 100644 (file)
@@ -2154,7 +2154,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 
                        if (!vpif_obj.sd[i]) {
                                vpif_err("Error registering v4l2 subdevice\n");
-                               err = -ENOMEM;
+                               err = -ENODEV;
                                goto probe_subdev_out;
                        }
                        v4l2_info(&vpif_obj.v4l2_dev,
index 76435d3..ef0a656 100644 (file)
@@ -45,6 +45,7 @@
 #define GSC_DST_FMT                    (1 << 2)
 #define GSC_CTX_M2M                    (1 << 3)
 #define GSC_CTX_STOP_REQ               (1 << 6)
+#define        GSC_CTX_ABORT                   (1 << 7)
 
 enum gsc_dev_flags {
        /* for global */
index e576ff2..810c3e1 100644 (file)
@@ -46,6 +46,17 @@ static int gsc_m2m_ctx_stop_req(struct gsc_ctx *ctx)
        return ret == 0 ? -ETIMEDOUT : ret;
 }
 
+static void __gsc_m2m_job_abort(struct gsc_ctx *ctx)
+{
+       int ret;
+
+       ret = gsc_m2m_ctx_stop_req(ctx);
+       if ((ret == -ETIMEDOUT) || (ctx->state & GSC_CTX_ABORT)) {
+               gsc_ctx_state_lock_clear(GSC_CTX_STOP_REQ | GSC_CTX_ABORT, ctx);
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+       }
+}
+
 static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct gsc_ctx *ctx = q->drv_priv;
@@ -58,11 +69,8 @@ static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
 static int gsc_m2m_stop_streaming(struct vb2_queue *q)
 {
        struct gsc_ctx *ctx = q->drv_priv;
-       int ret;
 
-       ret = gsc_m2m_ctx_stop_req(ctx);
-       if (ret == -ETIMEDOUT)
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+       __gsc_m2m_job_abort(ctx);
 
        pm_runtime_put(&ctx->gsc_dev->pdev->dev);
 
@@ -91,15 +99,9 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
        }
 }
 
-
 static void gsc_m2m_job_abort(void *priv)
 {
-       struct gsc_ctx *ctx = priv;
-       int ret;
-
-       ret = gsc_m2m_ctx_stop_req(ctx);
-       if (ret == -ETIMEDOUT)
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+       __gsc_m2m_job_abort((struct gsc_ctx *)priv);
 }
 
 static int gsc_get_bufs(struct gsc_ctx *ctx)
@@ -150,9 +152,10 @@ static void gsc_m2m_device_run(void *priv)
                gsc->m2m.ctx = ctx;
        }
 
-       is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
-       ctx->state &= ~GSC_CTX_STOP_REQ;
+       is_set = ctx->state & GSC_CTX_STOP_REQ;
        if (is_set) {
+               ctx->state &= ~GSC_CTX_STOP_REQ;
+               ctx->state |= GSC_CTX_ABORT;
                wake_up(&gsc->irq_queue);
                goto put_device;
        }
index d2e6cba..f3c6136 100644 (file)
@@ -511,7 +511,7 @@ static int __ctrl_set_metering(struct fimc_is *is, unsigned int value)
                break;
        default:
                return -EINVAL;
-       };
+       }
 
        __is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val);
        return 0;
index 540516c..36513e8 100644 (file)
@@ -1084,8 +1084,7 @@ free_dev:
 
 static int deinterlace_remove(struct platform_device *pdev)
 {
-       struct deinterlace_dev *pcdev =
-               (struct deinterlace_dev *)platform_get_drvdata(pdev);
+       struct deinterlace_dev *pcdev = platform_get_drvdata(pdev);
 
        v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
        v4l2_m2m_release(pcdev->m2m_dev);
index 5184887..32fab30 100644 (file)
@@ -1221,16 +1221,16 @@ static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
 {
        struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
        struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+       struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0);
        struct mcam_dma_desc *desc = mvb->dma_desc;
        struct scatterlist *sg;
        int i;
 
-       mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages,
-                       DMA_FROM_DEVICE);
+       mvb->dma_desc_nent = dma_map_sg(cam->dev, sg_table->sgl,
+                       sg_table->nents, DMA_FROM_DEVICE);
        if (mvb->dma_desc_nent <= 0)
                return -EIO;  /* Not sure what's right here */
-       for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) {
+       for_each_sg(sg_table->sgl, sg, mvb->dma_desc_nent, i) {
                desc->dma_addr = sg_dma_address(sg);
                desc->segment_len = sg_dma_len(sg);
                desc++;
@@ -1241,9 +1241,11 @@ static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
 static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
 {
        struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+       struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0);
 
-       dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE);
+       if (sg_table)
+               dma_unmap_sg(cam->dev, sg_table->sgl,
+                               sg_table->nents, DMA_FROM_DEVICE);
        return 0;
 }
 
index b5a19af..3458fa0 100644 (file)
@@ -481,7 +481,6 @@ static int mmpcam_remove(struct mmp_camera *cam)
        struct mmp_camera_platform_data *pdata;
 
        mmpcam_remove_device(cam);
-       free_irq(cam->irq, mcam);
        mccic_shutdown(mcam);
        mmpcam_power_down(mcam);
        pdata = cam->pdev->dev.platform_data;
index 6a17676..8df5975 100644 (file)
@@ -1090,8 +1090,7 @@ unreg_dev:
 
 static int m2mtest_remove(struct platform_device *pdev)
 {
-       struct m2mtest_dev *dev =
-               (struct m2mtest_dev *)platform_get_drvdata(pdev);
+       struct m2mtest_dev *dev = platform_get_drvdata(pdev);
 
        v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
        v4l2_m2m_release(dev->m2m_dev);
index fd6289d..0b29483 100644 (file)
@@ -840,7 +840,7 @@ put_clk:
 
 static int g2d_remove(struct platform_device *pdev)
 {
-       struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev);
+       struct g2d_dev *dev = platform_get_drvdata(pdev);
 
        v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
        v4l2_m2m_release(dev->m2m_dev);
index 084263d..5f2c4ad 100644 (file)
@@ -404,7 +404,11 @@ leave_handle_frame:
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
        s5p_mfc_clock_off();
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       /* if suspending, wake up device and do not try_run again*/
+       if (test_bit(0, &dev->enter_suspend))
+               wake_up_dev(dev, reason, err);
+       else
+               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 }
 
 /* Error handling for interrupt */
@@ -1101,7 +1105,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        }
        dev->irq = res->start;
        ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
-                                       IRQF_DISABLED, pdev->name, dev);
+                                       0, pdev->name, dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
                goto err_res;
@@ -1286,9 +1290,7 @@ static int s5p_mfc_suspend(struct device *dev)
                /* Try and lock the HW */
                /* Wait on the interrupt waitqueue */
                ret = wait_event_interruptible_timeout(m_dev->queue,
-                       m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
-                       msecs_to_jiffies(MFC_INT_TIMEOUT));
-
+                       m_dev->int_cond, msecs_to_jiffies(MFC_INT_TIMEOUT));
                if (ret == 0) {
                        mfc_err("Waiting for hardware to finish timed out\n");
                        return -EIO;
index ad4f1df..9a6efd6 100644 (file)
@@ -111,7 +111,7 @@ static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
                break;
        default:
                h2r_args.arg[0] = S5P_FIMV_CODEC_NONE;
-       };
+       }
        h2r_args.arg[1] = 0; /* no crc & no pixelcache */
        h2r_args.arg[2] = ctx->ctx.ofs;
        h2r_args.arg[3] = ctx->ctx.size;
index db796c8..ec1a594 100644 (file)
@@ -113,7 +113,7 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
                break;
        default:
                codec_type = S5P_FIMV_CODEC_NONE_V6;
-       };
+       }
        mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6);
        mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6);
        mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6);
index 41f5a3c..4ff3b6c 100644 (file)
@@ -113,7 +113,7 @@ static struct mfc_control controls[] = {
                .minimum = 0,
                .maximum = (1 << 16) - 1,
                .step = 1,
-               .default_value = 0,
+               .default_value = 12,
        },
        {
                .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
@@ -356,7 +356,7 @@ static struct mfc_control controls[] = {
                .minimum = 0,
                .maximum = 51,
                .step = 1,
-               .default_value = 1,
+               .default_value = 51,
        },
        {
                .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
@@ -399,7 +399,7 @@ static struct mfc_control controls[] = {
                .minimum = 1,
                .maximum = 31,
                .step = 1,
-               .default_value = 1,
+               .default_value = 31,
        },
        {
                .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
@@ -444,7 +444,7 @@ static struct mfc_control controls[] = {
                .minimum = 0,
                .maximum = 51,
                .step = 1,
-               .default_value = 1,
+               .default_value = 51,
        },
        {
                .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
index 368582b..58ec7bb 100644 (file)
@@ -1582,7 +1582,7 @@ static int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev)
                break;
        default:
                reason = S5P_MFC_R2H_CMD_EMPTY;
-       };
+       }
        return reason;
 }
 
index b93a21f..74344c7 100644 (file)
@@ -226,7 +226,7 @@ static void mxr_graph_fix_geometry(struct mxr_layer *layer,
                        src->width + src->x_offset, 32767);
                src->full_height = clamp_val(src->full_height,
                        src->height + src->y_offset, 2047);
-       };
+       }
 }
 
 /* PUBLIC API */
index 3d13a63..c9388c4 100644 (file)
@@ -197,7 +197,7 @@ static void mxr_vp_fix_geometry(struct mxr_layer *layer,
                        ALIGN(src->width + src->x_offset, 8), 8192U);
                src->full_height = clamp(src->full_height,
                        src->height + src->y_offset, 8192U);
-       };
+       }
 }
 
 /* PUBLIC API */
index d02a7e0..b21f777 100644 (file)
 #define VIN_MAX_HEIGHT         2048
 
 enum chip_id {
+       RCAR_H2,
        RCAR_H1,
        RCAR_M1,
        RCAR_E1,
@@ -300,7 +301,8 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
                dmr = 0;
                break;
        case V4L2_PIX_FMT_RGB32:
-               if (priv->chip == RCAR_H1 || priv->chip == RCAR_E1) {
+               if (priv->chip == RCAR_H2 || priv->chip == RCAR_H1 ||
+                   priv->chip == RCAR_E1) {
                        dmr = VNDMR_EXRGB;
                        break;
                }
@@ -1381,6 +1383,7 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
 };
 
 static struct platform_device_id rcar_vin_id_table[] = {
+       { "r8a7790-vin",  RCAR_H2 },
        { "r8a7779-vin",  RCAR_H1 },
        { "r8a7778-vin",  RCAR_M1 },
        { "uPD35004-vin", RCAR_E1 },
index 8df22f7..150bd4d 100644 (file)
@@ -1800,7 +1800,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
 
        /* request irq */
        err = devm_request_irq(&pdev->dev, pcdev->irq, sh_mobile_ceu_irq,
-                              IRQF_DISABLED, dev_name(&pdev->dev), pcdev);
+                              0, dev_name(&pdev->dev), pcdev);
        if (err) {
                dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
                goto exit_release_mem;
index 387a232..4b8c024 100644 (file)
@@ -71,13 +71,23 @@ static int video_dev_create(struct soc_camera_device *icd);
 int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
                        struct v4l2_clk *clk)
 {
-       int ret = clk ? v4l2_clk_enable(clk) : 0;
-       if (ret < 0) {
-               dev_err(dev, "Cannot enable clock: %d\n", ret);
-               return ret;
+       int ret;
+       bool clock_toggle;
+
+       if (clk && (!ssdd->unbalanced_power ||
+                   !test_and_set_bit(0, &ssdd->clock_state))) {
+               ret = v4l2_clk_enable(clk);
+               if (ret < 0) {
+                       dev_err(dev, "Cannot enable clock: %d\n", ret);
+                       return ret;
+               }
+               clock_toggle = true;
+       } else {
+               clock_toggle = false;
        }
-       ret = regulator_bulk_enable(ssdd->num_regulators,
-                                       ssdd->regulators);
+
+       ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators,
+                                   ssdd->sd_pdata.regulators);
        if (ret < 0) {
                dev_err(dev, "Cannot enable regulators\n");
                goto eregenable;
@@ -95,10 +105,10 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
        return 0;
 
 epwron:
-       regulator_bulk_disable(ssdd->num_regulators,
-                              ssdd->regulators);
+       regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
+                              ssdd->sd_pdata.regulators);
 eregenable:
-       if (clk)
+       if (clock_toggle)
                v4l2_clk_disable(clk);
 
        return ret;
@@ -120,14 +130,14 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd
                }
        }
 
-       err = regulator_bulk_disable(ssdd->num_regulators,
-                                    ssdd->regulators);
+       err = regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
+                                    ssdd->sd_pdata.regulators);
        if (err < 0) {
                dev_err(dev, "Cannot disable regulators\n");
                ret = ret ? : err;
        }
 
-       if (clk)
+       if (clk && (!ssdd->unbalanced_power || test_and_clear_bit(0, &ssdd->clock_state)))
                v4l2_clk_disable(clk);
 
        return ret;
@@ -137,8 +147,8 @@ EXPORT_SYMBOL(soc_camera_power_off);
 int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
 {
        /* Should not have any effect in synchronous case */
-       return devm_regulator_bulk_get(dev, ssdd->num_regulators,
-                                      ssdd->regulators);
+       return devm_regulator_bulk_get(dev, ssdd->sd_pdata.num_regulators,
+                                      ssdd->sd_pdata.regulators);
 }
 EXPORT_SYMBOL(soc_camera_power_init);
 
@@ -1346,8 +1356,8 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
         * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
         * to allocate them again.
         */
-       ssdd->num_regulators = 0;
-       ssdd->regulators = NULL;
+       ssdd->sd_pdata.num_regulators = 0;
+       ssdd->sd_pdata.regulators = NULL;
        shd->board_info->platform_data = ssdd;
 
        snprintf(clk_name, sizeof(clk_name), "%d-%04x",
@@ -2020,8 +2030,8 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
         * that case regulators are attached to the I2C device and not to the
         * camera platform device.
         */
-       ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators,
-                                     ssdd->regulators);
+       ret = devm_regulator_bulk_get(&pdev->dev, ssdd->sd_pdata.num_regulators,
+                                     ssdd->sd_pdata.regulators);
        if (ret < 0)
                return ret;
 
diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile
new file mode 100644 (file)
index 0000000..cbf0a80
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o
+
+ti-vpe-y := vpe.o vpdma.o
+
+ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
new file mode 100644 (file)
index 0000000..af0a5ff
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * VPDMA helper library
+ *
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include "vpdma.h"
+#include "vpdma_priv.h"
+
+#define VPDMA_FIRMWARE "vpdma-1b8.bin"
+
+const struct vpdma_data_format vpdma_yuv_fmts[] = {
+       [VPDMA_DATA_FMT_Y444] = {
+               .data_type      = DATA_TYPE_Y444,
+               .depth          = 8,
+       },
+       [VPDMA_DATA_FMT_Y422] = {
+               .data_type      = DATA_TYPE_Y422,
+               .depth          = 8,
+       },
+       [VPDMA_DATA_FMT_Y420] = {
+               .data_type      = DATA_TYPE_Y420,
+               .depth          = 8,
+       },
+       [VPDMA_DATA_FMT_C444] = {
+               .data_type      = DATA_TYPE_C444,
+               .depth          = 8,
+       },
+       [VPDMA_DATA_FMT_C422] = {
+               .data_type      = DATA_TYPE_C422,
+               .depth          = 8,
+       },
+       [VPDMA_DATA_FMT_C420] = {
+               .data_type      = DATA_TYPE_C420,
+               .depth          = 4,
+       },
+       [VPDMA_DATA_FMT_YC422] = {
+               .data_type      = DATA_TYPE_YC422,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_YC444] = {
+               .data_type      = DATA_TYPE_YC444,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_CY422] = {
+               .data_type      = DATA_TYPE_CY422,
+               .depth          = 16,
+       },
+};
+
+const struct vpdma_data_format vpdma_rgb_fmts[] = {
+       [VPDMA_DATA_FMT_RGB565] = {
+               .data_type      = DATA_TYPE_RGB16_565,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ARGB16_1555] = {
+               .data_type      = DATA_TYPE_ARGB_1555,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ARGB16] = {
+               .data_type      = DATA_TYPE_ARGB_4444,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_RGBA16_5551] = {
+               .data_type      = DATA_TYPE_RGBA_5551,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_RGBA16] = {
+               .data_type      = DATA_TYPE_RGBA_4444,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ARGB24] = {
+               .data_type      = DATA_TYPE_ARGB24_6666,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_RGB24] = {
+               .data_type      = DATA_TYPE_RGB24_888,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_ARGB32] = {
+               .data_type      = DATA_TYPE_ARGB32_8888,
+               .depth          = 32,
+       },
+       [VPDMA_DATA_FMT_RGBA24] = {
+               .data_type      = DATA_TYPE_RGBA24_6666,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_RGBA32] = {
+               .data_type      = DATA_TYPE_RGBA32_8888,
+               .depth          = 32,
+       },
+       [VPDMA_DATA_FMT_BGR565] = {
+               .data_type      = DATA_TYPE_BGR16_565,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ABGR16_1555] = {
+               .data_type      = DATA_TYPE_ABGR_1555,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ABGR16] = {
+               .data_type      = DATA_TYPE_ABGR_4444,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_BGRA16_5551] = {
+               .data_type      = DATA_TYPE_BGRA_5551,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_BGRA16] = {
+               .data_type      = DATA_TYPE_BGRA_4444,
+               .depth          = 16,
+       },
+       [VPDMA_DATA_FMT_ABGR24] = {
+               .data_type      = DATA_TYPE_ABGR24_6666,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_BGR24] = {
+               .data_type      = DATA_TYPE_BGR24_888,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_ABGR32] = {
+               .data_type      = DATA_TYPE_ABGR32_8888,
+               .depth          = 32,
+       },
+       [VPDMA_DATA_FMT_BGRA24] = {
+               .data_type      = DATA_TYPE_BGRA24_6666,
+               .depth          = 24,
+       },
+       [VPDMA_DATA_FMT_BGRA32] = {
+               .data_type      = DATA_TYPE_BGRA32_8888,
+               .depth          = 32,
+       },
+};
+
+const struct vpdma_data_format vpdma_misc_fmts[] = {
+       [VPDMA_DATA_FMT_MV] = {
+               .data_type      = DATA_TYPE_MV,
+               .depth          = 4,
+       },
+};
+
+struct vpdma_channel_info {
+       int num;                /* VPDMA channel number */
+       int cstat_offset;       /* client CSTAT register offset */
+};
+
+static const struct vpdma_channel_info chan_info[] = {
+       [VPE_CHAN_LUMA1_IN] = {
+               .num            = VPE_CHAN_NUM_LUMA1_IN,
+               .cstat_offset   = VPDMA_DEI_LUMA1_CSTAT,
+       },
+       [VPE_CHAN_CHROMA1_IN] = {
+               .num            = VPE_CHAN_NUM_CHROMA1_IN,
+               .cstat_offset   = VPDMA_DEI_CHROMA1_CSTAT,
+       },
+       [VPE_CHAN_LUMA2_IN] = {
+               .num            = VPE_CHAN_NUM_LUMA2_IN,
+               .cstat_offset   = VPDMA_DEI_LUMA2_CSTAT,
+       },
+       [VPE_CHAN_CHROMA2_IN] = {
+               .num            = VPE_CHAN_NUM_CHROMA2_IN,
+               .cstat_offset   = VPDMA_DEI_CHROMA2_CSTAT,
+       },
+       [VPE_CHAN_LUMA3_IN] = {
+               .num            = VPE_CHAN_NUM_LUMA3_IN,
+               .cstat_offset   = VPDMA_DEI_LUMA3_CSTAT,
+       },
+       [VPE_CHAN_CHROMA3_IN] = {
+               .num            = VPE_CHAN_NUM_CHROMA3_IN,
+               .cstat_offset   = VPDMA_DEI_CHROMA3_CSTAT,
+       },
+       [VPE_CHAN_MV_IN] = {
+               .num            = VPE_CHAN_NUM_MV_IN,
+               .cstat_offset   = VPDMA_DEI_MV_IN_CSTAT,
+       },
+       [VPE_CHAN_MV_OUT] = {
+               .num            = VPE_CHAN_NUM_MV_OUT,
+               .cstat_offset   = VPDMA_DEI_MV_OUT_CSTAT,
+       },
+       [VPE_CHAN_LUMA_OUT] = {
+               .num            = VPE_CHAN_NUM_LUMA_OUT,
+               .cstat_offset   = VPDMA_VIP_UP_Y_CSTAT,
+       },
+       [VPE_CHAN_CHROMA_OUT] = {
+               .num            = VPE_CHAN_NUM_CHROMA_OUT,
+               .cstat_offset   = VPDMA_VIP_UP_UV_CSTAT,
+       },
+       [VPE_CHAN_RGB_OUT] = {
+               .num            = VPE_CHAN_NUM_RGB_OUT,
+               .cstat_offset   = VPDMA_VIP_UP_Y_CSTAT,
+       },
+};
+
+static u32 read_reg(struct vpdma_data *vpdma, int offset)
+{
+       return ioread32(vpdma->base + offset);
+}
+
+static void write_reg(struct vpdma_data *vpdma, int offset, u32 value)
+{
+       iowrite32(value, vpdma->base + offset);
+}
+
+static int read_field_reg(struct vpdma_data *vpdma, int offset,
+               u32 mask, int shift)
+{
+       return (read_reg(vpdma, offset) & (mask << shift)) >> shift;
+}
+
+static void write_field_reg(struct vpdma_data *vpdma, int offset, u32 field,
+               u32 mask, int shift)
+{
+       u32 val = read_reg(vpdma, offset);
+
+       val &= ~(mask << shift);
+       val |= (field & mask) << shift;
+
+       write_reg(vpdma, offset, val);
+}
+
+void vpdma_dump_regs(struct vpdma_data *vpdma)
+{
+       struct device *dev = &vpdma->pdev->dev;
+
+#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(vpdma, VPDMA_##r))
+
+       dev_dbg(dev, "VPDMA Registers:\n");
+
+       DUMPREG(PID);
+       DUMPREG(LIST_ADDR);
+       DUMPREG(LIST_ATTR);
+       DUMPREG(LIST_STAT_SYNC);
+       DUMPREG(BG_RGB);
+       DUMPREG(BG_YUV);
+       DUMPREG(SETUP);
+       DUMPREG(MAX_SIZE1);
+       DUMPREG(MAX_SIZE2);
+       DUMPREG(MAX_SIZE3);
+
+       /*
+        * dumping registers of only group0 and group3, because VPE channels
+        * lie within group0 and group3 registers
+        */
+       DUMPREG(INT_CHAN_STAT(0));
+       DUMPREG(INT_CHAN_MASK(0));
+       DUMPREG(INT_CHAN_STAT(3));
+       DUMPREG(INT_CHAN_MASK(3));
+       DUMPREG(INT_CLIENT0_STAT);
+       DUMPREG(INT_CLIENT0_MASK);
+       DUMPREG(INT_CLIENT1_STAT);
+       DUMPREG(INT_CLIENT1_MASK);
+       DUMPREG(INT_LIST0_STAT);
+       DUMPREG(INT_LIST0_MASK);
+
+       /*
+        * these are registers specific to VPE clients, we can make this
+        * function dump client registers specific to VPE or VIP based on
+        * who is using it
+        */
+       DUMPREG(DEI_CHROMA1_CSTAT);
+       DUMPREG(DEI_LUMA1_CSTAT);
+       DUMPREG(DEI_CHROMA2_CSTAT);
+       DUMPREG(DEI_LUMA2_CSTAT);
+       DUMPREG(DEI_CHROMA3_CSTAT);
+       DUMPREG(DEI_LUMA3_CSTAT);
+       DUMPREG(DEI_MV_IN_CSTAT);
+       DUMPREG(DEI_MV_OUT_CSTAT);
+       DUMPREG(VIP_UP_Y_CSTAT);
+       DUMPREG(VIP_UP_UV_CSTAT);
+       DUMPREG(VPI_CTL_CSTAT);
+}
+
+/*
+ * Allocate a DMA buffer
+ */
+int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size)
+{
+       buf->size = size;
+       buf->mapped = false;
+       buf->addr = kzalloc(size, GFP_KERNEL);
+       if (!buf->addr)
+               return -ENOMEM;
+
+       WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN);
+
+       return 0;
+}
+
+void vpdma_free_desc_buf(struct vpdma_buf *buf)
+{
+       WARN_ON(buf->mapped);
+       kfree(buf->addr);
+       buf->addr = NULL;
+       buf->size = 0;
+}
+
+/*
+ * map descriptor/payload DMA buffer, enabling DMA access
+ */
+int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf)
+{
+       struct device *dev = &vpdma->pdev->dev;
+
+       WARN_ON(buf->mapped);
+       buf->dma_addr = dma_map_single(dev, buf->addr, buf->size,
+                               DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, buf->dma_addr)) {
+               dev_err(dev, "failed to map buffer\n");
+               return -EINVAL;
+       }
+
+       buf->mapped = true;
+
+       return 0;
+}
+
+/*
+ * unmap descriptor/payload DMA buffer, disabling DMA access and
+ * allowing the main processor to acces the data
+ */
+void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf)
+{
+       struct device *dev = &vpdma->pdev->dev;
+
+       if (buf->mapped)
+               dma_unmap_single(dev, buf->dma_addr, buf->size, DMA_TO_DEVICE);
+
+       buf->mapped = false;
+}
+
+/*
+ * create a descriptor list, the user of this list will append configuration,
+ * control and data descriptors to this list, this list will be submitted to
+ * VPDMA. VPDMA's list parser will go through each descriptor and perform the
+ * required DMA operations
+ */
+int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type)
+{
+       int r;
+
+       r = vpdma_alloc_desc_buf(&list->buf, size);
+       if (r)
+               return r;
+
+       list->next = list->buf.addr;
+
+       list->type = type;
+
+       return 0;
+}
+
+/*
+ * once a descriptor list is parsed by VPDMA, we reset the list by emptying it,
+ * to allow new descriptors to be added to the list.
+ */
+void vpdma_reset_desc_list(struct vpdma_desc_list *list)
+{
+       list->next = list->buf.addr;
+}
+
+/*
+ * free the buffer allocated fot the VPDMA descriptor list, this should be
+ * called when the user doesn't want to use VPDMA any more.
+ */
+void vpdma_free_desc_list(struct vpdma_desc_list *list)
+{
+       vpdma_free_desc_buf(&list->buf);
+
+       list->next = NULL;
+}
+
+static bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num)
+{
+       return read_reg(vpdma, VPDMA_LIST_STAT_SYNC) & BIT(list_num + 16);
+}
+
+/*
+ * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion
+ */
+int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list)
+{
+       /* we always use the first list */
+       int list_num = 0;
+       int list_size;
+
+       if (vpdma_list_busy(vpdma, list_num))
+               return -EBUSY;
+
+       /* 16-byte granularity */
+       list_size = (list->next - list->buf.addr) >> 4;
+
+       write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list->buf.dma_addr);
+
+       write_reg(vpdma, VPDMA_LIST_ATTR,
+                       (list_num << VPDMA_LIST_NUM_SHFT) |
+                       (list->type << VPDMA_LIST_TYPE_SHFT) |
+                       list_size);
+
+       return 0;
+}
+
+static void dump_cfd(struct vpdma_cfd *cfd)
+{
+       int class;
+
+       class = cfd_get_class(cfd);
+
+       pr_debug("config descriptor of payload class: %s\n",
+               class == CFD_CLS_BLOCK ? "simple block" :
+               "address data block");
+
+       if (class == CFD_CLS_BLOCK)
+               pr_debug("word0: dst_addr_offset = 0x%08x\n",
+                       cfd->dest_addr_offset);
+
+       if (class == CFD_CLS_BLOCK)
+               pr_debug("word1: num_data_wrds = %d\n", cfd->block_len);
+
+       pr_debug("word2: payload_addr = 0x%08x\n", cfd->payload_addr);
+
+       pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, "
+               "payload_len = %d\n", cfd_get_pkt_type(cfd),
+               cfd_get_direct(cfd), class, cfd_get_dest(cfd),
+               cfd_get_payload_len(cfd));
+}
+
+/*
+ * append a configuration descriptor to the given descriptor list, where the
+ * payload is in the form of a simple data block specified in the descriptor
+ * header, this is used to upload scaler coefficients to the scaler module
+ */
+void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client,
+               struct vpdma_buf *blk, u32 dest_offset)
+{
+       struct vpdma_cfd *cfd;
+       int len = blk->size;
+
+       WARN_ON(blk->dma_addr & VPDMA_DESC_ALIGN);
+
+       cfd = list->next;
+       WARN_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size));
+
+       cfd->dest_addr_offset = dest_offset;
+       cfd->block_len = len;
+       cfd->payload_addr = (u32) blk->dma_addr;
+       cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_BLOCK,
+                               client, len >> 4);
+
+       list->next = cfd + 1;
+
+       dump_cfd(cfd);
+}
+
+/*
+ * append a configuration descriptor to the given descriptor list, where the
+ * payload is in the address data block format, this is used to a configure a
+ * discontiguous set of MMRs
+ */
+void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
+               struct vpdma_buf *adb)
+{
+       struct vpdma_cfd *cfd;
+       unsigned int len = adb->size;
+
+       WARN_ON(len & VPDMA_ADB_SIZE_ALIGN);
+       WARN_ON(adb->dma_addr & VPDMA_DESC_ALIGN);
+
+       cfd = list->next;
+       BUG_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size));
+
+       cfd->w0 = 0;
+       cfd->w1 = 0;
+       cfd->payload_addr = (u32) adb->dma_addr;
+       cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_ADB,
+                               client, len >> 4);
+
+       list->next = cfd + 1;
+
+       dump_cfd(cfd);
+};
+
+/*
+ * control descriptor format change based on what type of control descriptor it
+ * is, we only use 'sync on channel' control descriptors for now, so assume it's
+ * that
+ */
+static void dump_ctd(struct vpdma_ctd *ctd)
+{
+       pr_debug("control descriptor\n");
+
+       pr_debug("word3: pkt_type = %d, source = %d, ctl_type = %d\n",
+               ctd_get_pkt_type(ctd), ctd_get_source(ctd), ctd_get_ctl(ctd));
+}
+
+/*
+ * append a 'sync on channel' type control descriptor to the given descriptor
+ * list, this descriptor stalls the VPDMA list till the time DMA is completed
+ * on the specified channel
+ */
+void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
+               enum vpdma_channel chan)
+{
+       struct vpdma_ctd *ctd;
+
+       ctd = list->next;
+       WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size));
+
+       ctd->w0 = 0;
+       ctd->w1 = 0;
+       ctd->w2 = 0;
+       ctd->type_source_ctl = ctd_type_source_ctl(chan_info[chan].num,
+                               CTD_TYPE_SYNC_ON_CHANNEL);
+
+       list->next = ctd + 1;
+
+       dump_ctd(ctd);
+}
+
+static void dump_dtd(struct vpdma_dtd *dtd)
+{
+       int dir, chan;
+
+       dir = dtd_get_dir(dtd);
+       chan = dtd_get_chan(dtd);
+
+       pr_debug("%s data transfer descriptor for channel %d\n",
+               dir == DTD_DIR_OUT ? "outbound" : "inbound", chan);
+
+       pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, "
+               "even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n",
+               dtd_get_data_type(dtd), dtd_get_notify(dtd), dtd_get_field(dtd),
+               dtd_get_1d(dtd), dtd_get_even_line_skip(dtd),
+               dtd_get_odd_line_skip(dtd), dtd_get_line_stride(dtd));
+
+       if (dir == DTD_DIR_IN)
+               pr_debug("word1: line_length = %d, xfer_height = %d\n",
+                       dtd_get_line_length(dtd), dtd_get_xfer_height(dtd));
+
+       pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr);
+
+       pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, "
+               "pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd),
+               dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd),
+               dtd_get_next_chan(dtd));
+
+       if (dir == DTD_DIR_IN)
+               pr_debug("word4: frame_width = %d, frame_height = %d\n",
+                       dtd_get_frame_width(dtd), dtd_get_frame_height(dtd));
+       else
+               pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, "
+                       "drp_data = %d, use_desc_reg = %d\n",
+                       dtd_get_desc_write_addr(dtd), dtd_get_write_desc(dtd),
+                       dtd_get_drop_data(dtd), dtd_get_use_desc(dtd));
+
+       if (dir == DTD_DIR_IN)
+               pr_debug("word5: hor_start = %d, ver_start = %d\n",
+                       dtd_get_h_start(dtd), dtd_get_v_start(dtd));
+       else
+               pr_debug("word5: max_width %d, max_height %d\n",
+                       dtd_get_max_width(dtd), dtd_get_max_height(dtd));
+
+       pr_debug("word6: client specfic attr0 = 0x%08x\n", dtd->client_attr0);
+       pr_debug("word7: client specfic attr1 = 0x%08x\n", dtd->client_attr1);
+}
+
+/*
+ * append an outbound data transfer descriptor to the given descriptor list,
+ * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ */
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+               const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
+               enum vpdma_channel chan, u32 flags)
+{
+       int priority = 0;
+       int field = 0;
+       int notify = 1;
+       int channel, next_chan;
+       int depth = fmt->depth;
+       int stride;
+       struct vpdma_dtd *dtd;
+
+       channel = next_chan = chan_info[chan].num;
+
+       if (fmt->data_type == DATA_TYPE_C420)
+               depth = 8;
+
+       stride = (depth * c_rect->width) >> 3;
+       dma_addr += (c_rect->left * depth) >> 3;
+
+       dtd = list->next;
+       WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
+
+       dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type,
+                                       notify,
+                                       field,
+                                       !!(flags & VPDMA_DATA_FRAME_1D),
+                                       !!(flags & VPDMA_DATA_EVEN_LINE_SKIP),
+                                       !!(flags & VPDMA_DATA_ODD_LINE_SKIP),
+                                       stride);
+       dtd->w1 = 0;
+       dtd->start_addr = (u32) dma_addr;
+       dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
+                               DTD_DIR_OUT, channel, priority, next_chan);
+       dtd->desc_write_addr = dtd_desc_write_addr(0, 0, 0, 0);
+       dtd->max_width_height = dtd_max_width_height(MAX_OUT_WIDTH_1920,
+                                       MAX_OUT_HEIGHT_1080);
+       dtd->client_attr0 = 0;
+       dtd->client_attr1 = 0;
+
+       list->next = dtd + 1;
+
+       dump_dtd(dtd);
+}
+
+/*
+ * append an inbound data transfer descriptor to the given descriptor list,
+ * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ */
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
+               int frame_height, struct v4l2_rect *c_rect,
+               const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
+               enum vpdma_channel chan, int field, u32 flags)
+{
+       int priority = 0;
+       int notify = 1;
+       int depth = fmt->depth;
+       int channel, next_chan;
+       int stride;
+       int height = c_rect->height;
+       struct vpdma_dtd *dtd;
+
+       channel = next_chan = chan_info[chan].num;
+
+       if (fmt->data_type == DATA_TYPE_C420) {
+               height >>= 1;
+               frame_height >>= 1;
+               depth = 8;
+       }
+
+       stride = (depth * c_rect->width) >> 3;
+       dma_addr += (c_rect->left * depth) >> 3;
+
+       dtd = list->next;
+       WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
+
+       dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type,
+                                       notify,
+                                       field,
+                                       !!(flags & VPDMA_DATA_FRAME_1D),
+                                       !!(flags & VPDMA_DATA_EVEN_LINE_SKIP),
+                                       !!(flags & VPDMA_DATA_ODD_LINE_SKIP),
+                                       stride);
+
+       dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+       dtd->start_addr = (u32) dma_addr;
+       dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
+                               DTD_DIR_IN, channel, priority, next_chan);
+       dtd->frame_width_height = dtd_frame_width_height(frame_width,
+                                       frame_height);
+       dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+       dtd->client_attr0 = 0;
+       dtd->client_attr1 = 0;
+
+       list->next = dtd + 1;
+
+       dump_dtd(dtd);
+}
+
+/* set or clear the mask for list complete interrupt */
+void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
+               bool enable)
+{
+       u32 val;
+
+       val = read_reg(vpdma, VPDMA_INT_LIST0_MASK);
+       if (enable)
+               val |= (1 << (list_num * 2));
+       else
+               val &= ~(1 << (list_num * 2));
+       write_reg(vpdma, VPDMA_INT_LIST0_MASK, val);
+}
+
+/* clear previosuly occured list intterupts in the LIST_STAT register */
+void vpdma_clear_list_stat(struct vpdma_data *vpdma)
+{
+       write_reg(vpdma, VPDMA_INT_LIST0_STAT,
+               read_reg(vpdma, VPDMA_INT_LIST0_STAT));
+}
+
+/*
+ * configures the output mode of the line buffer for the given client, the
+ * line buffer content can either be mirrored(each line repeated twice) or
+ * passed to the client as is
+ */
+void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode,
+               enum vpdma_channel chan)
+{
+       int client_cstat = chan_info[chan].cstat_offset;
+
+       write_field_reg(vpdma, client_cstat, line_mode,
+               VPDMA_CSTAT_LINE_MODE_MASK, VPDMA_CSTAT_LINE_MODE_SHIFT);
+}
+
+/*
+ * configures the event which should trigger VPDMA transfer for the given
+ * client
+ */
+void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
+               enum vpdma_frame_start_event fs_event,
+               enum vpdma_channel chan)
+{
+       int client_cstat = chan_info[chan].cstat_offset;
+
+       write_field_reg(vpdma, client_cstat, fs_event,
+               VPDMA_CSTAT_FRAME_START_MASK, VPDMA_CSTAT_FRAME_START_SHIFT);
+}
+
+static void vpdma_firmware_cb(const struct firmware *f, void *context)
+{
+       struct vpdma_data *vpdma = context;
+       struct vpdma_buf fw_dma_buf;
+       int i, r;
+
+       dev_dbg(&vpdma->pdev->dev, "firmware callback\n");
+
+       if (!f || !f->data) {
+               dev_err(&vpdma->pdev->dev, "couldn't get firmware\n");
+               return;
+       }
+
+       /* already initialized */
+       if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
+                       VPDMA_LIST_RDY_SHFT)) {
+               vpdma->ready = true;
+               return;
+       }
+
+       r = vpdma_alloc_desc_buf(&fw_dma_buf, f->size);
+       if (r) {
+               dev_err(&vpdma->pdev->dev,
+                       "failed to allocate dma buffer for firmware\n");
+               goto rel_fw;
+       }
+
+       memcpy(fw_dma_buf.addr, f->data, f->size);
+
+       vpdma_map_desc_buf(vpdma, &fw_dma_buf);
+
+       write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr);
+
+       for (i = 0; i < 100; i++) {             /* max 1 second */
+               msleep_interruptible(10);
+
+               if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
+                               VPDMA_LIST_RDY_SHFT))
+                       break;
+       }
+
+       if (i == 100) {
+               dev_err(&vpdma->pdev->dev, "firmware upload failed\n");
+               goto free_buf;
+       }
+
+       vpdma->ready = true;
+
+free_buf:
+       vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
+
+       vpdma_free_desc_buf(&fw_dma_buf);
+rel_fw:
+       release_firmware(f);
+}
+
+static int vpdma_load_firmware(struct vpdma_data *vpdma)
+{
+       int r;
+       struct device *dev = &vpdma->pdev->dev;
+
+       r = request_firmware_nowait(THIS_MODULE, 1,
+               (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
+               vpdma_firmware_cb);
+       if (r) {
+               dev_err(dev, "firmware not available %s\n", VPDMA_FIRMWARE);
+               return r;
+       } else {
+               dev_info(dev, "loading firmware %s\n", VPDMA_FIRMWARE);
+       }
+
+       return 0;
+}
+
+struct vpdma_data *vpdma_create(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct vpdma_data *vpdma;
+       int r;
+
+       dev_dbg(&pdev->dev, "vpdma_create\n");
+
+       vpdma = devm_kzalloc(&pdev->dev, sizeof(*vpdma), GFP_KERNEL);
+       if (!vpdma) {
+               dev_err(&pdev->dev, "couldn't alloc vpdma_dev\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       vpdma->pdev = pdev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
+       if (res == NULL) {
+               dev_err(&pdev->dev, "missing platform resources data\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!vpdma->base) {
+               dev_err(&pdev->dev, "failed to ioremap\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       r = vpdma_load_firmware(vpdma);
+       if (r) {
+               pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE);
+               return ERR_PTR(r);
+       }
+
+       return vpdma;
+}
+MODULE_FIRMWARE(VPDMA_FIRMWARE);
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h
new file mode 100644 (file)
index 0000000..eaa2a71
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __TI_VPDMA_H_
+#define __TI_VPDMA_H_
+
+/*
+ * A vpdma_buf tracks the size, DMA address and mapping status of each
+ * driver DMA area.
+ */
+struct vpdma_buf {
+       void                    *addr;
+       dma_addr_t              dma_addr;
+       size_t                  size;
+       bool                    mapped;
+};
+
+struct vpdma_desc_list {
+       struct vpdma_buf buf;
+       void *next;
+       int type;
+};
+
+struct vpdma_data {
+       void __iomem            *base;
+
+       struct platform_device  *pdev;
+
+       /* tells whether vpdma firmware is loaded or not */
+       bool ready;
+};
+
+struct vpdma_data_format {
+       int data_type;
+       u8 depth;
+};
+
+#define VPDMA_DESC_ALIGN               16      /* 16-byte descriptor alignment */
+
+#define VPDMA_DTD_DESC_SIZE            32      /* 8 words */
+#define VPDMA_CFD_CTD_DESC_SIZE                16      /* 4 words */
+
+#define VPDMA_LIST_TYPE_NORMAL         0
+#define VPDMA_LIST_TYPE_SELF_MODIFYING 1
+#define VPDMA_LIST_TYPE_DOORBELL       2
+
+enum vpdma_yuv_formats {
+       VPDMA_DATA_FMT_Y444 = 0,
+       VPDMA_DATA_FMT_Y422,
+       VPDMA_DATA_FMT_Y420,
+       VPDMA_DATA_FMT_C444,
+       VPDMA_DATA_FMT_C422,
+       VPDMA_DATA_FMT_C420,
+       VPDMA_DATA_FMT_YC422,
+       VPDMA_DATA_FMT_YC444,
+       VPDMA_DATA_FMT_CY422,
+};
+
+enum vpdma_rgb_formats {
+       VPDMA_DATA_FMT_RGB565 = 0,
+       VPDMA_DATA_FMT_ARGB16_1555,
+       VPDMA_DATA_FMT_ARGB16,
+       VPDMA_DATA_FMT_RGBA16_5551,
+       VPDMA_DATA_FMT_RGBA16,
+       VPDMA_DATA_FMT_ARGB24,
+       VPDMA_DATA_FMT_RGB24,
+       VPDMA_DATA_FMT_ARGB32,
+       VPDMA_DATA_FMT_RGBA24,
+       VPDMA_DATA_FMT_RGBA32,
+       VPDMA_DATA_FMT_BGR565,
+       VPDMA_DATA_FMT_ABGR16_1555,
+       VPDMA_DATA_FMT_ABGR16,
+       VPDMA_DATA_FMT_BGRA16_5551,
+       VPDMA_DATA_FMT_BGRA16,
+       VPDMA_DATA_FMT_ABGR24,
+       VPDMA_DATA_FMT_BGR24,
+       VPDMA_DATA_FMT_ABGR32,
+       VPDMA_DATA_FMT_BGRA24,
+       VPDMA_DATA_FMT_BGRA32,
+};
+
+enum vpdma_misc_formats {
+       VPDMA_DATA_FMT_MV = 0,
+};
+
+extern const struct vpdma_data_format vpdma_yuv_fmts[];
+extern const struct vpdma_data_format vpdma_rgb_fmts[];
+extern const struct vpdma_data_format vpdma_misc_fmts[];
+
+enum vpdma_frame_start_event {
+       VPDMA_FSEVENT_HDMI_FID = 0,
+       VPDMA_FSEVENT_DVO2_FID,
+       VPDMA_FSEVENT_HDCOMP_FID,
+       VPDMA_FSEVENT_SD_FID,
+       VPDMA_FSEVENT_LM_FID0,
+       VPDMA_FSEVENT_LM_FID1,
+       VPDMA_FSEVENT_LM_FID2,
+       VPDMA_FSEVENT_CHANNEL_ACTIVE,
+};
+
+/*
+ * VPDMA channel numbers
+ */
+enum vpdma_channel {
+       VPE_CHAN_LUMA1_IN,
+       VPE_CHAN_CHROMA1_IN,
+       VPE_CHAN_LUMA2_IN,
+       VPE_CHAN_CHROMA2_IN,
+       VPE_CHAN_LUMA3_IN,
+       VPE_CHAN_CHROMA3_IN,
+       VPE_CHAN_MV_IN,
+       VPE_CHAN_MV_OUT,
+       VPE_CHAN_LUMA_OUT,
+       VPE_CHAN_CHROMA_OUT,
+       VPE_CHAN_RGB_OUT,
+};
+
+/* flags for VPDMA data descriptors */
+#define VPDMA_DATA_ODD_LINE_SKIP       (1 << 0)
+#define VPDMA_DATA_EVEN_LINE_SKIP      (1 << 1)
+#define VPDMA_DATA_FRAME_1D            (1 << 2)
+#define VPDMA_DATA_MODE_TILED          (1 << 3)
+
+/*
+ * client identifiers used for configuration descriptors
+ */
+#define CFD_MMR_CLIENT         0
+#define CFD_SC_CLIENT          4
+
+/* Address data block header format */
+struct vpdma_adb_hdr {
+       u32                     offset;
+       u32                     nwords;
+       u32                     reserved0;
+       u32                     reserved1;
+};
+
+/* helpers for creating ADB headers for config descriptors MMRs as client */
+#define ADB_ADDR(dma_buf, str, fld)    ((dma_buf)->addr + offsetof(str, fld))
+#define MMR_ADB_ADDR(buf, str, fld)    ADB_ADDR(&(buf), struct str, fld)
+
+#define VPDMA_SET_MMR_ADB_HDR(buf, str, hdr, regs, offset_a)   \
+       do {                                                    \
+               struct vpdma_adb_hdr *h;                        \
+               struct str *adb = NULL;                         \
+               h = MMR_ADB_ADDR(buf, str, hdr);                \
+               h->offset = (offset_a);                         \
+               h->nwords = sizeof(adb->regs) >> 2;             \
+       } while (0)
+
+/* vpdma descriptor buffer allocation and management */
+int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size);
+void vpdma_free_desc_buf(struct vpdma_buf *buf);
+int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf);
+void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf);
+
+/* vpdma descriptor list funcs */
+int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type);
+void vpdma_reset_desc_list(struct vpdma_desc_list *list);
+void vpdma_free_desc_list(struct vpdma_desc_list *list);
+int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list);
+
+/* helpers for creating vpdma descriptors */
+void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client,
+               struct vpdma_buf *blk, u32 dest_offset);
+void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
+               struct vpdma_buf *adb);
+void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
+               enum vpdma_channel chan);
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+               const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
+               enum vpdma_channel chan, u32 flags);
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
+               int frame_height, struct v4l2_rect *c_rect,
+               const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
+               enum vpdma_channel chan, int field, u32 flags);
+
+/* vpdma list interrupt management */
+void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
+               bool enable);
+void vpdma_clear_list_stat(struct vpdma_data *vpdma);
+
+/* vpdma client configuration */
+void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode,
+               enum vpdma_channel chan);
+void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
+               enum vpdma_frame_start_event fs_event, enum vpdma_channel chan);
+
+void vpdma_dump_regs(struct vpdma_data *vpdma);
+
+/* initialize vpdma, passed with VPE's platform device pointer */
+struct vpdma_data *vpdma_create(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h
new file mode 100644 (file)
index 0000000..f0e9a80
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _TI_VPDMA_PRIV_H_
+#define _TI_VPDMA_PRIV_H_
+
+/*
+ * VPDMA Register offsets
+ */
+
+/* Top level */
+#define VPDMA_PID              0x00
+#define VPDMA_LIST_ADDR                0x04
+#define VPDMA_LIST_ATTR                0x08
+#define VPDMA_LIST_STAT_SYNC   0x0c
+#define VPDMA_BG_RGB           0x18
+#define VPDMA_BG_YUV           0x1c
+#define VPDMA_SETUP            0x30
+#define VPDMA_MAX_SIZE1                0x34
+#define VPDMA_MAX_SIZE2                0x38
+#define VPDMA_MAX_SIZE3                0x3c
+
+/* Interrupts */
+#define VPDMA_INT_CHAN_STAT(grp)       (0x40 + grp * 8)
+#define VPDMA_INT_CHAN_MASK(grp)       (VPDMA_INT_CHAN_STAT(grp) + 4)
+#define VPDMA_INT_CLIENT0_STAT         0x78
+#define VPDMA_INT_CLIENT0_MASK         0x7c
+#define VPDMA_INT_CLIENT1_STAT         0x80
+#define VPDMA_INT_CLIENT1_MASK         0x84
+#define VPDMA_INT_LIST0_STAT           0x88
+#define VPDMA_INT_LIST0_MASK           0x8c
+
+#define VPDMA_PERFMON(i)               (0x200 + i * 4)
+
+/* VPE specific client registers */
+#define VPDMA_DEI_CHROMA1_CSTAT                0x0300
+#define VPDMA_DEI_LUMA1_CSTAT          0x0304
+#define VPDMA_DEI_LUMA2_CSTAT          0x0308
+#define VPDMA_DEI_CHROMA2_CSTAT                0x030c
+#define VPDMA_DEI_LUMA3_CSTAT          0x0310
+#define VPDMA_DEI_CHROMA3_CSTAT                0x0314
+#define VPDMA_DEI_MV_IN_CSTAT          0x0330
+#define VPDMA_DEI_MV_OUT_CSTAT         0x033c
+#define VPDMA_VIP_UP_Y_CSTAT           0x0390
+#define VPDMA_VIP_UP_UV_CSTAT          0x0394
+#define VPDMA_VPI_CTL_CSTAT            0x03d0
+
+/* Reg field info for VPDMA_CLIENT_CSTAT registers */
+#define VPDMA_CSTAT_LINE_MODE_MASK     0x03
+#define VPDMA_CSTAT_LINE_MODE_SHIFT    8
+#define VPDMA_CSTAT_FRAME_START_MASK   0xf
+#define VPDMA_CSTAT_FRAME_START_SHIFT  10
+
+#define VPDMA_LIST_NUM_MASK            0x07
+#define VPDMA_LIST_NUM_SHFT            24
+#define VPDMA_LIST_STOP_SHFT           20
+#define VPDMA_LIST_RDY_MASK            0x01
+#define VPDMA_LIST_RDY_SHFT            19
+#define VPDMA_LIST_TYPE_MASK           0x03
+#define VPDMA_LIST_TYPE_SHFT           16
+#define VPDMA_LIST_SIZE_MASK           0xffff
+
+/* VPDMA data type values for data formats */
+#define DATA_TYPE_Y444                         0x0
+#define DATA_TYPE_Y422                         0x1
+#define DATA_TYPE_Y420                         0x2
+#define DATA_TYPE_C444                         0x4
+#define DATA_TYPE_C422                         0x5
+#define DATA_TYPE_C420                         0x6
+#define DATA_TYPE_YC422                                0x7
+#define DATA_TYPE_YC444                                0x8
+#define DATA_TYPE_CY422                                0x23
+
+#define DATA_TYPE_RGB16_565                    0x0
+#define DATA_TYPE_ARGB_1555                    0x1
+#define DATA_TYPE_ARGB_4444                    0x2
+#define DATA_TYPE_RGBA_5551                    0x3
+#define DATA_TYPE_RGBA_4444                    0x4
+#define DATA_TYPE_ARGB24_6666                  0x5
+#define DATA_TYPE_RGB24_888                    0x6
+#define DATA_TYPE_ARGB32_8888                  0x7
+#define DATA_TYPE_RGBA24_6666                  0x8
+#define DATA_TYPE_RGBA32_8888                  0x9
+#define DATA_TYPE_BGR16_565                    0x10
+#define DATA_TYPE_ABGR_1555                    0x11
+#define DATA_TYPE_ABGR_4444                    0x12
+#define DATA_TYPE_BGRA_5551                    0x13
+#define DATA_TYPE_BGRA_4444                    0x14
+#define DATA_TYPE_ABGR24_6666                  0x15
+#define DATA_TYPE_BGR24_888                    0x16
+#define DATA_TYPE_ABGR32_8888                  0x17
+#define DATA_TYPE_BGRA24_6666                  0x18
+#define DATA_TYPE_BGRA32_8888                  0x19
+
+#define DATA_TYPE_MV                           0x3
+
+/* VPDMA channel numbers(only VPE channels for now) */
+#define        VPE_CHAN_NUM_LUMA1_IN           0
+#define        VPE_CHAN_NUM_CHROMA1_IN         1
+#define        VPE_CHAN_NUM_LUMA2_IN           2
+#define        VPE_CHAN_NUM_CHROMA2_IN         3
+#define        VPE_CHAN_NUM_LUMA3_IN           4
+#define        VPE_CHAN_NUM_CHROMA3_IN         5
+#define        VPE_CHAN_NUM_MV_IN              12
+#define        VPE_CHAN_NUM_MV_OUT             15
+#define        VPE_CHAN_NUM_LUMA_OUT           102
+#define        VPE_CHAN_NUM_CHROMA_OUT         103
+#define        VPE_CHAN_NUM_RGB_OUT            106
+
+/*
+ * a VPDMA address data block payload for a configuration descriptor needs to
+ * have each sub block length as a multiple of 16 bytes. Therefore, the overall
+ * size of the payload also needs to be a multiple of 16 bytes. The sub block
+ * lengths should be ensured to be aligned by the VPDMA user.
+ */
+#define VPDMA_ADB_SIZE_ALIGN           0x0f
+
+/*
+ * data transfer descriptor
+ */
+struct vpdma_dtd {
+       u32                     type_ctl_stride;
+       union {
+               u32             xfer_length_height;
+               u32             w1;
+       };
+       dma_addr_t              start_addr;
+       u32                     pkt_ctl;
+       union {
+               u32             frame_width_height;     /* inbound */
+               dma_addr_t      desc_write_addr;        /* outbound */
+       };
+       union {
+               u32             start_h_v;              /* inbound */
+               u32             max_width_height;       /* outbound */
+       };
+       u32                     client_attr0;
+       u32                     client_attr1;
+};
+
+/* Data Transfer Descriptor specifics */
+#define DTD_NO_NOTIFY          0
+#define DTD_NOTIFY             1
+
+#define DTD_PKT_TYPE           0xa
+#define DTD_DIR_IN             0
+#define DTD_DIR_OUT            1
+
+/* type_ctl_stride */
+#define DTD_DATA_TYPE_MASK     0x3f
+#define DTD_DATA_TYPE_SHFT     26
+#define DTD_NOTIFY_MASK                0x01
+#define DTD_NOTIFY_SHFT                25
+#define DTD_FIELD_MASK         0x01
+#define DTD_FIELD_SHFT         24
+#define DTD_1D_MASK            0x01
+#define DTD_1D_SHFT            23
+#define DTD_EVEN_LINE_SKIP_MASK        0x01
+#define DTD_EVEN_LINE_SKIP_SHFT        20
+#define DTD_ODD_LINE_SKIP_MASK 0x01
+#define DTD_ODD_LINE_SKIP_SHFT 16
+#define DTD_LINE_STRIDE_MASK   0xffff
+#define DTD_LINE_STRIDE_SHFT   0
+
+/* xfer_length_height */
+#define DTD_LINE_LENGTH_MASK   0xffff
+#define DTD_LINE_LENGTH_SHFT   16
+#define DTD_XFER_HEIGHT_MASK   0xffff
+#define DTD_XFER_HEIGHT_SHFT   0
+
+/* pkt_ctl */
+#define DTD_PKT_TYPE_MASK      0x1f
+#define DTD_PKT_TYPE_SHFT      27
+#define DTD_MODE_MASK          0x01
+#define DTD_MODE_SHFT          26
+#define DTD_DIR_MASK           0x01
+#define DTD_DIR_SHFT           25
+#define DTD_CHAN_MASK          0x01ff
+#define DTD_CHAN_SHFT          16
+#define DTD_PRI_MASK           0x0f
+#define DTD_PRI_SHFT           9
+#define DTD_NEXT_CHAN_MASK     0x01ff
+#define DTD_NEXT_CHAN_SHFT     0
+
+/* frame_width_height */
+#define DTD_FRAME_WIDTH_MASK   0xffff
+#define DTD_FRAME_WIDTH_SHFT   16
+#define DTD_FRAME_HEIGHT_MASK  0xffff
+#define DTD_FRAME_HEIGHT_SHFT  0
+
+/* start_h_v */
+#define DTD_H_START_MASK       0xffff
+#define DTD_H_START_SHFT       16
+#define DTD_V_START_MASK       0xffff
+#define DTD_V_START_SHFT       0
+
+#define DTD_DESC_START_SHIFT   5
+#define DTD_WRITE_DESC_MASK    0x01
+#define DTD_WRITE_DESC_SHIFT   2
+#define DTD_DROP_DATA_MASK     0x01
+#define DTD_DROP_DATA_SHIFT    1
+#define DTD_USE_DESC_MASK      0x01
+#define DTD_USE_DESC_SHIFT     0
+
+/* max_width_height */
+#define DTD_MAX_WIDTH_MASK     0x07
+#define DTD_MAX_WIDTH_SHFT     4
+#define DTD_MAX_HEIGHT_MASK    0x07
+#define DTD_MAX_HEIGHT_SHFT    0
+
+/* max width configurations */
+ /* unlimited width */
+#define        MAX_OUT_WIDTH_UNLIMITED         0
+/* as specified in max_size1 reg */
+#define MAX_OUT_WIDTH_REG1             1
+/* as specified in max_size2 reg */
+#define MAX_OUT_WIDTH_REG2             2
+/* as specified in max_size3 reg */
+#define        MAX_OUT_WIDTH_REG3              3
+/* maximum of 352 pixels as width */
+#define MAX_OUT_WIDTH_352              4
+/* maximum of 768 pixels as width */
+#define        MAX_OUT_WIDTH_768               5
+/* maximum of 1280 pixels width */
+#define        MAX_OUT_WIDTH_1280              6
+/* maximum of 1920 pixels as width */
+#define        MAX_OUT_WIDTH_1920              7
+
+/* max height configurations */
+ /* unlimited height */
+#define        MAX_OUT_HEIGHT_UNLIMITED        0
+/* as specified in max_size1 reg */
+#define MAX_OUT_HEIGHT_REG1            1
+/* as specified in max_size2 reg */
+#define MAX_OUT_HEIGHT_REG2            2
+/* as specified in max_size3 reg */
+#define        MAX_OUT_HEIGHT_REG3             3
+/* maximum of 288 lines as height */
+#define MAX_OUT_HEIGHT_288             4
+/* maximum of 576 lines as height */
+#define        MAX_OUT_HEIGHT_576              5
+/* maximum of 720 lines as height */
+#define        MAX_OUT_HEIGHT_720              6
+/* maximum of 1080 lines as height */
+#define        MAX_OUT_HEIGHT_1080             7
+
+static inline u32 dtd_type_ctl_stride(int type, bool notify, int field,
+                       bool one_d, bool even_line_skip, bool odd_line_skip,
+                       int line_stride)
+{
+       return (type << DTD_DATA_TYPE_SHFT) | (notify << DTD_NOTIFY_SHFT) |
+               (field << DTD_FIELD_SHFT) | (one_d << DTD_1D_SHFT) |
+               (even_line_skip << DTD_EVEN_LINE_SKIP_SHFT) |
+               (odd_line_skip << DTD_ODD_LINE_SKIP_SHFT) |
+               line_stride;
+}
+
+static inline u32 dtd_xfer_length_height(int line_length, int xfer_height)
+{
+       return (line_length << DTD_LINE_LENGTH_SHFT) | xfer_height;
+}
+
+static inline u32 dtd_pkt_ctl(bool mode, bool dir, int chan, int pri,
+                       int next_chan)
+{
+       return (DTD_PKT_TYPE << DTD_PKT_TYPE_SHFT) | (mode << DTD_MODE_SHFT) |
+               (dir << DTD_DIR_SHFT) | (chan << DTD_CHAN_SHFT) |
+               (pri << DTD_PRI_SHFT) | next_chan;
+}
+
+static inline u32 dtd_frame_width_height(int width, int height)
+{
+       return (width << DTD_FRAME_WIDTH_SHFT) | height;
+}
+
+static inline u32 dtd_desc_write_addr(unsigned int addr, bool write_desc,
+                       bool drop_data, bool use_desc)
+{
+       return (addr << DTD_DESC_START_SHIFT) |
+               (write_desc << DTD_WRITE_DESC_SHIFT) |
+               (drop_data << DTD_DROP_DATA_SHIFT) |
+               use_desc;
+}
+
+static inline u32 dtd_start_h_v(int h_start, int v_start)
+{
+       return (h_start << DTD_H_START_SHFT) | v_start;
+}
+
+static inline u32 dtd_max_width_height(int max_width, int max_height)
+{
+       return (max_width << DTD_MAX_WIDTH_SHFT) | max_height;
+}
+
+static inline int dtd_get_data_type(struct vpdma_dtd *dtd)
+{
+       return dtd->type_ctl_stride >> DTD_DATA_TYPE_SHFT;
+}
+
+static inline bool dtd_get_notify(struct vpdma_dtd *dtd)
+{
+       return (dtd->type_ctl_stride >> DTD_NOTIFY_SHFT) & DTD_NOTIFY_MASK;
+}
+
+static inline int dtd_get_field(struct vpdma_dtd *dtd)
+{
+       return (dtd->type_ctl_stride >> DTD_FIELD_SHFT) & DTD_FIELD_MASK;
+}
+
+static inline bool dtd_get_1d(struct vpdma_dtd *dtd)
+{
+       return (dtd->type_ctl_stride >> DTD_1D_SHFT) & DTD_1D_MASK;
+}
+
+static inline bool dtd_get_even_line_skip(struct vpdma_dtd *dtd)
+{
+       return (dtd->type_ctl_stride >> DTD_EVEN_LINE_SKIP_SHFT)
+               & DTD_EVEN_LINE_SKIP_MASK;
+}
+
+static inline bool dtd_get_odd_line_skip(struct vpdma_dtd *dtd)
+{
+       return (dtd->type_ctl_stride >> DTD_ODD_LINE_SKIP_SHFT)
+               & DTD_ODD_LINE_SKIP_MASK;
+}
+
+static inline int dtd_get_line_stride(struct vpdma_dtd *dtd)
+{
+       return dtd->type_ctl_stride & DTD_LINE_STRIDE_MASK;
+}
+
+static inline int dtd_get_line_length(struct vpdma_dtd *dtd)
+{
+       return dtd->xfer_length_height >> DTD_LINE_LENGTH_SHFT;
+}
+
+static inline int dtd_get_xfer_height(struct vpdma_dtd *dtd)
+{
+       return dtd->xfer_length_height & DTD_XFER_HEIGHT_MASK;
+}
+
+static inline int dtd_get_pkt_type(struct vpdma_dtd *dtd)
+{
+       return dtd->pkt_ctl >> DTD_PKT_TYPE_SHFT;
+}
+
+static inline bool dtd_get_mode(struct vpdma_dtd *dtd)
+{
+       return (dtd->pkt_ctl >> DTD_MODE_SHFT) & DTD_MODE_MASK;
+}
+
+static inline bool dtd_get_dir(struct vpdma_dtd *dtd)
+{
+       return (dtd->pkt_ctl >> DTD_DIR_SHFT) & DTD_DIR_MASK;
+}
+
+static inline int dtd_get_chan(struct vpdma_dtd *dtd)
+{
+       return (dtd->pkt_ctl >> DTD_CHAN_SHFT) & DTD_CHAN_MASK;
+}
+
+static inline int dtd_get_priority(struct vpdma_dtd *dtd)
+{
+       return (dtd->pkt_ctl >> DTD_PRI_SHFT) & DTD_PRI_MASK;
+}
+
+static inline int dtd_get_next_chan(struct vpdma_dtd *dtd)
+{
+       return (dtd->pkt_ctl >> DTD_NEXT_CHAN_SHFT) & DTD_NEXT_CHAN_MASK;
+}
+
+static inline int dtd_get_frame_width(struct vpdma_dtd *dtd)
+{
+       return dtd->frame_width_height >> DTD_FRAME_WIDTH_SHFT;
+}
+
+static inline int dtd_get_frame_height(struct vpdma_dtd *dtd)
+{
+       return dtd->frame_width_height & DTD_FRAME_HEIGHT_MASK;
+}
+
+static inline int dtd_get_desc_write_addr(struct vpdma_dtd *dtd)
+{
+       return dtd->desc_write_addr >> DTD_DESC_START_SHIFT;
+}
+
+static inline bool dtd_get_write_desc(struct vpdma_dtd *dtd)
+{
+       return (dtd->desc_write_addr >> DTD_WRITE_DESC_SHIFT) &
+                                                       DTD_WRITE_DESC_MASK;
+}
+
+static inline bool dtd_get_drop_data(struct vpdma_dtd *dtd)
+{
+       return (dtd->desc_write_addr >> DTD_DROP_DATA_SHIFT) &
+                                                       DTD_DROP_DATA_MASK;
+}
+
+static inline bool dtd_get_use_desc(struct vpdma_dtd *dtd)
+{
+       return dtd->desc_write_addr & DTD_USE_DESC_MASK;
+}
+
+static inline int dtd_get_h_start(struct vpdma_dtd *dtd)
+{
+       return dtd->start_h_v >> DTD_H_START_SHFT;
+}
+
+static inline int dtd_get_v_start(struct vpdma_dtd *dtd)
+{
+       return dtd->start_h_v & DTD_V_START_MASK;
+}
+
+static inline int dtd_get_max_width(struct vpdma_dtd *dtd)
+{
+       return (dtd->max_width_height >> DTD_MAX_WIDTH_SHFT) &
+                                                       DTD_MAX_WIDTH_MASK;
+}
+
+static inline int dtd_get_max_height(struct vpdma_dtd *dtd)
+{
+       return (dtd->max_width_height >> DTD_MAX_HEIGHT_SHFT) &
+                                                       DTD_MAX_HEIGHT_MASK;
+}
+
+/*
+ * configuration descriptor
+ */
+struct vpdma_cfd {
+       union {
+               u32     dest_addr_offset;
+               u32     w0;
+       };
+       union {
+               u32     block_len;              /* in words */
+               u32     w1;
+       };
+       u32             payload_addr;
+       u32             ctl_payload_len;        /* in words */
+};
+
+/* Configuration descriptor specifics */
+
+#define CFD_PKT_TYPE           0xb
+
+#define CFD_DIRECT             1
+#define CFD_INDIRECT           0
+#define CFD_CLS_ADB            0
+#define CFD_CLS_BLOCK          1
+
+/* block_len */
+#define CFD__BLOCK_LEN_MASK    0xffff
+#define CFD__BLOCK_LEN_SHFT    0
+
+/* ctl_payload_len */
+#define CFD_PKT_TYPE_MASK      0x1f
+#define CFD_PKT_TYPE_SHFT      27
+#define CFD_DIRECT_MASK                0x01
+#define CFD_DIRECT_SHFT                26
+#define CFD_CLASS_MASK         0x03
+#define CFD_CLASS_SHFT         24
+#define CFD_DEST_MASK          0xff
+#define CFD_DEST_SHFT          16
+#define CFD_PAYLOAD_LEN_MASK   0xffff
+#define CFD_PAYLOAD_LEN_SHFT   0
+
+static inline u32 cfd_pkt_payload_len(bool direct, int cls, int dest,
+               int payload_len)
+{
+       return (CFD_PKT_TYPE << CFD_PKT_TYPE_SHFT) |
+               (direct << CFD_DIRECT_SHFT) |
+               (cls << CFD_CLASS_SHFT) |
+               (dest << CFD_DEST_SHFT) |
+               payload_len;
+}
+
+static inline int cfd_get_pkt_type(struct vpdma_cfd *cfd)
+{
+       return cfd->ctl_payload_len >> CFD_PKT_TYPE_SHFT;
+}
+
+static inline bool cfd_get_direct(struct vpdma_cfd *cfd)
+{
+       return (cfd->ctl_payload_len >> CFD_DIRECT_SHFT) & CFD_DIRECT_MASK;
+}
+
+static inline bool cfd_get_class(struct vpdma_cfd *cfd)
+{
+       return (cfd->ctl_payload_len >> CFD_CLASS_SHFT) & CFD_CLASS_MASK;
+}
+
+static inline int cfd_get_dest(struct vpdma_cfd *cfd)
+{
+       return (cfd->ctl_payload_len >> CFD_DEST_SHFT) & CFD_DEST_MASK;
+}
+
+static inline int cfd_get_payload_len(struct vpdma_cfd *cfd)
+{
+       return cfd->ctl_payload_len & CFD_PAYLOAD_LEN_MASK;
+}
+
+/*
+ * control descriptor
+ */
+struct vpdma_ctd {
+       union {
+               u32     timer_value;
+               u32     list_addr;
+               u32     w0;
+       };
+       union {
+               u32     pixel_line_count;
+               u32     list_size;
+               u32     w1;
+       };
+       union {
+               u32     event;
+               u32     fid_ctl;
+               u32     w2;
+       };
+       u32             type_source_ctl;
+};
+
+/* control descriptor types */
+#define CTD_TYPE_SYNC_ON_CLIENT                0
+#define CTD_TYPE_SYNC_ON_LIST          1
+#define CTD_TYPE_SYNC_ON_EXT           2
+#define CTD_TYPE_SYNC_ON_LM_TIMER      3
+#define CTD_TYPE_SYNC_ON_CHANNEL       4
+#define CTD_TYPE_CHNG_CLIENT_IRQ       5
+#define CTD_TYPE_SEND_IRQ              6
+#define CTD_TYPE_RELOAD_LIST           7
+#define CTD_TYPE_ABORT_CHANNEL         8
+
+#define CTD_PKT_TYPE           0xc
+
+/* timer_value */
+#define CTD_TIMER_VALUE_MASK   0xffff
+#define CTD_TIMER_VALUE_SHFT   0
+
+/* pixel_line_count */
+#define CTD_PIXEL_COUNT_MASK   0xffff
+#define CTD_PIXEL_COUNT_SHFT   16
+#define CTD_LINE_COUNT_MASK    0xffff
+#define CTD_LINE_COUNT_SHFT    0
+
+/* list_size */
+#define CTD_LIST_SIZE_MASK     0xffff
+#define CTD_LIST_SIZE_SHFT     0
+
+/* event */
+#define CTD_EVENT_MASK         0x0f
+#define CTD_EVENT_SHFT         0
+
+/* fid_ctl */
+#define CTD_FID2_MASK          0x03
+#define CTD_FID2_SHFT          4
+#define CTD_FID1_MASK          0x03
+#define CTD_FID1_SHFT          2
+#define CTD_FID0_MASK          0x03
+#define CTD_FID0_SHFT          0
+
+/* type_source_ctl */
+#define CTD_PKT_TYPE_MASK      0x1f
+#define CTD_PKT_TYPE_SHFT      27
+#define CTD_SOURCE_MASK                0xff
+#define CTD_SOURCE_SHFT                16
+#define CTD_CONTROL_MASK       0x0f
+#define CTD_CONTROL_SHFT       0
+
+static inline u32 ctd_pixel_line_count(int pixel_count, int line_count)
+{
+       return (pixel_count << CTD_PIXEL_COUNT_SHFT) | line_count;
+}
+
+static inline u32 ctd_set_fid_ctl(int fid0, int fid1, int fid2)
+{
+       return (fid2 << CTD_FID2_SHFT) | (fid1 << CTD_FID1_SHFT) | fid0;
+}
+
+static inline u32 ctd_type_source_ctl(int source, int control)
+{
+       return (CTD_PKT_TYPE << CTD_PKT_TYPE_SHFT) |
+               (source << CTD_SOURCE_SHFT) | control;
+}
+
+static inline u32 ctd_get_pixel_count(struct vpdma_ctd *ctd)
+{
+       return ctd->pixel_line_count >> CTD_PIXEL_COUNT_SHFT;
+}
+
+static inline int ctd_get_line_count(struct vpdma_ctd *ctd)
+{
+       return ctd->pixel_line_count & CTD_LINE_COUNT_MASK;
+}
+
+static inline int ctd_get_event(struct vpdma_ctd *ctd)
+{
+       return ctd->event & CTD_EVENT_MASK;
+}
+
+static inline int ctd_get_fid2_ctl(struct vpdma_ctd *ctd)
+{
+       return (ctd->fid_ctl >> CTD_FID2_SHFT) & CTD_FID2_MASK;
+}
+
+static inline int ctd_get_fid1_ctl(struct vpdma_ctd *ctd)
+{
+       return (ctd->fid_ctl >> CTD_FID1_SHFT) & CTD_FID1_MASK;
+}
+
+static inline int ctd_get_fid0_ctl(struct vpdma_ctd *ctd)
+{
+       return ctd->fid_ctl & CTD_FID2_MASK;
+}
+
+static inline int ctd_get_pkt_type(struct vpdma_ctd *ctd)
+{
+       return ctd->type_source_ctl >> CTD_PKT_TYPE_SHFT;
+}
+
+static inline int ctd_get_source(struct vpdma_ctd *ctd)
+{
+       return (ctd->type_source_ctl >> CTD_SOURCE_SHFT) & CTD_SOURCE_MASK;
+}
+
+static inline int ctd_get_ctl(struct vpdma_ctd *ctd)
+{
+       return ctd->type_source_ctl & CTD_CONTROL_MASK;
+}
+
+#endif
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
new file mode 100644 (file)
index 0000000..4e58069
--- /dev/null
@@ -0,0 +1,2099 @@
+/*
+ * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver
+ *
+ * Copyright (c) 2013 Texas Instruments Inc.
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * Based on the virtual v4l2-mem2mem example device
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vpdma.h"
+#include "vpe_regs.h"
+
+#define VPE_MODULE_NAME "vpe"
+
+/* minimum and maximum frame sizes */
+#define MIN_W          128
+#define MIN_H          128
+#define MAX_W          1920
+#define MAX_H          1080
+
+/* required alignments */
+#define S_ALIGN                0       /* multiple of 1 */
+#define H_ALIGN                1       /* multiple of 2 */
+#define W_ALIGN                1       /* multiple of 2 */
+
+/* multiple of 128 bits, line stride, 16 bytes */
+#define L_ALIGN                4
+
+/* flags that indicate a format can be used for capture/output */
+#define VPE_FMT_TYPE_CAPTURE   (1 << 0)
+#define VPE_FMT_TYPE_OUTPUT    (1 << 1)
+
+/* used as plane indices */
+#define VPE_MAX_PLANES 2
+#define VPE_LUMA       0
+#define VPE_CHROMA     1
+
+/* per m2m context info */
+#define VPE_MAX_SRC_BUFS       3       /* need 3 src fields to de-interlace */
+
+#define VPE_DEF_BUFS_PER_JOB   1       /* default one buffer per batch job */
+
+/*
+ * each VPE context can need up to 3 config desciptors, 7 input descriptors,
+ * 3 output descriptors, and 10 control descriptors
+ */
+#define VPE_DESC_LIST_SIZE     (10 * VPDMA_DTD_DESC_SIZE +     \
+                                       13 * VPDMA_CFD_CTD_DESC_SIZE)
+
+#define vpe_dbg(vpedev, fmt, arg...)   \
+               dev_dbg((vpedev)->v4l2_dev.dev, fmt, ##arg)
+#define vpe_err(vpedev, fmt, arg...)   \
+               dev_err((vpedev)->v4l2_dev.dev, fmt, ##arg)
+
+struct vpe_us_coeffs {
+       unsigned short  anchor_fid0_c0;
+       unsigned short  anchor_fid0_c1;
+       unsigned short  anchor_fid0_c2;
+       unsigned short  anchor_fid0_c3;
+       unsigned short  interp_fid0_c0;
+       unsigned short  interp_fid0_c1;
+       unsigned short  interp_fid0_c2;
+       unsigned short  interp_fid0_c3;
+       unsigned short  anchor_fid1_c0;
+       unsigned short  anchor_fid1_c1;
+       unsigned short  anchor_fid1_c2;
+       unsigned short  anchor_fid1_c3;
+       unsigned short  interp_fid1_c0;
+       unsigned short  interp_fid1_c1;
+       unsigned short  interp_fid1_c2;
+       unsigned short  interp_fid1_c3;
+};
+
+/*
+ * Default upsampler coefficients
+ */
+static const struct vpe_us_coeffs us_coeffs[] = {
+       {
+               /* Coefficients for progressive input */
+               0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,
+               0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,
+       },
+       {
+               /* Coefficients for Top Field Interlaced input */
+               0x0051, 0x03D5, 0x3FE3, 0x3FF7, 0x3FB5, 0x02E9, 0x018F, 0x3FD3,
+               /* Coefficients for Bottom Field Interlaced input */
+               0x016B, 0x0247, 0x00B1, 0x3F9D, 0x3FCF, 0x03DB, 0x005D, 0x3FF9,
+       },
+};
+
+/*
+ * the following registers are for configuring some of the parameters of the
+ * motion and edge detection blocks inside DEI, these generally remain the same,
+ * these could be passed later via userspace if some one needs to tweak these.
+ */
+struct vpe_dei_regs {
+       unsigned long mdt_spacial_freq_thr_reg;         /* VPE_DEI_REG2 */
+       unsigned long edi_config_reg;                   /* VPE_DEI_REG3 */
+       unsigned long edi_lut_reg0;                     /* VPE_DEI_REG4 */
+       unsigned long edi_lut_reg1;                     /* VPE_DEI_REG5 */
+       unsigned long edi_lut_reg2;                     /* VPE_DEI_REG6 */
+       unsigned long edi_lut_reg3;                     /* VPE_DEI_REG7 */
+};
+
+/*
+ * default expert DEI register values, unlikely to be modified.
+ */
+static const struct vpe_dei_regs dei_regs = {
+       0x020C0804u,
+       0x0118100Fu,
+       0x08040200u,
+       0x1010100Cu,
+       0x10101010u,
+       0x10101010u,
+};
+
+/*
+ * The port_data structure contains per-port data.
+ */
+struct vpe_port_data {
+       enum vpdma_channel channel;     /* VPDMA channel */
+       u8      vb_index;               /* input frame f, f-1, f-2 index */
+       u8      vb_part;                /* plane index for co-panar formats */
+};
+
+/*
+ * Define indices into the port_data tables
+ */
+#define VPE_PORT_LUMA1_IN      0
+#define VPE_PORT_CHROMA1_IN    1
+#define VPE_PORT_LUMA2_IN      2
+#define VPE_PORT_CHROMA2_IN    3
+#define VPE_PORT_LUMA3_IN      4
+#define VPE_PORT_CHROMA3_IN    5
+#define VPE_PORT_MV_IN         6
+#define VPE_PORT_MV_OUT                7
+#define VPE_PORT_LUMA_OUT      8
+#define VPE_PORT_CHROMA_OUT    9
+#define VPE_PORT_RGB_OUT       10
+
+static const struct vpe_port_data port_data[11] = {
+       [VPE_PORT_LUMA1_IN] = {
+               .channel        = VPE_CHAN_LUMA1_IN,
+               .vb_index       = 0,
+               .vb_part        = VPE_LUMA,
+       },
+       [VPE_PORT_CHROMA1_IN] = {
+               .channel        = VPE_CHAN_CHROMA1_IN,
+               .vb_index       = 0,
+               .vb_part        = VPE_CHROMA,
+       },
+       [VPE_PORT_LUMA2_IN] = {
+               .channel        = VPE_CHAN_LUMA2_IN,
+               .vb_index       = 1,
+               .vb_part        = VPE_LUMA,
+       },
+       [VPE_PORT_CHROMA2_IN] = {
+               .channel        = VPE_CHAN_CHROMA2_IN,
+               .vb_index       = 1,
+               .vb_part        = VPE_CHROMA,
+       },
+       [VPE_PORT_LUMA3_IN] = {
+               .channel        = VPE_CHAN_LUMA3_IN,
+               .vb_index       = 2,
+               .vb_part        = VPE_LUMA,
+       },
+       [VPE_PORT_CHROMA3_IN] = {
+               .channel        = VPE_CHAN_CHROMA3_IN,
+               .vb_index       = 2,
+               .vb_part        = VPE_CHROMA,
+       },
+       [VPE_PORT_MV_IN] = {
+               .channel        = VPE_CHAN_MV_IN,
+       },
+       [VPE_PORT_MV_OUT] = {
+               .channel        = VPE_CHAN_MV_OUT,
+       },
+       [VPE_PORT_LUMA_OUT] = {
+               .channel        = VPE_CHAN_LUMA_OUT,
+               .vb_part        = VPE_LUMA,
+       },
+       [VPE_PORT_CHROMA_OUT] = {
+               .channel        = VPE_CHAN_CHROMA_OUT,
+               .vb_part        = VPE_CHROMA,
+       },
+       [VPE_PORT_RGB_OUT] = {
+               .channel        = VPE_CHAN_RGB_OUT,
+               .vb_part        = VPE_LUMA,
+       },
+};
+
+
+/* driver info for each of the supported video formats */
+struct vpe_fmt {
+       char    *name;                  /* human-readable name */
+       u32     fourcc;                 /* standard format identifier */
+       u8      types;                  /* CAPTURE and/or OUTPUT */
+       u8      coplanar;               /* set for unpacked Luma and Chroma */
+       /* vpdma format info for each plane */
+       struct vpdma_data_format const *vpdma_fmt[VPE_MAX_PLANES];
+};
+
+static struct vpe_fmt vpe_formats[] = {
+       {
+               .name           = "YUV 422 co-planar",
+               .fourcc         = V4L2_PIX_FMT_NV16,
+               .types          = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
+               .coplanar       = 1,
+               .vpdma_fmt      = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y444],
+                                   &vpdma_yuv_fmts[VPDMA_DATA_FMT_C444],
+                                 },
+       },
+       {
+               .name           = "YUV 420 co-planar",
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .types          = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
+               .coplanar       = 1,
+               .vpdma_fmt      = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],
+                                   &vpdma_yuv_fmts[VPDMA_DATA_FMT_C420],
+                                 },
+       },
+       {
+               .name           = "YUYV 422 packed",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .types          = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422],
+                                 },
+       },
+       {
+               .name           = "UYVY 422 packed",
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+               .types          = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422],
+                                 },
+       },
+};
+
+/*
+ * per-queue, driver-specific private data.
+ * there is one source queue and one destination queue for each m2m context.
+ */
+struct vpe_q_data {
+       unsigned int            width;                          /* frame width */
+       unsigned int            height;                         /* frame height */
+       unsigned int            bytesperline[VPE_MAX_PLANES];   /* bytes per line in memory */
+       enum v4l2_colorspace    colorspace;
+       enum v4l2_field         field;                          /* supported field value */
+       unsigned int            flags;
+       unsigned int            sizeimage[VPE_MAX_PLANES];      /* image size in memory */
+       struct v4l2_rect        c_rect;                         /* crop/compose rectangle */
+       struct vpe_fmt          *fmt;                           /* format info */
+};
+
+/* vpe_q_data flag bits */
+#define        Q_DATA_FRAME_1D         (1 << 0)
+#define        Q_DATA_MODE_TILED       (1 << 1)
+#define        Q_DATA_INTERLACED       (1 << 2)
+
+enum {
+       Q_DATA_SRC = 0,
+       Q_DATA_DST = 1,
+};
+
+/* find our format description corresponding to the passed v4l2_format */
+static struct vpe_fmt *find_format(struct v4l2_format *f)
+{
+       struct vpe_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) {
+               fmt = &vpe_formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       return fmt;
+       }
+
+       return NULL;
+}
+
+/*
+ * there is one vpe_dev structure in the driver, it is shared by
+ * all instances.
+ */
+struct vpe_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     vfd;
+       struct v4l2_m2m_dev     *m2m_dev;
+
+       atomic_t                num_instances;  /* count of driver instances */
+       dma_addr_t              loaded_mmrs;    /* shadow mmrs in device */
+       struct mutex            dev_mutex;
+       spinlock_t              lock;
+
+       int                     irq;
+       void __iomem            *base;
+
+       struct vb2_alloc_ctx    *alloc_ctx;
+       struct vpdma_data       *vpdma;         /* vpdma data handle */
+};
+
+/*
+ * There is one vpe_ctx structure for each m2m context.
+ */
+struct vpe_ctx {
+       struct v4l2_fh          fh;
+       struct vpe_dev          *dev;
+       struct v4l2_m2m_ctx     *m2m_ctx;
+       struct v4l2_ctrl_handler hdl;
+
+       unsigned int            field;                  /* current field */
+       unsigned int            sequence;               /* current frame/field seq */
+       unsigned int            aborting;               /* abort after next irq */
+
+       unsigned int            bufs_per_job;           /* input buffers per batch */
+       unsigned int            bufs_completed;         /* bufs done in this batch */
+
+       struct vpe_q_data       q_data[2];              /* src & dst queue data */
+       struct vb2_buffer       *src_vbs[VPE_MAX_SRC_BUFS];
+       struct vb2_buffer       *dst_vb;
+
+       dma_addr_t              mv_buf_dma[2];          /* dma addrs of motion vector in/out bufs */
+       void                    *mv_buf[2];             /* virtual addrs of motion vector bufs */
+       size_t                  mv_buf_size;            /* current motion vector buffer size */
+       struct vpdma_buf        mmr_adb;                /* shadow reg addr/data block */
+       struct vpdma_desc_list  desc_list;              /* DMA descriptor list */
+
+       bool                    deinterlacing;          /* using de-interlacer */
+       bool                    load_mmrs;              /* have new shadow reg values */
+
+       unsigned int            src_mv_buf_selector;
+};
+
+
+/*
+ * M2M devices get 2 queues.
+ * Return the queue given the type.
+ */
+static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
+                                    enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return &ctx->q_data[Q_DATA_SRC];
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               return &ctx->q_data[Q_DATA_DST];
+       default:
+               BUG();
+       }
+       return NULL;
+}
+
+static u32 read_reg(struct vpe_dev *dev, int offset)
+{
+       return ioread32(dev->base + offset);
+}
+
+static void write_reg(struct vpe_dev *dev, int offset, u32 value)
+{
+       iowrite32(value, dev->base + offset);
+}
+
+/* register field read/write helpers */
+static int get_field(u32 value, u32 mask, int shift)
+{
+       return (value & (mask << shift)) >> shift;
+}
+
+static int read_field_reg(struct vpe_dev *dev, int offset, u32 mask, int shift)
+{
+       return get_field(read_reg(dev, offset), mask, shift);
+}
+
+static void write_field(u32 *valp, u32 field, u32 mask, int shift)
+{
+       u32 val = *valp;
+
+       val &= ~(mask << shift);
+       val |= (field & mask) << shift;
+       *valp = val;
+}
+
+static void write_field_reg(struct vpe_dev *dev, int offset, u32 field,
+               u32 mask, int shift)
+{
+       u32 val = read_reg(dev, offset);
+
+       write_field(&val, field, mask, shift);
+
+       write_reg(dev, offset, val);
+}
+
+/*
+ * DMA address/data block for the shadow registers
+ */
+struct vpe_mmr_adb {
+       struct vpdma_adb_hdr    out_fmt_hdr;
+       u32                     out_fmt_reg[1];
+       u32                     out_fmt_pad[3];
+       struct vpdma_adb_hdr    us1_hdr;
+       u32                     us1_regs[8];
+       struct vpdma_adb_hdr    us2_hdr;
+       u32                     us2_regs[8];
+       struct vpdma_adb_hdr    us3_hdr;
+       u32                     us3_regs[8];
+       struct vpdma_adb_hdr    dei_hdr;
+       u32                     dei_regs[8];
+       struct vpdma_adb_hdr    sc_hdr;
+       u32                     sc_regs[1];
+       u32                     sc_pad[3];
+       struct vpdma_adb_hdr    csc_hdr;
+       u32                     csc_regs[6];
+       u32                     csc_pad[2];
+};
+
+#define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a)  \
+       VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a)
+/*
+ * Set the headers for all of the address/data block structures.
+ */
+static void init_adb_hdrs(struct vpe_ctx *ctx)
+{
+       VPE_SET_MMR_ADB_HDR(ctx, out_fmt_hdr, out_fmt_reg, VPE_CLK_FORMAT_SELECT);
+       VPE_SET_MMR_ADB_HDR(ctx, us1_hdr, us1_regs, VPE_US1_R0);
+       VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0);
+       VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0);
+       VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE);
+       VPE_SET_MMR_ADB_HDR(ctx, sc_hdr, sc_regs, VPE_SC_MP_SC0);
+       VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, VPE_CSC_CSC00);
+};
+
+/*
+ * Allocate or re-allocate the motion vector DMA buffers
+ * There are two buffers, one for input and one for output.
+ * However, the roles are reversed after each field is processed.
+ * In other words, after each field is processed, the previous
+ * output (dst) MV buffer becomes the new input (src) MV buffer.
+ */
+static int realloc_mv_buffers(struct vpe_ctx *ctx, size_t size)
+{
+       struct device *dev = ctx->dev->v4l2_dev.dev;
+
+       if (ctx->mv_buf_size == size)
+               return 0;
+
+       if (ctx->mv_buf[0])
+               dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[0],
+                       ctx->mv_buf_dma[0]);
+
+       if (ctx->mv_buf[1])
+               dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[1],
+                       ctx->mv_buf_dma[1]);
+
+       if (size == 0)
+               return 0;
+
+       ctx->mv_buf[0] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[0],
+                               GFP_KERNEL);
+       if (!ctx->mv_buf[0]) {
+               vpe_err(ctx->dev, "failed to allocate motion vector buffer\n");
+               return -ENOMEM;
+       }
+
+       ctx->mv_buf[1] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[1],
+                               GFP_KERNEL);
+       if (!ctx->mv_buf[1]) {
+               vpe_err(ctx->dev, "failed to allocate motion vector buffer\n");
+               dma_free_coherent(dev, size, ctx->mv_buf[0],
+                       ctx->mv_buf_dma[0]);
+
+               return -ENOMEM;
+       }
+
+       ctx->mv_buf_size = size;
+       ctx->src_mv_buf_selector = 0;
+
+       return 0;
+}
+
+static void free_mv_buffers(struct vpe_ctx *ctx)
+{
+       realloc_mv_buffers(ctx, 0);
+}
+
+/*
+ * While de-interlacing, we keep the two most recent input buffers
+ * around.  This function frees those two buffers when we have
+ * finished processing the current stream.
+ */
+static void free_vbs(struct vpe_ctx *ctx)
+{
+       struct vpe_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       if (ctx->src_vbs[2] == NULL)
+               return;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (ctx->src_vbs[2]) {
+               v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE);
+               v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE);
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ * Enable or disable the VPE clocks
+ */
+static void vpe_set_clock_enable(struct vpe_dev *dev, bool on)
+{
+       u32 val = 0;
+
+       if (on)
+               val = VPE_DATA_PATH_CLK_ENABLE | VPE_VPEDMA_CLK_ENABLE;
+       write_reg(dev, VPE_CLK_ENABLE, val);
+}
+
+static void vpe_top_reset(struct vpe_dev *dev)
+{
+
+       write_field_reg(dev, VPE_CLK_RESET, 1, VPE_DATA_PATH_CLK_RESET_MASK,
+               VPE_DATA_PATH_CLK_RESET_SHIFT);
+
+       usleep_range(100, 150);
+
+       write_field_reg(dev, VPE_CLK_RESET, 0, VPE_DATA_PATH_CLK_RESET_MASK,
+               VPE_DATA_PATH_CLK_RESET_SHIFT);
+}
+
+static void vpe_top_vpdma_reset(struct vpe_dev *dev)
+{
+       write_field_reg(dev, VPE_CLK_RESET, 1, VPE_VPDMA_CLK_RESET_MASK,
+               VPE_VPDMA_CLK_RESET_SHIFT);
+
+       usleep_range(100, 150);
+
+       write_field_reg(dev, VPE_CLK_RESET, 0, VPE_VPDMA_CLK_RESET_MASK,
+               VPE_VPDMA_CLK_RESET_SHIFT);
+}
+
+/*
+ * Load the correct of upsampler coefficients into the shadow MMRs
+ */
+static void set_us_coefficients(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];
+       u32 *us1_reg = &mmr_adb->us1_regs[0];
+       u32 *us2_reg = &mmr_adb->us2_regs[0];
+       u32 *us3_reg = &mmr_adb->us3_regs[0];
+       const unsigned short *cp, *end_cp;
+
+       cp = &us_coeffs[0].anchor_fid0_c0;
+
+       if (s_q_data->flags & Q_DATA_INTERLACED)        /* interlaced */
+               cp += sizeof(us_coeffs[0]) / sizeof(*cp);
+
+       end_cp = cp + sizeof(us_coeffs[0]) / sizeof(*cp);
+
+       while (cp < end_cp) {
+               write_field(us1_reg, *cp++, VPE_US_C0_MASK, VPE_US_C0_SHIFT);
+               write_field(us1_reg, *cp++, VPE_US_C1_MASK, VPE_US_C1_SHIFT);
+               *us2_reg++ = *us1_reg;
+               *us3_reg++ = *us1_reg++;
+       }
+       ctx->load_mmrs = true;
+}
+
+/*
+ * Set the upsampler config mode and the VPDMA line mode in the shadow MMRs.
+ */
+static void set_cfg_and_line_modes(struct vpe_ctx *ctx)
+{
+       struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt;
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       u32 *us1_reg0 = &mmr_adb->us1_regs[0];
+       u32 *us2_reg0 = &mmr_adb->us2_regs[0];
+       u32 *us3_reg0 = &mmr_adb->us3_regs[0];
+       int line_mode = 1;
+       int cfg_mode = 1;
+
+       /*
+        * Cfg Mode 0: YUV420 source, enable upsampler, DEI is de-interlacing.
+        * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing.
+        */
+
+       if (fmt->fourcc == V4L2_PIX_FMT_NV12) {
+               cfg_mode = 0;
+               line_mode = 0;          /* double lines to line buffer */
+       }
+
+       write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);
+       write_field(us2_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);
+       write_field(us3_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);
+
+       /* regs for now */
+       vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA1_IN);
+       vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA2_IN);
+       vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA3_IN);
+
+       /* frame start for input luma */
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_LUMA1_IN);
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_LUMA2_IN);
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_LUMA3_IN);
+
+       /* frame start for input chroma */
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_CHROMA1_IN);
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_CHROMA2_IN);
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_CHROMA3_IN);
+
+       /* frame start for MV in client */
+       vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,
+               VPE_CHAN_MV_IN);
+
+       ctx->load_mmrs = true;
+}
+
+/*
+ * Set the shadow registers that are modified when the source
+ * format changes.
+ */
+static void set_src_registers(struct vpe_ctx *ctx)
+{
+       set_us_coefficients(ctx);
+}
+
+/*
+ * Set the shadow registers that are modified when the destination
+ * format changes.
+ */
+static void set_dst_registers(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt;
+       u32 val = 0;
+
+       /* select RGB path when color space conversion is supported in future */
+       if (fmt->fourcc == V4L2_PIX_FMT_RGB24)
+               val |= VPE_RGB_OUT_SELECT | VPE_CSC_SRC_DEI_SCALER;
+       else if (fmt->fourcc == V4L2_PIX_FMT_NV16)
+               val |= VPE_COLOR_SEPARATE_422;
+
+       /* The source of CHR_DS is always the scaler, whether it's used or not */
+       val |= VPE_DS_SRC_DEI_SCALER;
+
+       if (fmt->fourcc != V4L2_PIX_FMT_NV12)
+               val |= VPE_DS_BYPASS;
+
+       mmr_adb->out_fmt_reg[0] = val;
+
+       ctx->load_mmrs = true;
+}
+
+/*
+ * Set the de-interlacer shadow register values
+ */
+static void set_dei_regs(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];
+       unsigned int src_h = s_q_data->c_rect.height;
+       unsigned int src_w = s_q_data->c_rect.width;
+       u32 *dei_mmr0 = &mmr_adb->dei_regs[0];
+       bool deinterlace = true;
+       u32 val = 0;
+
+       /*
+        * according to TRM, we should set DEI in progressive bypass mode when
+        * the input content is progressive, however, DEI is bypassed correctly
+        * for both progressive and interlace content in interlace bypass mode.
+        * It has been recommended not to use progressive bypass mode.
+        */
+       if ((!ctx->deinterlacing && (s_q_data->flags & Q_DATA_INTERLACED)) ||
+                       !(s_q_data->flags & Q_DATA_INTERLACED)) {
+               deinterlace = false;
+               val = VPE_DEI_INTERLACE_BYPASS;
+       }
+
+       src_h = deinterlace ? src_h * 2 : src_h;
+
+       val |= (src_h << VPE_DEI_HEIGHT_SHIFT) |
+               (src_w << VPE_DEI_WIDTH_SHIFT) |
+               VPE_DEI_FIELD_FLUSH;
+
+       *dei_mmr0 = val;
+
+       ctx->load_mmrs = true;
+}
+
+static void set_dei_shadow_registers(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       u32 *dei_mmr = &mmr_adb->dei_regs[0];
+       const struct vpe_dei_regs *cur = &dei_regs;
+
+       dei_mmr[2]  = cur->mdt_spacial_freq_thr_reg;
+       dei_mmr[3]  = cur->edi_config_reg;
+       dei_mmr[4]  = cur->edi_lut_reg0;
+       dei_mmr[5]  = cur->edi_lut_reg1;
+       dei_mmr[6]  = cur->edi_lut_reg2;
+       dei_mmr[7]  = cur->edi_lut_reg3;
+
+       ctx->load_mmrs = true;
+}
+
+static void set_csc_coeff_bypass(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       u32 *shadow_csc_reg5 = &mmr_adb->csc_regs[5];
+
+       *shadow_csc_reg5 |= VPE_CSC_BYPASS;
+
+       ctx->load_mmrs = true;
+}
+
+static void set_sc_regs_bypass(struct vpe_ctx *ctx)
+{
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       u32 *sc_reg0 = &mmr_adb->sc_regs[0];
+       u32 val = 0;
+
+       val |= VPE_SC_BYPASS;
+       *sc_reg0 = val;
+
+       ctx->load_mmrs = true;
+}
+
+/*
+ * Set the shadow registers whose values are modified when either the
+ * source or destination format is changed.
+ */
+static int set_srcdst_params(struct vpe_ctx *ctx)
+{
+       struct vpe_q_data *s_q_data =  &ctx->q_data[Q_DATA_SRC];
+       struct vpe_q_data *d_q_data =  &ctx->q_data[Q_DATA_DST];
+       size_t mv_buf_size;
+       int ret;
+
+       ctx->sequence = 0;
+       ctx->field = V4L2_FIELD_TOP;
+
+       if ((s_q_data->flags & Q_DATA_INTERLACED) &&
+                       !(d_q_data->flags & Q_DATA_INTERLACED)) {
+               const struct vpdma_data_format *mv =
+                       &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
+
+               ctx->deinterlacing = 1;
+               mv_buf_size =
+                       (s_q_data->width * s_q_data->height * mv->depth) >> 3;
+       } else {
+               ctx->deinterlacing = 0;
+               mv_buf_size = 0;
+       }
+
+       free_vbs(ctx);
+
+       ret = realloc_mv_buffers(ctx, mv_buf_size);
+       if (ret)
+               return ret;
+
+       set_cfg_and_line_modes(ctx);
+       set_dei_regs(ctx);
+       set_csc_coeff_bypass(ctx);
+       set_sc_regs_bypass(ctx);
+
+       return 0;
+}
+
+/*
+ * Return the vpe_ctx structure for a given struct file
+ */
+static struct vpe_ctx *file2ctx(struct file *file)
+{
+       return container_of(file->private_data, struct vpe_ctx, fh);
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+/**
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+static int job_ready(void *priv)
+{
+       struct vpe_ctx *ctx = priv;
+       int needed = ctx->bufs_per_job;
+
+       if (ctx->deinterlacing && ctx->src_vbs[2] == NULL)
+               needed += 2;    /* need additional two most recent fields */
+
+       if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
+               return 0;
+
+       return 1;
+}
+
+static void job_abort(void *priv)
+{
+       struct vpe_ctx *ctx = priv;
+
+       /* Will cancel the transaction in the next interrupt handler */
+       ctx->aborting = 1;
+}
+
+/*
+ * Lock access to the device
+ */
+static void vpe_lock(void *priv)
+{
+       struct vpe_ctx *ctx = priv;
+       struct vpe_dev *dev = ctx->dev;
+       mutex_lock(&dev->dev_mutex);
+}
+
+static void vpe_unlock(void *priv)
+{
+       struct vpe_ctx *ctx = priv;
+       struct vpe_dev *dev = ctx->dev;
+       mutex_unlock(&dev->dev_mutex);
+}
+
+static void vpe_dump_regs(struct vpe_dev *dev)
+{
+#define DUMPREG(r) vpe_dbg(dev, "%-35s %08x\n", #r, read_reg(dev, VPE_##r))
+
+       vpe_dbg(dev, "VPE Registers:\n");
+
+       DUMPREG(PID);
+       DUMPREG(SYSCONFIG);
+       DUMPREG(INT0_STATUS0_RAW);
+       DUMPREG(INT0_STATUS0);
+       DUMPREG(INT0_ENABLE0);
+       DUMPREG(INT0_STATUS1_RAW);
+       DUMPREG(INT0_STATUS1);
+       DUMPREG(INT0_ENABLE1);
+       DUMPREG(CLK_ENABLE);
+       DUMPREG(CLK_RESET);
+       DUMPREG(CLK_FORMAT_SELECT);
+       DUMPREG(CLK_RANGE_MAP);
+       DUMPREG(US1_R0);
+       DUMPREG(US1_R1);
+       DUMPREG(US1_R2);
+       DUMPREG(US1_R3);
+       DUMPREG(US1_R4);
+       DUMPREG(US1_R5);
+       DUMPREG(US1_R6);
+       DUMPREG(US1_R7);
+       DUMPREG(US2_R0);
+       DUMPREG(US2_R1);
+       DUMPREG(US2_R2);
+       DUMPREG(US2_R3);
+       DUMPREG(US2_R4);
+       DUMPREG(US2_R5);
+       DUMPREG(US2_R6);
+       DUMPREG(US2_R7);
+       DUMPREG(US3_R0);
+       DUMPREG(US3_R1);
+       DUMPREG(US3_R2);
+       DUMPREG(US3_R3);
+       DUMPREG(US3_R4);
+       DUMPREG(US3_R5);
+       DUMPREG(US3_R6);
+       DUMPREG(US3_R7);
+       DUMPREG(DEI_FRAME_SIZE);
+       DUMPREG(MDT_BYPASS);
+       DUMPREG(MDT_SF_THRESHOLD);
+       DUMPREG(EDI_CONFIG);
+       DUMPREG(DEI_EDI_LUT_R0);
+       DUMPREG(DEI_EDI_LUT_R1);
+       DUMPREG(DEI_EDI_LUT_R2);
+       DUMPREG(DEI_EDI_LUT_R3);
+       DUMPREG(DEI_FMD_WINDOW_R0);
+       DUMPREG(DEI_FMD_WINDOW_R1);
+       DUMPREG(DEI_FMD_CONTROL_R0);
+       DUMPREG(DEI_FMD_CONTROL_R1);
+       DUMPREG(DEI_FMD_STATUS_R0);
+       DUMPREG(DEI_FMD_STATUS_R1);
+       DUMPREG(DEI_FMD_STATUS_R2);
+       DUMPREG(SC_MP_SC0);
+       DUMPREG(SC_MP_SC1);
+       DUMPREG(SC_MP_SC2);
+       DUMPREG(SC_MP_SC3);
+       DUMPREG(SC_MP_SC4);
+       DUMPREG(SC_MP_SC5);
+       DUMPREG(SC_MP_SC6);
+       DUMPREG(SC_MP_SC8);
+       DUMPREG(SC_MP_SC9);
+       DUMPREG(SC_MP_SC10);
+       DUMPREG(SC_MP_SC11);
+       DUMPREG(SC_MP_SC12);
+       DUMPREG(SC_MP_SC13);
+       DUMPREG(SC_MP_SC17);
+       DUMPREG(SC_MP_SC18);
+       DUMPREG(SC_MP_SC19);
+       DUMPREG(SC_MP_SC20);
+       DUMPREG(SC_MP_SC21);
+       DUMPREG(SC_MP_SC22);
+       DUMPREG(SC_MP_SC23);
+       DUMPREG(SC_MP_SC24);
+       DUMPREG(SC_MP_SC25);
+       DUMPREG(CSC_CSC00);
+       DUMPREG(CSC_CSC01);
+       DUMPREG(CSC_CSC02);
+       DUMPREG(CSC_CSC03);
+       DUMPREG(CSC_CSC04);
+       DUMPREG(CSC_CSC05);
+#undef DUMPREG
+}
+
+static void add_out_dtd(struct vpe_ctx *ctx, int port)
+{
+       struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
+       const struct vpe_port_data *p_data = &port_data[port];
+       struct vb2_buffer *vb = ctx->dst_vb;
+       struct v4l2_rect *c_rect = &q_data->c_rect;
+       struct vpe_fmt *fmt = q_data->fmt;
+       const struct vpdma_data_format *vpdma_fmt;
+       int mv_buf_selector = !ctx->src_mv_buf_selector;
+       dma_addr_t dma_addr;
+       u32 flags = 0;
+
+       if (port == VPE_PORT_MV_OUT) {
+               vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
+               dma_addr = ctx->mv_buf_dma[mv_buf_selector];
+       } else {
+               /* to incorporate interleaved formats */
+               int plane = fmt->coplanar ? p_data->vb_part : 0;
+
+               vpdma_fmt = fmt->vpdma_fmt[plane];
+               dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);
+               if (!dma_addr) {
+                       vpe_err(ctx->dev,
+                               "acquiring output buffer(%d) dma_addr failed\n",
+                               port);
+                       return;
+               }
+       }
+
+       if (q_data->flags & Q_DATA_FRAME_1D)
+               flags |= VPDMA_DATA_FRAME_1D;
+       if (q_data->flags & Q_DATA_MODE_TILED)
+               flags |= VPDMA_DATA_MODE_TILED;
+
+       vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
+               p_data->channel, flags);
+}
+
+static void add_in_dtd(struct vpe_ctx *ctx, int port)
+{
+       struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
+       const struct vpe_port_data *p_data = &port_data[port];
+       struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
+       struct v4l2_rect *c_rect = &q_data->c_rect;
+       struct vpe_fmt *fmt = q_data->fmt;
+       const struct vpdma_data_format *vpdma_fmt;
+       int mv_buf_selector = ctx->src_mv_buf_selector;
+       int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+       dma_addr_t dma_addr;
+       u32 flags = 0;
+
+       if (port == VPE_PORT_MV_IN) {
+               vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
+               dma_addr = ctx->mv_buf_dma[mv_buf_selector];
+       } else {
+               /* to incorporate interleaved formats */
+               int plane = fmt->coplanar ? p_data->vb_part : 0;
+
+               vpdma_fmt = fmt->vpdma_fmt[plane];
+
+               dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);
+               if (!dma_addr) {
+                       vpe_err(ctx->dev,
+                               "acquiring input buffer(%d) dma_addr failed\n",
+                               port);
+                       return;
+               }
+       }
+
+       if (q_data->flags & Q_DATA_FRAME_1D)
+               flags |= VPDMA_DATA_FRAME_1D;
+       if (q_data->flags & Q_DATA_MODE_TILED)
+               flags |= VPDMA_DATA_MODE_TILED;
+
+       vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
+               c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+}
+
+/*
+ * Enable the expected IRQ sources
+ */
+static void enable_irqs(struct vpe_ctx *ctx)
+{
+       write_reg(ctx->dev, VPE_INT0_ENABLE0_SET, VPE_INT0_LIST0_COMPLETE);
+       write_reg(ctx->dev, VPE_INT0_ENABLE1_SET, VPE_DEI_ERROR_INT |
+                               VPE_DS1_UV_ERROR_INT);
+
+       vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, true);
+}
+
+static void disable_irqs(struct vpe_ctx *ctx)
+{
+       write_reg(ctx->dev, VPE_INT0_ENABLE0_CLR, 0xffffffff);
+       write_reg(ctx->dev, VPE_INT0_ENABLE1_CLR, 0xffffffff);
+
+       vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, false);
+}
+
+/* device_run() - prepares and starts the device
+ *
+ * This function is only called when both the source and destination
+ * buffers are in place.
+ */
+static void device_run(void *priv)
+{
+       struct vpe_ctx *ctx = priv;
+       struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];
+
+       if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) {
+               ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               WARN_ON(ctx->src_vbs[2] == NULL);
+               ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               WARN_ON(ctx->src_vbs[1] == NULL);
+       }
+
+       ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+       WARN_ON(ctx->src_vbs[0] == NULL);
+       ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       WARN_ON(ctx->dst_vb == NULL);
+
+       /* config descriptors */
+       if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) {
+               vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb);
+               vpdma_add_cfd_adb(&ctx->desc_list, CFD_MMR_CLIENT, &ctx->mmr_adb);
+               ctx->dev->loaded_mmrs = ctx->mmr_adb.dma_addr;
+               ctx->load_mmrs = false;
+       }
+
+       /* output data descriptors */
+       if (ctx->deinterlacing)
+               add_out_dtd(ctx, VPE_PORT_MV_OUT);
+
+       add_out_dtd(ctx, VPE_PORT_LUMA_OUT);
+       if (d_q_data->fmt->coplanar)
+               add_out_dtd(ctx, VPE_PORT_CHROMA_OUT);
+
+       /* input data descriptors */
+       if (ctx->deinterlacing) {
+               add_in_dtd(ctx, VPE_PORT_LUMA3_IN);
+               add_in_dtd(ctx, VPE_PORT_CHROMA3_IN);
+
+               add_in_dtd(ctx, VPE_PORT_LUMA2_IN);
+               add_in_dtd(ctx, VPE_PORT_CHROMA2_IN);
+       }
+
+       add_in_dtd(ctx, VPE_PORT_LUMA1_IN);
+       add_in_dtd(ctx, VPE_PORT_CHROMA1_IN);
+
+       if (ctx->deinterlacing)
+               add_in_dtd(ctx, VPE_PORT_MV_IN);
+
+       /* sync on channel control descriptors for input ports */
+       vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA1_IN);
+       vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA1_IN);
+
+       if (ctx->deinterlacing) {
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_LUMA2_IN);
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_CHROMA2_IN);
+
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_LUMA3_IN);
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_CHROMA3_IN);
+
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_IN);
+       }
+
+       /* sync on channel control descriptors for output ports */
+       vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA_OUT);
+       if (d_q_data->fmt->coplanar)
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA_OUT);
+
+       if (ctx->deinterlacing)
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT);
+
+       enable_irqs(ctx);
+
+       vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->desc_list.buf);
+       vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list);
+}
+
+static void dei_error(struct vpe_ctx *ctx)
+{
+       dev_warn(ctx->dev->v4l2_dev.dev,
+               "received DEI error interrupt\n");
+}
+
+static void ds1_uv_error(struct vpe_ctx *ctx)
+{
+       dev_warn(ctx->dev->v4l2_dev.dev,
+               "received downsampler error interrupt\n");
+}
+
+static irqreturn_t vpe_irq(int irq_vpe, void *data)
+{
+       struct vpe_dev *dev = (struct vpe_dev *)data;
+       struct vpe_ctx *ctx;
+       struct vpe_q_data *d_q_data;
+       struct vb2_buffer *s_vb, *d_vb;
+       struct v4l2_buffer *s_buf, *d_buf;
+       unsigned long flags;
+       u32 irqst0, irqst1;
+
+       irqst0 = read_reg(dev, VPE_INT0_STATUS0);
+       if (irqst0) {
+               write_reg(dev, VPE_INT0_STATUS0_CLR, irqst0);
+               vpe_dbg(dev, "INT0_STATUS0 = 0x%08x\n", irqst0);
+       }
+
+       irqst1 = read_reg(dev, VPE_INT0_STATUS1);
+       if (irqst1) {
+               write_reg(dev, VPE_INT0_STATUS1_CLR, irqst1);
+               vpe_dbg(dev, "INT0_STATUS1 = 0x%08x\n", irqst1);
+       }
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (!ctx) {
+               vpe_err(dev, "instance released before end of transaction\n");
+               goto handled;
+       }
+
+       if (irqst1) {
+               if (irqst1 & VPE_DEI_ERROR_INT) {
+                       irqst1 &= ~VPE_DEI_ERROR_INT;
+                       dei_error(ctx);
+               }
+               if (irqst1 & VPE_DS1_UV_ERROR_INT) {
+                       irqst1 &= ~VPE_DS1_UV_ERROR_INT;
+                       ds1_uv_error(ctx);
+               }
+       }
+
+       if (irqst0) {
+               if (irqst0 & VPE_INT0_LIST0_COMPLETE)
+                       vpdma_clear_list_stat(ctx->dev->vpdma);
+
+               irqst0 &= ~(VPE_INT0_LIST0_COMPLETE);
+       }
+
+       if (irqst0 | irqst1) {
+               dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: "
+                       "INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n",
+                       irqst0, irqst1);
+       }
+
+       disable_irqs(ctx);
+
+       vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);
+       vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);
+
+       vpdma_reset_desc_list(&ctx->desc_list);
+
+        /* the previous dst mv buffer becomes the next src mv buffer */
+       ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector;
+
+       if (ctx->aborting)
+               goto finished;
+
+       s_vb = ctx->src_vbs[0];
+       d_vb = ctx->dst_vb;
+       s_buf = &s_vb->v4l2_buf;
+       d_buf = &d_vb->v4l2_buf;
+
+       d_buf->timestamp = s_buf->timestamp;
+       if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) {
+               d_buf->flags |= V4L2_BUF_FLAG_TIMECODE;
+               d_buf->timecode = s_buf->timecode;
+       }
+       d_buf->sequence = ctx->sequence;
+       d_buf->field = ctx->field;
+
+       d_q_data = &ctx->q_data[Q_DATA_DST];
+       if (d_q_data->flags & Q_DATA_INTERLACED) {
+               if (ctx->field == V4L2_FIELD_BOTTOM) {
+                       ctx->sequence++;
+                       ctx->field = V4L2_FIELD_TOP;
+               } else {
+                       WARN_ON(ctx->field != V4L2_FIELD_TOP);
+                       ctx->field = V4L2_FIELD_BOTTOM;
+               }
+       } else {
+               ctx->sequence++;
+       }
+
+       if (ctx->deinterlacing)
+               s_vb = ctx->src_vbs[2];
+
+       spin_lock_irqsave(&dev->lock, flags);
+       v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE);
+       v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_DONE);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (ctx->deinterlacing) {
+               ctx->src_vbs[2] = ctx->src_vbs[1];
+               ctx->src_vbs[1] = ctx->src_vbs[0];
+       }
+
+       ctx->bufs_completed++;
+       if (ctx->bufs_completed < ctx->bufs_per_job) {
+               device_run(ctx);
+               goto handled;
+       }
+
+finished:
+       vpe_dbg(ctx->dev, "finishing transaction\n");
+       ctx->bufs_completed = 0;
+       v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+handled:
+       return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int vpe_querycap(struct file *file, void *priv,
+                       struct v4l2_capability *cap)
+{
+       strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
+       strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
+       strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
+       cap->device_caps  = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+       int i, index;
+       struct vpe_fmt *fmt = NULL;
+
+       index = 0;
+       for (i = 0; i < ARRAY_SIZE(vpe_formats); ++i) {
+               if (vpe_formats[i].types & type) {
+                       if (index == f->index) {
+                               fmt = &vpe_formats[i];
+                               break;
+                       }
+                       index++;
+               }
+       }
+
+       if (!fmt)
+               return -EINVAL;
+
+       strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+static int vpe_enum_fmt(struct file *file, void *priv,
+                               struct v4l2_fmtdesc *f)
+{
+       if (V4L2_TYPE_IS_OUTPUT(f->type))
+               return __enum_fmt(f, VPE_FMT_TYPE_OUTPUT);
+
+       return __enum_fmt(f, VPE_FMT_TYPE_CAPTURE);
+}
+
+static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct vpe_ctx *ctx = file2ctx(file);
+       struct vb2_queue *vq;
+       struct vpe_q_data *q_data;
+       int i;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+
+       pix->width = q_data->width;
+       pix->height = q_data->height;
+       pix->pixelformat = q_data->fmt->fourcc;
+       pix->field = q_data->field;
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+               pix->colorspace = q_data->colorspace;
+       } else {
+               struct vpe_q_data *s_q_data;
+
+               /* get colorspace from the source queue */
+               s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+               pix->colorspace = s_q_data->colorspace;
+       }
+
+       pix->num_planes = q_data->fmt->coplanar ? 2 : 1;
+
+       for (i = 0; i < pix->num_planes; i++) {
+               pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+               pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+       }
+
+       return 0;
+}
+
+static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
+                      struct vpe_fmt *fmt, int type)
+{
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *plane_fmt;
+       int i;
+
+       if (!fmt || !(fmt->types & type)) {
+               vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
+                       pix->pixelformat);
+               return -EINVAL;
+       }
+
+       if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE)
+               pix->field = V4L2_FIELD_NONE;
+
+       v4l_bound_align_image(&pix->width, MIN_W, MAX_W, W_ALIGN,
+                             &pix->height, MIN_H, MAX_H, H_ALIGN,
+                             S_ALIGN);
+
+       pix->num_planes = fmt->coplanar ? 2 : 1;
+       pix->pixelformat = fmt->fourcc;
+
+       if (type == VPE_FMT_TYPE_CAPTURE) {
+               struct vpe_q_data *s_q_data;
+
+               /* get colorspace from the source queue */
+               s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+               pix->colorspace = s_q_data->colorspace;
+       } else {
+               if (!pix->colorspace)
+                       pix->colorspace = V4L2_COLORSPACE_SMPTE240M;
+       }
+
+       for (i = 0; i < pix->num_planes; i++) {
+               int depth;
+
+               plane_fmt = &pix->plane_fmt[i];
+               depth = fmt->vpdma_fmt[i]->depth;
+
+               if (i == VPE_LUMA)
+                       plane_fmt->bytesperline =
+                                       round_up((pix->width * depth) >> 3,
+                                               1 << L_ALIGN);
+               else
+                       plane_fmt->bytesperline = pix->width;
+
+               plane_fmt->sizeimage =
+                               (pix->height * pix->width * depth) >> 3;
+       }
+
+       return 0;
+}
+
+static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+       struct vpe_fmt *fmt = find_format(f);
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type))
+               return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_OUTPUT);
+       else
+               return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_CAPTURE);
+}
+
+static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *plane_fmt;
+       struct vpe_q_data *q_data;
+       struct vb2_queue *vq;
+       int i;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               vpe_err(ctx->dev, "queue busy\n");
+               return -EBUSY;
+       }
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       q_data->fmt             = find_format(f);
+       q_data->width           = pix->width;
+       q_data->height          = pix->height;
+       q_data->colorspace      = pix->colorspace;
+       q_data->field           = pix->field;
+
+       for (i = 0; i < pix->num_planes; i++) {
+               plane_fmt = &pix->plane_fmt[i];
+
+               q_data->bytesperline[i] = plane_fmt->bytesperline;
+               q_data->sizeimage[i]    = plane_fmt->sizeimage;
+       }
+
+       q_data->c_rect.left     = 0;
+       q_data->c_rect.top      = 0;
+       q_data->c_rect.width    = q_data->width;
+       q_data->c_rect.height   = q_data->height;
+
+       if (q_data->field == V4L2_FIELD_ALTERNATE)
+               q_data->flags |= Q_DATA_INTERLACED;
+       else
+               q_data->flags &= ~Q_DATA_INTERLACED;
+
+       vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d",
+               f->type, q_data->width, q_data->height, q_data->fmt->fourcc,
+               q_data->bytesperline[VPE_LUMA]);
+       if (q_data->fmt->coplanar)
+               vpe_dbg(ctx->dev, " bpl_uv %d\n",
+                       q_data->bytesperline[VPE_CHROMA]);
+
+       return 0;
+}
+
+static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       int ret;
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       ret = vpe_try_fmt(file, priv, f);
+       if (ret)
+               return ret;
+
+       ret = __vpe_s_fmt(ctx, f);
+       if (ret)
+               return ret;
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type))
+               set_src_registers(ctx);
+       else
+               set_dst_registers(ctx);
+
+       return set_srcdst_params(ctx);
+}
+
+static int vpe_reqbufs(struct file *file, void *priv,
+                      struct v4l2_requestbuffers *reqbufs)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vpe_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vpe_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vpe_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vpe_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vpe_streamoff(struct file *file, void *priv, enum v4l2_buf_type type)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       vpe_dump_regs(ctx->dev);
+       vpdma_dump_regs(ctx->dev->vpdma);
+
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+/*
+ * defines number of buffers/frames a context can process with VPE before
+ * switching to a different context. default value is 1 buffer per context
+ */
+#define V4L2_CID_VPE_BUFS_PER_JOB              (V4L2_CID_USER_TI_VPE_BASE + 0)
+
+static int vpe_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vpe_ctx *ctx =
+               container_of(ctrl->handler, struct vpe_ctx, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VPE_BUFS_PER_JOB:
+               ctx->bufs_per_job = ctrl->val;
+               break;
+
+       default:
+               vpe_err(ctx->dev, "Invalid control\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vpe_ctrl_ops = {
+       .s_ctrl = vpe_s_ctrl,
+};
+
+static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
+       .vidioc_querycap        = vpe_querycap,
+
+       .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt,
+       .vidioc_g_fmt_vid_cap_mplane    = vpe_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane  = vpe_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane    = vpe_s_fmt,
+
+       .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt,
+       .vidioc_g_fmt_vid_out_mplane    = vpe_g_fmt,
+       .vidioc_try_fmt_vid_out_mplane  = vpe_try_fmt,
+       .vidioc_s_fmt_vid_out_mplane    = vpe_s_fmt,
+
+       .vidioc_reqbufs         = vpe_reqbufs,
+       .vidioc_querybuf        = vpe_querybuf,
+
+       .vidioc_qbuf            = vpe_qbuf,
+       .vidioc_dqbuf           = vpe_dqbuf,
+
+       .vidioc_streamon        = vpe_streamon,
+       .vidioc_streamoff       = vpe_streamoff,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * Queue operations
+ */
+static int vpe_queue_setup(struct vb2_queue *vq,
+                          const struct v4l2_format *fmt,
+                          unsigned int *nbuffers, unsigned int *nplanes,
+                          unsigned int sizes[], void *alloc_ctxs[])
+{
+       int i;
+       struct vpe_ctx *ctx = vb2_get_drv_priv(vq);
+       struct vpe_q_data *q_data;
+
+       q_data = get_q_data(ctx, vq->type);
+
+       *nplanes = q_data->fmt->coplanar ? 2 : 1;
+
+       for (i = 0; i < *nplanes; i++) {
+               sizes[i] = q_data->sizeimage[i];
+               alloc_ctxs[i] = ctx->dev->alloc_ctx;
+       }
+
+       vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers,
+               sizes[VPE_LUMA]);
+       if (q_data->fmt->coplanar)
+               vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]);
+
+       return 0;
+}
+
+static int vpe_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vpe_q_data *q_data;
+       int i, num_planes;
+
+       vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+       num_planes = q_data->fmt->coplanar ? 2 : 1;
+
+       for (i = 0; i < num_planes; i++) {
+               if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
+                       vpe_err(ctx->dev,
+                               "data will not fit into plane (%lu < %lu)\n",
+                               vb2_plane_size(vb, i),
+                               (long) q_data->sizeimage[i]);
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < num_planes; i++)
+               vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+
+       return 0;
+}
+
+static void vpe_buf_queue(struct vb2_buffer *vb)
+{
+       struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void vpe_wait_prepare(struct vb2_queue *q)
+{
+       struct vpe_ctx *ctx = vb2_get_drv_priv(q);
+       vpe_unlock(ctx);
+}
+
+static void vpe_wait_finish(struct vb2_queue *q)
+{
+       struct vpe_ctx *ctx = vb2_get_drv_priv(q);
+       vpe_lock(ctx);
+}
+
+static struct vb2_ops vpe_qops = {
+       .queue_setup     = vpe_queue_setup,
+       .buf_prepare     = vpe_buf_prepare,
+       .buf_queue       = vpe_buf_queue,
+       .wait_prepare    = vpe_wait_prepare,
+       .wait_finish     = vpe_wait_finish,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
+{
+       struct vpe_ctx *ctx = priv;
+       int ret;
+
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes = VB2_MMAP;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->ops = &vpe_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes = VB2_MMAP;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &vpe_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+       return vb2_queue_init(dst_vq);
+}
+
+static const struct v4l2_ctrl_config vpe_bufs_per_job = {
+       .ops = &vpe_ctrl_ops,
+       .id = V4L2_CID_VPE_BUFS_PER_JOB,
+       .name = "Buffers Per Transaction",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .def = VPE_DEF_BUFS_PER_JOB,
+       .min = 1,
+       .max = VIDEO_MAX_FRAME,
+       .step = 1,
+};
+
+/*
+ * File operations
+ */
+static int vpe_open(struct file *file)
+{
+       struct vpe_dev *dev = video_drvdata(file);
+       struct vpe_ctx *ctx = NULL;
+       struct vpe_q_data *s_q_data;
+       struct v4l2_ctrl_handler *hdl;
+       int ret;
+
+       vpe_dbg(dev, "vpe_open\n");
+
+       if (!dev->vpdma->ready) {
+               vpe_err(dev, "vpdma firmware not loaded\n");
+               return -ENODEV;
+       }
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->dev = dev;
+
+       if (mutex_lock_interruptible(&dev->dev_mutex)) {
+               ret = -ERESTARTSYS;
+               goto free_ctx;
+       }
+
+       ret = vpdma_create_desc_list(&ctx->desc_list, VPE_DESC_LIST_SIZE,
+                       VPDMA_LIST_TYPE_NORMAL);
+       if (ret != 0)
+               goto unlock;
+
+       ret = vpdma_alloc_desc_buf(&ctx->mmr_adb, sizeof(struct vpe_mmr_adb));
+       if (ret != 0)
+               goto free_desc_list;
+
+       init_adb_hdrs(ctx);
+
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+
+       hdl = &ctx->hdl;
+       v4l2_ctrl_handler_init(hdl, 1);
+       v4l2_ctrl_new_custom(hdl, &vpe_bufs_per_job, NULL);
+       if (hdl->error) {
+               ret = hdl->error;
+               goto exit_fh;
+       }
+       ctx->fh.ctrl_handler = hdl;
+       v4l2_ctrl_handler_setup(hdl);
+
+       s_q_data = &ctx->q_data[Q_DATA_SRC];
+       s_q_data->fmt = &vpe_formats[2];
+       s_q_data->width = 1920;
+       s_q_data->height = 1080;
+       s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height *
+                       s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
+       s_q_data->colorspace = V4L2_COLORSPACE_SMPTE240M;
+       s_q_data->field = V4L2_FIELD_NONE;
+       s_q_data->c_rect.left = 0;
+       s_q_data->c_rect.top = 0;
+       s_q_data->c_rect.width = s_q_data->width;
+       s_q_data->c_rect.height = s_q_data->height;
+       s_q_data->flags = 0;
+
+       ctx->q_data[Q_DATA_DST] = *s_q_data;
+
+       set_dei_shadow_registers(ctx);
+       set_src_registers(ctx);
+       set_dst_registers(ctx);
+       ret = set_srcdst_params(ctx);
+       if (ret)
+               goto exit_fh;
+
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
+       if (IS_ERR(ctx->m2m_ctx)) {
+               ret = PTR_ERR(ctx->m2m_ctx);
+               goto exit_fh;
+       }
+
+       v4l2_fh_add(&ctx->fh);
+
+       /*
+        * for now, just report the creation of the first instance, we can later
+        * optimize the driver to enable or disable clocks when the first
+        * instance is created or the last instance released
+        */
+       if (atomic_inc_return(&dev->num_instances) == 1)
+               vpe_dbg(dev, "first instance created\n");
+
+       ctx->bufs_per_job = VPE_DEF_BUFS_PER_JOB;
+
+       ctx->load_mmrs = true;
+
+       vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n",
+               ctx, ctx->m2m_ctx);
+
+       mutex_unlock(&dev->dev_mutex);
+
+       return 0;
+exit_fh:
+       v4l2_ctrl_handler_free(hdl);
+       v4l2_fh_exit(&ctx->fh);
+       vpdma_free_desc_buf(&ctx->mmr_adb);
+free_desc_list:
+       vpdma_free_desc_list(&ctx->desc_list);
+unlock:
+       mutex_unlock(&dev->dev_mutex);
+free_ctx:
+       kfree(ctx);
+       return ret;
+}
+
+static int vpe_release(struct file *file)
+{
+       struct vpe_dev *dev = video_drvdata(file);
+       struct vpe_ctx *ctx = file2ctx(file);
+
+       vpe_dbg(dev, "releasing instance %p\n", ctx);
+
+       mutex_lock(&dev->dev_mutex);
+       free_vbs(ctx);
+       free_mv_buffers(ctx);
+       vpdma_free_desc_list(&ctx->desc_list);
+       vpdma_free_desc_buf(&ctx->mmr_adb);
+
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       v4l2_ctrl_handler_free(&ctx->hdl);
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+
+       kfree(ctx);
+
+       /*
+        * for now, just report the release of the last instance, we can later
+        * optimize the driver to enable or disable clocks when the first
+        * instance is created or the last instance released
+        */
+       if (atomic_dec_return(&dev->num_instances) == 0)
+               vpe_dbg(dev, "last instance released\n");
+
+       mutex_unlock(&dev->dev_mutex);
+
+       return 0;
+}
+
+static unsigned int vpe_poll(struct file *file,
+                            struct poll_table_struct *wait)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+       struct vpe_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&dev->dev_mutex);
+       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_unlock(&dev->dev_mutex);
+       return ret;
+}
+
+static int vpe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct vpe_ctx *ctx = file2ctx(file);
+       struct vpe_dev *dev = ctx->dev;
+       int ret;
+
+       if (mutex_lock_interruptible(&dev->dev_mutex))
+               return -ERESTARTSYS;
+       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&dev->dev_mutex);
+       return ret;
+}
+
+static const struct v4l2_file_operations vpe_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vpe_open,
+       .release        = vpe_release,
+       .poll           = vpe_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vpe_mmap,
+};
+
+static struct video_device vpe_videodev = {
+       .name           = VPE_MODULE_NAME,
+       .fops           = &vpe_fops,
+       .ioctl_ops      = &vpe_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release,
+       .vfl_dir        = VFL_DIR_M2M,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+       .device_run     = device_run,
+       .job_ready      = job_ready,
+       .job_abort      = job_abort,
+       .lock           = vpe_lock,
+       .unlock         = vpe_unlock,
+};
+
+static int vpe_runtime_get(struct platform_device *pdev)
+{
+       int r;
+
+       dev_dbg(&pdev->dev, "vpe_runtime_get\n");
+
+       r = pm_runtime_get_sync(&pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void vpe_runtime_put(struct platform_device *pdev)
+{
+
+       int r;
+
+       dev_dbg(&pdev->dev, "vpe_runtime_put\n");
+
+       r = pm_runtime_put_sync(&pdev->dev);
+       WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static int vpe_probe(struct platform_device *pdev)
+{
+       struct vpe_dev *dev;
+       struct video_device *vfd;
+       struct resource *res;
+       int ret, irq, func;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
+
+       spin_lock_init(&dev->lock);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               return ret;
+
+       atomic_set(&dev->num_instances, 0);
+       mutex_init(&dev->dev_mutex);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpe_top");
+       /*
+        * HACK: we get resource info from device tree in the form of a list of
+        * VPE sub blocks, the driver currently uses only the base of vpe_top
+        * for register access, the driver should be changed later to access
+        * registers based on the sub block base addresses
+        */
+       dev->base = devm_ioremap(&pdev->dev, res->start, SZ_32K);
+       if (IS_ERR(dev->base)) {
+               ret = PTR_ERR(dev->base);
+               goto v4l2_dev_unreg;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, irq, vpe_irq, 0, VPE_MODULE_NAME,
+                       dev);
+       if (ret)
+               goto v4l2_dev_unreg;
+
+       platform_set_drvdata(pdev, dev);
+
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               vpe_err(dev, "Failed to alloc vb2 context\n");
+               ret = PTR_ERR(dev->alloc_ctx);
+               goto v4l2_dev_unreg;
+       }
+
+       dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               vpe_err(dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(dev->m2m_dev);
+               goto rel_ctx;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+
+       ret = vpe_runtime_get(pdev);
+       if (ret)
+               goto rel_m2m;
+
+       /* Perform clk enable followed by reset */
+       vpe_set_clock_enable(dev, 1);
+
+       vpe_top_reset(dev);
+
+       func = read_field_reg(dev, VPE_PID, VPE_PID_FUNC_MASK,
+               VPE_PID_FUNC_SHIFT);
+       vpe_dbg(dev, "VPE PID function %x\n", func);
+
+       vpe_top_vpdma_reset(dev);
+
+       dev->vpdma = vpdma_create(pdev);
+       if (IS_ERR(dev->vpdma))
+               goto runtime_put;
+
+       vfd = &dev->vfd;
+       *vfd = vpe_videodev;
+       vfd->lock = &dev->dev_mutex;
+       vfd->v4l2_dev = &dev->v4l2_dev;
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               vpe_err(dev, "Failed to register video device\n");
+               goto runtime_put;
+       }
+
+       video_set_drvdata(vfd, dev);
+       snprintf(vfd->name, sizeof(vfd->name), "%s", vpe_videodev.name);
+       dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",
+               vfd->num);
+
+       return 0;
+
+runtime_put:
+       vpe_runtime_put(pdev);
+rel_m2m:
+       pm_runtime_disable(&pdev->dev);
+       v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+v4l2_dev_unreg:
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       return ret;
+}
+
+static int vpe_remove(struct platform_device *pdev)
+{
+       struct vpe_dev *dev =
+               (struct vpe_dev *) platform_get_drvdata(pdev);
+
+       v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME);
+
+       v4l2_m2m_release(dev->m2m_dev);
+       video_unregister_device(&dev->vfd);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+
+       vpe_set_clock_enable(dev, 0);
+       vpe_runtime_put(pdev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id vpe_of_match[] = {
+       {
+               .compatible = "ti,vpe",
+       },
+       {},
+};
+#else
+#define vpe_of_match NULL
+#endif
+
+static struct platform_driver vpe_pdrv = {
+       .probe          = vpe_probe,
+       .remove         = vpe_remove,
+       .driver         = {
+               .name   = VPE_MODULE_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = vpe_of_match,
+       },
+};
+
+static void __exit vpe_exit(void)
+{
+       platform_driver_unregister(&vpe_pdrv);
+}
+
+static int __init vpe_init(void)
+{
+       return platform_driver_register(&vpe_pdrv);
+}
+
+module_init(vpe_init);
+module_exit(vpe_exit);
+
+MODULE_DESCRIPTION("TI VPE driver");
+MODULE_AUTHOR("Dale Farnsworth, <dale@farnsworth.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h
new file mode 100644 (file)
index 0000000..ed214e8
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __TI_VPE_REGS_H
+#define __TI_VPE_REGS_H
+
+/* VPE register offsets and field selectors */
+
+/* VPE top level regs */
+#define VPE_PID                                0x0000
+#define VPE_PID_MINOR_MASK             0x3f
+#define VPE_PID_MINOR_SHIFT            0
+#define VPE_PID_CUSTOM_MASK            0x03
+#define VPE_PID_CUSTOM_SHIFT           6
+#define VPE_PID_MAJOR_MASK             0x07
+#define VPE_PID_MAJOR_SHIFT            8
+#define VPE_PID_RTL_MASK               0x1f
+#define VPE_PID_RTL_SHIFT              11
+#define VPE_PID_FUNC_MASK              0xfff
+#define VPE_PID_FUNC_SHIFT             16
+#define VPE_PID_SCHEME_MASK            0x03
+#define VPE_PID_SCHEME_SHIFT           30
+
+#define VPE_SYSCONFIG                  0x0010
+#define VPE_SYSCONFIG_IDLE_MASK                0x03
+#define VPE_SYSCONFIG_IDLE_SHIFT       2
+#define VPE_SYSCONFIG_STANDBY_MASK     0x03
+#define VPE_SYSCONFIG_STANDBY_SHIFT    4
+#define VPE_FORCE_IDLE_MODE            0
+#define VPE_NO_IDLE_MODE               1
+#define VPE_SMART_IDLE_MODE            2
+#define VPE_SMART_IDLE_WAKEUP_MODE     3
+#define VPE_FORCE_STANDBY_MODE         0
+#define VPE_NO_STANDBY_MODE            1
+#define VPE_SMART_STANDBY_MODE         2
+#define VPE_SMART_STANDBY_WAKEUP_MODE  3
+
+#define VPE_INT0_STATUS0_RAW_SET       0x0020
+#define VPE_INT0_STATUS0_RAW           VPE_INT0_STATUS0_RAW_SET
+#define VPE_INT0_STATUS0_CLR           0x0028
+#define VPE_INT0_STATUS0               VPE_INT0_STATUS0_CLR
+#define VPE_INT0_ENABLE0_SET           0x0030
+#define VPE_INT0_ENABLE0               VPE_INT0_ENABLE0_SET
+#define VPE_INT0_ENABLE0_CLR           0x0038
+#define VPE_INT0_LIST0_COMPLETE                (1 << 0)
+#define VPE_INT0_LIST0_NOTIFY          (1 << 1)
+#define VPE_INT0_LIST1_COMPLETE                (1 << 2)
+#define VPE_INT0_LIST1_NOTIFY          (1 << 3)
+#define VPE_INT0_LIST2_COMPLETE                (1 << 4)
+#define VPE_INT0_LIST2_NOTIFY          (1 << 5)
+#define VPE_INT0_LIST3_COMPLETE                (1 << 6)
+#define VPE_INT0_LIST3_NOTIFY          (1 << 7)
+#define VPE_INT0_LIST4_COMPLETE                (1 << 8)
+#define VPE_INT0_LIST4_NOTIFY          (1 << 9)
+#define VPE_INT0_LIST5_COMPLETE                (1 << 10)
+#define VPE_INT0_LIST5_NOTIFY          (1 << 11)
+#define VPE_INT0_LIST6_COMPLETE                (1 << 12)
+#define VPE_INT0_LIST6_NOTIFY          (1 << 13)
+#define VPE_INT0_LIST7_COMPLETE                (1 << 14)
+#define VPE_INT0_LIST7_NOTIFY          (1 << 15)
+#define VPE_INT0_DESCRIPTOR            (1 << 16)
+#define VPE_DEI_FMD_INT                        (1 << 18)
+
+#define VPE_INT0_STATUS1_RAW_SET       0x0024
+#define VPE_INT0_STATUS1_RAW           VPE_INT0_STATUS1_RAW_SET
+#define VPE_INT0_STATUS1_CLR           0x002c
+#define VPE_INT0_STATUS1               VPE_INT0_STATUS1_CLR
+#define VPE_INT0_ENABLE1_SET           0x0034
+#define VPE_INT0_ENABLE1               VPE_INT0_ENABLE1_SET
+#define VPE_INT0_ENABLE1_CLR           0x003c
+#define VPE_INT0_CHANNEL_GROUP0                (1 << 0)
+#define VPE_INT0_CHANNEL_GROUP1                (1 << 1)
+#define VPE_INT0_CHANNEL_GROUP2                (1 << 2)
+#define VPE_INT0_CHANNEL_GROUP3                (1 << 3)
+#define VPE_INT0_CHANNEL_GROUP4                (1 << 4)
+#define VPE_INT0_CHANNEL_GROUP5                (1 << 5)
+#define VPE_INT0_CLIENT                        (1 << 7)
+#define VPE_DEI_ERROR_INT              (1 << 16)
+#define VPE_DS1_UV_ERROR_INT           (1 << 22)
+
+#define VPE_INTC_EOI                   0x00a0
+
+#define VPE_CLK_ENABLE                 0x0100
+#define VPE_VPEDMA_CLK_ENABLE          (1 << 0)
+#define VPE_DATA_PATH_CLK_ENABLE       (1 << 1)
+
+#define VPE_CLK_RESET                  0x0104
+#define VPE_VPDMA_CLK_RESET_MASK       0x1
+#define VPE_VPDMA_CLK_RESET_SHIFT      0
+#define VPE_DATA_PATH_CLK_RESET_MASK   0x1
+#define VPE_DATA_PATH_CLK_RESET_SHIFT  1
+#define VPE_MAIN_RESET_MASK            0x1
+#define VPE_MAIN_RESET_SHIFT           31
+
+#define VPE_CLK_FORMAT_SELECT          0x010c
+#define VPE_CSC_SRC_SELECT_MASK                0x03
+#define VPE_CSC_SRC_SELECT_SHIFT       0
+#define VPE_RGB_OUT_SELECT             (1 << 8)
+#define VPE_DS_SRC_SELECT_MASK         0x07
+#define VPE_DS_SRC_SELECT_SHIFT                9
+#define VPE_DS_BYPASS                  (1 << 16)
+#define VPE_COLOR_SEPARATE_422         (1 << 18)
+
+#define VPE_DS_SRC_DEI_SCALER          (5 << VPE_DS_SRC_SELECT_SHIFT)
+#define VPE_CSC_SRC_DEI_SCALER         (3 << VPE_CSC_SRC_SELECT_SHIFT)
+
+#define VPE_CLK_RANGE_MAP              0x011c
+#define VPE_RANGE_RANGE_MAP_Y_MASK     0x07
+#define VPE_RANGE_RANGE_MAP_Y_SHIFT    0
+#define VPE_RANGE_RANGE_MAP_UV_MASK    0x07
+#define VPE_RANGE_RANGE_MAP_UV_SHIFT   3
+#define VPE_RANGE_MAP_ON               (1 << 6)
+#define VPE_RANGE_REDUCTION_ON         (1 << 28)
+
+/* VPE chrominance upsampler regs */
+#define VPE_US1_R0                     0x0304
+#define VPE_US2_R0                     0x0404
+#define VPE_US3_R0                     0x0504
+#define VPE_US_C1_MASK                 0x3fff
+#define VPE_US_C1_SHIFT                        2
+#define VPE_US_C0_MASK                 0x3fff
+#define VPE_US_C0_SHIFT                        18
+#define VPE_US_MODE_MASK               0x03
+#define VPE_US_MODE_SHIFT              16
+#define VPE_ANCHOR_FID0_C1_MASK                0x3fff
+#define VPE_ANCHOR_FID0_C1_SHIFT       2
+#define VPE_ANCHOR_FID0_C0_MASK                0x3fff
+#define VPE_ANCHOR_FID0_C0_SHIFT       18
+
+#define VPE_US1_R1                     0x0308
+#define VPE_US2_R1                     0x0408
+#define VPE_US3_R1                     0x0508
+#define VPE_ANCHOR_FID0_C3_MASK                0x3fff
+#define VPE_ANCHOR_FID0_C3_SHIFT       2
+#define VPE_ANCHOR_FID0_C2_MASK                0x3fff
+#define VPE_ANCHOR_FID0_C2_SHIFT       18
+
+#define VPE_US1_R2                     0x030c
+#define VPE_US2_R2                     0x040c
+#define VPE_US3_R2                     0x050c
+#define VPE_INTERP_FID0_C1_MASK                0x3fff
+#define VPE_INTERP_FID0_C1_SHIFT       2
+#define VPE_INTERP_FID0_C0_MASK                0x3fff
+#define VPE_INTERP_FID0_C0_SHIFT       18
+
+#define VPE_US1_R3                     0x0310
+#define VPE_US2_R3                     0x0410
+#define VPE_US3_R3                     0x0510
+#define VPE_INTERP_FID0_C3_MASK                0x3fff
+#define VPE_INTERP_FID0_C3_SHIFT       2
+#define VPE_INTERP_FID0_C2_MASK                0x3fff
+#define VPE_INTERP_FID0_C2_SHIFT       18
+
+#define VPE_US1_R4                     0x0314
+#define VPE_US2_R4                     0x0414
+#define VPE_US3_R4                     0x0514
+#define VPE_ANCHOR_FID1_C1_MASK                0x3fff
+#define VPE_ANCHOR_FID1_C1_SHIFT       2
+#define VPE_ANCHOR_FID1_C0_MASK                0x3fff
+#define VPE_ANCHOR_FID1_C0_SHIFT       18
+
+#define VPE_US1_R5                     0x0318
+#define VPE_US2_R5                     0x0418
+#define VPE_US3_R5                     0x0518
+#define VPE_ANCHOR_FID1_C3_MASK                0x3fff
+#define VPE_ANCHOR_FID1_C3_SHIFT       2
+#define VPE_ANCHOR_FID1_C2_MASK                0x3fff
+#define VPE_ANCHOR_FID1_C2_SHIFT       18
+
+#define VPE_US1_R6                     0x031c
+#define VPE_US2_R6                     0x041c
+#define VPE_US3_R6                     0x051c
+#define VPE_INTERP_FID1_C1_MASK                0x3fff
+#define VPE_INTERP_FID1_C1_SHIFT       2
+#define VPE_INTERP_FID1_C0_MASK                0x3fff
+#define VPE_INTERP_FID1_C0_SHIFT       18
+
+#define VPE_US1_R7                     0x0320
+#define VPE_US2_R7                     0x0420
+#define VPE_US3_R7                     0x0520
+#define VPE_INTERP_FID0_C3_MASK                0x3fff
+#define VPE_INTERP_FID0_C3_SHIFT       2
+#define VPE_INTERP_FID0_C2_MASK                0x3fff
+#define VPE_INTERP_FID0_C2_SHIFT       18
+
+/* VPE de-interlacer regs */
+#define VPE_DEI_FRAME_SIZE             0x0600
+#define VPE_DEI_WIDTH_MASK             0x07ff
+#define VPE_DEI_WIDTH_SHIFT            0
+#define VPE_DEI_HEIGHT_MASK            0x07ff
+#define VPE_DEI_HEIGHT_SHIFT           16
+#define VPE_DEI_INTERLACE_BYPASS       (1 << 29)
+#define VPE_DEI_FIELD_FLUSH            (1 << 30)
+#define VPE_DEI_PROGRESSIVE            (1 << 31)
+
+#define VPE_MDT_BYPASS                 0x0604
+#define VPE_MDT_TEMPMAX_BYPASS         (1 << 0)
+#define VPE_MDT_SPATMAX_BYPASS         (1 << 1)
+
+#define VPE_MDT_SF_THRESHOLD           0x0608
+#define VPE_MDT_SF_SC_THR1_MASK                0xff
+#define VPE_MDT_SF_SC_THR1_SHIFT       0
+#define VPE_MDT_SF_SC_THR2_MASK                0xff
+#define VPE_MDT_SF_SC_THR2_SHIFT       0
+#define VPE_MDT_SF_SC_THR3_MASK                0xff
+#define VPE_MDT_SF_SC_THR3_SHIFT       0
+
+#define VPE_EDI_CONFIG                 0x060c
+#define VPE_EDI_INP_MODE_MASK          0x03
+#define VPE_EDI_INP_MODE_SHIFT         0
+#define VPE_EDI_ENABLE_3D              (1 << 2)
+#define VPE_EDI_ENABLE_CHROMA_3D       (1 << 3)
+#define VPE_EDI_CHROMA3D_COR_THR_MASK  0xff
+#define VPE_EDI_CHROMA3D_COR_THR_SHIFT 8
+#define VPE_EDI_DIR_COR_LOWER_THR_MASK 0xff
+#define VPE_EDI_DIR_COR_LOWER_THR_SHIFT        16
+#define VPE_EDI_COR_SCALE_FACTOR_MASK  0xff
+#define VPE_EDI_COR_SCALE_FACTOR_SHIFT 23
+
+#define VPE_DEI_EDI_LUT_R0             0x0610
+#define VPE_EDI_LUT0_MASK              0x1f
+#define VPE_EDI_LUT0_SHIFT             0
+#define VPE_EDI_LUT1_MASK              0x1f
+#define VPE_EDI_LUT1_SHIFT             8
+#define VPE_EDI_LUT2_MASK              0x1f
+#define VPE_EDI_LUT2_SHIFT             16
+#define VPE_EDI_LUT3_MASK              0x1f
+#define VPE_EDI_LUT3_SHIFT             24
+
+#define VPE_DEI_EDI_LUT_R1             0x0614
+#define VPE_EDI_LUT0_MASK              0x1f
+#define VPE_EDI_LUT0_SHIFT             0
+#define VPE_EDI_LUT1_MASK              0x1f
+#define VPE_EDI_LUT1_SHIFT             8
+#define VPE_EDI_LUT2_MASK              0x1f
+#define VPE_EDI_LUT2_SHIFT             16
+#define VPE_EDI_LUT3_MASK              0x1f
+#define VPE_EDI_LUT3_SHIFT             24
+
+#define VPE_DEI_EDI_LUT_R2             0x0618
+#define VPE_EDI_LUT4_MASK              0x1f
+#define VPE_EDI_LUT4_SHIFT             0
+#define VPE_EDI_LUT5_MASK              0x1f
+#define VPE_EDI_LUT5_SHIFT             8
+#define VPE_EDI_LUT6_MASK              0x1f
+#define VPE_EDI_LUT6_SHIFT             16
+#define VPE_EDI_LUT7_MASK              0x1f
+#define VPE_EDI_LUT7_SHIFT             24
+
+#define VPE_DEI_EDI_LUT_R3             0x061c
+#define VPE_EDI_LUT8_MASK              0x1f
+#define VPE_EDI_LUT8_SHIFT             0
+#define VPE_EDI_LUT9_MASK              0x1f
+#define VPE_EDI_LUT9_SHIFT             8
+#define VPE_EDI_LUT10_MASK             0x1f
+#define VPE_EDI_LUT10_SHIFT            16
+#define VPE_EDI_LUT11_MASK             0x1f
+#define VPE_EDI_LUT11_SHIFT            24
+
+#define VPE_DEI_FMD_WINDOW_R0          0x0620
+#define VPE_FMD_WINDOW_MINX_MASK       0x07ff
+#define VPE_FMD_WINDOW_MINX_SHIFT      0
+#define VPE_FMD_WINDOW_MAXX_MASK       0x07ff
+#define VPE_FMD_WINDOW_MAXX_SHIFT      16
+#define VPE_FMD_WINDOW_ENABLE          (1 << 31)
+
+#define VPE_DEI_FMD_WINDOW_R1          0x0624
+#define VPE_FMD_WINDOW_MINY_MASK       0x07ff
+#define VPE_FMD_WINDOW_MINY_SHIFT      0
+#define VPE_FMD_WINDOW_MAXY_MASK       0x07ff
+#define VPE_FMD_WINDOW_MAXY_SHIFT      16
+
+#define VPE_DEI_FMD_CONTROL_R0         0x0628
+#define VPE_FMD_ENABLE                 (1 << 0)
+#define VPE_FMD_LOCK                   (1 << 1)
+#define VPE_FMD_JAM_DIR                        (1 << 2)
+#define VPE_FMD_BED_ENABLE             (1 << 3)
+#define VPE_FMD_CAF_FIELD_THR_MASK     0xff
+#define VPE_FMD_CAF_FIELD_THR_SHIFT    16
+#define VPE_FMD_CAF_LINE_THR_MASK      0xff
+#define VPE_FMD_CAF_LINE_THR_SHIFT     24
+
+#define VPE_DEI_FMD_CONTROL_R1         0x062c
+#define VPE_FMD_CAF_THR_MASK           0x000fffff
+#define VPE_FMD_CAF_THR_SHIFT          0
+
+#define VPE_DEI_FMD_STATUS_R0          0x0630
+#define VPE_FMD_CAF_MASK               0x000fffff
+#define VPE_FMD_CAF_SHIFT              0
+#define VPE_FMD_RESET                  (1 << 24)
+
+#define VPE_DEI_FMD_STATUS_R1          0x0634
+#define VPE_FMD_FIELD_DIFF_MASK                0x0fffffff
+#define VPE_FMD_FIELD_DIFF_SHIFT       0
+
+#define VPE_DEI_FMD_STATUS_R2          0x0638
+#define VPE_FMD_FRAME_DIFF_MASK                0x000fffff
+#define VPE_FMD_FRAME_DIFF_SHIFT       0
+
+/* VPE scaler regs */
+#define VPE_SC_MP_SC0                  0x0700
+#define VPE_INTERLACE_O                        (1 << 0)
+#define VPE_LINEAR                     (1 << 1)
+#define VPE_SC_BYPASS                  (1 << 2)
+#define VPE_INVT_FID                   (1 << 3)
+#define VPE_USE_RAV                    (1 << 4)
+#define VPE_ENABLE_EV                  (1 << 5)
+#define VPE_AUTO_HS                    (1 << 6)
+#define VPE_DCM_2X                     (1 << 7)
+#define VPE_DCM_4X                     (1 << 8)
+#define VPE_HP_BYPASS                  (1 << 9)
+#define VPE_INTERLACE_I                        (1 << 10)
+#define VPE_ENABLE_SIN2_VER_INTP       (1 << 11)
+#define VPE_Y_PK_EN                    (1 << 14)
+#define VPE_TRIM                       (1 << 15)
+#define VPE_SELFGEN_FID                        (1 << 16)
+
+#define VPE_SC_MP_SC1                  0x0704
+#define VPE_ROW_ACC_INC_MASK           0x07ffffff
+#define VPE_ROW_ACC_INC_SHIFT          0
+
+#define VPE_SC_MP_SC2                  0x0708
+#define VPE_ROW_ACC_OFFSET_MASK                0x0fffffff
+#define VPE_ROW_ACC_OFFSET_SHIFT       0
+
+#define VPE_SC_MP_SC3                  0x070c
+#define VPE_ROW_ACC_OFFSET_B_MASK      0x0fffffff
+#define VPE_ROW_ACC_OFFSET_B_SHIFT     0
+
+#define VPE_SC_MP_SC4                  0x0710
+#define VPE_TAR_H_MASK                 0x07ff
+#define VPE_TAR_H_SHIFT                        0
+#define VPE_TAR_W_MASK                 0x07ff
+#define VPE_TAR_W_SHIFT                        12
+#define VPE_LIN_ACC_INC_U_MASK         0x07
+#define VPE_LIN_ACC_INC_U_SHIFT                24
+#define VPE_NLIN_ACC_INIT_U_MASK       0x07
+#define VPE_NLIN_ACC_INIT_U_SHIFT      28
+
+#define VPE_SC_MP_SC5                  0x0714
+#define VPE_SRC_H_MASK                 0x07ff
+#define VPE_SRC_H_SHIFT                        0
+#define VPE_SRC_W_MASK                 0x07ff
+#define VPE_SRC_W_SHIFT                        12
+#define VPE_NLIN_ACC_INC_U_MASK                0x07
+#define VPE_NLIN_ACC_INC_U_SHIFT       24
+
+#define VPE_SC_MP_SC6                  0x0718
+#define VPE_ROW_ACC_INIT_RAV_MASK      0x03ff
+#define VPE_ROW_ACC_INIT_RAV_SHIFT     0
+#define VPE_ROW_ACC_INIT_RAV_B_MASK    0x03ff
+#define VPE_ROW_ACC_INIT_RAV_B_SHIFT   10
+
+#define VPE_SC_MP_SC8                  0x0720
+#define VPE_NLIN_LEFT_MASK             0x07ff
+#define VPE_NLIN_LEFT_SHIFT            0
+#define VPE_NLIN_RIGHT_MASK            0x07ff
+#define VPE_NLIN_RIGHT_SHIFT           12
+
+#define VPE_SC_MP_SC9                  0x0724
+#define VPE_LIN_ACC_INC                        VPE_SC_MP_SC9
+
+#define VPE_SC_MP_SC10                 0x0728
+#define VPE_NLIN_ACC_INIT              VPE_SC_MP_SC10
+
+#define VPE_SC_MP_SC11                 0x072c
+#define VPE_NLIN_ACC_INC               VPE_SC_MP_SC11
+
+#define VPE_SC_MP_SC12                 0x0730
+#define VPE_COL_ACC_OFFSET_MASK                0x01ffffff
+#define VPE_COL_ACC_OFFSET_SHIFT       0
+
+#define VPE_SC_MP_SC13                 0x0734
+#define VPE_SC_FACTOR_RAV_MASK         0x03ff
+#define VPE_SC_FACTOR_RAV_SHIFT                0
+#define VPE_CHROMA_INTP_THR_MASK       0x03ff
+#define VPE_CHROMA_INTP_THR_SHIFT      12
+#define VPE_DELTA_CHROMA_THR_MASK      0x0f
+#define VPE_DELTA_CHROMA_THR_SHIFT     24
+
+#define VPE_SC_MP_SC17                 0x0744
+#define VPE_EV_THR_MASK                        0x03ff
+#define VPE_EV_THR_SHIFT               12
+#define VPE_DELTA_LUMA_THR_MASK                0x0f
+#define VPE_DELTA_LUMA_THR_SHIFT       24
+#define VPE_DELTA_EV_THR_MASK          0x0f
+#define VPE_DELTA_EV_THR_SHIFT         28
+
+#define VPE_SC_MP_SC18                 0x0748
+#define VPE_HS_FACTOR_MASK             0x03ff
+#define VPE_HS_FACTOR_SHIFT            0
+#define VPE_CONF_DEFAULT_MASK          0x01ff
+#define VPE_CONF_DEFAULT_SHIFT         16
+
+#define VPE_SC_MP_SC19                 0x074c
+#define VPE_HPF_COEFF0_MASK            0xff
+#define VPE_HPF_COEFF0_SHIFT           0
+#define VPE_HPF_COEFF1_MASK            0xff
+#define VPE_HPF_COEFF1_SHIFT           8
+#define VPE_HPF_COEFF2_MASK            0xff
+#define VPE_HPF_COEFF2_SHIFT           16
+#define VPE_HPF_COEFF3_MASK            0xff
+#define VPE_HPF_COEFF3_SHIFT           23
+
+#define VPE_SC_MP_SC20                 0x0750
+#define VPE_HPF_COEFF4_MASK            0xff
+#define VPE_HPF_COEFF4_SHIFT           0
+#define VPE_HPF_COEFF5_MASK            0xff
+#define VPE_HPF_COEFF5_SHIFT           8
+#define VPE_HPF_NORM_SHIFT_MASK                0x07
+#define VPE_HPF_NORM_SHIFT_SHIFT       16
+#define VPE_NL_LIMIT_MASK              0x1ff
+#define VPE_NL_LIMIT_SHIFT             20
+
+#define VPE_SC_MP_SC21                 0x0754
+#define VPE_NL_LO_THR_MASK             0x01ff
+#define VPE_NL_LO_THR_SHIFT            0
+#define VPE_NL_LO_SLOPE_MASK           0xff
+#define VPE_NL_LO_SLOPE_SHIFT          16
+
+#define VPE_SC_MP_SC22                 0x0758
+#define VPE_NL_HI_THR_MASK             0x01ff
+#define VPE_NL_HI_THR_SHIFT            0
+#define VPE_NL_HI_SLOPE_SH_MASK                0x07
+#define VPE_NL_HI_SLOPE_SH_SHIFT       16
+
+#define VPE_SC_MP_SC23                 0x075c
+#define VPE_GRADIENT_THR_MASK          0x07ff
+#define VPE_GRADIENT_THR_SHIFT         0
+#define VPE_GRADIENT_THR_RANGE_MASK    0x0f
+#define VPE_GRADIENT_THR_RANGE_SHIFT   12
+#define VPE_MIN_GY_THR_MASK            0xff
+#define VPE_MIN_GY_THR_SHIFT           16
+#define VPE_MIN_GY_THR_RANGE_MASK      0x0f
+#define VPE_MIN_GY_THR_RANGE_SHIFT     28
+
+#define VPE_SC_MP_SC24                 0x0760
+#define VPE_ORG_H_MASK                 0x07ff
+#define VPE_ORG_H_SHIFT                        0
+#define VPE_ORG_W_MASK                 0x07ff
+#define VPE_ORG_W_SHIFT                        16
+
+#define VPE_SC_MP_SC25                 0x0764
+#define VPE_OFF_H_MASK                 0x07ff
+#define VPE_OFF_H_SHIFT                        0
+#define VPE_OFF_W_MASK                 0x07ff
+#define VPE_OFF_W_SHIFT                        16
+
+/* VPE color space converter regs */
+#define VPE_CSC_CSC00                  0x5700
+#define VPE_CSC_A0_MASK                        0x1fff
+#define VPE_CSC_A0_SHIFT               0
+#define VPE_CSC_B0_MASK                        0x1fff
+#define VPE_CSC_B0_SHIFT               16
+
+#define VPE_CSC_CSC01                  0x5704
+#define VPE_CSC_C0_MASK                        0x1fff
+#define VPE_CSC_C0_SHIFT               0
+#define VPE_CSC_A1_MASK                        0x1fff
+#define VPE_CSC_A1_SHIFT               16
+
+#define VPE_CSC_CSC02                  0x5708
+#define VPE_CSC_B1_MASK                        0x1fff
+#define VPE_CSC_B1_SHIFT               0
+#define VPE_CSC_C1_MASK                        0x1fff
+#define VPE_CSC_C1_SHIFT               16
+
+#define VPE_CSC_CSC03                  0x570c
+#define VPE_CSC_A2_MASK                        0x1fff
+#define VPE_CSC_A2_SHIFT               0
+#define VPE_CSC_B2_MASK                        0x1fff
+#define VPE_CSC_B2_SHIFT               16
+
+#define VPE_CSC_CSC04                  0x5710
+#define VPE_CSC_C2_MASK                        0x1fff
+#define VPE_CSC_C2_SHIFT               0
+#define VPE_CSC_D0_MASK                        0x0fff
+#define VPE_CSC_D0_SHIFT               16
+
+#define VPE_CSC_CSC05                  0x5714
+#define VPE_CSC_D1_MASK                        0x0fff
+#define VPE_CSC_D1_SHIFT               0
+#define VPE_CSC_D2_MASK                        0x0fff
+#define VPE_CSC_D2_SHIFT               16
+#define VPE_CSC_BYPASS                 (1 << 28)
+
+#endif
index b557caf..6a74ce0 100644 (file)
@@ -403,7 +403,7 @@ static int timblogiw_s_input(struct file *file, void  *priv, unsigned int input)
        return 0;
 }
 
-static int timblogiw_streamon(struct file *file, void  *priv, unsigned int type)
+static int timblogiw_streamon(struct file *file, void  *priv, enum v4l2_buf_type type)
 {
        struct video_device *vdev = video_devdata(file);
        struct timblogiw_fh *fh = priv;
@@ -420,7 +420,7 @@ static int timblogiw_streamon(struct file *file, void  *priv, unsigned int type)
 }
 
 static int timblogiw_streamoff(struct file *file, void  *priv,
-       unsigned int type)
+       enum v4l2_buf_type type)
 {
        struct video_device *vdev = video_devdata(file);
        struct timblogiw_fh *fh = priv;
index 21db23b..fa39640 100644 (file)
@@ -123,7 +123,7 @@ static int keene_cmd_set(struct keene_device *radio)
        /* If bit 0 is set, then transmit mono, otherwise stereo.
           If bit 2 is set, then enable 75 us preemphasis, otherwise
           it is 50 us. */
-       radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0);
+       radio->buffer[3] = (radio->stereo ? 0 : 1) | (radio->preemph_75_us ? 4 : 0);
        radio->buffer[4] = 0x00;
        radio->buffer[5] = 0x00;
        radio->buffer[6] = 0x00;
index f1e3714..93d864e 100644 (file)
@@ -74,8 +74,8 @@ static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea)
        struct fmr2 *fmr2 = tea->private_data;
        u8 bits = inb(fmr2->io);
 
-       return  (bits & STR_DATA) ? TEA575X_DATA : 0 |
-               (bits & STR_MOST) ? TEA575X_MOST : 0;
+       return  ((bits & STR_DATA) ? TEA575X_DATA : 0) |
+               ((bits & STR_MOST) ? TEA575X_MOST : 0);
 }
 
 static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
@@ -295,7 +295,6 @@ static void fmr2_remove(struct fmr2 *fmr2)
 static int fmr2_isa_remove(struct device *pdev, unsigned int ndev)
 {
        fmr2_remove(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 0bd2500..0e750ae 100644 (file)
@@ -254,7 +254,7 @@ static unsigned int si470x_get_step(struct si470x_device *radio)
        /* 2:  50 kHz */
        default:
                return 50 * 16;
-       };
+       }
 }
 
 
index fe16088..9ec48cc 100644 (file)
@@ -1456,7 +1456,7 @@ static int si4713_probe(struct i2c_client *client,
 
        if (client->irq) {
                rval = request_irq(client->irq,
-                       si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+                       si4713_handler, IRQF_TRIGGER_FALLING,
                        client->name, sdev);
                if (rval < 0) {
                        v4l2_err(&sdev->sd, "Could not request IRQ\n");
index 253f307..4b2e9e8 100644 (file)
@@ -175,7 +175,7 @@ static int_handler_prototype int_handler_table[] = {
        fm_irq_handle_intmsk_cmd_resp
 };
 
-long (*g_st_write) (struct sk_buff *skb);
+static long (*g_st_write) (struct sk_buff *skb);
 static struct completion wait_for_fmdrv_reg_comp;
 
 static inline void fm_irq_call(struct fmdev *fmdev)
index 11e84bc..904f113 100644 (file)
@@ -322,4 +322,14 @@ config IR_GPIO_CIR
           To compile this driver as a module, choose M here: the module will
           be called gpio-ir-recv.
 
+config RC_ST
+       tristate "ST remote control receiver"
+       depends on ARCH_STI && RC_CORE
+       help
+        Say Y here if you want support for ST remote control driver
+        which allows both IR and UHF RX.
+        The driver passes raw pulse and space information to the LIRC decoder.
+
+        If you're not sure, select N here.
+
 endif #RC_DEVICES
index 56bacf0..f4eb32c 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
 obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
 obj-$(CONFIG_IR_IGUANA) += iguanair.o
 obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
+obj-$(CONFIG_RC_ST) += st_rc.o
index 07aacfa..80c611c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
index 31b955b..b1e19a2 100644 (file)
@@ -201,8 +201,7 @@ static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
 
        lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
        retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
-                            IRQF_DISABLED | IRQF_SHARED,
-                            "lirc_pulse_timer", lirc_rx51);
+                            IRQF_SHARED, "lirc_pulse_timer", lirc_rx51);
        if (retval) {
                dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
                goto err2;
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
new file mode 100644 (file)
index 0000000..65120c2
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics Limited
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <media/rc-core.h>
+#include <linux/pinctrl/consumer.h>
+
+struct st_rc_device {
+       struct device                   *dev;
+       int                             irq;
+       int                             irq_wake;
+       struct clk                      *sys_clock;
+       void                            *base;  /* Register base address */
+       void                            *rx_base;/* RX Register base address */
+       struct rc_dev                   *rdev;
+       bool                            overclocking;
+       int                             sample_mult;
+       int                             sample_div;
+       bool                            rxuhfmode;
+};
+
+/* Registers */
+#define IRB_SAMPLE_RATE_COMM   0x64    /* sample freq divisor*/
+#define IRB_CLOCK_SEL          0x70    /* clock select       */
+#define IRB_CLOCK_SEL_STATUS   0x74    /* clock status       */
+/* IRB IR/UHF receiver registers */
+#define IRB_RX_ON               0x40   /* pulse time capture */
+#define IRB_RX_SYS              0X44   /* sym period capture */
+#define IRB_RX_INT_EN           0x48   /* IRQ enable (R/W)   */
+#define IRB_RX_INT_STATUS       0x4c   /* IRQ status (R/W)   */
+#define IRB_RX_EN               0x50   /* Receive enable     */
+#define IRB_MAX_SYM_PERIOD      0x54   /* max sym value      */
+#define IRB_RX_INT_CLEAR        0x58   /* overrun status     */
+#define IRB_RX_STATUS           0x6c   /* receive status     */
+#define IRB_RX_NOISE_SUPPR      0x5c   /* noise suppression  */
+#define IRB_RX_POLARITY_INV     0x68   /* polarity inverter  */
+
+/**
+ * IRQ set: Enable full FIFO                 1  -> bit  3;
+ *          Enable overrun IRQ               1  -> bit  2;
+ *          Enable last symbol IRQ           1  -> bit  1:
+ *          Enable RX interrupt              1  -> bit  0;
+ */
+#define IRB_RX_INTS            0x0f
+#define IRB_RX_OVERRUN_INT     0x04
+ /* maximum symbol period (microsecs),timeout to detect end of symbol train */
+#define MAX_SYMB_TIME          0x5000
+#define IRB_SAMPLE_FREQ                10000000
+#define        IRB_FIFO_NOT_EMPTY      0xff00
+#define IRB_OVERFLOW           0x4
+#define IRB_TIMEOUT            0xffff
+#define IR_ST_NAME "st-rc"
+
+static void st_rc_send_lirc_timeout(struct rc_dev *rdev)
+{
+       DEFINE_IR_RAW_EVENT(ev);
+       ev.timeout = true;
+       ir_raw_event_store(rdev, &ev);
+}
+
+/**
+ * RX graphical example to better understand the difference between ST IR block
+ * output and standard definition used by LIRC (and most of the world!)
+ *
+ *           mark                                     mark
+ *      |-IRB_RX_ON-|                            |-IRB_RX_ON-|
+ *      ___  ___  ___                            ___  ___  ___             _
+ *      | |  | |  | |                            | |  | |  | |             |
+ *      | |  | |  | |         space 0            | |  | |  | |   space 1   |
+ * _____| |__| |__| |____________________________| |__| |__| |_____________|
+ *
+ *      |--------------- IRB_RX_SYS -------------|------ IRB_RX_SYS -------|
+ *
+ *      |------------- encoding bit 0 -----------|---- encoding bit 1 -----|
+ *
+ * ST hardware returns mark (IRB_RX_ON) and total symbol time (IRB_RX_SYS), so
+ * convert to standard mark/space we have to calculate space=(IRB_RX_SYS-mark)
+ * The mark time represents the amount of time the carrier (usually 36-40kHz)
+ * is detected.The above examples shows Pulse Width Modulation encoding where
+ * bit 0 is represented by space>mark.
+ */
+
+static irqreturn_t st_rc_rx_interrupt(int irq, void *data)
+{
+       unsigned int symbol, mark = 0;
+       struct st_rc_device *dev = data;
+       int last_symbol = 0;
+       u32 status;
+       DEFINE_IR_RAW_EVENT(ev);
+
+       if (dev->irq_wake)
+               pm_wakeup_event(dev->dev, 0);
+
+       status  = readl(dev->rx_base + IRB_RX_STATUS);
+
+       while (status & (IRB_FIFO_NOT_EMPTY | IRB_OVERFLOW)) {
+               u32 int_status = readl(dev->rx_base + IRB_RX_INT_STATUS);
+               if (unlikely(int_status & IRB_RX_OVERRUN_INT)) {
+                       /* discard the entire collection in case of errors!  */
+                       ir_raw_event_reset(dev->rdev);
+                       dev_info(dev->dev, "IR RX overrun\n");
+                       writel(IRB_RX_OVERRUN_INT,
+                                       dev->rx_base + IRB_RX_INT_CLEAR);
+                       continue;
+               }
+
+               symbol = readl(dev->rx_base + IRB_RX_SYS);
+               mark = readl(dev->rx_base + IRB_RX_ON);
+
+               if (symbol == IRB_TIMEOUT)
+                       last_symbol = 1;
+
+                /* Ignore any noise */
+               if ((mark > 2) && (symbol > 1)) {
+                       symbol -= mark;
+                       if (dev->overclocking) { /* adjustments to timings */
+                               symbol *= dev->sample_mult;
+                               symbol /= dev->sample_div;
+                               mark *= dev->sample_mult;
+                               mark /= dev->sample_div;
+                       }
+
+                       ev.duration = US_TO_NS(mark);
+                       ev.pulse = true;
+                       ir_raw_event_store(dev->rdev, &ev);
+
+                       if (!last_symbol) {
+                               ev.duration = US_TO_NS(symbol);
+                               ev.pulse = false;
+                               ir_raw_event_store(dev->rdev, &ev);
+                       } else  {
+                               st_rc_send_lirc_timeout(dev->rdev);
+                       }
+
+               }
+               last_symbol = 0;
+               status  = readl(dev->rx_base + IRB_RX_STATUS);
+       }
+
+       writel(IRB_RX_INTS, dev->rx_base + IRB_RX_INT_CLEAR);
+
+       /* Empty software fifo */
+       ir_raw_event_handle(dev->rdev);
+       return IRQ_HANDLED;
+}
+
+static void st_rc_hardware_init(struct st_rc_device *dev)
+{
+       int baseclock, freqdiff;
+       unsigned int rx_max_symbol_per = MAX_SYMB_TIME;
+       unsigned int rx_sampling_freq_div;
+
+       clk_prepare_enable(dev->sys_clock);
+       baseclock = clk_get_rate(dev->sys_clock);
+
+       /* IRB input pins are inverted internally from high to low. */
+       writel(1, dev->rx_base + IRB_RX_POLARITY_INV);
+
+       rx_sampling_freq_div = baseclock / IRB_SAMPLE_FREQ;
+       writel(rx_sampling_freq_div, dev->base + IRB_SAMPLE_RATE_COMM);
+
+       freqdiff = baseclock - (rx_sampling_freq_div * IRB_SAMPLE_FREQ);
+       if (freqdiff) { /* over clocking, workout the adjustment factors */
+               dev->overclocking = true;
+               dev->sample_mult = 1000;
+               dev->sample_div = baseclock / (10000 * rx_sampling_freq_div);
+               rx_max_symbol_per = (rx_max_symbol_per * 1000)/dev->sample_div;
+       }
+
+       writel(rx_max_symbol_per, dev->rx_base + IRB_MAX_SYM_PERIOD);
+}
+
+static int st_rc_remove(struct platform_device *pdev)
+{
+       struct st_rc_device *rc_dev = platform_get_drvdata(pdev);
+       clk_disable_unprepare(rc_dev->sys_clock);
+       rc_unregister_device(rc_dev->rdev);
+       return 0;
+}
+
+static int st_rc_open(struct rc_dev *rdev)
+{
+       struct st_rc_device *dev = rdev->priv;
+       unsigned long flags;
+       local_irq_save(flags);
+       /* enable interrupts and receiver */
+       writel(IRB_RX_INTS, dev->rx_base + IRB_RX_INT_EN);
+       writel(0x01, dev->rx_base + IRB_RX_EN);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static void st_rc_close(struct rc_dev *rdev)
+{
+       struct st_rc_device *dev = rdev->priv;
+       /* disable interrupts and receiver */
+       writel(0x00, dev->rx_base + IRB_RX_EN);
+       writel(0x00, dev->rx_base + IRB_RX_INT_EN);
+}
+
+static int st_rc_probe(struct platform_device *pdev)
+{
+       int ret = -EINVAL;
+       struct rc_dev *rdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct st_rc_device *rc_dev;
+       struct device_node *np = pdev->dev.of_node;
+       const char *rx_mode;
+
+       rc_dev = devm_kzalloc(dev, sizeof(struct st_rc_device), GFP_KERNEL);
+
+       if (!rc_dev)
+               return -ENOMEM;
+
+       rdev = rc_allocate_device();
+
+       if (!rdev)
+               return -ENOMEM;
+
+       if (np && !of_property_read_string(np, "rx-mode", &rx_mode)) {
+
+               if (!strcmp(rx_mode, "uhf")) {
+                       rc_dev->rxuhfmode = true;
+               } else if (!strcmp(rx_mode, "infrared")) {
+                       rc_dev->rxuhfmode = false;
+               } else {
+                       dev_err(dev, "Unsupported rx mode [%s]\n", rx_mode);
+                       goto err;
+               }
+
+       } else {
+               goto err;
+       }
+
+       rc_dev->sys_clock = devm_clk_get(dev, NULL);
+       if (IS_ERR(rc_dev->sys_clock)) {
+               dev_err(dev, "System clock not found\n");
+               ret = PTR_ERR(rc_dev->sys_clock);
+               goto err;
+       }
+
+       rc_dev->irq = platform_get_irq(pdev, 0);
+       if (rc_dev->irq < 0) {
+               ret = rc_dev->irq;
+               goto err;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       rc_dev->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(rc_dev->base)) {
+               ret = PTR_ERR(rc_dev->base);
+               goto err;
+       }
+
+       if (rc_dev->rxuhfmode)
+               rc_dev->rx_base = rc_dev->base + 0x40;
+       else
+               rc_dev->rx_base = rc_dev->base;
+
+       rc_dev->dev = dev;
+       platform_set_drvdata(pdev, rc_dev);
+       st_rc_hardware_init(rc_dev);
+
+       rdev->driver_type = RC_DRIVER_IR_RAW;
+       rdev->allowed_protos = RC_BIT_ALL;
+       /* rx sampling rate is 10Mhz */
+       rdev->rx_resolution = 100;
+       rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
+       rdev->priv = rc_dev;
+       rdev->open = st_rc_open;
+       rdev->close = st_rc_close;
+       rdev->driver_name = IR_ST_NAME;
+       rdev->map_name = RC_MAP_LIRC;
+       rdev->input_name = "ST Remote Control Receiver";
+
+       /* enable wake via this device */
+       device_set_wakeup_capable(dev, true);
+       device_set_wakeup_enable(dev, true);
+
+       ret = rc_register_device(rdev);
+       if (ret < 0)
+               goto clkerr;
+
+       rc_dev->rdev = rdev;
+       if (devm_request_irq(dev, rc_dev->irq, st_rc_rx_interrupt,
+                       IRQF_NO_SUSPEND, IR_ST_NAME, rc_dev) < 0) {
+               dev_err(dev, "IRQ %d register failed\n", rc_dev->irq);
+               ret = -EINVAL;
+               goto rcerr;
+       }
+
+       /**
+        * for LIRC_MODE_MODE2 or LIRC_MODE_PULSE or LIRC_MODE_RAW
+        * lircd expects a long space first before a signal train to sync.
+        */
+       st_rc_send_lirc_timeout(rdev);
+
+       dev_info(dev, "setup in %s mode\n", rc_dev->rxuhfmode ? "UHF" : "IR");
+
+       return ret;
+rcerr:
+       rc_unregister_device(rdev);
+       rdev = NULL;
+clkerr:
+       clk_disable_unprepare(rc_dev->sys_clock);
+err:
+       rc_free_device(rdev);
+       dev_err(dev, "Unable to register device (%d)\n", ret);
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int st_rc_suspend(struct device *dev)
+{
+       struct st_rc_device *rc_dev = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               if (!enable_irq_wake(rc_dev->irq))
+                       rc_dev->irq_wake = 1;
+               else
+                       return -EINVAL;
+       } else {
+               pinctrl_pm_select_sleep_state(dev);
+               writel(0x00, rc_dev->rx_base + IRB_RX_EN);
+               writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN);
+               clk_disable_unprepare(rc_dev->sys_clock);
+       }
+
+       return 0;
+}
+
+static int st_rc_resume(struct device *dev)
+{
+       struct st_rc_device *rc_dev = dev_get_drvdata(dev);
+       struct rc_dev   *rdev = rc_dev->rdev;
+
+       if (rc_dev->irq_wake) {
+               disable_irq_wake(rc_dev->irq);
+               rc_dev->irq_wake = 0;
+       } else {
+               pinctrl_pm_select_default_state(dev);
+               st_rc_hardware_init(rc_dev);
+               if (rdev->users) {
+                       writel(IRB_RX_INTS, rc_dev->rx_base + IRB_RX_INT_EN);
+                       writel(0x01, rc_dev->rx_base + IRB_RX_EN);
+               }
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id st_rc_match[] = {
+       { .compatible = "st,comms-irb", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, st_rc_match);
+#endif
+
+static struct platform_driver st_rc_driver = {
+       .driver = {
+               .name = IR_ST_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(st_rc_match),
+#ifdef CONFIG_PM
+               .pm     = &st_rc_pm_ops,
+#endif
+       },
+       .probe = st_rc_probe,
+       .remove = st_rc_remove,
+};
+
+module_platform_driver(st_rc_driver);
+
+MODULE_DESCRIPTION("RC Transceiver driver for STMicroelectronics platforms");
+MODULE_AUTHOR("STMicroelectronics (R&D) Ltd");
+MODULE_LICENSE("GPL");
index 98bd496..904baf4 100644 (file)
@@ -1110,7 +1110,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        }
 
        err = request_irq(data->irq, wbcir_irq_handler,
-                         IRQF_DISABLED, DRVNAME, device);
+                         0, DRVNAME, device);
        if (err) {
                dev_err(dev, "Failed to claim IRQ %u\n", data->irq);
                err = -EBUSY;
index f4d0e79..d74e920 100644 (file)
@@ -139,7 +139,7 @@ static int fc0012_set_params(struct dvb_frontend *fe)
        unsigned char reg[7], am, pm, multi, tmp;
        unsigned long f_vco;
        unsigned short xtal_freq_khz_2, xin, xdiv;
-       int vco_select = false;
+       bool vco_select = false;
 
        if (fe->callback) {
                ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
index bd8f0f1..b416231 100644 (file)
@@ -233,7 +233,7 @@ static int fc0013_set_params(struct dvb_frontend *fe)
        unsigned char reg[7], am, pm, multi, tmp;
        unsigned long f_vco;
        unsigned short xtal_freq_khz_2, xin, xdiv;
-       int vco_select = false;
+       bool vco_select = false;
 
        if (fe->callback) {
                ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
index 1c23666..d9ee43f 100644 (file)
@@ -612,10 +612,19 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type,
 
        vco_fine_tune = (data[4] & 0x30) >> 4;
 
-       if (vco_fine_tune > VCO_POWER_REF)
-               div_num = div_num - 1;
-       else if (vco_fine_tune < VCO_POWER_REF)
-               div_num = div_num + 1;
+       tuner_dbg("mix_div=%d div_num=%d vco_fine_tune=%d\n",
+                       mix_div, div_num, vco_fine_tune);
+
+       /*
+        * XXX: R828D/16MHz seems to have always vco_fine_tune=1.
+        * Due to that, this calculation goes wrong.
+        */
+       if (priv->cfg->rafael_chip != CHIP_R828D) {
+               if (vco_fine_tune > VCO_POWER_REF)
+                       div_num = div_num - 1;
+               else if (vco_fine_tune < VCO_POWER_REF)
+                       div_num = div_num + 1;
+       }
 
        rc = r820t_write_reg_mask(priv, 0x10, div_num << 5, 0xe0);
        if (rc < 0)
@@ -637,11 +646,6 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type,
                vco_fra = pll_ref * 129 / 128;
        }
 
-       if (nint > 63) {
-               tuner_info("No valid PLL values for %u kHz!\n", freq);
-               return -EINVAL;
-       }
-
        ni = (nint - 13) / 4;
        si = nint - 4 * ni - 13;
 
index 878d2c4..e287a74 100644 (file)
@@ -572,7 +572,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                        return -EINVAL;
                }
 
-               size = le16_to_cpu(*(__u16 *) p);
+               size = le16_to_cpu(*(__le16 *) p);
                p += sizeof(size);
 
                if (size == 0xffff)
@@ -683,7 +683,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
                /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
                 * has a 2-byte size header in the firmware format. */
                if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
-                   le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+                   le16_to_cpu(*(__le16 *)(p + 14 * scode)) != 12)
                        return -EINVAL;
                p += 14 * scode + 2;
        }
index 8b6275f..0bd9690 100644 (file)
@@ -390,7 +390,7 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
                }
 
        if (fc_usb->iso_buffer != NULL)
-               pci_free_consistent(NULL,
+               usb_free_coherent(fc_usb->udev,
                        fc_usb->buffer_size, fc_usb->iso_buffer,
                        fc_usb->dma_addr);
 }
@@ -407,8 +407,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
                        "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
                        B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
 
-       fc_usb->iso_buffer = pci_alloc_consistent(NULL,
-                       bufsize, &fc_usb->dma_addr);
+       fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev,
+                       bufsize, GFP_KERNEL, &fc_usb->dma_addr);
        if (fc_usb->iso_buffer == NULL)
                return -ENOMEM;
 
index be17192..351a78a 100644 (file)
@@ -209,7 +209,7 @@ static void cpia2_usb_complete(struct urb *urb)
 {
        int i;
        unsigned char *cdata;
-       static int frame_ready = false;
+       static bool frame_ready = false;
        struct camera_data *cam = (struct camera_data *) urb->context;
 
        if (urb->status!=0) {
index a384f80..e9d017b 100644 (file)
@@ -978,7 +978,6 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
                            int minor)
 {
        int retval = -ENOMEM;
-       int errCode;
        unsigned int maxh, maxw;
 
        dev->udev = udev;
@@ -1014,8 +1013,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        /* Cx231xx pre card setup */
        cx231xx_pre_card_setup(dev);
 
-       errCode = cx231xx_config(dev);
-       if (errCode) {
+       retval = cx231xx_config(dev);
+       if (retval) {
                cx231xx_errdev("error configuring device\n");
                return -ENOMEM;
        }
@@ -1024,12 +1023,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        dev->norm = dev->board.norm;
 
        /* register i2c bus */
-       errCode = cx231xx_dev_init(dev);
-       if (errCode < 0) {
-               cx231xx_dev_uninit(dev);
+       retval = cx231xx_dev_init(dev);
+       if (retval) {
                cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
-                              __func__, errCode);
-               return errCode;
+                              __func__, retval);
+               goto err_dev_init;
        }
 
        /* Do board specific init */
@@ -1047,11 +1045,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        dev->interlaced = 0;
        dev->video_input = 0;
 
-       errCode = cx231xx_config(dev);
-       if (errCode < 0) {
+       retval = cx231xx_config(dev);
+       if (retval) {
                cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n",
-                              __func__, errCode);
-               return errCode;
+                              __func__, retval);
+               goto err_dev_init;
        }
 
        /* init video dma queues */
@@ -1075,9 +1073,9 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        }
 
        retval = cx231xx_register_analog_devices(dev);
-       if (retval < 0) {
-               cx231xx_release_resources(dev);
-               return retval;
+       if (retval) {
+               cx231xx_release_analog_resources(dev);
+               goto err_analog;
        }
 
        cx231xx_ir_init(dev);
@@ -1085,6 +1083,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        cx231xx_init_extension(dev);
 
        return 0;
+err_analog:
+       cx231xx_remove_from_devlist(dev);
+err_dev_init:
+       cx231xx_dev_uninit(dev);
+       return retval;
 }
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
@@ -1132,7 +1135,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        char *speed;
        struct usb_interface_assoc_descriptor *assoc_desc;
 
-       udev = usb_get_dev(interface_to_usbdev(interface));
        ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
        /*
@@ -1161,6 +1163,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                return -ENOMEM;
        }
 
+       udev = usb_get_dev(interface_to_usbdev(interface));
+
        snprintf(dev->name, 29, "cx231xx #%d", nr);
        dev->devno = nr;
        dev->model = id->driver_info;
@@ -1223,10 +1227,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        if (assoc_desc->bFirstInterface != ifnum) {
                cx231xx_err(DRIVER_NAME ": Not found "
                            "matching IAD interface\n");
-               clear_bit(dev->devno, &cx231xx_devused);
-               kfree(dev);
-               dev = NULL;
-               return -ENODEV;
+               retval = -ENODEV;
+               goto err_if;
        }
 
        cx231xx_info("registering interface %d\n", ifnum);
@@ -1242,22 +1244,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
        if (retval) {
                cx231xx_errdev("v4l2_device_register failed\n");
-               clear_bit(dev->devno, &cx231xx_devused);
-               kfree(dev);
-               dev = NULL;
-               return -EIO;
+               retval = -EIO;
+               goto err_v4l2;
        }
        /* allocate device struct */
        retval = cx231xx_init_dev(dev, udev, nr);
-       if (retval) {
-               clear_bit(dev->devno, &cx231xx_devused);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               kfree(dev);
-               dev = NULL;
-               usb_set_intfdata(interface, NULL);
-
-               return retval;
-       }
+       if (retval)
+               goto err_init;
 
        /* compute alternate max packet sizes for video */
        uif = udev->actconfig->interface[dev->current_pcb_config.
@@ -1275,11 +1268,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->video_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               clear_bit(dev->devno, &cx231xx_devused);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               kfree(dev);
-               dev = NULL;
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto err_video_alt;
        }
 
        for (i = 0; i < dev->video_mode.num_alt; i++) {
@@ -1309,11 +1299,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->vbi_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               clear_bit(dev->devno, &cx231xx_devused);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               kfree(dev);
-               dev = NULL;
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto err_vbi_alt;
        }
 
        for (i = 0; i < dev->vbi_mode.num_alt; i++) {
@@ -1344,11 +1331,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               clear_bit(dev->devno, &cx231xx_devused);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               kfree(dev);
-               dev = NULL;
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto err_sliced_cc_alt;
        }
 
        for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
@@ -1380,11 +1364,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
                if (dev->ts1_mode.alt_max_pkt_size == NULL) {
                        cx231xx_errdev("out of memory!\n");
-                       clear_bit(dev->devno, &cx231xx_devused);
-                       v4l2_device_unregister(&dev->v4l2_dev);
-                       kfree(dev);
-                       dev = NULL;
-                       return -ENOMEM;
+                       retval = -ENOMEM;
+                       goto err_ts1_alt;
                }
 
                for (i = 0; i < dev->ts1_mode.num_alt; i++) {
@@ -1411,6 +1392,29 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        request_modules(dev);
 
        return 0;
+err_ts1_alt:
+       kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+err_sliced_cc_alt:
+       kfree(dev->vbi_mode.alt_max_pkt_size);
+err_vbi_alt:
+       kfree(dev->video_mode.alt_max_pkt_size);
+err_video_alt:
+       /* cx231xx_uninit_dev: */
+       cx231xx_close_extension(dev);
+       cx231xx_ir_exit(dev);
+       cx231xx_release_analog_resources(dev);
+       cx231xx_417_unregister(dev);
+       cx231xx_remove_from_devlist(dev);
+       cx231xx_dev_uninit(dev);
+err_init:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2:
+       usb_set_intfdata(interface, NULL);
+err_if:
+       usb_put_dev(udev);
+       kfree(dev);
+       clear_bit(dev->devno, &cx231xx_devused);
+       return retval;
 }
 
 /*
index d7308ab..2a34cee 100644 (file)
@@ -28,7 +28,7 @@ MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]");
 
 /******************************************************************************/
 
-struct pcb_config cx231xx_Scenario[] = {
+static struct pcb_config cx231xx_Scenario[] = {
        {
         INDEX_SELFPOWER_DIGITAL_ONLY,  /* index */
         USB_SELF_POWER,        /* power_type */
@@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev)
        pcb config it is related to */
        cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
 
-       config_info = le32_to_cpu(*((u32 *) data));
+       config_info = le32_to_cpu(*((__le32 *)data));
        usb_speed = (u8) (config_info & 0x1);
 
        /* Verify this device belongs to Bus power or Self power device */
index c0cd084..ecca036 100644 (file)
@@ -377,6 +377,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
        struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
        struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
        struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};
+       struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
 
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
@@ -489,6 +490,15 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
                goto found;
        }
 
+       /* check R828D ID register; reg=00 val=69 */
+       ret = rtl28xxu_ctrl_msg(d, &req_r828d);
+       if (ret == 0 && buf[0] == 0x69) {
+               priv->tuner = TUNER_RTL2832_R828D;
+               priv->tuner_name = "R828D";
+               goto found;
+       }
+
+
 found:
        dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
 
@@ -745,6 +755,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
                rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
                break;
        case TUNER_RTL2832_R820T:
+       case TUNER_RTL2832_R828D:
                rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
                break;
        default:
@@ -866,6 +877,13 @@ static const struct r820t_config rtl2832u_r820t_config = {
        .rafael_chip = CHIP_R820T,
 };
 
+static const struct r820t_config rtl2832u_r828d_config = {
+       .i2c_addr = 0x3a,
+       .xtal = 16000000,
+       .max_i2c_msg_len = 2,
+       .rafael_chip = CHIP_R828D,
+};
+
 static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
@@ -919,6 +937,27 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
                fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
                                &rtl2832u_r820t_config);
 
+               /* Use tuner to get the signal strength */
+               adap->fe[0]->ops.read_signal_strength =
+                               adap->fe[0]->ops.tuner_ops.get_rf_strength;
+               break;
+       case TUNER_RTL2832_R828D:
+               /* power off mn88472 demod on GPIO0 */
+               ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01);
+               if (ret)
+                       goto err;
+
+               ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
+               if (ret)
+                       goto err;
+
+               ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
+               if (ret)
+                       goto err;
+
+               fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+                               &rtl2832u_r828d_config);
+
                /* Use tuner to get the signal strength */
                adap->fe[0]->ops.read_signal_strength =
                                adap->fe[0]->ops.tuner_ops.get_rf_strength;
@@ -1388,6 +1427,9 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
                &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
        { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
                &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
+
+       { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
+               &rtl2832u_props, "Astrometa DVB-T2", NULL) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
index 729b354..2142bcb 100644 (file)
@@ -83,6 +83,7 @@ enum rtl28xxu_tuner {
        TUNER_RTL2832_TDA18272,
        TUNER_RTL2832_FC0013,
        TUNER_RTL2832_R820T,
+       TUNER_RTL2832_R828D,
 };
 
 struct rtl28xxu_req {
index ea2d5ee..c11138e 100644 (file)
@@ -254,7 +254,7 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
 
 
 
-struct stb0899_config az6027_stb0899_config = {
+static struct stb0899_config az6027_stb0899_config = {
        .init_dev               = az6027_stb0899_s1_init_1,
        .init_s2_demod          = stb0899_s2_init_2,
        .init_s1_demod          = az6027_stb0899_s1_init_3,
@@ -291,7 +291,7 @@ struct stb0899_config az6027_stb0899_config = {
        .tuner_set_rfsiggain    = NULL,
 };
 
-struct stb6100_config az6027_stb6100_config = {
+static struct stb6100_config az6027_stb6100_config = {
        .tuner_address  = 0xc0,
        .refclock       = 27000000,
 };
index 6e237b6..6136a2c 100644 (file)
@@ -955,9 +955,10 @@ static struct ds3000_config dw2104_ds3000_config = {
        .demod_address = 0x68,
 };
 
-static struct ts2020_config dw2104_ts2020_config  = {
+static struct ts2020_config dw2104_ts2020_config = {
        .tuner_address = 0x60,
        .clk_out_div = 1,
+       .frequency_div = 1060000,
 };
 
 static struct ds3000_config s660_ds3000_config = {
@@ -966,6 +967,12 @@ static struct ds3000_config s660_ds3000_config = {
        .set_lock_led = dw210x_led_ctrl,
 };
 
+static struct ts2020_config s660_ts2020_config = {
+       .tuner_address = 0x60,
+       .clk_out_div = 1,
+       .frequency_div = 1146000,
+};
+
 static struct stv0900_config dw2104a_stv0900_config = {
        .demod_address = 0x6a,
        .demod_mode = 0,
@@ -1205,7 +1212,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
        if (d->fe_adap[0].fe == NULL)
                return -EIO;
 
-       dvb_attach(ts2020_attach, d->fe_adap[0].fe, &dw2104_ts2020_config,
+       dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config,
                &d->dev->i2c_adap);
 
        st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
@@ -1213,7 +1220,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
 
        dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
 
-       info("Attached ds3000+ds2020!\n");
+       info("Attached ds3000+ts2020!\n");
 
        return 0;
 }
index 73cc50a..d666741 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/i2c.h>
 #include <media/soc_camera.h>
 #include <media/mt9v011.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
@@ -47,6 +48,7 @@ static struct soc_camera_link camlink = {
        .bus_id = 0,
        .flags = 0,
        .module_name = "em28xx",
+       .unbalanced_power = true,
 };
 
 
@@ -325,13 +327,24 @@ int em28xx_detect_sensor(struct em28xx *dev)
 
 int em28xx_init_camera(struct em28xx *dev)
 {
+       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
+       struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
+       int ret = 0;
+
+       v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+                         i2c_adapter_id(adap), client->addr);
+       dev->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
+       if (IS_ERR(dev->clk))
+               return PTR_ERR(dev->clk);
+
        switch (dev->em28xx_sensor) {
        case EM28XX_MT9V011:
        {
                struct mt9v011_platform_data pdata;
                struct i2c_board_info mt9v011_info = {
                        .type = "mt9v011",
-                       .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+                       .addr = client->addr,
                        .platform_data = &pdata,
                };
 
@@ -352,10 +365,11 @@ int em28xx_init_camera(struct em28xx *dev)
                dev->sensor_xtal = 4300000;
                pdata.xtal = dev->sensor_xtal;
                if (NULL ==
-                   v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
-                                             &dev->i2c_adap[dev->def_i2c_bus],
-                                             &mt9v011_info, NULL))
-                       return -ENODEV;
+                   v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
+                                             &mt9v011_info, NULL)) {
+                       ret = -ENODEV;
+                       break;
+               }
                /* probably means GRGB 16 bit bayer */
                dev->vinmode = 0x0d;
                dev->vinctl = 0x00;
@@ -391,7 +405,7 @@ int em28xx_init_camera(struct em28xx *dev)
                struct i2c_board_info ov2640_info = {
                        .type = "ov2640",
                        .flags = I2C_CLIENT_SCCB,
-                       .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+                       .addr = client->addr,
                        .platform_data = &camlink,
                };
                struct v4l2_mbus_framefmt fmt;
@@ -408,9 +422,12 @@ int em28xx_init_camera(struct em28xx *dev)
                dev->sensor_yres = 480;
 
                subdev =
-                    v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
-                                              &dev->i2c_adap[dev->def_i2c_bus],
+                    v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
                                               &ov2640_info, NULL);
+               if (NULL == subdev) {
+                       ret = -ENODEV;
+                       break;
+               }
 
                fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
                fmt.width = 640;
@@ -427,8 +444,13 @@ int em28xx_init_camera(struct em28xx *dev)
        }
        case EM28XX_NOSENSOR:
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
 
-       return 0;
+       if (ret < 0) {
+               v4l2_clk_unregister_fixed(dev->clk);
+               dev->clk = NULL;
+       }
+
+       return ret;
 }
index dc65742..a519669 100644 (file)
@@ -36,6 +36,7 @@
 #include <media/tvaudio.h>
 #include <media/i2c-addr.h>
 #include <media/tveeprom.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
@@ -95,8 +96,8 @@ static struct em28xx_reg_seq default_digital[] = {
 /* Board Hauppauge WinTV HVR 900 analog */
 static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
        {EM2820_R08_GPIO_CTRL,  0x2d,   ~EM_GPIO_4,     10},
-       {0x05,                  0xff,   0x10,           10},
-       {  -1,                  -1,     -1,             -1},
+       {       0x05,           0xff,   0x10,           10},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Board Hauppauge WinTV HVR 900 digital */
@@ -104,20 +105,20 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x2e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x04,   0x0f,           10},
        {EM2880_R04_GPO,        0x0c,   0x0f,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Board Hauppauge WinTV HVR 900 (R2) digital */
 static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x2e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x0c,   0x0f,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
 static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
-       {EM2820_R08_GPIO_CTRL,       0x69,   ~EM_GPIO_4,         10},
-       {       -1,             -1,     -1,              -1},
+       {EM2820_R08_GPIO_CTRL,  0x69,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
@@ -132,7 +133,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
        {EM2880_R04_GPO,        0x04,   0xff,           10},
        {EM2880_R04_GPO,        0x0c,   0xff,           10},
        {EM2820_R08_GPIO_CTRL,  0x7e,   0xff,           10},
-       {  -1,                  -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
@@ -140,19 +141,19 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
        {EM2880_R04_GPO,        0x0c,   0xff,           10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
        {EM2880_R04_GPO,        0x0c,   0xff,           10},
-       {  -1,                  -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq kworld_330u_analog[] = {
        {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq kworld_330u_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Evga inDtube
@@ -170,11 +171,11 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x7a,   0xff,            1},
        {EM2880_R04_GPO,        0x04,   0xff,           10},
        {EM2880_R04_GPO,        0x0c,   0xff,            1},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /*
- * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * KWorld PlusTV 340U, UB435-Q and UB435-Q V2 (ATSC) GPIOs map:
  * EM_GPIO_0 - currently unknown
  * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
  * EM_GPIO_2 - currently unknown
@@ -185,8 +186,8 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
  * EM_GPIO_7 - currently unknown
  */
 static struct em28xx_reg_seq kworld_a340_digital[] = {
-       {EM2820_R08_GPIO_CTRL,  0x6d,           ~EM_GPIO_4,     10},
-       { -1,                   -1,             -1,             -1},
+       {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Pinnacle Hybrid Pro eb1a:2881 */
@@ -205,13 +206,13 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
 static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
        {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* eb1a:2868 Reddo DVB-C USB TV Box
@@ -225,7 +226,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
        {EM2820_R08_GPIO_CTRL,  0x7f,   0xff,           10},
        {EM2820_R08_GPIO_CTRL,  0x6f,   0xff,           10},
        {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
-       {-1,                    -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 /* Callback for the most boards */
@@ -233,23 +234,23 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
        {EM2820_R08_GPIO_CTRL,  EM_GPIO_4,      EM_GPIO_4,      10},
        {EM2820_R08_GPIO_CTRL,  0,              EM_GPIO_4,      10},
        {EM2820_R08_GPIO_CTRL,  EM_GPIO_4,      EM_GPIO_4,      10},
-       {  -1,                  -1,             -1,             -1},
+       {       -1,             -1,             -1,             -1},
 };
 
 /* Mute/unmute */
 static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
-       {EM2820_R08_GPIO_CTRL,  5,              7,              10},
-       {  -1,                  -1,             -1,             -1},
+       {EM2820_R08_GPIO_CTRL,  5,      7,      10},
+       {       -1,             -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
-       {EM2820_R08_GPIO_CTRL,  4,              7,              10},
-       {  -1,                  -1,             -1,             -1},
+       {EM2820_R08_GPIO_CTRL,  4,      7,      10},
+       {       -1,             -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq compro_mute_gpio[] = {
-       {EM2820_R08_GPIO_CTRL,  6,              7,              10},
-       {  -1,                  -1,             -1,             -1},
+       {EM2820_R08_GPIO_CTRL,  6,      7,      10},
+       {       -1,             -1,     -1,     -1},
 };
 
 /* Terratec AV350 */
@@ -279,21 +280,21 @@ static struct em28xx_reg_seq vc211a_enable[] = {
 static struct em28xx_reg_seq dikom_dk300_digital[] = {
        {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
-       { -1,                   -1,     -1,             -1},
+       {       -1,             -1,     -1,             -1},
 };
 
 
 /* Reset for the most [digital] boards */
 static struct em28xx_reg_seq leadership_digital[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0x70,   0xff,   10},
-       {       -1,             -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq leadership_reset[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0xf0,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xb0,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xf0,   0xff,   10},
-       {       -1,             -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 /* 2013:024f PCTV nanoStick T2 290e
@@ -304,7 +305,7 @@ static struct em28xx_reg_seq pctv_290e[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0x00,   0xff,   80},
        {EM2874_R80_GPIO_P0_CTRL,       0x40,   0xff,   80}, /* GPIO_6 = 1 */
        {EM2874_R80_GPIO_P0_CTRL,       0xc0,   0xff,   80}, /* GPIO_7 = 1 */
-       {-1,                    -1,     -1,             -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 #if 0
@@ -313,14 +314,14 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
        {EM2874_R80_GPIO_P0_CTRL,       0xf2,   0xff,   50},
        {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   50},
-       { -1,                   -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq terratec_h5_digital[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
        {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   10},
-       { -1,                   -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 #endif
 
@@ -335,12 +336,12 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
  * GPIO_7 - LED (green LED)
  */
 static struct em28xx_reg_seq pctv_460e[] = {
-       {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff,  50},
-       {0x0d,            0xff, 0xff,  50},
-       {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff,  50}, /* GPIO_6=1 */
-       {0x0d,            0x42, 0xff,  50},
-       {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff,  50}, /* GPIO_5=1 */
-       {             -1,   -1,   -1,  -1},
+       {EM2874_R80_GPIO_P0_CTRL,       0x01,   0xff,   50},
+       {       0x0d,                   0xff,   0xff,   50},
+       {EM2874_R80_GPIO_P0_CTRL,       0x41,   0xff,   50}, /* GPIO_6=1 */
+       {       0x0d,                   0x42,   0xff,   50},
+       {EM2874_R80_GPIO_P0_CTRL,       0x61,   0xff,   50}, /* GPIO_5=1 */
+       {       -1,                     -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
@@ -352,7 +353,7 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0xfe,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xbe,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xfe,   0xff,   20},
-       { -1,                   -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 #if 0
@@ -361,14 +362,14 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0x4f,   0xff,   10}, /* xc5000 reset */
        {EM2874_R80_GPIO_P0_CTRL,       0x6f,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0x4f,   0xff,   10},
-       { -1,                   -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq hauppauge_930c_digital[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   10},
        {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
        {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   10},
-       { -1,                   -1,     -1,     -1},
+       {       -1,                     -1,     -1,     -1},
 };
 #endif
 
@@ -378,10 +379,10 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = {
  * GPIO_7 - LED, 0=active
  */
 static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
-       {EM2874_R80_GPIO_P0_CTRL,  0x83,  0xff,  100},
-       {EM2874_R80_GPIO_P0_CTRL,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
-       {EM2874_R80_GPIO_P0_CTRL,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
-       {-1,                 -1,    -1,   -1},
+       {EM2874_R80_GPIO_P0_CTRL,       0x83,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0xc3,   0xff,   100}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0x43,   0xff,   000}, /* GPIO_7 = 0 */
+       {       -1,                     -1,     -1,     -1},
 };
 
 /* 2304:0242 PCTV QuatroStick (510e)
@@ -391,10 +392,10 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
  * GPIO_7: LED, 1=active
  */
 static struct em28xx_reg_seq pctv_510e[] = {
-       {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
-       {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
-       {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
-       {             -1,   -1,   -1,  -1},
+       {EM2874_R80_GPIO_P0_CTRL,       0x10,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0x14,   0xff,   100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0x54,   0xff,   050}, /* GPIO_6 = 1 */
+       {       -1,                     -1,     -1,     -1},
 };
 
 /* 2013:0251 PCTV QuatroStick nano (520e)
@@ -404,11 +405,11 @@ static struct em28xx_reg_seq pctv_510e[] = {
  * GPIO_7: LED, 1=active
  */
 static struct em28xx_reg_seq pctv_520e[] = {
-       {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
-       {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
-       {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
-       {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
-       {             -1,   -1,   -1,  -1},
+       {EM2874_R80_GPIO_P0_CTRL,       0x10,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0x14,   0xff,   100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0x54,   0xff,   050}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0xd4,   0xff,   000}, /* GPIO_7 = 1 */
+       {       -1,                     -1,     -1,     -1},
 };
 
 /*
@@ -2030,6 +2031,18 @@ struct em28xx_board em28xx_boards[] = {
                .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE |
                                EM28XX_I2C_FREQ_400_KHZ,
        },
+       /*
+        * 1b80:e346 KWorld USB ATSC TV Stick UB435-Q V2
+        * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2
+        */
+       [EM2874_BOARD_KWORLD_UB435Q_V2] = {
+               .name           = "KWorld USB ATSC TV Stick UB435-Q V2",
+               .tuner_type     = TUNER_ABSENT,
+               .has_dvb        = 1,
+               .dvb_gpio       = kworld_a340_digital,
+               .tuner_gpio     = default_tuner_gpio,
+               .def_i2c_bus    = 1,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -2173,6 +2186,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2860_BOARD_GADMEI_UTV330 },
        { USB_DEVICE(0x1b80, 0xa340),
                        .driver_info = EM2870_BOARD_KWORLD_A340 },
+       { USB_DEVICE(0x1b80, 0xe346),
+                       .driver_info = EM2874_BOARD_KWORLD_UB435Q_V2 },
        { USB_DEVICE(0x2013, 0x024f),
                        .driver_info = EM28174_BOARD_PCTV_290E },
        { USB_DEVICE(0x2013, 0x024c),
@@ -2857,6 +2872,8 @@ void em28xx_release_resources(struct em28xx *dev)
        if (dev->def_i2c_bus)
                em28xx_i2c_unregister(dev, 1);
        em28xx_i2c_unregister(dev, 0);
+       if (dev->clk)
+               v4l2_clk_unregister_fixed(dev->clk);
 
        v4l2_ctrl_handler_free(&dev->ctrl_handler);
 
index bb1e8dc..344042b 100644 (file)
@@ -298,6 +298,18 @@ static struct lgdt3305_config em2870_lgdt3304_dev = {
        .qam_if_khz         = 4000,
 };
 
+static struct lgdt3305_config em2874_lgdt3305_dev = {
+       .i2c_addr           = 0x0e,
+       .demod_chip         = LGDT3305,
+       .spectral_inversion = 1,
+       .deny_i2c_rptr      = 0,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .vsb_if_khz         = 3250,
+       .qam_if_khz         = 4000,
+};
+
 static struct s921_config sharp_isdbt = {
        .demod_address = 0x30 >> 1
 };
@@ -329,6 +341,11 @@ static struct tda18271_config kworld_a340_config = {
        .std_map           = &kworld_a340_std_map,
 };
 
+static struct tda18271_config kworld_ub435q_v2_config = {
+       .std_map        = &kworld_a340_std_map,
+       .gate           = TDA18271_GATE_DIGITAL,
+};
+
 static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
@@ -384,7 +401,10 @@ static struct drxk_config maxmedia_ub425_tc_drxk = {
        .adr = 0x29,
        .single_master = 1,
        .no_i2c_bridge = 1,
+       .microcode_name = "dvb-demod-drxk-01.fw",
+       .chunk_size = 62,
        .load_firmware_sync = true,
+       .qam_demod_parameter_count = 2,
 };
 
 static struct drxk_config pctv_520e_drxk = {
@@ -424,7 +444,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
                {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   0x65},
                {EM2874_R80_GPIO_P0_CTRL,       0xfb,   0xff,   0x32},
                {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   0xb8},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
        struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
                {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x01},
@@ -439,7 +459,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
                {EM2874_R80_GPIO_P0_CTRL,       0xcf,   0xff,   0x0b},
                {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x65},
 
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
 
        struct {
@@ -491,13 +511,13 @@ static void terratec_h5_init(struct em28xx *dev)
                {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xf2,   0xff,   50},
                {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_h5_end[] = {
                {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   50},
                {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
        struct {
                unsigned char r[4];
@@ -547,12 +567,12 @@ static void terratec_htc_stick_init(struct em28xx *dev)
                {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   50},
                {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_htc_stick_end[] = {
                {EM2874_R80_GPIO_P0_CTRL,       0xb6,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   50},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
 
        /*
@@ -594,13 +614,13 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
                {EM2874_R80_GPIO_P0_CTRL,       0xb2,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xb2,   0xff,   50},
                {EM2874_R80_GPIO_P0_CTRL,       0xb6,   0xff,   100},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_htc_usb_xs_end[] = {
                {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   100},
                {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   50},
                {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
-               { -1,                   -1,     -1,     -1},
+               {       -1,                     -1,     -1,     -1},
        };
 
        /*
@@ -1227,18 +1247,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
 
                        /* attach tuner */
-                       if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
-                                       &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
+                       if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+                                       &dev->i2c_adap[dev->def_i2c_bus],
+                                       &em28xx_cxd2820r_tda18271_config)) {
                                dvb_frontend_detach(dvb->fe[0]);
                                result = -EINVAL;
                                goto out_free;
                        }
                }
-
-               /* TODO: we need drx-3913k firmware in order to support DVB-T */
-               em28xx_info("MaxMedia UB425-TC/Delock 61959: only DVB-C " \
-                               "supported by that driver version\n");
-
                break;
        case EM2884_BOARD_PCTV_510E:
        case EM2884_BOARD_PCTV_520E:
@@ -1297,6 +1313,23 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2874_BOARD_KWORLD_UB435Q_V2:
+               dvb->fe[0] = dvb_attach(lgdt3305_attach,
+                                       &em2874_lgdt3305_dev,
+                                       &dev->i2c_adap[dev->def_i2c_bus]);
+               if (!dvb->fe[0]) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* Attach the demodulator. */
+               if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+                               &dev->i2c_adap[dev->def_i2c_bus],
+                               &kworld_ub435q_v2_config)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
index 9d10334..fc5d60e 100644 (file)
@@ -638,7 +638,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
        if (rc)
                return rc;
 
-       if (dev->streaming_users++ == 0) {
+       if (dev->streaming_users == 0) {
                /* First active streaming user, so allocate all the URBs */
 
                /* Allocate the USB bandwidth */
@@ -657,7 +657,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
                                          dev->packet_multiplier,
                                          em28xx_urb_data_copy);
                if (rc < 0)
-                       goto fail;
+                       return rc;
 
                /*
                 * djh: it's not clear whether this code is still needed.  I'm
@@ -675,7 +675,8 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
                v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
        }
 
-fail:
+       dev->streaming_users++;
+
        return rc;
 }
 
index 205e903..f8726ad 100644 (file)
 #define EM2884_BOARD_TERRATEC_HTC_USB_XS         87
 #define EM2884_BOARD_C3TECH_DIGITAL_DUO                  88
 #define EM2874_BOARD_DELOCK_61959                89
+#define EM2874_BOARD_KWORLD_UB435Q_V2            90
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -492,6 +493,7 @@ struct em28xx {
 
        struct v4l2_device v4l2_dev;
        struct v4l2_ctrl_handler ctrl_handler;
+       struct v4l2_clk *clk;
        struct em28xx_board board;
 
        /* Webcam specific fields */
index 38714df..2e15c80 100644 (file)
@@ -783,7 +783,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 
index 064b530..f23df4a 100644 (file)
@@ -1553,9 +1553,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
                sd->params.format.videoSize = VIDEOSIZE_CIF;
 
        sd->params.roi.colEnd = sd->params.roi.colStart +
-                               (gspca_dev->width >> 3);
+                               (gspca_dev->pixfmt.width >> 3);
        sd->params.roi.rowEnd = sd->params.roi.rowStart +
-                               (gspca_dev->height >> 2);
+                               (gspca_dev->pixfmt.height >> 2);
 
        /* And now set the camera to a known state */
        ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,
index 048507b..f3a7ace 100644 (file)
@@ -504,8 +504,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
        unsigned int frsz;
        int i;
 
-       i = gspca_dev->curr_mode;
-       frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+       frsz = gspca_dev->pixfmt.sizeimage;
        PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
        frsz = PAGE_ALIGN(frsz);
        if (count >= GSPCA_MAX_FRAMES)
@@ -627,16 +626,14 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
 static u32 which_bandwidth(struct gspca_dev *gspca_dev)
 {
        u32 bandwidth;
-       int i;
 
        /* get the (max) image size */
-       i = gspca_dev->curr_mode;
-       bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
+       bandwidth = gspca_dev->pixfmt.sizeimage;
 
        /* if the image is compressed, estimate its mean size */
        if (!gspca_dev->cam.needs_full_bandwidth &&
-           bandwidth < gspca_dev->cam.cam_mode[i].width *
-                               gspca_dev->cam.cam_mode[i].height)
+           bandwidth < gspca_dev->pixfmt.width *
+                               gspca_dev->pixfmt.height)
                bandwidth = bandwidth * 3 / 8;  /* 0.375 */
 
        /* estimate the frame rate */
@@ -650,7 +647,7 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev)
 
                /* don't hope more than 15 fps with USB 1.1 and
                 * image resolution >= 640x480 */
-               if (gspca_dev->width >= 640
+               if (gspca_dev->pixfmt.width >= 640
                 && gspca_dev->dev->speed == USB_SPEED_FULL)
                        bandwidth *= 15;                /* 15 fps */
                else
@@ -982,9 +979,7 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
 
        i = gspca_dev->cam.nmodes - 1;  /* take the highest mode */
        gspca_dev->curr_mode = i;
-       gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
-       gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
-       gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+       gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i];
 
        /* does nothing if ctrl_handler == NULL */
        v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
@@ -1105,10 +1100,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                            struct v4l2_format *fmt)
 {
        struct gspca_dev *gspca_dev = video_drvdata(file);
-       int mode;
 
-       mode = gspca_dev->curr_mode;
-       fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+       fmt->fmt.pix = gspca_dev->pixfmt;
        /* some drivers use priv internally, zero it before giving it to
           userspace */
        fmt->fmt.pix.priv = 0;
@@ -1140,6 +1133,12 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
                        mode = mode2;
        }
        fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+       if (gspca_dev->sd_desc->try_fmt) {
+               /* pass original resolution to subdriver try_fmt */
+               fmt->fmt.pix.width = w;
+               fmt->fmt.pix.height = h;
+               gspca_dev->sd_desc->try_fmt(gspca_dev, fmt);
+       }
        /* some drivers use priv internally, zero it before giving it to
           userspace */
        fmt->fmt.pix.priv = 0;
@@ -1178,19 +1177,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       if (ret == gspca_dev->curr_mode) {
-               ret = 0;
-               goto out;                       /* same mode */
-       }
-
        if (gspca_dev->streaming) {
                ret = -EBUSY;
                goto out;
        }
-       gspca_dev->width = fmt->fmt.pix.width;
-       gspca_dev->height = fmt->fmt.pix.height;
-       gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
        gspca_dev->curr_mode = ret;
+       if (gspca_dev->sd_desc->try_fmt)
+               /* subdriver try_fmt can modify format parameters */
+               gspca_dev->pixfmt = fmt->fmt.pix;
+       else
+               gspca_dev->pixfmt = gspca_dev->cam.cam_mode[ret];
 
        ret = 0;
 out:
@@ -1205,6 +1201,9 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
        int i;
        __u32 index = 0;
 
+       if (gspca_dev->sd_desc->enum_framesizes)
+               return gspca_dev->sd_desc->enum_framesizes(gspca_dev, fsize);
+
        for (i = 0; i < gspca_dev->cam.nmodes; i++) {
                if (fsize->pixel_format !=
                                gspca_dev->cam.cam_mode[i].pixelformat)
@@ -1471,8 +1470,9 @@ static int vidioc_streamon(struct file *file, void *priv,
                if (ret < 0)
                        goto out;
        }
-       PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt,
-                   gspca_dev->width, gspca_dev->height);
+       PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK",
+                   gspca_dev->pixfmt.pixelformat,
+                   gspca_dev->pixfmt.width, gspca_dev->pixfmt.height);
        ret = 0;
 out:
        mutex_unlock(&gspca_dev->queue_lock);
index ac0b11f..300642d 100644 (file)
@@ -88,6 +88,10 @@ typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
 typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev,
                                u8 *data,
                                int len);
+typedef void (*cam_format_op) (struct gspca_dev *gspca_dev,
+                               struct v4l2_format *fmt);
+typedef int (*cam_frmsize_op) (struct gspca_dev *gspca_dev,
+                               struct v4l2_frmsizeenum *fsize);
 
 /* subdriver description */
 struct sd_desc {
@@ -109,6 +113,8 @@ struct sd_desc {
        cam_set_jpg_op set_jcomp;
        cam_streamparm_op get_streamparm;
        cam_streamparm_op set_streamparm;
+       cam_format_op try_fmt;
+       cam_frmsize_op enum_framesizes;
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        cam_set_reg_op set_register;
        cam_get_reg_op get_register;
@@ -183,9 +189,7 @@ struct gspca_dev {
        __u8 streaming;                 /* protected by both mutexes (*) */
 
        __u8 curr_mode;                 /* current camera mode */
-       __u32 pixfmt;                   /* current mode parameters */
-       __u16 width;
-       __u16 height;
+       struct v4l2_pix_format pixfmt;  /* current mode parameters */
        __u32 sequence;                 /* frame sequence number */
 
        wait_queue_head_t wq;           /* wait queue */
index 8da3dde..19736e2 100644 (file)
@@ -378,11 +378,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *dev = (struct sd *) gspca_dev;
 
        /* create the JPEG header */
-       jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(dev->jpeg_hdr, dev->quality);
        PDEBUG(D_STREAM, "Start streaming at %dx%d",
-               gspca_dev->height, gspca_dev->width);
+               gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
        jlj_start(gspca_dev);
        return gspca_dev->usb_err;
 }
index fdaeeb1..5b481fa 100644 (file)
@@ -455,7 +455,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        sd->cap_mode = gspca_dev->cam.cam_mode;
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 640:
                PDEBUG(D_STREAM, "Start streaming at vga resolution");
                jl2005c_stream_start_vga_lg(gspca_dev);
index cfa4663..27fcef1 100644 (file)
@@ -266,7 +266,7 @@ static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
                return err;
 
        data[0] = MT9M111_RMB_OVER_SIZED;
-       if (gspca_dev->width == 640) {
+       if (gspca_dev->pixfmt.width == 640) {
                data[1] = MT9M111_RMB_ROW_SKIP_2X |
                          MT9M111_RMB_COLUMN_SKIP_2X |
                          (hflip << 1) | vflip;
index ff2c5ab..779a878 100644 (file)
@@ -254,7 +254,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int i;
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 
@@ -270,8 +271,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;         /* address */
        data[1] = 0x0c | 0x01;  /* reg 0 */
        data[2] = 0x01;         /* reg 1 */
-       data[3] = gspca_dev->width / 8;         /* h_size , reg 2 */
-       data[4] = gspca_dev->height / 8;        /* v_size , reg 3 */
+       data[3] = gspca_dev->pixfmt.width / 8;  /* h_size , reg 2 */
+       data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
        data[6] = 0x02;         /* reg 5, H start - was 0x04 */
index 68bb2f3..f006e29 100644 (file)
@@ -521,7 +521,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
        if (sd->sensor_type)
                data[5] = 0xbb;
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                data[9] |= 0x04;  /* reg 8, 2:1 scale down from 320 */
                /* fall thru */
@@ -618,7 +618,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
                data[10] = 0x18;
        }
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                data[9] |= 0x0c;  /* reg 8, 4:1 scale down */
                /* fall thru */
@@ -847,7 +847,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv)
                u8 clockdiv = (60 * expo + 7999) / 8000;
 
                /* Limit framerate to not exceed usb bandwidth */
-               if (clockdiv < min_clockdiv && gspca_dev->width >= 320)
+               if (clockdiv < min_clockdiv && gspca_dev->pixfmt.width >= 320)
                        clockdiv = min_clockdiv;
                else if (clockdiv < 2)
                        clockdiv = 2;
index 44c9964..599f755 100644 (file)
@@ -1708,7 +1708,7 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val)
 
        reg_r(gspca_dev, 0x1004, 1);
        if (gspca_dev->usb_buf[0] & 0x04) {     /* if AE_FULL_FRM */
-               sd->ae_res = gspca_dev->width * gspca_dev->height;
+               sd->ae_res = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
        } else {                                /* get the AE window size */
                reg_r(gspca_dev, 0x1011, 8);
                w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]
@@ -1717,7 +1717,8 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val)
                  - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6];
                sd->ae_res = h * w;
                if (sd->ae_res == 0)
-                       sd->ae_res = gspca_dev->width * gspca_dev->height;
+                       sd->ae_res = gspca_dev->pixfmt.width *
+                                       gspca_dev->pixfmt.height;
        }
 }
 
@@ -1856,21 +1857,21 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w_buf(gspca_dev, cmd);
        switch (sd->webcam) {
        case P35u:
-               if (gspca_dev->width == 320)
+               if (gspca_dev->pixfmt.width == 320)
                        reg_w_buf(gspca_dev, nw801_start_qvga);
                else
                        reg_w_buf(gspca_dev, nw801_start_vga);
                reg_w_buf(gspca_dev, nw801_start_2);
                break;
        case Kr651us:
-               if (gspca_dev->width == 320)
+               if (gspca_dev->pixfmt.width == 320)
                        reg_w_buf(gspca_dev, kr651_start_qvga);
                else
                        reg_w_buf(gspca_dev, kr651_start_vga);
                reg_w_buf(gspca_dev, kr651_start_2);
                break;
        case Proscope:
-               if (gspca_dev->width == 320)
+               if (gspca_dev->pixfmt.width == 320)
                        reg_w_buf(gspca_dev, proscope_start_qvga);
                else
                        reg_w_buf(gspca_dev, proscope_start_vga);
index 8937d79..c95f32a 100644 (file)
@@ -3468,7 +3468,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
 
        switch (sd->bridge) {
        case BRIDGE_OVFX2:
-               if (gspca_dev->width != 800)
+               if (gspca_dev->pixfmt.width != 800)
                        gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE;
                else
                        gspca_dev->cam.bulk_size = 7 * 4096;
@@ -3507,8 +3507,8 @@ static void ov511_mode_init_regs(struct sd *sd)
        /* Here I'm assuming that snapshot size == image size.
         * I hope that's always true. --claudio
         */
-       hsegs = (sd->gspca_dev.width >> 3) - 1;
-       vsegs = (sd->gspca_dev.height >> 3) - 1;
+       hsegs = (sd->gspca_dev.pixfmt.width >> 3) - 1;
+       vsegs = (sd->gspca_dev.pixfmt.height >> 3) - 1;
 
        reg_w(sd, R511_CAM_PXCNT, hsegs);
        reg_w(sd, R511_CAM_LNCNT, vsegs);
@@ -3541,7 +3541,7 @@ static void ov511_mode_init_regs(struct sd *sd)
        case SEN_OV7640:
        case SEN_OV7648:
        case SEN_OV76BE:
-               if (sd->gspca_dev.width == 320)
+               if (sd->gspca_dev.pixfmt.width == 320)
                        interlaced = 1;
                /* Fall through */
        case SEN_OV6630:
@@ -3551,7 +3551,7 @@ static void ov511_mode_init_regs(struct sd *sd)
                case 30:
                case 25:
                        /* Not enough bandwidth to do 640x480 @ 30 fps */
-                       if (sd->gspca_dev.width != 640) {
+                       if (sd->gspca_dev.pixfmt.width != 640) {
                                sd->clockdiv = 0;
                                break;
                        }
@@ -3584,7 +3584,8 @@ static void ov511_mode_init_regs(struct sd *sd)
 
        /* Check if we have enough bandwidth to disable compression */
        fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
-       needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
+       needed = fps * sd->gspca_dev.pixfmt.width *
+                       sd->gspca_dev.pixfmt.height * 3 / 2;
        /* 1000 isoc packets/sec */
        if (needed > 1000 * packet_size) {
                /* Enable Y and UV quantization and compression */
@@ -3646,8 +3647,8 @@ static void ov518_mode_init_regs(struct sd *sd)
                reg_w(sd, 0x38, 0x80);
        }
 
-       hsegs = sd->gspca_dev.width / 16;
-       vsegs = sd->gspca_dev.height / 4;
+       hsegs = sd->gspca_dev.pixfmt.width / 16;
+       vsegs = sd->gspca_dev.pixfmt.height / 4;
 
        reg_w(sd, 0x29, hsegs);
        reg_w(sd, 0x2a, vsegs);
@@ -3686,7 +3687,8 @@ static void ov518_mode_init_regs(struct sd *sd)
                         * happened to be with revision < 2 cams using an
                         * OV7620 and revision 2 cams using an OV7620AE.
                         */
-                       if (sd->revision > 0 && sd->gspca_dev.width == 640) {
+                       if (sd->revision > 0 &&
+                                       sd->gspca_dev.pixfmt.width == 640) {
                                reg_w(sd, 0x20, 0x60);
                                reg_w(sd, 0x21, 0x1f);
                        } else {
@@ -3812,8 +3814,8 @@ static void ov519_mode_init_regs(struct sd *sd)
                break;
        }
 
-       reg_w(sd, OV519_R10_H_SIZE,     sd->gspca_dev.width >> 4);
-       reg_w(sd, OV519_R11_V_SIZE,     sd->gspca_dev.height >> 3);
+       reg_w(sd, OV519_R10_H_SIZE,     sd->gspca_dev.pixfmt.width >> 4);
+       reg_w(sd, OV519_R11_V_SIZE,     sd->gspca_dev.pixfmt.height >> 3);
        if (sd->sensor == SEN_OV7670 &&
            sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
                reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
@@ -3947,14 +3949,16 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
            }
        case SEN_OV3610:
                if (qvga) {
-                       xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
-                       ystart = (776 - gspca_dev->height) / 2;
+                       xstart = (1040 - gspca_dev->pixfmt.width) / 2 +
+                               (0x1f << 4);
+                       ystart = (776 - gspca_dev->pixfmt.height) / 2;
                } else {
-                       xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4);
-                       ystart = (1544 - gspca_dev->height) / 2;
+                       xstart = (2076 - gspca_dev->pixfmt.width) / 2 +
+                               (0x10 << 4);
+                       ystart = (1544 - gspca_dev->pixfmt.height) / 2;
                }
-               xend = xstart + gspca_dev->width;
-               yend = ystart + gspca_dev->height;
+               xend = xstart + gspca_dev->pixfmt.width;
+               yend = ystart + gspca_dev->pixfmt.height;
                /* Writing to the COMH register resets the other windowing regs
                   to their default values, so we must do this first. */
                i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0);
@@ -4229,8 +4233,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* Default for most bridges, allow bridge_mode_init_regs to override */
-       sd->sensor_width = sd->gspca_dev.width;
-       sd->sensor_height = sd->gspca_dev.height;
+       sd->sensor_width = sd->gspca_dev.pixfmt.width;
+       sd->sensor_height = sd->gspca_dev.pixfmt.height;
 
        switch (sd->bridge) {
        case BRIDGE_OV511:
@@ -4345,12 +4349,13 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
                ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
                if (in[8] & 0x80) {
                        /* Frame end */
-                       if ((in[9] + 1) * 8 != gspca_dev->width ||
-                           (in[10] + 1) * 8 != gspca_dev->height) {
+                       if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width ||
+                           (in[10] + 1) * 8 != gspca_dev->pixfmt.height) {
                                PERR("Invalid frame size, got: %dx%d,"
                                        " requested: %dx%d\n",
                                        (in[9] + 1) * 8, (in[10] + 1) * 8,
-                                       gspca_dev->width, gspca_dev->height);
+                                       gspca_dev->pixfmt.width,
+                                       gspca_dev->pixfmt.height);
                                gspca_dev->last_packet_type = DISCARD_PACKET;
                                return;
                        }
@@ -4470,7 +4475,8 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
                if (sd->first_frame) {
                        sd->first_frame--;
                        if (gspca_dev->image_len <
-                                 sd->gspca_dev.width * sd->gspca_dev.height)
+                                 sd->gspca_dev.pixfmt.width *
+                                       sd->gspca_dev.pixfmt.height)
                                gspca_dev->last_packet_type = DISCARD_PACKET;
                }
                gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
index 03a33c4..90f0d63 100644 (file)
@@ -1440,9 +1440,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                /* If this packet is marked as EOF, end the frame */
                } else if (data[1] & UVC_STREAM_EOF) {
                        sd->last_pts = 0;
-                       if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV
+                       if (gspca_dev->pixfmt.pixelformat == V4L2_PIX_FMT_YUYV
                         && gspca_dev->image_len + len - 12 !=
-                                  gspca_dev->width * gspca_dev->height * 2) {
+                                  gspca_dev->pixfmt.width *
+                                       gspca_dev->pixfmt.height * 2) {
                                PDEBUG(D_PACK, "wrong sized frame");
                                goto discard;
                        }
index c4cd028..47085cf 100644 (file)
@@ -59,6 +59,7 @@ enum sensors {
        SENSOR_OV965x,          /* ov9657 */
        SENSOR_OV971x,          /* ov9712 */
        SENSOR_OV562x,          /* ov5621 */
+       SENSOR_OV361x,          /* ov3610 */
        NSENSORS
 };
 
@@ -106,6 +107,274 @@ static const struct v4l2_pix_format ov562x_mode[] = {
        }
 };
 
+enum ov361x {
+       ov361x_2048 = 0,
+       ov361x_1600,
+       ov361x_1024,
+       ov361x_640,
+       ov361x_320,
+       ov361x_160,
+       ov361x_last
+};
+
+static const struct v4l2_pix_format ov361x_mode[] = {
+       {0x800, 0x600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 0x800,
+               .sizeimage = 0x800 * 0x600,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1600,
+               .sizeimage = 1600 * 1200,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 768,
+               .sizeimage = 1024 * 768,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB}
+};
+
+static const u8 ov361x_start_2048[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0c},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x00},
+       {0x17, 0x10},
+       {0x18, 0x90},
+       {0x19, 0x00},
+       {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_2048[][2] = {
+       {0xf1, 0x60},
+       {0x88, 0x00},
+       {0x89, 0x08},
+       {0x8a, 0x00},
+       {0x8b, 0x06},
+       {0x8c, 0x01},
+       {0x8d, 0x10},
+       {0x1c, 0x00},
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},
+       {0x1d, 0x2e},
+       {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1600[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0C},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x00},
+       {0x17, 0x10},
+       {0x18, 0x90},
+       {0x19, 0x00},
+       {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_1600[][2] = {
+       {0xf1, 0x60},  /* Hsize[7:0] */
+       {0x88, 0x00},  /* Hsize[15:8] Write Only, can't read */
+       {0x89, 0x08},  /* Vsize[7:0] */
+       {0x8a, 0x00},  /* Vsize[15:8] Write Only, can't read */
+       {0x8b, 0x06},  /* for Iso */
+       {0x8c, 0x01},  /* RAW input */
+       {0x8d, 0x10},
+       {0x1c, 0x00},  /* RAW output, Iso transfer */
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},  /* turn off JPEG, Iso mode */
+       {0x1d, 0x2e},  /* for Iso */
+       {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1024[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0C},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x40},
+       {0x17, 0x1f},
+       {0x18, 0x5f},
+       {0x19, 0x00},
+       {0x1a, 0x68},
+};
+static const u8 ov361x_bridge_start_1024[][2] = {
+       {0xf1, 0x60},  /* Hsize[7:0] */
+       {0x88, 0x00},  /* Hsize[15:8] Write Only, can't read */
+       {0x89, 0x04},  /* Vsize[7:0] */
+       {0x8a, 0x00},  /* Vsize[15:8] Write Only, can't read */
+       {0x8b, 0x03},  /* for Iso */
+       {0x8c, 0x01},  /* RAW input  */
+       {0x8d, 0x10},
+       {0x1c, 0x00},  /* RAW output, Iso transfer */
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},  /* turn off JPEG, Iso mode */
+       {0x1d, 0x2e},  /* for Iso */
+       {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_640[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0C},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x40},
+       {0x17, 0x1f},
+       {0x18, 0x5f},
+       {0x19, 0x00},
+       {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_640[][2] = {
+       {0xf1, 0x60},  /* Hsize[7:0]*/
+       {0x88, 0x00},  /* Hsize[15:8] Write Only, can't read */
+       {0x89, 0x04},  /* Vsize[7:0] */
+       {0x8a, 0x00},  /* Vsize[15:8] Write Only, can't read */
+       {0x8b, 0x03},  /* for Iso */
+       {0x8c, 0x01},  /* RAW input */
+       {0x8d, 0x10},
+       {0x1c, 0x00},  /* RAW output, Iso transfer */
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},  /* turn off JPEG, Iso mode */
+       {0x1d, 0x2e},  /* for Iso */
+       {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_320[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0C},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x40},
+       {0x17, 0x1f},
+       {0x18, 0x5f},
+       {0x19, 0x00},
+       {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_320[][2] = {
+       {0xf1, 0x60},  /* Hsize[7:0] */
+       {0x88, 0x00},  /* Hsize[15:8] Write Only, can't read */
+       {0x89, 0x04},  /* Vsize[7:0] */
+       {0x8a, 0x00},  /* Vsize[15:8] Write Only, can't read */
+       {0x8b, 0x03},  /* for Iso */
+       {0x8c, 0x01},  /* RAW input */
+       {0x8d, 0x10},
+       {0x1c, 0x00},  /* RAW output, Iso transfer; */
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},  /* turn off JPEG, Iso mode */
+       {0x1d, 0x2e},  /* for Iso */
+       {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_160[][2] = {
+       {0x12, 0x80},
+       {0x13, 0xcf},
+       {0x14, 0x40},
+       {0x15, 0x00},
+       {0x01, 0x80},
+       {0x02, 0x80},
+       {0x04, 0x70},
+       {0x0d, 0x40},
+       {0x0f, 0x47},
+       {0x11, 0x81},
+       {0x32, 0x36},
+       {0x33, 0x0C},
+       {0x34, 0x00},
+       {0x35, 0x90},
+       {0x12, 0x40},
+       {0x17, 0x1f},
+       {0x18, 0x5f},
+       {0x19, 0x00},
+       {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_160[][2] = {
+       {0xf1, 0x60},  /* Hsize[7:0] */
+       {0x88, 0x00},  /* Hsize[15:8] Write Only, can't read */
+       {0x89, 0x04},  /* Vsize[7:0] */
+       {0x8a, 0x00},  /* Vsize[15:8] Write Only, can't read */
+       {0x8b, 0x03},  /* for Iso */
+       {0x8c, 0x01},  /* RAW input */
+       {0x8d, 0x10},
+       {0x1c, 0x00},  /* RAW output, Iso transfer */
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},  /* turn off JPEG, Iso mode */
+       {0x1d, 0x2e},  /* for Iso */
+       {0x1d, 0x1e},
+};
+
 static const u8 bridge_init[][2] = {
        {0x88, 0xf8},
        {0x89, 0xff},
@@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
        int i;
 
        for (i = 0; i < 5; i++) {
-               msleep(10);
+               msleep(20);
                data = reg_r(gspca_dev, OV534_REG_STATUS);
 
                switch (data) {
@@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
                sccb_w_array(gspca_dev, ov562x_init_2,
                                ARRAY_SIZE(ov562x_init_2));
                reg_w(gspca_dev, 0xe0, 0x00);
+       } else if ((sensor_id & 0xfff0) == 0x3610) {
+               sd->sensor = SENSOR_OV361x;
+               gspca_dev->cam.cam_mode = ov361x_mode;
+               gspca_dev->cam.nmodes = ARRAY_SIZE(ov361x_mode);
+               reg_w(gspca_dev, 0xe7, 0x3a);
+               reg_w(gspca_dev, 0xf1, 0x60);
+               sccb_write(gspca_dev, 0x12, 0x80);
        } else {
                pr_err("Unknown sensor %04x", sensor_id);
                return -EINVAL;
@@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return gspca_dev->usb_err;
 }
 
+static int sd_start_ov361x(struct gspca_dev *gspca_dev)
+{
+       sccb_write(gspca_dev, 0x12, 0x80);
+       msleep(20);
+       switch (gspca_dev->curr_mode % (ov361x_last)) {
+       case ov361x_2048:
+               reg_w_array(gspca_dev, ov361x_bridge_start_2048,
+                           ARRAY_SIZE(ov361x_bridge_start_2048));
+               sccb_w_array(gspca_dev, ov361x_start_2048,
+                            ARRAY_SIZE(ov361x_start_2048));
+               break;
+       case ov361x_1600:
+               reg_w_array(gspca_dev, ov361x_bridge_start_1600,
+                           ARRAY_SIZE(ov361x_bridge_start_1600));
+               sccb_w_array(gspca_dev, ov361x_start_1600,
+                            ARRAY_SIZE(ov361x_start_1600));
+               break;
+       case ov361x_1024:
+               reg_w_array(gspca_dev, ov361x_bridge_start_1024,
+                           ARRAY_SIZE(ov361x_bridge_start_1024));
+               sccb_w_array(gspca_dev, ov361x_start_1024,
+                            ARRAY_SIZE(ov361x_start_1024));
+               break;
+       case ov361x_640:
+               reg_w_array(gspca_dev, ov361x_bridge_start_640,
+                           ARRAY_SIZE(ov361x_bridge_start_640));
+               sccb_w_array(gspca_dev, ov361x_start_640,
+                            ARRAY_SIZE(ov361x_start_640));
+               break;
+       case ov361x_320:
+               reg_w_array(gspca_dev, ov361x_bridge_start_320,
+                           ARRAY_SIZE(ov361x_bridge_start_320));
+               sccb_w_array(gspca_dev, ov361x_start_320,
+                            ARRAY_SIZE(ov361x_start_320));
+               break;
+       case ov361x_160:
+               reg_w_array(gspca_dev, ov361x_bridge_start_160,
+                           ARRAY_SIZE(ov361x_bridge_start_160));
+               sccb_w_array(gspca_dev, ov361x_start_160,
+                            ARRAY_SIZE(ov361x_start_160));
+               break;
+       }
+       reg_w(gspca_dev, 0xe0, 0x00); /* start transfer */
+
+       return gspca_dev->usb_err;
+}
+
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                return gspca_dev->usb_err;
        if (sd->sensor == SENSOR_OV562x)
                return gspca_dev->usb_err;
+       if (sd->sensor == SENSOR_OV361x)
+               return sd_start_ov361x(gspca_dev);
 
        switch (gspca_dev->curr_mode) {
        case QVGA_MODE:                 /* 320x240 */
@@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+       if (((struct sd *)gspca_dev)->sensor == SENSOR_OV361x) {
+               reg_w(gspca_dev, 0xe0, 0x01); /* stop transfer */
+               /* reg_w(gspca_dev, 0x31, 0x09); */
+               return;
+       }
        reg_w(gspca_dev, 0xe0, 0x01);
        set_led(gspca_dev, 0);
        reg_w(gspca_dev, 0xe0, 0x00);
@@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
 
        if (sd->sensor == SENSOR_OV971x)
                return 0;
+       if (sd->sensor == SENSOR_OV361x)
+               return 0;
        gspca_dev->vdev.ctrl_handler = hdl;
        v4l2_ctrl_handler_init(hdl, 7);
        if (sd->sensor == SENSOR_OV562x) {
index 83519be..cd79c18 100644 (file)
@@ -299,7 +299,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
 
        /* Compression Balance */
-       if (gspca_dev->width == 176)
+       if (gspca_dev->pixfmt.width == 176)
                pac207_write_reg(gspca_dev, 0x4a, 0xff);
        else
                pac207_write_reg(gspca_dev, 0x4a, 0x30);
@@ -317,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                mode = 0x00;
        else
                mode = 0x02;
-       if (gspca_dev->width == 176) {  /* 176x144 */
+       if (gspca_dev->pixfmt.width == 176) {   /* 176x144 */
                mode |= 0x01;
                PDEBUG(D_STREAM, "pac207_start mode 176x144");
        } else {                                /* 352x288 */
index 1a5bdc8..25f86b1 100644 (file)
@@ -326,7 +326,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val)
         *  640x480 mode and page 4 reg 2 <= 3 then it must be 9
         */
        reg_w(gspca_dev, 0xff, 0x01);
-       if (gspca_dev->width != 640 && val <= 3)
+       if (gspca_dev->pixfmt.width != 640 && val <= 3)
                reg_w(gspca_dev, 0x08, 0x09);
        else
                reg_w(gspca_dev, 0x08, 0x08);
@@ -337,7 +337,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val)
         * camera to use higher compression or we may run out of
         * bandwidth.
         */
-       if (gspca_dev->width == 640 && val == 2)
+       if (gspca_dev->pixfmt.width == 640 && val == 2)
                reg_w(gspca_dev, 0x80, 0x01);
        else
                reg_w(gspca_dev, 0x80, 0x1c);
@@ -615,7 +615,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
                /* Start the new frame with the jpeg header */
                pac_start_frame(gspca_dev,
-                       gspca_dev->height, gspca_dev->width);
+                       gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
index 5f729b8..5102cea 100644 (file)
@@ -354,9 +354,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        /* set size + mode */
        se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH,
-                       gspca_dev->width * mult, 0);
+                       gspca_dev->pixfmt.width * mult, 0);
        se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT,
-                       gspca_dev->height * mult, 0);
+                       gspca_dev->pixfmt.height * mult, 0);
        /*
         * HDG: disabled this as it does not seem to do anything
         * se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE,
@@ -480,7 +480,7 @@ static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len)
 static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
 {
        struct sd *sd = (struct sd *)gspca_dev;
-       int imagesize = gspca_dev->width * gspca_dev->height;
+       int imagesize = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
        int i, plen, bits, pixels, info, count;
 
        if (sd->restart_stream)
index f4453d5..2a38621 100644 (file)
@@ -1955,7 +1955,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
                        return 0;
                }
 
-               switch (gspca_dev->width) {
+               switch (gspca_dev->pixfmt.width) {
                case 160: /* 160x120 */
                        gspca_dev->alt = 2;
                        break;
@@ -1985,8 +1985,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
-       int width = gspca_dev->width;
-       int height = gspca_dev->height;
+       int width = gspca_dev->pixfmt.width;
+       int height = gspca_dev->pixfmt.height;
        u8 fmt, scale = 0;
 
        jpeg_define(sd->jpeg_hdr, height, width,
index d7ff3b9..7277dbd 100644 (file)
@@ -513,10 +513,7 @@ static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf)
                if (gspca_dev->usb_buf[0] & 0x04) {
                        if (gspca_dev->usb_buf[0] & 0x08) {
                                dev_err(gspca_dev->v4l2_dev.dev,
-                                       "i2c error writing %02x %02x %02x %02x"
-                                       " %02x %02x %02x %02x\n",
-                                       buf[0], buf[1], buf[2], buf[3],
-                                       buf[4], buf[5], buf[6], buf[7]);
+                                       "i2c error writing %8ph\n", buf);
                                gspca_dev->usb_err = -EIO;
                        }
                        return;
@@ -753,7 +750,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
                /* In 640x480, if the reg11 has less than 4, the image is
                   unstable (the bridge goes into a higher compression mode
                   which we have not reverse engineered yet). */
-               if (gspca_dev->width == 640 && reg11 < 4)
+               if (gspca_dev->pixfmt.width == 640 && reg11 < 4)
                        reg11 = 4;
 
                /* frame exposure time in ms = 1000 * reg11 / 30    ->
index 3b5ccb1..c69b45d 100644 (file)
@@ -2204,7 +2204,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                { 0x14, 0xe7, 0x1e, 0xdd };
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x21);          /* JPEG 422 */
 
        /* initialize the bridge */
index 688592b..f38fd89 100644 (file)
@@ -255,7 +255,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* initialize the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x22);          /* JPEG 411 */
 
        /* the JPEG quality shall be 85% */
index 9f8bf51..f011a30 100644 (file)
@@ -608,7 +608,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        __u8 xmult, ymult;
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 
index acb19fb..aa21edc 100644 (file)
@@ -272,7 +272,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        dev->cap_mode = gspca_dev->cam.cam_mode;
        /* "Open the shutter" and set size, to start capture */
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 640:
                PDEBUG(D_STREAM, "Start streaming at high resolution");
                dev->cap_mode++;
index b10d082..e274cf1 100644 (file)
@@ -906,7 +906,8 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
 
        gspca_dev->cam.bulk_nurbs = 1;  /* there must be one URB only */
        sd->do_ctrl = 0;
-       gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8;
+       gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width *
+                       gspca_dev->pixfmt.height + 8;
        return 0;
 }
 
index 8c09826..b0c70fe 100644 (file)
@@ -250,7 +250,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int ret, value;
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 
@@ -261,7 +262,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x00000000);
        set_par(gspca_dev, 0x8002e001);
        set_par(gspca_dev, 0x14000000);
-       if (gspca_dev->width > 320)
+       if (gspca_dev->pixfmt.width > 320)
                value = 0x8002e001;             /* 640x480 */
        else
                value = 0x4001f000;             /* 320x240 */
index 5858688..1fc80af 100644 (file)
@@ -48,42 +48,11 @@ struct sd {
 };
 
 static const struct v4l2_pix_format stk1135_modes[] = {
-       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 160,
-               .sizeimage = 160 * 120,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 176,
-               .sizeimage = 176 * 144,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 320,
-               .sizeimage = 320 * 240,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 352,
-               .sizeimage = 352 * 288,
-               .colorspace = V4L2_COLORSPACE_SRGB},
+       /* default mode (this driver supports variable resolution) */
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480,
                .colorspace = V4L2_COLORSPACE_SRGB},
-       {720, 576, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 720,
-               .sizeimage = 720 * 576,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 800,
-               .sizeimage = 800 * 600,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 1024,
-               .sizeimage = 1024 * 768,
-               .colorspace = V4L2_COLORSPACE_SRGB},
-       {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
-               .bytesperline = 1280,
-               .sizeimage = 1280 * 1024,
-               .colorspace = V4L2_COLORSPACE_SRGB},
 };
 
 /* -- read a register -- */
@@ -347,16 +316,16 @@ static void stk1135_configure_mt9m112(struct gspca_dev *gspca_dev)
                sensor_write(gspca_dev, cfg[i].reg, cfg[i].val);
 
        /* set output size */
-       width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width;
-       height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height;
-       if (width <= 640) { /* use context A (half readout speed by default) */
+       width = gspca_dev->pixfmt.width;
+       height = gspca_dev->pixfmt.height;
+       if (width <= 640 && height <= 512) { /* context A (half readout speed)*/
                sensor_write(gspca_dev, 0x1a7, width);
                sensor_write(gspca_dev, 0x1aa, height);
                /* set read mode context A */
                sensor_write(gspca_dev, 0x0c8, 0x0000);
                /* set resize, read mode, vblank, hblank context A */
                sensor_write(gspca_dev, 0x2c8, 0x0000);
-       } else { /* use context B (full readout speed by default) */
+       } else { /* context B (full readout speed) */
                sensor_write(gspca_dev, 0x1a1, width);
                sensor_write(gspca_dev, 0x1a4, height);
                /* set read mode context B */
@@ -484,8 +453,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, STK1135_REG_CISPO + 3, 0x00);
 
        /* set capture end position */
-       width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width;
-       height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height;
+       width = gspca_dev->pixfmt.width;
+       height = gspca_dev->pixfmt.height;
        reg_w(gspca_dev, STK1135_REG_CIEPO + 0, width & 0xff);
        reg_w(gspca_dev, STK1135_REG_CIEPO + 1, width >> 8);
        reg_w(gspca_dev, STK1135_REG_CIEPO + 2, height & 0xff);
@@ -643,6 +612,35 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+static void stk1135_try_fmt(struct gspca_dev *gspca_dev, struct v4l2_format *fmt)
+{
+       fmt->fmt.pix.width = clamp(fmt->fmt.pix.width, 32U, 1280U);
+       fmt->fmt.pix.height = clamp(fmt->fmt.pix.height, 32U, 1024U);
+       /* round up to even numbers */
+       fmt->fmt.pix.width += (fmt->fmt.pix.width & 1);
+       fmt->fmt.pix.height += (fmt->fmt.pix.height & 1);
+
+       fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
+       fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height;
+}
+
+static int stk1135_enum_framesizes(struct gspca_dev *gspca_dev,
+                       struct v4l2_frmsizeenum *fsize)
+{
+       if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_SBGGR8)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise.min_width = 32;
+       fsize->stepwise.min_height = 32;
+       fsize->stepwise.max_width = 1280;
+       fsize->stepwise.max_height = 1024;
+       fsize->stepwise.step_width = 2;
+       fsize->stepwise.step_height = 2;
+
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -653,6 +651,8 @@ static const struct sd_desc sd_desc = {
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = stk1135_dq_callback,
+       .try_fmt = stk1135_try_fmt,
+       .enum_framesizes = stk1135_enum_framesizes,
 };
 
 /* -- module initialisation -- */
index 55ee7a6..49d209b 100644 (file)
@@ -452,7 +452,7 @@ frame_data:
                                        NULL, 0);
 
                        if (sd->bridge == BRIDGE_ST6422)
-                               sd->to_skip = gspca_dev->width * 4;
+                               sd->to_skip = gspca_dev->pixfmt.width * 4;
 
                        if (chunk_len)
                                PERR("Chunk length is "
index 8206b77..8d785ed 100644 (file)
@@ -421,7 +421,7 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
 
        /* Number of pixels counted by the sensor when subsampling the pixels.
         * Slightly larger than the real value to avoid oscillation */
-       totalpixels = gspca_dev->width * gspca_dev->height;
+       totalpixels = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
        totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
 
        brightpixels = (totalpixels * val) >> 8;
index af8767a..a517d18 100644 (file)
@@ -715,7 +715,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int enable;
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 
index 4cb511c..640c2fe 100644 (file)
@@ -3856,7 +3856,7 @@ static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
 
        if (sd->bridge == BRIDGE_TP6800) {
                val |= 0x08;            /* grid compensation enable */
-               if (gspca_dev->width == 640)
+               if (gspca_dev->pixfmt.width == 640)
                        reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */
                else
                        val |= 0x04;            /* scaling down enable */
@@ -3880,7 +3880,7 @@ static void set_resolution(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
-       if (gspca_dev->width == 320) {
+       if (gspca_dev->pixfmt.width == 320) {
                reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06);
                msleep(100);
                i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
@@ -3924,7 +3924,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
 
                /* 640x480 * 30 fps does not work */
                if (i == 6                      /* if 30 fps */
-                && gspca_dev->width == 640)
+                && gspca_dev->pixfmt.width == 640)
                        i = 0x05;               /* 15 fps */
        } else {
                for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
@@ -3935,7 +3935,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
 
                /* 640x480 * 30 fps does not work */
                if (i == 7                      /* if 30 fps */
-                && gspca_dev->width == 640)
+                && gspca_dev->pixfmt.width == 640)
                        i = 6;                  /* 15 fps */
                i |= 0x80;                      /* clock * 1 */
        }
@@ -4554,7 +4554,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width);
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width);
        set_dqt(gspca_dev, sd->quality);
        if (sd->bridge == BRIDGE_TP6800) {
                if (sd->sensor == SENSOR_CX0342)
@@ -4737,7 +4738,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
                        (gspca_dev->usb_buf[26] << 8) + gspca_dev->usb_buf[25] +
                        (gspca_dev->usb_buf[29] << 8) + gspca_dev->usb_buf[28])
                                / 8;
-               if (gspca_dev->width == 640)
+               if (gspca_dev->pixfmt.width == 640)
                        luma /= 4;
                reg_w(gspca_dev, 0x7d, 0x00);
 
index 8591324..d497ba3 100644 (file)
@@ -268,7 +268,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        packet_type0 = packet_type1 = INTER_PACKET;
        if (gspca_dev->empty_packet) {
                gspca_dev->empty_packet = 0;
-               sd->packet = gspca_dev->height / 2;
+               sd->packet = gspca_dev->pixfmt.height / 2;
                packet_type0 = FIRST_PACKET;
        } else if (sd->packet == 0)
                return;                 /* 2 more lines in 352x288 ! */
@@ -284,9 +284,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
         * - 4 bytes
         */
        gspca_frame_add(gspca_dev, packet_type0,
-                       data + 2, gspca_dev->width);
+                       data + 2, gspca_dev->pixfmt.width);
        gspca_frame_add(gspca_dev, packet_type1,
-                       data + gspca_dev->width + 5, gspca_dev->width);
+                       data + gspca_dev->pixfmt.width + 5,
+                       gspca_dev->pixfmt.width);
 }
 
 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
index a2275cf..103f6c4 100644 (file)
@@ -121,13 +121,13 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)
 
        memset(req_data, 0, 16);
        req_data[0] = gain;
-       if (gspca_dev->width == 256)
+       if (gspca_dev->pixfmt.width == 256)
                req_data[1] |= 0x01; /* low nibble x-scale */
-       if (gspca_dev->height <= 122) {
+       if (gspca_dev->pixfmt.height <= 122) {
                req_data[1] |= 0x10; /* high nibble y-scale */
-               unscaled_height = gspca_dev->height * 2;
+               unscaled_height = gspca_dev->pixfmt.height * 2;
        } else
-               unscaled_height = gspca_dev->height;
+               unscaled_height = gspca_dev->pixfmt.height;
        req_data[2] = 0x90; /* unknown, does not seem to do anything */
        if (unscaled_height <= 200)
                req_data[3] = 0x06; /* vend? */
index 2165da0..fb9fe2e 100644 (file)
@@ -430,11 +430,11 @@ static void w9968cf_set_crop_window(struct sd *sd)
        #define SC(x) ((x) << 10)
 
        /* Scaling factors */
-       fw = SC(sd->gspca_dev.width) / max_width;
-       fh = SC(sd->gspca_dev.height) / max_height;
+       fw = SC(sd->gspca_dev.pixfmt.width) / max_width;
+       fh = SC(sd->gspca_dev.pixfmt.height) / max_height;
 
-       cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh;
-       ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height;
+       cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.pixfmt.width) / fh;
+       ch = (fw >= fh) ? SC(sd->gspca_dev.pixfmt.height) / fw : max_height;
 
        sd->sensor_width = max_width;
        sd->sensor_height = max_height;
@@ -454,34 +454,34 @@ static void w9968cf_mode_init_regs(struct sd *sd)
 
        w9968cf_set_crop_window(sd);
 
-       reg_w(sd, 0x14, sd->gspca_dev.width);
-       reg_w(sd, 0x15, sd->gspca_dev.height);
+       reg_w(sd, 0x14, sd->gspca_dev.pixfmt.width);
+       reg_w(sd, 0x15, sd->gspca_dev.pixfmt.height);
 
        /* JPEG width & height */
-       reg_w(sd, 0x30, sd->gspca_dev.width);
-       reg_w(sd, 0x31, sd->gspca_dev.height);
+       reg_w(sd, 0x30, sd->gspca_dev.pixfmt.width);
+       reg_w(sd, 0x31, sd->gspca_dev.pixfmt.height);
 
        /* Y & UV frame buffer strides (in WORD) */
        if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
            V4L2_PIX_FMT_JPEG) {
-               reg_w(sd, 0x2c, sd->gspca_dev.width / 2);
-               reg_w(sd, 0x2d, sd->gspca_dev.width / 4);
+               reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width / 2);
+               reg_w(sd, 0x2d, sd->gspca_dev.pixfmt.width / 4);
        } else
-               reg_w(sd, 0x2c, sd->gspca_dev.width);
+               reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width);
 
        reg_w(sd, 0x00, 0xbf17); /* reset everything */
        reg_w(sd, 0x00, 0xbf10); /* normal operation */
 
        /* Transfer size in WORDS (for UYVY format only) */
-       val = sd->gspca_dev.width * sd->gspca_dev.height;
+       val = sd->gspca_dev.pixfmt.width * sd->gspca_dev.pixfmt.height;
        reg_w(sd, 0x3d, val & 0xffff); /* low bits */
        reg_w(sd, 0x3e, val >> 16);    /* high bits */
 
        if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
            V4L2_PIX_FMT_JPEG) {
                /* We may get called multiple times (usb isoc bw negotiat.) */
-               jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
-                           sd->gspca_dev.width, 0x22); /* JPEG 420 */
+               jpeg_define(sd->jpeg_hdr, sd->gspca_dev.pixfmt.height,
+                           sd->gspca_dev.pixfmt.width, 0x22); /* JPEG 420 */
                jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
                w9968cf_upload_quantizationtables(sd);
                v4l2_ctrl_grab(sd->jpegqual, true);
index 7eaf64e..a41aa78 100644 (file)
@@ -1471,14 +1471,14 @@ static int cit_get_clock_div(struct gspca_dev *gspca_dev)
 
        while (clock_div > 3 &&
                        1000 * packet_size >
-                       gspca_dev->width * gspca_dev->height *
+                       gspca_dev->pixfmt.width * gspca_dev->pixfmt.height *
                        fps[clock_div - 1] * 3 / 2)
                clock_div--;
 
        PDEBUG(D_PROBE,
               "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)",
-              packet_size, gspca_dev->width, gspca_dev->height, clock_div,
-              fps[clock_div]);
+              packet_size, gspca_dev->pixfmt.width, gspca_dev->pixfmt.height,
+              clock_div, fps[clock_div]);
 
        return clock_div;
 }
@@ -1502,7 +1502,7 @@ static int cit_start_model0(struct gspca_dev *gspca_dev)
        cit_write_reg(gspca_dev, 0x0002, 0x0426);
        cit_write_reg(gspca_dev, 0x0014, 0x0427);
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160: /* 160x120 */
                cit_write_reg(gspca_dev, 0x0004, 0x010b);
                cit_write_reg(gspca_dev, 0x0001, 0x010a);
@@ -1643,7 +1643,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev)
        cit_write_reg(gspca_dev, 0x00, 0x0101);
        cit_write_reg(gspca_dev, 0x00, 0x010a);
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 128: /* 128x96 */
                cit_write_reg(gspca_dev, 0x80, 0x0103);
                cit_write_reg(gspca_dev, 0x60, 0x0105);
@@ -1700,7 +1700,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev)
        }
 
        /* Assorted init */
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 128: /* 128x96 */
                cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
                cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
@@ -1753,7 +1753,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
        cit_write_reg(gspca_dev, 0x0000, 0x0108);
        cit_write_reg(gspca_dev, 0x0001, 0x0133);
        cit_write_reg(gspca_dev, 0x0001, 0x0102);
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 176: /* 176x144 */
                cit_write_reg(gspca_dev, 0x002c, 0x0103);       /* All except 320x240 */
                cit_write_reg(gspca_dev, 0x0000, 0x0104);       /* Same */
@@ -1792,7 +1792,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
 
        cit_write_reg(gspca_dev, 0x0000, 0x0100);       /* LED on */
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 176: /* 176x144 */
                cit_write_reg(gspca_dev, 0x0050, 0x0111);
                cit_write_reg(gspca_dev, 0x00d0, 0x0111);
@@ -1840,7 +1840,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
         * Magic control of CMOS sensor. Only lower values like
         * 0-3 work, and picture shifts left or right. Don't change.
         */
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 176: /* 176x144 */
                cit_model2_Packet1(gspca_dev, 0x0014, 0x0002);
                cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
@@ -1899,7 +1899,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
         * does not allow arbitrary values and apparently is a bit mask, to
         * be activated only at appropriate time. Don't change it randomly!
         */
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 176: /* 176x144 */
                cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2);
                break;
@@ -2023,7 +2023,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
        cit_model3_Packet1(gspca_dev, 0x009e, 0x0096);
        cit_model3_Packet1(gspca_dev, 0x009f, 0x000a);
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
                cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
@@ -2134,7 +2134,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
           like with the IBM netcam pro). */
        cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
                cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
@@ -2211,7 +2211,7 @@ static int cit_start_model4(struct gspca_dev *gspca_dev)
        cit_write_reg(gspca_dev, 0xfffa, 0x0124);
        cit_model4_Packet1(gspca_dev, 0x0034, 0x0000);
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 128: /* 128x96 */
                cit_write_reg(gspca_dev, 0x0070, 0x0119);
                cit_write_reg(gspca_dev, 0x00d0, 0x0111);
@@ -2531,7 +2531,7 @@ static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
        cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
        cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160: /* 160x120 */
                cit_write_reg(gspca_dev, 0x0024, 0x010b);
                cit_write_reg(gspca_dev, 0x0089, 0x0119);
@@ -2635,7 +2635,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
        struct usb_host_interface *alt;
        int max_packet_size;
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                max_packet_size = 450;
                break;
@@ -2659,7 +2659,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
        int ret, packet_size, min_packet_size;
        struct usb_host_interface *alt;
 
-       switch (gspca_dev->width) {
+       switch (gspca_dev->pixfmt.width) {
        case 160:
                min_packet_size = 200;
                break;
@@ -2780,7 +2780,7 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
        case CIT_MODEL1:
        case CIT_MODEL3:
        case CIT_IBM_NETCAM_PRO:
-               switch (gspca_dev->width) {
+               switch (gspca_dev->pixfmt.width) {
                case 160: /* 160x120 */
                        byte3 = 0x02;
                        byte4 = 0x0a;
@@ -2864,20 +2864,16 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
                                if (data[i] == 0xff) {
                                        if (i >= 4)
                                                PDEBUG(D_FRAM,
-                                                      "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n",
+                                                      "header found at offset: %d: %02x %02x 00 %3ph\n",
                                                       i - 1,
                                                       data[i - 4],
                                                       data[i - 3],
-                                                      data[i],
-                                                      data[i + 1],
-                                                      data[i + 2]);
+                                                      &data[i]);
                                        else
                                                PDEBUG(D_FRAM,
-                                                      "header found at offset: %d: 00 %02x %02x %02x\n",
+                                                      "header found at offset: %d: 00 %3ph\n",
                                                       i - 1,
-                                                      data[i],
-                                                      data[i + 1],
-                                                      data[i + 2]);
+                                                      &data[i]);
                                        return data + i + (sd->sof_len - 1);
                                }
                                break;
index cbfc2f9..7b95d8e 100644 (file)
@@ -6700,7 +6700,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        };
 
        /* create the JPEG header */
-       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+       jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+                       gspca_dev->pixfmt.width,
                        0x21);          /* JPEG 422 */
 
        mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
index 6e50707..2f0c89c 100644 (file)
@@ -78,7 +78,8 @@ void hdpvr_delete(struct hdpvr_device *dev)
 
 static void challenge(u8 *bytes)
 {
-       u64 *i64P, tmp64;
+       __le64 *i64P;
+       u64 tmp64;
        uint i, idx;
 
        for (idx = 0; idx < 32; ++idx) {
@@ -106,10 +107,10 @@ static void challenge(u8 *bytes)
                        for (i = 0; i < 3; i++)
                                bytes[1] *= bytes[6] + 1;
                        for (i = 0; i < 3; i++) {
-                               i64P = (u64 *)bytes;
+                               i64P = (__le64 *)bytes;
                                tmp64 = le64_to_cpup(i64P);
-                               tmp64 <<= bytes[7] & 0x0f;
-                               *i64P += cpu_to_le64(tmp64);
+                               tmp64 = tmp64 + (tmp64 << (bytes[7] & 0x0f));
+                               *i64P = cpu_to_le64(tmp64);
                        }
                        break;
                }
@@ -301,8 +302,6 @@ static int hdpvr_probe(struct usb_interface *interface,
                goto error;
        }
 
-       dev->workqueue = 0;
-
        /* init video transfer queues first of all */
        /* to prevent oops in hdpvr_delete() on error paths */
        INIT_LIST_HEAD(&dev->free_buff_list);
index c4d51d7..ea05f67 100644 (file)
@@ -2868,7 +2868,7 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
                pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
        }
 
-v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
+static v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
 {
        v4l2_std_id std;
        std = (v4l2_std_id)hdw->std_mask_avail;
index 03761c6..05bd91a 100644 (file)
@@ -209,8 +209,10 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
        struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
        int dummy;
 
-       if (dev->state != SMSUSB_ACTIVE)
+       if (dev->state != SMSUSB_ACTIVE) {
+               sms_debug("Device not active yet");
                return -ENOENT;
+       }
 
        sms_debug("sending %s(%d) size: %d",
                  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
@@ -243,6 +245,9 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
        int rc, dummy;
        char *fw_filename;
 
+       if (id < 0)
+               id = sms_get_board(board_id)->default_mode;
+
        if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
                sms_err("invalid firmware id specified %d", id);
                return -EINVAL;
@@ -445,14 +450,15 @@ static int smsusb_probe(struct usb_interface *intf,
        char devpath[32];
        int i, rc;
 
-       sms_info("interface number %d",
+       sms_info("board id=%lu, interface number %d",
+                id->driver_info,
                 intf->cur_altsetting->desc.bInterfaceNumber);
 
        if (sms_get_board(id->driver_info)->intf_num !=
            intf->cur_altsetting->desc.bInterfaceNumber) {
-               sms_err("interface number is %d expecting %d",
-                       sms_get_board(id->driver_info)->intf_num,
-                       intf->cur_altsetting->desc.bInterfaceNumber);
+               sms_debug("interface %d won't be used. Expecting interface %d to popup",
+                       intf->cur_altsetting->desc.bInterfaceNumber,
+                       sms_get_board(id->driver_info)->intf_num);
                return -ENODEV;
        }
 
@@ -483,22 +489,32 @@ static int smsusb_probe(struct usb_interface *intf,
        }
        if ((udev->actconfig->desc.bNumInterfaces == 2) &&
            (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
-               sms_err("rom interface 0 is not used");
+               sms_debug("rom interface 0 is not used");
                return -ENODEV;
        }
 
        if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
-               sms_info("stellar device was found.");
+               /* Detected a Siano Stellar uninitialized */
+
                snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
                         udev->bus->busnum, udev->devpath);
-               sms_info("stellar device was found.");
-               return smsusb1_load_firmware(
+               sms_info("stellar device in cold state was found at %s.", devpath);
+               rc = smsusb1_load_firmware(
                                udev, smscore_registry_getmode(devpath),
                                id->driver_info);
+
+               /* This device will reset and gain another USB ID */
+               if (!rc)
+                       sms_info("stellar device now in warm state");
+               else
+                       sms_err("Failed to put stellar in warm state. Error: %d", rc);
+
+               return rc;
+       } else {
+               rc = smsusb_init_device(intf, id->driver_info);
        }
 
-       rc = smsusb_init_device(intf, id->driver_info);
-       sms_info("rc %d", rc);
+       sms_info("Device initialized with return code %d", rc);
        sms_board_load_modules(id->driver_info);
        return rc;
 }
@@ -550,10 +566,13 @@ static int smsusb_resume(struct usb_interface *intf)
 }
 
 static const struct usb_device_id smsusb_id_table[] = {
+       /* This device is only present before firmware load */
        { USB_DEVICE(0x187f, 0x0010),
-               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM },
+       /* This device pops up after firmware load */
        { USB_DEVICE(0x187f, 0x0100),
                .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+
        { USB_DEVICE(0x187f, 0x0200),
                .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
        { USB_DEVICE(0x187f, 0x0201),
index 95f94e5..3316caa 100644 (file)
@@ -232,7 +232,7 @@ static int firmware_download(struct usb_device *udev)
                goto out;
        }
 
-       max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
+       max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize);
        log("\t\t download size : %d", (int)max_packet_size);
 
        for (offset = 0; offset < fwlength; offset += max_packet_size) {
index e52c3b9..29724af 100644 (file)
@@ -366,7 +366,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
                }
                return 0;
        } else {
-               return -1;
+               return -ENOENT;
        }
 }
 
@@ -1241,6 +1241,8 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
 
 static int ttusb_dec_init_usb(struct ttusb_dec *dec)
 {
+       int result;
+
        dprintk("%s\n", __func__);
 
        mutex_init(&dec->usb_mutex);
@@ -1258,7 +1260,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
                        return -ENOMEM;
                }
                dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
-                                       GFP_ATOMIC, &dec->irq_dma_handle);
+                                       GFP_KERNEL, &dec->irq_dma_handle);
                if(!dec->irq_buffer) {
                        usb_free_urb(dec->irq_urb);
                        return -ENOMEM;
@@ -1270,7 +1272,13 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
                dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        }
 
-       return ttusb_dec_alloc_iso_urbs(dec);
+       result = ttusb_dec_alloc_iso_urbs(dec);
+       if (result) {
+               usb_free_urb(dec->irq_urb);
+               usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
+                                 dec->irq_buffer, dec->irq_dma_handle);
+       }
+       return result;
 }
 
 static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1293,10 +1301,11 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
 
        dprintk("%s\n", __func__);
 
-       if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
+       result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev);
+       if (result) {
                printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
                       __func__, dec->firmware_name);
-               return 1;
+               return result;
        }
 
        firmware = fw_entry->data;
@@ -1306,7 +1315,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
                printk("%s: firmware size too small for DSP code (%zu < 60).\n",
                        __func__, firmware_size);
                release_firmware(fw_entry);
-               return -1;
+               return -ENOENT;
        }
 
        /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
@@ -1320,7 +1329,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
                       "0x%08x != 0x%08x in file), file invalid.\n",
                        __func__, crc32_csum, crc32_check);
                release_firmware(fw_entry);
-               return -1;
+               return -ENOENT;
        }
        memcpy(idstring, &firmware[36], 20);
        idstring[20] = '\0';
@@ -1389,55 +1398,48 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
        dprintk("%s\n", __func__);
 
        result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
+       if (result)
+               return result;
 
-       if (!result) {
-               if (!mode) {
-                       if (version == 0xABCDEFAB)
-                               printk(KERN_INFO "ttusb_dec: no version "
-                                      "info in Firmware\n");
-                       else
-                               printk(KERN_INFO "ttusb_dec: Firmware "
-                                      "%x.%02x%c%c\n",
-                                      version >> 24, (version >> 16) & 0xff,
-                                      (version >> 8) & 0xff, version & 0xff);
-
-                       result = ttusb_dec_boot_dsp(dec);
-                       if (result)
-                               return result;
-                       else
-                               return 1;
-               } else {
-                       /* We can't trust the USB IDs that some firmwares
-                          give the box */
-                       switch (model) {
-                       case 0x00070001:
-                       case 0x00070008:
-                       case 0x0007000c:
-                               ttusb_dec_set_model(dec, TTUSB_DEC3000S);
-                               break;
-                       case 0x00070009:
-                       case 0x00070013:
-                               ttusb_dec_set_model(dec, TTUSB_DEC2000T);
-                               break;
-                       case 0x00070011:
-                               ttusb_dec_set_model(dec, TTUSB_DEC2540T);
-                               break;
-                       default:
-                               printk(KERN_ERR "%s: unknown model returned "
-                                      "by firmware (%08x) - please report\n",
-                                      __func__, model);
-                               return -1;
-                               break;
-                       }
+       if (!mode) {
+               if (version == 0xABCDEFAB)
+                       printk(KERN_INFO "ttusb_dec: no version "
+                              "info in Firmware\n");
+               else
+                       printk(KERN_INFO "ttusb_dec: Firmware "
+                              "%x.%02x%c%c\n",
+                              version >> 24, (version >> 16) & 0xff,
+                              (version >> 8) & 0xff, version & 0xff);
 
+               result = ttusb_dec_boot_dsp(dec);
+               if (result)
+                       return result;
+       } else {
+               /* We can't trust the USB IDs that some firmwares
+                  give the box */
+               switch (model) {
+               case 0x00070001:
+               case 0x00070008:
+               case 0x0007000c:
+                       ttusb_dec_set_model(dec, TTUSB_DEC3000S);
+                       break;
+               case 0x00070009:
+               case 0x00070013:
+                       ttusb_dec_set_model(dec, TTUSB_DEC2000T);
+                       break;
+               case 0x00070011:
+                       ttusb_dec_set_model(dec, TTUSB_DEC2540T);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: unknown model returned "
+                              "by firmware (%08x) - please report\n",
+                              __func__, model);
+                       return -ENOENT;
+               }
                        if (version >= 0x01770000)
                                dec->can_playback = 1;
-
-                       return 0;
-               }
        }
-       else
-               return result;
+       return 0;
 }
 
 static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
@@ -1539,19 +1541,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
 
 static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
 {
-
        dprintk("%s\n", __func__);
-       /* we have to check whether the irq URB is already submitted.
-         * As the irq is submitted after the interface is changed,
-         * this is the best method i figured out.
-         * Any others?*/
-       if (dec->interface == TTUSB_DEC_INTERFACE_IN)
-               usb_kill_urb(dec->irq_urb);
-
-       usb_free_urb(dec->irq_urb);
-
-       usb_free_coherent(dec->udev,IRQ_PACKET_SIZE,
-                         dec->irq_buffer, dec->irq_dma_handle);
 
        if (dec->rc_input_dev) {
                input_unregister_device(dec->rc_input_dev);
@@ -1566,6 +1556,20 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
 
        dprintk("%s\n", __func__);
 
+       if (enable_rc) {
+               /* we have to check whether the irq URB is already submitted.
+                * As the irq is submitted after the interface is changed,
+                * this is the best method i figured out.
+                * Any others?*/
+               if (dec->interface == TTUSB_DEC_INTERFACE_IN)
+                       usb_kill_urb(dec->irq_urb);
+
+               usb_free_urb(dec->irq_urb);
+
+               usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
+                                 dec->irq_buffer, dec->irq_dma_handle);
+       }
+
        dec->iso_stream_count = 0;
 
        for (i = 0; i < ISO_BUF_COUNT; i++)
@@ -1623,6 +1627,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
 {
        struct usb_device *udev;
        struct ttusb_dec *dec;
+       int result;
 
        dprintk("%s\n", __func__);
 
@@ -1651,13 +1656,15 @@ static int ttusb_dec_probe(struct usb_interface *intf,
 
        dec->udev = udev;
 
-       if (ttusb_dec_init_usb(dec))
-               return 0;
-       if (ttusb_dec_init_stb(dec)) {
-               ttusb_dec_exit_usb(dec);
-               return 0;
-       }
-       ttusb_dec_init_dvb(dec);
+       result = ttusb_dec_init_usb(dec);
+       if (result)
+               goto err_usb;
+       result = ttusb_dec_init_stb(dec);
+       if (result)
+               goto err_stb;
+       result = ttusb_dec_init_dvb(dec);
+       if (result)
+               goto err_stb;
 
        dec->adapter.priv = dec;
        switch (id->idProduct) {
@@ -1696,6 +1703,11 @@ static int ttusb_dec_probe(struct usb_interface *intf,
                ttusb_init_rc(dec);
 
        return 0;
+err_stb:
+       ttusb_dec_exit_usb(dec);
+err_usb:
+       kfree(dec);
+       return result;
 }
 
 static void ttusb_dec_disconnect(struct usb_interface *intf)
index a2f4501..0eb8210 100644 (file)
@@ -664,7 +664,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .size           = 32,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
-               .data_type      = UVC_CTRL_DATA_TYPE_UNSIGNED,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
        },
        {
                .id             = V4L2_CID_TILT_ABSOLUTE,
@@ -674,7 +674,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .size           = 32,
                .offset         = 32,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
-               .data_type      = UVC_CTRL_DATA_TYPE_UNSIGNED,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
        },
        {
                .id             = V4L2_CID_PRIVACY,
index ddc9379..4b8a9a3 100644 (file)
@@ -247,7 +247,7 @@ static const struct analog_demod_ops tuner_analog_ops = {
 /**
  * set_type - Sets the tuner type for a given device
  *
- * @c:                 i2c_client descriptoy
+ * @c:                 i2c_client descriptor
  * @type:              type of the tuner (e. g. tuner number)
  * @new_mode_mask:     Indicates if tuner supports TV and/or Radio
  * @new_config:                an optional parameter used by a few tuners to adjust
index b67de86..e18cc04 100644 (file)
@@ -240,3 +240,42 @@ void v4l2_clk_unregister(struct v4l2_clk *clk)
        kfree(clk);
 }
 EXPORT_SYMBOL(v4l2_clk_unregister);
+
+struct v4l2_clk_fixed {
+       unsigned long rate;
+       struct v4l2_clk_ops ops;
+};
+
+static unsigned long fixed_get_rate(struct v4l2_clk *clk)
+{
+       struct v4l2_clk_fixed *priv = clk->priv;
+       return priv->rate;
+}
+
+struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id,
+               const char *id, unsigned long rate, struct module *owner)
+{
+       struct v4l2_clk *clk;
+       struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+
+       if (!priv)
+               return ERR_PTR(-ENOMEM);
+
+       priv->rate = rate;
+       priv->ops.get_rate = fixed_get_rate;
+       priv->ops.owner = owner;
+
+       clk = v4l2_clk_register(&priv->ops, dev_id, id, priv);
+       if (IS_ERR(clk))
+               kfree(priv);
+
+       return clk;
+}
+EXPORT_SYMBOL(__v4l2_clk_register_fixed);
+
+void v4l2_clk_unregister_fixed(struct v4l2_clk *clk)
+{
+       kfree(clk->priv);
+       v4l2_clk_unregister(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_unregister_fixed);
index c3f0803..60dcc0f 100644 (file)
@@ -565,13 +565,13 @@ EXPORT_SYMBOL(v4l2_ctrl_get_menu);
  * Returns NULL or an s64 type array containing the menu for given
  * control ID. The total number of the menu items is returned in @len.
  */
-const s64 const *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
+const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
 {
-       static const s64 const qmenu_int_vpx_num_partitions[] = {
+       static const s64 qmenu_int_vpx_num_partitions[] = {
                1, 2, 4, 8,
        };
 
-       static const s64 const qmenu_int_vpx_num_ref_frames[] = {
+       static const s64 qmenu_int_vpx_num_ref_frames[] = {
                1, 2, 3,
        };
 
@@ -583,7 +583,7 @@ const s64 const *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
        default:
                *len = 0;
                return NULL;
-       };
+       }
 }
 EXPORT_SYMBOL(v4l2_ctrl_get_int_menu);
 
index 7c43712..73035ee 100644 (file)
@@ -41,6 +41,8 @@ module_param(debug, bool, 0644);
 #define TRANS_QUEUED           (1 << 0)
 /* Instance is currently running in hardware */
 #define TRANS_RUNNING          (1 << 1)
+/* Instance is currently aborting */
+#define TRANS_ABORT            (1 << 2)
 
 
 /* Offset base for buffers on the destination queue - used to distinguish
@@ -221,6 +223,14 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
        }
 
        spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
+
+       /* If the context is aborted then don't schedule it */
+       if (m2m_ctx->job_flags & TRANS_ABORT) {
+               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+               dprintk("Aborted context\n");
+               return;
+       }
+
        if (m2m_ctx->job_flags & TRANS_QUEUED) {
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("On job queue already\n");
@@ -280,6 +290,8 @@ static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx)
 
        m2m_dev = m2m_ctx->m2m_dev;
        spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+
+       m2m_ctx->job_flags |= TRANS_ABORT;
        if (m2m_ctx->job_flags & TRANS_RUNNING) {
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
                m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
@@ -480,13 +492,15 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        m2m_dev = m2m_ctx->m2m_dev;
        spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
        /* We should not be scheduled anymore, since we're dropping a queue. */
-       INIT_LIST_HEAD(&m2m_ctx->queue);
+       if (m2m_ctx->job_flags & TRANS_QUEUED)
+               list_del(&m2m_ctx->queue);
        m2m_ctx->job_flags = 0;
 
        spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
        /* Drop queue, since streamoff returns device to the same state as after
         * calling reqbufs. */
        INIT_LIST_HEAD(&q_ctx->rdy_queue);
+       q_ctx->num_rdy = 0;
        spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
 
        if (m2m_dev->curr_ctx == m2m_ctx) {
index de0e87f..b19b306 100644 (file)
@@ -241,7 +241,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
                q->bufs[q->num_buffers + buffer] = vb;
        }
 
-       __setup_offsets(q, buffer);
+       if (memory == V4L2_MEMORY_MMAP)
+               __setup_offsets(q, buffer);
 
        dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
                        buffer, num_planes);
@@ -1015,6 +1016,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
                /* Check if the provided plane buffer is large enough */
                if (planes[plane].length < q->plane_sizes[plane]) {
+                       dprintk(1, "qbuf: provided buffer size %u is less than "
+                                               "setup size %u for plane %d\n",
+                                               planes[plane].length,
+                                               q->plane_sizes[plane], plane);
                        ret = -EINVAL;
                        goto err;
                }
@@ -1205,8 +1210,11 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
        int ret;
 
        ret = __verify_length(vb, b);
-       if (ret < 0)
+       if (ret < 0) {
+               dprintk(1, "%s(): plane parameters verification failed: %d\n",
+                       __func__, ret);
                return ret;
+       }
 
        switch (q->memory) {
        case V4L2_MEMORY_MMAP:
@@ -2469,10 +2477,11 @@ size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
 }
 EXPORT_SYMBOL_GPL(vb2_read);
 
-size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
                loff_t *ppos, int nonblocking)
 {
-       return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0);
+       return __vb2_perform_fileio(q, (char __user *) data, count,
+                                                       ppos, nonblocking, 0);
 }
 EXPORT_SYMBOL_GPL(vb2_write);
 
@@ -2633,7 +2642,7 @@ int vb2_fop_release(struct file *file)
 }
 EXPORT_SYMBOL_GPL(vb2_fop_release);
 
-ssize_t vb2_fop_write(struct file *file, char __user *buf,
+ssize_t vb2_fop_write(struct file *file, const char __user *buf,
                size_t count, loff_t *ppos)
 {
        struct video_device *vdev = video_devdata(file);
index 16ae3dc..2f86054 100644 (file)
@@ -35,17 +35,61 @@ struct vb2_dma_sg_buf {
        struct page                     **pages;
        int                             write;
        int                             offset;
-       struct vb2_dma_sg_desc          sg_desc;
+       struct sg_table                 sg_table;
+       size_t                          size;
+       unsigned int                    num_pages;
        atomic_t                        refcount;
        struct vb2_vmarea_handler       handler;
 };
 
 static void vb2_dma_sg_put(void *buf_priv);
 
+static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
+               gfp_t gfp_flags)
+{
+       unsigned int last_page = 0;
+       int size = buf->size;
+
+       while (size > 0) {
+               struct page *pages;
+               int order;
+               int i;
+
+               order = get_order(size);
+               /* Dont over allocate*/
+               if ((PAGE_SIZE << order) > size)
+                       order--;
+
+               pages = NULL;
+               while (!pages) {
+                       pages = alloc_pages(GFP_KERNEL | __GFP_ZERO |
+                                       __GFP_NOWARN | gfp_flags, order);
+                       if (pages)
+                               break;
+
+                       if (order == 0) {
+                               while (last_page--)
+                                       __free_page(buf->pages[last_page]);
+                               return -ENOMEM;
+                       }
+                       order--;
+               }
+
+               split_page(pages, order);
+               for (i = 0; i < (1 << order); i++)
+                       buf->pages[last_page++] = &pages[i];
+
+               size -= PAGE_SIZE << order;
+       }
+
+       return 0;
+}
+
 static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
 {
        struct vb2_dma_sg_buf *buf;
-       int i;
+       int ret;
+       int num_pages;
 
        buf = kzalloc(sizeof *buf, GFP_KERNEL);
        if (!buf)
@@ -54,29 +98,23 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
        buf->vaddr = NULL;
        buf->write = 0;
        buf->offset = 0;
-       buf->sg_desc.size = size;
+       buf->size = size;
        /* size is already page aligned */
-       buf->sg_desc.num_pages = size >> PAGE_SHIFT;
+       buf->num_pages = size >> PAGE_SHIFT;
 
-       buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
-                                     sizeof(*buf->sg_desc.sglist));
-       if (!buf->sg_desc.sglist)
-               goto fail_sglist_alloc;
-       sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
-
-       buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
+       buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
                             GFP_KERNEL);
        if (!buf->pages)
                goto fail_pages_array_alloc;
 
-       for (i = 0; i < buf->sg_desc.num_pages; ++i) {
-               buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO |
-                                          __GFP_NOWARN | gfp_flags);
-               if (NULL == buf->pages[i])
-                       goto fail_pages_alloc;
-               sg_set_page(&buf->sg_desc.sglist[i],
-                           buf->pages[i], PAGE_SIZE, 0);
-       }
+       ret = vb2_dma_sg_alloc_compacted(buf, gfp_flags);
+       if (ret)
+               goto fail_pages_alloc;
+
+       ret = sg_alloc_table_from_pages(&buf->sg_table, buf->pages,
+                       buf->num_pages, 0, size, gfp_flags);
+       if (ret)
+               goto fail_table_alloc;
 
        buf->handler.refcount = &buf->refcount;
        buf->handler.put = vb2_dma_sg_put;
@@ -85,18 +123,16 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
        atomic_inc(&buf->refcount);
 
        dprintk(1, "%s: Allocated buffer of %d pages\n",
-               __func__, buf->sg_desc.num_pages);
+               __func__, buf->num_pages);
        return buf;
 
+fail_table_alloc:
+       num_pages = buf->num_pages;
+       while (num_pages--)
+               __free_page(buf->pages[num_pages]);
 fail_pages_alloc:
-       while (--i >= 0)
-               __free_page(buf->pages[i]);
        kfree(buf->pages);
-
 fail_pages_array_alloc:
-       vfree(buf->sg_desc.sglist);
-
-fail_sglist_alloc:
        kfree(buf);
        return NULL;
 }
@@ -104,14 +140,14 @@ fail_sglist_alloc:
 static void vb2_dma_sg_put(void *buf_priv)
 {
        struct vb2_dma_sg_buf *buf = buf_priv;
-       int i = buf->sg_desc.num_pages;
+       int i = buf->num_pages;
 
        if (atomic_dec_and_test(&buf->refcount)) {
                dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
-                       buf->sg_desc.num_pages);
+                       buf->num_pages);
                if (buf->vaddr)
-                       vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
-               vfree(buf->sg_desc.sglist);
+                       vm_unmap_ram(buf->vaddr, buf->num_pages);
+               sg_free_table(&buf->sg_table);
                while (--i >= 0)
                        __free_page(buf->pages[i]);
                kfree(buf->pages);
@@ -124,7 +160,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 {
        struct vb2_dma_sg_buf *buf;
        unsigned long first, last;
-       int num_pages_from_user, i;
+       int num_pages_from_user;
 
        buf = kzalloc(sizeof *buf, GFP_KERNEL);
        if (!buf)
@@ -133,56 +169,41 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
        buf->vaddr = NULL;
        buf->write = write;
        buf->offset = vaddr & ~PAGE_MASK;
-       buf->sg_desc.size = size;
+       buf->size = size;
 
        first = (vaddr           & PAGE_MASK) >> PAGE_SHIFT;
        last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
-       buf->sg_desc.num_pages = last - first + 1;
-
-       buf->sg_desc.sglist = vzalloc(
-               buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
-       if (!buf->sg_desc.sglist)
-               goto userptr_fail_sglist_alloc;
-
-       sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
+       buf->num_pages = last - first + 1;
 
-       buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
+       buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
                             GFP_KERNEL);
        if (!buf->pages)
-               goto userptr_fail_pages_array_alloc;
+               return NULL;
 
        num_pages_from_user = get_user_pages(current, current->mm,
                                             vaddr & PAGE_MASK,
-                                            buf->sg_desc.num_pages,
+                                            buf->num_pages,
                                             write,
                                             1, /* force */
                                             buf->pages,
                                             NULL);
 
-       if (num_pages_from_user != buf->sg_desc.num_pages)
+       if (num_pages_from_user != buf->num_pages)
                goto userptr_fail_get_user_pages;
 
-       sg_set_page(&buf->sg_desc.sglist[0], buf->pages[0],
-                   PAGE_SIZE - buf->offset, buf->offset);
-       size -= PAGE_SIZE - buf->offset;
-       for (i = 1; i < buf->sg_desc.num_pages; ++i) {
-               sg_set_page(&buf->sg_desc.sglist[i], buf->pages[i],
-                           min_t(size_t, PAGE_SIZE, size), 0);
-               size -= min_t(size_t, PAGE_SIZE, size);
-       }
+       if (sg_alloc_table_from_pages(&buf->sg_table, buf->pages,
+                       buf->num_pages, buf->offset, size, 0))
+               goto userptr_fail_alloc_table_from_pages;
+
        return buf;
 
+userptr_fail_alloc_table_from_pages:
 userptr_fail_get_user_pages:
        dprintk(1, "get_user_pages requested/got: %d/%d]\n",
-              num_pages_from_user, buf->sg_desc.num_pages);
+              num_pages_from_user, buf->num_pages);
        while (--num_pages_from_user >= 0)
                put_page(buf->pages[num_pages_from_user]);
        kfree(buf->pages);
-
-userptr_fail_pages_array_alloc:
-       vfree(buf->sg_desc.sglist);
-
-userptr_fail_sglist_alloc:
        kfree(buf);
        return NULL;
 }
@@ -194,18 +215,18 @@ userptr_fail_sglist_alloc:
 static void vb2_dma_sg_put_userptr(void *buf_priv)
 {
        struct vb2_dma_sg_buf *buf = buf_priv;
-       int i = buf->sg_desc.num_pages;
+       int i = buf->num_pages;
 
        dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
-              __func__, buf->sg_desc.num_pages);
+              __func__, buf->num_pages);
        if (buf->vaddr)
-               vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
+               vm_unmap_ram(buf->vaddr, buf->num_pages);
+       sg_free_table(&buf->sg_table);
        while (--i >= 0) {
                if (buf->write)
                        set_page_dirty_lock(buf->pages[i]);
                put_page(buf->pages[i]);
        }
-       vfree(buf->sg_desc.sglist);
        kfree(buf->pages);
        kfree(buf);
 }
@@ -218,7 +239,7 @@ static void *vb2_dma_sg_vaddr(void *buf_priv)
 
        if (!buf->vaddr)
                buf->vaddr = vm_map_ram(buf->pages,
-                                       buf->sg_desc.num_pages,
+                                       buf->num_pages,
                                        -1,
                                        PAGE_KERNEL);
 
@@ -274,7 +295,7 @@ static void *vb2_dma_sg_cookie(void *buf_priv)
 {
        struct vb2_dma_sg_buf *buf = buf_priv;
 
-       return &buf->sg_desc;
+       return &buf->sg_table;
 }
 
 const struct vb2_mem_ops vb2_dma_sg_memops = {
index b6cb593..cbea5d8 100644 (file)
@@ -2,6 +2,11 @@
   (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
   example of a previously completed port).
 
+- lirc_bt829 uses registers on a Mach64 VT, which has a separate kernel
+  framebuffer driver (atyfb) and userland X driver (mach64).  It can't
+  simply be converted to a normal PCI driver, but ideally it should be
+  coordinated with the other drivers.
+
 Please send patches to:
 Jarod Wilson <jarod@wilsonet.com>
 Greg Kroah-Hartman <greg@kroah.com>
index fbbdce4..30edc74 100644 (file)
@@ -63,7 +63,7 @@ static bool debug;
        } while (0)
 
 static int atir_minor;
-static unsigned long pci_addr_phys;
+static phys_addr_t pci_addr_phys;
 static unsigned char *pci_addr_lin;
 
 static struct lirc_driver atir_driver;
@@ -78,11 +78,11 @@ static struct pci_dev *do_pci_probe(void)
                pci_addr_phys = 0;
                if (my_dev->resource[0].flags & IORESOURCE_MEM) {
                        pci_addr_phys = my_dev->resource[0].start;
-                       pr_info("memory at 0x%08X\n",
-                              (unsigned int)pci_addr_phys);
+                       pr_info("memory at %pa\n", &pci_addr_phys);
                }
                if (pci_addr_phys == 0) {
                        pr_err("no memory resource ?\n");
+                       pci_dev_put(my_dev);
                        return NULL;
                }
        } else {
@@ -120,13 +120,20 @@ static void atir_set_use_dec(void *data)
 int init_module(void)
 {
        struct pci_dev *pdev;
+       int rc;
 
        pdev = do_pci_probe();
        if (pdev == NULL)
                return -ENODEV;
 
-       if (!atir_init_start())
-               return -ENODEV;
+       rc = pci_enable_device(pdev);
+       if (rc)
+               goto err_put_dev;
+
+       if (!atir_init_start()) {
+               rc = -ENODEV;
+               goto err_disable;
+       }
 
        strcpy(atir_driver.name, "ATIR");
        atir_driver.minor       = -1;
@@ -142,17 +149,31 @@ int init_module(void)
        atir_minor = lirc_register_driver(&atir_driver);
        if (atir_minor < 0) {
                pr_err("failed to register driver!\n");
-               return atir_minor;
+               rc = atir_minor;
+               goto err_unmap;
        }
        dprintk("driver is registered on minor %d\n", atir_minor);
 
        return 0;
+
+err_unmap:
+       iounmap(pci_addr_lin);
+err_disable:
+       pci_disable_device(pdev);
+err_put_dev:
+       pci_dev_put(pdev);
+       return rc;
 }
 
 
 void cleanup_module(void)
 {
+       struct pci_dev *pdev = to_pci_dev(atir_driver.dev);
+
        lirc_unregister_driver(atir_minor);
+       iounmap(pci_addr_lin);
+       pci_disable_device(pdev);
+       pci_dev_put(pdev);
 }
 
 
index 76d5bbd..0c349c8 100644 (file)
@@ -1,4 +1,5 @@
 config USB_MSI3101
        tristate "Mirics MSi3101 SDR Dongle"
        depends on USB && VIDEO_DEV && VIDEO_V4L2
-        select VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_CORE
+       select VIDEOBUF2_VMALLOC
index 32d9953..145295a 100644 (file)
@@ -176,18 +176,27 @@ static void solo_vout_config(struct solo_dev *solo_dev)
 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
                               u16 val, int reg_size)
 {
-       u16 buf[64];
-       int i;
-       int ret = 0;
+       u16 *buf;
+       const int n = 64, size = n * sizeof(*buf);
+       int i, ret = 0;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       for (i = 0; i < sizeof(buf) >> 1; i++)
+       for (i = 0; i < n; i++)
                buf[i] = cpu_to_le16(val);
 
-       for (i = 0; i < reg_size; i += sizeof(buf))
-               ret |= solo_p2m_dma(solo_dev, 1, buf,
-                                   SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
-                                   sizeof(buf), 0, 0);
+       for (i = 0; i < reg_size; i += size) {
+               ret = solo_p2m_dma(solo_dev, 1, buf,
+                                  SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
+                                  size, 0, 0);
+
+               if (ret)
+                       break;
+       }
 
+       kfree(buf);
        return ret;
 }
 
index a4c5896..d582c5b 100644 (file)
@@ -95,38 +95,11 @@ static unsigned char vop_6110_pal_cif[] = {
        0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
 };
 
-struct vop_header {
-       /* VE_STATUS0 */
-       u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2,
-               channel:5, source_fl:1, interlace:1, progressive:1;
-
-       /* VE_STATUS1 */
-       u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4;
-
-       /* VE_STATUS2 */
-       u32 mpeg_off;
-
-       /* VE_STATUS3 */
-       u32 jpeg_off;
-
-       /* VE_STATUS4 */
-       u32 jpeg_size:20, interval:10, nop1:2;
-
-       /* VE_STATUS5/6 */
-       u32 sec, usec;
-
-       /* VE_STATUS7/8/9 */
-       u32 nop2[3];
-
-       /* VE_STATUS10 */
-       u32 mpeg_size_alt:20, nop3:12;
-
-       u32 end_nops[5];
-} __packed;
+typedef __le32 vop_header[16];
 
 struct solo_enc_buf {
        enum solo_enc_types     type;
-       struct vop_header       *vh;
+       const vop_header        *vh;
        int                     motion;
 };
 
@@ -346,7 +319,7 @@ static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
 /* Build a descriptor queue out of an SG list and send it to the P2M for
  * processing. */
 static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
-                         struct vb2_dma_sg_desc *vbuf, int off, int size,
+                         struct sg_table *vbuf, int off, int size,
                          unsigned int base, unsigned int base_size)
 {
        struct solo_dev *solo_dev = solo_enc->solo_dev;
@@ -359,7 +332,7 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
 
        solo_enc->desc_count = 1;
 
-       for_each_sg(vbuf->sglist, sg, vbuf->num_pages, i) {
+       for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
                struct solo_p2m_desc *desc;
                dma_addr_t dma;
                int len;
@@ -430,84 +403,145 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
                                 solo_enc->desc_count - 1);
 }
 
+/* Extract values from VOP header - VE_STATUSxx */
+static inline int vop_interlaced(const vop_header *vh)
+{
+       return (__le32_to_cpu((*vh)[0]) >> 30) & 1;
+}
+
+static inline u8 vop_channel(const vop_header *vh)
+{
+       return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F;
+}
+
+static inline u8 vop_type(const vop_header *vh)
+{
+       return (__le32_to_cpu((*vh)[0]) >> 22) & 3;
+}
+
+static inline u32 vop_mpeg_size(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[0]) & 0xFFFFF;
+}
+
+static inline u8 vop_hsize(const vop_header *vh)
+{
+       return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF;
+}
+
+static inline u8 vop_vsize(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[1]) & 0xFF;
+}
+
+static inline u32 vop_mpeg_offset(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[2]);
+}
+
+static inline u32 vop_jpeg_offset(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[3]);
+}
+
+static inline u32 vop_jpeg_size(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[4]) & 0xFFFFF;
+}
+
+static inline u32 vop_sec(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[5]);
+}
+
+static inline u32 vop_usec(const vop_header *vh)
+{
+       return __le32_to_cpu((*vh)[6]);
+}
+
 static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
-               struct vb2_buffer *vb, struct vop_header *vh)
+                         struct vb2_buffer *vb, const vop_header *vh)
 {
        struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+       struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
        int frame_size;
        int ret;
 
        vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
 
-       if (vb2_plane_size(vb, 0) < vh->jpeg_size + solo_enc->jpeg_len)
+       if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
                return -EIO;
 
-       sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages,
-                       solo_enc->jpeg_header,
-                       solo_enc->jpeg_len);
-
-       frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1))
+       frame_size = (vop_jpeg_size(vh) + solo_enc->jpeg_len + (DMA_ALIGN - 1))
                & ~(DMA_ALIGN - 1);
-       vb2_set_plane_payload(vb, 0, vh->jpeg_size + solo_enc->jpeg_len);
+       vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
 
-       dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+       /* may discard all previous data in vbuf->sgl */
+       dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
                        DMA_FROM_DEVICE);
-       ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off,
-                       frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
-                       SOLO_JPEG_EXT_SIZE(solo_dev));
-       dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+       ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
+                            vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
+                            frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
+                            SOLO_JPEG_EXT_SIZE(solo_dev));
+       dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
                        DMA_FROM_DEVICE);
+
+       /* add the header only after dma_unmap_sg() */
+       sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+                           solo_enc->jpeg_header, solo_enc->jpeg_len);
+
        return ret;
 }
 
 static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
-               struct vb2_buffer *vb, struct vop_header *vh)
+               struct vb2_buffer *vb, const vop_header *vh)
 {
        struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+       struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
        int frame_off, frame_size;
        int skip = 0;
        int ret;
 
-       if (vb2_plane_size(vb, 0) < vh->mpeg_size)
+       if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
                return -EIO;
 
        /* If this is a key frame, add extra header */
-       if (!vh->vop_type) {
-               sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages,
-                               solo_enc->vop,
-                               solo_enc->vop_len);
-
+       vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
+       if (!vop_type(vh)) {
                skip = solo_enc->vop_len;
-
                vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-               vb2_set_plane_payload(vb, 0, vh->mpeg_size + solo_enc->vop_len);
+               vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) + solo_enc->vop_len);
        } else {
                vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-               vb2_set_plane_payload(vb, 0, vh->mpeg_size);
+               vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
        }
 
        /* Now get the actual mpeg payload */
-       frame_off = (vh->mpeg_off + sizeof(*vh))
+       frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) + sizeof(*vh))
                % SOLO_MP4E_EXT_SIZE(solo_dev);
-       frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1))
+       frame_size = (vop_mpeg_size(vh) + skip + (DMA_ALIGN - 1))
                & ~(DMA_ALIGN - 1);
 
-       dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+       /* may discard all previous data in vbuf->sgl */
+       dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
                        DMA_FROM_DEVICE);
        ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
                        SOLO_MP4E_EXT_ADDR(solo_dev),
                        SOLO_MP4E_EXT_SIZE(solo_dev));
-       dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+       dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
                        DMA_FROM_DEVICE);
+
+       /* add the header only after dma_unmap_sg() */
+       if (!vop_type(vh))
+               sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+                                   solo_enc->vop, solo_enc->vop_len);
        return ret;
 }
 
 static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
                            struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
 {
-       struct vop_header *vh = enc_buf->vh;
+       const vop_header *vh = enc_buf->vh;
        int ret;
 
        /* Check for motion flags */
@@ -531,8 +565,8 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
 
        if (!ret) {
                vb->v4l2_buf.sequence = solo_enc->sequence++;
-               vb->v4l2_buf.timestamp.tv_sec = vh->sec;
-               vb->v4l2_buf.timestamp.tv_usec = vh->usec;
+               vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
+               vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
        }
 
        vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
@@ -605,15 +639,13 @@ static void solo_handle_ring(struct solo_dev *solo_dev)
 
                /* FAIL... */
                if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
-                                    sizeof(struct vop_header)))
+                                    sizeof(vop_header)))
                        continue;
 
-               enc_buf.vh = (struct vop_header *)solo_dev->vh_buf;
-               enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev);
-               enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev);
+               enc_buf.vh = solo_dev->vh_buf;
 
                /* Sanity check */
-               if (enc_buf.vh->mpeg_off != off)
+               if (vop_mpeg_offset(enc_buf.vh) != SOLO_MP4E_EXT_ADDR(solo_dev) + off)
                        continue;
 
                if (solo_motion_detected(solo_enc))
@@ -1329,7 +1361,7 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
 
        init_waitqueue_head(&solo_dev->ring_thread_wait);
 
-       solo_dev->vh_size = sizeof(struct vop_header);
+       solo_dev->vh_size = sizeof(vop_header);
        solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
                                                solo_dev->vh_size,
                                                &solo_dev->vh_dma);
index 6f91d2e..f1bbb8c 100644 (file)
@@ -94,7 +94,6 @@
 #define SOLO_ENC_MODE_HD1              1
 #define SOLO_ENC_MODE_D1               9
 
-#define SOLO_DEFAULT_GOP               30
 #define SOLO_DEFAULT_QP                        3
 
 #ifndef V4L2_BUF_FLAG_MOTION_ON
diff --git a/include/media/lm3560.h b/include/media/lm3560.h
new file mode 100644 (file)
index 0000000..4667070
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * include/media/lm3560.h
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ *                     Ldd-Mlp <ldd-mlp@list.ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __LM3560_H__
+#define __LM3560_H__
+
+#include <media/v4l2-subdev.h>
+
+#define LM3560_NAME    "lm3560"
+#define LM3560_I2C_ADDR        (0x53)
+
+/*  FLASH Brightness
+ *     min 62500uA, step 62500uA, max 1000000uA
+ */
+#define LM3560_FLASH_BRT_MIN 62500
+#define LM3560_FLASH_BRT_STEP 62500
+#define LM3560_FLASH_BRT_MAX 1000000
+#define LM3560_FLASH_BRT_uA_TO_REG(a)  \
+       ((a) < LM3560_FLASH_BRT_MIN ? 0 :       \
+        (((a) - LM3560_FLASH_BRT_MIN) / LM3560_FLASH_BRT_STEP))
+#define LM3560_FLASH_BRT_REG_TO_uA(a)          \
+       ((a) * LM3560_FLASH_BRT_STEP + LM3560_FLASH_BRT_MIN)
+
+/*  FLASH TIMEOUT DURATION
+ *     min 32ms, step 32ms, max 1024ms
+ */
+#define LM3560_FLASH_TOUT_MIN 32
+#define LM3560_FLASH_TOUT_STEP 32
+#define LM3560_FLASH_TOUT_MAX 1024
+#define LM3560_FLASH_TOUT_ms_TO_REG(a) \
+       ((a) < LM3560_FLASH_TOUT_MIN ? 0 :      \
+        (((a) - LM3560_FLASH_TOUT_MIN) / LM3560_FLASH_TOUT_STEP))
+#define LM3560_FLASH_TOUT_REG_TO_ms(a)         \
+       ((a) * LM3560_FLASH_TOUT_STEP + LM3560_FLASH_TOUT_MIN)
+
+/*  TORCH BRT
+ *     min 31250uA, step 31250uA, max 250000uA
+ */
+#define LM3560_TORCH_BRT_MIN 31250
+#define LM3560_TORCH_BRT_STEP 31250
+#define LM3560_TORCH_BRT_MAX 250000
+#define LM3560_TORCH_BRT_uA_TO_REG(a)  \
+       ((a) < LM3560_TORCH_BRT_MIN ? 0 :       \
+        (((a) - LM3560_TORCH_BRT_MIN) / LM3560_TORCH_BRT_STEP))
+#define LM3560_TORCH_BRT_REG_TO_uA(a)          \
+       ((a) * LM3560_TORCH_BRT_STEP + LM3560_TORCH_BRT_MIN)
+
+enum lm3560_led_id {
+       LM3560_LED0 = 0,
+       LM3560_LED1,
+       LM3560_LED_MAX
+};
+
+enum lm3560_peak_current {
+       LM3560_PEAK_1600mA = 0x00,
+       LM3560_PEAK_2300mA = 0x20,
+       LM3560_PEAK_3000mA = 0x40,
+       LM3560_PEAK_3600mA = 0x60
+};
+
+/* struct lm3560_platform_data
+ *
+ * @peak :  peak current
+ * @max_flash_timeout: flash timeout
+ * @max_flash_brt: flash mode led brightness
+ * @max_torch_brt: torch mode led brightness
+ */
+struct lm3560_platform_data {
+       enum lm3560_peak_current peak;
+
+       u32 max_flash_timeout;
+       u32 max_flash_brt[LM3560_LED_MAX];
+       u32 max_torch_brt[LM3560_LED_MAX];
+};
+
+#endif /* __LM3560_H__ */
index 34d2414..865246b 100644 (file)
@@ -146,9 +146,14 @@ struct soc_camera_subdev_desc {
        /* sensor driver private platform data */
        void *drv_priv;
 
-       /* Optional regulators that have to be managed on power on/off events */
-       struct regulator_bulk_data *regulators;
-       int num_regulators;
+       /*
+        * Set unbalanced_power to true to deal with legacy drivers, failing to
+        * balance their calls to subdevice's .s_power() method. clock_state is
+        * then used internally by helper functions, it shouldn't be touched by
+        * drivers or the platform code.
+        */
+       bool unbalanced_power;
+       unsigned long clock_state;
 
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
@@ -162,6 +167,9 @@ struct soc_camera_subdev_desc {
        int (*set_bus_param)(struct soc_camera_subdev_desc *, unsigned long flags);
        unsigned long (*query_bus_param)(struct soc_camera_subdev_desc *);
        void (*free_bus)(struct soc_camera_subdev_desc *);
+
+       /* Optional regulators that have to be managed on power on/off events */
+       struct v4l2_subdev_platform_data sd_pdata;
 };
 
 struct soc_camera_host_desc {
@@ -202,9 +210,10 @@ struct soc_camera_link {
 
        void *priv;
 
-       /* Optional regulators that have to be managed on power on/off events */
-       struct regulator_bulk_data *regulators;
-       int num_regulators;
+       /* Set by platforms to handle misbehaving drivers */
+       bool unbalanced_power;
+       /* Used by soc-camera helper functions */
+       unsigned long clock_state;
 
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
@@ -218,6 +227,12 @@ struct soc_camera_link {
        unsigned long (*query_bus_param)(struct soc_camera_link *);
        void (*free_bus)(struct soc_camera_link *);
 
+       /* Optional regulators that have to be managed on power on/off events */
+       struct regulator_bulk_data *regulators;
+       int num_regulators;
+
+       void *host_priv;
+
        /*
         * Host part - keep at bottom and compatible to
         * struct soc_camera_host_desc
index 0503a90..0b36cc1 100644 (file)
@@ -15,6 +15,7 @@
 #define MEDIA_V4L2_CLK_H
 
 #include <linux/atomic.h>
+#include <linux/export.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 
@@ -51,4 +52,20 @@ void v4l2_clk_disable(struct v4l2_clk *clk);
 unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk);
 int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate);
 
+struct module;
+
+struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id,
+               const char *id, unsigned long rate, struct module *owner);
+void v4l2_clk_unregister_fixed(struct v4l2_clk *clk);
+
+static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id,
+                                                       const char *id,
+                                                       unsigned long rate)
+{
+       return __v4l2_clk_register_fixed(dev_id, id, rate, THIS_MODULE);
+}
+
+#define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \
+                         "%d-%04x", adap, client)
+
 #endif
index 16550c4..b87692c 100644 (file)
@@ -86,7 +86,7 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
                const char * const *menu_items);
 const char *v4l2_ctrl_get_name(u32 id);
 const char * const *v4l2_ctrl_get_menu(u32 id);
-const s64 const *v4l2_ctrl_get_int_menu(u32 id, u32 *len);
+const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
                struct v4l2_queryctrl *qctrl, const char * const *menu_items);
index 47ada23..16f7f26 100644 (file)
@@ -571,7 +571,7 @@ static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)
        mutex_lock(ctrl->handler->lock);
 }
 
-/** v4l2_ctrl_lock() - Helper function to unlock the handler
+/** v4l2_ctrl_unlock() - Helper function to unlock the handler
   * associated with the control.
   * @ctrl:     The control to unlock.
   */
index a62ee18..528cdaf 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef V4L2_FH_H
 #define V4L2_FH_H
 
+#include <linux/fs.h>
 #include <linux/list.h>
+#include <linux/videodev2.h>
 
 struct video_device;
 struct v4l2_ctrl_handler;
index bfda0fe..d67210a 100644 (file)
@@ -559,6 +559,17 @@ struct v4l2_subdev_internal_ops {
 /* Set this flag if this subdev generates events. */
 #define V4L2_SUBDEV_FL_HAS_EVENTS              (1U << 3)
 
+struct regulator_bulk_data;
+
+struct v4l2_subdev_platform_data {
+       /* Optional regulators uset to power on/off the subdevice */
+       struct regulator_bulk_data *regulators;
+       int num_regulators;
+
+       /* Per-subdevice data, specific for a certain video host device */
+       void *host_priv;
+};
+
 /* Each instance of a subdev driver should create this struct, either
    stand-alone or embedded in a larger struct.
  */
@@ -592,6 +603,8 @@ struct v4l2_subdev {
        struct v4l2_async_subdev *asd;
        /* Pointer to the managing notifier. */
        struct v4l2_async_notifier *notifier;
+       /* common part of subdevice platform data */
+       struct v4l2_subdev_platform_data *pdata;
 };
 
 #define media_entity_to_v4l2_subdev(ent) \
@@ -622,13 +635,13 @@ struct v4l2_subdev_fh {
        v4l2_subdev_get_try_##fun_name(struct v4l2_subdev_fh *fh,       \
                                       unsigned int pad)                \
        {                                                               \
-               BUG_ON(unlikely(pad >= vdev_to_v4l2_subdev(             \
-                                       fh->vfh.vdev)->entity.num_pads)); \
+               BUG_ON(pad >= vdev_to_v4l2_subdev(                      \
+                                       fh->vfh.vdev)->entity.num_pads); \
                return &fh->pad[pad].field_name;                        \
        }
 
 __V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, format, try_fmt)
-__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_compose)
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_crop)
 __V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, compose, try_compose)
 #endif
 
index 6781258..bd8218b 100644 (file)
@@ -391,7 +391,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
 size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
                loff_t *ppos, int nonblock);
-size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
                loff_t *ppos, int nonblock);
 
 /**
@@ -491,7 +491,7 @@ int vb2_ioctl_expbuf(struct file *file, void *priv,
 
 int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma);
 int vb2_fop_release(struct file *file);
-ssize_t vb2_fop_write(struct file *file, char __user *buf,
+ssize_t vb2_fop_write(struct file *file, const char __user *buf,
                size_t count, loff_t *ppos);
 ssize_t vb2_fop_read(struct file *file, char __user *buf,
                size_t count, loff_t *ppos);
index 0038526..7b89852 100644 (file)
 
 #include <media/videobuf2-core.h>
 
-struct vb2_dma_sg_desc {
-       unsigned long           size;
-       unsigned int            num_pages;
-       struct scatterlist      *sglist;
-};
-
-static inline struct vb2_dma_sg_desc *vb2_dma_sg_plane_desc(
+static inline struct sg_table *vb2_dma_sg_plane_desc(
                struct vb2_buffer *vb, unsigned int plane_no)
 {
-       return (struct vb2_dma_sg_desc *)vb2_plane_cookie(vb, plane_no);
+       return (struct sg_table *)vb2_plane_cookie(vb, plane_no);
 }
 
 extern const struct vb2_mem_ops vb2_dma_sg_memops;
index 083bb5a..1666aab 100644 (file)
@@ -160,6 +160,10 @@ enum v4l2_colorfx {
  * of controls. Total of 16 controls is reserved for this driver */
 #define V4L2_CID_USER_SI476X_BASE              (V4L2_CID_USER_BASE + 0x1040)
 
+/* The base for the TI VPE driver controls. Total of 16 controls is reserved for
+ * this driver */
+#define V4L2_CID_USER_TI_VPE_BASE              (V4L2_CID_USER_BASE + 0x1050)
+
 /* MPEG-class control IDs */
 /* The MPEG controls are applicable to all codec controls
  * and the 'MPEG' part of the define is historical */