]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'v4.11-rc1' into patchwork
authorMauro Carvalho Chehab <mchehab@s-opensource.com>
Mon, 6 Mar 2017 09:49:34 +0000 (06:49 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Mon, 6 Mar 2017 09:49:34 +0000 (06:49 -0300)
Linux 4.11-rc1

* tag 'v4.11-rc1': (10730 commits)
  Linux 4.11-rc1
  strparser: destroy workqueue on module exit
  Documentation/sphinx: fix primary_domain configuration
  docs: Fix htmldocs build failure
  doc/ko_KR/memory-barriers: Update control-dependencies section
  pcieaer doc: update the link
  Documentation: Update path to sysrq.txt
  sfc: fix IPID endianness in TSOv2
  sfc: avoid max() in array size
  rds: remove unnecessary returned value check
  rxrpc: Fix potential NULL-pointer exception
  nfp: correct DMA direction in XDP DMA sync
  nfp: don't tell FW about the reserved buffer space
  net: ethernet: bgmac: mac address change bug
  net: ethernet: bgmac: init sequence bug
  xen-netback: don't vfree() queues under spinlock
  xen-netback: keep a local pointer for vif in backend_disconnect()
  netfilter: nf_tables: don't call nfnetlink_set_err() if nfnetlink_send() fails
  netfilter: nft_set_rbtree: incorrect assumption on lower interval lookups
  netfilter: nf_conntrack_sip: fix wrong memory initialisation
  ...

49 files changed:
Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt [new file with mode: 0644]
Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst
Documentation/media/v4l-drivers/vivid.rst
MAINTAINERS
drivers/media/common/tveeprom.c
drivers/media/dvb-frontends/si2168.c
drivers/media/dvb-frontends/si2168_priv.h
drivers/media/i2c/tc358743.c
drivers/media/pci/bt8xx/bttv-cards.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx88/cx88-cards.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/saa7134/saa7134-cards.c
drivers/media/pci/saa7164/saa7164-cards.c
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/atmel/atmel-isc-regs.h
drivers/media/platform/atmel/atmel-isc.c
drivers/media/platform/coda/imx-vdoa.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/mtk-jpeg/Makefile [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h [new file with mode: 0644]
drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h [new file with mode: 0644]
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/ti-vpe/vpdma.h
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/vivid/Kconfig
drivers/media/platform/vivid/vivid-core.c
drivers/media/tuners/si2157.c
drivers/media/tuners/si2157_priv.h
drivers/media/usb/au0828/au0828-cards.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-i2c.c
drivers/media/usb/dvb-usb-v2/mxl111sf.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
drivers/staging/media/bcm2048/radio-bcm2048.c
drivers/staging/media/omap4iss/iss_video.c
include/media/tveeprom.h
include/uapi/linux/cec.h

diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
new file mode 100644 (file)
index 0000000..3813947
--- /dev/null
@@ -0,0 +1,37 @@
+* Mediatek JPEG Decoder
+
+Mediatek JPEG Decoder is the JPEG decode hardware present in Mediatek SoCs
+
+Required properties:
+- compatible : must be one of the following string:
+       "mediatek,mt8173-jpgdec"
+       "mediatek,mt2701-jpgdec"
+- reg : physical base address of the jpeg decoder registers and length of
+  memory mapped region.
+- interrupts : interrupt number to the interrupt controller.
+- clocks: device clocks, see
+  Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+- clock-names: must contain "jpgdec-smi" and "jpgdec".
+- power-domains: a phandle to the power domain, see
+  Documentation/devicetree/bindings/power/power_domain.txt for details.
+- mediatek,larb: must contain the local arbiters in the current Socs, see
+  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+  for details.
+- iommus: should point to the respective IOMMU block with master port as
+  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+  for details.
+
+Example:
+       jpegdec: jpegdec@15004000 {
+               compatible = "mediatek,mt2701-jpgdec";
+               reg = <0 0x15004000 0 0x1000>;
+               interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_LOW>;
+               clocks =  <&imgsys CLK_IMG_JPGDEC_SMI>,
+                         <&imgsys CLK_IMG_JPGDEC>;
+               clock-names = "jpgdec-smi",
+                             "jpgdec";
+               power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+               mediatek,larb = <&larb2>;
+               iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>,
+                        <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>;
+       };
index aea276502f5e91409a64cea183e333db92840f76..e573c74138dee05afff4493891d9b54ed5baa13c 100644 (file)
@@ -146,8 +146,20 @@ EBUSY
       - ``flags``
       - Several flags giving more information about the format. See
        :ref:`dv-bt-flags` for a description of the flags.
-    * - __u32
-      - ``reserved[14]``
+    * - struct :c:type:`v4l2_fract`
+      - ``picture_aspect``
+      - The picture aspect if the pixels are not square. Only valid if the
+        ``V4L2_DV_FL_HAS_PICTURE_ASPECT`` flag is set.
+    * - __u8
+      - ``cea861_vic``
+      - The Video Identification Code according to the CEA-861 standard.
+        Only valid if the ``V4L2_DV_FL_HAS_CEA861_VIC`` flag is set.
+    * - __u8
+      - ``hdmi_vic``
+      - The Video Identification Code according to the HDMI standard.
+        Only valid if the ``V4L2_DV_FL_HAS_HDMI_VIC`` flag is set.
+    * - __u8
+      - ``reserved[46]``
       - Reserved for future extensions. Drivers and applications must set
        the array to zero.
 
index c8cf371e8bb91cd71d9d168265f6f54a6bfacffe..3e44b2217f2d33dbd1a57d3aa675a99fc4741e62 100644 (file)
@@ -263,6 +263,14 @@ all configurable using the following module options:
        removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the
        will default to enabling crop, compose and scaling.
 
+- allocators:
+
+       memory allocator selection, default is 0. It specifies the way buffers
+       will be allocated.
+
+               - 0: vmalloc
+               - 1: dma-contig
+
 Taken together, all these module options allow you to precisely customize
 the driver behavior and test your application with all sorts of permutations.
 It is also very suitable to emulate hardware that is not yet available, e.g.
index c265a5fe48481f548629079cb529137e0a377f31..83a42ef1d1a7e369f8c666470e1ab80184b051ad 100644 (file)
@@ -8093,6 +8093,13 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/mediatek/
 
+MEDIATEK JPEG DRIVER
+M:     Rick Chang <rick.chang@mediatek.com>
+M:     Bin Liu <bin.liu@mediatek.com>
+S:     Supported
+F:     drivers/media/platform/mtk-jpeg/
+F:     Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
+
 MEDIATEK MEDIA DRIVER
 M:     Tiffany Lin <tiffany.lin@mediatek.com>
 M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
index 6e1020227f9fe7d5f4843902509b6b3e845b01f5..ccf2d3b12aec56666ff3928997bb2df8c35e2ff3 100644 (file)
@@ -420,8 +420,8 @@ static int hasRadioTuner(int tunerType)
        return 0;
 }
 
-void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
-                               unsigned char *eeprom_data)
+void tveeprom_hauppauge_analog(struct tveeprom *tvee,
+                              unsigned char *eeprom_data)
 {
        /* ----------------------------------------------
        ** The hauppauge eeprom format is tagged
index 680ba06c29fb57610b6804d9b233f7a4458ada23..172fc367ccaaccdedadba19f9343e48e364ef06a 100644 (file)
@@ -740,6 +740,9 @@ static int si2168_probe(struct i2c_client *client,
        case SI2168_CHIP_ID_B40:
                dev->firmware_name = SI2168_B40_FIRMWARE;
                break;
+       case SI2168_CHIP_ID_D60:
+               dev->firmware_name = SI2168_D60_FIRMWARE;
+               break;
        default:
                dev_dbg(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
                        cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
@@ -827,3 +830,4 @@ MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(SI2168_A20_FIRMWARE);
 MODULE_FIRMWARE(SI2168_A30_FIRMWARE);
 MODULE_FIRMWARE(SI2168_B40_FIRMWARE);
+MODULE_FIRMWARE(SI2168_D60_FIRMWARE);
index 2fecac6231ff47dce1cb6c71fd9147fe4d975f24..737cf416fbb22b293d17cc2999fbf4559653ad20 100644 (file)
@@ -26,6 +26,7 @@
 #define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw"
 #define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw"
 #define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw"
+#define SI2168_D60_FIRMWARE "dvb-demod-si2168-d60-01.fw"
 #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
 
 /* state struct */
@@ -38,6 +39,7 @@ struct si2168_dev {
        #define SI2168_CHIP_ID_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0)
        #define SI2168_CHIP_ID_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0)
        #define SI2168_CHIP_ID_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0)
+       #define SI2168_CHIP_ID_D60 ('D' << 24 | 68 << 16 | '6' << 8 | '0' << 0)
        unsigned int chip_id;
        unsigned int version;
        const char *firmware_name;
index f569a05fe10547e4ffc159bbce96d5765ae9e40b..140c804a6dc34dc858a0d70bcca13c942da9fe82 100644 (file)
@@ -194,57 +194,61 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
        }
 }
 
-static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
 {
-       u8 val;
+       __le32 val = 0;
 
-       i2c_rd(sd, reg, &val, 1);
+       i2c_rd(sd, reg, (u8 __force *)&val, n);
 
-       return val;
+       return le32_to_cpu(val);
+}
+
+static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
+{
+       __le32 raw = cpu_to_le32(val);
+
+       i2c_wr(sd, reg, (u8 __force *)&raw, n);
+}
+
+static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+{
+       return i2c_rdreg(sd, reg, 1);
 }
 
 static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
-       i2c_wr(sd, reg, &val, 1);
+       i2c_wrreg(sd, reg, val, 1);
 }
 
 static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
                u8 mask, u8 val)
 {
-       i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val);
+       i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
 }
 
 static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
 {
-       u16 val;
-
-       i2c_rd(sd, reg, (u8 *)&val, 2);
-
-       return val;
+       return i2c_rdreg(sd, reg, 2);
 }
 
 static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
 {
-       i2c_wr(sd, reg, (u8 *)&val, 2);
+       i2c_wrreg(sd, reg, val, 2);
 }
 
 static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
 {
-       i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val);
+       i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
 }
 
 static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
 {
-       u32 val;
-
-       i2c_rd(sd, reg, (u8 *)&val, 4);
-
-       return val;
+       return i2c_rdreg(sd, reg, 4);
 }
 
 static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
 {
-       i2c_wr(sd, reg, (u8 *)&val, 4);
+       i2c_wrreg(sd, reg, val, 4);
 }
 
 /* --------------- STATUS --------------- */
@@ -1227,7 +1231,7 @@ static int tc358743_g_register(struct v4l2_subdev *sd,
 
        reg->size = tc358743_get_reg_size(reg->reg);
 
-       i2c_rd(sd, reg->reg, (u8 *)&reg->val, reg->size);
+       reg->val = i2c_rdreg(sd, reg->reg, reg->size);
 
        return 0;
 }
@@ -1253,7 +1257,7 @@ static int tc358743_s_register(struct v4l2_subdev *sd,
            reg->reg == BCAPS)
                return 0;
 
-       i2c_wr(sd, (u16)reg->reg, (u8 *)&reg->val,
+       i2c_wrreg(sd, (u16)reg->reg, reg->val,
                        tc358743_get_reg_size(reg->reg));
 
        return 0;
index a1b0f3193bc069cee54fb7083a4036e56a675bdf..5cc42b426715841ef2cf7c3d94972106e6e1ff72 100644 (file)
@@ -3717,7 +3717,7 @@ static void hauppauge_eeprom(struct bttv *btv)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
        btv->tuner_type = tv.tuner_type;
        btv->has_radio  = tv.has_radio;
 
index 206db81ef78eb7723192adc4abfe9f6b4d87bd67..8bce49cdad46873d4eeffe09e474e0e146fc8b58 100644 (file)
@@ -339,7 +339,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
        case CX18_CARD_HVR_1600_ESMT:
        case CX18_CARD_HVR_1600_SAMSUNG:
        case CX18_CARD_HVR_1600_S5H1411:
-               tveeprom_hauppauge_analog(c, tv, eedata);
+               tveeprom_hauppauge_analog(tv, eedata);
                break;
        case CX18_CARD_YUAN_MPC718:
        case CX18_CARD_GOTVIEW_PCI_DVD3:
index 0350f13c5a9fe7b77d9cb1d7cb04311fc6bde6dc..9e39aea85df6b6fe5cb647c0b8500027f84e60ab 100644 (file)
@@ -1143,8 +1143,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
-               eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
 
        /* Make sure we support the board model */
        switch (tv.model) {
index cdfbde277b8bab2cdaa5c32b3fa36b53ba9fc5b3..61e1803882d9b174f503e148f8a6b00ce52cdd8e 100644 (file)
@@ -2854,7 +2854,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
        core->board.tuner_type = tv.tuner_type;
        core->tuner_formats = tv.tuner_formats;
        core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
index e73c153285f0d506d8d78f4c3674d013cdc12d4b..a71a03e223859513b5f4a5450511275d2a979f75 100644 (file)
@@ -409,7 +409,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
 
        itv->i2c_client.addr = 0xA0 >> 1;
        tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata));
-       tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata);
+       tveeprom_hauppauge_analog(tv, eedata);
 }
 
 static void ivtv_process_eeprom(struct ivtv *itv)
index 321253827997a2c163893126e9ef444c355c50d6..f79380faf499e309350fc9eedcbe40e9a6818e37 100644 (file)
@@ -7319,7 +7319,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
 
        /* Make sure we support the board model */
        switch (tv.model) {
index 0e1cd7e153ca83ba08c13061eabd38f179a58d5c..3af16062e79dce44ef8d0626a9c07c923cd47f9f 100644 (file)
@@ -780,9 +780,7 @@ static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       /* TODO: Assumption: eeprom on bus 0 */
-       tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
-               eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
 
        /* Make sure we support the board model */
        switch (tv.model) {
index c9106e105baba8eba37a36e6e27e1e6a28feea17..53f6f12bff0d8fe7286b0ef825b8d8ad4fb7f3d2 100644 (file)
@@ -165,6 +165,21 @@ config VIDEO_CODA
 config VIDEO_IMX_VDOA
        def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST
 
+config VIDEO_MEDIATEK_JPEG
+       tristate "Mediatek JPEG Codec driver"
+       depends on MTK_IOMMU_V1 || COMPILE_TEST
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on HAS_DMA
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       ---help---
+         Mediatek jpeg codec driver provides HW capability to decode
+         JPEG format
+
+         To compile this driver as a module, choose M here: the
+         module will be called mtk-jpeg
+
 config VIDEO_MEDIATEK_VPU
        tristate "Mediatek Video Processor Unit"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
index 349ddf6a69da2183b5e36d303add55aa79d68793..8959f6e6692a363623a2f867a268538a1992ed80 100644 (file)
@@ -71,3 +71,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VPU)      += mtk-vpu/
 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)    += mtk-vcodec/
 
 obj-$(CONFIG_VIDEO_MEDIATEK_MDP)       += mtk-mdp/
+
+obj-$(CONFIG_VIDEO_MEDIATEK_JPEG)      += mtk-jpeg/
index 00c449717cde6cdc279f72f66485ca5bd9b450df..6936ac467609f09441156ea2fef87e20af9c1e89 100644 (file)
@@ -65,6 +65,7 @@
 #define ISC_INTSR       0x00000034
 
 #define ISC_INT_DDONE          BIT(8)
+#define ISC_INT_HISDONE                BIT(12)
 
 /* ISC White Balance Control Register */
 #define ISC_WB_CTRL     0x00000058
 /* ISC White Balance Configuration Register */
 #define ISC_WB_CFG      0x0000005c
 
+/* ISC White Balance Offset for R, GR Register */
+#define ISC_WB_O_RGR   0x00000060
+
+/* ISC White Balance Offset for B, GB Register */
+#define ISC_WB_O_BGR   0x00000064
+
+/* ISC White Balance Gain for R, GR Register */
+#define ISC_WB_G_RGR   0x00000068
+
+/* ISC White Balance Gain for B, GB Register */
+#define ISC_WB_G_BGR   0x0000006c
+
 /* ISC Color Filter Array Control Register */
 #define ISC_CFA_CTRL    0x00000070
 
 /* ISC Color Filter Array Configuration Register */
 #define ISC_CFA_CFG     0x00000074
+#define ISC_CFA_CFG_EITPOL     BIT(4)
 
 #define ISC_BAY_CFG_GRGR       0x0
 #define ISC_BAY_CFG_RGRG       0x1
 #define ISC_BAY_CFG_GBGB       0x2
 #define ISC_BAY_CFG_BGBG       0x3
-#define ISC_BAY_CFG_MASK       GENMASK(1, 0)
 
 /* ISC Color Correction Control Register */
 #define ISC_CC_CTRL     0x00000078
 
+/* ISC Color Correction RR RG Register */
+#define ISC_CC_RR_RG   0x0000007c
+
+/* ISC Color Correction RB OR Register */
+#define ISC_CC_RB_OR   0x00000080
+
+/* ISC Color Correction GR GG Register */
+#define ISC_CC_GR_GG   0x00000084
+
+/* ISC Color Correction GB OG Register */
+#define ISC_CC_GB_OG   0x00000088
+
+/* ISC Color Correction BR BG Register */
+#define ISC_CC_BR_BG   0x0000008c
+
+/* ISC Color Correction BB OB Register */
+#define ISC_CC_BB_OB   0x00000090
+
 /* ISC Gamma Correction Control Register */
 #define ISC_GAM_CTRL    0x00000094
 
+/* ISC_Gamma Correction Blue Entry Register */
+#define ISC_GAM_BENTRY 0x00000098
+
+/* ISC_Gamma Correction Green Entry Register */
+#define ISC_GAM_GENTRY 0x00000198
+
+/* ISC_Gamma Correction Green Entry Register */
+#define ISC_GAM_RENTRY 0x00000298
+
 /* Color Space Conversion Control Register */
 #define ISC_CSC_CTRL    0x00000398
 
+/* Color Space Conversion YR YG Register */
+#define ISC_CSC_YR_YG  0x0000039c
+
+/* Color Space Conversion YB OY Register */
+#define ISC_CSC_YB_OY  0x000003a0
+
+/* Color Space Conversion CBR CBG Register */
+#define ISC_CSC_CBR_CBG        0x000003a4
+
+/* Color Space Conversion CBB OCB Register */
+#define ISC_CSC_CBB_OCB        0x000003a8
+
+/* Color Space Conversion CRR CRG Register */
+#define ISC_CSC_CRR_CRG        0x000003ac
+
+/* Color Space Conversion CRB OCR Register */
+#define ISC_CSC_CRB_OCR        0x000003b0
+
 /* Contrast And Brightness Control Register */
 #define ISC_CBC_CTRL    0x000003b4
 
+/* Contrast And Brightness Configuration Register */
+#define ISC_CBC_CFG    0x000003b8
+
+/* Brightness Register */
+#define ISC_CBC_BRIGHT 0x000003bc
+#define ISC_CBC_BRIGHT_MASK    GENMASK(10, 0)
+
+/* Contrast Register */
+#define ISC_CBC_CONTRAST       0x000003c0
+#define ISC_CBC_CONTRAST_MASK  GENMASK(11, 0)
+
 /* Subsampling 4:4:4 to 4:2:2 Control Register */
 #define ISC_SUB422_CTRL 0x000003c4
 
 #define ISC_RLP_CFG_MODE_YYCC_LIMITED   0xc
 #define ISC_RLP_CFG_MODE_MASK           GENMASK(3, 0)
 
+/* Histogram Control Register */
+#define ISC_HIS_CTRL   0x000003d4
+
+#define ISC_HIS_CTRL_EN                        BIT(0)
+#define ISC_HIS_CTRL_DIS               0x0
+
+/* Histogram Configuration Register */
+#define ISC_HIS_CFG    0x000003d8
+
+#define ISC_HIS_CFG_MODE_GR            0x0
+#define ISC_HIS_CFG_MODE_R             0x1
+#define ISC_HIS_CFG_MODE_GB            0x2
+#define ISC_HIS_CFG_MODE_B             0x3
+#define ISC_HIS_CFG_MODE_Y             0x4
+#define ISC_HIS_CFG_MODE_RAW           0x5
+#define ISC_HIS_CFG_MODE_YCCIR656      0x6
+
+#define ISC_HIS_CFG_BAYSEL_SHIFT       4
+
+#define ISC_HIS_CFG_RAR                        BIT(8)
+
 /* DMA Configuration Register */
 #define ISC_DCFG        0x000003e0
 #define ISC_DCFG_IMODE_PACKED8          0x0
 /* DMA Address 0 Register */
 #define ISC_DAD0        0x000003ec
 
-/* DMA Stride 0 Register */
-#define ISC_DST0        0x000003f0
+/* DMA Address 1 Register */
+#define ISC_DAD1        0x000003f4
+
+/* DMA Address 2 Register */
+#define ISC_DAD2        0x000003fc
+
+/* Histogram Entry */
+#define ISC_HIS_ENTRY  0x00000410
 
 #endif
index fa68fe912c95e1aea4c38acfa84f13205ec2d50b..b380a7d40d858f7caa59d839ee3b27da8a26f3ac 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -36,7 +37,9 @@
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
 
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-of.h>
@@ -89,10 +92,12 @@ struct isc_subdev_entity {
  * struct isc_format - ISC media bus format information
  * @fourcc:            Fourcc code for this format
  * @mbus_code:         V4L2 media bus format code.
- * @bpp:               Bytes per pixel (when stored in memory)
+ * @bpp:               Bits per pixel (when stored in memory)
  * @reg_bps:           reg value for bits per sample
  *                     (when transferred over a bus)
- * @support:           Indicates format supported by subdev
+ * @pipeline:          pipeline switch
+ * @sd_support:                Subdev supports this format
+ * @isc_support:       ISC can convert raw format to this format
  */
 struct isc_format {
        u32     fourcc;
@@ -100,11 +105,42 @@ struct isc_format {
        u8      bpp;
 
        u32     reg_bps;
+       u32     reg_bay_cfg;
        u32     reg_rlp_mode;
        u32     reg_dcfg_imode;
        u32     reg_dctrl_dview;
 
-       bool    support;
+       u32     pipeline;
+
+       bool    sd_support;
+       bool    isc_support;
+};
+
+
+#define HIST_ENTRIES           512
+#define HIST_BAYER             (ISC_HIS_CFG_MODE_B + 1)
+
+enum{
+       HIST_INIT = 0,
+       HIST_ENABLED,
+       HIST_DISABLED,
+};
+
+struct isc_ctrls {
+       struct v4l2_ctrl_handler handler;
+
+       u32 brightness;
+       u32 contrast;
+       u8 gamma_index;
+       u8 awb;
+
+       u32 r_gain;
+       u32 b_gain;
+
+       u32 hist_entry[HIST_ENTRIES];
+       u32 hist_count[HIST_BAYER];
+       u8 hist_id;
+       u8 hist_stat;
 };
 
 #define ISC_PIPE_LINE_NODE_NUM 11
@@ -131,6 +167,10 @@ struct isc_device {
        struct isc_format       **user_formats;
        unsigned int            num_user_formats;
        const struct isc_format *current_fmt;
+       const struct isc_format *raw_fmt;
+
+       struct isc_ctrls        ctrls;
+       struct work_struct      awb_work;
 
        struct mutex            lock;
 
@@ -140,51 +180,134 @@ struct isc_device {
        struct list_head                subdev_entities;
 };
 
+#define RAW_FMT_IND_START    0
+#define RAW_FMT_IND_END      11
+#define ISC_FMT_IND_START    12
+#define ISC_FMT_IND_END      14
+
 static struct isc_format isc_formats[] = {
-       { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8,
-         1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8,
-         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8,
-         1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8,
-         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8,
-         1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8,
-         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8,
-         1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8,
-         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false },
-
-       { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10,
-         2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10,
-         2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10,
-         2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10,
-         2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-
-       { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12,
-         2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12,
-         2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12,
-         2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-       { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12,
-         2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12,
-         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false },
-
-       { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8,
-         2, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8,
-         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false },
+       { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8,
+         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8,
+         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8,
+         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8,
+         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+
+       { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16,
+         ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16,
+         ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16,
+         ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16,
+         ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+
+       { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16,
+         ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16,
+         ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16,
+         ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+       { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16,
+         ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+
+       { V4L2_PIX_FMT_YUV420, 0x0, 12,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC,
+         ISC_DCFG_IMODE_YC420P | ISC_DCFG_YMBSIZE_BEATS8 |
+         ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x7fb,
+         false, false },
+       { V4L2_PIX_FMT_YUV422P, 0x0, 16,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC,
+         ISC_DCFG_IMODE_YC422P | ISC_DCFG_YMBSIZE_BEATS8 |
+         ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x3fb,
+         false, false },
+       { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565,
+         ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b,
+         false, false },
+
+       { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16,
+         ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8,
+         ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
+         false, false },
+};
+
+#define GAMMA_MAX      2
+#define GAMMA_ENTRIES  64
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
+       /* 0 --> gamma 1/1.8 */
+       {      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
+         0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
+         0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
+         0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
+         0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
+         0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
+         0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
+         0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
+         0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
+         0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
+         0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
+
+       /* 1 --> gamma 1/2 */
+       {      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
+         0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
+         0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
+         0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
+         0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
+         0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
+         0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
+         0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
+         0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
+         0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
+         0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
+
+       /* 2 --> gamma 1/2.2 */
+       {      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
+         0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
+         0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
+         0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
+         0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
+         0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
+         0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
+         0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
+         0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
+         0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
+         0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
 };
 
+static unsigned int sensor_preferred = 1;
+module_param(sensor_preferred, uint, 0644);
+MODULE_PARM_DESC(sensor_preferred,
+                "Sensor is preferred to output the specified format (1-on 0-off), default 1");
+
 static int isc_clk_enable(struct clk_hw *hw)
 {
        struct isc_clk *isc_clk = to_isc_clk(hw);
@@ -447,27 +570,155 @@ static int isc_buffer_prepare(struct vb2_buffer *vb)
        return 0;
 }
 
-static inline void isc_start_dma(struct regmap *regmap,
-                                 struct isc_buffer *frm, u32 dview)
+static inline bool sensor_is_preferred(const struct isc_format *isc_fmt)
 {
-       dma_addr_t addr;
+       return (sensor_preferred && isc_fmt->sd_support) ||
+               !isc_fmt->isc_support;
+}
 
-       addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0);
+static void isc_start_dma(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
+       u32 sizeimage = pixfmt->sizeimage;
+       u32 dctrl_dview;
+       dma_addr_t addr0;
+
+       addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
+       regmap_write(regmap, ISC_DAD0, addr0);
+
+       switch (pixfmt->pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+               regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
+               regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
+               break;
+       case V4L2_PIX_FMT_YUV422P:
+               regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2);
+               regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4);
+               break;
+       default:
+               break;
+       }
+
+       if (sensor_is_preferred(isc->current_fmt))
+               dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+       else
+               dctrl_dview = isc->current_fmt->reg_dctrl_dview;
 
-       regmap_write(regmap, ISC_DCTRL, dview | ISC_DCTRL_IE_IS);
-       regmap_write(regmap, ISC_DAD0, addr);
+       regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
        regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
 }
 
 static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
 {
-       u32 val;
+       struct regmap *regmap = isc->regmap;
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       u32 val, bay_cfg;
+       const u32 *gamma;
        unsigned int i;
 
+       /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
        for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
                val = pipeline & BIT(i) ? 1 : 0;
                regmap_field_write(isc->pipeline[i], val);
        }
+
+       if (!pipeline)
+               return;
+
+       bay_cfg = isc->raw_fmt->reg_bay_cfg;
+
+       regmap_write(regmap, ISC_WB_CFG, bay_cfg);
+       regmap_write(regmap, ISC_WB_O_RGR, 0x0);
+       regmap_write(regmap, ISC_WB_O_BGR, 0x0);
+       regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25));
+       regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25));
+
+       regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
+
+       gamma = &isc_gamma_table[ctrls->gamma_index][0];
+       regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
+       regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
+       regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+
+       /* Convert RGB to YUV */
+       regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16));
+       regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16));
+       regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16));
+       regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16));
+       regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16));
+       regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16));
+
+       regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness);
+       regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast);
+}
+
+static int isc_update_profile(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       u32 sr;
+       int counter = 100;
+
+       regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
+
+       regmap_read(regmap, ISC_CTRLSR, &sr);
+       while ((sr & ISC_CTRL_UPPRO) && counter--) {
+               usleep_range(1000, 2000);
+               regmap_read(regmap, ISC_CTRLSR, &sr);
+       }
+
+       if (counter < 0) {
+               v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void isc_set_histogram(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       struct isc_ctrls *ctrls = &isc->ctrls;
+
+       if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) {
+               regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R |
+                     (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) |
+                     ISC_HIS_CFG_RAR);
+               regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
+               regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
+               ctrls->hist_id = ISC_HIS_CFG_MODE_R;
+               isc_update_profile(isc);
+               regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+
+               ctrls->hist_stat = HIST_ENABLED;
+       } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) {
+               regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
+               regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
+
+               ctrls->hist_stat = HIST_DISABLED;
+       }
+}
+
+static inline void isc_get_param(const struct isc_format *fmt,
+                                    u32 *rlp_mode, u32 *dcfg_imode)
+{
+       switch (fmt->fourcc) {
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SRGGB10:
+       case V4L2_PIX_FMT_SBGGR12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SRGGB12:
+               *rlp_mode = fmt->reg_rlp_mode;
+               *dcfg_imode = fmt->reg_dcfg_imode;
+               break;
+       default:
+               *rlp_mode = ISC_RLP_CFG_MODE_DAT8;
+               *dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+               break;
+       }
 }
 
 static int isc_configure(struct isc_device *isc)
@@ -475,39 +726,40 @@ static int isc_configure(struct isc_device *isc)
        struct regmap *regmap = isc->regmap;
        const struct isc_format *current_fmt = isc->current_fmt;
        struct isc_subdev_entity *subdev = isc->current_subdev;
-       u32 val, mask;
-       int counter = 10;
+       u32 pfe_cfg0, rlp_mode, dcfg_imode, mask, pipeline;
+
+       if (sensor_is_preferred(current_fmt)) {
+               pfe_cfg0 = current_fmt->reg_bps;
+               pipeline = 0x0;
+               isc_get_param(current_fmt, &rlp_mode, &dcfg_imode);
+               isc->ctrls.hist_stat = HIST_INIT;
+       } else {
+               pfe_cfg0  = isc->raw_fmt->reg_bps;
+               pipeline = current_fmt->pipeline;
+               rlp_mode = current_fmt->reg_rlp_mode;
+               dcfg_imode = current_fmt->reg_dcfg_imode;
+       }
 
-       val = current_fmt->reg_bps | subdev->pfe_cfg0 |
-             ISC_PFE_CFG0_MODE_PROGRESSIVE;
+       pfe_cfg0  |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
        mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
               ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
               ISC_PFE_CFG0_MODE_MASK;
 
-       regmap_update_bits(regmap, ISC_PFE_CFG0, mask, val);
+       regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
 
        regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK,
-                          current_fmt->reg_rlp_mode);
+                          rlp_mode);
 
-       regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK,
-                          current_fmt->reg_dcfg_imode);
+       regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, dcfg_imode);
 
-       /* Disable the pipeline */
-       isc_set_pipeline(isc, 0x0);
+       /* Set the pipeline */
+       isc_set_pipeline(isc, pipeline);
 
-       /* Update profile */
-       regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
+       if (pipeline)
+               isc_set_histogram(isc);
 
-       regmap_read(regmap, ISC_CTRLSR, &val);
-       while ((val & ISC_CTRL_UPPRO) && counter--) {
-               usleep_range(1000, 2000);
-               regmap_read(regmap, ISC_CTRLSR, &val);
-       }
-
-       if (counter < 0)
-               return -ETIMEDOUT;
-
-       return 0;
+       /* Update profile */
+       return isc_update_profile(isc);
 }
 
 static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
@@ -517,7 +769,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
        struct isc_buffer *buf;
        unsigned long flags;
        int ret;
-       u32 val;
 
        /* Enable stream on the sub device */
        ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
@@ -528,12 +779,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
 
        pm_runtime_get_sync(isc->dev);
 
-       /* Disable all the interrupts */
-       regmap_write(isc->regmap, ISC_INTDIS, (u32)~0UL);
-
-       /* Clean the interrupt status register */
-       regmap_read(regmap, ISC_INTSR, &val);
-
        ret = isc_configure(isc);
        if (unlikely(ret))
                goto err_configure;
@@ -551,7 +796,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
                                        struct isc_buffer, list);
        list_del(&isc->cur_frm->list);
 
-       isc_start_dma(regmap, isc->cur_frm, isc->current_fmt->reg_dctrl_dview);
+       isc_start_dma(isc);
 
        spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
 
@@ -620,8 +865,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb)
        if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
                vb2_is_streaming(vb->vb2_queue)) {
                isc->cur_frm = buf;
-               isc_start_dma(isc->regmap, isc->cur_frm,
-                       isc->current_fmt->reg_dctrl_dview);
+               isc_start_dma(isc);
        } else
                list_add_tail(&buf->list, &isc->dma_queue);
        spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
@@ -691,13 +935,14 @@ static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
 }
 
 static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
-                       struct isc_format **current_fmt)
+                       struct isc_format **current_fmt, u32 *code)
 {
        struct isc_format *isc_fmt;
        struct v4l2_pix_format *pixfmt = &f->fmt.pix;
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
+       u32 mbus_code;
        int ret;
 
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -717,7 +962,12 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
        if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
                pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
 
-       v4l2_fill_mbus_format(&format.format, pixfmt, isc_fmt->mbus_code);
+       if (sensor_is_preferred(isc_fmt))
+               mbus_code = isc_fmt->mbus_code;
+       else
+               mbus_code = isc->raw_fmt->mbus_code;
+
+       v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
                               isc->current_subdev->config, &format);
        if (ret < 0)
@@ -726,12 +976,15 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
        v4l2_fill_pix_format(pixfmt, &format.format);
 
        pixfmt->field = V4L2_FIELD_NONE;
-       pixfmt->bytesperline = pixfmt->width * isc_fmt->bpp;
+       pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3;
        pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
 
        if (current_fmt)
                *current_fmt = isc_fmt;
 
+       if (code)
+               *code = mbus_code;
+
        return 0;
 }
 
@@ -741,14 +994,14 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
        struct isc_format *current_fmt;
+       u32 mbus_code;
        int ret;
 
-       ret = isc_try_fmt(isc, f, &current_fmt);
+       ret = isc_try_fmt(isc, f, &current_fmt, &mbus_code);
        if (ret)
                return ret;
 
-       v4l2_fill_mbus_format(&format.format, &f->fmt.pix,
-                             current_fmt->mbus_code);
+       v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code);
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
                               set_fmt, NULL, &format);
        if (ret < 0)
@@ -776,7 +1029,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv,
 {
        struct isc_device *isc = video_drvdata(file);
 
-       return isc_try_fmt(isc, f, NULL);
+       return isc_try_fmt(isc, f, NULL, NULL);
 }
 
 static int isc_enum_input(struct file *file, void *priv,
@@ -842,7 +1095,10 @@ static int isc_enum_framesizes(struct file *file, void *fh,
        if (!isc_fmt)
                return -EINVAL;
 
-       fse.code = isc_fmt->mbus_code;
+       if (sensor_is_preferred(isc_fmt))
+               fse.code = isc_fmt->mbus_code;
+       else
+               fse.code = isc->raw_fmt->mbus_code;
 
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
                               NULL, &fse);
@@ -873,7 +1129,10 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
        if (!isc_fmt)
                return -EINVAL;
 
-       fie.code = isc_fmt->mbus_code;
+       if (sensor_is_preferred(isc_fmt))
+               fie.code = isc_fmt->mbus_code;
+       else
+               fie.code = isc->raw_fmt->mbus_code;
 
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
                               enum_frame_interval, NULL, &fie);
@@ -911,6 +1170,10 @@ static const struct v4l2_ioctl_ops isc_ioctl_ops = {
        .vidioc_s_parm                  = isc_s_parm,
        .vidioc_enum_framesizes         = isc_enum_framesizes,
        .vidioc_enum_frameintervals     = isc_enum_frameintervals,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 };
 
 static int isc_open(struct file *file)
@@ -984,14 +1247,13 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id)
        u32 isc_intsr, isc_intmask, pending;
        irqreturn_t ret = IRQ_NONE;
 
-       spin_lock(&isc->dma_queue_lock);
-
        regmap_read(regmap, ISC_INTSR, &isc_intsr);
        regmap_read(regmap, ISC_INTMASK, &isc_intmask);
 
        pending = isc_intsr & isc_intmask;
 
        if (likely(pending & ISC_INT_DDONE)) {
+               spin_lock(&isc->dma_queue_lock);
                if (isc->cur_frm) {
                        struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
                        struct vb2_buffer *vb = &vbuf->vb2_buf;
@@ -1007,21 +1269,144 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id)
                                                     struct isc_buffer, list);
                        list_del(&isc->cur_frm->list);
 
-                       isc_start_dma(regmap, isc->cur_frm,
-                                     isc->current_fmt->reg_dctrl_dview);
+                       isc_start_dma(isc);
                }
 
                if (isc->stop)
                        complete(&isc->comp);
 
                ret = IRQ_HANDLED;
+               spin_unlock(&isc->dma_queue_lock);
        }
 
-       spin_unlock(&isc->dma_queue_lock);
+       if (pending & ISC_INT_HISDONE) {
+               schedule_work(&isc->awb_work);
+               ret = IRQ_HANDLED;
+       }
 
        return ret;
 }
 
+static void isc_hist_count(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
+       u32 *hist_entry = &ctrls->hist_entry[0];
+       u32 i;
+
+       regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
+
+       *hist_count = 0;
+       for (i = 0; i <= HIST_ENTRIES; i++)
+               *hist_count += i * (*hist_entry++);
+}
+
+static void isc_wb_update(struct isc_ctrls *ctrls)
+{
+       u32 *hist_count = &ctrls->hist_count[0];
+       u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9;
+       u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R];
+       u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B];
+
+       if (hist_r)
+               ctrls->r_gain = div_u64(g_count, hist_r);
+
+       if (hist_b)
+               ctrls->b_gain = div_u64(g_count, hist_b);
+}
+
+static void isc_awb_work(struct work_struct *w)
+{
+       struct isc_device *isc =
+               container_of(w, struct isc_device, awb_work);
+       struct regmap *regmap = isc->regmap;
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       u32 hist_id = ctrls->hist_id;
+       u32 baysel;
+
+       if (ctrls->hist_stat != HIST_ENABLED)
+               return;
+
+       isc_hist_count(isc);
+
+       if (hist_id != ISC_HIS_CFG_MODE_B) {
+               hist_id++;
+       } else {
+               isc_wb_update(ctrls);
+               hist_id = ISC_HIS_CFG_MODE_R;
+       }
+
+       ctrls->hist_id = hist_id;
+       baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT;
+
+       pm_runtime_get_sync(isc->dev);
+
+       regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
+       isc_update_profile(isc);
+       regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+
+       pm_runtime_put_sync(isc->dev);
+}
+
+static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct isc_device *isc = container_of(ctrl->handler,
+                                            struct isc_device, ctrls.handler);
+       struct isc_ctrls *ctrls = &isc->ctrls;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
+               break;
+       case V4L2_CID_GAMMA:
+               ctrls->gamma_index = ctrl->val;
+               break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ctrls->awb = ctrl->val;
+               if (ctrls->hist_stat != HIST_ENABLED) {
+                       ctrls->r_gain = 0x1 << 9;
+                       ctrls->b_gain = 0x1 << 9;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_ctrl_ops = {
+       .s_ctrl = isc_s_ctrl,
+};
+
+static int isc_ctrl_init(struct isc_device *isc)
+{
+       const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+       int ret;
+
+       ctrls->hist_stat = HIST_INIT;
+
+       ret = v4l2_ctrl_handler_init(hdl, 4);
+       if (ret < 0)
+               return ret;
+
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+
+       v4l2_ctrl_handler_setup(hdl);
+
+       return 0;
+}
+
+
 static int isc_async_bound(struct v4l2_async_notifier *notifier,
                            struct v4l2_subdev *subdev,
                            struct v4l2_async_subdev *asd)
@@ -1047,10 +1432,11 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier,
 {
        struct isc_device *isc = container_of(notifier->v4l2_dev,
                                              struct isc_device, v4l2_dev);
-
+       cancel_work_sync(&isc->awb_work);
        video_unregister_device(&isc->video_dev);
        if (isc->current_subdev->config)
                v4l2_subdev_free_pad_config(isc->current_subdev->config);
+       v4l2_ctrl_handler_free(&isc->ctrls.handler);
 }
 
 static struct isc_format *find_format_by_code(unsigned int code, int *index)
@@ -1074,14 +1460,16 @@ static int isc_formats_init(struct isc_device *isc)
 {
        struct isc_format *fmt;
        struct v4l2_subdev *subdev = isc->current_subdev->sd;
-       int num_fmts = 0, i, j;
+       unsigned int num_fmts, i, j;
        struct v4l2_subdev_mbus_code_enum mbus_code = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
 
        fmt = &isc_formats[0];
        for (i = 0; i < ARRAY_SIZE(isc_formats); i++) {
-               fmt->support = false;
+               fmt->isc_support = false;
+               fmt->sd_support = false;
+
                fmt++;
        }
 
@@ -1092,8 +1480,21 @@ static int isc_formats_init(struct isc_device *isc)
                if (!fmt)
                        continue;
 
-               fmt->support = true;
-               num_fmts++;
+               fmt->sd_support = true;
+
+               if (i <= RAW_FMT_IND_END) {
+                       for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++)
+                               isc_formats[j].isc_support = true;
+
+                       isc->raw_fmt = fmt;
+               }
+       }
+
+       for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) {
+               if (fmt->isc_support || fmt->sd_support)
+                       num_fmts++;
+
+               fmt++;
        }
 
        if (!num_fmts)
@@ -1110,7 +1511,7 @@ static int isc_formats_init(struct isc_device *isc)
 
        fmt = &isc_formats[0];
        for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) {
-               if (fmt->support)
+               if (fmt->isc_support || fmt->sd_support)
                        isc->user_formats[j++] = fmt;
 
                fmt++;
@@ -1132,7 +1533,7 @@ static int isc_set_default_fmt(struct isc_device *isc)
        };
        int ret;
 
-       ret = isc_try_fmt(isc, &f, NULL);
+       ret = isc_try_fmt(isc, &f, NULL, NULL);
        if (ret)
                return ret;
 
@@ -1151,6 +1552,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
        struct vb2_queue *q = &isc->vb2_vidq;
        int ret;
 
+       ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
+       if (ret < 0) {
+               v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
+               return ret;
+       }
+
        isc->current_subdev = container_of(notifier,
                                           struct isc_subdev_entity, notifier);
        sd_entity = isc->current_subdev;
@@ -1198,6 +1605,14 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
                return ret;
        }
 
+       ret = isc_ctrl_init(isc);
+       if (ret) {
+               v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
+               return ret;
+       }
+
+       INIT_WORK(&isc->awb_work, isc_awb_work);
+
        /* Register video device */
        strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
        vdev->release           = video_device_release_empty;
@@ -1207,7 +1622,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
        vdev->vfl_dir           = VFL_DIR_RX;
        vdev->queue             = q;
        vdev->lock              = &isc->lock;
-       vdev->ctrl_handler      = isc->current_subdev->sd->ctrl_handler;
+       vdev->ctrl_handler      = &isc->ctrls.handler;
        vdev->device_caps       = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
        video_set_drvdata(vdev, isc);
 
index 67fd8ffa60a418f6538d6b358c3e3d91f4f385b6..669a4c82f1ffa4c79b5e47173536faedecf52c34 100644 (file)
@@ -321,7 +321,7 @@ static const struct of_device_id vdoa_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, vdoa_dt_ids);
 
-static const struct platform_driver vdoa_driver = {
+static struct platform_driver vdoa_driver = {
        .probe          = vdoa_probe,
        .remove         = vdoa_remove,
        .driver         = {
index cbb03768f5d73574b4d95939a08d7605e94dd6d7..59a6342018307170a3d5143e9ee061c08c688589 100644 (file)
@@ -111,6 +111,15 @@ static const struct gsc_fmt gsc_formats[] = {
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 2,
+       }, {
+               .name           = "YUV 4:2:2 non-contig, Y/CbCr",
+               .pixelformat    = V4L2_PIX_FMT_NV16M,
+               .depth          = { 8, 8 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 2,
+               .num_comp       = 2,
        }, {
                .name           = "YUV 4:2:2 planar, Y/CrCb",
                .pixelformat    = V4L2_PIX_FMT_NV61,
@@ -120,6 +129,15 @@ static const struct gsc_fmt gsc_formats[] = {
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+       }, {
+               .name           = "YUV 4:2:2 non-contig, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV61M,
+               .depth          = { 8, 8 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 2,
+               .num_comp       = 2,
        }, {
                .name           = "YUV 4:2:0 planar, YCbCr",
                .pixelformat    = V4L2_PIX_FMT_YUV420,
@@ -157,6 +175,15 @@ static const struct gsc_fmt gsc_formats[] = {
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+       }, {
+               .name           = "YUV 4:2:0 non-contig. 2p, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV21M,
+               .depth          = { 8, 4 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 2,
+               .num_comp       = 2,
        }, {
                .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV12M,
@@ -861,9 +888,7 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
 
        if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
                swap(addr->cb, addr->cr);
 
diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile
new file mode 100644 (file)
index 0000000..b2e6069
--- /dev/null
@@ -0,0 +1,2 @@
+mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o
+obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
new file mode 100644 (file)
index 0000000..b10183f
--- /dev/null
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <soc/mediatek/smi.h>
+
+#include "mtk_jpeg_hw.h"
+#include "mtk_jpeg_core.h"
+#include "mtk_jpeg_parse.h"
+
+static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
+       {
+               .fourcc         = V4L2_PIX_FMT_JPEG,
+               .colplanes      = 1,
+               .flags          = MTK_JPEG_FMT_FLAG_DEC_OUTPUT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV420M,
+               .h_sample       = {4, 2, 2},
+               .v_sample       = {4, 2, 2},
+               .colplanes      = 3,
+               .h_align        = 5,
+               .v_align        = 4,
+               .flags          = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV422M,
+               .h_sample       = {4, 2, 2},
+               .v_sample       = {4, 4, 4},
+               .colplanes      = 3,
+               .h_align        = 5,
+               .v_align        = 3,
+               .flags          = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+       },
+};
+
+#define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats)
+
+enum {
+       MTK_JPEG_BUF_FLAGS_INIT                 = 0,
+       MTK_JPEG_BUF_FLAGS_LAST_FRAME           = 1,
+};
+
+struct mtk_jpeg_src_buf {
+       struct vb2_v4l2_buffer b;
+       struct list_head list;
+       int flags;
+       struct mtk_jpeg_dec_param dec_param;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+
+static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh)
+{
+       return container_of(fh, struct mtk_jpeg_ctx, fh);
+}
+
+static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf(
+                                                       struct vb2_buffer *vb)
+{
+       return container_of(to_vb2_v4l2_buffer(vb), struct mtk_jpeg_src_buf, b);
+}
+
+static int mtk_jpeg_querycap(struct file *file, void *priv,
+                            struct v4l2_capability *cap)
+{
+       struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+
+       strlcpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
+       strlcpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                dev_name(jpeg->dev));
+
+       return 0;
+}
+
+static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n,
+                            struct v4l2_fmtdesc *f, u32 type)
+{
+       int i, num = 0;
+
+       for (i = 0; i < n; ++i) {
+               if (mtk_jpeg_formats[i].flags & type) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+               }
+       }
+
+       if (i >= n)
+               return -EINVAL;
+
+       f->pixelformat = mtk_jpeg_formats[i].fourcc;
+
+       return 0;
+}
+
+static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+                                    struct v4l2_fmtdesc *f)
+{
+       return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
+                                MTK_JPEG_FMT_FLAG_DEC_CAPTURE);
+}
+
+static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+                                    struct v4l2_fmtdesc *f)
+{
+       return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
+                                MTK_JPEG_FMT_FLAG_DEC_OUTPUT);
+}
+
+static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx,
+                                                  enum v4l2_buf_type type)
+{
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               return &ctx->out_q;
+       return &ctx->cap_q;
+}
+
+static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx,
+                                                u32 pixelformat,
+                                                unsigned int fmt_type)
+{
+       unsigned int k, fmt_flag;
+
+       fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ?
+                  MTK_JPEG_FMT_FLAG_DEC_OUTPUT :
+                  MTK_JPEG_FMT_FLAG_DEC_CAPTURE;
+
+       for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) {
+               struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k];
+
+               if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag)
+                       return fmt;
+       }
+
+       return NULL;
+}
+
+static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin,
+                                      unsigned int wmax, unsigned int walign,
+                                      u32 *h, unsigned int hmin,
+                                      unsigned int hmax, unsigned int halign)
+{
+       int width, height, w_step, h_step;
+
+       width = *w;
+       height = *h;
+       w_step = 1 << walign;
+       h_step = 1 << halign;
+
+       v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+       if (*w < width && (*w + w_step) <= wmax)
+               *w += w_step;
+       if (*h < height && (*h + h_step) <= hmax)
+               *h += h_step;
+}
+
+static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx,
+                                      struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct mtk_jpeg_q_data *q_data;
+       int i;
+
+       q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+       pix_mp->width = q_data->w;
+       pix_mp->height = q_data->h;
+       pix_mp->pixelformat = q_data->fmt->fourcc;
+       pix_mp->num_planes = q_data->fmt->colplanes;
+
+       for (i = 0; i < pix_mp->num_planes; i++) {
+               pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+               pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+       }
+}
+
+static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f,
+                                  struct mtk_jpeg_fmt *fmt,
+                                  struct mtk_jpeg_ctx *ctx, int q_type)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       int i;
+
+       memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+       pix_mp->field = V4L2_FIELD_NONE;
+
+       if (ctx->state != MTK_JPEG_INIT) {
+               mtk_jpeg_adjust_fmt_mplane(ctx, f);
+               goto end;
+       }
+
+       pix_mp->num_planes = fmt->colplanes;
+       pix_mp->pixelformat = fmt->fourcc;
+
+       if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) {
+               struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
+
+               mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
+                                          MTK_JPEG_MAX_WIDTH, 0,
+                                          &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
+                                          MTK_JPEG_MAX_HEIGHT, 0);
+
+               memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+               pfmt->bytesperline = 0;
+               /* Source size must be aligned to 128 */
+               pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128);
+               if (pfmt->sizeimage == 0)
+                       pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE;
+               goto end;
+       }
+
+       /* type is MTK_JPEG_FMT_TYPE_CAPTURE */
+       mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
+                                  MTK_JPEG_MAX_WIDTH, fmt->h_align,
+                                  &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
+                                  MTK_JPEG_MAX_HEIGHT, fmt->v_align);
+
+       for (i = 0; i < fmt->colplanes; i++) {
+               struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
+               u32 stride = pix_mp->width * fmt->h_sample[i] / 4;
+               u32 h = pix_mp->height * fmt->v_sample[i] / 4;
+
+               memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+               pfmt->bytesperline = stride;
+               pfmt->sizeimage = stride * h;
+       }
+end:
+       v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n",
+                pix_mp->width, pix_mp->height);
+       for (i = 0; i < pix_mp->num_planes; i++) {
+               v4l2_dbg(2, debug, &jpeg->v4l2_dev,
+                        "plane[%d] bpl=%u, size=%u\n",
+                        i,
+                        pix_mp->plane_fmt[i].bytesperline,
+                        pix_mp->plane_fmt[i].sizeimage);
+       }
+       return 0;
+}
+
+static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv,
+                                    struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct mtk_jpeg_q_data *q_data = NULL;
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       int i;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+       memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+       pix_mp->width = q_data->w;
+       pix_mp->height = q_data->h;
+       pix_mp->field = V4L2_FIELD_NONE;
+       pix_mp->pixelformat = q_data->fmt->fourcc;
+       pix_mp->num_planes = q_data->fmt->colplanes;
+       pix_mp->colorspace = ctx->colorspace;
+       pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+       pix_mp->xfer_func = ctx->xfer_func;
+       pix_mp->quantization = ctx->quantization;
+
+       v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%c%c%c%c wxh:%ux%u\n",
+                f->type,
+                (pix_mp->pixelformat & 0xff),
+                (pix_mp->pixelformat >>  8 & 0xff),
+                (pix_mp->pixelformat >> 16 & 0xff),
+                (pix_mp->pixelformat >> 24 & 0xff),
+                pix_mp->width, pix_mp->height);
+
+       for (i = 0; i < pix_mp->num_planes; i++) {
+               struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
+
+               pfmt->bytesperline = q_data->bytesperline[i];
+               pfmt->sizeimage = q_data->sizeimage[i];
+               memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+                        "plane[%d] bpl=%u, size=%u\n",
+                        i,
+                        pfmt->bytesperline,
+                        pfmt->sizeimage);
+       }
+       return 0;
+}
+
+static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                          struct v4l2_format *f)
+{
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+       struct mtk_jpeg_fmt *fmt;
+
+       fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+                                  MTK_JPEG_FMT_TYPE_CAPTURE);
+       if (!fmt)
+               fmt = ctx->cap_q.fmt;
+
+       v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n",
+                f->type,
+                (fmt->fourcc & 0xff),
+                (fmt->fourcc >>  8 & 0xff),
+                (fmt->fourcc >> 16 & 0xff),
+                (fmt->fourcc >> 24 & 0xff));
+
+       return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE);
+}
+
+static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv,
+                                          struct v4l2_format *f)
+{
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+       struct mtk_jpeg_fmt *fmt;
+
+       fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+                                  MTK_JPEG_FMT_TYPE_OUTPUT);
+       if (!fmt)
+               fmt = ctx->out_q.fmt;
+
+       v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n",
+                f->type,
+                (fmt->fourcc & 0xff),
+                (fmt->fourcc >>  8 & 0xff),
+                (fmt->fourcc >> 16 & 0xff),
+                (fmt->fourcc >> 24 & 0xff));
+
+       return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT);
+}
+
+static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
+                                struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct mtk_jpeg_q_data *q_data = NULL;
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       unsigned int f_type;
+       int i;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
+               return -EBUSY;
+       }
+
+       f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
+                        MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE;
+
+       q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
+       q_data->w = pix_mp->width;
+       q_data->h = pix_mp->height;
+       ctx->colorspace = pix_mp->colorspace;
+       ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+       ctx->xfer_func = pix_mp->xfer_func;
+       ctx->quantization = pix_mp->quantization;
+
+       v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%c%c%c%c wxh:%ux%u\n",
+                f->type,
+                (q_data->fmt->fourcc & 0xff),
+                (q_data->fmt->fourcc >>  8 & 0xff),
+                (q_data->fmt->fourcc >> 16 & 0xff),
+                (q_data->fmt->fourcc >> 24 & 0xff),
+                q_data->w, q_data->h);
+
+       for (i = 0; i < q_data->fmt->colplanes; i++) {
+               q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
+               q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+                        "plane[%d] bpl=%u, size=%u\n",
+                        i, q_data->bytesperline[i], q_data->sizeimage[i]);
+       }
+
+       return 0;
+}
+
+static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv,
+                                        struct v4l2_format *f)
+{
+       int ret;
+
+       ret = mtk_jpeg_try_fmt_vid_out_mplane(file, priv, f);
+       if (ret)
+               return ret;
+
+       return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+}
+
+static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                        struct v4l2_format *f)
+{
+       int ret;
+
+       ret = mtk_jpeg_try_fmt_vid_cap_mplane(file, priv, f);
+       if (ret)
+               return ret;
+
+       return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+}
+
+static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx)
+{
+       static const struct v4l2_event ev_src_ch = {
+               .type = V4L2_EVENT_SOURCE_CHANGE,
+               .u.src_change.changes =
+               V4L2_EVENT_SRC_CH_RESOLUTION,
+       };
+
+       v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh,
+                                   const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subscribe(fh, sub);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mtk_jpeg_g_selection(struct file *file, void *priv,
+                               struct v4l2_selection *s)
+{
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               s->r.width = ctx->out_q.w;
+               s->r.height = ctx->out_q.h;
+               s->r.left = 0;
+               s->r.top = 0;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               s->r.width = ctx->cap_q.w;
+               s->r.height = ctx->cap_q.h;
+               s->r.left = 0;
+               s->r.top = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int mtk_jpeg_s_selection(struct file *file, void *priv,
+                               struct v4l2_selection *s)
+{
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = ctx->out_q.w;
+               s->r.height = ctx->out_q.h;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+       struct vb2_queue *vq;
+       struct vb2_buffer *vb;
+       struct mtk_jpeg_src_buf *jpeg_src_buf;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               goto end;
+
+       vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
+       if (buf->index >= vq->num_buffers) {
+               dev_err(ctx->jpeg->dev, "buffer index out of range\n");
+               return -EINVAL;
+       }
+
+       vb = vq->bufs[buf->index];
+       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+       jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ?
+               MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT;
+end:
+       return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+
+static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
+       .vidioc_querycap                = mtk_jpeg_querycap,
+       .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out,
+       .vidioc_try_fmt_vid_cap_mplane  = mtk_jpeg_try_fmt_vid_cap_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = mtk_jpeg_try_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = mtk_jpeg_g_fmt_vid_mplane,
+       .vidioc_g_fmt_vid_out_mplane    = mtk_jpeg_g_fmt_vid_mplane,
+       .vidioc_s_fmt_vid_cap_mplane    = mtk_jpeg_s_fmt_vid_cap_mplane,
+       .vidioc_s_fmt_vid_out_mplane    = mtk_jpeg_s_fmt_vid_out_mplane,
+       .vidioc_qbuf                    = mtk_jpeg_qbuf,
+       .vidioc_subscribe_event         = mtk_jpeg_subscribe_event,
+       .vidioc_g_selection             = mtk_jpeg_g_selection,
+       .vidioc_s_selection             = mtk_jpeg_s_selection,
+
+       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+static int mtk_jpeg_queue_setup(struct vb2_queue *q,
+                               unsigned int *num_buffers,
+                               unsigned int *num_planes,
+                               unsigned int sizes[],
+                               struct device *alloc_ctxs[])
+{
+       struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+       struct mtk_jpeg_q_data *q_data = NULL;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       int i;
+
+       v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) buf_req count=%u\n",
+                q->type, *num_buffers);
+
+       q_data = mtk_jpeg_get_q_data(ctx, q->type);
+       if (!q_data)
+               return -EINVAL;
+
+       *num_planes = q_data->fmt->colplanes;
+       for (i = 0; i < q_data->fmt->colplanes; i++) {
+               sizes[i] = q_data->sizeimage[i];
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n",
+                        i, sizes[i]);
+       }
+
+       return 0;
+}
+
+static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+       struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct mtk_jpeg_q_data *q_data = NULL;
+       int i;
+
+       q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
+       if (!q_data)
+               return -EINVAL;
+
+       for (i = 0; i < q_data->fmt->colplanes; i++)
+               vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+
+       return 0;
+}
+
+static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx,
+                                            struct mtk_jpeg_dec_param *param)
+{
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       struct mtk_jpeg_q_data *q_data;
+
+       q_data = &ctx->out_q;
+       if (q_data->w != param->pic_w || q_data->h != param->pic_h) {
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n");
+               return true;
+       }
+
+       q_data = &ctx->cap_q;
+       if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc,
+                                               MTK_JPEG_FMT_TYPE_CAPTURE)) {
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n");
+               return true;
+       }
+       return false;
+}
+
+static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx,
+                                   struct mtk_jpeg_dec_param *param)
+{
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       struct mtk_jpeg_q_data *q_data;
+       int i;
+
+       q_data = &ctx->out_q;
+       q_data->w = param->pic_w;
+       q_data->h = param->pic_h;
+
+       q_data = &ctx->cap_q;
+       q_data->w = param->dec_w;
+       q_data->h = param->dec_h;
+       q_data->fmt = mtk_jpeg_find_format(ctx,
+                                          param->dst_fourcc,
+                                          MTK_JPEG_FMT_TYPE_CAPTURE);
+
+       for (i = 0; i < q_data->fmt->colplanes; i++) {
+               q_data->bytesperline[i] = param->mem_stride[i];
+               q_data->sizeimage[i] = param->comp_size[i];
+       }
+
+       v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+                "set_parse cap:%c%c%c%c pic(%u, %u), buf(%u, %u)\n",
+                (param->dst_fourcc & 0xff),
+                (param->dst_fourcc >>  8 & 0xff),
+                (param->dst_fourcc >> 16 & 0xff),
+                (param->dst_fourcc >> 24 & 0xff),
+                param->pic_w, param->pic_h,
+                param->dec_w, param->dec_h);
+}
+
+static void mtk_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+       struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct mtk_jpeg_dec_param *param;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       struct mtk_jpeg_src_buf *jpeg_src_buf;
+       bool header_valid;
+
+       v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p\n",
+                vb->vb2_queue->type, vb->index, vb);
+
+       if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               goto end;
+
+       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+       param = &jpeg_src_buf->dec_param;
+       memset(param, 0, sizeof(*param));
+
+       if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
+               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos\n");
+               goto end;
+       }
+       header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0),
+                                     vb2_get_plane_payload(vb, 0));
+       if (!header_valid) {
+               v4l2_err(&jpeg->v4l2_dev, "Header invalid.\n");
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               return;
+       }
+
+       if (ctx->state == MTK_JPEG_INIT) {
+               struct vb2_queue *dst_vq = v4l2_m2m_get_vq(
+                       ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+               mtk_jpeg_queue_src_chg_event(ctx);
+               mtk_jpeg_set_queue_data(ctx, param);
+               ctx->state = vb2_is_streaming(dst_vq) ?
+                               MTK_JPEG_SOURCE_CHANGE : MTK_JPEG_RUNNING;
+       }
+end:
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
+                                enum v4l2_buf_type type)
+{
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               return v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       else
+               return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+}
+
+static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_buffer *vb;
+       int ret = 0;
+
+       ret = pm_runtime_get_sync(ctx->jpeg->dev);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+err:
+       while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
+               v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_QUEUED);
+       return ret;
+}
+
+static void mtk_jpeg_stop_streaming(struct vb2_queue *q)
+{
+       struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_buffer *vb;
+
+       /*
+        * STREAMOFF is an acknowledgment for source change event.
+        * Before STREAMOFF, we still have to return the old resolution and
+        * subsampling. Update capture queue when the stream is off.
+        */
+       if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
+           !V4L2_TYPE_IS_OUTPUT(q->type)) {
+               struct mtk_jpeg_src_buf *src_buf;
+
+               vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+               src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+               mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
+               ctx->state = MTK_JPEG_RUNNING;
+       } else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               ctx->state = MTK_JPEG_INIT;
+       }
+
+       while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
+               v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
+
+       pm_runtime_put_sync(ctx->jpeg->dev);
+}
+
+static struct vb2_ops mtk_jpeg_qops = {
+       .queue_setup        = mtk_jpeg_queue_setup,
+       .buf_prepare        = mtk_jpeg_buf_prepare,
+       .buf_queue          = mtk_jpeg_buf_queue,
+       .wait_prepare       = vb2_ops_wait_prepare,
+       .wait_finish        = vb2_ops_wait_finish,
+       .start_streaming    = mtk_jpeg_start_streaming,
+       .stop_streaming     = mtk_jpeg_stop_streaming,
+};
+
+static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx,
+                                struct vb2_buffer *src_buf,
+                                struct mtk_jpeg_bs *bs)
+{
+       bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       bs->end_addr = bs->str_addr +
+                        mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16);
+       bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128);
+}
+
+static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
+                               struct mtk_jpeg_dec_param *param,
+                               struct vb2_buffer *dst_buf,
+                               struct mtk_jpeg_fb *fb)
+{
+       int i;
+
+       if (param->comp_num != dst_buf->num_planes) {
+               dev_err(ctx->jpeg->dev, "plane number mismatch (%u != %u)\n",
+                       param->comp_num, dst_buf->num_planes);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < dst_buf->num_planes; i++) {
+               if (vb2_plane_size(dst_buf, i) < param->comp_size[i]) {
+                       dev_err(ctx->jpeg->dev,
+                               "buffer size is underflow (%lu < %u)\n",
+                               vb2_plane_size(dst_buf, 0),
+                               param->comp_size[i]);
+                       return -EINVAL;
+               }
+               fb->plane_addr[i] = vb2_dma_contig_plane_dma_addr(dst_buf, i);
+       }
+
+       return 0;
+}
+
+static void mtk_jpeg_device_run(void *priv)
+{
+       struct mtk_jpeg_ctx *ctx = priv;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       struct vb2_buffer *src_buf, *dst_buf;
+       enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+       unsigned long flags;
+       struct mtk_jpeg_src_buf *jpeg_src_buf;
+       struct mtk_jpeg_bs bs;
+       struct mtk_jpeg_fb fb;
+       int i;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
+
+       if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
+               for (i = 0; i < dst_buf->num_planes; i++)
+                       vb2_set_plane_payload(dst_buf, i, 0);
+               buf_state = VB2_BUF_STATE_DONE;
+               goto dec_end;
+       }
+
+       if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
+               mtk_jpeg_queue_src_chg_event(ctx);
+               ctx->state = MTK_JPEG_SOURCE_CHANGE;
+               v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+               return;
+       }
+
+       mtk_jpeg_set_dec_src(ctx, src_buf, &bs);
+       if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb))
+               goto dec_end;
+
+       spin_lock_irqsave(&jpeg->hw_lock, flags);
+       mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+       mtk_jpeg_dec_set_config(jpeg->dec_reg_base,
+                               &jpeg_src_buf->dec_param, &bs, &fb);
+
+       mtk_jpeg_dec_start(jpeg->dec_reg_base);
+       spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+       return;
+
+dec_end:
+       v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static int mtk_jpeg_job_ready(void *priv)
+{
+       struct mtk_jpeg_ctx *ctx = priv;
+
+       return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0;
+}
+
+static void mtk_jpeg_job_abort(void *priv)
+{
+       struct mtk_jpeg_ctx *ctx = priv;
+       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+       struct vb2_buffer *src_buf, *dst_buf;
+
+       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), VB2_BUF_STATE_ERROR);
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_ERROR);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static struct v4l2_m2m_ops mtk_jpeg_m2m_ops = {
+       .device_run = mtk_jpeg_device_run,
+       .job_ready  = mtk_jpeg_job_ready,
+       .job_abort  = mtk_jpeg_job_abort,
+};
+
+static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
+                              struct vb2_queue *dst_vq)
+{
+       struct mtk_jpeg_ctx *ctx = priv;
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
+       src_vq->ops = &mtk_jpeg_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->jpeg->lock;
+       src_vq->dev = ctx->jpeg->dev;
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &mtk_jpeg_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->jpeg->lock;
+       dst_vq->dev = ctx->jpeg->dev;
+       ret = vb2_queue_init(dst_vq);
+
+       return ret;
+}
+
+static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
+{
+       int ret;
+
+       ret = mtk_smi_larb_get(jpeg->larb);
+       if (ret)
+               dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret);
+       clk_prepare_enable(jpeg->clk_jdec_smi);
+       clk_prepare_enable(jpeg->clk_jdec);
+}
+
+static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
+{
+       clk_disable_unprepare(jpeg->clk_jdec);
+       clk_disable_unprepare(jpeg->clk_jdec_smi);
+       mtk_smi_larb_put(jpeg->larb);
+}
+
+static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
+{
+       struct mtk_jpeg_dev *jpeg = priv;
+       struct mtk_jpeg_ctx *ctx;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct mtk_jpeg_src_buf *jpeg_src_buf;
+       enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+       u32     dec_irq_ret;
+       u32 dec_ret;
+       int i;
+
+       ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+       if (!ctx) {
+               v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n");
+               return IRQ_HANDLED;
+       }
+
+       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
+
+       dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base);
+       dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret);
+
+       if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW)
+               mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+
+       if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) {
+               dev_err(jpeg->dev, "decode failed\n");
+               goto dec_end;
+       }
+
+       for (i = 0; i < dst_buf->num_planes; i++)
+               vb2_set_plane_payload(dst_buf, i,
+                                     jpeg_src_buf->dec_param.comp_size[i]);
+
+       buf_state = VB2_BUF_STATE_DONE;
+
+dec_end:
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
+       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+       return IRQ_HANDLED;
+}
+
+static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx)
+{
+       struct mtk_jpeg_q_data *q = &ctx->out_q;
+       int i;
+
+       ctx->colorspace = V4L2_COLORSPACE_JPEG,
+       ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+       ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+                                             MTK_JPEG_FMT_TYPE_OUTPUT);
+       q->w = MTK_JPEG_MIN_WIDTH;
+       q->h = MTK_JPEG_MIN_HEIGHT;
+       q->bytesperline[0] = 0;
+       q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE;
+
+       q = &ctx->cap_q;
+       q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M,
+                                             MTK_JPEG_FMT_TYPE_CAPTURE);
+       q->w = MTK_JPEG_MIN_WIDTH;
+       q->h = MTK_JPEG_MIN_HEIGHT;
+
+       for (i = 0; i < q->fmt->colplanes; i++) {
+               u32 stride = q->w * q->fmt->h_sample[i] / 4;
+               u32 h = q->h * q->fmt->v_sample[i] / 4;
+
+               q->bytesperline[i] = stride;
+               q->sizeimage[i] = stride * h;
+       }
+}
+
+static int mtk_jpeg_open(struct file *file)
+{
+       struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+       struct video_device *vfd = video_devdata(file);
+       struct mtk_jpeg_ctx *ctx;
+       int ret = 0;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       if (mutex_lock_interruptible(&jpeg->lock)) {
+               ret = -ERESTARTSYS;
+               goto free;
+       }
+
+       v4l2_fh_init(&ctx->fh, vfd);
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       ctx->jpeg = jpeg;
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
+                                           mtk_jpeg_queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+               goto error;
+       }
+
+       mtk_jpeg_set_default_params(ctx);
+       mutex_unlock(&jpeg->lock);
+       return 0;
+
+error:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       mutex_unlock(&jpeg->lock);
+free:
+       kfree(ctx);
+       return ret;
+}
+
+static int mtk_jpeg_release(struct file *file)
+{
+       struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+       struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data);
+
+       mutex_lock(&jpeg->lock);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       mutex_unlock(&jpeg->lock);
+       return 0;
+}
+
+static const struct v4l2_file_operations mtk_jpeg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mtk_jpeg_open,
+       .release        = mtk_jpeg_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
+{
+       struct device_node *node;
+       struct platform_device *pdev;
+
+       node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0);
+       if (!node)
+               return -EINVAL;
+       pdev = of_find_device_by_node(node);
+       if (WARN_ON(!pdev)) {
+               of_node_put(node);
+               return -EINVAL;
+       }
+       of_node_put(node);
+
+       jpeg->larb = &pdev->dev;
+
+       jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec");
+       if (IS_ERR(jpeg->clk_jdec))
+               return -EINVAL;
+
+       jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi");
+       if (IS_ERR(jpeg->clk_jdec_smi))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int mtk_jpeg_probe(struct platform_device *pdev)
+{
+       struct mtk_jpeg_dev *jpeg;
+       struct resource *res;
+       int dec_irq;
+       int ret;
+
+       jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL);
+       if (!jpeg)
+               return -ENOMEM;
+
+       mutex_init(&jpeg->lock);
+       spin_lock_init(&jpeg->hw_lock);
+       jpeg->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(jpeg->dec_reg_base)) {
+               ret = PTR_ERR(jpeg->dec_reg_base);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       dec_irq = platform_get_irq(pdev, 0);
+       if (!res || dec_irq < 0) {
+               dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0,
+                              pdev->name, jpeg);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n",
+                       dec_irq, ret);
+               ret = -EINVAL;
+               goto err_req_irq;
+       }
+
+       ret = mtk_jpeg_clk_init(jpeg);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret);
+               goto err_clk_init;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+               ret = -EINVAL;
+               goto err_dev_register;
+       }
+
+       jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops);
+       if (IS_ERR(jpeg->m2m_dev)) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(jpeg->m2m_dev);
+               goto err_m2m_init;
+       }
+
+       jpeg->dec_vdev = video_device_alloc();
+       if (!jpeg->dec_vdev) {
+               ret = -ENOMEM;
+               goto err_dec_vdev_alloc;
+       }
+       snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name),
+                "%s-dec", MTK_JPEG_NAME);
+       jpeg->dec_vdev->fops = &mtk_jpeg_fops;
+       jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops;
+       jpeg->dec_vdev->minor = -1;
+       jpeg->dec_vdev->release = video_device_release;
+       jpeg->dec_vdev->lock = &jpeg->lock;
+       jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
+       jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
+       jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
+                                     V4L2_CAP_VIDEO_M2M_MPLANE;
+
+       ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3);
+       if (ret) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+               goto err_dec_vdev_register;
+       }
+
+       video_set_drvdata(jpeg->dec_vdev, jpeg);
+       v4l2_info(&jpeg->v4l2_dev,
+                 "decoder device registered as /dev/video%d (%d,%d)\n",
+                 jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor);
+
+       platform_set_drvdata(pdev, jpeg);
+
+       pm_runtime_enable(&pdev->dev);
+
+       return 0;
+
+err_dec_vdev_register:
+       video_device_release(jpeg->dec_vdev);
+
+err_dec_vdev_alloc:
+       v4l2_m2m_release(jpeg->m2m_dev);
+
+err_m2m_init:
+       v4l2_device_unregister(&jpeg->v4l2_dev);
+
+err_dev_register:
+
+err_clk_init:
+
+err_req_irq:
+
+       return ret;
+}
+
+static int mtk_jpeg_remove(struct platform_device *pdev)
+{
+       struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       video_unregister_device(jpeg->dec_vdev);
+       video_device_release(jpeg->dec_vdev);
+       v4l2_m2m_release(jpeg->m2m_dev);
+       v4l2_device_unregister(&jpeg->v4l2_dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mtk_jpeg_pm_suspend(struct device *dev)
+{
+       struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+       mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+       mtk_jpeg_clk_off(jpeg);
+
+       return 0;
+}
+
+static int mtk_jpeg_pm_resume(struct device *dev)
+{
+       struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+       mtk_jpeg_clk_on(jpeg);
+       mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_jpeg_suspend(struct device *dev)
+{
+       int ret;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       ret = mtk_jpeg_pm_suspend(dev);
+       return ret;
+}
+
+static int mtk_jpeg_resume(struct device *dev)
+{
+       int ret;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       ret = mtk_jpeg_pm_resume(dev);
+
+       return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops mtk_jpeg_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(mtk_jpeg_suspend, mtk_jpeg_resume)
+       SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL)
+};
+
+static const struct of_device_id mtk_jpeg_match[] = {
+       {
+               .compatible = "mediatek,mt8173-jpgdec",
+               .data       = NULL,
+       },
+       {
+               .compatible = "mediatek,mt2701-jpgdec",
+               .data       = NULL,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
+
+static struct platform_driver mtk_jpeg_driver = {
+       .probe = mtk_jpeg_probe,
+       .remove = mtk_jpeg_remove,
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = MTK_JPEG_NAME,
+               .of_match_table = mtk_jpeg_match,
+               .pm             = &mtk_jpeg_pm_ops,
+       },
+};
+
+module_platform_driver(mtk_jpeg_driver);
+
+MODULE_DESCRIPTION("MediaTek JPEG codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
new file mode 100644 (file)
index 0000000..1a6cdfd
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#ifndef _MTK_JPEG_CORE_H
+#define _MTK_JPEG_CORE_H
+
+#include <linux/interrupt.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+
+#define MTK_JPEG_NAME          "mtk-jpeg"
+
+#define MTK_JPEG_FMT_FLAG_DEC_OUTPUT   BIT(0)
+#define MTK_JPEG_FMT_FLAG_DEC_CAPTURE  BIT(1)
+
+#define MTK_JPEG_FMT_TYPE_OUTPUT       1
+#define MTK_JPEG_FMT_TYPE_CAPTURE      2
+
+#define MTK_JPEG_MIN_WIDTH     32
+#define MTK_JPEG_MIN_HEIGHT    32
+#define MTK_JPEG_MAX_WIDTH     8192
+#define MTK_JPEG_MAX_HEIGHT    8192
+
+#define MTK_JPEG_DEFAULT_SIZEIMAGE     (1 * 1024 * 1024)
+
+enum mtk_jpeg_ctx_state {
+       MTK_JPEG_INIT = 0,
+       MTK_JPEG_RUNNING,
+       MTK_JPEG_SOURCE_CHANGE,
+};
+
+/**
+ * struct mt_jpeg - JPEG IP abstraction
+ * @lock:              the mutex protecting this structure
+ * @hw_lock:           spinlock protecting the hw device resource
+ * @workqueue:         decode work queue
+ * @dev:               JPEG device
+ * @v4l2_dev:          v4l2 device for mem2mem mode
+ * @m2m_dev:           v4l2 mem2mem device data
+ * @alloc_ctx:         videobuf2 memory allocator's context
+ * @dec_vdev:          video device node for decoder mem2mem mode
+ * @dec_reg_base:      JPEG registers mapping
+ * @clk_jdec:          JPEG hw working clock
+ * @clk_jdec_smi:      JPEG SMI bus clock
+ * @larb:              SMI device
+ */
+struct mtk_jpeg_dev {
+       struct mutex            lock;
+       spinlock_t              hw_lock;
+       struct workqueue_struct *workqueue;
+       struct device           *dev;
+       struct v4l2_device      v4l2_dev;
+       struct v4l2_m2m_dev     *m2m_dev;
+       void                    *alloc_ctx;
+       struct video_device     *dec_vdev;
+       void __iomem            *dec_reg_base;
+       struct clk              *clk_jdec;
+       struct clk              *clk_jdec_smi;
+       struct device           *larb;
+};
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @fourcc:    the fourcc code, 0 if not applicable
+ * @h_sample:  horizontal sample count of plane in 4 * 4 pixel image
+ * @v_sample:  vertical sample count of plane in 4 * 4 pixel image
+ * @colplanes: number of color planes (1 for packed formats)
+ * @h_align:   horizontal alignment order (align to 2^h_align)
+ * @v_align:   vertical alignment order (align to 2^v_align)
+ * @flags:     flags describing format applicability
+ */
+struct mtk_jpeg_fmt {
+       u32     fourcc;
+       int     h_sample[VIDEO_MAX_PLANES];
+       int     v_sample[VIDEO_MAX_PLANES];
+       int     colplanes;
+       int     h_align;
+       int     v_align;
+       u32     flags;
+};
+
+/**
+ * mtk_jpeg_q_data - parameters of one queue
+ * @fmt:         driver-specific format of this queue
+ * @w:           image width
+ * @h:           image height
+ * @bytesperline: distance in bytes between the leftmost pixels in two adjacent
+ *                lines
+ * @sizeimage:   image buffer size in bytes
+ */
+struct mtk_jpeg_q_data {
+       struct mtk_jpeg_fmt     *fmt;
+       u32                     w;
+       u32                     h;
+       u32                     bytesperline[VIDEO_MAX_PLANES];
+       u32                     sizeimage[VIDEO_MAX_PLANES];
+};
+
+/**
+ * mtk_jpeg_ctx - the device context data
+ * @jpeg:              JPEG IP device for this context
+ * @out_q:             source (output) queue information
+ * @cap_q:             destination (capture) queue queue information
+ * @fh:                        V4L2 file handle
+ * @dec_param          parameters for HW decoding
+ * @state:             state of the context
+ * @header_valid:      set if header has been parsed and valid
+ * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
+ * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization: enum v4l2_quantization, colorspace quantization
+ * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ */
+struct mtk_jpeg_ctx {
+       struct mtk_jpeg_dev             *jpeg;
+       struct mtk_jpeg_q_data          out_q;
+       struct mtk_jpeg_q_data          cap_q;
+       struct v4l2_fh                  fh;
+       enum mtk_jpeg_ctx_state         state;
+
+       enum v4l2_colorspace colorspace;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_quantization quantization;
+       enum v4l2_xfer_func xfer_func;
+};
+
+#endif /* _MTK_JPEG_CORE_H */
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
new file mode 100644 (file)
index 0000000..77b4cc6
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <media/videobuf2-core.h>
+
+#include "mtk_jpeg_hw.h"
+
+#define MTK_JPEG_DUNUM_MASK(val)       (((val) - 1) & 0x3)
+
+enum mtk_jpeg_color {
+       MTK_JPEG_COLOR_420              = 0x00221111,
+       MTK_JPEG_COLOR_422              = 0x00211111,
+       MTK_JPEG_COLOR_444              = 0x00111111,
+       MTK_JPEG_COLOR_422V             = 0x00121111,
+       MTK_JPEG_COLOR_422X2            = 0x00412121,
+       MTK_JPEG_COLOR_422VX2           = 0x00222121,
+       MTK_JPEG_COLOR_400              = 0x00110000
+};
+
+static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg)
+{
+       if (val & (align - 1)) {
+               pr_err("mtk-jpeg: write reg %x without %d align\n", reg, align);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int mtk_jpeg_decide_format(struct mtk_jpeg_dec_param *param)
+{
+       param->src_color = (param->sampling_w[0] << 20) |
+                          (param->sampling_h[0] << 16) |
+                          (param->sampling_w[1] << 12) |
+                          (param->sampling_h[1] << 8) |
+                          (param->sampling_w[2] << 4) |
+                          (param->sampling_h[2]);
+
+       param->uv_brz_w = 0;
+       switch (param->src_color) {
+       case MTK_JPEG_COLOR_444:
+               param->uv_brz_w = 1;
+               param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
+               break;
+       case MTK_JPEG_COLOR_422X2:
+       case MTK_JPEG_COLOR_422:
+               param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
+               break;
+       case MTK_JPEG_COLOR_422V:
+       case MTK_JPEG_COLOR_422VX2:
+               param->uv_brz_w = 1;
+               param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
+               break;
+       case MTK_JPEG_COLOR_420:
+               param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
+               break;
+       case MTK_JPEG_COLOR_400:
+               param->dst_fourcc = V4L2_PIX_FMT_GREY;
+               break;
+       default:
+               param->dst_fourcc = 0;
+               return -1;
+       }
+
+       return 0;
+}
+
+static void mtk_jpeg_calc_mcu(struct mtk_jpeg_dec_param *param)
+{
+       u32 factor_w, factor_h;
+       u32 i, comp, blk;
+
+       factor_w = 2 + param->sampling_w[0];
+       factor_h = 2 + param->sampling_h[0];
+       param->mcu_w = (param->pic_w + (1 << factor_w) - 1) >> factor_w;
+       param->mcu_h = (param->pic_h + (1 << factor_h) - 1) >> factor_h;
+       param->total_mcu = param->mcu_w * param->mcu_h;
+       param->unit_num = ((param->pic_w + 7) >> 3) * ((param->pic_h + 7) >> 3);
+       param->blk_num = 0;
+       for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
+               param->blk_comp[i] = 0;
+               if (i >= param->comp_num)
+                       continue;
+               param->blk_comp[i] = param->sampling_w[i] *
+                                    param->sampling_h[i];
+               param->blk_num += param->blk_comp[i];
+       }
+
+       param->membership = 0;
+       for (i = 0, blk = 0, comp = 0; i < MTK_JPEG_BLOCK_MAX; i++) {
+               if (i < param->blk_num && comp < param->comp_num) {
+                       u32 tmp;
+
+                       tmp = (0x04 + (comp & 0x3));
+                       param->membership |= tmp << (i * 3);
+                       if (++blk == param->blk_comp[comp]) {
+                               comp++;
+                               blk = 0;
+                       }
+               } else {
+                       param->membership |=  7 << (i * 3);
+               }
+       }
+}
+
+static void mtk_jpeg_calc_dma_group(struct mtk_jpeg_dec_param *param)
+{
+       u32 factor_mcu = 3;
+
+       if (param->src_color == MTK_JPEG_COLOR_444 &&
+           param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
+               factor_mcu = 4;
+       else if (param->src_color == MTK_JPEG_COLOR_422V &&
+                param->dst_fourcc == V4L2_PIX_FMT_YUV420M)
+               factor_mcu = 4;
+       else if (param->src_color == MTK_JPEG_COLOR_422X2 &&
+                param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
+               factor_mcu = 2;
+       else if (param->src_color == MTK_JPEG_COLOR_400 ||
+                (param->src_color & 0x0FFFF) == 0)
+               factor_mcu = 4;
+
+       param->dma_mcu = 1 << factor_mcu;
+       param->dma_group = param->mcu_w / param->dma_mcu;
+       param->dma_last_mcu = param->mcu_w % param->dma_mcu;
+       if (param->dma_last_mcu)
+               param->dma_group++;
+       else
+               param->dma_last_mcu = param->dma_mcu;
+}
+
+static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param)
+{
+       u32 i, padding_w;
+       u32 ds_row_h[3];
+       u32 brz_w[3];
+
+       brz_w[0] = 0;
+       brz_w[1] = param->uv_brz_w;
+       brz_w[2] = brz_w[1];
+
+       for (i = 0; i < param->comp_num; i++) {
+               if (brz_w[i] > 3)
+                       return -1;
+
+               padding_w = param->mcu_w * MTK_JPEG_DCTSIZE *
+                               param->sampling_w[i];
+               /* output format is 420/422 */
+               param->comp_w[i] = padding_w >> brz_w[i];
+               param->comp_w[i] = mtk_jpeg_align(param->comp_w[i],
+                                                 MTK_JPEG_DCTSIZE);
+               param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16)
+                                       : mtk_jpeg_align(param->comp_w[i], 32);
+               ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]);
+       }
+       param->dec_w = param->img_stride[0];
+       param->dec_h = ds_row_h[0] * param->mcu_h;
+
+       for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
+               /* They must be equal in frame mode. */
+               param->mem_stride[i] = param->img_stride[i];
+               param->comp_size[i] = param->mem_stride[i] * ds_row_h[i] *
+                                     param->mcu_h;
+       }
+
+       param->y_size = param->comp_size[0];
+       param->uv_size = param->comp_size[1];
+       param->dec_size = param->y_size + (param->uv_size << 1);
+
+       return 0;
+}
+
+int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param)
+{
+       if (mtk_jpeg_decide_format(param))
+               return -1;
+
+       mtk_jpeg_calc_mcu(param);
+       mtk_jpeg_calc_dma_group(param);
+       if (mtk_jpeg_calc_dst_size(param))
+               return -2;
+
+       return 0;
+}
+
+u32 mtk_jpeg_dec_get_int_status(void __iomem *base)
+{
+       u32 ret;
+
+       ret = readl(base + JPGDEC_REG_INTERRUPT_STATUS) & BIT_INQST_MASK_ALLIRQ;
+       if (ret)
+               writel(ret, base + JPGDEC_REG_INTERRUPT_STATUS);
+
+       return ret;
+}
+
+u32 mtk_jpeg_dec_enum_result(u32 irq_result)
+{
+       if (irq_result & BIT_INQST_MASK_EOF)
+               return MTK_JPEG_DEC_RESULT_EOF_DONE;
+       if (irq_result & BIT_INQST_MASK_PAUSE)
+               return MTK_JPEG_DEC_RESULT_PAUSE;
+       if (irq_result & BIT_INQST_MASK_UNDERFLOW)
+               return MTK_JPEG_DEC_RESULT_UNDERFLOW;
+       if (irq_result & BIT_INQST_MASK_OVERFLOW)
+               return MTK_JPEG_DEC_RESULT_OVERFLOW;
+       if (irq_result & BIT_INQST_MASK_ERROR_BS)
+               return MTK_JPEG_DEC_RESULT_ERROR_BS;
+
+       return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN;
+}
+
+void mtk_jpeg_dec_start(void __iomem *base)
+{
+       writel(0, base + JPGDEC_REG_TRIG);
+}
+
+static void mtk_jpeg_dec_soft_reset(void __iomem *base)
+{
+       writel(0x0000FFFF, base + JPGDEC_REG_INTERRUPT_STATUS);
+       writel(0x00, base + JPGDEC_REG_RESET);
+       writel(0x01, base + JPGDEC_REG_RESET);
+}
+
+static void mtk_jpeg_dec_hard_reset(void __iomem *base)
+{
+       writel(0x00, base + JPGDEC_REG_RESET);
+       writel(0x10, base + JPGDEC_REG_RESET);
+}
+
+void mtk_jpeg_dec_reset(void __iomem *base)
+{
+       mtk_jpeg_dec_soft_reset(base);
+       mtk_jpeg_dec_hard_reset(base);
+}
+
+static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w,
+                                       u8 yscale_h, u8 uvscale_w, u8 uvscale_h)
+{
+       u32 val;
+
+       val = (uvscale_h << 12) | (uvscale_w << 8) |
+             (yscale_h << 4) | yscale_w;
+       writel(val, base + JPGDEC_REG_BRZ_FACTOR);
+}
+
+static void mtk_jpeg_dec_set_dst_bank0(void __iomem *base, u32 addr_y,
+                                      u32 addr_u, u32 addr_v)
+{
+       mtk_jpeg_verify_align(addr_y, 16, JPGDEC_REG_DEST_ADDR0_Y);
+       writel(addr_y, base + JPGDEC_REG_DEST_ADDR0_Y);
+       mtk_jpeg_verify_align(addr_u, 16, JPGDEC_REG_DEST_ADDR0_U);
+       writel(addr_u, base + JPGDEC_REG_DEST_ADDR0_U);
+       mtk_jpeg_verify_align(addr_v, 16, JPGDEC_REG_DEST_ADDR0_V);
+       writel(addr_v, base + JPGDEC_REG_DEST_ADDR0_V);
+}
+
+static void mtk_jpeg_dec_set_dst_bank1(void __iomem *base, u32 addr_y,
+                                      u32 addr_u, u32 addr_v)
+{
+       writel(addr_y, base + JPGDEC_REG_DEST_ADDR1_Y);
+       writel(addr_u, base + JPGDEC_REG_DEST_ADDR1_U);
+       writel(addr_v, base + JPGDEC_REG_DEST_ADDR1_V);
+}
+
+static void mtk_jpeg_dec_set_mem_stride(void __iomem *base, u32 stride_y,
+                                       u32 stride_uv)
+{
+       writel((stride_y & 0xFFFF), base + JPGDEC_REG_STRIDE_Y);
+       writel((stride_uv & 0xFFFF), base + JPGDEC_REG_STRIDE_UV);
+}
+
+static void mtk_jpeg_dec_set_img_stride(void __iomem *base, u32 stride_y,
+                                       u32 stride_uv)
+{
+       writel((stride_y & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_Y);
+       writel((stride_uv & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_UV);
+}
+
+static void mtk_jpeg_dec_set_pause_mcu_idx(void __iomem *base, u32 idx)
+{
+       writel(idx & 0x0003FFFFFF, base + JPGDEC_REG_PAUSE_MCU_NUM);
+}
+
+static void mtk_jpeg_dec_set_dec_mode(void __iomem *base, u32 mode)
+{
+       writel(mode & 0x03, base + JPGDEC_REG_OPERATION_MODE);
+}
+
+static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr)
+{
+       mtk_jpeg_verify_align(ptr, 16, JPGDEC_REG_FILE_BRP);
+       writel(ptr, base + JPGDEC_REG_FILE_BRP);
+}
+
+static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size)
+{
+       mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR);
+       mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE);
+       writel(addr, base + JPGDEC_REG_FILE_ADDR);
+       writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE);
+}
+
+static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u,
+                                    u32 id_v)
+{
+       u32 val;
+
+       val = ((id_y & 0x00FF) << 24) | ((id_u & 0x00FF) << 16) |
+             ((id_v & 0x00FF) << 8);
+       writel(val, base + JPGDEC_REG_COMP_ID);
+}
+
+static void mtk_jpeg_dec_set_total_mcu(void __iomem *base, u32 num)
+{
+       writel(num - 1, base + JPGDEC_REG_TOTAL_MCU_NUM);
+}
+
+static void mtk_jpeg_dec_set_comp0_du(void __iomem *base, u32 num)
+{
+       writel(num - 1, base + JPGDEC_REG_COMP0_DATA_UNIT_NUM);
+}
+
+static void mtk_jpeg_dec_set_du_membership(void __iomem *base, u32 member,
+                                          u32 gmc, u32 isgray)
+{
+       if (isgray)
+               member = 0x3FFFFFFC;
+       member |= (isgray << 31) | (gmc << 30);
+       writel(member, base + JPGDEC_REG_DU_CTRL);
+}
+
+static void mtk_jpeg_dec_set_q_table(void __iomem *base, u32 id0, u32 id1,
+                                    u32 id2)
+{
+       u32 val;
+
+       val = ((id0 & 0x0f) << 8) | ((id1 & 0x0f) << 4) | ((id2 & 0x0f) << 0);
+       writel(val, base + JPGDEC_REG_QT_ID);
+}
+
+static void mtk_jpeg_dec_set_dma_group(void __iomem *base, u32 mcu_group,
+                                      u32 group_num, u32 last_mcu)
+{
+       u32 val;
+
+       val = (((mcu_group - 1) & 0x00FF) << 16) |
+             (((group_num - 1) & 0x007F) << 8) |
+             ((last_mcu - 1) & 0x00FF);
+       writel(val, base + JPGDEC_REG_WDMA_CTRL);
+}
+
+static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num,
+                                            u32 y_w, u32 y_h, u32 u_w,
+                                            u32 u_h, u32 v_w, u32 v_h)
+{
+       u32 val;
+       u32 y_wh = (MTK_JPEG_DUNUM_MASK(y_w) << 2) | MTK_JPEG_DUNUM_MASK(y_h);
+       u32 u_wh = (MTK_JPEG_DUNUM_MASK(u_w) << 2) | MTK_JPEG_DUNUM_MASK(u_h);
+       u32 v_wh = (MTK_JPEG_DUNUM_MASK(v_w) << 2) | MTK_JPEG_DUNUM_MASK(v_h);
+
+       if (comp_num == 1)
+               val = 0;
+       else
+               val = (y_wh << 8) | (u_wh << 4) | v_wh;
+       writel(val, base + JPGDEC_REG_DU_NUM);
+}
+
+void mtk_jpeg_dec_set_config(void __iomem *base,
+                            struct mtk_jpeg_dec_param *config,
+                            struct mtk_jpeg_bs *bs,
+                            struct mtk_jpeg_fb *fb)
+{
+       mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0);
+       mtk_jpeg_dec_set_dec_mode(base, 0);
+       mtk_jpeg_dec_set_comp0_du(base, config->unit_num);
+       mtk_jpeg_dec_set_total_mcu(base, config->total_mcu);
+       mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size);
+       mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr);
+       mtk_jpeg_dec_set_du_membership(base, config->membership, 1,
+                                      (config->comp_num == 1) ? 1 : 0);
+       mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1],
+                                config->comp_id[2]);
+       mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0],
+                                config->qtbl_num[1], config->qtbl_num[2]);
+       mtk_jpeg_dec_set_sampling_factor(base, config->comp_num,
+                                        config->sampling_w[0],
+                                        config->sampling_h[0],
+                                        config->sampling_w[1],
+                                        config->sampling_h[1],
+                                        config->sampling_w[2],
+                                        config->sampling_h[2]);
+       mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0],
+                                   config->mem_stride[1]);
+       mtk_jpeg_dec_set_img_stride(base, config->img_stride[0],
+                                   config->img_stride[1]);
+       mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0],
+                                  fb->plane_addr[1], fb->plane_addr[2]);
+       mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0);
+       mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group,
+                                  config->dma_last_mcu);
+       mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu);
+}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
new file mode 100644 (file)
index 0000000..37152a6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#ifndef _MTK_JPEG_HW_H
+#define _MTK_JPEG_HW_H
+
+#include <media/videobuf2-core.h>
+
+#include "mtk_jpeg_core.h"
+#include "mtk_jpeg_reg.h"
+
+enum {
+       MTK_JPEG_DEC_RESULT_EOF_DONE            = 0,
+       MTK_JPEG_DEC_RESULT_PAUSE               = 1,
+       MTK_JPEG_DEC_RESULT_UNDERFLOW           = 2,
+       MTK_JPEG_DEC_RESULT_OVERFLOW            = 3,
+       MTK_JPEG_DEC_RESULT_ERROR_BS            = 4,
+       MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN       = 6
+};
+
+struct mtk_jpeg_dec_param {
+       u32 pic_w;
+       u32 pic_h;
+       u32 dec_w;
+       u32 dec_h;
+       u32 src_color;
+       u32 dst_fourcc;
+       u32 mcu_w;
+       u32 mcu_h;
+       u32 total_mcu;
+       u32 unit_num;
+       u32 comp_num;
+       u32 comp_id[MTK_JPEG_COMP_MAX];
+       u32 sampling_w[MTK_JPEG_COMP_MAX];
+       u32 sampling_h[MTK_JPEG_COMP_MAX];
+       u32 qtbl_num[MTK_JPEG_COMP_MAX];
+       u32 blk_num;
+       u32 blk_comp[MTK_JPEG_COMP_MAX];
+       u32 membership;
+       u32 dma_mcu;
+       u32 dma_group;
+       u32 dma_last_mcu;
+       u32 img_stride[MTK_JPEG_COMP_MAX];
+       u32 mem_stride[MTK_JPEG_COMP_MAX];
+       u32 comp_w[MTK_JPEG_COMP_MAX];
+       u32 comp_size[MTK_JPEG_COMP_MAX];
+       u32 y_size;
+       u32 uv_size;
+       u32 dec_size;
+       u8 uv_brz_w;
+};
+
+static inline u32 mtk_jpeg_align(u32 val, u32 align)
+{
+       return (val + align - 1) & ~(align - 1);
+}
+
+struct mtk_jpeg_bs {
+       dma_addr_t      str_addr;
+       dma_addr_t      end_addr;
+       size_t          size;
+};
+
+struct mtk_jpeg_fb {
+       dma_addr_t      plane_addr[MTK_JPEG_COMP_MAX];
+       size_t          size;
+};
+
+int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param);
+u32 mtk_jpeg_dec_get_int_status(void __iomem *dec_reg_base);
+u32 mtk_jpeg_dec_enum_result(u32 irq_result);
+void mtk_jpeg_dec_set_config(void __iomem *base,
+                            struct mtk_jpeg_dec_param *config,
+                            struct mtk_jpeg_bs *bs,
+                            struct mtk_jpeg_fb *fb);
+void mtk_jpeg_dec_reset(void __iomem *dec_reg_base);
+void mtk_jpeg_dec_start(void __iomem *dec_reg_base);
+
+#endif /* _MTK_JPEG_HW_H */
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
new file mode 100644 (file)
index 0000000..3886854
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+#include "mtk_jpeg_parse.h"
+
+#define TEM    0x01
+#define SOF0   0xc0
+#define RST    0xd0
+#define SOI    0xd8
+#define EOI    0xd9
+
+struct mtk_jpeg_stream {
+       u8 *addr;
+       u32 size;
+       u32 curr;
+};
+
+static int read_byte(struct mtk_jpeg_stream *stream)
+{
+       if (stream->curr >= stream->size)
+               return -1;
+       return stream->addr[stream->curr++];
+}
+
+static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word)
+{
+       u32 temp;
+       int byte;
+
+       byte = read_byte(stream);
+       if (byte == -1)
+               return -1;
+       temp = byte << 8;
+       byte = read_byte(stream);
+       if (byte == -1)
+               return -1;
+       *word = (u32)byte | temp;
+
+       return 0;
+}
+
+static void read_skip(struct mtk_jpeg_stream *stream, long len)
+{
+       if (len <= 0)
+               return;
+       while (len--)
+               read_byte(stream);
+}
+
+static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+                             u32 src_size)
+{
+       bool notfound = true;
+       struct mtk_jpeg_stream stream;
+
+       stream.addr = src_addr_va;
+       stream.size = src_size;
+       stream.curr = 0;
+
+       while (notfound) {
+               int i, length, byte;
+               u32 word;
+
+               byte = read_byte(&stream);
+               if (byte == -1)
+                       return false;
+               if (byte != 0xff)
+                       continue;
+               do
+                       byte = read_byte(&stream);
+               while (byte == 0xff);
+               if (byte == -1)
+                       return false;
+               if (byte == 0)
+                       continue;
+
+               length = 0;
+               switch (byte) {
+               case SOF0:
+                       /* length */
+                       if (read_word_be(&stream, &word))
+                               break;
+
+                       /* precision */
+                       if (read_byte(&stream) == -1)
+                               break;
+
+                       if (read_word_be(&stream, &word))
+                               break;
+                       param->pic_h = word;
+
+                       if (read_word_be(&stream, &word))
+                               break;
+                       param->pic_w = word;
+
+                       param->comp_num = read_byte(&stream);
+                       if (param->comp_num != 1 && param->comp_num != 3)
+                               break;
+
+                       for (i = 0; i < param->comp_num; i++) {
+                               param->comp_id[i] = read_byte(&stream);
+                               if (param->comp_id[i] == -1)
+                                       break;
+
+                               /* sampling */
+                               byte = read_byte(&stream);
+                               if (byte == -1)
+                                       break;
+                               param->sampling_w[i] = (byte >> 4) & 0x0F;
+                               param->sampling_h[i] = byte & 0x0F;
+
+                               param->qtbl_num[i] = read_byte(&stream);
+                               if (param->qtbl_num[i] == -1)
+                                       break;
+                       }
+
+                       notfound = !(i == param->comp_num);
+                       break;
+               case RST ... RST + 7:
+               case SOI:
+               case EOI:
+               case TEM:
+                       break;
+               default:
+                       if (read_word_be(&stream, &word))
+                               break;
+                       length = (long)word - 2;
+                       read_skip(&stream, length);
+                       break;
+               }
+       }
+
+       return !notfound;
+}
+
+bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+                   u32 src_size)
+{
+       if (!mtk_jpeg_do_parse(param, src_addr_va, src_size))
+               return false;
+       if (mtk_jpeg_dec_fill_param(param))
+               return false;
+
+       return true;
+}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
new file mode 100644 (file)
index 0000000..5d92340
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#ifndef _MTK_JPEG_PARSE_H
+#define _MTK_JPEG_PARSE_H
+
+#include "mtk_jpeg_hw.h"
+
+bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+                   u32 src_size);
+
+#endif /* _MTK_JPEG_PARSE_H */
+
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
new file mode 100644 (file)
index 0000000..fc490d6
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ *         Rick Chang <rick.chang@mediatek.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.
+ */
+
+#ifndef _MTK_JPEG_REG_H
+#define _MTK_JPEG_REG_H
+
+#define MTK_JPEG_COMP_MAX              3
+#define MTK_JPEG_BLOCK_MAX             10
+#define MTK_JPEG_DCTSIZE               8
+
+#define BIT_INQST_MASK_ERROR_BS                0x20
+#define BIT_INQST_MASK_PAUSE           0x10
+#define BIT_INQST_MASK_OVERFLOW                0x04
+#define BIT_INQST_MASK_UNDERFLOW       0x02
+#define BIT_INQST_MASK_EOF             0x01
+#define BIT_INQST_MASK_ALLIRQ          0x37
+
+#define JPGDEC_REG_RESET               0x0090
+#define JPGDEC_REG_BRZ_FACTOR          0x00F8
+#define JPGDEC_REG_DU_NUM              0x00FC
+#define JPGDEC_REG_DEST_ADDR0_Y                0x0140
+#define JPGDEC_REG_DEST_ADDR0_U                0x0144
+#define JPGDEC_REG_DEST_ADDR0_V                0x0148
+#define JPGDEC_REG_DEST_ADDR1_Y                0x014C
+#define JPGDEC_REG_DEST_ADDR1_U                0x0150
+#define JPGDEC_REG_DEST_ADDR1_V                0x0154
+#define JPGDEC_REG_STRIDE_Y            0x0158
+#define JPGDEC_REG_STRIDE_UV           0x015C
+#define JPGDEC_REG_IMG_STRIDE_Y                0x0160
+#define JPGDEC_REG_IMG_STRIDE_UV       0x0164
+#define JPGDEC_REG_WDMA_CTRL           0x016C
+#define JPGDEC_REG_PAUSE_MCU_NUM       0x0170
+#define JPGDEC_REG_OPERATION_MODE      0x017C
+#define JPGDEC_REG_FILE_ADDR           0x0200
+#define JPGDEC_REG_COMP_ID             0x020C
+#define JPGDEC_REG_TOTAL_MCU_NUM       0x0210
+#define JPGDEC_REG_COMP0_DATA_UNIT_NUM 0x0224
+#define JPGDEC_REG_DU_CTRL             0x023C
+#define JPGDEC_REG_TRIG                        0x0240
+#define JPGDEC_REG_FILE_BRP            0x0248
+#define JPGDEC_REG_FILE_TOTAL_SIZE     0x024C
+#define JPGDEC_REG_QT_ID               0x0270
+#define JPGDEC_REG_INTERRUPT_STATUS    0x0274
+#define JPGDEC_REG_STATUS              0x0278
+
+#endif /* _MTK_JPEG_REG_H */
index 823608112d89c14272c9ca2f5f8ebf46ffd30383..7918b928f0589b59b52c17c8470c3e3159d33c1e 100644 (file)
@@ -632,8 +632,8 @@ static int bdisp_open(struct file *file)
 
 error_ctrls:
        bdisp_ctrls_delete(ctx);
-error_fh:
        v4l2_fh_del(&ctx->fh);
+error_fh:
        v4l2_fh_exit(&ctx->fh);
        bdisp_hw_free_nodes(ctx);
 mem_ctx:
index 23472e3784ff169f0c05c9bcb473cccb6d9af0d0..e2cf2b90e500fb81480f6a7b1b2f62333260dcb3 100644 (file)
@@ -801,17 +801,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
  * flags: VPDMA flags to configure some descriptor fileds
  */
 void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const struct v4l2_rect *c_rect,
                const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
                int max_w, int max_h, enum vpdma_channel chan, u32 flags)
 {
-       vpdma_rawchan_add_out_dtd(list, width, c_rect, fmt, dma_addr,
+       vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr,
                                  max_w, max_h, chan_info[chan].num, flags);
 }
 EXPORT_SYMBOL(vpdma_add_out_dtd);
 
 void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const struct v4l2_rect *c_rect,
                const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
                int max_w, int max_h, int raw_vpdma_chan, u32 flags)
 {
@@ -821,7 +821,6 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width,
        int channel, next_chan;
        struct v4l2_rect rect = *c_rect;
        int depth = fmt->depth;
-       int stride;
        struct vpdma_dtd *dtd;
 
        channel = next_chan = raw_vpdma_chan;
@@ -833,8 +832,6 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width,
                depth = 8;
        }
 
-       stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
-
        dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
        dtd = list->next;
@@ -882,7 +879,7 @@ EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd);
  *                     contribute to the client)
  */
 void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const 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 frame_width,
                int frame_height, int start_h, int start_v)
@@ -892,7 +889,6 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
        int depth = fmt->depth;
        int channel, next_chan;
        struct v4l2_rect rect = *c_rect;
-       int stride;
        struct vpdma_dtd *dtd;
 
        channel = next_chan = chan_info[chan].num;
@@ -904,8 +900,6 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
                depth = 8;
        }
 
-       stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
-
        dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
        dtd = list->next;
index 131700c112b2675d2cde282ac8c43057c3d9c5a6..7e611501c291696a45b6283d064d2ac8fccd0405 100644 (file)
@@ -242,16 +242,16 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list,
                int chan_num);
 void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const struct v4l2_rect *c_rect,
                const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
                int max_w, int max_h, enum vpdma_channel chan, u32 flags);
 void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const struct v4l2_rect *c_rect,
                const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
                int max_w, int max_h, int raw_vpdma_chan, u32 flags);
 
 void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
-               const struct v4l2_rect *c_rect,
+               int stride, const 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 frame_width,
                int frame_height, int start_h, int start_v);
index f0156b7759e9263d303abdf5e145de6e54f3ac33..c47151495b6f41a52c6331c6729faa07e7c464ad 100644 (file)
@@ -1085,7 +1085,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
        vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1,
                           MAX_W, MAX_H);
 
-       vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+       vpdma_add_out_dtd(&ctx->desc_list, q_data->width,
+                         q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
                          vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1,
                          MAX_OUT_HEIGHT_REG1, p_data->channel, flags);
 }
@@ -1169,7 +1170,8 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
        if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
                frame_height /= 2;
 
-       vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+       vpdma_add_in_dtd(&ctx->desc_list, q_data->width,
+                        q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
                vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
                frame_height, 0, 0);
 }
@@ -1595,6 +1597,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
        struct v4l2_plane_pix_format *plane_fmt;
        unsigned int w_align;
        int i, depth, depth_bytes, height;
+       unsigned int stride = 0;
 
        if (!fmt || !(fmt->types & type)) {
                vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
@@ -1681,16 +1684,27 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
                plane_fmt = &pix->plane_fmt[i];
                depth = fmt->vpdma_fmt[i]->depth;
 
-               if (i == VPE_LUMA)
-                       plane_fmt->bytesperline = (pix->width * depth) >> 3;
-               else
-                       plane_fmt->bytesperline = pix->width;
+               stride = (pix->width * fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
+               if (stride > plane_fmt->bytesperline)
+                       plane_fmt->bytesperline = stride;
+
+               plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline,
+                                               VPDMA_STRIDE_ALIGN);
 
-               if (pix->num_planes == 1 && fmt->coplanar)
-                       depth += fmt->vpdma_fmt[VPE_CHROMA]->depth;
-               plane_fmt->sizeimage =
-                               (pix->height * pix->width * depth) >> 3;
+               if (i == VPE_LUMA) {
+                       plane_fmt->sizeimage = pix->height *
+                                              plane_fmt->bytesperline;
 
+                       if (pix->num_planes == 1 && fmt->coplanar)
+                               plane_fmt->sizeimage += pix->height *
+                                       plane_fmt->bytesperline *
+                                       fmt->vpdma_fmt[VPE_CHROMA]->depth >> 3;
+
+               } else { /* i == VIP_CHROMA */
+                       plane_fmt->sizeimage = (pix->height *
+                                              plane_fmt->bytesperline *
+                                              depth) >> 3;
+               }
                memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved));
        }
 
index db0dd19d227acc313052c1620fe740eb4b02c6f5..94ab1364a792c88c896db3d754e6524c6742dfb0 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_VIVID
        tristate "Virtual Video Test Driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB
+       depends on HAS_DMA
        select FONT_SUPPORT
        select FONT_8x16
        select FB_CFB_FILLRECT
@@ -8,6 +9,7 @@ config VIDEO_VIVID
        select FB_CFB_IMAGEBLIT
        select MEDIA_CEC_EDID
        select VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_DMA_CONTIG
        select VIDEO_V4L2_TPG
        default n
        ---help---
index 51e37812ec98c63c3855ab41507caf7f2f6295f9..ef344b9a48afb22fd7072295b43b8e027b82a3d7 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/videodev2.h>
 #include <linux/v4l2-dv-timings.h>
 #include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-fh.h>
@@ -151,6 +152,12 @@ static bool no_error_inj;
 module_param(no_error_inj, bool, 0444);
 MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls");
 
+static unsigned int allocators[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0 };
+module_param_array(allocators, uint, NULL, 0444);
+MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n"
+                            "\t\t    0 == vmalloc\n"
+                            "\t\t    1 == dma-contig");
+
 static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
 
 const struct v4l2_rect vivid_min_rect = {
@@ -636,6 +643,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
 {
        static const struct v4l2_dv_timings def_dv_timings =
                                        V4L2_DV_BT_CEA_1280X720P60;
+       static const struct vb2_mem_ops * const vivid_mem_ops[2] = {
+               &vb2_vmalloc_memops,
+               &vb2_dma_contig_memops,
+       };
        unsigned in_type_counter[4] = { 0, 0, 0, 0 };
        unsigned out_type_counter[4] = { 0, 0, 0, 0 };
        int ccs_cap = ccs_cap_mode[inst];
@@ -646,6 +657,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
        struct video_device *vfd;
        struct vb2_queue *q;
        unsigned node_type = node_types[inst];
+       unsigned int allocator = allocators[inst];
        v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
        int ret;
        int i;
@@ -1039,6 +1051,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                goto unreg_dev;
        }
 
+       if (allocator == 1)
+               dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       else if (allocator >= ARRAY_SIZE(vivid_mem_ops))
+               allocator = 0;
+
        /* start creating the vb2 queues */
        if (dev->has_vid_cap) {
                /* initialize vid_cap queue */
@@ -1049,10 +1066,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                q->drv_priv = dev;
                q->buf_struct_size = sizeof(struct vivid_buffer);
                q->ops = &vivid_vid_cap_qops;
-               q->mem_ops = &vb2_vmalloc_memops;
+               q->mem_ops = vivid_mem_ops[allocator];
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
                q->min_buffers_needed = 2;
                q->lock = &dev->mutex;
+               q->dev = dev->v4l2_dev.dev;
 
                ret = vb2_queue_init(q);
                if (ret)
@@ -1068,10 +1086,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                q->drv_priv = dev;
                q->buf_struct_size = sizeof(struct vivid_buffer);
                q->ops = &vivid_vid_out_qops;
-               q->mem_ops = &vb2_vmalloc_memops;
+               q->mem_ops = vivid_mem_ops[allocator];
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
                q->min_buffers_needed = 2;
                q->lock = &dev->mutex;
+               q->dev = dev->v4l2_dev.dev;
 
                ret = vb2_queue_init(q);
                if (ret)
@@ -1087,10 +1106,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                q->drv_priv = dev;
                q->buf_struct_size = sizeof(struct vivid_buffer);
                q->ops = &vivid_vbi_cap_qops;
-               q->mem_ops = &vb2_vmalloc_memops;
+               q->mem_ops = vivid_mem_ops[allocator];
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
                q->min_buffers_needed = 2;
                q->lock = &dev->mutex;
+               q->dev = dev->v4l2_dev.dev;
 
                ret = vb2_queue_init(q);
                if (ret)
@@ -1106,10 +1126,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                q->drv_priv = dev;
                q->buf_struct_size = sizeof(struct vivid_buffer);
                q->ops = &vivid_vbi_out_qops;
-               q->mem_ops = &vb2_vmalloc_memops;
+               q->mem_ops = vivid_mem_ops[allocator];
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
                q->min_buffers_needed = 2;
                q->lock = &dev->mutex;
+               q->dev = dev->v4l2_dev.dev;
 
                ret = vb2_queue_init(q);
                if (ret)
@@ -1124,10 +1145,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                q->drv_priv = dev;
                q->buf_struct_size = sizeof(struct vivid_buffer);
                q->ops = &vivid_sdr_cap_qops;
-               q->mem_ops = &vb2_vmalloc_memops;
+               q->mem_ops = vivid_mem_ops[allocator];
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
                q->min_buffers_needed = 8;
                q->lock = &dev->mutex;
+               q->dev = dev->v4l2_dev.dev;
 
                ret = vb2_queue_init(q);
                if (ret)
index 57b250847cd37cf53fe86862121dfae16e109c2c..b46b14997ddd778cdd1d5f4dd55bccae48258f06 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
+ * Silicon Labs Si2141/2146/2147/2148/2151/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -75,6 +75,7 @@ err_mutex_unlock:
        return ret;
 }
 
+#define MAX_RESET_ATTEMPTS 10
 static int si2157_init(struct dvb_frontend *fe)
 {
        struct i2c_client *client = fe->tuner_priv;
@@ -84,7 +85,7 @@ static int si2157_init(struct dvb_frontend *fe)
        struct si2157_cmd cmd;
        const struct firmware *fw;
        const char *fw_name;
-       unsigned int uitmp, chip_id;
+       unsigned int uitmp, chip_id, i;
 
        dev_dbg(&client->dev, "\n");
 
@@ -102,14 +103,44 @@ static int si2157_init(struct dvb_frontend *fe)
        if (uitmp == dev->if_frequency / 1000)
                goto warm;
 
+       if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
+               for (i = 0; i < MAX_RESET_ATTEMPTS; i++)  {
+                       /* reset */
+                       memcpy(cmd.args, "\xc0\x05\x00\x00", 4);
+                       cmd.wlen = 4;
+                       cmd.rlen = 1;
+                       ret = si2157_cmd_execute(client, &cmd);
+                       if (ret)
+                               goto err;
+
+                       memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10);
+                       cmd.wlen = 10;
+                       cmd.rlen = 1;
+                       ret = si2157_cmd_execute(client, &cmd);
+                       if (ret)
+                               goto err;
+                       if (cmd.args[0] != 0xfe)
+                               break;
+               }
+               if (i >= MAX_RESET_ATTEMPTS)
+                       goto err;
+       }
+
        /* power up */
-       if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
+       switch (dev->chiptype) {
+       case SI2157_CHIPTYPE_SI2146:
                memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
                cmd.wlen = 9;
-       } else {
+               break;
+       case SI2157_CHIPTYPE_SI2141:
+               memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x08\x01", 7);
+               cmd.wlen = 7;
+               break;
+       default:
                memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
                cmd.wlen = 15;
        }
+
        cmd.rlen = 1;
        ret = si2157_cmd_execute(client, &cmd);
        if (ret)
@@ -131,6 +162,8 @@ static int si2157_init(struct dvb_frontend *fe)
        #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
        #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
        #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
+       #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
+       #define SI2151_A10 ('A' << 24 | 51 << 16 | '1' << 8 | '0' << 0)
 
        switch (chip_id) {
        case SI2158_A20:
@@ -142,6 +175,10 @@ static int si2157_init(struct dvb_frontend *fe)
        case SI2146_A10:
                fw_name = NULL;
                break;
+       case SI2141_A10:
+       case SI2151_A10:
+               fw_name = SI2141_A10_FIRMWARE;
+               break;
        default:
                dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
                                cmd.args[2], cmd.args[1],
@@ -214,6 +251,23 @@ skip_fw_download:
 
        dev_info(&client->dev, "firmware version: %c.%c.%d\n",
                        cmd.args[6], cmd.args[7], cmd.args[8]);
+
+       if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
+               /* set clock */
+               memcpy(cmd.args, "\xc0\x00\x0d", 3);
+               cmd.wlen = 3;
+               cmd.rlen = 1;
+               ret = si2157_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+               /* setup PIN */
+               memcpy(cmd.args, "\x12\x80\x80\x85\x00\x81\x00", 7);
+               cmd.wlen = 7;
+               cmd.rlen = 7;
+               ret = si2157_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+       }
 warm:
        /* init statistics in order signal app which are supported */
        c->strength.len = 1;
@@ -471,7 +525,8 @@ static int si2157_probe(struct i2c_client *client,
 #endif
 
        dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
-                       dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
+                       dev->chiptype == SI2157_CHIPTYPE_SI2141 ?
+                       "Si2141/2151" : dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
                        "Si2146" : "Si2147/2148/2157/2158");
 
        return 0;
@@ -508,6 +563,8 @@ static int si2157_remove(struct i2c_client *client)
 static const struct i2c_device_id si2157_id_table[] = {
        {"si2157", SI2157_CHIPTYPE_SI2157},
        {"si2146", SI2157_CHIPTYPE_SI2146},
+       {"si2141", SI2157_CHIPTYPE_SI2141},
+       {"si2151", SI2157_CHIPTYPE_SI2141},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, si2157_id_table);
@@ -524,7 +581,8 @@ static struct i2c_driver si2157_driver = {
 
 module_i2c_driver(si2157_driver);
 
-MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver");
+MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2151/2157/2158 silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
+MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
index d6b2c7b4405321558534edf9291dfb217e2e9b76..e6436f74abaafb502f9ac0248a988ce5ec6b343e 100644 (file)
@@ -42,6 +42,7 @@ struct si2157_dev {
 
 #define SI2157_CHIPTYPE_SI2157 0
 #define SI2157_CHIPTYPE_SI2146 1
+#define SI2157_CHIPTYPE_SI2141 2
 
 /* firmware command struct */
 #define SI2157_ARGLEN      30
@@ -52,5 +53,6 @@ struct si2157_cmd {
 };
 
 #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"
+#define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw"
 
 #endif
index 313f659f0bfb00554d8a7c74b57de6b6432d7903..43bfa778b07033bc091278a33a36d10001098a65 100644 (file)
@@ -153,7 +153,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+       tveeprom_hauppauge_analog(&tv, eeprom_data);
        dev->board.tuner_type = tv.tuner_type;
 
        /* Make sure we support the board model */
index f730fdbc915670225ff2ca08a9f4cc60340523ed..9b28d57006af693c0619eedd25630b8e61b19d5e 100644 (file)
@@ -1165,8 +1165,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
                        e->client.addr = 0xa0 >> 1;
 
                        read_eeprom(dev, &e->client, e->eeprom, sizeof(e->eeprom));
-                       tveeprom_hauppauge_analog(&e->client,
-                                               &e->tvee, e->eeprom + 0xc0);
+                       tveeprom_hauppauge_analog(&e->tvee, e->eeprom + 0xc0);
                        kfree(e);
                        break;
                }
index 35e9acfe63d3bff8e9b349740a6ff5bcad95cf24..24e23a06d8c62a71b934f866092828449dad27b0 100644 (file)
@@ -491,20 +491,24 @@ void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port)
 {
        unsigned char buf;
        int i, rc;
-       struct i2c_client client;
+       struct i2c_adapter *adap;
+       struct i2c_msg msg = {
+               .flags = I2C_M_RD,
+               .len = 1,
+               .buf = &buf,
+       };
 
        if (!i2c_scan)
                return;
 
        /* Don't generate I2C errors during scan */
        dev->i2c_scan_running = true;
-
-       memset(&client, 0, sizeof(client));
-       client.adapter = cx231xx_get_i2c_adap(dev, i2c_port);
+       adap = cx231xx_get_i2c_adap(dev, i2c_port);
 
        for (i = 0; i < 128; i++) {
-               client.addr = i;
-               rc = i2c_master_recv(&client, &buf, 0);
+               msg.addr = i;
+               rc = i2c_transfer(adap, &msg, 1);
+
                if (rc < 0)
                        continue;
                dev_info(dev->dev,
index 80c63598052688e7d0ba1392da3b44c47abb5e46..abf69d8fa469e67fb876f8470b4ba29313ae9886 100644 (file)
@@ -919,7 +919,12 @@ static int mxl111sf_init(struct dvb_usb_device *d)
        struct mxl111sf_state *state = d_to_priv(d);
        int ret;
        static u8 eeprom[256];
-       struct i2c_client c;
+       u8 reg = 0;
+       struct i2c_msg msg[2] = {
+               { .addr = 0xa0 >> 1, .len = 1, .buf = &reg },
+               { .addr = 0xa0 >> 1, .flags = I2C_M_RD,
+                 .len = sizeof(eeprom), .buf = eeprom },
+       };
 
        ret = get_chip_info(state);
        if (mxl_fail(ret))
@@ -930,14 +935,11 @@ static int mxl111sf_init(struct dvb_usb_device *d)
        if (state->chip_rev > MXL111SF_V6)
                mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1);
 
-       c.adapter = &d->i2c_adap;
-       c.addr = 0xa0 >> 1;
-
-       ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
+       ret = i2c_transfer(&d->i2c_adap, msg, 2);
        if (mxl_fail(ret))
                return 0;
-       tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ?
-                       eeprom + 0xa0 : eeprom + 0x80);
+       tveeprom_hauppauge_analog(&state->tv, (0x84 == eeprom[0xa0]) ?
+                                 eeprom + 0xa0 : eeprom + 0x80);
 #if 0
        switch (state->tv.model) {
        case 117001:
index 51620e02292f588b6643862c3207aa6d5cd75948..9a7665fddc29d908ff27e5943c57b7b3bccf87c7 100644 (file)
@@ -1239,6 +1239,82 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int cxusb_mygica_t230c_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap->dev;
+       struct cxusb_state *st = d->priv;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client_demod;
+       struct i2c_client *client_tuner;
+       struct i2c_board_info info;
+       struct si2168_config si2168_config;
+       struct si2157_config si2157_config;
+
+       /* Select required USB configuration */
+       if (usb_set_interface(d->udev, 0, 0) < 0)
+               err("set interface failed");
+
+       /* Unblock all USB pipes */
+       usb_clear_halt(d->udev,
+               usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+       usb_clear_halt(d->udev,
+               usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+       usb_clear_halt(d->udev,
+               usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
+
+       /* attach frontend */
+       memset(&si2168_config, 0, sizeof(si2168_config));
+       si2168_config.i2c_adapter = &adapter;
+       si2168_config.fe = &adap->fe_adap[0].fe;
+       si2168_config.ts_mode = SI2168_TS_PARALLEL;
+       si2168_config.ts_clock_inv = 1;
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+       info.addr = 0x64;
+       info.platform_data = &si2168_config;
+       request_module(info.type);
+       client_demod = i2c_new_device(&d->i2c_adap, &info);
+       if (client_demod == NULL || client_demod->dev.driver == NULL)
+               return -ENODEV;
+
+       if (!try_module_get(client_demod->dev.driver->owner)) {
+               i2c_unregister_device(client_demod);
+               return -ENODEV;
+       }
+
+       /* attach tuner */
+       memset(&si2157_config, 0, sizeof(si2157_config));
+       si2157_config.fe = adap->fe_adap[0].fe;
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "si2141", I2C_NAME_SIZE);
+       info.addr = 0x60;
+       info.platform_data = &si2157_config;
+       request_module("si2157");
+       client_tuner = i2c_new_device(adapter, &info);
+       if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
+               module_put(client_demod->dev.driver->owner);
+               i2c_unregister_device(client_demod);
+               return -ENODEV;
+       }
+       if (!try_module_get(client_tuner->dev.driver->owner)) {
+               i2c_unregister_device(client_tuner);
+               module_put(client_demod->dev.driver->owner);
+               i2c_unregister_device(client_demod);
+               return -ENODEV;
+       }
+
+       st->i2c_client_demod = client_demod;
+       st->i2c_client_tuner = client_tuner;
+
+       /* hook fe: need to resync the slave fifo when signal locks. */
+       mutex_init(&st->stream_mutex);
+       st->last_lock = 0;
+       st->fe_read_status = adap->fe_adap[0].fe->ops.read_status;
+       adap->fe_adap[0].fe->ops.read_status = cxusb_read_status;
+
+       return 0;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -1321,6 +1397,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
 static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
 static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
 static struct dvb_usb_device_properties cxusb_mygica_t230_properties;
+static struct dvb_usb_device_properties cxusb_mygica_t230c_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
@@ -1353,6 +1430,8 @@ static int cxusb_probe(struct usb_interface *intf,
                                     THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
                                     THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &cxusb_mygica_t230c_properties,
+                                    THIS_MODULE, NULL, adapter_nr) ||
            0)
                return 0;
 
@@ -1404,6 +1483,7 @@ enum cxusb_table_index {
        CONEXANT_D680_DMB,
        MYGICA_D689,
        MYGICA_T230,
+       MYGICA_T230C,
        NR__cxusb_table_index
 };
 
@@ -1471,6 +1551,9 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
        [MYGICA_T230] = {
                USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230)
        },
+       [MYGICA_T230C] = {
+               USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230+1)
+       },
        {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2165,7 +2248,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
 
        .rc.core = {
                .rc_interval    = 100,
-               .rc_codes       = RC_MAP_D680_DMB,
+               .rc_codes       = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
                .module_name    = KBUILD_MODNAME,
                .rc_query       = cxusb_d680_dmb_rc_query,
                .allowed_protos = RC_BIT_UNKNOWN,
@@ -2181,6 +2264,60 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
        }
 };
 
+static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl         = CYPRESS_FX2,
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+               .num_frontends = 1,
+               .fe = {{
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_mygica_t230c_frontend_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
+               } },
+               },
+       },
+
+       .power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_d680_dmb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {
+                       "Mygica T230C DVB-T/T2/C",
+                       { NULL },
+                       { &cxusb_table[MYGICA_T230C], NULL },
+               },
+       }
+};
+
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
index ab9866024ec7983d597efd157476820222ad8134..04033efe7ad5394d4fd9493ce6b790de1404666b 100644 (file)
@@ -36,16 +36,18 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le
 int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
        struct hexline *hx;
-       u8 reset;
-       int ret,pos=0;
+       u8 *buf;
+       int ret, pos = 0;
+       u16 cpu_cs_register = cypress[type].cpu_cs_register;
 
-       hx = kmalloc(sizeof(*hx), GFP_KERNEL);
-       if (!hx)
+       buf = kmalloc(sizeof(*hx), GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
+       hx = (struct hexline *)buf;
 
        /* stop the CPU */
-       reset = 1;
-       if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+       buf[0] = 1;
+       if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
                err("could not stop the USB controller CPU.");
 
        while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
@@ -61,21 +63,21 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw
        }
        if (ret < 0) {
                err("firmware download failed at %d with %d",pos,ret);
-               kfree(hx);
+               kfree(buf);
                return ret;
        }
 
        if (ret == 0) {
                /* restart the CPU */
-               reset = 0;
-               if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+               buf[0] = 0;
+               if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
        } else
                ret = -EIO;
 
-       kfree(hx);
+       kfree(buf);
 
        return ret;
 }
index 5f90d0899a45f5ed8af5b62c5d3e863fcd4ab191..5f80a1b2fb8c51905e67840945381dcbfa3cf466 100644 (file)
@@ -2974,8 +2974,7 @@ static void em28xx_card_setup(struct em28xx *dev)
 #endif
                /* Call first TVeeprom */
 
-               dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1;
-               tveeprom_hauppauge_analog(&dev->i2c_client[dev->def_i2c_bus], &tv, dev->eedata);
+               tveeprom_hauppauge_analog(&tv, dev->eedata);
 
                dev->tuner_type = tv.tuner_type;
 
index 4af2fb5c85d50d2947692fa499af083633f5b6f5..8b643d511a0b1d143eb092e7e6f459949d84aa85 100644 (file)
@@ -118,15 +118,10 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
        memset(&tvdata,0,sizeof(tvdata));
 
        eeprom = pvr2_eeprom_fetch(hdw);
-       if (!eeprom) return -EINVAL;
-
-       {
-               struct i2c_client fake_client;
-               /* Newer version expects a useless client interface */
-               fake_client.addr = hdw->eeprom_addr;
-               fake_client.adapter = &hdw->i2c_adap;
-               tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom);
-       }
+       if (!eeprom)
+               return -EINVAL;
+
+       tveeprom_hauppauge_analog(&tvdata, eeprom);
 
        trace_eeprom("eeprom assumed v4l tveeprom module");
        trace_eeprom("eeprom direct call results:");
index d605c41d0424f0021c02e926860d482b63bcb66e..ddf7b9dacb50fdb6cd6f4d55c258fad1a70d6847 100644 (file)
@@ -1534,7 +1534,11 @@ static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i,
        if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
                return 0;
 
-       BUG_ON((index+2) >= BCM2048_MAX_RDS_RT);
+       if ((index + 2) >= BCM2048_MAX_RDS_RT) {
+               dev_err(&bdev->client->dev,
+                       "Incorrect index = %d\n", index);
+               return 0;
+       }
 
        if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
                BCM2048_RDS_BLOCK_C) {
@@ -1557,7 +1561,11 @@ static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i,
        if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
                return;
 
-       BUG_ON((index+4) >= BCM2048_MAX_RDS_RT);
+       if ((index + 4) >= BCM2048_MAX_RDS_RT) {
+               dev_err(&bdev->client->dev,
+                       "Incorrect index = %d\n", index);
+               return;
+       }
 
        if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
            BCM2048_RDS_BLOCK_D)
index bb0e3b4a4558ab6f69da99891c77cadc634681a0..0bac58241a22072105b022a54dccc93b292b1dcc 100644 (file)
@@ -128,7 +128,8 @@ static unsigned int iss_video_mbus_to_pix(const struct iss_video *video,
        pix->width = mbus->width;
        pix->height = mbus->height;
 
-       /* Skip the last format in the loop so that it will be selected if no
+       /*
+        * Skip the last format in the loop so that it will be selected if no
         * match is found.
         */
        for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
@@ -138,7 +139,8 @@ static unsigned int iss_video_mbus_to_pix(const struct iss_video *video,
 
        min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
 
-       /* Clamp the requested bytes per line value. If the maximum bytes per
+       /*
+        * Clamp the requested bytes per line value. If the maximum bytes per
         * line value is zero, the module doesn't support user configurable line
         * sizes. Override the requested value with the minimum in that case.
         */
@@ -172,7 +174,8 @@ static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix,
        mbus->width = pix->width;
        mbus->height = pix->height;
 
-       /* Skip the last format in the loop so that it will be selected if no
+       /*
+        * Skip the last format in the loop so that it will be selected if no
         * match is found.
         */
        for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
@@ -298,7 +301,8 @@ iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh)
 
 static int iss_video_queue_setup(struct vb2_queue *vq,
                                 unsigned int *count, unsigned int *num_planes,
-                                unsigned int sizes[], struct device *alloc_devs[])
+                                unsigned int sizes[],
+                                struct device *alloc_devs[])
 {
        struct iss_video_fh *vfh = vb2_get_drv_priv(vq);
        struct iss_video *video = vfh->video;
@@ -360,7 +364,8 @@ static void iss_video_buf_queue(struct vb2_buffer *vb)
 
        spin_lock_irqsave(&video->qlock, flags);
 
-       /* Mark the buffer is faulty and give it back to the queue immediately
+       /*
+        * Mark the buffer is faulty and give it back to the queue immediately
         * if the video node has registered an error. vb2 will perform the same
         * check when preparing the buffer, but that is inherently racy, so we
         * need to handle the race condition with an authoritative check here.
@@ -443,7 +448,8 @@ struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
 
        buf->vb.vb2_buf.timestamp = ktime_get_ns();
 
-       /* Do frame number propagation only if this is the output video node.
+       /*
+        * Do frame number propagation only if this is the output video node.
         * Frame number either comes from the CSI receivers or it gets
         * incremented here if H3A is not active.
         * Note: There is no guarantee that the output buffer will finish
@@ -605,7 +611,8 @@ iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
 
        mutex_lock(&video->mutex);
 
-       /* Fill the bytesperline and sizeimage fields by converting to media bus
+       /*
+        * Fill the bytesperline and sizeimage fields by converting to media bus
         * format and back to pixel format.
         */
        iss_video_pix_to_mbus(&format->fmt.pix, &fmt);
@@ -678,8 +685,9 @@ iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
        if (subdev == NULL)
                return -EINVAL;
 
-       /* Try the get selection operation first and fallback to get format if not
-        * implemented.
+       /*
+        * Try the get selection operation first and fallback to get format if
+        * not implemented.
         */
        sdsel.pad = pad;
        ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
@@ -867,7 +875,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 
        mutex_lock(&video->stream_lock);
 
-       /* Start streaming on the pipeline. No link touching an entity in the
+       /*
+        * Start streaming on the pipeline. No link touching an entity in the
         * pipeline can be activated or deactivated once streaming is started.
         */
        pipe = entity->pipe
@@ -895,7 +904,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        while ((entity = media_graph_walk_next(&graph)))
                media_entity_enum_set(&pipe->ent_enum, entity);
 
-       /* Verify that the currently configured format matches the output of
+       /*
+        * Verify that the currently configured format matches the output of
         * the connected subdev.
         */
        ret = iss_video_check_format(video, vfh);
@@ -905,7 +915,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        video->bpl_padding = ret;
        video->bpl_value = vfh->format.fmt.pix.bytesperline;
 
-       /* Find the ISS video node connected at the far end of the pipeline and
+       /*
+        * Find the ISS video node connected at the far end of the pipeline and
         * update the pipeline.
         */
        far_end = iss_video_far_end(video);
@@ -930,7 +941,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        pipe->state |= state;
        spin_unlock_irqrestore(&pipe->lock, flags);
 
-       /* Set the maximum time per frame as the value requested by userspace.
+       /*
+        * Set the maximum time per frame as the value requested by userspace.
         * This is a soft limit that can be overridden if the hardware doesn't
         * support the request limit.
         */
@@ -946,7 +958,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto err_iss_video_check_format;
 
-       /* In sensor-to-memory mode, the stream can be started synchronously
+       /*
+        * In sensor-to-memory mode, the stream can be started synchronously
         * to the stream on command. In memory-to-memory mode, it will be
         * started when buffers are queued on both the input and output.
         */
index c56501ee0484a1a1e0b7c6720499195637756b3d..5324c82fc810abf3ca6082a11966f5249c53460d 100644 (file)
@@ -100,7 +100,7 @@ struct tveeprom {
  *                     contain 256 bytes filled with the contents of the
  *                     eeprom read from the Hauppauge device.
  */
-void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+void tveeprom_hauppauge_analog(struct tveeprom *tvee,
                               unsigned char *eeprom_data);
 
 /**
index 14b6f24b189ef31e59b7cd354dda260f8f98aa28..a0dfe27bc6c7c0d07bf6abca546105b7d94773fb 100644 (file)
@@ -223,7 +223,7 @@ static inline int cec_msg_status_is_ok(const struct cec_msg *msg)
 #define CEC_LOG_ADDR_BACKUP_2          13
 #define CEC_LOG_ADDR_SPECIFIC          14
 #define CEC_LOG_ADDR_UNREGISTERED      15 /* as initiator address */
-#define CEC_LOG_ADDR_BROADCAST         15 /* ad destination address */
+#define CEC_LOG_ADDR_BROADCAST         15 /* as destination address */
 
 /* The logical address types that the CEC device wants to claim */
 #define CEC_LOG_ADDR_TYPE_TV           0