summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/cec/core/cec-adap.c7
-rw-r--r--drivers/media/cec/platform/cec-gpio/cec-gpio.c5
-rw-r--r--drivers/media/cec/platform/cros-ec/cros-ec-cec.c22
-rw-r--r--drivers/media/cec/platform/meson/ao-cec-g12a.c6
-rw-r--r--drivers/media/cec/platform/meson/ao-cec.c6
-rw-r--r--drivers/media/cec/platform/s5p/s5p_cec.c5
-rw-r--r--drivers/media/cec/platform/seco/seco-cec.c6
-rw-r--r--drivers/media/cec/platform/sti/stih-cec.c6
-rw-r--r--drivers/media/cec/platform/stm32/stm32-cec.c6
-rw-r--r--drivers/media/cec/platform/tegra/tegra_cec.c6
-rw-r--r--drivers/media/common/btcx-risc.h29
-rw-r--r--drivers/media/common/saa7146/Kconfig2
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c40
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c373
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c355
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c287
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c959
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c5
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c2
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c6
-rw-r--r--drivers/media/dvb-frontends/zd1301_demod.c6
-rw-r--r--drivers/media/i2c/Kconfig68
-rw-r--r--drivers/media/i2c/Makefile8
-rw-r--r--drivers/media/i2c/ad9389b.c1215
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c21
-rw-r--r--drivers/media/i2c/adv7604.c5
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c157
-rw-r--r--drivers/media/i2c/ccs/ccs.h14
-rw-r--r--drivers/media/i2c/hi556.c150
-rw-r--r--drivers/media/i2c/hi846.c11
-rw-r--r--drivers/media/i2c/imx258.c33
-rw-r--r--drivers/media/i2c/imx290.c602
-rw-r--r--drivers/media/i2c/imx296.c11
-rw-r--r--drivers/media/i2c/imx334.c322
-rw-r--r--drivers/media/i2c/m5mols/Kconfig8
-rw-r--r--drivers/media/i2c/m5mols/Makefile4
-rw-r--r--drivers/media/i2c/m5mols/m5mols.h349
-rw-r--r--drivers/media/i2c/m5mols/m5mols_capture.c158
-rw-r--r--drivers/media/i2c/m5mols/m5mols_controls.c625
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c1051
-rw-r--r--drivers/media/i2c/m5mols/m5mols_reg.h359
-rw-r--r--drivers/media/i2c/max9286.c1
-rw-r--r--drivers/media/i2c/mt9m032.c891
-rw-r--r--drivers/media/i2c/mt9t001.c992
-rw-r--r--drivers/media/i2c/noon010pc30.c821
-rw-r--r--drivers/media/i2c/ov13b10.c75
-rw-r--r--drivers/media/i2c/ov2685.c85
-rw-r--r--drivers/media/i2c/ov5647.c56
-rw-r--r--drivers/media/i2c/ov5670.c116
-rw-r--r--drivers/media/i2c/ov5695.c5
-rw-r--r--drivers/media/i2c/ov7670.c11
-rw-r--r--drivers/media/i2c/ov8856.c40
-rw-r--r--drivers/media/i2c/s5k6aa.c1652
-rw-r--r--drivers/media/i2c/sr030pc30.c762
-rw-r--r--drivers/media/i2c/st-vgxy61.c23
-rw-r--r--drivers/media/i2c/tc358746.c4
-rw-r--r--drivers/media/i2c/vs6624.c854
-rw-r--r--drivers/media/i2c/vs6624_regs.h325
-rw-r--r--drivers/media/mc/mc-device.c3
-rw-r--r--drivers/media/pci/bt8xx/Kconfig2
-rw-r--r--drivers/media/pci/bt8xx/btcx-risc.c153
-rw-r--r--drivers/media/pci/bt8xx/btcx-risc.h9
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c15
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c436
-rw-r--r--drivers/media/pci/bt8xx/bttv-risc.c131
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h28
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c21
-rw-r--r--drivers/media/pci/cx18/Kconfig2
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c4
-rw-r--r--drivers/media/pci/cx18/cx18-driver.h24
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.c85
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.h3
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c391
-rw-r--r--drivers/media/pci/cx18/cx18-mailbox.c27
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c278
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c13
-rw-r--r--drivers/media/pci/dm1105/dm1105.c1
-rw-r--r--drivers/media/pci/intel/ipu3/cio2-bridge.c23
-rw-r--r--drivers/media/pci/intel/ipu3/cio2-bridge.h3
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2-main.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c32
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c412
-rw-r--r--drivers/media/pci/saa7134/saa7134.h13
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c23
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c24
-rw-r--r--drivers/media/pci/saa7146/mxb.c53
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c10
-rw-r--r--drivers/media/pci/ttpci/budget-av.c5
-rw-r--r--drivers/media/pci/tw68/tw68-video.c16
-rw-r--r--drivers/media/pci/zoran/zoran_device.h2
-rw-r--r--drivers/media/platform/allegro-dvt/allegro-core.c6
-rw-r--r--drivers/media/platform/amlogic/meson-ge2d/ge2d.c6
-rw-r--r--drivers/media/platform/amphion/vdec.c53
-rw-r--r--drivers/media/platform/amphion/vpu_codec.h3
-rw-r--r--drivers/media/platform/amphion/vpu_core.c6
-rw-r--r--drivers/media/platform/amphion/vpu_drv.c6
-rw-r--r--drivers/media/platform/amphion/vpu_malone.c45
-rw-r--r--drivers/media/platform/amphion/vpu_malone.h1
-rw-r--r--drivers/media/platform/aspeed/aspeed-video.c6
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c10
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c6
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c6
-rw-r--r--drivers/media/platform/chips-media/coda-common.c5
-rw-r--r--drivers/media/platform/intel/pxa_camera.c10
-rw-r--r--drivers/media/platform/m2m-deinterlace.c6
-rw-r--r--drivers/media/platform/marvell/mcam-core.c4
-rw-r--r--drivers/media/platform/marvell/mmp-driver.c16
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c140
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h28
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c43
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c38
-rw-r--r--drivers/media/platform/mediatek/mdp/mtk_mdp_core.c5
-rw-r--r--drivers/media/platform/mediatek/mdp3/Makefile2
-rw-r--r--drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c453
-rw-r--r--drivers/media/platform/mediatek/mdp3/mdp_sm_mt8183.h144
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h189
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h20
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c148
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c539
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h24
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c53
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h18
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c36
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h1
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c293
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h214
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-type.h53
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c193
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h29
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c31
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c10
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c8
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c12
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c14
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c23
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c95
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h12
-rw-r--r--drivers/media/platform/mediatek/vpu/mtk_vpu.c6
-rw-r--r--drivers/media/platform/microchip/microchip-csi2dc.c6
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c5
-rw-r--r--drivers/media/platform/microchip/microchip-sama5d2-isc.c6
-rw-r--r--drivers/media/platform/microchip/microchip-sama7g5-isc.c6
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/vde.c6
-rw-r--r--drivers/media/platform/nxp/Kconfig2
-rw-r--r--drivers/media/platform/nxp/Makefile1
-rw-r--r--drivers/media/platform/nxp/dw100/dw100.c10
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c19
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h5
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c344
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c6
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c6
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c33
-rw-r--r--drivers/media/platform/nxp/imx8-isi/Kconfig22
-rw-r--r--drivers/media/platform/nxp/imx8-isi/Makefile8
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c539
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h394
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c529
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c109
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c650
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c858
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c867
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h418
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c1512
-rw-r--r--drivers/media/platform/nxp/mx2_emmaprp.c6
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid-gen2.c54
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c44
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.h11
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-170.c4
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-480.c61
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-gen1.c4
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c1
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c26
-rw-r--r--drivers/media/platform/qcom/camss/camss.c8
-rw-r--r--drivers/media/platform/qcom/venus/core.c6
-rw-r--r--drivers/media/platform/qcom/venus/core.h10
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c4
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c4
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c23
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h18
-rw-r--r--drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c4
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c29
-rw-r--r--drivers/media/platform/qcom/venus/venc.c115
-rw-r--r--drivers/media/platform/renesas/rcar-fcp.c6
-rw-r--r--drivers/media/platform/renesas/rcar-isp.c11
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-core.c42
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-csi2.c21
-rw-r--r--drivers/media/platform/renesas/rcar_drif.c8
-rw-r--r--drivers/media/platform/renesas/rcar_fdp1.c21
-rw-r--r--drivers/media/platform/renesas/rcar_jpu.c6
-rw-r--r--drivers/media/platform/renesas/renesas-ceu.c10
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c6
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c6
-rw-r--r--drivers/media/platform/renesas/sh_vou.c5
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drm.c26
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drv.c17
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.c11
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.h2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.h2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_regs.h2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c7
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c6
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c52
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c6
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c14
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-core.c5
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-capture.c18
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-core.c5
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-errno.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c6
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is.c6
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c10
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-lite.c14
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.c18
-rw-r--r--drivers/media/platform/samsung/exynos4-is/mipi-csis.c6
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-capture.c5
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-core.c11
-rw-r--r--drivers/media/platform/samsung/s5p-g2d/g2d.c5
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c6
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c5
-rw-r--r--drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c8
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c6
-rw-r--r--drivers/media/platform/st/sti/delta/delta-v4l2.c6
-rw-r--r--drivers/media/platform/st/sti/hva/hva-v4l2.c6
-rw-r--r--drivers/media/platform/st/stm32/dma2d/dma2d.c11
-rw-r--r--drivers/media/platform/st/stm32/dma2d/dma2d.h2
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c7
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c6
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c6
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c6
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c6
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/sun8i-di.c6
-rw-r--r--drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c6
-rw-r--r--drivers/media/platform/ti/am437x/am437x-vpfe.c41
-rw-r--r--drivers/media/platform/ti/cal/cal-video.c37
-rw-r--r--drivers/media/platform/ti/cal/cal.c6
-rw-r--r--drivers/media/platform/ti/davinci/vpif.c6
-rw-r--r--drivers/media/platform/ti/davinci/vpif_capture.c5
-rw-r--r--drivers/media/platform/ti/davinci/vpif_display.c6
-rw-r--r--drivers/media/platform/ti/omap/omap_vout.c5
-rw-r--r--drivers/media/platform/ti/omap3isp/isp.c6
-rw-r--r--drivers/media/platform/ti/omap3isp/ispccdc.c5
-rw-r--r--drivers/media/platform/ti/omap3isp/ispvideo.c20
-rw-r--r--drivers/media/platform/ti/vpe/vpe.c6
-rw-r--r--drivers/media/platform/verisilicon/hantro_drv.c56
-rw-r--r--drivers/media/platform/verisilicon/hantro_postproc.c2
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.c100
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.h3
-rw-r--r--drivers/media/platform/verisilicon/imx8m_vpu_hw.c2
-rw-r--r--drivers/media/platform/via/via-camera.c13
-rw-r--r--drivers/media/platform/video-mux.c6
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c6
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c5
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c6
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c6
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.c8
-rw-r--r--drivers/media/radio/radio-si476x.c6
-rw-r--r--drivers/media/radio/radio-timb.c5
-rw-r--r--drivers/media/radio/radio-wl1273.c6
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c6
-rw-r--r--drivers/media/rc/gpio-ir-recv.c8
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c5
-rw-r--r--drivers/media/rc/ir-hix5hd2.c5
-rw-r--r--drivers/media/rc/keymaps/Makefile2
-rw-r--r--drivers/media/rc/keymaps/rc-beelink-mxiii.c57
-rw-r--r--drivers/media/rc/keymaps/rc-dreambox.c151
-rw-r--r--drivers/media/rc/meson-ir-tx.c6
-rw-r--r--drivers/media/rc/meson-ir.c6
-rw-r--r--drivers/media/rc/mtk-cir.c6
-rw-r--r--drivers/media/rc/st_rc.c5
-rw-r--r--drivers/media/rc/sunxi-cir.c6
-rw-r--r--drivers/media/test-drivers/vicodec/vicodec-core.c6
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_bridge.c6
-rw-r--r--drivers/media/test-drivers/vim2m.c6
-rw-r--r--drivers/media/test-drivers/vimc/vimc-common.c8
-rw-r--r--drivers/media/test-drivers/vimc/vimc-core.c6
-rw-r--r--drivers/media/test-drivers/visl/visl-core.c6
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c54
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.h19
-rw-r--r--drivers/media/test-drivers/vivid/vivid-kthread-cap.c131
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c272
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.h3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-out.c74
-rw-r--r--drivers/media/tuners/it913x.c6
-rw-r--r--drivers/media/tuners/mxl5005s.c12
-rw-r--r--drivers/media/usb/au0828/au0828-core.c11
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c4
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c14
-rw-r--r--drivers/media/usb/dvb-usb/pctv452e.c2
-rw-r--r--drivers/media/usb/pvrusb2/Kconfig2
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c13
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c85
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c86
-rw-r--r--drivers/media/v4l2-core/v4l2-mc.c15
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c200
307 files changed, 11688 insertions, 16642 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 4f5ab3cae8a7..769ea6b2e1d0 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -1052,6 +1052,7 @@ void cec_received_msg_ts(struct cec_adapter *adap,
u8 cmd = msg->msg[1];
bool is_reply = false;
bool valid_la = true;
+ bool monitor_valid_la = true;
u8 min_len = 0;
if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE))
@@ -1093,8 +1094,10 @@ void cec_received_msg_ts(struct cec_adapter *adap,
adap->last_initiator = 0xff;
/* Check if this message was for us (directed or broadcast). */
- if (!cec_msg_is_broadcast(msg))
+ if (!cec_msg_is_broadcast(msg)) {
valid_la = cec_has_log_addr(adap, msg_dest);
+ monitor_valid_la = valid_la;
+ }
/*
* Check if the length is not too short or if the message is a
@@ -1227,7 +1230,7 @@ void cec_received_msg_ts(struct cec_adapter *adap,
mutex_unlock(&adap->lock);
/* Pass the message on to any monitoring filehandles */
- cec_queue_msg_monitor(adap, msg, valid_la);
+ cec_queue_msg_monitor(adap, msg, monitor_valid_la);
/* We're done if it is not for us or a poll message */
if (!valid_la || msg->len <= 1)
diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c
index c8c4efc83f5f..ff34490fd869 100644
--- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c
@@ -269,13 +269,12 @@ del_adap:
return ret;
}
-static int cec_gpio_remove(struct platform_device *pdev)
+static void cec_gpio_remove(struct platform_device *pdev)
{
struct cec_gpio *cec = platform_get_drvdata(pdev);
cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
- return 0;
}
static const struct of_device_id cec_gpio_match[] = {
@@ -288,7 +287,7 @@ MODULE_DEVICE_TABLE(of, cec_gpio_match);
static struct platform_driver cec_gpio_pdrv = {
.probe = cec_gpio_probe,
- .remove = cec_gpio_remove,
+ .remove_new = cec_gpio_remove,
.driver = {
.name = "cec-gpio",
.of_match_table = cec_gpio_match,
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 6ebedc71d67d..c17faf002877 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -225,6 +225,12 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
{ "Google", "Kinox", "0000:00:02.0", "Port B" },
/* Google Kuldax */
{ "Google", "Kuldax", "0000:00:02.0", "Port B" },
+ /* Google Aurash */
+ { "Google", "Aurash", "0000:00:02.0", "Port B" },
+ /* Google Gladios */
+ { "Google", "Gladios", "0000:00:02.0", "Port B" },
+ /* Google Lisbon */
+ { "Google", "Lisbon", "0000:00:02.0", "Port B" },
};
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
@@ -326,31 +332,31 @@ out_probe_adapter:
return ret;
}
-static int cros_ec_cec_remove(struct platform_device *pdev)
+static void cros_ec_cec_remove(struct platform_device *pdev)
{
struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
int ret;
+ /*
+ * blocking_notifier_chain_unregister() only fails if the notifier isn't
+ * in the list. We know it was added to it by .probe(), so there should
+ * be no need for error checking. Be cautious and still check.
+ */
ret = blocking_notifier_chain_unregister(
&cros_ec_cec->cros_ec->event_notifier,
&cros_ec_cec->notifier);
-
- if (ret) {
+ if (ret)
dev_err(dev, "failed to unregister notifier\n");
- return ret;
- }
cec_notifier_cec_adap_unregister(cros_ec_cec->notify,
cros_ec_cec->adap);
cec_unregister_adapter(cros_ec_cec->adap);
-
- return 0;
}
static struct platform_driver cros_ec_cec_driver = {
.probe = cros_ec_cec_probe,
- .remove = cros_ec_cec_remove,
+ .remove_new = cros_ec_cec_remove,
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_cec_pm_ops,
diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c
index 68fe6d6a8178..51294b9b6cd5 100644
--- a/drivers/media/cec/platform/meson/ao-cec-g12a.c
+++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c
@@ -744,7 +744,7 @@ out_probe_adapter:
return ret;
}
-static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
+static void meson_ao_cec_g12a_remove(struct platform_device *pdev)
{
struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
@@ -753,8 +753,6 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
cec_unregister_adapter(ao_cec->adap);
-
- return 0;
}
static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = {
@@ -780,7 +778,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
static struct platform_driver meson_ao_cec_g12a_driver = {
.probe = meson_ao_cec_g12a_probe,
- .remove = meson_ao_cec_g12a_remove,
+ .remove_new = meson_ao_cec_g12a_remove,
.driver = {
.name = "meson-ao-cec-g12a",
.of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c
index 6b440f0635d9..f6f51a34f7bd 100644
--- a/drivers/media/cec/platform/meson/ao-cec.c
+++ b/drivers/media/cec/platform/meson/ao-cec.c
@@ -696,7 +696,7 @@ out_probe_adapter:
return ret;
}
-static int meson_ao_cec_remove(struct platform_device *pdev)
+static void meson_ao_cec_remove(struct platform_device *pdev)
{
struct meson_ao_cec_device *ao_cec = platform_get_drvdata(pdev);
@@ -704,8 +704,6 @@ static int meson_ao_cec_remove(struct platform_device *pdev)
cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
cec_unregister_adapter(ao_cec->adap);
-
- return 0;
}
static const struct of_device_id meson_ao_cec_of_match[] = {
@@ -716,7 +714,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match);
static struct platform_driver meson_ao_cec_driver = {
.probe = meson_ao_cec_probe,
- .remove = meson_ao_cec_remove,
+ .remove_new = meson_ao_cec_remove,
.driver = {
.name = "meson-ao-cec",
.of_match_table = of_match_ptr(meson_ao_cec_of_match),
diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c
index 0a30e7acdc10..51ab4a80aafe 100644
--- a/drivers/media/cec/platform/s5p/s5p_cec.c
+++ b/drivers/media/cec/platform/s5p/s5p_cec.c
@@ -249,14 +249,13 @@ err_delete_adapter:
return ret;
}
-static int s5p_cec_remove(struct platform_device *pdev)
+static void s5p_cec_remove(struct platform_device *pdev)
{
struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static int __maybe_unused s5p_cec_runtime_suspend(struct device *dev)
@@ -295,7 +294,7 @@ MODULE_DEVICE_TABLE(of, s5p_cec_match);
static struct platform_driver s5p_cec_pdrv = {
.probe = s5p_cec_probe,
- .remove = s5p_cec_remove,
+ .remove_new = s5p_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = s5p_cec_match,
diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c
index 580905e3d066..5d4c5a2cae09 100644
--- a/drivers/media/cec/platform/seco/seco-cec.c
+++ b/drivers/media/cec/platform/seco/seco-cec.c
@@ -668,7 +668,7 @@ err:
return ret;
}
-static int secocec_remove(struct platform_device *pdev)
+static void secocec_remove(struct platform_device *pdev)
{
struct secocec_data *secocec = platform_get_drvdata(pdev);
u16 val;
@@ -686,8 +686,6 @@ static int secocec_remove(struct platform_device *pdev)
release_region(BRA_SMB_BASE_ADDR, 7);
dev_dbg(&pdev->dev, "CEC device removed\n");
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -780,7 +778,7 @@ static struct platform_driver secocec_driver = {
.pm = SECOCEC_PM_OPS,
},
.probe = secocec_probe,
- .remove = secocec_remove,
+ .remove_new = secocec_remove,
};
module_platform_driver(secocec_driver);
diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c
index 4edbdd09535d..a20fc5c0c88d 100644
--- a/drivers/media/cec/platform/sti/stih-cec.c
+++ b/drivers/media/cec/platform/sti/stih-cec.c
@@ -364,14 +364,12 @@ err_delete_adapter:
return ret;
}
-static int stih_cec_remove(struct platform_device *pdev)
+static void stih_cec_remove(struct platform_device *pdev)
{
struct stih_cec *cec = platform_get_drvdata(pdev);
cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
-
- return 0;
}
static const struct of_device_id stih_cec_match[] = {
@@ -384,7 +382,7 @@ MODULE_DEVICE_TABLE(of, stih_cec_match);
static struct platform_driver stih_cec_pdrv = {
.probe = stih_cec_probe,
- .remove = stih_cec_remove,
+ .remove_new = stih_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = stih_cec_match,
diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c
index 7b2db46a5722..ada3d153362a 100644
--- a/drivers/media/cec/platform/stm32/stm32-cec.c
+++ b/drivers/media/cec/platform/stm32/stm32-cec.c
@@ -344,7 +344,7 @@ err_unprepare_cec_clk:
return ret;
}
-static int stm32_cec_remove(struct platform_device *pdev)
+static void stm32_cec_remove(struct platform_device *pdev)
{
struct stm32_cec *cec = platform_get_drvdata(pdev);
@@ -352,8 +352,6 @@ static int stm32_cec_remove(struct platform_device *pdev)
clk_unprepare(cec->clk_hdmi_cec);
cec_unregister_adapter(cec->adap);
-
- return 0;
}
static const struct of_device_id stm32_cec_of_match[] = {
@@ -364,7 +362,7 @@ MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
static struct platform_driver stm32_cec_driver = {
.probe = stm32_cec_probe,
- .remove = stm32_cec_remove,
+ .remove_new = stm32_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = stm32_cec_of_match,
diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c
index 5e907395ca2e..04dc06e3c42a 100644
--- a/drivers/media/cec/platform/tegra/tegra_cec.c
+++ b/drivers/media/cec/platform/tegra/tegra_cec.c
@@ -421,7 +421,7 @@ err_clk:
return ret;
}
-static int tegra_cec_remove(struct platform_device *pdev)
+static void tegra_cec_remove(struct platform_device *pdev)
{
struct tegra_cec *cec = platform_get_drvdata(pdev);
@@ -429,8 +429,6 @@ static int tegra_cec_remove(struct platform_device *pdev)
cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -467,7 +465,7 @@ static struct platform_driver tegra_cec_driver = {
.of_match_table = of_match_ptr(tegra_cec_of_match),
},
.probe = tegra_cec_probe,
- .remove = tegra_cec_remove,
+ .remove_new = tegra_cec_remove,
#ifdef CONFIG_PM
.suspend = tegra_cec_suspend,
diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h
deleted file mode 100644
index 76dc16f402b9..000000000000
--- a/drivers/media/common/btcx-risc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- */
-struct btcx_riscmem {
- unsigned int size;
- __le32 *cpu;
- __le32 *jmp;
- dma_addr_t dma;
-};
-
-struct btcx_skiplist {
- int start;
- int end;
-};
-
-int btcx_riscmem_alloc(struct pci_dev *pci,
- struct btcx_riscmem *risc,
- unsigned int size);
-void btcx_riscmem_free(struct pci_dev *pci,
- struct btcx_riscmem *risc);
-
-int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
- struct v4l2_clip *clips, unsigned int n);
-int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
- unsigned int n, int mask);
-void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, int *maxy,
- struct btcx_skiplist *skips, unsigned int *nskips,
- const struct v4l2_clip *clips, unsigned int nclips);
diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig
index a0aa155e5d85..dfec86e50dff 100644
--- a/drivers/media/common/saa7146/Kconfig
+++ b/drivers/media/common/saa7146/Kconfig
@@ -6,5 +6,5 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
depends on VIDEO_DEV
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
select VIDEO_SAA7146
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index e50fa0ff7c5d..bcb957883044 100644
--- a/drivers/media/common/saa7146/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -37,7 +37,8 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
{
u32 value = 0;
- BUG_ON(port > 3);
+ if (WARN_ON(port > 3))
+ return;
value = saa7146_read(dev, GPIO_CTRL);
value &= ~(0xff << (8*port));
@@ -148,7 +149,8 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
pg = vmalloc_to_page(virt);
if (NULL == pg)
goto err;
- BUG_ON(PageHighMem(pg));
+ if (WARN_ON(PageHighMem(pg)))
+ return NULL;
sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
}
return sglist;
@@ -233,46 +235,32 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
}
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
- struct scatterlist *list, int sglen )
+ struct scatterlist *list, int sglen)
{
+ struct sg_dma_page_iter dma_iter;
__le32 *ptr, fill;
int nr_pages = 0;
- int i,p;
+ int i;
- BUG_ON(0 == sglen);
- BUG_ON(list->offset > PAGE_SIZE);
+ if (WARN_ON(!sglen) ||
+ WARN_ON(list->offset > PAGE_SIZE))
+ return -EIO;
/* if we have a user buffer, the first page may not be
aligned to a page boundary. */
pt->offset = list->offset;
ptr = pt->cpu;
- for (i = 0; i < sglen; i++, list++) {
-/*
- pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
- i, sg_dma_address(list), sg_dma_len(list),
- list->offset);
-*/
- for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr++) {
- *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
- nr_pages++;
- }
+ for_each_sg_dma_page(list, &dma_iter, sglen, 0) {
+ *ptr++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter));
+ nr_pages++;
}
/* safety; fill the page table up with the last valid page */
fill = *(ptr-1);
- for(i=nr_pages;i<1024;i++) {
+ for (i = nr_pages; i < 1024; i++)
*ptr++ = fill;
- }
-
-/*
- ptr = pt->cpu;
- pr_debug("offset: %d\n", pt->offset);
- for(i=0;i<5;i++) {
- pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
- }
-*/
return 0;
}
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index e9a15de6126e..79214459387a 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -7,12 +7,11 @@
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
-int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
+int saa7146_res_get(struct saa7146_dev *dev, unsigned int bit)
{
- struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- if (fh->resources & bit) {
+ if (vv->resources & bit) {
DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
bit, vv->resources);
/* have it already allocated */
@@ -27,42 +26,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
return 0;
}
/* it's free, grab it */
- fh->resources |= bit;
vv->resources |= bit;
DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
return 1;
}
-void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
+void saa7146_res_free(struct saa7146_dev *dev, unsigned int bits)
{
- struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- BUG_ON((fh->resources & bits) != bits);
+ WARN_ON((vv->resources & bits) != bits);
- fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
}
/********************************************************************************/
-/* common dma functions */
-
-void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
- struct saa7146_buf *buf)
-{
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- DEB_EE("dev:%p, buf:%p\n", dev, buf);
-
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-
-/********************************************************************************/
/* common buffer functions */
int saa7146_buffer_queue(struct saa7146_dev *dev,
@@ -72,15 +52,15 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
assert_spin_locked(&dev->slock);
DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
- BUG_ON(!q);
+ if (WARN_ON(!q))
+ return -EIO;
if (NULL == q->curr) {
q->curr = buf;
DEB_D("immediately activating buffer %p\n", buf);
buf->activate(dev,buf,NULL);
} else {
- list_add_tail(&buf->vb.queue,&q->queue);
- buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->list, &q->queue);
DEB_D("adding buffer %p to queue. (active buffer present)\n",
buf);
}
@@ -91,21 +71,31 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
struct saa7146_dmaqueue *q,
int state)
{
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_buf *buf = q->curr;
+
assert_spin_locked(&dev->slock);
DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
DEB_EE("q->curr:%p\n", q->curr);
/* finish current buffer */
- if (NULL == q->curr) {
+ if (!buf) {
DEB_D("aiii. no current buffer\n");
return;
}
- q->curr->vb.state = state;
- q->curr->vb.ts = ktime_get_ns();
- wake_up(&q->curr->vb.done);
-
q->curr = NULL;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ if (vv->video_fmt.field == V4L2_FIELD_ALTERNATE)
+ buf->vb.field = vv->last_field;
+ else if (vv->video_fmt.field == V4L2_FIELD_ANY)
+ buf->vb.field = (vv->video_fmt.height > vv->standard->v_max_out / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ else
+ buf->vb.field = vv->video_fmt.field;
+ buf->vb.sequence = vv->seqnr++;
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
}
void saa7146_buffer_next(struct saa7146_dev *dev,
@@ -113,17 +103,18 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
{
struct saa7146_buf *buf,*next = NULL;
- BUG_ON(!q);
+ if (WARN_ON(!q))
+ return;
DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
assert_spin_locked(&dev->slock);
if (!list_empty(&q->queue)) {
/* activate next one from queue */
- buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
- list_del(&buf->vb.queue);
+ buf = list_entry(q->queue.next, struct saa7146_buf, list);
+ list_del(&buf->list);
if (!list_empty(&q->queue))
- next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
+ next = list_entry(q->queue.next, struct saa7146_buf, list);
q->curr = buf;
DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
buf, q->queue.prev, q->queue.next);
@@ -171,7 +162,7 @@ void saa7146_buffer_timeout(struct timer_list *t)
spin_lock_irqsave(&dev->slock,flags);
if (q->curr) {
DEB_D("timeout on %p\n", q->curr);
- saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
+ saa7146_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
}
/* we don't restart the transfer here like other drivers do. when
@@ -180,256 +171,39 @@ void saa7146_buffer_timeout(struct timer_list *t)
we mess up our capture logic. if a timeout occurs on another buffer,
then something is seriously broken before, so no need to buffer the
next capture IMHO... */
-/*
- saa7146_buffer_next(dev,q);
-*/
+
+ saa7146_buffer_next(dev, q, 0);
+
spin_unlock_irqrestore(&dev->slock,flags);
}
/********************************************************************************/
/* file operations */
-static int fops_open(struct file *file)
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
struct video_device *vdev = video_devdata(file);
struct saa7146_dev *dev = video_drvdata(file);
- struct saa7146_fh *fh = NULL;
- int result = 0;
-
- DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
-
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
-
- DEB_D("using: %p\n", dev);
-
- /* check if an extension is registered */
- if( NULL == dev->ext ) {
- DEB_S("no extension registered for this device\n");
- result = -ENODEV;
- goto out;
- }
-
- /* allocate per open data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- DEB_S("cannot allocate memory for per open data\n");
- result = -ENOMEM;
- goto out;
- }
-
- v4l2_fh_init(&fh->fh, vdev);
-
- file->private_data = &fh->fh;
- fh->dev = dev;
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- DEB_S("initializing vbi...\n");
- if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- result = saa7146_vbi_uops.open(dev,file);
- if (dev->ext_vv_data->vbi_fops.open)
- dev->ext_vv_data->vbi_fops.open(file);
- } else {
- DEB_S("initializing video...\n");
- result = saa7146_video_uops.open(dev,file);
- }
-
- if (0 != result) {
- goto out;
- }
-
- if( 0 == try_module_get(dev->ext->module)) {
- result = -EINVAL;
- goto out;
- }
-
- result = 0;
- v4l2_fh_add(&fh->fh);
-out:
- if (fh && result != 0) {
- kfree(fh);
- file->private_data = NULL;
- }
- mutex_unlock(vdev->lock);
- return result;
-}
-
-static int fops_release(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
-
- DEB_EE("file:%p\n", file);
-
- mutex_lock(vdev->lock);
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- saa7146_vbi_uops.release(dev,file);
- if (dev->ext_vv_data->vbi_fops.release)
- dev->ext_vv_data->vbi_fops.release(file);
- } else {
- saa7146_video_uops.release(dev,file);
- }
-
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- module_put(dev->ext->module);
- file->private_data = NULL;
- kfree(fh);
-
- mutex_unlock(vdev->lock);
-
- return 0;
-}
-
-static int fops_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct videobuf_queue *q;
- int res;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_VIDEO: {
- DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
- file, vma);
- q = &fh->video_q;
- break;
- }
- case VFL_TYPE_VBI: {
- DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
- file, vma);
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
- return -ENODEV;
- q = &fh->vbi_q;
- break;
- }
- default:
- BUG();
- }
+ int ret;
+ if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_fops.write)
+ return -EINVAL;
if (mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
- res = videobuf_mmap_mapper(q, vma);
+ ret = dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
mutex_unlock(vdev->lock);
- return res;
-}
-
-static __poll_t __fops_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct videobuf_buffer *buf = NULL;
- struct videobuf_queue *q;
- __poll_t res = v4l2_ctrl_poll(file, wait);
-
- DEB_EE("file:%p, poll:%p\n", file, wait);
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
- return res | EPOLLOUT | EPOLLWRNORM;
- if( 0 == fh->vbi_q.streaming )
- return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
- q = &fh->vbi_q;
- } else {
- DEB_D("using video queue\n");
- q = &fh->video_q;
- }
-
- if (!list_empty(&q->stream))
- buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-
- if (!buf) {
- DEB_D("buf == NULL!\n");
- return res | EPOLLERR;
- }
-
- poll_wait(file, &buf->done, wait);
- if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
- DEB_D("poll succeeded!\n");
- return res | EPOLLIN | EPOLLRDNORM;
- }
-
- DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
- return res;
-}
-
-static __poll_t fops_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *vdev = video_devdata(file);
- __poll_t res;
-
- mutex_lock(vdev->lock);
- res = __fops_poll(file, wait);
- mutex_unlock(vdev->lock);
- return res;
-}
-
-static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- int ret;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_VIDEO:
-/*
- DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
- file, data, (unsigned long)count);
-*/
- return saa7146_video_uops.read(file,data,count,ppos);
- case VFL_TYPE_VBI:
-/*
- DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
- file, data, (unsigned long)count);
-*/
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- ret = saa7146_vbi_uops.read(file, data, count, ppos);
- mutex_unlock(vdev->lock);
- return ret;
- }
- return -EINVAL;
- default:
- BUG();
- }
-}
-
-static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- int ret;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_VIDEO:
- return -EINVAL;
- case VFL_TYPE_VBI:
- if (fh->dev->ext_vv_data->vbi_fops.write) {
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
- mutex_unlock(vdev->lock);
- return ret;
- }
- return -EINVAL;
- default:
- BUG();
- }
+ return ret;
}
static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
- .open = fops_open,
- .release = fops_release,
- .read = fops_read,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
.write = fops_write,
- .poll = fops_poll,
- .mmap = fops_mmap,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -516,33 +290,15 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
configuration data) */
dev->ext_vv_data = ext_vv;
- vv->d_clipping.cpu_addr =
- dma_alloc_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM,
- &vv->d_clipping.dma_handle, GFP_KERNEL);
- if( NULL == vv->d_clipping.cpu_addr ) {
- ERR("out of memory. aborting.\n");
- kfree(vv);
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- return -ENOMEM;
- }
-
saa7146_video_uops.init(dev,vv);
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv);
- vv->ov_fb.fmt.width = vv->standard->h_max_out;
- vv->ov_fb.fmt.height = vv->standard->v_max_out;
- vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
- vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width;
- vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height;
- vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;
-
fmt = &vv->video_fmt;
fmt->width = 384;
fmt->height = 288;
fmt->pixelformat = V4L2_PIX_FMT_BGR24;
- fmt->field = V4L2_FIELD_ANY;
+ fmt->field = V4L2_FIELD_INTERLACED;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->bytesperline = 3 * fmt->width;
fmt->sizeimage = fmt->bytesperline * fmt->height;
@@ -561,8 +317,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
timer_setup(&vv->vbi_read_timeout, NULL, 0);
- vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
dev->vv_data = vv;
dev->vv_callback = &vv_callback;
@@ -577,8 +331,6 @@ int saa7146_vv_release(struct saa7146_dev* dev)
DEB_EE("dev:%p\n", dev);
v4l2_device_unregister(&dev->v4l2_dev);
- dma_free_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM,
- vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
kfree(vv);
dev->vv_data = NULL;
@@ -591,16 +343,20 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
char *name, int type)
{
+ struct vb2_queue *q;
int err;
int i;
DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
vfd->fops = &video_fops;
- if (type == VFL_TYPE_VIDEO)
+ if (type == VFL_TYPE_VIDEO) {
vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
- else
+ q = &dev->vv_data->video_dmaq.q;
+ } else {
vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
+ q = &dev->vv_data->vbi_dmaq.q;
+ }
vfd->release = video_device_release_empty;
vfd->lock = &dev->v4l2_lock;
vfd->v4l2_dev = &dev->v4l2_dev;
@@ -608,15 +364,36 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
strscpy(vfd->name, name, sizeof(vfd->name));
- vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
vfd->device_caps |= dev->ext_vv_data->capabilities;
- if (type == VFL_TYPE_VIDEO)
+ if (type == VFL_TYPE_VIDEO) {
vfd->device_caps &=
~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
- else
- vfd->device_caps &=
- ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
+ } else if (vfd->device_caps & V4L2_CAP_SLICED_VBI_OUTPUT) {
+ vfd->vfl_dir = VFL_DIR_TX;
+ vfd->device_caps &= ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_AUDIO | V4L2_CAP_TUNER);
+ } else {
+ vfd->device_caps &= ~V4L2_CAP_VIDEO_CAPTURE;
+ }
+
+ q->type = type == VFL_TYPE_VIDEO ? V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
+ q->ops = type == VFL_TYPE_VIDEO ? &video_qops : &vbi_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->drv_priv = dev;
+ q->gfp_flags = __GFP_DMA32;
+ q->buf_struct_size = sizeof(struct saa7146_buf);
+ q->lock = &dev->v4l2_lock;
+ q->min_buffers_needed = 2;
+ q->dev = &dev->pci->dev;
+ err = vb2_queue_init(q);
+ if (err)
+ return err;
+ vfd->queue = q;
+
video_set_drvdata(vfd, dev);
err = video_register_device(vfd, type, -1);
diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index 6c9946a402ee..7569d8cdd4d8 100644
--- a/drivers/media/common/saa7146/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -306,221 +306,6 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field
}
/* simple bubble-sort algorithm with duplicate elimination */
-static int sort_and_eliminate(u32* values, int* count)
-{
- int low = 0, high = 0, top = 0;
- int cur = 0, next = 0;
-
- /* sanity checks */
- if( (0 > *count) || (NULL == values) ) {
- return -EINVAL;
- }
-
- /* bubble sort the first @count items of the array @values */
- for( top = *count; top > 0; top--) {
- for( low = 0, high = 1; high < top; low++, high++) {
- if( values[low] > values[high] )
- swap(values[low], values[high]);
- }
- }
-
- /* remove duplicate items */
- for( cur = 0, next = 1; next < *count; next++) {
- if( values[cur] != values[next])
- values[++cur] = values[next];
- }
-
- *count = cur + 1;
-
- return 0;
-}
-
-static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh,
- struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
-{
- struct saa7146_vv *vv = dev->vv_data;
- __le32 *clipping = vv->d_clipping.cpu_addr;
-
- int width = vv->ov.win.w.width;
- int height = vv->ov.win.w.height;
- int clipcount = vv->ov.nclips;
-
- u32 line_list[32];
- u32 pixel_list[32];
- int numdwords = 0;
-
- int i = 0, j = 0;
- int cnt_line = 0, cnt_pixel = 0;
-
- int x[32], y[32], w[32], h[32];
-
- /* clear out memory */
- memset(&line_list[0], 0x00, sizeof(u32)*32);
- memset(&pixel_list[0], 0x00, sizeof(u32)*32);
- memset(clipping, 0x00, SAA7146_CLIPPING_MEM);
-
- /* fill the line and pixel-lists */
- for(i = 0; i < clipcount; i++) {
- int l = 0, r = 0, t = 0, b = 0;
-
- x[i] = vv->ov.clips[i].c.left;
- y[i] = vv->ov.clips[i].c.top;
- w[i] = vv->ov.clips[i].c.width;
- h[i] = vv->ov.clips[i].c.height;
-
- if( w[i] < 0) {
- x[i] += w[i]; w[i] = -w[i];
- }
- if( h[i] < 0) {
- y[i] += h[i]; h[i] = -h[i];
- }
- if( x[i] < 0) {
- w[i] += x[i]; x[i] = 0;
- }
- if( y[i] < 0) {
- h[i] += y[i]; y[i] = 0;
- }
- if( 0 != vv->vflip ) {
- y[i] = height - y[i] - h[i];
- }
-
- l = x[i];
- r = x[i]+w[i];
- t = y[i];
- b = y[i]+h[i];
-
- /* insert left/right coordinates */
- pixel_list[ 2*i ] = min_t(int, l, width);
- pixel_list[(2*i)+1] = min_t(int, r, width);
- /* insert top/bottom coordinates */
- line_list[ 2*i ] = min_t(int, t, height);
- line_list[(2*i)+1] = min_t(int, b, height);
- }
-
- /* sort and eliminate lists */
- cnt_line = cnt_pixel = 2*clipcount;
- sort_and_eliminate( &pixel_list[0], &cnt_pixel );
- sort_and_eliminate( &line_list[0], &cnt_line );
-
- /* calculate the number of used u32s */
- numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2;
- numdwords = max_t(int, 4, numdwords);
- numdwords = min_t(int, 64, numdwords);
-
- /* fill up cliptable */
- for(i = 0; i < cnt_pixel; i++) {
- clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
- }
- for(i = 0; i < cnt_line; i++) {
- clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
- }
-
- /* fill up cliptable with the display infos */
- for(j = 0; j < clipcount; j++) {
-
- for(i = 0; i < cnt_pixel; i++) {
-
- if( x[j] < 0)
- x[j] = 0;
-
- if( pixel_list[i] < (x[j] + w[j])) {
-
- if ( pixel_list[i] >= x[j] ) {
- clipping[2*i] |= cpu_to_le32(1 << j);
- }
- }
- }
- for(i = 0; i < cnt_line; i++) {
-
- if( y[j] < 0)
- y[j] = 0;
-
- if( line_list[i] < (y[j] + h[j]) ) {
-
- if( line_list[i] >= y[j] ) {
- clipping[(2*i)+1] |= cpu_to_le32(1 << j);
- }
- }
- }
- }
-
- /* adjust arbitration control register */
- *arbtr_ctrl &= 0xffff00ff;
- *arbtr_ctrl |= 0x00001c00;
-
- vdma2->base_even = vv->d_clipping.dma_handle;
- vdma2->base_odd = vv->d_clipping.dma_handle;
- vdma2->prot_addr = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
- vdma2->base_page = 0x04;
- vdma2->pitch = 0x00;
- vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) );
-
- /* set clipping-mode. this depends on the field(s) used */
- *clip_format &= 0xfffffff7;
- if (V4L2_FIELD_HAS_BOTH(field)) {
- *clip_format |= 0x00000008;
- } else {
- *clip_format |= 0x00000000;
- }
-}
-
-/* disable clipping */
-static void saa7146_disable_clipping(struct saa7146_dev *dev)
-{
- u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
-
- /* mask out relevant bits (=lower word)*/
- clip_format &= MASK_W1;
-
- /* upload clipping-registers*/
- saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
- saa7146_write(dev, MC2, (MASK_05 | MASK_21));
-
- /* disable video dma2 */
- saa7146_write(dev, MC1, MASK_21);
-}
-
-static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- enum v4l2_field field = vv->ov.win.field;
- struct saa7146_video_dma vdma2;
- u32 clip_format;
- u32 arbtr_ctrl;
-
- /* check clipcount, disable clipping if clipcount == 0*/
- if (vv->ov.nclips == 0) {
- saa7146_disable_clipping(dev);
- return;
- }
-
- clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
- arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
-
- calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
-
- /* set clipping format */
- clip_format &= 0xffff0008;
- clip_format |= (SAA7146_CLIPPING_RECT << 4);
-
- /* prepare video dma2 */
- saa7146_write(dev, BASE_EVEN2, vdma2.base_even);
- saa7146_write(dev, BASE_ODD2, vdma2.base_odd);
- saa7146_write(dev, PROT_ADDR2, vdma2.prot_addr);
- saa7146_write(dev, BASE_PAGE2, vdma2.base_page);
- saa7146_write(dev, PITCH2, vdma2.pitch);
- saa7146_write(dev, NUM_LINE_BYTE2, vdma2.num_line_byte);
-
- /* prepare the rest */
- saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
- saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
-
- /* upload clip_control-register, clipping-registers, enable video dma2 */
- saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
- saa7146_write(dev, MC1, (MASK_05 | MASK_21));
-}
-
static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field)
{
struct saa7146_vv *vv = dev->vv_data;
@@ -556,62 +341,6 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
}
-/* calculate the new memory offsets for a desired position */
-static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
-{
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
-
- int b_depth = vv->ov_fmt->depth;
- int b_bpl = vv->ov_fb.fmt.bytesperline;
- /* The unsigned long cast is to remove a 64-bit compile warning since
- it looks like a 64-bit address is cast to a 32-bit value, even
- though the base pointer is really a 32-bit physical address that
- goes into a 32-bit DMA register.
- FIXME: might not work on some 64-bit platforms, but see the FIXME
- in struct v4l2_framebuffer (videodev2.h) for that.
- */
- u32 base = (u32)(unsigned long)vv->ov_fb.base;
-
- struct saa7146_video_dma vdma1;
-
- /* calculate memory offsets for picture, look if we shall top-down-flip */
- vdma1.pitch = 2*b_bpl;
- if ( 0 == vv->vflip ) {
- vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
- vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2);
- vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
- }
- else {
- vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
- vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2);
- vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
- }
-
- if (V4L2_FIELD_HAS_BOTH(field)) {
- } else if (field == V4L2_FIELD_ALTERNATE) {
- /* fixme */
- vdma1.base_odd = vdma1.prot_addr;
- vdma1.pitch /= 2;
- } else if (field == V4L2_FIELD_TOP) {
- vdma1.base_odd = vdma1.prot_addr;
- vdma1.pitch /= 2;
- } else if (field == V4L2_FIELD_BOTTOM) {
- vdma1.base_odd = vdma1.base_even;
- vdma1.base_even = vdma1.prot_addr;
- vdma1.pitch /= 2;
- }
-
- if ( 0 != vv->vflip ) {
- vdma1.pitch *= -1;
- }
-
- vdma1.base_page = sfmt->swap;
- vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
-
- saa7146_write_out_dma(dev, 1, &vdma1);
-}
-
static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
{
u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
@@ -645,30 +374,6 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
}
EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-int saa7146_enable_overlay(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
- saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
- saa7146_set_output_format(dev, vv->ov_fmt->trans);
- saa7146_set_clipping_rect(fh);
-
- /* enable video dma1 */
- saa7146_write(dev, MC1, (MASK_06 | MASK_22));
- return 0;
-}
-
-void saa7146_disable_overlay(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
-
- /* disable clipping + video dma1 */
- saa7146_disable_clipping(dev);
- saa7146_write(dev, MC1, MASK_22);
-}
-
void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
{
int where = 0;
@@ -702,14 +407,14 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi
static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
{
struct saa7146_vv *vv = dev->vv_data;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
struct saa7146_video_dma vdma1;
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat);
- struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
-
- int width = buf->fmt->width;
- int height = buf->fmt->height;
- int bytesperline = buf->fmt->bytesperline;
- enum v4l2_field field = buf->fmt->field;
+ int width = pix->width;
+ int height = pix->height;
+ int bytesperline = pix->bytesperline;
+ enum v4l2_field field = pix->field;
int depth = sfmt->depth;
@@ -764,8 +469,9 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
{
- int height = buf->fmt->height;
- int width = buf->fmt->width;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
+ int height = pix->height;
+ int width = pix->width;
vdma2->pitch = width;
vdma3->pitch = width;
@@ -795,8 +501,9 @@ static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struc
static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
{
- int height = buf->fmt->height;
- int width = buf->fmt->width;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
+ int height = pix->height;
+ int width = pix->width;
vdma2->pitch = width/2;
vdma3->pitch = width/2;
@@ -825,19 +532,20 @@ static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struc
static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
{
struct saa7146_vv *vv = dev->vv_data;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
struct saa7146_video_dma vdma1;
struct saa7146_video_dma vdma2;
struct saa7146_video_dma vdma3;
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat);
- struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+ int width = pix->width;
+ int height = pix->height;
+ enum v4l2_field field = pix->field;
- int width = buf->fmt->width;
- int height = buf->fmt->height;
- enum v4l2_field field = buf->fmt->field;
-
- BUG_ON(0 == buf->pt[0].dma);
- BUG_ON(0 == buf->pt[1].dma);
- BUG_ON(0 == buf->pt[2].dma);
+ if (WARN_ON(!buf->pt[0].dma) ||
+ WARN_ON(!buf->pt[1].dma) ||
+ WARN_ON(!buf->pt[2].dma))
+ return -1;
DEB_CAP("[size=%dx%d,fields=%s]\n",
width, height, v4l2_field_names[field]);
@@ -994,10 +702,27 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
WRITE_RPS0(CMD_STOP);
}
+/* disable clipping */
+static void saa7146_disable_clipping(struct saa7146_dev *dev)
+{
+ u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
+
+ /* mask out relevant bits (=lower word)*/
+ clip_format &= MASK_W1;
+
+ /* upload clipping-registers*/
+ saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
+ saa7146_write(dev, MC2, (MASK_05 | MASK_21));
+
+ /* disable video dma2 */
+ saa7146_write(dev, MC1, MASK_21);
+}
+
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
- struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
struct saa7146_vv *vv = dev->vv_data;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat);
u32 vdma1_prot_addr;
DEB_CAP("buf:%p, next:%p\n", buf, next);
@@ -1009,7 +734,7 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc
saa7146_write(dev, MC2, MASK_27 );
}
- saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
+ saa7146_set_window(dev, pix->width, pix->height, pix->field);
saa7146_set_output_format(dev, sfmt->trans);
saa7146_disable_clipping(dev);
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index bd442b984423..bb7d81f7eba6 100644
--- a/drivers/media/common/saa7146/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -207,7 +207,6 @@ static int buffer_activate(struct saa7146_dev *dev,
struct saa7146_buf *next)
{
struct saa7146_vv *vv = dev->vv_data;
- buf->vb.state = VIDEOBUF_ACTIVE;
DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
saa7146_set_vbi_capture(dev,buf,next);
@@ -216,114 +215,101 @@ static int buffer_activate(struct saa7146_dev *dev,
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)
-{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+/* ------------------------------------------------------------------ */
- int err = 0;
- int lines, llength, size;
+static int queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ unsigned int size = 16 * 2 * vbi_pixel_to_capture;
- lines = 16 * 2 ; /* 2 fields */
- llength = vbi_pixel_to_capture;
- size = lines * llength;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+ *num_planes = 1;
+ sizes[0] = size;
- DEB_VBI("vb:%p\n", vb);
+ return 0;
+}
- if (0 != buf->vb.baddr && buf->vb.bsize < size) {
- DEB_VBI("size mismatch\n");
- return -EINVAL;
- }
+static void buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ unsigned long flags;
- if (buf->vb.size != size)
- saa7146_dma_free(dev,q,buf);
+ spin_lock_irqsave(&dev->slock, flags);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
- buf->vb.width = llength;
- buf->vb.height = lines;
- buf->vb.size = size;
- buf->vb.field = field; // FIXME: check this
+static int buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
+ struct scatterlist *list = sgt->sgl;
+ int length = sgt->nents;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
+ int ret;
- saa7146_pgtable_free(dev->pci, &buf->pt[2]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
-
- err = videobuf_iolock(q,&buf->vb, NULL);
- if (err)
- goto oops;
- err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
- dma->sglist, dma->sglen);
- if (0 != err)
- return err;
- }
- buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
- return 0;
-
- oops:
- DEB_VBI("error out\n");
- saa7146_dma_free(dev,q,buf);
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
- return err;
+ ret = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+ list, length);
+ if (ret)
+ saa7146_pgtable_free(dev->pci, &buf->pt[2]);
+ return ret;
}
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int buf_prepare(struct vb2_buffer *vb)
{
- int llength,lines;
-
- lines = 16 * 2 ; /* 2 fields */
- llength = vbi_pixel_to_capture;
-
- *size = lines * llength;
- *count = 2;
-
- DEB_VBI("count:%d, size:%d\n", *count, *size);
+ unsigned int size = 16 * 2 * vbi_pixel_to_capture;
+ if (vb2_plane_size(vb, 0) < size)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, size);
return 0;
}
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buf_cleanup(struct vb2_buffer *vb)
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
- DEB_VBI("vb:%p\n", vb);
- saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
+ saa7146_pgtable_free(dev->pci, &buf->pt[2]);
}
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void return_buffers(struct vb2_queue *q, int state)
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
-
- DEB_VBI("vb:%p\n", vb);
- saa7146_dma_free(dev,q,buf);
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ struct saa7146_dmaqueue *dq = &dev->vv_data->vbi_dmaq;
+ struct saa7146_buf *buf;
+
+ if (dq->curr) {
+ buf = dq->curr;
+ dq->curr = NULL;
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+ while (!list_empty(&dq->queue)) {
+ buf = list_entry(dq->queue.next, struct saa7146_buf, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
}
-static const struct videobuf_queue_ops vbi_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-static void vbi_stop(struct saa7146_fh *fh, struct file *file)
+static void vbi_stop(struct saa7146_dev *dev)
{
- struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
unsigned long flags;
- DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+ DEB_VBI("dev:%p\n", dev);
spin_lock_irqsave(&dev->slock,flags);
@@ -336,13 +322,6 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
/* shut down dma 3 transfers */
saa7146_write(dev, MC1, MASK_20);
- if (vv->vbi_dmaq.curr)
- saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
-
- videobuf_queue_cancel(&fh->vbi_q);
-
- vv->vbi_streaming = NULL;
-
del_timer(&vv->vbi_dmaq.timeout);
del_timer(&vv->vbi_read_timeout);
@@ -352,38 +331,22 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
static void vbi_read_timeout(struct timer_list *t)
{
struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout);
- struct file *file = vv->vbi_read_timeout_file;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
-
- DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+ struct saa7146_dev *dev = vv->vbi_dmaq.dev;
- vbi_stop(fh, file);
-}
-
-static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
-{
DEB_VBI("dev:%p\n", dev);
- INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
-
- timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0);
- vv->vbi_dmaq.dev = dev;
-
- init_waitqueue_head(&vv->vbi_wq);
+ vbi_stop(dev);
}
-static int vbi_open(struct saa7146_dev *dev, struct file *file)
+static int vbi_begin(struct saa7146_dev *dev)
{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_vv *vv = fh->dev->vv_data;
-
+ struct saa7146_vv *vv = dev->vv_data;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
- DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+ DEB_VBI("dev:%p\n", dev);
- ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
+ ret = saa7146_res_get(dev, RESOURCE_DMA3_BRS);
if (0 == ret) {
DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
return -EBUSY;
@@ -395,15 +358,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
saa7146_write(dev, MC2, (MASK_04|MASK_20));
- videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
- sizeof(struct saa7146_buf),
- file, &dev->v4l2_lock);
-
vv->vbi_read_timeout.function = vbi_read_timeout;
- vv->vbi_read_timeout_file = file;
/* initialize the brs */
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
@@ -422,16 +377,52 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
return 0;
}
-static void vbi_close(struct saa7146_dev *dev, struct file *file)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_vv *vv = dev->vv_data;
- DEB_VBI("dev:%p, fh:%p\n", dev, fh);
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ int ret;
+
+ if (!vb2_is_streaming(&dev->vv_data->vbi_dmaq.q))
+ dev->vv_data->seqnr = 0;
+ ret = vbi_begin(dev);
+ if (ret)
+ return_buffers(q, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
- if( fh == vv->vbi_streaming ) {
- vbi_stop(fh, file);
- }
- saa7146_res_free(fh, RESOURCE_DMA3_BRS);
+static void stop_streaming(struct vb2_queue *q)
+{
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+
+ vbi_stop(dev);
+ return_buffers(q, VB2_BUF_STATE_ERROR);
+ saa7146_res_free(dev, RESOURCE_DMA3_BRS);
+}
+
+const struct vb2_ops vbi_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buf_queue,
+ .buf_init = buf_init,
+ .buf_prepare = buf_prepare,
+ .buf_cleanup = buf_cleanup,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------ */
+
+static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
+{
+ DEB_VBI("dev:%p\n", dev);
+
+ INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
+
+ timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0);
+ vv->vbi_dmaq.dev = dev;
+
+ init_waitqueue_head(&vv->vbi_wq);
}
static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
@@ -441,10 +432,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
if (vv->vbi_dmaq.curr) {
DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
- /* this must be += 2, one count for each field */
- vv->vbi_fieldcount+=2;
- vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
- saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
+ saa7146_buffer_finish(dev, &vv->vbi_dmaq, VB2_BUF_STATE_DONE);
} else {
DEB_VBI("dev:%p\n", dev);
}
@@ -453,46 +441,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
spin_unlock(&dev->slock);
}
-static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- ssize_t ret = 0;
-
- DEB_VBI("dev:%p, fh:%p\n", dev, fh);
-
- if( NULL == vv->vbi_streaming ) {
- // fixme: check if dma3 is available
- // fixme: activate vbi engine here if necessary. (really?)
- vv->vbi_streaming = fh;
- }
-
- if( fh != vv->vbi_streaming ) {
- DEB_VBI("open %p is already using vbi capture\n",
- vv->vbi_streaming);
- return -EBUSY;
- }
-
- mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
- ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
- file->f_flags & O_NONBLOCK);
-/*
- printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3));
- printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3));
- printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3));
- printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3));
- printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3));
- printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
- printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL));
-*/
- return ret;
-}
-
const struct saa7146_use_ops saa7146_vbi_uops = {
.init = vbi_init,
- .open = vbi_open,
- .release = vbi_close,
.irq_done = vbi_irq_done,
- .read = vbi_read,
};
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 2296765079a4..040489e15ea0 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -6,17 +6,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-static int max_memory = 32;
-
-module_param(max_memory, int, 0644);
-MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
-
-#define IS_CAPTURE_ACTIVE(fh) \
- (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
-
-#define IS_OVERLAY_ACTIVE(fh) \
- (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
-
/* format descriptions for capture and preview */
static struct saa7146_format formats[] = {
{
@@ -54,7 +43,7 @@ static struct saa7146_format formats[] = {
.pixelformat = V4L2_PIX_FMT_YUV422P,
.trans = YUV422_DECOMPOSED,
.depth = 16,
- .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
+ .flags = FORMAT_IS_PLANAR,
}, {
.pixelformat = V4L2_PIX_FMT_YVU420,
.trans = YUV420_DECOMPOSED,
@@ -91,115 +80,18 @@ struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fou
return NULL;
}
-static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
-
-int saa7146_start_preview(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct v4l2_format fmt;
- int ret = 0, err = 0;
-
- DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
- /* check if we have overlay information */
- if (vv->ov.fh == NULL) {
- DEB_D("no overlay data available. try S_FMT first.\n");
- return -EAGAIN;
- }
-
- /* check if streaming capture is running */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D("streaming capture is active\n");
- return -EBUSY;
- }
-
- /* check if overlay is running */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- if (vv->video_fh == fh) {
- DEB_D("overlay is already active\n");
- return 0;
- }
- DEB_D("overlay is already active in another open\n");
- return -EBUSY;
- }
-
- if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
- DEB_D("cannot get necessary overlay resources\n");
- return -EBUSY;
- }
-
- fmt.fmt.win = vv->ov.win;
- err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
- if (0 != err) {
- saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
- return -EBUSY;
- }
- vv->ov.win = fmt.fmt.win;
-
- DEB_D("%dx%d+%d+%d 0x%08x field=%s\n",
- vv->ov.win.w.width, vv->ov.win.w.height,
- vv->ov.win.w.left, vv->ov.win.w.top,
- vv->ov_fmt->pixelformat, v4l2_field_names[vv->ov.win.field]);
-
- if (0 != (ret = saa7146_enable_overlay(fh))) {
- DEB_D("enabling overlay failed: %d\n", ret);
- saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
- return ret;
- }
-
- vv->video_status = STATUS_OVERLAY;
- vv->video_fh = fh;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-
-int saa7146_stop_preview(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
- /* check if streaming capture is running */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D("streaming capture is active\n");
- return -EBUSY;
- }
-
- /* check if overlay is running at all */
- if ((vv->video_status & STATUS_OVERLAY) == 0) {
- DEB_D("no active overlay\n");
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_D("overlay is active, but in another open\n");
- return -EBUSY;
- }
-
- vv->video_status = 0;
- vv->video_fh = NULL;
-
- saa7146_disable_overlay(fh);
-
- saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
/********************************************************************************/
/* common pagetable functions */
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
+ struct saa7146_vv *vv = dev->vv_data;
struct pci_dev *pci = dev->pci;
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- struct scatterlist *list = dma->sglist;
- int length = dma->sglen;
- struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
+ struct scatterlist *list = sgt->sgl;
+ int length = sgt->nents;
+ struct v4l2_pix_format *pix = &vv->video_fmt;
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat);
DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
@@ -207,31 +99,32 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
struct saa7146_pgtable *pt1 = &buf->pt[0];
struct saa7146_pgtable *pt2 = &buf->pt[1];
struct saa7146_pgtable *pt3 = &buf->pt[2];
+ struct sg_dma_page_iter dma_iter;
__le32 *ptr1, *ptr2, *ptr3;
__le32 fill;
- int size = buf->fmt->width*buf->fmt->height;
- int i,p,m1,m2,m3,o1,o2;
+ int size = pix->width * pix->height;
+ int i, m1, m2, m3, o1, o2;
switch( sfmt->depth ) {
case 12: {
/* create some offsets inside the page table */
- m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
- m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
- m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
- o1 = size%PAGE_SIZE;
- o2 = (size+(size/4))%PAGE_SIZE;
+ m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1;
+ m2 = ((size + (size / 4) + PAGE_SIZE) / PAGE_SIZE) - 1;
+ m3 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1;
+ o1 = size % PAGE_SIZE;
+ o2 = (size + (size / 4)) % PAGE_SIZE;
DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
size, m1, m2, m3, o1, o2);
break;
}
case 16: {
/* create some offsets inside the page table */
- m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
- m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
- m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
- o1 = size%PAGE_SIZE;
- o2 = (size+(size/2))%PAGE_SIZE;
+ m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1;
+ m2 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1;
+ m3 = ((2 * size + PAGE_SIZE) / PAGE_SIZE) - 1;
+ o1 = size % PAGE_SIZE;
+ o2 = (size + (size / 2)) % PAGE_SIZE;
DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
size, m1, m2, m3, o1, o2);
break;
@@ -245,64 +138,37 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
ptr2 = pt2->cpu;
ptr3 = pt3->cpu;
- /* walk all pages, copy all page addresses to ptr1 */
- for (i = 0; i < length; i++, list++) {
- for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr1++)
- *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
- }
-/*
- ptr1 = pt1->cpu;
- for(j=0;j<40;j++) {
- printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
- }
-*/
+ for_each_sg_dma_page(list, &dma_iter, length, 0)
+ *ptr1++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter) - list->offset);
/* if we have a user buffer, the first page may not be
aligned to a page boundary. */
- pt1->offset = dma->sglist->offset;
- pt2->offset = pt1->offset+o1;
- pt3->offset = pt1->offset+o2;
+ pt1->offset = sgt->sgl->offset;
+ pt2->offset = pt1->offset + o1;
+ pt3->offset = pt1->offset + o2;
/* create video-dma2 page table */
ptr1 = pt1->cpu;
- for(i = m1; i <= m2 ; i++, ptr2++) {
+ for (i = m1; i <= m2; i++, ptr2++)
*ptr2 = ptr1[i];
- }
- fill = *(ptr2-1);
- for(;i<1024;i++,ptr2++) {
+ fill = *(ptr2 - 1);
+ for (; i < 1024; i++, ptr2++)
*ptr2 = fill;
- }
/* create video-dma3 page table */
ptr1 = pt1->cpu;
- for(i = m2; i <= m3; i++,ptr3++) {
+ for (i = m2; i <= m3; i++, ptr3++)
*ptr3 = ptr1[i];
- }
- fill = *(ptr3-1);
- for(;i<1024;i++,ptr3++) {
+ fill = *(ptr3 - 1);
+ for (; i < 1024; i++, ptr3++)
*ptr3 = fill;
- }
/* finally: finish up video-dma1 page table */
- ptr1 = pt1->cpu+m1;
+ ptr1 = pt1->cpu + m1;
fill = pt1->cpu[m1];
- for(i=m1;i<1024;i++,ptr1++) {
+ for (i = m1; i < 1024; i++, ptr1++)
*ptr1 = fill;
- }
-/*
- ptr1 = pt1->cpu;
- ptr2 = pt2->cpu;
- ptr3 = pt3->cpu;
- for(j=0;j<40;j++) {
- printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
- }
- for(j=0;j<40;j++) {
- printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
- }
- for(j=0;j<40;j++) {
- printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
- }
-*/
} else {
struct saa7146_pgtable *pt = &buf->pt[0];
+
return saa7146_pgtable_build_single(pci, pt, list, length);
}
@@ -313,34 +179,14 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
/********************************************************************************/
/* file operations */
-static int video_begin(struct saa7146_fh *fh)
+static int video_begin(struct saa7146_dev *dev)
{
- struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt = NULL;
unsigned int resource;
- int ret = 0, err = 0;
-
- DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
- if ((vv->video_status & STATUS_CAPTURE) != 0) {
- if (vv->video_fh == fh) {
- DEB_S("already capturing\n");
- return 0;
- }
- DEB_S("already capturing in another open\n");
- return -EBUSY;
- }
+ int ret = 0;
- if ((vv->video_status & STATUS_OVERLAY) != 0) {
- DEB_S("warning: suspending overlay video for streaming capture\n");
- vv->ov_suspend = vv->video_fh;
- err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
- if (0 != err) {
- DEB_D("suspending video failed. aborting\n");
- return err;
- }
- }
+ DEB_EE("dev:%p\n", dev);
fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
/* we need to have a valid format set here */
@@ -353,13 +199,9 @@ static int video_begin(struct saa7146_fh *fh)
resource = RESOURCE_DMA1_HPS;
}
- ret = saa7146_res_get(fh, resource);
+ ret = saa7146_res_get(dev, resource);
if (0 == ret) {
DEB_S("cannot get capture resource %d\n", resource);
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
return -EBUSY;
}
@@ -369,37 +211,22 @@ static int video_begin(struct saa7146_fh *fh)
/* enable rps0 irqs */
SAA7146_IER_ENABLE(dev, MASK_27);
- vv->video_fh = fh;
- vv->video_status = STATUS_CAPTURE;
-
return 0;
}
-static int video_end(struct saa7146_fh *fh, struct file *file)
+static void video_end(struct saa7146_dev *dev)
{
- struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_dmaqueue *q = &vv->video_dmaq;
struct saa7146_format *fmt = NULL;
unsigned long flags;
unsigned int resource;
u32 dmas = 0;
- DEB_EE("dev:%p, fh:%p\n", dev, fh);
-
- if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
- DEB_S("not capturing\n");
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_S("capturing, but in another open\n");
- return -EBUSY;
- }
+ DEB_EE("dev:%p\n", dev);
fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
/* we need to have a valid format set here */
if (!fmt)
- return -EINVAL;
+ return;
if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
@@ -419,88 +246,24 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
/* shut down all used video dma transfers */
saa7146_write(dev, MC1, dmas);
- if (q->curr)
- saa7146_buffer_finish(dev, q, VIDEOBUF_DONE);
-
spin_unlock_irqrestore(&dev->slock, flags);
- vv->video_fh = NULL;
- vv->video_status = 0;
-
- saa7146_res_free(fh, resource);
-
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
- return 0;
+ saa7146_res_free(dev, resource);
}
static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_DEVICE_CAPS;
cap->capabilities |= dev->ext_vv_data->capabilities;
return 0;
}
-static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- *fb = vv->ov_fb;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- fb->flags = V4L2_FBUF_FLAG_PRIMARY;
- return 0;
-}
-
-static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *fmt;
-
- DEB_EE("VIDIOC_S_FBUF\n");
-
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- /* planar formats are not allowed for overlay video, clipping and video dma would clash */
- if (fmt->flags & FORMAT_IS_PLANAR)
- DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
- (char *)&fmt->pixelformat);
-
- /* check if overlay is running */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- if (vv->video_fh != fh) {
- DEB_D("refusing to change framebuffer information while overlay is active in another open\n");
- return -EBUSY;
- }
- }
-
- /* ok, accept it */
- vv->ov_fb = *fb;
- vv->ov_fmt = fmt;
-
- if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
- vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
- DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
- }
- return 0;
-}
-
static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
if (f->index >= ARRAY_SIZE(formats))
@@ -543,13 +306,13 @@ int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_HFLIP:
/* fixme: we can support changing VFLIP and HFLIP here... */
- if ((vv->video_status & STATUS_CAPTURE))
+ if (vb2_is_busy(&vv->video_dmaq.q))
return -EBUSY;
vv->hflip = ctrl->val;
break;
case V4L2_CID_VFLIP:
- if ((vv->video_status & STATUS_CAPTURE))
+ if (vb2_is_busy(&vv->video_dmaq.q))
return -EBUSY;
vv->vflip = ctrl->val;
break;
@@ -557,20 +320,13 @@ int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
default:
return -EINVAL;
}
-
- if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
- struct saa7146_fh *fh = vv->video_fh;
-
- saa7146_stop_preview(fh);
- saa7146_start_preview(fh);
- }
return 0;
}
static int vidioc_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *parm)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -583,25 +339,16 @@ static int vidioc_g_parm(struct file *file, void *fh,
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
f->fmt.pix = vv->video_fmt;
return 0;
}
-static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- f->fmt.win = vv->ov.win;
- return 0;
-}
-
static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
f->fmt.vbi = vv->vbi_fmt;
@@ -610,7 +357,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format
static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt;
enum v4l2_field field;
@@ -634,24 +381,21 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
}
switch (field) {
case V4L2_FIELD_ALTERNATE:
- vv->last_field = V4L2_FIELD_TOP;
- maxh = maxh / 2;
- break;
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
- vv->last_field = V4L2_FIELD_INTERLACED;
maxh = maxh / 2;
break;
- case V4L2_FIELD_INTERLACED:
- vv->last_field = V4L2_FIELD_INTERLACED;
- break;
default:
- DEB_D("no known field mode '%d'\n", field);
- return -EINVAL;
+ field = V4L2_FIELD_INTERLACED;
+ break;
}
f->fmt.pix.field = field;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
@@ -673,169 +417,65 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
return 0;
}
-
-static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct v4l2_window *win = &f->fmt.win;
- enum v4l2_field field;
- int maxw, maxh;
-
- DEB_EE("dev:%p\n", dev);
-
- if (NULL == vv->ov_fb.base) {
- DEB_D("no fb base set\n");
- return -EINVAL;
- }
- if (NULL == vv->ov_fmt) {
- DEB_D("no fb fmt set\n");
- return -EINVAL;
- }
- if (win->w.width < 48 || win->w.height < 32) {
- DEB_D("min width/height. (%d,%d)\n",
- win->w.width, win->w.height);
- return -EINVAL;
- }
- if (win->clipcount > 16) {
- DEB_D("clipcount too big\n");
- return -EINVAL;
- }
-
- field = win->field;
- maxw = vv->standard->h_max_out;
- maxh = vv->standard->v_max_out;
-
- if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh / 2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_ALTERNATE:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- DEB_D("no known field mode '%d'\n", field);
- return -EINVAL;
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
-{
- struct saa7146_fh *fh = __fh;
- struct saa7146_dev *dev = fh->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
int err;
- DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p\n", dev);
+ if (vb2_is_busy(&vv->video_dmaq.q)) {
DEB_EE("streaming capture is active\n");
return -EBUSY;
}
err = vidioc_try_fmt_vid_cap(file, fh, f);
if (0 != err)
return err;
+ switch (f->fmt.pix.field) {
+ case V4L2_FIELD_ALTERNATE:
+ vv->last_field = V4L2_FIELD_TOP;
+ break;
+ default:
+ vv->last_field = V4L2_FIELD_INTERLACED;
+ break;
+ }
vv->video_fmt = f->fmt.pix;
DEB_EE("set to pixelformat '%4.4s'\n",
(char *)&vv->video_fmt.pixelformat);
return 0;
}
-static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
-{
- struct saa7146_fh *fh = __fh;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- int err;
-
- DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
- err = vidioc_try_fmt_vid_overlay(file, fh, f);
- if (0 != err)
- return err;
- vv->ov.win = f->fmt.win;
- vv->ov.nclips = f->fmt.win.clipcount;
- if (vv->ov.nclips > 16)
- vv->ov.nclips = 16;
- memcpy(vv->ov.clips, f->fmt.win.clips,
- sizeof(struct v4l2_clip) * vv->ov.nclips);
-
- /* vv->ov.fh is used to indicate that we have valid overlay information, too */
- vv->ov.fh = fh;
-
- /* check if our current overlay is active */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- saa7146_stop_preview(fh);
- saa7146_start_preview(fh);
- }
- return 0;
-}
-
static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
*norm = vv->standard->id;
return 0;
}
- /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
- PAL / NTSC / SECAM. if your hardware does not (or does more)
- -- override this function in your extension */
-/*
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- if (e->index < 0 )
- return -EINVAL;
- if( e->index < dev->ext_vv_data->num_stds ) {
- DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
- v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
- return 0;
- }
- return -EINVAL;
- }
- */
-
static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_vv *vv = dev->vv_data;
int found = 0;
- int err, i;
+ int i;
DEB_EE("VIDIOC_S_STD\n");
- if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
+ for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+ if (id & dev->ext_vv_data->stds[i].id)
+ break;
+
+ if (i != dev->ext_vv_data->num_stds &&
+ vv->standard == &dev->ext_vv_data->stds[i])
+ return 0;
+
+ if (vb2_is_busy(&vv->video_dmaq.q) || vb2_is_busy(&vv->vbi_dmaq.q)) {
DEB_D("cannot change video standard while streaming capture is active\n");
return -EBUSY;
}
- if ((vv->video_status & STATUS_OVERLAY) != 0) {
- vv->ov_suspend = vv->video_fh;
- err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
- if (0 != err) {
- DEB_D("suspending video failed. aborting\n");
- return err;
- }
- }
-
- for (i = 0; i < dev->ext_vv_data->num_stds; i++)
- if (id & dev->ext_vv_data->stds[i].id)
- break;
if (i != dev->ext_vv_data->num_stds) {
vv->standard = &dev->ext_vv_data->stds[i];
if (NULL != dev->ext_vv_data->std_callback)
@@ -843,11 +483,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
found = 1;
}
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
if (!found) {
DEB_EE("VIDIOC_S_STD: standard not found\n");
return -EINVAL;
@@ -857,138 +492,22 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
return 0;
}
-static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
-{
- int err;
-
- DEB_D("VIDIOC_OVERLAY on:%d\n", on);
- if (on)
- err = saa7146_start_preview(fh);
- else
- err = saa7146_stop_preview(fh);
- return err;
-}
-
-static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
-{
- struct saa7146_fh *fh = __fh;
-
- if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_reqbufs(&fh->video_q, b);
- if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return videobuf_reqbufs(&fh->vbi_q, b);
- return -EINVAL;
-}
-
-static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
- struct saa7146_fh *fh = __fh;
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_querybuf(&fh->video_q, buf);
- if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return videobuf_querybuf(&fh->vbi_q, buf);
- return -EINVAL;
-}
-
-static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
- struct saa7146_fh *fh = __fh;
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_qbuf(&fh->video_q, buf);
- if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return videobuf_qbuf(&fh->vbi_q, buf);
- return -EINVAL;
-}
-
-static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
-{
- struct saa7146_fh *fh = __fh;
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
- if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
- return -EINVAL;
-}
-
-static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
-{
- struct saa7146_fh *fh = __fh;
- int err;
-
- DEB_D("VIDIOC_STREAMON, type:%d\n", type);
-
- err = video_begin(fh);
- if (err)
- return err;
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_streamon(&fh->video_q);
- if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return videobuf_streamon(&fh->vbi_q);
- return -EINVAL;
-}
-
-static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
-{
- struct saa7146_fh *fh = __fh;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- int err;
-
- DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
-
- /* ugly: we need to copy some checks from video_end(),
- because videobuf_streamoff() relies on the capture running.
- check and fix this */
- if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
- DEB_S("not capturing\n");
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_S("capturing, but in another open\n");
- return -EBUSY;
- }
-
- err = -EINVAL;
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- err = videobuf_streamoff(&fh->video_q);
- else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
- err = videobuf_streamoff(&fh->vbi_q);
- if (0 != err) {
- DEB_D("warning: videobuf_streamoff() failed\n");
- video_end(fh, file);
- } else {
- err = video_end(fh, file);
- }
- return err;
-}
-
const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
- .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
- .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
-
- .vidioc_overlay = vidioc_overlay,
- .vidioc_g_fbuf = vidioc_g_fbuf,
- .vidioc_s_fbuf = vidioc_s_fbuf,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -996,16 +515,18 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
-
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -1019,7 +540,6 @@ static int buffer_activate (struct saa7146_dev *dev,
{
struct saa7146_vv *vv = dev->vv_data;
- buf->vb.state = VIDEOBUF_ACTIVE;
saa7146_set_capture(dev,buf,next);
mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
@@ -1033,140 +553,136 @@ static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *
saa7146_pgtable_free(dev->pci, &buf->pt[2]);
}
-static int buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static int queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], struct device *alloc_devs[])
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
- int size,err = 0;
-
- DEB_CAP("vbuf:%p\n", vb);
-
- /* sanity checks */
- if (vv->video_fmt.width < 48 ||
- vv->video_fmt.height < 32 ||
- vv->video_fmt.width > vv->standard->h_max_out ||
- vv->video_fmt.height > vv->standard->v_max_out) {
- DEB_D("w (%d) / h (%d) out of bounds\n",
- vv->video_fmt.width, vv->video_fmt.height);
- return -EINVAL;
- }
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ unsigned int size = dev->vv_data->video_fmt.sizeimage;
- size = vv->video_fmt.sizeimage;
- if (0 != buf->vb.baddr && buf->vb.bsize < size) {
- DEB_D("size mismatch\n");
- return -EINVAL;
- }
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+ *num_planes = 1;
+ sizes[0] = size;
- DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
- vv->video_fmt.width, vv->video_fmt.height,
- size, v4l2_field_names[vv->video_fmt.field]);
- if (buf->vb.width != vv->video_fmt.width ||
- buf->vb.bytesperline != vv->video_fmt.bytesperline ||
- buf->vb.height != vv->video_fmt.height ||
- buf->vb.size != size ||
- buf->vb.field != field ||
- buf->vb.field != vv->video_fmt.field ||
- buf->fmt != &vv->video_fmt) {
- saa7146_dma_free(dev,q,buf);
- }
+ return 0;
+}
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct saa7146_format *sfmt;
+static void buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ unsigned long flags;
- buf->vb.bytesperline = vv->video_fmt.bytesperline;
- buf->vb.width = vv->video_fmt.width;
- buf->vb.height = vv->video_fmt.height;
- buf->vb.size = size;
- buf->vb.field = field;
- buf->fmt = &vv->video_fmt;
- buf->vb.field = vv->video_fmt.field;
+ spin_lock_irqsave(&dev->slock, flags);
- sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+ saa7146_buffer_queue(dev, &dev->vv_data->video_dmaq, buf);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
- release_all_pagetables(dev, buf);
- if( 0 != IS_PLANAR(sfmt->trans)) {
- saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
- } else {
- saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
- }
+static int buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_format *sfmt;
+ int ret;
- err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
- if (err)
- goto oops;
- err = saa7146_pgtable_build(dev,buf);
- if (err)
- goto oops;
- }
- buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
+ sfmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
- return 0;
-
- oops:
- DEB_D("error out\n");
- saa7146_dma_free(dev,q,buf);
+ if (IS_PLANAR(sfmt->trans)) {
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
+ } else {
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+ }
- return err;
+ ret = saa7146_pgtable_build(dev, buf);
+ if (ret)
+ release_all_pagetables(dev, buf);
+ return ret;
}
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int buf_prepare(struct vb2_buffer *vb)
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_vv *vv = fh->dev->vv_data;
-
- if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
- *count = MAX_SAA7146_CAPTURE_BUFFERS;
-
- *size = vv->video_fmt.sizeimage;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
+ struct saa7146_vv *vv = dev->vv_data;
+ unsigned int size = vv->video_fmt.sizeimage;
- /* check if we exceed the "max_memory" parameter */
- if( (*count * *size) > (max_memory*1048576) ) {
- *count = (max_memory*1048576) / *size;
- }
+ if (vb2_plane_size(vb, 0) < size)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, size);
+ return 0;
+}
- DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
+static void buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct saa7146_dev *dev = vb2_get_drv_priv(vq);
- return 0;
+ release_all_pagetables(dev, buf);
}
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void return_buffers(struct vb2_queue *q, int state)
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq;
+ struct saa7146_buf *buf;
- DEB_CAP("vbuf:%p\n", vb);
- saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
+ if (dq->curr) {
+ buf = dq->curr;
+ dq->curr = NULL;
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+ while (!list_empty(&dq->queue)) {
+ buf = list_entry(dq->queue.next, struct saa7146_buf, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
}
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ int ret;
- DEB_CAP("vbuf:%p\n", vb);
+ if (!vb2_is_streaming(&dev->vv_data->video_dmaq.q))
+ dev->vv_data->seqnr = 0;
+ ret = video_begin(dev);
+ if (ret)
+ return_buffers(q, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
- saa7146_dma_free(dev,q,buf);
+static void stop_streaming(struct vb2_queue *q)
+{
+ struct saa7146_dev *dev = vb2_get_drv_priv(q);
+ struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq;
- release_all_pagetables(dev, buf);
+ del_timer(&dq->timeout);
+ video_end(dev);
+ return_buffers(q, VB2_BUF_STATE_ERROR);
}
-static const struct videobuf_queue_ops video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+const struct vb2_ops video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buf_queue,
+ .buf_init = buf_init,
+ .buf_prepare = buf_prepare,
+ .buf_cleanup = buf_cleanup,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/********************************************************************************/
@@ -1187,38 +703,6 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
}
-
-static int video_open(struct saa7146_dev *dev, struct file *file)
-{
- struct saa7146_fh *fh = file->private_data;
-
- videobuf_queue_sg_init(&fh->video_q, &video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct saa7146_buf),
- file, &dev->v4l2_lock);
-
- return 0;
-}
-
-
-static void video_close(struct saa7146_dev *dev, struct file *file)
-{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_vv *vv = dev->vv_data;
- struct videobuf_queue *q = &fh->video_q;
-
- if (IS_CAPTURE_ACTIVE(fh) != 0)
- video_end(fh, file);
- else if (IS_OVERLAY_ACTIVE(fh) != 0)
- saa7146_stop_preview(fh);
-
- videobuf_stop(q);
- /* hmm, why is this function declared void? */
-}
-
-
static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
{
struct saa7146_vv *vv = dev->vv_data;
@@ -1228,59 +712,14 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
DEB_CAP("called\n");
/* only finish the buffer if we have one... */
- if( NULL != q->curr ) {
- saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
- }
+ if (q->curr)
+ saa7146_buffer_finish(dev, q, VB2_BUF_STATE_DONE);
saa7146_buffer_next(dev,q,0);
spin_unlock(&dev->slock);
}
-static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- ssize_t ret = 0;
-
- DEB_EE("called\n");
-
- if ((vv->video_status & STATUS_CAPTURE) != 0) {
- /* fixme: should we allow read() captures while streaming capture? */
- if (vv->video_fh == fh) {
- DEB_S("already capturing\n");
- return -EBUSY;
- }
- DEB_S("already capturing in another open\n");
- return -EBUSY;
- }
-
- ret = video_begin(fh);
- if( 0 != ret) {
- goto out;
- }
-
- ret = videobuf_read_one(&fh->video_q , data, count, ppos,
- file->f_flags & O_NONBLOCK);
- if (ret != 0) {
- video_end(fh, file);
- } else {
- ret = video_end(fh, file);
- }
-out:
- /* restart overlay if it was active before */
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
- return ret;
-}
-
const struct saa7146_use_ops saa7146_video_uops = {
.init = video_init,
- .open = video_open,
- .release = video_close,
.irq_done = video_irq_done,
- .read = video_read,
};
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 1f5d235a8441..c7a54d82a55e 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -1171,10 +1171,11 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev->queue, file))
goto exit;
+ vdev->queue->owner = file->private_data;
err = vb2_read(vdev->queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);
- if (vdev->queue->fileio)
- vdev->queue->owner = file->private_data;
+ if (!vdev->queue->fileio)
+ vdev->queue->owner = NULL;
exit:
if (lock)
mutex_unlock(lock);
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 6bf6559b127f..68f4e8b5a0ab 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -11070,7 +11070,7 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode)
sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
break;
default:
- /* Unknow sleep mode */
+ /* Unknown sleep mode */
return -EINVAL;
}
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 9807f5411996..3301ef75d441 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -1585,7 +1585,7 @@ static int ctrl_power_mode(struct drxk_state *state, enum drx_power_mode *mode)
sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
break;
default:
- /* Unknow sleep mode */
+ /* Unknown sleep mode */
return -EINVAL;
}
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 05f71d169726..02c619e51641 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -1463,7 +1463,7 @@ err:
return ret;
}
-static int rtl2832_sdr_remove(struct platform_device *pdev)
+static void rtl2832_sdr_remove(struct platform_device *pdev)
{
struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev);
@@ -1479,8 +1479,6 @@ static int rtl2832_sdr_remove(struct platform_device *pdev)
mutex_unlock(&dev->vb_queue_lock);
v4l2_device_put(&dev->v4l2_dev);
module_put(pdev->dev.parent->driver->owner);
-
- return 0;
}
static struct platform_driver rtl2832_sdr_driver = {
@@ -1488,7 +1486,7 @@ static struct platform_driver rtl2832_sdr_driver = {
.name = "rtl2832_sdr",
},
.probe = rtl2832_sdr_probe,
- .remove = rtl2832_sdr_remove,
+ .remove_new = rtl2832_sdr_remove,
};
module_platform_driver(rtl2832_sdr_driver);
diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c
index bbabe6a2d4f4..17f6e373c13d 100644
--- a/drivers/media/dvb-frontends/zd1301_demod.c
+++ b/drivers/media/dvb-frontends/zd1301_demod.c
@@ -515,7 +515,7 @@ err:
return ret;
}
-static int zd1301_demod_remove(struct platform_device *pdev)
+static void zd1301_demod_remove(struct platform_device *pdev)
{
struct zd1301_demod_dev *dev = platform_get_drvdata(pdev);
@@ -523,8 +523,6 @@ static int zd1301_demod_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter);
kfree(dev);
-
- return 0;
}
static struct platform_driver zd1301_demod_driver = {
@@ -533,7 +531,7 @@ static struct platform_driver zd1301_demod_driver = {
.suppress_bind_attrs = true,
},
.probe = zd1301_demod_probe,
- .remove = zd1301_demod_remove,
+ .remove_new = zd1301_demod_remove,
};
module_platform_driver(zd1301_demod_driver);
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index c3d5952ca27e..256d55bb2b1d 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -267,16 +267,6 @@ config VIDEO_MT9M001
This driver supports MT9M001 cameras from Micron, monochrome
and colour models.
-config VIDEO_MT9M032
- tristate "MT9M032 camera sensor support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- select VIDEO_APTINA_PLL
- help
- This driver supports MT9M032 camera sensors from Aptina, monochrome
- models only.
-
config VIDEO_MT9M111
tristate "mt9m111, mt9m112 and mt9m131 support"
depends on I2C && VIDEO_DEV
@@ -296,15 +286,6 @@ config VIDEO_MT9P031
This is a Video4Linux2 sensor driver for the Aptina
(Micron) mt9p031 5 Mpixel camera.
-config VIDEO_MT9T001
- tristate "Aptina MT9T001 support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- help
- This is a Video4Linux2 sensor driver for the Aptina
- (Micron) mt0t001 3 Mpixel camera.
-
config VIDEO_MT9T112
tristate "Aptina MT9T111/MT9T112 support"
depends on I2C && VIDEO_DEV
@@ -344,14 +325,6 @@ config VIDEO_MT9V111
To compile this driver as a module, choose M here: the
module will be called mt9v111.
-config VIDEO_NOON010PC30
- tristate "Siliconfile NOON010PC30 sensor support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- help
- This driver supports NOON010PC30 CIF camera from Siliconfile
-
config VIDEO_OG01A1B
tristate "OmniVision OG01A1B sensor support"
depends on I2C && VIDEO_DEV
@@ -462,6 +435,7 @@ config VIDEO_OV2685
tristate "OmniVision OV2685 sensor support"
depends on VIDEO_DEV && I2C
select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
@@ -810,21 +784,6 @@ config VIDEO_S5K6A3
This is a V4L2 sensor driver for Samsung S5K6A3 raw
camera sensor.
-config VIDEO_S5K6AA
- tristate "Samsung S5K6AAFX sensor support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- help
- This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M
- camera sensor with an embedded SoC image signal processor.
-
-config VIDEO_SR030PC30
- tristate "Siliconfile SR030PC30 sensor support"
- depends on I2C && VIDEO_DEV
- help
- This driver supports SR030PC30 VGA camera from Siliconfile
-
config VIDEO_ST_VGXY61
tristate "ST VGXY61 sensor support"
depends on OF && GPIOLIB && VIDEO_DEV && I2C
@@ -835,19 +794,8 @@ config VIDEO_ST_VGXY61
This is a Video4Linux2 sensor driver for the ST VGXY61
camera sensor.
-config VIDEO_VS6624
- tristate "ST VS6624 sensor support"
- depends on VIDEO_DEV && I2C
- help
- This is a Video4Linux2 sensor driver for the ST VS6624
- camera.
-
- To compile this driver as a module, choose M here: the
- module will be called vs6624.
-
source "drivers/media/i2c/ccs/Kconfig"
source "drivers/media/i2c/et8ek8/Kconfig"
-source "drivers/media/i2c/m5mols/Kconfig"
endmenu
@@ -1453,20 +1401,6 @@ endmenu
menu "Video encoders"
visible if !MEDIA_HIDE_ANCILLARY_SUBDRV
-config VIDEO_AD9389B
- tristate "Analog Devices AD9389B encoder"
- depends on VIDEO_DEV && I2C
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
-
- help
- Support for the Analog Devices AD9389B video encoder.
-
- This is a Analog Devices HDMI transmitter.
-
- To compile this driver as a module, choose M here: the
- module will be called ad9389b.
-
config VIDEO_ADV7170
tristate "Analog Devices ADV7170 video encoder"
depends on VIDEO_DEV && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 4f5e9d9cee85..b44dacf935f4 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -4,7 +4,6 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o
obj-$(CONFIG_VIDEO_AD5820) += ad5820.o
-obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
@@ -56,21 +55,17 @@ obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
obj-$(CONFIG_VIDEO_LM3560) += lm3560.o
obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
-obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
-obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
-obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o
obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o
@@ -110,7 +105,6 @@ obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o
obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o
-obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o
obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
@@ -119,7 +113,6 @@ obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
-obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
@@ -145,6 +138,5 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
-obj-$(CONFIG_VIDEO_VS6624) += vs6624.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
deleted file mode 100644
index ad17097a2d25..000000000000
--- a/drivers/media/i2c/ad9389b.c
+++ /dev/null
@@ -1,1215 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Analog Devices AD9389B/AD9889B video encoder driver
- *
- * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- */
-
-/*
- * References (c = chapter, p = page):
- * REF_01 - Analog Devices, Programming Guide, AD9889B/AD9389B,
- * HDMI Transitter, Rev. A, October 2010
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <linux/workqueue.h>
-#include <linux/v4l2-dv-timings.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-dv-timings.h>
-#include <media/v4l2-ctrls.h>
-#include <media/i2c/ad9389b.h>
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
-
-MODULE_DESCRIPTION("Analog Devices AD9389B/AD9889B video encoder driver");
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
-MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>");
-MODULE_LICENSE("GPL");
-
-#define MASK_AD9389B_EDID_RDY_INT 0x04
-#define MASK_AD9389B_MSEN_INT 0x40
-#define MASK_AD9389B_HPD_INT 0x80
-
-#define MASK_AD9389B_HPD_DETECT 0x40
-#define MASK_AD9389B_MSEN_DETECT 0x20
-#define MASK_AD9389B_EDID_RDY 0x10
-
-#define EDID_MAX_RETRIES (8)
-#define EDID_DELAY 250
-#define EDID_MAX_SEGM 8
-
-/*
-**********************************************************************
-*
-* Arrays with configuration parameters for the AD9389B
-*
-**********************************************************************
-*/
-
-struct ad9389b_state_edid {
- /* total number of blocks */
- u32 blocks;
- /* Number of segments read */
- u32 segments;
- u8 data[EDID_MAX_SEGM * 256];
- /* Number of EDID read retries left */
- unsigned read_retries;
-};
-
-struct ad9389b_state {
- struct ad9389b_platform_data pdata;
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_ctrl_handler hdl;
- int chip_revision;
- /* Is the ad9389b powered on? */
- bool power_on;
- /* Did we receive hotplug and rx-sense signals? */
- bool have_monitor;
- /* timings from s_dv_timings */
- struct v4l2_dv_timings dv_timings;
- /* controls */
- struct v4l2_ctrl *hdmi_mode_ctrl;
- struct v4l2_ctrl *hotplug_ctrl;
- struct v4l2_ctrl *rx_sense_ctrl;
- struct v4l2_ctrl *have_edid0_ctrl;
- struct v4l2_ctrl *rgb_quantization_range_ctrl;
- struct i2c_client *edid_i2c_client;
- struct ad9389b_state_edid edid;
- /* Running counter of the number of detected EDIDs (for debugging) */
- unsigned edid_detect_counter;
- struct delayed_work edid_handler; /* work entry */
-};
-
-static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd);
-static bool ad9389b_check_edid_status(struct v4l2_subdev *sd);
-static void ad9389b_setup(struct v4l2_subdev *sd);
-static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq);
-static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
-
-static inline struct ad9389b_state *get_ad9389b_state(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct ad9389b_state, sd);
-}
-
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct ad9389b_state, hdl)->sd;
-}
-
-/* ------------------------ I2C ----------------------------------------------- */
-
-static int ad9389b_rd(struct v4l2_subdev *sd, u8 reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- int i;
-
- for (i = 0; i < 3; i++) {
- ret = i2c_smbus_write_byte_data(client, reg, val);
- if (ret == 0)
- return 0;
- }
- v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val);
- return ret;
-}
-
-/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
- and then the value-mask (to be OR-ed). */
-static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg,
- u8 clr_mask, u8 val_mask)
-{
- ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask);
-}
-
-static void ad9389b_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- int i;
-
- v4l2_dbg(1, debug, sd, "%s:\n", __func__);
-
- for (i = 0; i < len; i++)
- buf[i] = i2c_smbus_read_byte_data(state->edid_i2c_client, i);
-}
-
-static inline bool ad9389b_have_hotplug(struct v4l2_subdev *sd)
-{
- return ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT;
-}
-
-static inline bool ad9389b_have_rx_sense(struct v4l2_subdev *sd)
-{
- return ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT;
-}
-
-static void ad9389b_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode)
-{
- ad9389b_wr_and_or(sd, 0x17, 0xe7, (mode & 0x3)<<3);
- ad9389b_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5);
-}
-
-static void ad9389b_csc_coeff(struct v4l2_subdev *sd,
- u16 A1, u16 A2, u16 A3, u16 A4,
- u16 B1, u16 B2, u16 B3, u16 B4,
- u16 C1, u16 C2, u16 C3, u16 C4)
-{
- /* A */
- ad9389b_wr_and_or(sd, 0x18, 0xe0, A1>>8);
- ad9389b_wr(sd, 0x19, A1);
- ad9389b_wr_and_or(sd, 0x1A, 0xe0, A2>>8);
- ad9389b_wr(sd, 0x1B, A2);
- ad9389b_wr_and_or(sd, 0x1c, 0xe0, A3>>8);
- ad9389b_wr(sd, 0x1d, A3);
- ad9389b_wr_and_or(sd, 0x1e, 0xe0, A4>>8);
- ad9389b_wr(sd, 0x1f, A4);
-
- /* B */
- ad9389b_wr_and_or(sd, 0x20, 0xe0, B1>>8);
- ad9389b_wr(sd, 0x21, B1);
- ad9389b_wr_and_or(sd, 0x22, 0xe0, B2>>8);
- ad9389b_wr(sd, 0x23, B2);
- ad9389b_wr_and_or(sd, 0x24, 0xe0, B3>>8);
- ad9389b_wr(sd, 0x25, B3);
- ad9389b_wr_and_or(sd, 0x26, 0xe0, B4>>8);
- ad9389b_wr(sd, 0x27, B4);
-
- /* C */
- ad9389b_wr_and_or(sd, 0x28, 0xe0, C1>>8);
- ad9389b_wr(sd, 0x29, C1);
- ad9389b_wr_and_or(sd, 0x2A, 0xe0, C2>>8);
- ad9389b_wr(sd, 0x2B, C2);
- ad9389b_wr_and_or(sd, 0x2C, 0xe0, C3>>8);
- ad9389b_wr(sd, 0x2D, C3);
- ad9389b_wr_and_or(sd, 0x2E, 0xe0, C4>>8);
- ad9389b_wr(sd, 0x2F, C4);
-}
-
-static void ad9389b_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)
-{
- if (enable) {
- u8 csc_mode = 0;
-
- ad9389b_csc_conversion_mode(sd, csc_mode);
- ad9389b_csc_coeff(sd,
- 4096-564, 0, 0, 256,
- 0, 4096-564, 0, 256,
- 0, 0, 4096-564, 256);
- /* enable CSC */
- ad9389b_wr_and_or(sd, 0x3b, 0xfe, 0x1);
- /* AVI infoframe: Limited range RGB (16-235) */
- ad9389b_wr_and_or(sd, 0xcd, 0xf9, 0x02);
- } else {
- /* disable CSC */
- ad9389b_wr_and_or(sd, 0x3b, 0xfe, 0x0);
- /* AVI infoframe: Full range RGB (0-255) */
- ad9389b_wr_and_or(sd, 0xcd, 0xf9, 0x04);
- }
-}
-
-static void ad9389b_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
- /* CE format, not IT */
- ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x00);
- } else {
- /* IT format */
- ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x40);
- }
-}
-
-static int ad9389b_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- switch (ctrl->val) {
- case V4L2_DV_RGB_RANGE_AUTO:
- /* automatic */
- if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
- /* CE format, RGB limited range (16-235) */
- ad9389b_csc_rgb_full2limit(sd, true);
- } else {
- /* not CE format, RGB full range (0-255) */
- ad9389b_csc_rgb_full2limit(sd, false);
- }
- break;
- case V4L2_DV_RGB_RANGE_LIMITED:
- /* RGB limited range (16-235) */
- ad9389b_csc_rgb_full2limit(sd, true);
- break;
- case V4L2_DV_RGB_RANGE_FULL:
- /* RGB full range (0-255) */
- ad9389b_csc_rgb_full2limit(sd, false);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static void ad9389b_set_manual_pll_gear(struct v4l2_subdev *sd, u32 pixelclock)
-{
- u8 gear;
-
- /* Workaround for TMDS PLL problem
- * The TMDS PLL in AD9389b change gear when the chip is heated above a
- * certain temperature. The output is disabled when the PLL change gear
- * so the monitor has to lock on the signal again. A workaround for
- * this is to use the manual PLL gears. This is a solution from Analog
- * Devices that is not documented in the datasheets.
- * 0x98 [7] = enable manual gearing. 0x98 [6:4] = gear
- *
- * The pixel frequency ranges are based on readout of the gear the
- * automatic gearing selects for different pixel clocks
- * (read from 0x9e [3:1]).
- */
-
- if (pixelclock > 140000000)
- gear = 0xc0; /* 4th gear */
- else if (pixelclock > 117000000)
- gear = 0xb0; /* 3rd gear */
- else if (pixelclock > 87000000)
- gear = 0xa0; /* 2nd gear */
- else if (pixelclock > 60000000)
- gear = 0x90; /* 1st gear */
- else
- gear = 0x80; /* 0th gear */
-
- ad9389b_wr_and_or(sd, 0x98, 0x0f, gear);
-}
-
-/* ------------------------------ CTRL OPS ------------------------------ */
-
-static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- v4l2_dbg(1, debug, sd,
- "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
-
- if (state->hdmi_mode_ctrl == ctrl) {
- /* Set HDMI or DVI-D */
- ad9389b_wr_and_or(sd, 0xaf, 0xfd,
- ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
- return 0;
- }
- if (state->rgb_quantization_range_ctrl == ctrl)
- return ad9389b_set_rgb_quantization_mode(sd, ctrl);
- return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops ad9389b_ctrl_ops = {
- .s_ctrl = ad9389b_s_ctrl,
-};
-
-/* ---------------------------- CORE OPS ------------------------------------------- */
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
-{
- reg->val = ad9389b_rd(sd, reg->reg & 0xff);
- reg->size = 1;
- return 0;
-}
-
-static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
-{
- ad9389b_wr(sd, reg->reg & 0xff, reg->val & 0xff);
- return 0;
-}
-#endif
-
-static int ad9389b_log_status(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- struct ad9389b_state_edid *edid = &state->edid;
-
- static const char * const states[] = {
- "in reset",
- "reading EDID",
- "idle",
- "initializing HDCP",
- "HDCP enabled",
- "initializing HDCP repeater",
- "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"
- };
- static const char * const errors[] = {
- "no error",
- "bad receiver BKSV",
- "Ri mismatch",
- "Pj mismatch",
- "i2c error",
- "timed out",
- "max repeater cascade exceeded",
- "hash check failed",
- "too many devices",
- "9", "A", "B", "C", "D", "E", "F"
- };
-
- u8 manual_gear;
-
- v4l2_info(sd, "chip revision %d\n", state->chip_revision);
- v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
- v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
- (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
- "detected" : "no",
- (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
- "detected" : "no",
- edid->segments ? "found" : "no", edid->blocks);
- v4l2_info(sd, "%s output %s\n",
- (ad9389b_rd(sd, 0xaf) & 0x02) ?
- "HDMI" : "DVI-D",
- (ad9389b_rd(sd, 0xa1) & 0x3c) ?
- "disabled" : "enabled");
- v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ?
- "encrypted" : "no encryption");
- v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
- states[ad9389b_rd(sd, 0xc8) & 0xf],
- errors[ad9389b_rd(sd, 0xc8) >> 4],
- state->edid_detect_counter,
- ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
- manual_gear = ad9389b_rd(sd, 0x98) & 0x80;
- v4l2_info(sd, "ad9389b: RGB quantization: %s range\n",
- ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
- v4l2_info(sd, "ad9389b: %s gear %d\n",
- manual_gear ? "manual" : "automatic",
- manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) :
- ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
- if (ad9389b_rd(sd, 0xaf) & 0x02) {
- /* HDMI only */
- u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
- u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
- ad9389b_rd(sd, 0x02) << 8 |
- ad9389b_rd(sd, 0x03);
- u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
- u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
- u32 CTS;
-
- if (manual_cts)
- CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
- ad9389b_rd(sd, 0x08) << 8 |
- ad9389b_rd(sd, 0x09);
- else
- CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
- ad9389b_rd(sd, 0x05) << 8 |
- ad9389b_rd(sd, 0x06);
- N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
- ad9389b_rd(sd, 0x02) << 8 |
- ad9389b_rd(sd, 0x03);
-
- v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
- manual_cts ? "manual" : "automatic", N, CTS);
-
- v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
- vic_detect, vic_sent);
- }
- if (state->dv_timings.type == V4L2_DV_BT_656_1120)
- v4l2_print_dv_timings(sd->name, "timings: ",
- &state->dv_timings, false);
- else
- v4l2_info(sd, "no timings set\n");
- return 0;
-}
-
-/* Power up/down ad9389b */
-static int ad9389b_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- struct ad9389b_platform_data *pdata = &state->pdata;
- const int retries = 20;
- int i;
-
- v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
-
- state->power_on = on;
-
- if (!on) {
- /* Power down */
- ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x40);
- return true;
- }
-
- /* Power up */
- /* The ad9389b does not always come up immediately.
- Retry multiple times. */
- for (i = 0; i < retries; i++) {
- ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x0);
- if ((ad9389b_rd(sd, 0x41) & 0x40) == 0)
- break;
- ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x40);
- msleep(10);
- }
- if (i == retries) {
- v4l2_dbg(1, debug, sd, "failed to powerup the ad9389b\n");
- ad9389b_s_power(sd, 0);
- return false;
- }
- if (i > 1)
- v4l2_dbg(1, debug, sd,
- "needed %d retries to powerup the ad9389b\n", i);
-
- /* Select chip: AD9389B */
- ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10);
-
- /* Reserved registers that must be set according to REF_01 p. 11*/
- ad9389b_wr_and_or(sd, 0x98, 0xf0, 0x07);
- ad9389b_wr(sd, 0x9c, 0x38);
- ad9389b_wr_and_or(sd, 0x9d, 0xfc, 0x01);
-
- /* Differential output drive strength */
- if (pdata->diff_data_drive_strength > 0)
- ad9389b_wr(sd, 0xa2, pdata->diff_data_drive_strength);
- else
- ad9389b_wr(sd, 0xa2, 0x87);
-
- if (pdata->diff_clk_drive_strength > 0)
- ad9389b_wr(sd, 0xa3, pdata->diff_clk_drive_strength);
- else
- ad9389b_wr(sd, 0xa3, 0x87);
-
- ad9389b_wr(sd, 0x0a, 0x01);
- ad9389b_wr(sd, 0xbb, 0xff);
-
- /* Set number of attempts to read the EDID */
- ad9389b_wr(sd, 0xc9, 0xf);
- return true;
-}
-
-/* Enable interrupts */
-static void ad9389b_set_isr(struct v4l2_subdev *sd, bool enable)
-{
- u8 irqs = MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT;
- u8 irqs_rd;
- int retries = 100;
-
- /* The datasheet says that the EDID ready interrupt should be
- disabled if there is no hotplug. */
- if (!enable)
- irqs = 0;
- else if (ad9389b_have_hotplug(sd))
- irqs |= MASK_AD9389B_EDID_RDY_INT;
-
- /*
- * This i2c write can fail (approx. 1 in 1000 writes). But it
- * is essential that this register is correct, so retry it
- * multiple times.
- *
- * Note that the i2c write does not report an error, but the readback
- * clearly shows the wrong value.
- */
- do {
- ad9389b_wr(sd, 0x94, irqs);
- irqs_rd = ad9389b_rd(sd, 0x94);
- } while (retries-- && irqs_rd != irqs);
-
- if (irqs_rd != irqs)
- v4l2_err(sd, "Could not set interrupts: hw failure?\n");
-}
-
-/* Interrupt handler */
-static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
-{
- u8 irq_status;
-
- /* disable interrupts to prevent a race condition */
- ad9389b_set_isr(sd, false);
- irq_status = ad9389b_rd(sd, 0x96);
- /* clear detected interrupts */
- ad9389b_wr(sd, 0x96, irq_status);
- /* enable interrupts */
- ad9389b_set_isr(sd, true);
-
- v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status);
-
- if (irq_status & (MASK_AD9389B_HPD_INT))
- ad9389b_check_monitor_present_status(sd);
- if (irq_status & MASK_AD9389B_EDID_RDY_INT)
- ad9389b_check_edid_status(sd);
-
- *handled = true;
- return 0;
-}
-
-static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
- .log_status = ad9389b_log_status,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ad9389b_g_register,
- .s_register = ad9389b_s_register,
-#endif
- .s_power = ad9389b_s_power,
- .interrupt_service_routine = ad9389b_isr,
-};
-
-/* ------------------------------ VIDEO OPS ------------------------------ */
-
-/* Enable/disable ad9389b output */
-static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
-{
- v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
-
- ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
- if (enable) {
- ad9389b_check_monitor_present_status(sd);
- } else {
- ad9389b_s_power(sd, 0);
- }
- return 0;
-}
-
-static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
- .type = V4L2_DV_BT_656_1120,
- /* keep this initialization for compatibility with GCC < 4.4.6 */
- .reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
- V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
- V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
- V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
- V4L2_DV_BT_CAP_CUSTOM)
-};
-
-static int ad9389b_s_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *timings)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- v4l2_dbg(1, debug, sd, "%s:\n", __func__);
-
- /* quick sanity check */
- if (!v4l2_valid_dv_timings(timings, &ad9389b_timings_cap, NULL, NULL))
- return -EINVAL;
-
- /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
- if the format is one of the CEA or DMT timings. */
- v4l2_find_dv_timings_cap(timings, &ad9389b_timings_cap, 0, NULL, NULL);
-
- timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
-
- /* save timings */
- state->dv_timings = *timings;
-
- /* update quantization range based on new dv_timings */
- ad9389b_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
-
- /* update PLL gear based on new dv_timings */
- if (state->pdata.tmds_pll_gear == AD9389B_TMDS_PLL_GEAR_SEMI_AUTOMATIC)
- ad9389b_set_manual_pll_gear(sd, (u32)timings->bt.pixelclock);
-
- /* update AVI infoframe */
- ad9389b_set_IT_content_AVI_InfoFrame(sd);
-
- return 0;
-}
-
-static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *timings)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- v4l2_dbg(1, debug, sd, "%s:\n", __func__);
-
- if (!timings)
- return -EINVAL;
-
- *timings = state->dv_timings;
-
- return 0;
-}
-
-static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_enum_dv_timings *timings)
-{
- if (timings->pad != 0)
- return -EINVAL;
-
- return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
- NULL, NULL);
-}
-
-static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
- struct v4l2_dv_timings_cap *cap)
-{
- if (cap->pad != 0)
- return -EINVAL;
-
- *cap = ad9389b_timings_cap;
- return 0;
-}
-
-static const struct v4l2_subdev_video_ops ad9389b_video_ops = {
- .s_stream = ad9389b_s_stream,
- .s_dv_timings = ad9389b_s_dv_timings,
- .g_dv_timings = ad9389b_g_dv_timings,
-};
-
-/* ------------------------------ PAD OPS ------------------------------ */
-
-static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- if (edid->pad != 0)
- return -EINVAL;
- if (edid->blocks == 0 || edid->blocks > 256)
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
- }
- if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if (edid->blocks + edid->start_block >= state->edid.segments * 2)
- edid->blocks = state->edid.segments * 2 - edid->start_block;
- memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
- 128 * edid->blocks);
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
- .get_edid = ad9389b_get_edid,
- .enum_dv_timings = ad9389b_enum_dv_timings,
- .dv_timings_cap = ad9389b_dv_timings_cap,
-};
-
-/* ------------------------------ AUDIO OPS ------------------------------ */
-
-static int ad9389b_s_audio_stream(struct v4l2_subdev *sd, int enable)
-{
- v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
-
- if (enable)
- ad9389b_wr_and_or(sd, 0x45, 0x3f, 0x80);
- else
- ad9389b_wr_and_or(sd, 0x45, 0x3f, 0x40);
-
- return 0;
-}
-
-static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
-{
- u32 N;
-
- switch (freq) {
- case 32000: N = 4096; break;
- case 44100: N = 6272; break;
- case 48000: N = 6144; break;
- case 88200: N = 12544; break;
- case 96000: N = 12288; break;
- case 176400: N = 25088; break;
- case 192000: N = 24576; break;
- default:
- return -EINVAL;
- }
-
- /* Set N (used with CTS to regenerate the audio clock) */
- ad9389b_wr(sd, 0x01, (N >> 16) & 0xf);
- ad9389b_wr(sd, 0x02, (N >> 8) & 0xff);
- ad9389b_wr(sd, 0x03, N & 0xff);
-
- return 0;
-}
-
-static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
-{
- u32 i2s_sf;
-
- switch (freq) {
- case 32000: i2s_sf = 0x30; break;
- case 44100: i2s_sf = 0x00; break;
- case 48000: i2s_sf = 0x20; break;
- case 88200: i2s_sf = 0x80; break;
- case 96000: i2s_sf = 0xa0; break;
- case 176400: i2s_sf = 0xc0; break;
- case 192000: i2s_sf = 0xe0; break;
- default:
- return -EINVAL;
- }
-
- /* Set sampling frequency for I2S audio to 48 kHz */
- ad9389b_wr_and_or(sd, 0x15, 0xf, i2s_sf);
-
- return 0;
-}
-
-static int ad9389b_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config)
-{
- /* TODO based on input/output/config */
- /* TODO See datasheet "Programmers guide" p. 39-40 */
-
- /* Only 2 channels in use for application */
- ad9389b_wr_and_or(sd, 0x50, 0x1f, 0x20);
- /* Speaker mapping */
- ad9389b_wr(sd, 0x51, 0x00);
-
- /* TODO Where should this be placed? */
- /* 16 bit audio word length */
- ad9389b_wr_and_or(sd, 0x14, 0xf0, 0x02);
-
- return 0;
-}
-
-static const struct v4l2_subdev_audio_ops ad9389b_audio_ops = {
- .s_stream = ad9389b_s_audio_stream,
- .s_clock_freq = ad9389b_s_clock_freq,
- .s_i2s_clock_freq = ad9389b_s_i2s_clock_freq,
- .s_routing = ad9389b_s_routing,
-};
-
-/* --------------------- SUBDEV OPS --------------------------------------- */
-
-static const struct v4l2_subdev_ops ad9389b_ops = {
- .core = &ad9389b_core_ops,
- .video = &ad9389b_video_ops,
- .audio = &ad9389b_audio_ops,
- .pad = &ad9389b_pad_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
- int segment, u8 *buf)
-{
- int i, j;
-
- if (debug < lvl)
- return;
-
- v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment);
- for (i = 0; i < 256; i += 16) {
- u8 b[128];
- u8 *bp = b;
-
- if (i == 128)
- v4l2_dbg(lvl, debug, sd, "\n");
- for (j = i; j < i + 16; j++) {
- sprintf(bp, "0x%02x, ", buf[j]);
- bp += 6;
- }
- bp[0] = '\0';
- v4l2_dbg(lvl, debug, sd, "%s\n", b);
- }
-}
-
-static void ad9389b_edid_handler(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct ad9389b_state *state =
- container_of(dwork, struct ad9389b_state, edid_handler);
- struct v4l2_subdev *sd = &state->sd;
- struct ad9389b_edid_detect ed;
-
- v4l2_dbg(1, debug, sd, "%s:\n", __func__);
-
- if (ad9389b_check_edid_status(sd)) {
- /* Return if we received the EDID. */
- return;
- }
-
- if (ad9389b_have_hotplug(sd)) {
- /* We must retry reading the EDID several times, it is possible
- * that initially the EDID couldn't be read due to i2c errors
- * (DVI connectors are particularly prone to this problem). */
- if (state->edid.read_retries) {
- state->edid.read_retries--;
- v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
- ad9389b_s_power(sd, false);
- ad9389b_s_power(sd, true);
- schedule_delayed_work(&state->edid_handler, EDID_DELAY);
- return;
- }
- }
-
- /* We failed to read the EDID, so send an event for this. */
- ed.present = false;
- ed.segment = ad9389b_rd(sd, 0xc4);
- v4l2_subdev_notify(sd, AD9389B_EDID_DETECT, (void *)&ed);
- v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
-}
-
-static void ad9389b_audio_setup(struct v4l2_subdev *sd)
-{
- v4l2_dbg(1, debug, sd, "%s\n", __func__);
-
- ad9389b_s_i2s_clock_freq(sd, 48000);
- ad9389b_s_clock_freq(sd, 48000);
- ad9389b_s_routing(sd, 0, 0, 0);
-}
-
-/* Initial setup of AD9389b */
-
-/* Configure hdmi transmitter. */
-static void ad9389b_setup(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- v4l2_dbg(1, debug, sd, "%s\n", __func__);
-
- /* Input format: RGB 4:4:4 */
- ad9389b_wr_and_or(sd, 0x15, 0xf1, 0x0);
- /* Output format: RGB 4:4:4 */
- ad9389b_wr_and_or(sd, 0x16, 0x3f, 0x0);
- /* 1st order interpolation 4:2:2 -> 4:4:4 up conversion,
- Aspect ratio: 16:9 */
- ad9389b_wr_and_or(sd, 0x17, 0xf9, 0x06);
- /* Output format: RGB 4:4:4, Active Format Information is valid. */
- ad9389b_wr_and_or(sd, 0x45, 0xc7, 0x08);
- /* Underscanned */
- ad9389b_wr_and_or(sd, 0x46, 0x3f, 0x80);
- /* Setup video format */
- ad9389b_wr(sd, 0x3c, 0x0);
- /* Active format aspect ratio: same as picure. */
- ad9389b_wr(sd, 0x47, 0x80);
- /* No encryption */
- ad9389b_wr_and_or(sd, 0xaf, 0xef, 0x0);
- /* Positive clk edge capture for input video clock */
- ad9389b_wr_and_or(sd, 0xba, 0x1f, 0x60);
-
- ad9389b_audio_setup(sd);
-
- v4l2_ctrl_handler_setup(&state->hdl);
-
- ad9389b_set_IT_content_AVI_InfoFrame(sd);
-}
-
-static void ad9389b_notify_monitor_detect(struct v4l2_subdev *sd)
-{
- struct ad9389b_monitor_detect mdt;
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- mdt.present = state->have_monitor;
- v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt);
-}
-
-static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- /* read hotplug and rx-sense state */
- u8 status = ad9389b_rd(sd, 0x42);
-
- v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
- __func__,
- status,
- status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
- status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
-
- if (status & MASK_AD9389B_HPD_DETECT) {
- v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
- state->have_monitor = true;
- if (!ad9389b_s_power(sd, true)) {
- v4l2_dbg(1, debug, sd,
- "%s: monitor detected, powerup failed\n", __func__);
- return;
- }
- ad9389b_setup(sd);
- ad9389b_notify_monitor_detect(sd);
- state->edid.read_retries = EDID_MAX_RETRIES;
- schedule_delayed_work(&state->edid_handler, EDID_DELAY);
- } else if (!(status & MASK_AD9389B_HPD_DETECT)) {
- v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
- state->have_monitor = false;
- ad9389b_notify_monitor_detect(sd);
- ad9389b_s_power(sd, false);
- memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
- }
-
- /* update read only ctrls */
- v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0);
- v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0);
- v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
-
- /* update with setting from ctrls */
- ad9389b_s_ctrl(state->rgb_quantization_range_ctrl);
- ad9389b_s_ctrl(state->hdmi_mode_ctrl);
-}
-
-static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- int retry = 0;
-
- ad9389b_update_monitor_present_status(sd);
-
- /*
- * Rapid toggling of the hotplug may leave the chip powered off,
- * even if we think it is on. In that case reset and power up again.
- */
- while (state->power_on && (ad9389b_rd(sd, 0x41) & 0x40)) {
- if (++retry > 5) {
- v4l2_err(sd, "retried %d times, give up\n", retry);
- return;
- }
- v4l2_dbg(1, debug, sd, "%s: reset and re-check status (%d)\n", __func__, retry);
- ad9389b_notify_monitor_detect(sd);
- cancel_delayed_work_sync(&state->edid_handler);
- memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
- ad9389b_s_power(sd, false);
- ad9389b_update_monitor_present_status(sd);
- }
-}
-
-static bool edid_block_verify_crc(u8 *edid_block)
-{
- u8 sum = 0;
- int i;
-
- for (i = 0; i < 128; i++)
- sum += edid_block[i];
- return sum == 0;
-}
-
-static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- u32 blocks = state->edid.blocks;
- u8 *data = state->edid.data;
-
- if (edid_block_verify_crc(&data[segment * 256])) {
- if ((segment + 1) * 2 <= blocks)
- return edid_block_verify_crc(&data[segment * 256 + 128]);
- return true;
- }
- return false;
-}
-
-static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
-{
- static const u8 hdmi_header[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
- };
- struct ad9389b_state *state = get_ad9389b_state(sd);
- u8 *data = state->edid.data;
- int i;
-
- if (segment)
- return true;
-
- for (i = 0; i < ARRAY_SIZE(hdmi_header); i++)
- if (data[i] != hdmi_header[i])
- return false;
-
- return true;
-}
-
-static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- struct ad9389b_edid_detect ed;
- int segment;
- u8 edidRdy = ad9389b_rd(sd, 0xc5);
-
- v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
- __func__, EDID_MAX_RETRIES - state->edid.read_retries);
-
- if (!(edidRdy & MASK_AD9389B_EDID_RDY))
- return false;
-
- segment = ad9389b_rd(sd, 0xc4);
- if (segment >= EDID_MAX_SEGM) {
- v4l2_err(sd, "edid segment number too big\n");
- return false;
- }
- v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
- ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]);
- ad9389b_dbg_dump_edid(2, debug, sd, segment,
- &state->edid.data[segment * 256]);
- if (segment == 0) {
- state->edid.blocks = state->edid.data[0x7e] + 1;
- v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n",
- __func__, state->edid.blocks);
- }
- if (!edid_verify_crc(sd, segment) ||
- !edid_verify_header(sd, segment)) {
- /* edid crc error, force reread of edid segment */
- v4l2_err(sd, "%s: edid crc or header error\n", __func__);
- ad9389b_s_power(sd, false);
- ad9389b_s_power(sd, true);
- return false;
- }
- /* one more segment read ok */
- state->edid.segments = segment + 1;
- if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
- /* Request next EDID segment */
- v4l2_dbg(1, debug, sd, "%s: request segment %d\n",
- __func__, state->edid.segments);
- ad9389b_wr(sd, 0xc9, 0xf);
- ad9389b_wr(sd, 0xc4, state->edid.segments);
- state->edid.read_retries = EDID_MAX_RETRIES;
- schedule_delayed_work(&state->edid_handler, EDID_DELAY);
- return false;
- }
-
- /* report when we have all segments but report only for segment 0 */
- ed.present = true;
- ed.segment = 0;
- v4l2_subdev_notify(sd, AD9389B_EDID_DETECT, (void *)&ed);
- state->edid_detect_counter++;
- v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
- return ed.present;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void ad9389b_init_setup(struct v4l2_subdev *sd)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
- struct ad9389b_state_edid *edid = &state->edid;
-
- v4l2_dbg(1, debug, sd, "%s\n", __func__);
-
- /* clear all interrupts */
- ad9389b_wr(sd, 0x96, 0xff);
-
- memset(edid, 0, sizeof(struct ad9389b_state_edid));
- state->have_monitor = false;
- ad9389b_set_isr(sd, false);
-}
-
-static int ad9389b_probe(struct i2c_client *client)
-{
- const struct v4l2_dv_timings dv1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
- struct ad9389b_state *state;
- struct ad9389b_platform_data *pdata = client->dev.platform_data;
- struct v4l2_ctrl_handler *hdl;
- struct v4l2_subdev *sd;
- int err = -EIO;
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
- v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
- client->addr << 1);
-
- state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
-
- /* Platform data */
- if (pdata == NULL) {
- v4l_err(client, "No platform data!\n");
- return -ENODEV;
- }
- memcpy(&state->pdata, pdata, sizeof(state->pdata));
-
- sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &ad9389b_ops);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- hdl = &state->hdl;
- v4l2_ctrl_handler_init(hdl, 5);
-
- state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
- V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
- 0, V4L2_DV_TX_MODE_DVI_D);
- state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0);
- state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0);
- state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0);
- state->rgb_quantization_range_ctrl =
- v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
- V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
- 0, V4L2_DV_RGB_RANGE_AUTO);
- sd->ctrl_handler = hdl;
- if (hdl->error) {
- err = hdl->error;
-
- goto err_hdl;
- }
- state->pad.flags = MEDIA_PAD_FL_SINK;
- sd->entity.function = MEDIA_ENT_F_DV_ENCODER;
- err = media_entity_pads_init(&sd->entity, 1, &state->pad);
- if (err)
- goto err_hdl;
-
- state->chip_revision = ad9389b_rd(sd, 0x0);
- if (state->chip_revision != 2) {
- v4l2_err(sd, "chip_revision %d != 2\n", state->chip_revision);
- err = -EIO;
- goto err_entity;
- }
- v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n",
- ad9389b_rd(sd, 0x41), state->chip_revision);
-
- state->edid_i2c_client = i2c_new_dummy_device(client->adapter, (0x7e >> 1));
- if (IS_ERR(state->edid_i2c_client)) {
- v4l2_err(sd, "failed to register edid i2c client\n");
- err = PTR_ERR(state->edid_i2c_client);
- goto err_entity;
- }
-
- INIT_DELAYED_WORK(&state->edid_handler, ad9389b_edid_handler);
- state->dv_timings = dv1080p60;
-
- ad9389b_init_setup(sd);
- ad9389b_set_isr(sd, true);
-
- v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
- client->addr << 1, client->adapter->name);
- return 0;
-
-err_entity:
- media_entity_cleanup(&sd->entity);
-err_hdl:
- v4l2_ctrl_handler_free(&state->hdl);
- return err;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void ad9389b_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- state->chip_revision = -1;
-
- v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
- client->addr << 1, client->adapter->name);
-
- ad9389b_s_stream(sd, false);
- ad9389b_s_audio_stream(sd, false);
- ad9389b_init_setup(sd);
- cancel_delayed_work_sync(&state->edid_handler);
- i2c_unregister_device(state->edid_i2c_client);
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id ad9389b_id[] = {
- { "ad9389b", 0 },
- { "ad9889b", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ad9389b_id);
-
-static struct i2c_driver ad9389b_driver = {
- .driver = {
- .name = "ad9389b",
- },
- .probe_new = ad9389b_probe,
- .remove = ad9389b_remove,
- .id_table = ad9389b_id,
-};
-
-module_i2c_driver(ad9389b_driver);
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index 52fa7bd75660..400d71c2745c 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -176,9 +176,9 @@ static int adv748x_hdmi_set_video_timings(struct adv748x_state *state,
unsigned int i;
for (i = 0; i < ARRAY_SIZE(adv748x_hdmi_video_standards); i++) {
- if (!v4l2_match_dv_timings(timings, &stds[i].timings, 250000,
- false))
- continue;
+ if (v4l2_match_dv_timings(timings, &stds[i].timings, 250000,
+ false))
+ break;
}
if (i >= ARRAY_SIZE(adv748x_hdmi_video_standards))
@@ -283,6 +283,16 @@ static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd,
memset(timings, 0, sizeof(struct v4l2_dv_timings));
+ /*
+ * If the pattern generator is enabled the device shall not be queried
+ * for timings. Instead the timings programmed shall be reported as they
+ * are the ones being used to generate the pattern.
+ */
+ if (cp_read(state, ADV748X_CP_PAT_GEN) & ADV748X_CP_PAT_GEN_EN) {
+ *timings = hdmi->timings;
+ return 0;
+ }
+
if (!adv748x_hdmi_has_signal(state))
return -ENOLINK;
@@ -721,11 +731,10 @@ static int adv748x_hdmi_init_controls(struct adv748x_hdmi *hdmi)
int adv748x_hdmi_init(struct adv748x_hdmi *hdmi)
{
struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
- static const struct v4l2_dv_timings cea1280x720 =
- V4L2_DV_BT_CEA_1280X720P30;
+ struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30;
int ret;
- hdmi->timings = cea1280x720;
+ adv748x_hdmi_s_dv_timings(&hdmi->sd, &cea1280x720);
/* Initialise a default 16:9 aspect ratio */
hdmi->aspect_ratio.numerator = 16;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 9d218962d7c8..3d0898c4175e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1805,6 +1805,9 @@ static void select_input(struct v4l2_subdev *sd)
v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
__func__, state->selected_input);
}
+
+ /* Enable video adjustment (contrast, saturation, brightness and hue) */
+ cp_write_clr_set(sd, 0x3e, 0x80, 0x80);
}
static int adv76xx_s_routing(struct v4l2_subdev *sd,
@@ -3545,7 +3548,7 @@ static int adv76xx_probe(struct i2c_client *client)
v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_SATURATION, 0, 255, 1, 128);
v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
- V4L2_CID_HUE, 0, 128, 1, 0);
+ V4L2_CID_HUE, 0, 255, 1, 0);
ctrl = v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops,
V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC,
0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index 4a14d7e5d9f2..559a415fd827 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -569,8 +569,6 @@ static u32 ccs_pixel_order(struct ccs_sensor *sensor)
flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP;
}
- flip ^= sensor->hvflip_inv_mask;
-
dev_dbg(&client->dev, "flip %u\n", flip);
return sensor->default_pixel_order ^ flip;
}
@@ -632,8 +630,6 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl)
if (sensor->vflip->val)
orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP;
- orient ^= sensor->hvflip_inv_mask;
-
ccs_update_mbus_formats(sensor);
break;
@@ -800,14 +796,24 @@ static const struct v4l2_ctrl_ops ccs_ctrl_ops = {
static int ccs_init_controls(struct ccs_sensor *sensor)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct v4l2_fwnode_device_properties props;
int rval;
- rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 17);
+ rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 19);
if (rval)
return rval;
sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
+ rval = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (rval)
+ return rval;
+
+ rval = v4l2_ctrl_new_fwnode_properties(&sensor->pixel_array->ctrl_handler,
+ &ccs_ctrl_ops, &props);
+ if (rval)
+ return rval;
+
switch (CCS_LIM(sensor, ANALOG_GAIN_CAPABILITY)) {
case CCS_ANALOG_GAIN_CAPABILITY_GLOBAL: {
struct {
@@ -2828,6 +2834,10 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_REVISION_NUMBER,
&minfo->sensor_revision_number);
+ if (!rval && !minfo->sensor_revision_number)
+ rval = ccs_read_addr_8only(sensor,
+ CCS_R_SENSOR_REVISION_NUMBER_16,
+ &minfo->sensor_revision_number);
if (!rval)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_FIRMWARE_VERSION,
@@ -2870,7 +2880,7 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
minfo->sensor_model_id);
dev_dbg(&client->dev,
- "sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+ "sensor revision 0x%4.4x firmware version 0x%2.2x\n",
minfo->sensor_revision_number, minfo->sensor_firmware_version);
if (minfo->ccs_version) {
@@ -2884,19 +2894,18 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
"smia version %2.2d smiapp version %2.2d\n",
minfo->smia_version, minfo->smiapp_version);
minfo->name = SMIAPP_NAME;
- }
-
- /*
- * Some modules have bad data in the lvalues below. Hope the
- * rvalues have better stuff. The lvalues are module
- * parameters whereas the rvalues are sensor parameters.
- */
- if (minfo->sensor_smia_manufacturer_id &&
- !minfo->smia_manufacturer_id && !minfo->model_id) {
- minfo->smia_manufacturer_id =
- minfo->sensor_smia_manufacturer_id;
- minfo->model_id = minfo->sensor_model_id;
- minfo->revision_number = minfo->sensor_revision_number;
+ /*
+ * Some modules have bad data in the lvalues below. Hope the
+ * rvalues have better stuff. The lvalues are module
+ * parameters whereas the rvalues are sensor parameters.
+ */
+ if (minfo->sensor_smia_manufacturer_id &&
+ !minfo->smia_manufacturer_id && !minfo->model_id) {
+ minfo->smia_manufacturer_id =
+ minfo->sensor_smia_manufacturer_id;
+ minfo->model_id = minfo->sensor_model_id;
+ minfo->revision_number = minfo->sensor_revision_number;
+ }
}
for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) {
@@ -3185,7 +3194,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_UNKNOWN };
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
- u32 rotation;
unsigned int i;
int rval;
@@ -3224,22 +3232,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
goto out_err;
}
- rval = fwnode_property_read_u32(fwnode, "rotation", &rotation);
- if (!rval) {
- switch (rotation) {
- case 180:
- hwcfg->module_board_orient =
- CCS_MODULE_BOARD_ORIENT_180;
- fallthrough;
- case 0:
- break;
- default:
- dev_err(dev, "invalid rotation %u\n", rotation);
- rval = -EINVAL;
- goto out_err;
- }
- }
-
rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
&hwcfg->ext_clk);
if (rval)
@@ -3279,8 +3271,47 @@ out_err:
return rval;
}
+static int ccs_firmware_name(struct i2c_client *client,
+ struct ccs_sensor *sensor, char *filename,
+ size_t filename_size, bool is_module)
+{
+ const struct ccs_device *ccsdev = device_get_match_data(&client->dev);
+ bool is_ccs = !(ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA);
+ bool is_smiapp = sensor->minfo.smiapp_version;
+ u16 manufacturer_id;
+ u16 model_id;
+ u16 revision_number;
+
+ /*
+ * Old SMIA is module-agnostic. Its sensor identification is based on
+ * what now are those of the module.
+ */
+ if (is_module || (!is_ccs && !is_smiapp)) {
+ manufacturer_id = is_ccs ?
+ sensor->minfo.mipi_manufacturer_id :
+ sensor->minfo.smia_manufacturer_id;
+ model_id = sensor->minfo.model_id;
+ revision_number = sensor->minfo.revision_number;
+ } else {
+ manufacturer_id = is_ccs ?
+ sensor->minfo.sensor_mipi_manufacturer_id :
+ sensor->minfo.sensor_smia_manufacturer_id;
+ model_id = sensor->minfo.sensor_model_id;
+ revision_number = sensor->minfo.sensor_revision_number;
+ }
+
+ return snprintf(filename, filename_size,
+ "ccs/%s-%s-%0*x-%4.4x-%0*x.fw",
+ is_ccs ? "ccs" : is_smiapp ? "smiapp" : "smia",
+ is_module || (!is_ccs && !is_smiapp) ?
+ "module" : "sensor",
+ is_ccs ? 4 : 2, manufacturer_id, model_id,
+ !is_ccs && !is_module ? 2 : 4, revision_number);
+}
+
static int ccs_probe(struct i2c_client *client)
{
+ const struct ccs_device *ccsdev = device_get_match_data(&client->dev);
struct ccs_sensor *sensor;
const struct firmware *fw;
char filename[40];
@@ -3389,11 +3420,8 @@ static int ccs_probe(struct i2c_client *client)
goto out_power_off;
}
- rval = snprintf(filename, sizeof(filename),
- "ccs/ccs-sensor-%4.4x-%4.4x-%4.4x.fw",
- sensor->minfo.sensor_mipi_manufacturer_id,
- sensor->minfo.sensor_model_id,
- sensor->minfo.sensor_revision_number);
+ rval = ccs_firmware_name(client, sensor, filename, sizeof(filename),
+ false);
if (rval >= sizeof(filename)) {
rval = -ENOMEM;
goto out_power_off;
@@ -3406,21 +3434,21 @@ static int ccs_probe(struct i2c_client *client)
release_firmware(fw);
}
- rval = snprintf(filename, sizeof(filename),
- "ccs/ccs-module-%4.4x-%4.4x-%4.4x.fw",
- sensor->minfo.mipi_manufacturer_id,
- sensor->minfo.model_id,
- sensor->minfo.revision_number);
- if (rval >= sizeof(filename)) {
- rval = -ENOMEM;
- goto out_release_sdata;
- }
+ if (!(ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA) ||
+ sensor->minfo.smiapp_version) {
+ rval = ccs_firmware_name(client, sensor, filename,
+ sizeof(filename), true);
+ if (rval >= sizeof(filename)) {
+ rval = -ENOMEM;
+ goto out_release_sdata;
+ }
- rval = request_firmware(&fw, filename, &client->dev);
- if (!rval) {
- ccs_data_parse(&sensor->mdata, fw->data, fw->size, &client->dev,
- true);
- release_firmware(fw);
+ rval = request_firmware(&fw, filename, &client->dev);
+ if (!rval) {
+ ccs_data_parse(&sensor->mdata, fw->data, fw->size,
+ &client->dev, true);
+ release_firmware(fw);
+ }
}
rval = ccs_read_all_limits(sensor);
@@ -3437,25 +3465,6 @@ static int ccs_probe(struct i2c_client *client)
if (rval < 0)
goto out_free_ccs_limits;
- /*
- * Handle Sensor Module orientation on the board.
- *
- * The application of H-FLIP and V-FLIP on the sensor is modified by
- * the sensor orientation on the board.
- *
- * For CCS_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
- * both H-FLIP and V-FLIP for normal operation which also implies
- * that a set/unset operation for user space HFLIP and VFLIP v4l2
- * controls will need to be internally inverted.
- *
- * Rotation also changes the bayer pattern.
- */
- if (sensor->hwcfg.module_board_orient ==
- CCS_MODULE_BOARD_ORIENT_180)
- sensor->hvflip_inv_mask =
- CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR |
- CCS_IMAGE_ORIENTATION_VERTICAL_FLIP;
-
rval = ccs_call_quirk(sensor, limits);
if (rval) {
dev_err(&client->dev, "limits quirks failed\n");
diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h
index 6beac375cc48..a94c796cea48 100644
--- a/drivers/media/i2c/ccs/ccs.h
+++ b/drivers/media/i2c/ccs/ccs.h
@@ -57,17 +57,6 @@
#define CCS_LIM_AT(sensor, limit, offset) \
ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset))
-/*
- * Sometimes due to board layout considerations the camera module can be
- * mounted rotated. The typical rotation used is 180 degrees which can be
- * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
- * FIXME: rotation also changes the bayer pattern.
- */
-enum ccs_module_board_orient {
- CCS_MODULE_BOARD_ORIENT_0 = 0,
- CCS_MODULE_BOARD_ORIENT_180,
-};
-
struct ccs_flash_strobe_parms {
u8 mode;
u32 strobe_width_high_us;
@@ -90,8 +79,6 @@ struct ccs_hwconfig {
u32 csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */
u64 *op_sys_clock;
- enum ccs_module_board_orient module_board_orient;
-
struct ccs_flash_strobe_parms *strobe_setup;
};
@@ -243,7 +230,6 @@ struct ccs_sensor {
u8 scale_m;
u8 scaling_mode;
- u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
u8 frame_skip;
u16 embedded_start; /* embedded data start line */
u16 embedded_end;
diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c
index e422ac7609b5..7daefab35cf0 100644
--- a/drivers/media/i2c/hi556.c
+++ b/drivers/media/i2c/hi556.c
@@ -63,6 +63,14 @@
#define HI556_REG_ISP_TPG_EN 0x01
#define HI556_REG_TEST_PATTERN 0x0201
+/* HI556 native and active pixel array size. */
+#define HI556_NATIVE_WIDTH 2592U
+#define HI556_NATIVE_HEIGHT 1944U
+#define HI556_PIXEL_ARRAY_LEFT 0U
+#define HI556_PIXEL_ARRAY_TOP 0U
+#define HI556_PIXEL_ARRAY_WIDTH 2592U
+#define HI556_PIXEL_ARRAY_HEIGHT 1944U
+
enum {
HI556_LINK_FREQ_437MHZ_INDEX,
};
@@ -88,6 +96,9 @@ struct hi556_mode {
/* Frame height in pixels */
u32 height;
+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+
/* Horizontal timining size */
u32 llp;
@@ -378,6 +389,49 @@ static const struct hi556_reg mode_2592x1944_regs[] = {
{0x0958, 0xbb80},
};
+static const struct hi556_reg mode_2592x1444_regs[] = {
+ {0x0a00, 0x0000},
+ {0x0b0a, 0x8252},
+ {0x0f30, 0xe545},
+ {0x0f32, 0x7067},
+ {0x004a, 0x0100},
+ {0x004c, 0x0000},
+ {0x000c, 0x0022},
+ {0x0008, 0x0b00},
+ {0x005a, 0x0202},
+ {0x0012, 0x000e},
+ {0x0018, 0x0a33},
+ {0x0022, 0x0008},
+ {0x0028, 0x0017},
+ {0x0024, 0x0122},
+ {0x002a, 0x0127},
+ {0x0026, 0x012a},
+ {0x002c, 0x06cf},
+ {0x002e, 0x1111},
+ {0x0030, 0x1111},
+ {0x0032, 0x1111},
+ {0x0006, 0x0821},
+ {0x0a22, 0x0000},
+ {0x0a12, 0x0a20},
+ {0x0a14, 0x05a4},
+ {0x003e, 0x0000},
+ {0x0074, 0x081f},
+ {0x0070, 0x040f},
+ {0x0804, 0x0300},
+ {0x0806, 0x0100},
+ {0x0a04, 0x014a},
+ {0x090c, 0x0fdc},
+ {0x090e, 0x002d},
+ {0x0902, 0x4319},
+ {0x0914, 0xc10a},
+ {0x0916, 0x071f},
+ {0x0918, 0x0408},
+ {0x091a, 0x0c0d},
+ {0x091c, 0x0f09},
+ {0x091e, 0x0a00},
+ {0x0958, 0xbb80},
+};
+
static const struct hi556_reg mode_1296x972_regs[] = {
{0x0a00, 0x0000},
{0x0b0a, 0x8259},
@@ -450,8 +504,14 @@ static const struct hi556_link_freq_config link_freq_configs[] = {
static const struct hi556_mode supported_modes[] = {
{
- .width = 2592,
- .height = 1944,
+ .width = HI556_PIXEL_ARRAY_WIDTH,
+ .height = HI556_PIXEL_ARRAY_HEIGHT,
+ .crop = {
+ .left = HI556_PIXEL_ARRAY_LEFT,
+ .top = HI556_PIXEL_ARRAY_TOP,
+ .width = HI556_PIXEL_ARRAY_WIDTH,
+ .height = HI556_PIXEL_ARRAY_HEIGHT
+ },
.fll_def = HI556_FLL_30FPS,
.fll_min = HI556_FLL_30FPS_MIN,
.llp = 0x0b00,
@@ -462,8 +522,32 @@ static const struct hi556_mode supported_modes[] = {
.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
},
{
+ .width = HI556_PIXEL_ARRAY_WIDTH,
+ .height = 1444,
+ .crop = {
+ .left = HI556_PIXEL_ARRAY_LEFT,
+ .top = 250,
+ .width = HI556_PIXEL_ARRAY_WIDTH,
+ .height = 1444
+ },
+ .fll_def = 0x821,
+ .fll_min = 0x821,
+ .llp = 0x0b00,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_2592x1444_regs),
+ .regs = mode_2592x1444_regs,
+ },
+ .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
+ },
+ {
.width = 1296,
.height = 972,
+ .crop = {
+ .left = HI556_PIXEL_ARRAY_LEFT,
+ .top = HI556_PIXEL_ARRAY_TOP,
+ .width = HI556_PIXEL_ARRAY_WIDTH,
+ .height = HI556_PIXEL_ARRAY_HEIGHT
+ },
.fll_def = HI556_FLL_30FPS,
.fll_min = HI556_FLL_30FPS_MIN,
.llp = 0x0b00,
@@ -785,6 +869,58 @@ static int hi556_identify_module(struct hi556 *hi556)
return 0;
}
+static const struct v4l2_rect *
+__hi556_get_pad_crop(struct hi556 *hi556,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &hi556->cur_mode->crop;
+ }
+
+ return NULL;
+}
+
+static int hi556_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct hi556 *hi556 = to_hi556(sd);
+
+ mutex_lock(&hi556->mutex);
+ sel->r = *__hi556_get_pad_crop(hi556, sd_state, sel->pad,
+ sel->which);
+ mutex_unlock(&hi556->mutex);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = HI556_NATIVE_WIDTH;
+ sel->r.height = HI556_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = HI556_PIXEL_ARRAY_TOP;
+ sel->r.left = HI556_PIXEL_ARRAY_LEFT;
+ sel->r.width = HI556_PIXEL_ARRAY_WIDTH;
+ sel->r.height = HI556_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int hi556_start_streaming(struct hi556 *hi556)
{
struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
@@ -1000,10 +1136,19 @@ static int hi556_enum_frame_size(struct v4l2_subdev *sd,
static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct hi556 *hi556 = to_hi556(sd);
+ struct v4l2_rect *try_crop;
mutex_lock(&hi556->mutex);
hi556_assign_pad_format(&supported_modes[0],
v4l2_subdev_get_try_format(sd, fh->state, 0));
+
+ /* Initialize try_crop rectangle. */
+ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
+ try_crop->top = HI556_PIXEL_ARRAY_TOP;
+ try_crop->left = HI556_PIXEL_ARRAY_LEFT;
+ try_crop->width = HI556_PIXEL_ARRAY_WIDTH;
+ try_crop->height = HI556_PIXEL_ARRAY_HEIGHT;
+
mutex_unlock(&hi556->mutex);
return 0;
@@ -1016,6 +1161,7 @@ static const struct v4l2_subdev_video_ops hi556_video_ops = {
static const struct v4l2_subdev_pad_ops hi556_pad_ops = {
.set_fmt = hi556_set_format,
.get_fmt = hi556_get_format,
+ .get_selection = hi556_get_selection,
.enum_mbus_code = hi556_enum_mbus_code,
.enum_frame_size = hi556_enum_frame_size,
};
diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c
index 7c61873b7198..306dc35e925f 100644
--- a/drivers/media/i2c/hi846.c
+++ b/drivers/media/i2c/hi846.c
@@ -1472,21 +1472,26 @@ static int hi846_init_controls(struct hi846 *hi846)
if (ctrl_hdlr->error) {
dev_err(&client->dev, "v4l ctrl handler error: %d\n",
ctrl_hdlr->error);
- return ctrl_hdlr->error;
+ ret = ctrl_hdlr->error;
+ goto error;
}
ret = v4l2_fwnode_device_parse(&client->dev, &props);
if (ret)
- return ret;
+ goto error;
ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &hi846_ctrl_ops,
&props);
if (ret)
- return ret;
+ goto error;
hi846->sd.ctrl_handler = ctrl_hdlr;
return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ return ret;
}
static int hi846_set_video_mode(struct hi846 *hi846, int fps)
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index eab5fc1ee2f7..85d73b186111 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -9,6 +9,7 @@
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <asm/unaligned.h>
#define IMX258_REG_VALUE_08BIT 1
@@ -1148,7 +1149,9 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = {
static int imx258_init_controls(struct imx258 *imx258)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
+ struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
+ struct v4l2_ctrl *vflip, *hflip;
s64 vblank_def;
s64 vblank_min;
s64 pixel_rate_min;
@@ -1156,7 +1159,7 @@ static int imx258_init_controls(struct imx258 *imx258)
int ret;
ctrl_hdlr = &imx258->ctrl_handler;
- ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 13);
if (ret)
return ret;
@@ -1172,6 +1175,17 @@ static int imx258_init_controls(struct imx258 *imx258)
if (imx258->link_freq)
imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ /* The driver only supports one bayer order and flips by default. */
+ hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_HFLIP, 1, 1, 1, 1);
+ if (hflip)
+ hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_VFLIP, 1, 1, 1, 1);
+ if (vflip)
+ vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
/* By default, PIXEL_RATE is read only */
@@ -1232,6 +1246,15 @@ static int imx258_init_controls(struct imx258 *imx258)
goto error;
}
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx258_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
+
imx258->sd.ctrl_handler = ctrl_hdlr;
return 0;
@@ -1276,14 +1299,6 @@ static int imx258_probe(struct i2c_client *client)
return -EINVAL;
}
- /*
- * Check that the device is mounted upside down. The driver only
- * supports a single pixel order right now.
- */
- ret = device_property_read_u32(&client->dev, "rotation", &val);
- if (ret || val != 180)
- return -EINVAL;
-
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 49d6c8bdec41..5ea25b7acc55 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -13,12 +13,17 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+
+#include <asm/unaligned.h>
+
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
@@ -44,7 +49,9 @@
#define IMX290_BLKLEVEL IMX290_REG_16BIT(0x300a)
#define IMX290_GAIN IMX290_REG_8BIT(0x3014)
#define IMX290_VMAX IMX290_REG_24BIT(0x3018)
+#define IMX290_VMAX_MAX 0x3ffff
#define IMX290_HMAX IMX290_REG_16BIT(0x301c)
+#define IMX290_HMAX_MAX 0xffff
#define IMX290_SHS1 IMX290_REG_24BIT(0x3020)
#define IMX290_WINWV_OB IMX290_REG_8BIT(0x303a)
#define IMX290_WINPV IMX290_REG_16BIT(0x303c)
@@ -98,13 +105,16 @@
#define IMX290_TCLKPREPARE IMX290_REG_16BIT(0x3452)
#define IMX290_TLPX IMX290_REG_16BIT(0x3454)
#define IMX290_X_OUT_SIZE IMX290_REG_16BIT(0x3472)
+#define IMX290_INCKSEL7 IMX290_REG_8BIT(0x3480)
#define IMX290_PGCTRL_REGEN BIT(0)
#define IMX290_PGCTRL_THRU BIT(1)
#define IMX290_PGCTRL_MODE(n) ((n) << 4)
-#define IMX290_VMAX_DEFAULT 1125
+/* Number of lines by which exposure must be less than VMAX */
+#define IMX290_EXPOSURE_OFFSET 2
+#define IMX290_PIXEL_RATE 148500000
/*
* The IMX290 pixel array is organized as follows:
@@ -157,26 +167,81 @@
#define IMX290_NUM_SUPPLIES 3
+enum imx290_colour_variant {
+ IMX290_VARIANT_COLOUR,
+ IMX290_VARIANT_MONO,
+ IMX290_VARIANT_MAX
+};
+
+enum imx290_model {
+ IMX290_MODEL_IMX290LQR,
+ IMX290_MODEL_IMX290LLR,
+ IMX290_MODEL_IMX327LQR,
+};
+
+struct imx290_model_info {
+ enum imx290_colour_variant colour_variant;
+ const struct imx290_regval *init_regs;
+ size_t init_regs_num;
+ const char *name;
+};
+
+enum imx290_clk_freq {
+ IMX290_CLK_37_125,
+ IMX290_CLK_74_25,
+ IMX290_NUM_CLK
+};
+
struct imx290_regval {
u32 reg;
u32 val;
};
+/*
+ * Clock configuration for registers INCKSEL1 to INCKSEL6.
+ */
+struct imx290_clk_cfg {
+ u8 incksel1;
+ u8 incksel2;
+ u8 incksel3;
+ u8 incksel4;
+ u8 incksel5;
+ u8 incksel6;
+};
+
struct imx290_mode {
u32 width;
u32 height;
- u32 hmax;
+ u32 hmax_min;
+ u32 vmax_min;
u8 link_freq_index;
+ u8 ctrl_07;
const struct imx290_regval *data;
u32 data_size;
+
+ const struct imx290_clk_cfg *clk_cfg;
+};
+
+struct imx290_csi_cfg {
+ u16 repetition;
+ u16 tclkpost;
+ u16 thszero;
+ u16 thsprepare;
+ u16 tclktrail;
+ u16 thstrail;
+ u16 tclkzero;
+ u16 tclkprepare;
+ u16 tlpx;
};
struct imx290 {
struct device *dev;
struct clk *xclk;
struct regmap *regmap;
+ enum imx290_clk_freq xclk_idx;
u8 nlanes;
+ const struct imx290_model_info *model;
struct v4l2_subdev sd;
struct media_pad pad;
@@ -188,9 +253,13 @@ struct imx290 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_freq;
- struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *exposure;
+ struct {
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
};
static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
@@ -203,9 +272,6 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
*/
static const struct imx290_regval imx290_global_init_settings[] = {
- { IMX290_CTRL_07, IMX290_WINMODE_1080P },
- { IMX290_VMAX, IMX290_VMAX_DEFAULT },
- { IMX290_EXTCK_FREQ, 0x2520 },
{ IMX290_WINWV_OB, 12 },
{ IMX290_WINPH, 0 },
{ IMX290_WINPV, 0 },
@@ -213,10 +279,14 @@ static const struct imx290_regval imx290_global_init_settings[] = {
{ IMX290_WINWV, 1097 },
{ IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC |
IMX290_XSOUTSEL_XHSOUTSEL_HSYNC },
- { IMX290_REG_8BIT(0x300f), 0x00 },
- { IMX290_REG_8BIT(0x3010), 0x21 },
+ { IMX290_REG_8BIT(0x3011), 0x02 },
{ IMX290_REG_8BIT(0x3012), 0x64 },
{ IMX290_REG_8BIT(0x3013), 0x00 },
+};
+
+static const struct imx290_regval imx290_global_init_settings_290[] = {
+ { IMX290_REG_8BIT(0x300f), 0x00 },
+ { IMX290_REG_8BIT(0x3010), 0x21 },
{ IMX290_REG_8BIT(0x3016), 0x09 },
{ IMX290_REG_8BIT(0x3070), 0x02 },
{ IMX290_REG_8BIT(0x3071), 0x11 },
@@ -255,57 +325,40 @@ static const struct imx290_regval imx290_global_init_settings[] = {
{ IMX290_REG_8BIT(0x33b0), 0x50 },
{ IMX290_REG_8BIT(0x33b2), 0x1a },
{ IMX290_REG_8BIT(0x33b3), 0x04 },
- { IMX290_REG_8BIT(0x3480), 0x49 },
+};
+
+#define IMX290_NUM_CLK_REGS 2
+static const struct imx290_regval xclk_regs[][IMX290_NUM_CLK_REGS] = {
+ [IMX290_CLK_37_125] = {
+ { IMX290_EXTCK_FREQ, (37125 * 256) / 1000 },
+ { IMX290_INCKSEL7, 0x49 },
+ },
+ [IMX290_CLK_74_25] = {
+ { IMX290_EXTCK_FREQ, (74250 * 256) / 1000 },
+ { IMX290_INCKSEL7, 0x92 },
+ },
+};
+
+static const struct imx290_regval imx290_global_init_settings_327[] = {
+ { IMX290_REG_8BIT(0x309e), 0x4A },
+ { IMX290_REG_8BIT(0x309f), 0x4A },
+ { IMX290_REG_8BIT(0x313b), 0x61 },
};
static const struct imx290_regval imx290_1080p_settings[] = {
/* mode settings */
- { IMX290_CTRL_07, IMX290_WINMODE_1080P },
{ IMX290_WINWV_OB, 12 },
{ IMX290_OPB_SIZE_V, 10 },
{ IMX290_X_OUT_SIZE, 1920 },
{ IMX290_Y_OUT_SIZE, 1080 },
- { IMX290_INCKSEL1, 0x18 },
- { IMX290_INCKSEL2, 0x03 },
- { IMX290_INCKSEL3, 0x20 },
- { IMX290_INCKSEL4, 0x01 },
- { IMX290_INCKSEL5, 0x1a },
- { IMX290_INCKSEL6, 0x1a },
- /* data rate settings */
- { IMX290_REPETITION, 0x10 },
- { IMX290_TCLKPOST, 87 },
- { IMX290_THSZERO, 55 },
- { IMX290_THSPREPARE, 31 },
- { IMX290_TCLKTRAIL, 31 },
- { IMX290_THSTRAIL, 31 },
- { IMX290_TCLKZERO, 119 },
- { IMX290_TCLKPREPARE, 31 },
- { IMX290_TLPX, 23 },
};
static const struct imx290_regval imx290_720p_settings[] = {
/* mode settings */
- { IMX290_CTRL_07, IMX290_WINMODE_720P },
{ IMX290_WINWV_OB, 6 },
{ IMX290_OPB_SIZE_V, 4 },
{ IMX290_X_OUT_SIZE, 1280 },
{ IMX290_Y_OUT_SIZE, 720 },
- { IMX290_INCKSEL1, 0x20 },
- { IMX290_INCKSEL2, 0x00 },
- { IMX290_INCKSEL3, 0x20 },
- { IMX290_INCKSEL4, 0x01 },
- { IMX290_INCKSEL5, 0x1a },
- { IMX290_INCKSEL6, 0x1a },
- /* data rate settings */
- { IMX290_REPETITION, 0x10 },
- { IMX290_TCLKPOST, 79 },
- { IMX290_THSZERO, 47 },
- { IMX290_THSPREPARE, 23 },
- { IMX290_TCLKTRAIL, 23 },
- { IMX290_THSTRAIL, 23 },
- { IMX290_TCLKZERO, 87 },
- { IMX290_TCLKPREPARE, 23 },
- { IMX290_TLPX, 23 },
};
static const struct imx290_regval imx290_10bit_settings[] = {
@@ -326,6 +379,58 @@ static const struct imx290_regval imx290_12bit_settings[] = {
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 },
};
+static const struct imx290_csi_cfg imx290_csi_222_75mhz = {
+ /* 222.75MHz or 445.5Mbit/s per lane */
+ .repetition = 0x10,
+ .tclkpost = 87,
+ .thszero = 55,
+ .thsprepare = 31,
+ .tclktrail = 31,
+ .thstrail = 31,
+ .tclkzero = 119,
+ .tclkprepare = 31,
+ .tlpx = 23,
+};
+
+static const struct imx290_csi_cfg imx290_csi_445_5mhz = {
+ /* 445.5MHz or 891Mbit/s per lane */
+ .repetition = 0x00,
+ .tclkpost = 119,
+ .thszero = 103,
+ .thsprepare = 71,
+ .tclktrail = 55,
+ .thstrail = 63,
+ .tclkzero = 255,
+ .tclkprepare = 63,
+ .tlpx = 55,
+};
+
+static const struct imx290_csi_cfg imx290_csi_148_5mhz = {
+ /* 148.5MHz or 297Mbit/s per lane */
+ .repetition = 0x10,
+ .tclkpost = 79,
+ .thszero = 47,
+ .thsprepare = 23,
+ .tclktrail = 23,
+ .thstrail = 23,
+ .tclkzero = 87,
+ .tclkprepare = 23,
+ .tlpx = 23,
+};
+
+static const struct imx290_csi_cfg imx290_csi_297mhz = {
+ /* 297MHz or 594Mbit/s per lane */
+ .repetition = 0x00,
+ .tclkpost = 103,
+ .thszero = 87,
+ .thsprepare = 47,
+ .tclktrail = 39,
+ .thstrail = 47,
+ .tclkzero = 191,
+ .tclkprepare = 47,
+ .tlpx = 39,
+};
+
/* supported link frequencies */
#define FREQ_INDEX_1080P 0
#define FREQ_INDEX_720P 1
@@ -333,6 +438,7 @@ static const s64 imx290_link_freq_2lanes[] = {
[FREQ_INDEX_1080P] = 445500000,
[FREQ_INDEX_720P] = 297000000,
};
+
static const s64 imx290_link_freq_4lanes[] = {
[FREQ_INDEX_1080P] = 222750000,
[FREQ_INDEX_720P] = 148500000,
@@ -358,23 +464,71 @@ static inline int imx290_link_freqs_num(const struct imx290 *imx290)
return ARRAY_SIZE(imx290_link_freq_4lanes);
}
+static const struct imx290_clk_cfg imx290_1080p_clock_config[] = {
+ [IMX290_CLK_37_125] = {
+ /* 37.125MHz clock config */
+ .incksel1 = 0x18,
+ .incksel2 = 0x03,
+ .incksel3 = 0x20,
+ .incksel4 = 0x01,
+ .incksel5 = 0x1a,
+ .incksel6 = 0x1a,
+ },
+ [IMX290_CLK_74_25] = {
+ /* 74.25MHz clock config */
+ .incksel1 = 0x0c,
+ .incksel2 = 0x03,
+ .incksel3 = 0x10,
+ .incksel4 = 0x01,
+ .incksel5 = 0x1b,
+ .incksel6 = 0x1b,
+ },
+};
+
+static const struct imx290_clk_cfg imx290_720p_clock_config[] = {
+ [IMX290_CLK_37_125] = {
+ /* 37.125MHz clock config */
+ .incksel1 = 0x20,
+ .incksel2 = 0x00,
+ .incksel3 = 0x20,
+ .incksel4 = 0x01,
+ .incksel5 = 0x1a,
+ .incksel6 = 0x1a,
+ },
+ [IMX290_CLK_74_25] = {
+ /* 74.25MHz clock config */
+ .incksel1 = 0x10,
+ .incksel2 = 0x00,
+ .incksel3 = 0x10,
+ .incksel4 = 0x01,
+ .incksel5 = 0x1b,
+ .incksel6 = 0x1b,
+ },
+};
+
/* Mode configs */
static const struct imx290_mode imx290_modes_2lanes[] = {
{
.width = 1920,
.height = 1080,
- .hmax = 4400,
+ .hmax_min = 2200,
+ .vmax_min = 1125,
.link_freq_index = FREQ_INDEX_1080P,
+ .ctrl_07 = IMX290_WINMODE_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
+ .clk_cfg = imx290_1080p_clock_config,
},
{
.width = 1280,
.height = 720,
- .hmax = 6600,
+ .hmax_min = 3300,
+ .vmax_min = 750,
.link_freq_index = FREQ_INDEX_720P,
+ .ctrl_07 = IMX290_WINMODE_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
+ .clk_cfg = imx290_720p_clock_config,
},
};
@@ -382,18 +536,24 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
{
.width = 1920,
.height = 1080,
- .hmax = 2200,
+ .hmax_min = 2200,
+ .vmax_min = 1125,
.link_freq_index = FREQ_INDEX_1080P,
+ .ctrl_07 = IMX290_WINMODE_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
+ .clk_cfg = imx290_1080p_clock_config,
},
{
.width = 1280,
.height = 720,
- .hmax = 3300,
+ .hmax_min = 3300,
+ .vmax_min = 750,
.link_freq_index = FREQ_INDEX_720P,
+ .ctrl_07 = IMX290_WINMODE_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
+ .clk_cfg = imx290_720p_clock_config,
},
};
@@ -414,7 +574,7 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
}
struct imx290_format_info {
- u32 code;
+ u32 code[IMX290_VARIANT_MAX];
u8 bpp;
const struct imx290_regval *regs;
unsigned int num_regs;
@@ -422,26 +582,33 @@ struct imx290_format_info {
static const struct imx290_format_info imx290_formats[] = {
{
- .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .code = {
+ [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB10_1X10,
+ [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y10_1X10
+ },
.bpp = 10,
.regs = imx290_10bit_settings,
.num_regs = ARRAY_SIZE(imx290_10bit_settings),
}, {
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .code = {
+ [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB12_1X12,
+ [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y12_1X12
+ },
.bpp = 12,
.regs = imx290_12bit_settings,
.num_regs = ARRAY_SIZE(imx290_12bit_settings),
}
};
-static const struct imx290_format_info *imx290_format_info(u32 code)
+static const struct imx290_format_info *
+imx290_format_info(const struct imx290 *imx290, u32 code)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) {
const struct imx290_format_info *info = &imx290_formats[i];
- if (info->code == code)
+ if (info->code[imx290->model->colour_variant] == code)
return info;
}
@@ -461,28 +628,30 @@ static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *val
data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
if (ret < 0) {
dev_err(imx290->dev, "%u-bit read from 0x%04x failed: %d\n",
- ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
+ ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
addr & IMX290_REG_ADDR_MASK, ret);
return ret;
}
- *value = (data[2] << 16) | (data[1] << 8) | data[0];
+ *value = get_unaligned_le24(data);
return 0;
}
static int imx290_write(struct imx290 *imx290, u32 addr, u32 value, int *err)
{
- u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
+ u8 data[3];
int ret;
if (err && *err)
return *err;
+ put_unaligned_le24(value, data);
+
ret = regmap_raw_write(imx290->regmap, addr & IMX290_REG_ADDR_MASK,
data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
if (ret < 0) {
dev_err(imx290->dev, "%u-bit write to 0x%04x failed: %d\n",
- ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
+ ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
addr & IMX290_REG_ADDR_MASK, ret);
if (err)
*err = ret;
@@ -510,24 +679,33 @@ static int imx290_set_register_array(struct imx290 *imx290,
return 0;
}
+static int imx290_set_clock(struct imx290 *imx290)
+{
+ const struct imx290_mode *mode = imx290->current_mode;
+ enum imx290_clk_freq clk_idx = imx290->xclk_idx;
+ const struct imx290_clk_cfg *clk_cfg = &mode->clk_cfg[clk_idx];
+ int ret;
+
+ ret = imx290_set_register_array(imx290, xclk_regs[clk_idx],
+ IMX290_NUM_CLK_REGS);
+
+ imx290_write(imx290, IMX290_INCKSEL1, clk_cfg->incksel1, &ret);
+ imx290_write(imx290, IMX290_INCKSEL2, clk_cfg->incksel2, &ret);
+ imx290_write(imx290, IMX290_INCKSEL3, clk_cfg->incksel3, &ret);
+ imx290_write(imx290, IMX290_INCKSEL4, clk_cfg->incksel4, &ret);
+ imx290_write(imx290, IMX290_INCKSEL5, clk_cfg->incksel5, &ret);
+ imx290_write(imx290, IMX290_INCKSEL6, clk_cfg->incksel6, &ret);
+
+ return ret;
+}
+
static int imx290_set_data_lanes(struct imx290 *imx290)
{
int ret = 0;
- u32 frsel;
-
- switch (imx290->nlanes) {
- case 2:
- default:
- frsel = 0x02;
- break;
- case 4:
- frsel = 0x01;
- break;
- }
imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret);
imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret);
- imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
+ imx290_write(imx290, IMX290_FR_FDG_SEL, 0x01, &ret);
return ret;
}
@@ -536,19 +714,55 @@ static int imx290_set_black_level(struct imx290 *imx290,
const struct v4l2_mbus_framefmt *format,
unsigned int black_level, int *err)
{
- unsigned int bpp = imx290_format_info(format->code)->bpp;
+ unsigned int bpp = imx290_format_info(imx290, format->code)->bpp;
return imx290_write(imx290, IMX290_BLKLEVEL,
black_level >> (16 - bpp), err);
}
+static int imx290_set_csi_config(struct imx290 *imx290)
+{
+ const s64 *link_freqs = imx290_link_freqs_ptr(imx290);
+ const struct imx290_csi_cfg *csi_cfg;
+ int ret = 0;
+
+ switch (link_freqs[imx290->current_mode->link_freq_index]) {
+ case 445500000:
+ csi_cfg = &imx290_csi_445_5mhz;
+ break;
+ case 297000000:
+ csi_cfg = &imx290_csi_297mhz;
+ break;
+ case 222750000:
+ csi_cfg = &imx290_csi_222_75mhz;
+ break;
+ case 148500000:
+ csi_cfg = &imx290_csi_148_5mhz;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ imx290_write(imx290, IMX290_REPETITION, csi_cfg->repetition, &ret);
+ imx290_write(imx290, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret);
+ imx290_write(imx290, IMX290_THSZERO, csi_cfg->thszero, &ret);
+ imx290_write(imx290, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret);
+ imx290_write(imx290, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret);
+ imx290_write(imx290, IMX290_THSTRAIL, csi_cfg->thstrail, &ret);
+ imx290_write(imx290, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret);
+ imx290_write(imx290, IMX290_TCLKPREPARE, csi_cfg->tclkprepare, &ret);
+ imx290_write(imx290, IMX290_TLPX, csi_cfg->tlpx, &ret);
+
+ return ret;
+}
+
static int imx290_setup_format(struct imx290 *imx290,
const struct v4l2_mbus_framefmt *format)
{
const struct imx290_format_info *info;
int ret;
- info = imx290_format_info(format->code);
+ info = imx290_format_info(imx290, format->code);
ret = imx290_set_register_array(imx290, info->regs, info->num_regs);
if (ret < 0) {
@@ -563,6 +777,16 @@ static int imx290_setup_format(struct imx290 *imx290,
/* ----------------------------------------------------------------------------
* Controls
*/
+static void imx290_exposure_update(struct imx290 *imx290,
+ const struct imx290_mode *mode)
+{
+ unsigned int exposure_max;
+
+ exposure_max = imx290->vblank->val + mode->height -
+ IMX290_EXPOSURE_OFFSET;
+ __v4l2_ctrl_modify_range(imx290->exposure, 1, exposure_max, 1,
+ exposure_max);
+}
static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
{
@@ -570,7 +794,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
struct imx290, ctrls);
const struct v4l2_mbus_framefmt *format;
struct v4l2_subdev_state *state;
- int ret = 0;
+ int ret = 0, vmax;
/*
* Return immediately for controls that don't need to be applied to the
@@ -579,6 +803,11 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
return 0;
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ /* Changing vblank changes the allowed range for exposure. */
+ imx290_exposure_update(imx290, imx290->current_mode);
+ }
+
/* V4L2 controls values will be applied only when power is already up */
if (!pm_runtime_get_if_in_use(imx290->dev))
return 0;
@@ -591,9 +820,23 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL);
break;
+ case V4L2_CID_VBLANK:
+ ret = imx290_write(imx290, IMX290_VMAX,
+ ctrl->val + imx290->current_mode->height,
+ NULL);
+ /*
+ * Due to the way that exposure is programmed in this sensor in
+ * relation to VMAX, we have to reprogramme it whenever VMAX is
+ * changed.
+ * Update ctrl so that the V4L2_CID_EXPOSURE case can refer to
+ * it.
+ */
+ ctrl = imx290->exposure;
+ fallthrough;
case V4L2_CID_EXPOSURE:
+ vmax = imx290->vblank->val + imx290->current_mode->height;
ret = imx290_write(imx290, IMX290_SHS1,
- IMX290_VMAX_DEFAULT - ctrl->val - 1, NULL);
+ vmax - ctrl->val - 1, NULL);
break;
case V4L2_CID_TEST_PATTERN:
@@ -612,6 +855,26 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
}
break;
+ case V4L2_CID_HBLANK:
+ ret = imx290_write(imx290, IMX290_HMAX,
+ ctrl->val + imx290->current_mode->width,
+ NULL);
+ break;
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ {
+ u32 reg;
+
+ reg = imx290->current_mode->ctrl_07;
+ if (imx290->hflip->val)
+ reg |= IMX290_HREVERSE;
+ if (imx290->vflip->val)
+ reg |= IMX290_VREVERSE;
+ ret = imx290_write(imx290, IMX290_CTRL_07, reg, NULL);
+ break;
+ }
+
default:
ret = -EINVAL;
break;
@@ -642,20 +905,17 @@ static void imx290_ctrl_update(struct imx290 *imx290,
const struct v4l2_mbus_framefmt *format,
const struct imx290_mode *mode)
{
- unsigned int hblank = mode->hmax - mode->width;
- unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height;
- s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index];
- u64 pixel_rate;
-
- /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- pixel_rate = link_freq * 2 * imx290->nlanes;
- do_div(pixel_rate, imx290_format_info(format->code)->bpp);
+ unsigned int hblank_min = mode->hmax_min - mode->width;
+ unsigned int hblank_max = IMX290_HMAX_MAX - mode->width;
+ unsigned int vblank_min = mode->vmax_min - mode->height;
+ unsigned int vblank_max = IMX290_VMAX_MAX - mode->height;
__v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index);
- __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate);
- __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank);
- __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank);
+ __v4l2_ctrl_modify_range(imx290->hblank, hblank_min, hblank_max, 1,
+ hblank_min);
+ __v4l2_ctrl_modify_range(imx290->vblank, vblank_min, vblank_max, 1,
+ vblank_min);
}
static int imx290_ctrl_init(struct imx290 *imx290)
@@ -667,7 +927,7 @@ static int imx290_ctrl_init(struct imx290 *imx290)
if (ret < 0)
return ret;
- v4l2_ctrl_handler_init(&imx290->ctrls, 9);
+ v4l2_ctrl_handler_init(&imx290->ctrls, 11);
/*
* The sensor has an analog gain and a digital gain, both controlled
@@ -685,9 +945,13 @@ static int imx290_ctrl_init(struct imx290 *imx290)
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
- v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
- IMX290_VMAX_DEFAULT - 2);
+ /*
+ * Correct range will be determined through imx290_ctrl_update setting
+ * V4L2_CID_VBLANK.
+ */
+ imx290->exposure = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 65535, 1,
+ 65535);
/*
* Set the link frequency, pixel rate, horizontal blanking and vertical
@@ -702,24 +966,29 @@ static int imx290_ctrl_init(struct imx290 *imx290)
if (imx290->link_freq)
imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_PIXEL_RATE,
- 1, INT_MAX, 1, 1);
+ v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ IMX290_PIXEL_RATE, IMX290_PIXEL_RATE, 1,
+ IMX290_PIXEL_RATE);
v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx290_test_pattern_menu) - 1,
0, 0, imx290_test_pattern_menu);
+ /*
+ * Actual range will be set from imx290_ctrl_update later in the probe.
+ */
imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_HBLANK, 1, 1, 1, 1);
- if (imx290->hblank)
- imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_VBLANK, 1, 1, 1, 1);
- if (imx290->vblank)
- imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &imx290->hflip);
v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
&props);
@@ -748,17 +1017,37 @@ static int imx290_start_streaming(struct imx290 *imx290,
/* Set init register settings */
ret = imx290_set_register_array(imx290, imx290_global_init_settings,
- ARRAY_SIZE(
- imx290_global_init_settings));
+ ARRAY_SIZE(imx290_global_init_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set init registers\n");
return ret;
}
+ /* Set mdel specific init register settings */
+ ret = imx290_set_register_array(imx290, imx290->model->init_regs,
+ imx290->model->init_regs_num);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set model specific init registers\n");
+ return ret;
+ }
+
+ /* Set clock parameters based on mode and xclk */
+ ret = imx290_set_clock(imx290);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set clocks - %d\n", ret);
+ return ret;
+ }
+
/* Set data lane count */
ret = imx290_set_data_lanes(imx290);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set data lanes\n");
+ dev_err(imx290->dev, "Could not set data lanes - %d\n", ret);
+ return ret;
+ }
+
+ ret = imx290_set_csi_config(imx290);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set csi cfg - %d\n", ret);
return ret;
}
@@ -766,7 +1055,7 @@ static int imx290_start_streaming(struct imx290 *imx290,
format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
ret = imx290_setup_format(imx290, format);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set frame format\n");
+ dev_err(imx290->dev, "Could not set frame format - %d\n", ret);
return ret;
}
@@ -774,19 +1063,14 @@ static int imx290_start_streaming(struct imx290 *imx290,
ret = imx290_set_register_array(imx290, imx290->current_mode->data,
imx290->current_mode->data_size);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set current mode\n");
+ dev_err(imx290->dev, "Could not set current mode - %d\n", ret);
return ret;
}
- ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
- NULL);
- if (ret)
- return ret;
-
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
if (ret) {
- dev_err(imx290->dev, "Could not sync v4l2 controls\n");
+ dev_err(imx290->dev, "Could not sync v4l2 controls - %d\n", ret);
return ret;
}
@@ -835,6 +1119,13 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
pm_runtime_put_autosuspend(imx290->dev);
}
+ /*
+ * vflip and hflip should not be changed during streaming as the sensor
+ * will produce an invalid frame.
+ */
+ __v4l2_ctrl_grab(imx290->vflip, enable);
+ __v4l2_ctrl_grab(imx290->hflip, enable);
+
unlock:
v4l2_subdev_unlock_state(state);
return ret;
@@ -844,10 +1135,12 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
+ const struct imx290 *imx290 = to_imx290(sd);
+
if (code->index >= ARRAY_SIZE(imx290_formats))
return -EINVAL;
- code->code = imx290_formats[code->index].code;
+ code->code = imx290_formats[code->index].code[imx290->model->colour_variant];
return 0;
}
@@ -859,7 +1152,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
const struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
- if (!imx290_format_info(fse->code))
+ if (!imx290_format_info(imx290, fse->code))
return -EINVAL;
if (fse->index >= imx290_modes_num(imx290))
@@ -888,10 +1181,14 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- if (!imx290_format_info(fmt->format.code))
- fmt->format.code = imx290_formats[0].code;
+ if (!imx290_format_info(imx290, fmt->format.code))
+ fmt->format.code = imx290_formats[0].code[imx290->model->colour_variant];
fmt->format.field = V4L2_FIELD_NONE;
+ fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+ fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
@@ -899,6 +1196,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
imx290->current_mode = mode;
imx290_ctrl_update(imx290, &fmt->format, mode);
+ imx290_exposure_update(imx290, mode);
}
*format = fmt->format;
@@ -910,16 +1208,23 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
+ struct imx290 *imx290 = to_imx290(sd);
struct v4l2_mbus_framefmt *format;
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
+ /*
+ * The sensor moves the readout by 1 pixel based on flips to
+ * keep the Bayer order the same.
+ */
sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP
- + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2;
+ + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2
+ + imx290->vflip->val;
sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT
- + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2;
+ + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2
+ + imx290->hflip->val;
sel->r.width = format->width;
sel->r.height = format->height;
@@ -964,6 +1269,11 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
return 0;
}
+static const struct v4l2_subdev_core_ops imx290_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops imx290_video_ops = {
.s_stream = imx290_set_stream,
};
@@ -978,6 +1288,7 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
};
static const struct v4l2_subdev_ops imx290_subdev_ops = {
+ .core = &imx290_core_ops,
.video = &imx290_video_ops,
.pad = &imx290_pad_ops,
};
@@ -996,7 +1307,8 @@ static int imx290_subdev_init(struct imx290 *imx290)
imx290->current_mode = &imx290_modes_ptr(imx290)[0];
v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
- imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
imx290->sd.dev = imx290->dev;
imx290->sd.entity.ops = &imx290_subdev_entity_ops;
imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
@@ -1098,7 +1410,7 @@ static int imx290_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops imx290_pm_ops = {
- SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL)
+ RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL)
};
/* ----------------------------------------------------------------------------
@@ -1132,15 +1444,22 @@ static int imx290_init_clk(struct imx290 *imx290)
u32 xclk_freq;
int ret;
- ret = fwnode_property_read_u32(dev_fwnode(imx290->dev),
- "clock-frequency", &xclk_freq);
+ ret = device_property_read_u32(imx290->dev, "clock-frequency",
+ &xclk_freq);
if (ret) {
dev_err(imx290->dev, "Could not get xclk frequency\n");
return ret;
}
- /* external clock must be 37.125 MHz */
- if (xclk_freq != 37125000) {
+ /* external clock must be 37.125 MHz or 74.25MHz */
+ switch (xclk_freq) {
+ case 37125000:
+ imx290->xclk_idx = IMX290_CLK_37_125;
+ break;
+ case 74250000:
+ imx290->xclk_idx = IMX290_CLK_74_25;
+ break;
+ default:
dev_err(imx290->dev, "External clock frequency %u is not supported\n",
xclk_freq);
return -EINVAL;
@@ -1177,6 +1496,27 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290,
return 0;
}
+static const struct imx290_model_info imx290_models[] = {
+ [IMX290_MODEL_IMX290LQR] = {
+ .colour_variant = IMX290_VARIANT_COLOUR,
+ .init_regs = imx290_global_init_settings_290,
+ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
+ .name = "imx290",
+ },
+ [IMX290_MODEL_IMX290LLR] = {
+ .colour_variant = IMX290_VARIANT_MONO,
+ .init_regs = imx290_global_init_settings_290,
+ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
+ .name = "imx290",
+ },
+ [IMX290_MODEL_IMX327LQR] = {
+ .colour_variant = IMX290_VARIANT_COLOUR,
+ .init_regs = imx290_global_init_settings_327,
+ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_327),
+ .name = "imx327",
+ },
+};
+
static int imx290_parse_dt(struct imx290 *imx290)
{
/* Only CSI2 is supported for now: */
@@ -1187,6 +1527,8 @@ static int imx290_parse_dt(struct imx290 *imx290)
int ret;
s64 fq;
+ imx290->model = of_device_get_match_data(imx290->dev);
+
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL);
if (!endpoint) {
dev_err(imx290->dev, "Endpoint node not found\n");
@@ -1260,7 +1602,7 @@ static int imx290_probe(struct i2c_client *client)
imx290->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(imx290->xclk))
return dev_err_probe(dev, PTR_ERR(imx290->xclk),
- "Could not get xclk");
+ "Could not get xclk\n");
ret = imx290_get_regulators(dev, imx290);
if (ret < 0)
@@ -1304,6 +1646,9 @@ static int imx290_probe(struct i2c_client *client)
if (ret)
goto err_pm;
+ v4l2_i2c_subdev_set_name(&imx290->sd, client,
+ imx290->model->name, NULL);
+
/*
* Finally, register the V4L2 subdev. This must be done after
* initializing everything as the subdev can be used immediately after
@@ -1352,8 +1697,21 @@ static void imx290_remove(struct i2c_client *client)
}
static const struct of_device_id imx290_of_match[] = {
- { .compatible = "sony,imx290" },
- { /* sentinel */ }
+ {
+ /* Deprecated - synonym for "sony,imx290lqr" */
+ .compatible = "sony,imx290",
+ .data = &imx290_models[IMX290_MODEL_IMX290LQR],
+ }, {
+ .compatible = "sony,imx290lqr",
+ .data = &imx290_models[IMX290_MODEL_IMX290LQR],
+ }, {
+ .compatible = "sony,imx290llr",
+ .data = &imx290_models[IMX290_MODEL_IMX290LLR],
+ }, {
+ .compatible = "sony,imx327lqr",
+ .data = &imx290_models[IMX290_MODEL_IMX327LQR],
+ },
+ { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, imx290_of_match);
@@ -1362,8 +1720,8 @@ static struct i2c_driver imx290_i2c_driver = {
.remove = imx290_remove,
.driver = {
.name = "imx290",
- .pm = &imx290_pm_ops,
- .of_match_table = of_match_ptr(imx290_of_match),
+ .pm = pm_ptr(&imx290_pm_ops),
+ .of_match_table = imx290_of_match,
},
};
diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c
index 3c12b6edeac9..4f22c0515ef8 100644
--- a/drivers/media/i2c/imx296.c
+++ b/drivers/media/i2c/imx296.c
@@ -685,15 +685,6 @@ static int imx296_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int imx296_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_format *fmt)
-{
- fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad);
-
- return 0;
-}
-
static int imx296_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt)
@@ -845,7 +836,7 @@ static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = {
static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = {
.enum_mbus_code = imx296_enum_mbus_code,
.enum_frame_size = imx296_enum_frame_size,
- .get_fmt = imx296_get_format,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx296_set_format,
.get_selection = imx296_get_selection,
.set_selection = imx296_set_selection,
diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c
index 7b0a9086447d..309c706114d2 100644
--- a/drivers/media/i2c/imx334.c
+++ b/drivers/media/i2c/imx334.c
@@ -79,7 +79,6 @@ struct imx334_reg_list {
* struct imx334_mode - imx334 sensor mode structure
* @width: Frame width
* @height: Frame height
- * @code: Format code
* @hblank: Horizontal blanking in lines
* @vblank: Vertical blanking in lines
* @vblank_min: Minimal vertical blanking in lines
@@ -91,7 +90,6 @@ struct imx334_reg_list {
struct imx334_mode {
u32 width;
u32 height;
- u32 code;
u32 hblank;
u32 vblank;
u32 vblank_min;
@@ -119,6 +117,7 @@ struct imx334_mode {
* @vblank: Vertical blanking in lines
* @cur_mode: Pointer to current selected sensor mode
* @mutex: Mutex for serializing sensor controls
+ * @cur_code: current selected format code
* @streaming: Flag indicating streaming state
*/
struct imx334 {
@@ -140,6 +139,7 @@ struct imx334 {
u32 vblank;
const struct imx334_mode *cur_mode;
struct mutex mutex;
+ u32 cur_code;
bool streaming;
};
@@ -147,7 +147,170 @@ static const s64 link_freq[] = {
IMX334_LINK_FREQ,
};
-/* Sensor mode registers */
+/* Sensor mode registers for 1920x1080@30fps */
+static const struct imx334_reg mode_1920x1080_regs[] = {
+ {0x3000, 0x01},
+ {0x3018, 0x04},
+ {0x3030, 0xca},
+ {0x3031, 0x08},
+ {0x3032, 0x00},
+ {0x3034, 0x4c},
+ {0x3035, 0x04},
+ {0x302c, 0xf0},
+ {0x302d, 0x03},
+ {0x302e, 0x80},
+ {0x302f, 0x07},
+ {0x3074, 0xcc},
+ {0x3075, 0x02},
+ {0x308e, 0xcd},
+ {0x308f, 0x02},
+ {0x3076, 0x38},
+ {0x3077, 0x04},
+ {0x3090, 0x38},
+ {0x3091, 0x04},
+ {0x3308, 0x38},
+ {0x3309, 0x04},
+ {0x30C6, 0x00},
+ {0x30c7, 0x00},
+ {0x30ce, 0x00},
+ {0x30cf, 0x00},
+ {0x30d8, 0x18},
+ {0x30d9, 0x0a},
+ {0x304c, 0x00},
+ {0x304e, 0x00},
+ {0x304f, 0x00},
+ {0x3050, 0x00},
+ {0x30b6, 0x00},
+ {0x30b7, 0x00},
+ {0x3116, 0x08},
+ {0x3117, 0x00},
+ {0x31a0, 0x20},
+ {0x31a1, 0x0f},
+ {0x300c, 0x3b},
+ {0x300d, 0x29},
+ {0x314c, 0x29},
+ {0x314d, 0x01},
+ {0x315a, 0x06},
+ {0x3168, 0xa0},
+ {0x316a, 0x7e},
+ {0x319e, 0x02},
+ {0x3199, 0x00},
+ {0x319d, 0x00},
+ {0x31dd, 0x03},
+ {0x3300, 0x00},
+ {0x341c, 0xff},
+ {0x341d, 0x01},
+ {0x3a01, 0x03},
+ {0x3a18, 0x7f},
+ {0x3a19, 0x00},
+ {0x3a1a, 0x37},
+ {0x3a1b, 0x00},
+ {0x3a1c, 0x37},
+ {0x3a1d, 0x00},
+ {0x3a1e, 0xf7},
+ {0x3a1f, 0x00},
+ {0x3a20, 0x3f},
+ {0x3a21, 0x00},
+ {0x3a20, 0x6f},
+ {0x3a21, 0x00},
+ {0x3a20, 0x3f},
+ {0x3a21, 0x00},
+ {0x3a20, 0x5f},
+ {0x3a21, 0x00},
+ {0x3a20, 0x2f},
+ {0x3a21, 0x00},
+ {0x3078, 0x02},
+ {0x3079, 0x00},
+ {0x307a, 0x00},
+ {0x307b, 0x00},
+ {0x3080, 0x02},
+ {0x3081, 0x00},
+ {0x3082, 0x00},
+ {0x3083, 0x00},
+ {0x3088, 0x02},
+ {0x3094, 0x00},
+ {0x3095, 0x00},
+ {0x3096, 0x00},
+ {0x309b, 0x02},
+ {0x309c, 0x00},
+ {0x309d, 0x00},
+ {0x309e, 0x00},
+ {0x30a4, 0x00},
+ {0x30a5, 0x00},
+ {0x3288, 0x21},
+ {0x328a, 0x02},
+ {0x3414, 0x05},
+ {0x3416, 0x18},
+ {0x35Ac, 0x0e},
+ {0x3648, 0x01},
+ {0x364a, 0x04},
+ {0x364c, 0x04},
+ {0x3678, 0x01},
+ {0x367c, 0x31},
+ {0x367e, 0x31},
+ {0x3708, 0x02},
+ {0x3714, 0x01},
+ {0x3715, 0x02},
+ {0x3716, 0x02},
+ {0x3717, 0x02},
+ {0x371c, 0x3d},
+ {0x371d, 0x3f},
+ {0x372c, 0x00},
+ {0x372d, 0x00},
+ {0x372e, 0x46},
+ {0x372f, 0x00},
+ {0x3730, 0x89},
+ {0x3731, 0x00},
+ {0x3732, 0x08},
+ {0x3733, 0x01},
+ {0x3734, 0xfe},
+ {0x3735, 0x05},
+ {0x375d, 0x00},
+ {0x375e, 0x00},
+ {0x375f, 0x61},
+ {0x3760, 0x06},
+ {0x3768, 0x1b},
+ {0x3769, 0x1b},
+ {0x376a, 0x1a},
+ {0x376b, 0x19},
+ {0x376c, 0x18},
+ {0x376d, 0x14},
+ {0x376e, 0x0f},
+ {0x3776, 0x00},
+ {0x3777, 0x00},
+ {0x3778, 0x46},
+ {0x3779, 0x00},
+ {0x377a, 0x08},
+ {0x377b, 0x01},
+ {0x377c, 0x45},
+ {0x377d, 0x01},
+ {0x377e, 0x23},
+ {0x377f, 0x02},
+ {0x3780, 0xd9},
+ {0x3781, 0x03},
+ {0x3782, 0xf5},
+ {0x3783, 0x06},
+ {0x3784, 0xa5},
+ {0x3788, 0x0f},
+ {0x378a, 0xd9},
+ {0x378b, 0x03},
+ {0x378c, 0xeb},
+ {0x378d, 0x05},
+ {0x378e, 0x87},
+ {0x378f, 0x06},
+ {0x3790, 0xf5},
+ {0x3792, 0x43},
+ {0x3794, 0x7a},
+ {0x3796, 0xa1},
+ {0x37b0, 0x37},
+ {0x3e04, 0x0e},
+ {0x30e8, 0x50},
+ {0x30e9, 0x00},
+ {0x3e04, 0x0e},
+ {0x3002, 0x00},
+};
+
+/* Sensor mode registers for 3840x2160@30fps */
static const struct imx334_reg mode_3840x2160_regs[] = {
{0x3000, 0x01},
{0x3002, 0x00},
@@ -166,6 +329,7 @@ static const struct imx334_reg mode_3840x2160_regs[] = {
{0x3288, 0x21},
{0x328a, 0x02},
{0x302c, 0x3c},
+ {0x302d, 0x00},
{0x302e, 0x00},
{0x302f, 0x0f},
{0x3076, 0x70},
@@ -240,23 +404,75 @@ static const struct imx334_reg mode_3840x2160_regs[] = {
{0x3794, 0x7a},
{0x3796, 0xa1},
{0x3e04, 0x0e},
+ {0x319e, 0x00},
{0x3a00, 0x01},
+ {0x3a18, 0xbf},
+ {0x3a19, 0x00},
+ {0x3a1a, 0x67},
+ {0x3a1b, 0x00},
+ {0x3a1c, 0x6f},
+ {0x3a1d, 0x00},
+ {0x3a1e, 0xd7},
+ {0x3a1f, 0x01},
+ {0x3a20, 0x6f},
+ {0x3a21, 0x00},
+ {0x3a22, 0xcf},
+ {0x3a23, 0x00},
+ {0x3a24, 0x6f},
+ {0x3a25, 0x00},
+ {0x3a26, 0xb7},
+ {0x3a27, 0x00},
+ {0x3a28, 0x5f},
+ {0x3a29, 0x00},
+};
+
+static const struct imx334_reg raw10_framefmt_regs[] = {
+ {0x3050, 0x00},
+ {0x319d, 0x00},
+ {0x341c, 0xff},
+ {0x341d, 0x01},
+};
+
+static const struct imx334_reg raw12_framefmt_regs[] = {
+ {0x3050, 0x01},
+ {0x319d, 0x01},
+ {0x341c, 0x47},
+ {0x341d, 0x00},
+};
+
+static const u32 imx334_mbus_codes[] = {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
};
/* Supported sensor mode configurations */
-static const struct imx334_mode supported_mode = {
- .width = 3840,
- .height = 2160,
- .hblank = 560,
- .vblank = 2340,
- .vblank_min = 90,
- .vblank_max = 132840,
- .pclk = 594000000,
- .link_freq_idx = 0,
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs),
- .regs = mode_3840x2160_regs,
+static const struct imx334_mode supported_modes[] = {
+ {
+ .width = 3840,
+ .height = 2160,
+ .hblank = 560,
+ .vblank = 2340,
+ .vblank_min = 90,
+ .vblank_max = 132840,
+ .pclk = 594000000,
+ .link_freq_idx = 0,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs),
+ .regs = mode_3840x2160_regs,
+ },
+ }, {
+ .width = 1920,
+ .height = 1080,
+ .hblank = 2480,
+ .vblank = 1170,
+ .vblank_min = 45,
+ .vblank_max = 132840,
+ .pclk = 297000000,
+ .link_freq_idx = 0,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
+ .regs = mode_1920x1080_regs,
+ },
},
};
@@ -382,7 +598,8 @@ static int imx334_update_controls(struct imx334 *imx334,
if (ret)
return ret;
- ret = __v4l2_ctrl_s_ctrl(imx334->hblank_ctrl, mode->hblank);
+ ret = __v4l2_ctrl_modify_range(imx334->hblank_ctrl, mode->hblank,
+ mode->hblank, 1, mode->hblank);
if (ret)
return ret;
@@ -481,6 +698,9 @@ static int imx334_set_ctrl(struct v4l2_ctrl *ctrl)
pm_runtime_put(imx334->dev);
break;
+ case V4L2_CID_HBLANK:
+ ret = 0;
+ break;
default:
dev_err(imx334->dev, "Invalid control %d", ctrl->id);
ret = -EINVAL;
@@ -494,6 +714,18 @@ static const struct v4l2_ctrl_ops imx334_ctrl_ops = {
.s_ctrl = imx334_set_ctrl,
};
+static int imx334_get_format_code(struct imx334 *imx334, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx334_mbus_codes); i++) {
+ if (imx334_mbus_codes[i] == code)
+ return imx334_mbus_codes[i];
+ }
+
+ return imx334_mbus_codes[0];
+}
+
/**
* imx334_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes
* @sd: pointer to imx334 V4L2 sub-device structure
@@ -506,10 +738,10 @@ static int imx334_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index > 0)
+ if (code->index >= ARRAY_SIZE(imx334_mbus_codes))
return -EINVAL;
- code->code = supported_mode.code;
+ code->code = imx334_mbus_codes[code->index];
return 0;
}
@@ -526,15 +758,20 @@ static int imx334_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fsize)
{
- if (fsize->index > 0)
+ struct imx334 *imx334 = to_imx334(sd);
+ u32 code;
+
+ if (fsize->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- if (fsize->code != supported_mode.code)
+ code = imx334_get_format_code(imx334, fsize->code);
+
+ if (fsize->code != code)
return -EINVAL;
- fsize->min_width = supported_mode.width;
+ fsize->min_width = supported_modes[fsize->index].width;
fsize->max_width = fsize->min_width;
- fsize->min_height = supported_mode.height;
+ fsize->min_height = supported_modes[fsize->index].height;
fsize->max_height = fsize->min_height;
return 0;
@@ -553,7 +790,6 @@ static void imx334_fill_pad_format(struct imx334 *imx334,
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = mode->code;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
@@ -583,6 +819,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
+ fmt->format.code = imx334->cur_code;
imx334_fill_pad_format(imx334, imx334->cur_mode, fmt);
}
@@ -609,15 +846,21 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
mutex_lock(&imx334->mutex);
- mode = &supported_mode;
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+
imx334_fill_pad_format(imx334, mode, fmt);
+ fmt->format.code = imx334_get_format_code(imx334, fmt->format.code);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
- } else {
+ } else if (imx334->cur_mode != mode || imx334->cur_code != fmt->format.code) {
+ imx334->cur_code = fmt->format.code;
ret = imx334_update_controls(imx334, mode);
if (!ret)
imx334->cur_mode = mode;
@@ -642,11 +885,26 @@ static int imx334_init_pad_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_format fmt = { 0 };
fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- imx334_fill_pad_format(imx334, &supported_mode, &fmt);
+ imx334_fill_pad_format(imx334, &supported_modes[0], &fmt);
return imx334_set_pad_format(sd, sd_state, &fmt);
}
+static int imx334_set_framefmt(struct imx334 *imx334)
+{
+ switch (imx334->cur_code) {
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ return imx334_write_regs(imx334, raw10_framefmt_regs,
+ ARRAY_SIZE(raw10_framefmt_regs));
+
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
+ return imx334_write_regs(imx334, raw12_framefmt_regs,
+ ARRAY_SIZE(raw12_framefmt_regs));
+ }
+
+ return -EINVAL;
+}
+
/**
* imx334_start_streaming() - Start sensor stream
* @imx334: pointer to imx334 device
@@ -667,6 +925,13 @@ static int imx334_start_streaming(struct imx334 *imx334)
return ret;
}
+ ret = imx334_set_framefmt(imx334);
+ if (ret) {
+ dev_err(imx334->dev, "%s failed to set frame format: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
/* Setup handler will write actual exposure and gain */
ret = __v4l2_ctrl_handler_setup(imx334->sd.ctrl_handler);
if (ret) {
@@ -1037,7 +1302,8 @@ static int imx334_probe(struct i2c_client *client)
}
/* Set default mode to max resolution */
- imx334->cur_mode = &supported_mode;
+ imx334->cur_mode = &supported_modes[0];
+ imx334->cur_code = imx334_mbus_codes[0];
imx334->vblank = imx334->cur_mode->vblank;
ret = imx334_init_controls(imx334);
diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig
deleted file mode 100644
index 7f0af32f4376..000000000000
--- a/drivers/media/i2c/m5mols/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_M5MOLS
- tristate "Fujitsu M-5MOLS 8MP sensor support"
- depends on I2C && VIDEO_DEV
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- help
- This driver supports Fujitsu M-5MOLS camera sensor with ISP
diff --git a/drivers/media/i2c/m5mols/Makefile b/drivers/media/i2c/m5mols/Makefile
deleted file mode 100644
index 13fa8ec29ac0..000000000000
--- a/drivers/media/i2c/m5mols/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o
-
-obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o
diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h
deleted file mode 100644
index d8545d2280af..000000000000
--- a/drivers/media/i2c/m5mols/m5mols.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Header for M-5MOLS 8M Pixel camera sensor with ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#ifndef M5MOLS_H
-#define M5MOLS_H
-
-#include <linux/sizes.h>
-#include <linux/gpio/consumer.h>
-#include <media/v4l2-subdev.h>
-#include "m5mols_reg.h"
-
-
-/* An amount of data transmitted in addition to the value
- * determined by CAPP_JPEG_SIZE_MAX register.
- */
-#define M5MOLS_JPEG_TAGS_SIZE 0x20000
-#define M5MOLS_MAIN_JPEG_SIZE_MAX (5 * SZ_1M)
-
-extern int m5mols_debug;
-
-enum m5mols_restype {
- M5MOLS_RESTYPE_MONITOR,
- M5MOLS_RESTYPE_CAPTURE,
- M5MOLS_RESTYPE_MAX,
-};
-
-/**
- * struct m5mols_resolution - structure for the resolution
- * @type: resolution type according to the pixel code
- * @width: width of the resolution
- * @height: height of the resolution
- * @reg: resolution preset register value
- */
-struct m5mols_resolution {
- u8 reg;
- enum m5mols_restype type;
- u16 width;
- u16 height;
-};
-
-/**
- * struct m5mols_exif - structure for the EXIF information of M-5MOLS
- * @exposure_time: exposure time register value
- * @shutter_speed: speed of the shutter register value
- * @aperture: aperture register value
- * @brightness: brightness register value
- * @exposure_bias: it calls also EV bias
- * @iso_speed: ISO register value
- * @flash: status register value of the flash
- * @sdr: status register value of the Subject Distance Range
- * @qval: not written exact meaning in document
- */
-struct m5mols_exif {
- u32 exposure_time;
- u32 shutter_speed;
- u32 aperture;
- u32 brightness;
- u32 exposure_bias;
- u16 iso_speed;
- u16 flash;
- u16 sdr;
- u16 qval;
-};
-
-/**
- * struct m5mols_capture - Structure for the capture capability
- * @exif: EXIF information
- * @buf_size: internal JPEG frame buffer size, in bytes
- * @main: size in bytes of the main image
- * @thumb: size in bytes of the thumb image, if it was accompanied
- * @total: total size in bytes of the produced image
- */
-struct m5mols_capture {
- struct m5mols_exif exif;
- unsigned int buf_size;
- u32 main;
- u32 thumb;
- u32 total;
-};
-
-/**
- * struct m5mols_scenemode - structure for the scenemode capability
- * @metering: metering light register value
- * @ev_bias: EV bias register value
- * @wb_mode: mode which means the WhiteBalance is Auto or Manual
- * @wb_preset: whitebalance preset register value in the Manual mode
- * @chroma_en: register value whether the Chroma capability is enabled or not
- * @chroma_lvl: chroma's level register value
- * @edge_en: register value Whether the Edge capability is enabled or not
- * @edge_lvl: edge's level register value
- * @af_range: Auto Focus's range
- * @fd_mode: Face Detection mode
- * @mcc: Multi-axis Color Conversion which means emotion color
- * @light: status of the Light
- * @flash: status of the Flash
- * @tone: Tone color which means Contrast
- * @iso: ISO register value
- * @capt_mode: Mode of the Image Stabilization while the camera capturing
- * @wdr: Wide Dynamic Range register value
- *
- * The each value according to each scenemode is recommended in the documents.
- */
-struct m5mols_scenemode {
- u8 metering;
- u8 ev_bias;
- u8 wb_mode;
- u8 wb_preset;
- u8 chroma_en;
- u8 chroma_lvl;
- u8 edge_en;
- u8 edge_lvl;
- u8 af_range;
- u8 fd_mode;
- u8 mcc;
- u8 light;
- u8 flash;
- u8 tone;
- u8 iso;
- u8 capt_mode;
- u8 wdr;
-};
-
-#define VERSION_STRING_SIZE 22
-
-/**
- * struct m5mols_version - firmware version information
- * @customer: customer information
- * @project: version of project information according to customer
- * @fw: firmware revision
- * @hw: hardware revision
- * @param: version of the parameter
- * @awb: Auto WhiteBalance algorithm version
- * @str: information about manufacturer and packaging vendor
- * @af: Auto Focus version
- *
- * The register offset starts the customer version at 0x0, and it ends
- * the awb version at 0x09. The customer, project information occupies 1 bytes
- * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
- * unique string associated with firmware's version. It includes information
- * about manufacturer and the vendor of the sensor's packaging. The least
- * significant 2 bytes of the string indicate packaging manufacturer.
- */
-struct m5mols_version {
- u8 customer;
- u8 project;
- u16 fw;
- u16 hw;
- u16 param;
- u16 awb;
- u8 str[VERSION_STRING_SIZE];
- u8 af;
-};
-
-/**
- * struct m5mols_info - M-5MOLS driver data structure
- * @pdata: platform data
- * @sd: v4l-subdev instance
- * @pad: media pad
- * @irq_waitq: waitqueue for the capture
- * @irq_done: set to 1 in the interrupt handler
- * @handle: control handler
- * @auto_exposure: auto/manual exposure control
- * @exposure_bias: exposure compensation control
- * @exposure: manual exposure control
- * @metering: exposure metering control
- * @auto_iso: auto/manual ISO sensitivity control
- * @iso: manual ISO sensitivity control
- * @auto_wb: auto white balance control
- * @lock_3a: 3A lock control
- * @colorfx: color effect control
- * @saturation: saturation control
- * @zoom: zoom control
- * @wdr: wide dynamic range control
- * @stabilization: image stabilization control
- * @jpeg_quality: JPEG compression quality control
- * @set_power: optional power callback to the board code
- * @reset: GPIO driving the reset pin of M-5MOLS
- * @lock: mutex protecting the structure fields below
- * @ffmt: current fmt according to resolution type
- * @res_type: current resolution type
- * @ver: information of the version
- * @cap: the capture mode attributes
- * @isp_ready: 1 when the ISP controller has completed booting
- * @power: current sensor's power status
- * @ctrl_sync: 1 when the control handler state is restored in H/W
- * @resolution: register value for current resolution
- * @mode: register value for current operation mode
- */
-struct m5mols_info {
- const struct m5mols_platform_data *pdata;
- struct v4l2_subdev sd;
- struct media_pad pad;
-
- wait_queue_head_t irq_waitq;
- atomic_t irq_done;
-
- struct v4l2_ctrl_handler handle;
- struct {
- /* exposure/exposure bias/auto exposure cluster */
- struct v4l2_ctrl *auto_exposure;
- struct v4l2_ctrl *exposure_bias;
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *metering;
- };
- struct {
- /* iso/auto iso cluster */
- struct v4l2_ctrl *auto_iso;
- struct v4l2_ctrl *iso;
- };
- struct v4l2_ctrl *auto_wb;
-
- struct v4l2_ctrl *lock_3a;
- struct v4l2_ctrl *colorfx;
- struct v4l2_ctrl *saturation;
- struct v4l2_ctrl *zoom;
- struct v4l2_ctrl *wdr;
- struct v4l2_ctrl *stabilization;
- struct v4l2_ctrl *jpeg_quality;
-
- int (*set_power)(struct device *dev, int on);
- struct gpio_desc *reset;
-
- struct mutex lock;
-
- struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
- int res_type;
-
- struct m5mols_version ver;
- struct m5mols_capture cap;
-
- unsigned int isp_ready:1;
- unsigned int power:1;
- unsigned int ctrl_sync:1;
-
- u8 resolution;
- u8 mode;
-};
-
-#define is_available_af(__info) (__info->ver.af)
-#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
-#define is_manufacturer(__info, __manufacturer) \
- (__info->ver.str[0] == __manufacturer[0] && \
- __info->ver.str[1] == __manufacturer[1])
-/*
- * I2C operation of the M-5MOLS
- *
- * The I2C read operation of the M-5MOLS requires 2 messages. The first
- * message sends the information about the command, command category, and total
- * message size. The second message is used to retrieve the data specified in
- * the first message
- *
- * 1st message 2nd message
- * +-------+---+----------+-----+-------+ +------+------+------+------+
- * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] |
- * +-------+---+----------+-----+-------+ +------+------+------+------+
- * - size1: message data size(5 in this case)
- * - size2: desired buffer size of the 2nd message
- * - d[0..3]: according to size2
- *
- * The I2C write operation needs just one message. The message includes
- * category, command, total size, and desired data.
- *
- * 1st message
- * +-------+---+----------+-----+------+------+------+------+
- * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
- * +-------+---+----------+-----+------+------+------+------+
- * - d[0..3]: according to size1
- */
-int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
-int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
-int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
-int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-
-int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
- int timeout);
-
-/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
-#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16)
-/* ISP state transition timeout, in ms */
-#define M5MOLS_MODE_CHANGE_TIMEOUT 200
-#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250
-
-/*
- * Mode operation of the M-5MOLS
- *
- * Changing the mode of the M-5MOLS is needed right executing order.
- * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
- * by user. There are various categories associated with each mode.
- *
- * +============================================================+
- * | mode | category |
- * +============================================================+
- * | FLASH | FLASH(only after Stand-by or Power-on) |
- * | SYSTEM | SYSTEM(only after sensor arm-booting) |
- * | PARAMETER | PARAMETER |
- * | MONITOR | MONITOR(preview), Auto Focus, Face Detection |
- * | CAPTURE | Single CAPTURE, Preview(recording) |
- * +============================================================+
- *
- * The available executing order between each modes are as follows:
- * PARAMETER <---> MONITOR <---> CAPTURE
- */
-int m5mols_set_mode(struct m5mols_info *info, u8 mode);
-
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
-int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
-int m5mols_restore_controls(struct m5mols_info *info);
-int m5mols_start_capture(struct m5mols_info *info);
-int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
-int m5mols_lock_3a(struct m5mols_info *info, bool lock);
-int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
-int m5mols_init_controls(struct v4l2_subdev *sd);
-
-/* The firmware function */
-int m5mols_update_fw(struct v4l2_subdev *sd,
- int (*set_power)(struct m5mols_info *, bool));
-
-static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev)
-{
- return container_of(subdev, struct m5mols_info, sd);
-}
-
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- struct m5mols_info *info = container_of(ctrl->handler,
- struct m5mols_info, handle);
- return &info->sd;
-}
-
-static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl,
- unsigned int mode)
-{
- ctrl->priv = (void *)(uintptr_t)mode;
-}
-
-static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl)
-{
- return (unsigned int)(uintptr_t)ctrl->priv;
-}
-
-#endif /* M5MOLS_H */
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
deleted file mode 100644
index 275c5b2539fd..000000000000
--- a/drivers/media/i2c/m5mols/m5mols_capture.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-/*
- * The Capture code for Fujitsu M-5MOLS ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/i2c/m5mols.h>
-#include <media/drv-intf/exynos-fimc.h>
-
-#include "m5mols.h"
-#include "m5mols_reg.h"
-
-/**
- * m5mols_read_rational - I2C read of a rational number
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @addr_num: numerator register
- * @addr_den: denominator register
- * @val: place to store the division result
- *
- * Read numerator and denominator from registers @addr_num and @addr_den
- * respectively and return the division result in @val.
- */
-static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
- u32 addr_den, u32 *val)
-{
- u32 num, den;
-
- int ret = m5mols_read_u32(sd, addr_num, &num);
- if (!ret)
- ret = m5mols_read_u32(sd, addr_den, &den);
- if (ret)
- return ret;
- *val = den == 0 ? 0 : num / den;
- return ret;
-}
-
-/**
- * m5mols_capture_info - Gather captured image information
- * @info: M-5MOLS driver data structure
- *
- * For now it gathers only EXIF information and file size.
- */
-static int m5mols_capture_info(struct m5mols_info *info)
-{
- struct m5mols_exif *exif = &info->cap.exif;
- struct v4l2_subdev *sd = &info->sd;
- int ret;
-
- ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU,
- EXIF_INFO_EXPTIME_DE, &exif->exposure_time);
- if (ret)
- return ret;
- ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE,
- &exif->shutter_speed);
- if (ret)
- return ret;
- ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE,
- &exif->aperture);
- if (ret)
- return ret;
- ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE,
- &exif->brightness);
- if (ret)
- return ret;
- ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE,
- &exif->exposure_bias);
- if (ret)
- return ret;
-
- ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed);
- if (!ret)
- ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash);
- if (!ret)
- ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr);
- if (!ret)
- ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval);
- if (ret)
- return ret;
-
- if (!ret)
- ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main);
- if (!ret)
- ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
- if (!ret)
- info->cap.total = info->cap.main + info->cap.thumb;
-
- return ret;
-}
-
-int m5mols_start_capture(struct m5mols_info *info)
-{
- unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE;
- struct v4l2_subdev *sd = &info->sd;
- int ret;
-
- /*
- * Synchronize the controls, set the capture frame resolution and color
- * format. The frame capture is initiated during switching from Monitor
- * to Capture mode.
- */
- ret = m5mols_set_mode(info, REG_MONITOR);
- if (!ret)
- ret = m5mols_restore_controls(info);
- if (!ret)
- ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
- if (!ret)
- ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution);
- if (!ret)
- ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize);
- if (!ret)
- ret = m5mols_set_mode(info, REG_CAPTURE);
- if (!ret)
- /* Wait until a frame is captured to ISP internal memory */
- ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
- if (ret)
- return ret;
-
- /*
- * Initiate the captured data transfer to a MIPI-CSI receiver.
- */
- ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
- if (!ret)
- ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
- if (!ret) {
- bool captured = false;
- unsigned int size;
-
- /* Wait for the capture completion interrupt */
- ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
- if (!ret) {
- captured = true;
- ret = m5mols_capture_info(info);
- }
- size = captured ? info->cap.main : 0;
- v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n",
- __func__, size, info->cap.thumb);
-
- v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size);
- }
-
- return ret;
-}
diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c
deleted file mode 100644
index b45e0e08b6c8..000000000000
--- a/drivers/media/i2c/m5mols/m5mols_controls.c
+++ /dev/null
@@ -1,625 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Controls for M-5MOLS 8M Pixel camera sensor with ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-
-#include "m5mols.h"
-#include "m5mols_reg.h"
-
-static struct m5mols_scenemode m5mols_default_scenemode[] = {
- [REG_SCENE_NORMAL] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
- 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_PORTRAIT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
- REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_LANDSCAPE] = {
- REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_SPORTS] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_PARTY_INDOOR] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_BEACH_SNOW] = {
- REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_SUNSET] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
- REG_AWB_DAYLIGHT,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_DAWN_DUSK] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
- REG_AWB_FLUORESCENT_1,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_FALL] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_NIGHT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_AGAINST_LIGHT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_FIRE] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_TEXT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
- REG_AF_MACRO, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
- },
- [REG_SCENE_CANDLE] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
-};
-
-/**
- * m5mols_do_scenemode() - Change current scenemode
- * @info: M-5MOLS driver data structure
- * @mode: Desired mode of the scenemode
- *
- * WARNING: The execution order is important. Do not change the order.
- */
-int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
-{
- struct v4l2_subdev *sd = &info->sd;
- struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
- int ret;
-
- if (mode > REG_SCENE_CANDLE)
- return -EINVAL;
-
- ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
- if (!ret)
- ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
- if (!ret)
- ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
- if (!ret)
- ret = m5mols_write(sd, AE_MODE, scenemode.metering);
- if (!ret)
- ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
- if (!ret)
- ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
- if (!ret)
- ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
- if (!ret)
- ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
- if (!ret)
- ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
- if (!ret && is_available_af(info))
- ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
- if (!ret && is_available_af(info))
- ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
- if (!ret)
- ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
- if (!ret)
- ret = m5mols_write(sd, AE_ISO, scenemode.iso);
- if (!ret)
- ret = m5mols_set_mode(info, REG_CAPTURE);
- if (!ret)
- ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
- if (!ret)
- ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
- if (!ret)
- ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
- if (!ret)
- ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
- if (!ret)
- ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
- if (!ret)
- ret = m5mols_set_mode(info, REG_MONITOR);
-
- return ret;
-}
-
-static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
-{
- bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
- int ret = 0;
-
- if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
- bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
-
- ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
- REG_AE_LOCK : REG_AE_UNLOCK);
- if (ret)
- return ret;
- }
-
- if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
- && info->auto_wb->val) {
- bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
-
- ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
- REG_AWB_LOCK : REG_AWB_UNLOCK);
- if (ret)
- return ret;
- }
-
- if (!info->ver.af || !af_lock)
- return ret;
-
- if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
- ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
-
- return ret;
-}
-
-static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
-{
- unsigned int metering;
-
- switch (mode) {
- case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
- metering = REG_AE_CENTER;
- break;
- case V4L2_EXPOSURE_METERING_SPOT:
- metering = REG_AE_SPOT;
- break;
- default:
- metering = REG_AE_ALL;
- break;
- }
-
- return m5mols_write(&info->sd, AE_MODE, metering);
-}
-
-static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
-{
- struct v4l2_subdev *sd = &info->sd;
- int ret = 0;
-
- if (exposure == V4L2_EXPOSURE_AUTO) {
- /* Unlock auto exposure */
- info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
- m5mols_3a_lock(info, info->lock_3a);
-
- ret = m5mols_set_metering_mode(info, info->metering->val);
- if (ret < 0)
- return ret;
-
- v4l2_dbg(1, m5mols_debug, sd,
- "%s: exposure bias: %#x, metering: %#x\n",
- __func__, info->exposure_bias->val,
- info->metering->val);
-
- return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
- }
-
- if (exposure == V4L2_EXPOSURE_MANUAL) {
- ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
- if (ret == 0)
- ret = m5mols_write(sd, AE_MAN_GAIN_MON,
- info->exposure->val);
- if (ret == 0)
- ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
- info->exposure->val);
-
- v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
- __func__, info->exposure->val);
- }
-
- return ret;
-}
-
-static int m5mols_set_white_balance(struct m5mols_info *info, int val)
-{
- static const unsigned short wb[][2] = {
- { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT },
- { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 },
- { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 },
- { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON },
- { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT },
- { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT },
- { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY },
- { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE },
- { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO },
- };
- int i;
- struct v4l2_subdev *sd = &info->sd;
- int ret = -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(wb); i++) {
- int awb;
- if (wb[i][0] != val)
- continue;
-
- v4l2_dbg(1, m5mols_debug, sd,
- "Setting white balance to: %#x\n", wb[i][0]);
-
- awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
- ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
- REG_AWB_PRESET);
- if (ret < 0)
- return ret;
-
- if (!awb)
- ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
- }
-
- return ret;
-}
-
-static int m5mols_set_saturation(struct m5mols_info *info, int val)
-{
- int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
- if (ret < 0)
- return ret;
-
- return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
-}
-
-static int m5mols_set_color_effect(struct m5mols_info *info, int val)
-{
- unsigned int m_effect = REG_COLOR_EFFECT_OFF;
- unsigned int p_effect = REG_EFFECT_OFF;
- unsigned int cfix_r = 0, cfix_b = 0;
- struct v4l2_subdev *sd = &info->sd;
- int ret = 0;
-
- switch (val) {
- case V4L2_COLORFX_BW:
- m_effect = REG_COLOR_EFFECT_ON;
- break;
- case V4L2_COLORFX_NEGATIVE:
- p_effect = REG_EFFECT_NEGA;
- break;
- case V4L2_COLORFX_EMBOSS:
- p_effect = REG_EFFECT_EMBOSS;
- break;
- case V4L2_COLORFX_SEPIA:
- m_effect = REG_COLOR_EFFECT_ON;
- cfix_r = REG_CFIXR_SEPIA;
- cfix_b = REG_CFIXB_SEPIA;
- break;
- }
-
- ret = m5mols_write(sd, PARM_EFFECT, p_effect);
- if (!ret)
- ret = m5mols_write(sd, MON_EFFECT, m_effect);
-
- if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
- ret = m5mols_write(sd, MON_CFIXR, cfix_r);
- if (!ret)
- ret = m5mols_write(sd, MON_CFIXB, cfix_b);
- }
-
- v4l2_dbg(1, m5mols_debug, sd,
- "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
- p_effect, m_effect, cfix_r, cfix_b, ret);
-
- return ret;
-}
-
-static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
-{
- u32 iso = auto_iso ? 0 : info->iso->val + 1;
-
- return m5mols_write(&info->sd, AE_ISO, iso);
-}
-
-static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
-{
- int ret;
-
- ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
- if (ret < 0)
- return ret;
-
- ret = m5mols_set_mode(info, REG_CAPTURE);
- if (ret < 0)
- return ret;
-
- return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
-}
-
-static int m5mols_set_stabilization(struct m5mols_info *info, int val)
-{
- struct v4l2_subdev *sd = &info->sd;
- unsigned int evp = val ? 0xe : 0x0;
- int ret;
-
- ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
- if (ret < 0)
- return ret;
-
- return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
-}
-
-static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct m5mols_info *info = to_m5mols(sd);
- int ret = 0;
- u8 status = REG_ISO_AUTO;
-
- v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
- __func__, ctrl->name, info->isp_ready);
-
- if (!info->isp_ready)
- return -EBUSY;
-
- switch (ctrl->id) {
- case V4L2_CID_ISO_SENSITIVITY_AUTO:
- ret = m5mols_read_u8(sd, AE_ISO, &status);
- if (ret == 0)
- ctrl->val = !status;
- if (status != REG_ISO_AUTO)
- info->iso->val = status - 1;
- break;
-
- case V4L2_CID_3A_LOCK:
- ctrl->val &= ~0x7;
-
- ret = m5mols_read_u8(sd, AE_LOCK, &status);
- if (ret)
- return ret;
- if (status)
- info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
-
- ret = m5mols_read_u8(sd, AWB_LOCK, &status);
- if (ret)
- return ret;
- if (status)
- info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
-
- ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
- if (!status)
- info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
- break;
- }
-
- return ret;
-}
-
-static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct m5mols_info *info = to_m5mols(sd);
- int last_mode = info->mode;
- int ret = 0;
-
- /*
- * If needed, defer restoring the controls until
- * the device is fully initialized.
- */
- if (!info->isp_ready) {
- info->ctrl_sync = 0;
- return 0;
- }
-
- v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %p\n",
- __func__, ctrl->name, ctrl->val, ctrl->priv);
-
- if (ctrl_mode && ctrl_mode != info->mode) {
- ret = m5mols_set_mode(info, ctrl_mode);
- if (ret < 0)
- return ret;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_3A_LOCK:
- ret = m5mols_3a_lock(info, ctrl);
- break;
-
- case V4L2_CID_ZOOM_ABSOLUTE:
- ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
- break;
-
- case V4L2_CID_EXPOSURE_AUTO:
- ret = m5mols_set_exposure(info, ctrl->val);
- break;
-
- case V4L2_CID_ISO_SENSITIVITY:
- ret = m5mols_set_iso(info, ctrl->val);
- break;
-
- case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
- ret = m5mols_set_white_balance(info, ctrl->val);
- break;
-
- case V4L2_CID_SATURATION:
- ret = m5mols_set_saturation(info, ctrl->val);
- break;
-
- case V4L2_CID_COLORFX:
- ret = m5mols_set_color_effect(info, ctrl->val);
- break;
-
- case V4L2_CID_WIDE_DYNAMIC_RANGE:
- ret = m5mols_set_wdr(info, ctrl->val);
- break;
-
- case V4L2_CID_IMAGE_STABILIZATION:
- ret = m5mols_set_stabilization(info, ctrl->val);
- break;
-
- case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
- break;
- }
-
- if (ret == 0 && info->mode != last_mode)
- ret = m5mols_set_mode(info, last_mode);
-
- return ret;
-}
-
-static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
- .g_volatile_ctrl = m5mols_g_volatile_ctrl,
- .s_ctrl = m5mols_s_ctrl,
-};
-
-/* Supported manual ISO values */
-static const s64 iso_qmenu[] = {
- /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */
- 50000, 100000, 200000, 400000, 800000, 1600000, 3200000
-};
-
-/* Supported Exposure Bias values, -2.0EV...+2.0EV */
-static const s64 ev_bias_qmenu[] = {
- /* AE_INDEX: 0x00...0x08 */
- -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
-};
-
-int m5mols_init_controls(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
- u16 exposure_max;
- u16 zoom_step;
- int ret;
-
- /* Determine the firmware dependent control range and step values */
- ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
- if (ret < 0)
- return ret;
-
- zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
- v4l2_ctrl_handler_init(&info->handle, 20);
-
- info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
- 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
-
- /* Exposure control cluster */
- info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
- 1, ~0x03, V4L2_EXPOSURE_AUTO);
-
- info->exposure = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
- 0, exposure_max, 1, exposure_max / 2);
-
- info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
- ARRAY_SIZE(ev_bias_qmenu) - 1,
- ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
- ev_bias_qmenu);
-
- info->metering = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
- 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
-
- /* ISO control cluster */
- info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
-
- info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
- ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
-
- info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_SATURATION, 1, 5, 1, 3);
-
- info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
-
- info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);
-
- info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
-
- info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
-
- info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
-
- info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
- V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
-
- if (info->handle.error) {
- int ret = info->handle.error;
- v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
- v4l2_ctrl_handler_free(&info->handle);
- return ret;
- }
-
- v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
- info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
- V4L2_CTRL_FLAG_UPDATE;
- v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
-
- info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
-
- m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
- m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
- m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
-
- sd->ctrl_handler = &info->handle;
-
- return 0;
-}
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
deleted file mode 100644
index 2b01873ba0db..000000000000
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ /dev/null
@@ -1,1051 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for M-5MOLS 8M Pixel camera sensor with ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/regulator/consumer.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/i2c/m5mols.h>
-
-#include "m5mols.h"
-#include "m5mols_reg.h"
-
-int m5mols_debug;
-module_param(m5mols_debug, int, 0644);
-
-#define MODULE_NAME "M5MOLS"
-#define M5MOLS_I2C_CHECK_RETRY 500
-
-/* The regulator consumer names for external voltage regulators */
-static struct regulator_bulk_data supplies[] = {
- {
- .supply = "core", /* ARM core power, 1.2V */
- }, {
- .supply = "dig_18", /* digital power 1, 1.8V */
- }, {
- .supply = "d_sensor", /* sensor power 1, 1.8V */
- }, {
- .supply = "dig_28", /* digital power 2, 2.8V */
- }, {
- .supply = "a_sensor", /* analog power */
- }, {
- .supply = "dig_12", /* digital power 3, 1.2V */
- },
-};
-
-static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
- [M5MOLS_RESTYPE_MONITOR] = {
- .width = 1920,
- .height = 1080,
- .code = MEDIA_BUS_FMT_VYUY8_2X8,
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
- [M5MOLS_RESTYPE_CAPTURE] = {
- .width = 1920,
- .height = 1080,
- .code = MEDIA_BUS_FMT_JPEG_1X8,
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
-};
-#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt)
-
-static const struct m5mols_resolution m5mols_reg_res[] = {
- { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */
- { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */
- { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */
- { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
- { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */
- { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */
- { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */
- { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */
- { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */
- { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
- { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */
- { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */
- { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
- { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */
- { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */
- { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */
- { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */
- { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */
- { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */
-
- { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */
- { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */
- { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
- { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */
- { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */
- { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */
- { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */
- { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */
- { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */
- { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */
- { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */
- { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
- { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */
- { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
- { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */
- { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */
- { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
- { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */
-};
-
-/**
- * m5mols_swap_byte - an byte array to integer conversion function
- * @data: byte array
- * @length: size in bytes of I2C packet defined in the M-5MOLS datasheet
- *
- * Convert I2C data byte array with performing any required byte
- * reordering to assure proper values for each data type, regardless
- * of the architecture endianness.
- */
-static u32 m5mols_swap_byte(u8 *data, u8 length)
-{
- if (length == 1)
- return *data;
- else if (length == 2)
- return be16_to_cpu(*((__be16 *)data));
- else
- return be32_to_cpu(*((__be32 *)data));
-}
-
-/**
- * m5mols_read - I2C read function
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @size: desired size of I2C packet
- * @reg: combination of size, category and command for the I2C packet
- * @val: read value
- *
- * Returns 0 on success, or else negative errno.
- */
-static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct m5mols_info *info = to_m5mols(sd);
- u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
- u8 category = I2C_CATEGORY(reg);
- u8 cmd = I2C_COMMAND(reg);
- struct i2c_msg msg[2];
- u8 wbuf[5];
- int ret;
-
- if (!client->adapter)
- return -ENODEV;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 5;
- msg[0].buf = wbuf;
- wbuf[0] = 5;
- wbuf[1] = M5MOLS_BYTE_READ;
- wbuf[2] = category;
- wbuf[3] = cmd;
- wbuf[4] = size;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = size + 1;
- msg[1].buf = rbuf;
-
- /* minimum stabilization time */
- usleep_range(200, 300);
-
- ret = i2c_transfer(client->adapter, msg, 2);
-
- if (ret == 2) {
- *val = m5mols_swap_byte(&rbuf[1], size);
- return 0;
- }
-
- if (info->isp_ready)
- v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
- size, category, cmd, ret);
-
- return ret < 0 ? ret : -EIO;
-}
-
-int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
-{
- u32 val_32;
- int ret;
-
- if (I2C_SIZE(reg) != 1) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
- if (ret)
- return ret;
-
- *val = (u8)val_32;
- return ret;
-}
-
-int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val)
-{
- u32 val_32;
- int ret;
-
- if (I2C_SIZE(reg) != 2) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
- if (ret)
- return ret;
-
- *val = (u16)val_32;
- return ret;
-}
-
-int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
-{
- if (I2C_SIZE(reg) != 4) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- return m5mols_read(sd, I2C_SIZE(reg), reg, val);
-}
-
-/**
- * m5mols_write - I2C command write function
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @reg: combination of size, category and command for the I2C packet
- * @val: value to write
- *
- * Returns 0 on success, or else negative errno.
- */
-int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct m5mols_info *info = to_m5mols(sd);
- u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
- u8 category = I2C_CATEGORY(reg);
- u8 cmd = I2C_COMMAND(reg);
- u8 size = I2C_SIZE(reg);
- u32 *buf = (u32 *)&wbuf[4];
- struct i2c_msg msg[1];
- int ret;
-
- if (!client->adapter)
- return -ENODEV;
-
- if (size != 1 && size != 2 && size != 4) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- msg->addr = client->addr;
- msg->flags = 0;
- msg->len = (u16)size + 4;
- msg->buf = wbuf;
- wbuf[0] = size + 4;
- wbuf[1] = M5MOLS_BYTE_WRITE;
- wbuf[2] = category;
- wbuf[3] = cmd;
-
- *buf = m5mols_swap_byte((u8 *)&val, size);
-
- /* minimum stabilization time */
- usleep_range(200, 300);
-
- ret = i2c_transfer(client->adapter, msg, 1);
- if (ret == 1)
- return 0;
-
- if (info->isp_ready)
- v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
- category, cmd, ret);
-
- return ret < 0 ? ret : -EIO;
-}
-
-/**
- * m5mols_busy_wait - Busy waiting with I2C register polling
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @reg: the I2C_REG() address of an 8-bit status register to check
- * @value: expected status register value
- * @mask: bit mask for the read status register value
- * @timeout: timeout in milliseconds, or -1 for default timeout
- *
- * The @reg register value is ORed with @mask before comparing with @value.
- *
- * Return: 0 if the requested condition became true within less than
- * @timeout ms, or else negative errno.
- */
-int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
- int timeout)
-{
- int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
- unsigned long end = jiffies + msecs_to_jiffies(ms);
- u8 status;
-
- do {
- int ret = m5mols_read_u8(sd, reg, &status);
-
- if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
- return ret;
- if (!ret && (status & mask & 0xff) == (value & 0xff))
- return 0;
- usleep_range(100, 250);
- } while (ms > 0 && time_is_after_jiffies(end));
-
- return -EBUSY;
-}
-
-/**
- * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @reg: combination of size, category and command for the I2C packet
- *
- * Before writing desired interrupt value the INT_FACTOR register should
- * be read to clear pending interrupts.
- */
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
-{
- struct m5mols_info *info = to_m5mols(sd);
- u8 mask = is_available_af(info) ? REG_INT_AF : 0;
- u8 dummy;
- int ret;
-
- ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
- if (!ret)
- ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
- return ret;
-}
-
-int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
-{
- struct m5mols_info *info = to_m5mols(sd);
-
- int ret = wait_event_interruptible_timeout(info->irq_waitq,
- atomic_add_unless(&info->irq_done, -1, 0),
- msecs_to_jiffies(timeout));
- if (ret <= 0)
- return ret ? ret : -ETIMEDOUT;
-
- return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
- M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
-}
-
-/**
- * m5mols_reg_mode - Write the mode and check busy status
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @mode: the required operation mode
- *
- * It always accompanies a little delay changing the M-5MOLS mode, so it is
- * needed checking current busy status to guarantee right mode.
- */
-static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
-{
- int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
- if (ret < 0)
- return ret;
- return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
- M5MOLS_MODE_CHANGE_TIMEOUT);
-}
-
-/**
- * m5mols_set_mode - set the M-5MOLS controller mode
- * @info: M-5MOLS driver data structure
- * @mode: the required operation mode
- *
- * The commands of M-5MOLS are grouped into specific modes. Each functionality
- * can be guaranteed only when the sensor is operating in mode which a command
- * belongs to.
- */
-int m5mols_set_mode(struct m5mols_info *info, u8 mode)
-{
- struct v4l2_subdev *sd = &info->sd;
- int ret = -EINVAL;
- u8 reg;
-
- if (mode < REG_PARAMETER || mode > REG_CAPTURE)
- return ret;
-
- ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
- if (ret || reg == mode)
- return ret;
-
- switch (reg) {
- case REG_PARAMETER:
- ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (mode == REG_MONITOR)
- break;
- if (!ret)
- ret = m5mols_reg_mode(sd, REG_CAPTURE);
- break;
-
- case REG_MONITOR:
- if (mode == REG_PARAMETER) {
- ret = m5mols_reg_mode(sd, REG_PARAMETER);
- break;
- }
-
- ret = m5mols_reg_mode(sd, REG_CAPTURE);
- break;
-
- case REG_CAPTURE:
- ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (mode == REG_MONITOR)
- break;
- if (!ret)
- ret = m5mols_reg_mode(sd, REG_PARAMETER);
- break;
-
- default:
- v4l2_warn(sd, "Wrong mode: %d\n", mode);
- }
-
- if (!ret)
- info->mode = mode;
-
- return ret;
-}
-
-/**
- * m5mols_get_version - retrieve full revisions information of M-5MOLS
- * @sd: sub-device, as pointed by struct v4l2_subdev
- *
- * The version information includes revisions of hardware and firmware,
- * AutoFocus alghorithm version and the version string.
- */
-static int m5mols_get_version(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
- struct m5mols_version *ver = &info->ver;
- u8 *str = ver->str;
- int i;
- int ret;
-
- ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
- if (!ret)
- ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb);
- if (!ret)
- ret = m5mols_read_u8(sd, AF_VERSION, &ver->af);
- if (ret)
- return ret;
-
- for (i = 0; i < VERSION_STRING_SIZE; i++) {
- ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
- if (ret)
- return ret;
- }
-
- v4l2_info(sd, "Manufacturer\t[%s]\n",
- is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
- "Samsung Electro-Mechanics" :
- is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
- "Samsung Fiber-Optics" :
- is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
- "Samsung Techwin" : "None");
- v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
- info->ver.customer, info->ver.project);
-
- if (!is_available_af(info))
- v4l2_info(sd, "No support Auto Focus on this firmware\n");
-
- return ret;
-}
-
-/**
- * __find_restype - Lookup M-5MOLS resolution type according to pixel code
- * @code: pixel code
- */
-static enum m5mols_restype __find_restype(u32 code)
-{
- enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
-
- do {
- if (code == m5mols_default_ffmt[type].code)
- return type;
- } while (type++ != SIZE_DEFAULT_FFMT);
-
- return 0;
-}
-
-/**
- * __find_resolution - Lookup preset and type of M-5MOLS's resolution
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @mf: pixel format to find/negotiate the resolution preset for
- * @type: M-5MOLS resolution type
- * @resolution: M-5MOLS resolution preset register value
- *
- * Find nearest resolution matching resolution preset and adjust mf
- * to supported values.
- */
-static int __find_resolution(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf,
- enum m5mols_restype *type,
- u32 *resolution)
-{
- const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
- const struct m5mols_resolution *match = NULL;
- enum m5mols_restype stype = __find_restype(mf->code);
- int i = ARRAY_SIZE(m5mols_reg_res);
- unsigned int min_err = ~0;
-
- while (i--) {
- int err;
- if (stype == fsize->type) {
- err = abs(fsize->width - mf->width)
- + abs(fsize->height - mf->height);
-
- if (err < min_err) {
- min_err = err;
- match = fsize;
- }
- }
- fsize++;
- }
- if (match) {
- mf->width = match->width;
- mf->height = match->height;
- *resolution = match->reg;
- *type = stype;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which,
- enum m5mols_restype type)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return sd_state ? v4l2_subdev_get_try_format(&info->sd,
- sd_state, 0) : NULL;
-
- return &info->ffmt[type];
-}
-
-static int m5mols_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct m5mols_info *info = to_m5mols(sd);
- struct v4l2_mbus_framefmt *format;
- int ret = 0;
-
- mutex_lock(&info->lock);
-
- format = __find_format(info, sd_state, fmt->which, info->res_type);
- if (format)
- fmt->format = *format;
- else
- ret = -EINVAL;
-
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int m5mols_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct m5mols_info *info = to_m5mols(sd);
- struct v4l2_mbus_framefmt *format = &fmt->format;
- struct v4l2_mbus_framefmt *sfmt;
- enum m5mols_restype type;
- u32 resolution = 0;
- int ret;
-
- ret = __find_resolution(sd, format, &type, &resolution);
- if (ret < 0)
- return ret;
-
- sfmt = __find_format(info, sd_state, fmt->which, type);
- if (!sfmt)
- return 0;
-
- mutex_lock(&info->lock);
-
- format->code = m5mols_default_ffmt[type].code;
- format->colorspace = V4L2_COLORSPACE_JPEG;
- format->field = V4L2_FIELD_NONE;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- *sfmt = *format;
- info->resolution = resolution;
- info->res_type = type;
- }
-
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
- struct v4l2_mbus_frame_desc *fd)
-{
- struct m5mols_info *info = to_m5mols(sd);
-
- if (pad != 0 || fd == NULL)
- return -EINVAL;
-
- mutex_lock(&info->lock);
- /*
- * .get_frame_desc is only used for compressed formats,
- * thus we always return the capture frame parameters here.
- */
- fd->entry[0].length = info->cap.buf_size;
- fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code;
- mutex_unlock(&info->lock);
-
- fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
- fd->num_entries = 1;
-
- return 0;
-}
-
-static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
- struct v4l2_mbus_frame_desc *fd)
-{
- struct m5mols_info *info = to_m5mols(sd);
- struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE];
-
- if (pad != 0 || fd == NULL)
- return -EINVAL;
-
- fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
- fd->num_entries = 1;
- fd->entry[0].length = clamp_t(u32, fd->entry[0].length,
- mf->width * mf->height,
- M5MOLS_MAIN_JPEG_SIZE_MAX);
- mutex_lock(&info->lock);
- info->cap.buf_size = fd->entry[0].length;
- mutex_unlock(&info->lock);
-
- return 0;
-}
-
-
-static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (!code || code->index >= SIZE_DEFAULT_FFMT)
- return -EINVAL;
-
- code->code = m5mols_default_ffmt[code->index].code;
-
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops m5mols_pad_ops = {
- .enum_mbus_code = m5mols_enum_mbus_code,
- .get_fmt = m5mols_get_fmt,
- .set_fmt = m5mols_set_fmt,
- .get_frame_desc = m5mols_get_frame_desc,
- .set_frame_desc = m5mols_set_frame_desc,
-};
-
-/**
- * m5mols_restore_controls - Apply current control values to the registers
- * @info: M-5MOLS driver data structure
- *
- * m5mols_do_scenemode() handles all parameters for which there is yet no
- * individual control. It should be replaced at some point by setting each
- * control individually, in required register set up order.
- */
-int m5mols_restore_controls(struct m5mols_info *info)
-{
- int ret;
-
- if (info->ctrl_sync)
- return 0;
-
- ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
- if (ret)
- return ret;
-
- ret = v4l2_ctrl_handler_setup(&info->handle);
- info->ctrl_sync = !ret;
-
- return ret;
-}
-
-/**
- * m5mols_start_monitor - Start the monitor mode
- * @info: M-5MOLS driver data structure
- *
- * Before applying the controls setup the resolution and frame rate
- * in PARAMETER mode, and then switch over to MONITOR mode.
- */
-static int m5mols_start_monitor(struct m5mols_info *info)
-{
- struct v4l2_subdev *sd = &info->sd;
- int ret;
-
- ret = m5mols_set_mode(info, REG_PARAMETER);
- if (!ret)
- ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
- if (!ret)
- ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
- if (!ret)
- ret = m5mols_set_mode(info, REG_MONITOR);
- if (!ret)
- ret = m5mols_restore_controls(info);
-
- return ret;
-}
-
-static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct m5mols_info *info = to_m5mols(sd);
- u32 code;
- int ret;
-
- mutex_lock(&info->lock);
- code = info->ffmt[info->res_type].code;
-
- if (enable) {
- if (is_code(code, M5MOLS_RESTYPE_MONITOR))
- ret = m5mols_start_monitor(info);
- else if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
- ret = m5mols_start_capture(info);
- else
- ret = -EINVAL;
- } else {
- ret = m5mols_set_mode(info, REG_PARAMETER);
- }
-
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static const struct v4l2_subdev_video_ops m5mols_video_ops = {
- .s_stream = m5mols_s_stream,
-};
-
-static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
-{
- struct v4l2_subdev *sd = &info->sd;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- if (info->power == enable)
- return 0;
-
- if (enable) {
- if (info->set_power) {
- ret = info->set_power(&client->dev, 1);
- if (ret)
- return ret;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
- if (ret) {
- if (info->set_power)
- info->set_power(&client->dev, 0);
- return ret;
- }
-
- gpiod_set_value(info->reset, 0);
- info->power = 1;
-
- return ret;
- }
-
- ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
- if (ret)
- return ret;
-
- if (info->set_power)
- info->set_power(&client->dev, 0);
-
- gpiod_set_value(info->reset, 1);
-
- info->isp_ready = 0;
- info->power = 0;
-
- return ret;
-}
-
-/* m5mols_update_fw - optional firmware update routine */
-int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
- int (*set_power)(struct m5mols_info *, bool))
-{
- return 0;
-}
-
-/**
- * m5mols_fw_start - M-5MOLS internal ARM controller initialization
- * @sd: sub-device, as pointed by struct v4l2_subdev
- *
- * Execute the M-5MOLS internal ARM controller initialization sequence.
- * This function should be called after the supply voltage has been
- * applied and before any requests to the device are made.
- */
-static int m5mols_fw_start(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
- int ret;
-
- atomic_set(&info->irq_done, 0);
- /* Wait until I2C slave is initialized in Flash Writer mode */
- ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
- M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
- if (!ret)
- ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
- if (!ret)
- ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
- if (ret < 0)
- return ret;
-
- info->isp_ready = 1;
-
- ret = m5mols_get_version(sd);
- if (!ret)
- ret = m5mols_update_fw(sd, m5mols_sensor_power);
- if (ret)
- return ret;
-
- v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
-
- ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
- if (!ret)
- ret = m5mols_enable_interrupt(sd,
- REG_INT_AF | REG_INT_CAPTURE);
-
- return ret;
-}
-
-/* Execute the lens soft-landing algorithm */
-static int m5mols_auto_focus_stop(struct m5mols_info *info)
-{
- int ret;
-
- ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
- if (!ret)
- ret = m5mols_write(&info->sd, AF_MODE, REG_AF_POWEROFF);
- if (!ret)
- ret = m5mols_busy_wait(&info->sd, SYSTEM_STATUS, REG_AF_IDLE,
- 0xff, -1);
- return ret;
-}
-
-/**
- * m5mols_s_power - Main sensor power control function
- * @sd: sub-device, as pointed by struct v4l2_subdev
- * @on: if true, powers on the device; powers off otherwise.
- *
- * To prevent breaking the lens when the sensor is powered off the Soft-Landing
- * algorithm is called where available. The Soft-Landing algorithm availability
- * dependends on the firmware provider.
- */
-static int m5mols_s_power(struct v4l2_subdev *sd, int on)
-{
- struct m5mols_info *info = to_m5mols(sd);
- int ret;
-
- mutex_lock(&info->lock);
-
- if (on) {
- ret = m5mols_sensor_power(info, true);
- if (!ret)
- ret = m5mols_fw_start(sd);
- } else {
- if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
- ret = m5mols_set_mode(info, REG_MONITOR);
- if (!ret)
- ret = m5mols_auto_focus_stop(info);
- if (ret < 0)
- v4l2_warn(sd, "Soft landing lens failed\n");
- }
- ret = m5mols_sensor_power(info, false);
-
- info->ctrl_sync = 0;
- }
-
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int m5mols_log_status(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
-
- v4l2_ctrl_handler_log_status(&info->handle, sd->name);
-
- return 0;
-}
-
-static const struct v4l2_subdev_core_ops m5mols_core_ops = {
- .s_power = m5mols_s_power,
- .log_status = m5mols_log_status,
-};
-
-/*
- * V4L2 subdev internal operations
- */
-static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
-
- *format = m5mols_default_ffmt[0];
- return 0;
-}
-
-static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
- .open = m5mols_open,
-};
-
-static const struct v4l2_subdev_ops m5mols_ops = {
- .core = &m5mols_core_ops,
- .pad = &m5mols_pad_ops,
- .video = &m5mols_video_ops,
-};
-
-static irqreturn_t m5mols_irq_handler(int irq, void *data)
-{
- struct m5mols_info *info = to_m5mols(data);
-
- atomic_set(&info->irq_done, 1);
- wake_up_interruptible(&info->irq_waitq);
-
- return IRQ_HANDLED;
-}
-
-static int m5mols_probe(struct i2c_client *client)
-{
- const struct m5mols_platform_data *pdata = client->dev.platform_data;
- struct m5mols_info *info;
- struct v4l2_subdev *sd;
- int ret;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "No platform data\n");
- return -EINVAL;
- }
-
- if (!client->irq) {
- dev_err(&client->dev, "Interrupt not assigned\n");
- return -EINVAL;
- }
-
- info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- /* This asserts reset, descriptor shall have polarity specified */
- info->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(info->reset))
- return PTR_ERR(info->reset);
- /* Notice: the "N" in M5MOLS_NRST implies active low */
- gpiod_set_consumer_name(info->reset, "M5MOLS_NRST");
-
- info->pdata = pdata;
- info->set_power = pdata->set_power;
-
- ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies),
- supplies);
- if (ret) {
- dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
- return ret;
- }
-
- sd = &info->sd;
- v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
- /* Static name; NEVER use in new drivers! */
- strscpy(sd->name, MODULE_NAME, sizeof(sd->name));
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- sd->internal_ops = &m5mols_subdev_internal_ops;
- info->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&sd->entity, 1, &info->pad);
- if (ret < 0)
- return ret;
- sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
- init_waitqueue_head(&info->irq_waitq);
- mutex_init(&info->lock);
-
- ret = devm_request_irq(&client->dev, client->irq, m5mols_irq_handler,
- IRQF_TRIGGER_RISING, MODULE_NAME, sd);
- if (ret) {
- dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
- goto error;
- }
- info->res_type = M5MOLS_RESTYPE_MONITOR;
- info->ffmt[0] = m5mols_default_ffmt[0];
- info->ffmt[1] = m5mols_default_ffmt[1];
-
- ret = m5mols_sensor_power(info, true);
- if (ret)
- goto error;
-
- ret = m5mols_fw_start(sd);
- if (!ret)
- ret = m5mols_init_controls(sd);
-
- ret = m5mols_sensor_power(info, false);
- if (!ret)
- return 0;
-error:
- media_entity_cleanup(&sd->entity);
- return ret;
-}
-
-static void m5mols_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- media_entity_cleanup(&sd->entity);
-}
-
-static const struct i2c_device_id m5mols_id[] = {
- { MODULE_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, m5mols_id);
-
-static struct i2c_driver m5mols_i2c_driver = {
- .driver = {
- .name = MODULE_NAME,
- },
- .probe_new = m5mols_probe,
- .remove = m5mols_remove,
- .id_table = m5mols_id,
-};
-
-module_i2c_driver(m5mols_i2c_driver);
-
-MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
-MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
-MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h
deleted file mode 100644
index 947ee33812d3..000000000000
--- a/drivers/media/i2c/m5mols/m5mols_reg.h
+++ /dev/null
@@ -1,359 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Register map for M-5MOLS 8M Pixel camera sensor with ISP
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- *
- * Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#ifndef M5MOLS_REG_H
-#define M5MOLS_REG_H
-
-#define M5MOLS_I2C_MAX_SIZE 4
-#define M5MOLS_BYTE_READ 0x01
-#define M5MOLS_BYTE_WRITE 0x02
-
-#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff)
-#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff)
-#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff)
-#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s)
-
-/*
- * Category section register
- *
- * The category means set including relevant command of M-5MOLS.
- */
-#define CAT_SYSTEM 0x00
-#define CAT_PARAM 0x01
-#define CAT_MONITOR 0x02
-#define CAT_AE 0x03
-#define CAT_WB 0x06
-#define CAT_EXIF 0x07
-#define CAT_FD 0x09
-#define CAT_LENS 0x0a
-#define CAT_CAPT_PARM 0x0b
-#define CAT_CAPT_CTRL 0x0c
-#define CAT_FLASH 0x0f /* related to FW, revisions, booting */
-
-/*
- * Category 0 - SYSTEM mode
- *
- * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
- * & all-round system of sensor. It deals with version/interrupt/setting mode &
- * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
- * packaging & manufacturer, even the customer and project code. And the
- * function details may vary among them. The version information helps to
- * determine what methods shall be used in the driver.
- *
- * There is many registers between customer version address and awb one. For
- * more specific contents, see definition if file m5mols.h.
- */
-#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1)
-#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1)
-#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2)
-#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2)
-#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2)
-#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2)
-
-#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1)
-#define REG_SYSINIT 0x00 /* SYSTEM mode */
-#define REG_PARAMETER 0x01 /* PARAMETER mode */
-#define REG_MONITOR 0x02 /* MONITOR mode */
-#define REG_CAPTURE 0x03 /* CAPTURE mode */
-
-#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1)
-#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1)
-#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */
-#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */
-#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */
-/* SYSTEM mode status */
-#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1)
-
-/* Interrupt pending register */
-#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1)
-/* interrupt enable register */
-#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1)
-#define REG_INT_MODE (1 << 0)
-#define REG_INT_AF (1 << 1)
-#define REG_INT_ZOOM (1 << 2)
-#define REG_INT_CAPTURE (1 << 3)
-#define REG_INT_FRAMESYNC (1 << 4)
-#define REG_INT_FD (1 << 5)
-#define REG_INT_LENS_INIT (1 << 6)
-#define REG_INT_SOUND (1 << 7)
-#define REG_INT_MASK 0x0f
-
-/*
- * category 1 - PARAMETER mode
- *
- * This category supports function of camera features of M-5MOLS. It means we
- * can handle with preview(MONITOR) resolution size/frame per second/interface
- * between the sensor and the Application Processor/even the image effect.
- */
-
-/* Resolution in the MONITOR mode */
-#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1)
-
-/* Frame rate */
-#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1)
-#define REG_FPS_30 0x02
-
-/* Video bus between the sensor and a host processor */
-#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1)
-#define REG_INTERFACE_MIPI 0x02
-
-/* Image effects */
-#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1)
-#define REG_EFFECT_OFF 0x00
-#define REG_EFFECT_NEGA 0x01
-#define REG_EFFECT_EMBOSS 0x06
-#define REG_EFFECT_OUTLINE 0x07
-#define REG_EFFECT_WATERCOLOR 0x08
-
-/*
- * Category 2 - MONITOR mode
- *
- * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
- * mode named "Preview", but this preview mode is used at the case specific
- * vider-recording mode. This mmode supports only YUYV format. On the other
- * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
- * another options like zoom/color effect(different with effect in PARAMETER
- * mode)/anti hand shaking algorithm.
- */
-
-/* Target digital zoom position */
-#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1)
-
-/* CR value for color effect */
-#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1)
-/* CB value for color effect */
-#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1)
-#define REG_CFIXB_SEPIA 0xd8
-#define REG_CFIXR_SEPIA 0x18
-
-#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1)
-#define REG_COLOR_EFFECT_OFF 0x00
-#define REG_COLOR_EFFECT_ON 0x01
-
-/* Chroma enable */
-#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1)
-/* Chroma level */
-#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1)
-#define REG_CHROMA_OFF 0x00
-#define REG_CHROMA_ON 0x01
-
-/* Sharpness on/off */
-#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1)
-/* Sharpness level */
-#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1)
-#define REG_EDGE_OFF 0x00
-#define REG_EDGE_ON 0x01
-
-/* Set color tone (contrast) */
-#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1)
-
-/*
- * Category 3 - Auto Exposure
- *
- * The M-5MOLS exposure capbility is detailed as which is similar to digital
- * camera. This category supports AE locking/various AE mode(range of exposure)
- * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
- * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
- * different. So, this category also provide getting the max/min values. And,
- * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
- */
-
-/* Auto Exposure locking */
-#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1)
-#define REG_AE_UNLOCK 0x00
-#define REG_AE_LOCK 0x01
-
-/* Auto Exposure algorithm mode */
-#define AE_MODE I2C_REG(CAT_AE, 0x01, 1)
-#define REG_AE_OFF 0x00 /* AE off */
-#define REG_AE_ALL 0x01 /* calc AE in all block integral */
-#define REG_AE_CENTER 0x03 /* calc AE in center weighted */
-#define REG_AE_SPOT 0x06 /* calc AE in specific spot */
-
-#define AE_ISO I2C_REG(CAT_AE, 0x05, 1)
-#define REG_ISO_AUTO 0x00
-#define REG_ISO_50 0x01
-#define REG_ISO_100 0x02
-#define REG_ISO_200 0x03
-#define REG_ISO_400 0x04
-#define REG_ISO_800 0x05
-
-/* EV (scenemode) preset for MONITOR */
-#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1)
-/* EV (scenemode) preset for CAPTURE */
-#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1)
-#define REG_SCENE_NORMAL 0x00
-#define REG_SCENE_PORTRAIT 0x01
-#define REG_SCENE_LANDSCAPE 0x02
-#define REG_SCENE_SPORTS 0x03
-#define REG_SCENE_PARTY_INDOOR 0x04
-#define REG_SCENE_BEACH_SNOW 0x05
-#define REG_SCENE_SUNSET 0x06
-#define REG_SCENE_DAWN_DUSK 0x07
-#define REG_SCENE_FALL 0x08
-#define REG_SCENE_NIGHT 0x09
-#define REG_SCENE_AGAINST_LIGHT 0x0a
-#define REG_SCENE_FIRE 0x0b
-#define REG_SCENE_TEXT 0x0c
-#define REG_SCENE_CANDLE 0x0d
-
-/* Manual gain in MONITOR mode */
-#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2)
-/* Maximum gain in MONITOR mode */
-#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2)
-/* Manual gain in CAPTURE mode */
-#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2)
-
-#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1)
-#define REG_AE_INDEX_20_NEG 0x00
-#define REG_AE_INDEX_15_NEG 0x01
-#define REG_AE_INDEX_10_NEG 0x02
-#define REG_AE_INDEX_05_NEG 0x03
-#define REG_AE_INDEX_00 0x04
-#define REG_AE_INDEX_05_POS 0x05
-#define REG_AE_INDEX_10_POS 0x06
-#define REG_AE_INDEX_15_POS 0x07
-#define REG_AE_INDEX_20_POS 0x08
-
-/*
- * Category 6 - White Balance
- */
-
-/* Auto Whitebalance locking */
-#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1)
-#define REG_AWB_UNLOCK 0x00
-#define REG_AWB_LOCK 0x01
-
-#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1)
-#define REG_AWB_AUTO 0x01 /* AWB off */
-#define REG_AWB_PRESET 0x02 /* AWB preset */
-
-/* Manual WB (preset) */
-#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1)
-#define REG_AWB_INCANDESCENT 0x01
-#define REG_AWB_FLUORESCENT_1 0x02
-#define REG_AWB_FLUORESCENT_2 0x03
-#define REG_AWB_DAYLIGHT 0x04
-#define REG_AWB_CLOUDY 0x05
-#define REG_AWB_SHADE 0x06
-#define REG_AWB_HORIZON 0x07
-#define REG_AWB_LEDLIGHT 0x09
-
-/*
- * Category 7 - EXIF information
- */
-#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4)
-#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4)
-#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4)
-#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4)
-#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4)
-#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4)
-#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4)
-#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4)
-#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4)
-#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4)
-#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2)
-#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2)
-#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2)
-#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2)
-
-/*
- * Category 9 - Face Detection
- */
-#define FD_CTL I2C_REG(CAT_FD, 0x00, 1)
-#define BIT_FD_EN 0
-#define BIT_FD_DRAW_FACE_FRAME 4
-#define BIT_FD_DRAW_SMILE_LVL 6
-#define REG_FD(shift) (1 << shift)
-#define REG_FD_OFF 0x0
-
-/*
- * Category A - Lens Parameter
- */
-#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1)
-#define REG_AF_NORMAL 0x00 /* Normal AF, one time */
-#define REG_AF_MACRO 0x01 /* Macro AF, one time */
-#define REG_AF_POWEROFF 0x07
-
-#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1)
-#define REG_AF_STOP 0x00
-#define REG_AF_EXE_AUTO 0x01
-#define REG_AF_EXE_CAF 0x02
-
-#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1)
-#define REG_AF_FAIL 0x00
-#define REG_AF_SUCCESS 0x02
-#define REG_AF_IDLE 0x04
-#define REG_AF_BUSY 0x05
-
-#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1)
-
-/*
- * Category B - CAPTURE Parameter
- */
-#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1)
-#define REG_YUV422 0x00
-#define REG_BAYER10 0x05
-#define REG_BAYER8 0x06
-#define REG_JPEG 0x10
-
-#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1)
-#define CAPP_JPEG_SIZE_MAX I2C_REG(CAT_CAPT_PARM, 0x0f, 4)
-#define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1)
-
-#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
-#define REG_MCC_OFF 0x00
-#define REG_MCC_NORMAL 0x01
-
-#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1)
-#define REG_WDR_OFF 0x00
-#define REG_WDR_ON 0x01
-#define REG_WDR_AUTO 0x02
-
-#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1)
-#define REG_LIGHT_OFF 0x00
-#define REG_LIGHT_ON 0x01
-#define REG_LIGHT_AUTO 0x02
-
-#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1)
-#define REG_FLASH_OFF 0x00
-#define REG_FLASH_ON 0x01
-#define REG_FLASH_AUTO 0x02
-
-/*
- * Category C - CAPTURE Control
- */
-#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1)
-#define REG_CAP_NONE 0x00
-#define REG_CAP_ANTI_SHAKE 0x02
-
-/* Select single- or multi-shot capture */
-#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1)
-
-#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1)
-#define REG_CAP_START_MAIN 0x01
-#define REG_CAP_START_THUMB 0x03
-
-#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4)
-#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4)
-
-/*
- * Category F - Flash
- *
- * This mode provides functions about internal flash stuff and system startup.
- */
-
-/* Starts internal ARM core booting after power-up */
-#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1)
-#define REG_START_ARM_BOOT 0x01 /* write value */
-#define REG_IN_FLASH_MODE 0x00 /* read value */
-
-#endif /* M5MOLS_REG_H */
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 701038d6d19b..13a986b88588 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -1122,6 +1122,7 @@ err_async:
static void max9286_v4l2_unregister(struct max9286_priv *priv)
{
fwnode_handle_put(priv->sd.fwnode);
+ v4l2_ctrl_handler_free(&priv->ctrls);
v4l2_async_unregister_subdev(&priv->sd);
max9286_v4l2_notifier_unregister(priv);
}
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
deleted file mode 100644
index 958cfdd73d57..000000000000
--- a/drivers/media/i2c/mt9m032.c
+++ /dev/null
@@ -1,891 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for MT9M032 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2010-2011 Lund Engineering
- * Contact: Gil Lund <gwlund@lundeng.com>
- * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
- */
-
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/math64.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/media-entity.h>
-#include <media/i2c/mt9m032.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-
-#include "aptina-pll.h"
-
-/*
- * width and height include active boundary and black parts
- *
- * column 0- 15 active boundary
- * column 16-1455 image
- * column 1456-1471 active boundary
- * column 1472-1599 black
- *
- * row 0- 51 black
- * row 53- 59 active boundary
- * row 60-1139 image
- * row 1140-1147 active boundary
- * row 1148-1151 black
- */
-
-#define MT9M032_PIXEL_ARRAY_WIDTH 1600
-#define MT9M032_PIXEL_ARRAY_HEIGHT 1152
-
-#define MT9M032_CHIP_VERSION 0x00
-#define MT9M032_CHIP_VERSION_VALUE 0x1402
-#define MT9M032_ROW_START 0x01
-#define MT9M032_ROW_START_MIN 0
-#define MT9M032_ROW_START_MAX 1152
-#define MT9M032_ROW_START_DEF 60
-#define MT9M032_COLUMN_START 0x02
-#define MT9M032_COLUMN_START_MIN 0
-#define MT9M032_COLUMN_START_MAX 1600
-#define MT9M032_COLUMN_START_DEF 16
-#define MT9M032_ROW_SIZE 0x03
-#define MT9M032_ROW_SIZE_MIN 32
-#define MT9M032_ROW_SIZE_MAX 1152
-#define MT9M032_ROW_SIZE_DEF 1080
-#define MT9M032_COLUMN_SIZE 0x04
-#define MT9M032_COLUMN_SIZE_MIN 32
-#define MT9M032_COLUMN_SIZE_MAX 1600
-#define MT9M032_COLUMN_SIZE_DEF 1440
-#define MT9M032_HBLANK 0x05
-#define MT9M032_VBLANK 0x06
-#define MT9M032_VBLANK_MAX 0x7ff
-#define MT9M032_SHUTTER_WIDTH_HIGH 0x08
-#define MT9M032_SHUTTER_WIDTH_LOW 0x09
-#define MT9M032_SHUTTER_WIDTH_MIN 1
-#define MT9M032_SHUTTER_WIDTH_MAX 1048575
-#define MT9M032_SHUTTER_WIDTH_DEF 1943
-#define MT9M032_PIX_CLK_CTRL 0x0a
-#define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000
-#define MT9M032_RESTART 0x0b
-#define MT9M032_RESET 0x0d
-#define MT9M032_PLL_CONFIG1 0x11
-#define MT9M032_PLL_CONFIG1_PREDIV_MASK 0x3f
-#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8
-#define MT9M032_READ_MODE1 0x1e
-#define MT9M032_READ_MODE1_OUTPUT_BAD_FRAMES (1 << 13)
-#define MT9M032_READ_MODE1_MAINTAIN_FRAME_RATE (1 << 12)
-#define MT9M032_READ_MODE1_XOR_LINE_VALID (1 << 11)
-#define MT9M032_READ_MODE1_CONT_LINE_VALID (1 << 10)
-#define MT9M032_READ_MODE1_INVERT_TRIGGER (1 << 9)
-#define MT9M032_READ_MODE1_SNAPSHOT (1 << 8)
-#define MT9M032_READ_MODE1_GLOBAL_RESET (1 << 7)
-#define MT9M032_READ_MODE1_BULB_EXPOSURE (1 << 6)
-#define MT9M032_READ_MODE1_INVERT_STROBE (1 << 5)
-#define MT9M032_READ_MODE1_STROBE_ENABLE (1 << 4)
-#define MT9M032_READ_MODE1_STROBE_START_TRIG1 (0 << 2)
-#define MT9M032_READ_MODE1_STROBE_START_EXP (1 << 2)
-#define MT9M032_READ_MODE1_STROBE_START_SHUTTER (2 << 2)
-#define MT9M032_READ_MODE1_STROBE_START_TRIG2 (3 << 2)
-#define MT9M032_READ_MODE1_STROBE_END_TRIG1 (0 << 0)
-#define MT9M032_READ_MODE1_STROBE_END_EXP (1 << 0)
-#define MT9M032_READ_MODE1_STROBE_END_SHUTTER (2 << 0)
-#define MT9M032_READ_MODE1_STROBE_END_TRIG2 (3 << 0)
-#define MT9M032_READ_MODE2 0x20
-#define MT9M032_READ_MODE2_VFLIP_SHIFT 15
-#define MT9M032_READ_MODE2_HFLIP_SHIFT 14
-#define MT9M032_READ_MODE2_ROW_BLC 0x40
-#define MT9M032_GAIN_GREEN1 0x2b
-#define MT9M032_GAIN_BLUE 0x2c
-#define MT9M032_GAIN_RED 0x2d
-#define MT9M032_GAIN_GREEN2 0x2e
-
-/* write only */
-#define MT9M032_GAIN_ALL 0x35
-#define MT9M032_GAIN_DIGITAL_MASK 0x7f
-#define MT9M032_GAIN_DIGITAL_SHIFT 8
-#define MT9M032_GAIN_AMUL_SHIFT 6
-#define MT9M032_GAIN_ANALOG_MASK 0x3f
-#define MT9M032_FORMATTER1 0x9e
-#define MT9M032_FORMATTER1_PLL_P1_6 (1 << 8)
-#define MT9M032_FORMATTER1_PARALLEL (1 << 12)
-#define MT9M032_FORMATTER2 0x9f
-#define MT9M032_FORMATTER2_DOUT_EN 0x1000
-#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000
-
-/*
- * The available MT9M032 datasheet is missing documentation for register 0x10
- * MT9P031 seems to be close enough, so use constants from that datasheet for
- * now.
- * But keep the name MT9P031 to remind us, that this isn't really confirmed
- * for this sensor.
- */
-#define MT9P031_PLL_CONTROL 0x10
-#define MT9P031_PLL_CONTROL_PWROFF 0x0050
-#define MT9P031_PLL_CONTROL_PWRON 0x0051
-#define MT9P031_PLL_CONTROL_USEPLL 0x0052
-
-struct mt9m032 {
- struct v4l2_subdev subdev;
- struct media_pad pad;
- struct mt9m032_platform_data *pdata;
-
- unsigned int pix_clock;
-
- struct v4l2_ctrl_handler ctrls;
- struct {
- struct v4l2_ctrl *hflip;
- struct v4l2_ctrl *vflip;
- };
-
- struct mutex lock; /* Protects streaming, format, interval and crop */
-
- bool streaming;
-
- struct v4l2_mbus_framefmt format;
- struct v4l2_rect crop;
- struct v4l2_fract frame_interval;
-};
-
-#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev)
-#define to_dev(sensor) \
- (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev)
-
-static int mt9m032_read(struct i2c_client *client, u8 reg)
-{
- return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data)
-{
- return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width)
-{
- unsigned int effective_width;
- u32 ns;
-
- effective_width = width + 716; /* empirical value */
- ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock);
- dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns);
- return ns;
-}
-
-static int mt9m032_update_timing(struct mt9m032 *sensor,
- struct v4l2_fract *interval)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- struct v4l2_rect *crop = &sensor->crop;
- unsigned int min_vblank;
- unsigned int vblank;
- u32 row_time;
-
- if (!interval)
- interval = &sensor->frame_interval;
-
- row_time = mt9m032_row_time(sensor, crop->width);
-
- vblank = div_u64(1000000000ULL * interval->numerator,
- (u64)row_time * interval->denominator)
- - crop->height;
-
- if (vblank > MT9M032_VBLANK_MAX) {
- /* hardware limits to 11 bit values */
- interval->denominator = 1000;
- interval->numerator =
- div_u64((crop->height + MT9M032_VBLANK_MAX) *
- (u64)row_time * interval->denominator,
- 1000000000ULL);
- vblank = div_u64(1000000000ULL * interval->numerator,
- (u64)row_time * interval->denominator)
- - crop->height;
- }
- /* enforce minimal 1.6ms blanking time. */
- min_vblank = 1600000 / row_time;
- vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX);
-
- return mt9m032_write(client, MT9M032_VBLANK, vblank);
-}
-
-static int mt9m032_update_geom_timing(struct mt9m032 *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- int ret;
-
- ret = mt9m032_write(client, MT9M032_COLUMN_SIZE,
- sensor->crop.width - 1);
- if (!ret)
- ret = mt9m032_write(client, MT9M032_ROW_SIZE,
- sensor->crop.height - 1);
- if (!ret)
- ret = mt9m032_write(client, MT9M032_COLUMN_START,
- sensor->crop.left);
- if (!ret)
- ret = mt9m032_write(client, MT9M032_ROW_START,
- sensor->crop.top);
- if (!ret)
- ret = mt9m032_update_timing(sensor, NULL);
- return ret;
-}
-
-static int update_formatter2(struct mt9m032 *sensor, bool streaming)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- u16 reg_val = MT9M032_FORMATTER2_DOUT_EN
- | 0x0070; /* parts reserved! */
- /* possibly for changing to 14-bit mode */
-
- if (streaming)
- reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */
-
- return mt9m032_write(client, MT9M032_FORMATTER2, reg_val);
-}
-
-static int mt9m032_setup_pll(struct mt9m032 *sensor)
-{
- static const struct aptina_pll_limits limits = {
- .ext_clock_min = 8000000,
- .ext_clock_max = 16500000,
- .int_clock_min = 2000000,
- .int_clock_max = 24000000,
- .out_clock_min = 322000000,
- .out_clock_max = 693000000,
- .pix_clock_max = 99000000,
- .n_min = 1,
- .n_max = 64,
- .m_min = 16,
- .m_max = 255,
- .p1_min = 6,
- .p1_max = 7,
- };
-
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- struct mt9m032_platform_data *pdata = sensor->pdata;
- struct aptina_pll pll;
- u16 reg_val;
- int ret;
-
- pll.ext_clock = pdata->ext_clock;
- pll.pix_clock = pdata->pix_clock;
-
- ret = aptina_pll_calculate(&client->dev, &limits, &pll);
- if (ret < 0)
- return ret;
-
- sensor->pix_clock = pdata->pix_clock;
-
- ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
- (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) |
- ((pll.n - 1) & MT9M032_PLL_CONFIG1_PREDIV_MASK));
- if (!ret)
- ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
- MT9P031_PLL_CONTROL_PWRON |
- MT9P031_PLL_CONTROL_USEPLL);
- if (!ret) /* more reserved, Continuous, Master Mode */
- ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8000 |
- MT9M032_READ_MODE1_STROBE_START_EXP |
- MT9M032_READ_MODE1_STROBE_END_SHUTTER);
- if (!ret) {
- reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0)
- | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */
- ret = mt9m032_write(client, MT9M032_FORMATTER1, reg_val);
- }
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * Subdev pad operations
- */
-
-static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index != 0)
- return -EINVAL;
-
- code->code = MEDIA_BUS_FMT_Y8_1X8;
- return 0;
-}
-
-static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8)
- return -EINVAL;
-
- fse->min_width = MT9M032_COLUMN_SIZE_DEF;
- fse->max_width = MT9M032_COLUMN_SIZE_DEF;
- fse->min_height = MT9M032_ROW_SIZE_DEF;
- fse->max_height = MT9M032_ROW_SIZE_DEF;
-
- return 0;
-}
-
-/**
- * __mt9m032_get_pad_crop() - get crop rect
- * @sensor: pointer to the sensor struct
- * @sd_state: v4l2_subdev_state for getting the try crop rect from
- * @which: select try or active crop rect
- *
- * Returns a pointer the current active or fh relative try crop rect
- */
-static struct v4l2_rect *
-__mt9m032_get_pad_crop(struct mt9m032 *sensor,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&sensor->subdev, sd_state, 0);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &sensor->crop;
- default:
- return NULL;
- }
-}
-
-/**
- * __mt9m032_get_pad_format() - get format
- * @sensor: pointer to the sensor struct
- * @sd_state: v4l2_subdev_state for getting the try format from
- * @which: select try or active format
- *
- * Returns a pointer the current active or fh relative try format
- */
-static struct v4l2_mbus_framefmt *
-__mt9m032_get_pad_format(struct mt9m032 *sensor,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
- 0);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &sensor->format;
- default:
- return NULL;
- }
-}
-
-static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
-
- mutex_lock(&sensor->lock);
- fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
- mutex_unlock(&sensor->lock);
-
- return 0;
-}
-
-static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
- int ret;
-
- mutex_lock(&sensor->lock);
-
- if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- ret = -EBUSY;
- goto done;
- }
-
- /* Scaling is not supported, the format is thus fixed. */
- fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
- ret = 0;
-
-done:
- mutex_unlock(&sensor->lock);
- return ret;
-}
-
-static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- mutex_lock(&sensor->lock);
- sel->r = *__mt9m032_get_pad_crop(sensor, sd_state, sel->which);
- mutex_unlock(&sensor->lock);
-
- return 0;
-}
-
-static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *__crop;
- struct v4l2_rect rect;
- int ret = 0;
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- mutex_lock(&sensor->lock);
-
- if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- ret = -EBUSY;
- goto done;
- }
-
- /* Clamp the crop rectangle boundaries and align them to a multiple of 2
- * pixels to ensure a GRBG Bayer pattern.
- */
- rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN,
- MT9M032_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN,
- MT9M032_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
- MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
- rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
- MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
-
- rect.width = min_t(unsigned int, rect.width,
- MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
- rect.height = min_t(unsigned int, rect.height,
- MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
-
- __crop = __mt9m032_get_pad_crop(sensor, sd_state, sel->which);
-
- if (rect.width != __crop->width || rect.height != __crop->height) {
- /* Reset the output image size if the crop rectangle size has
- * been modified.
- */
- format = __mt9m032_get_pad_format(sensor, sd_state,
- sel->which);
- format->width = rect.width;
- format->height = rect.height;
- }
-
- *__crop = rect;
- sel->r = rect;
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- ret = mt9m032_update_geom_timing(sensor);
-
-done:
- mutex_unlock(&sensor->lock);
- return ret;
-}
-
-static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
-
- mutex_lock(&sensor->lock);
- memset(fi, 0, sizeof(*fi));
- fi->interval = sensor->frame_interval;
- mutex_unlock(&sensor->lock);
-
- return 0;
-}
-
-static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
- int ret;
-
- mutex_lock(&sensor->lock);
-
- if (sensor->streaming) {
- ret = -EBUSY;
- goto done;
- }
-
- /* Avoid divisions by 0. */
- if (fi->interval.denominator == 0)
- fi->interval.denominator = 1;
-
- ret = mt9m032_update_timing(sensor, &fi->interval);
- if (!ret)
- sensor->frame_interval = fi->interval;
-
-done:
- mutex_unlock(&sensor->lock);
- return ret;
-}
-
-static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming)
-{
- struct mt9m032 *sensor = to_mt9m032(subdev);
- int ret;
-
- mutex_lock(&sensor->lock);
- ret = update_formatter2(sensor, streaming);
- if (!ret)
- sensor->streaming = streaming;
- mutex_unlock(&sensor->lock);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev core operations
- */
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m032_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct mt9m032 *sensor = to_mt9m032(sd);
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- int val;
-
- if (reg->reg > 0xff)
- return -EINVAL;
-
- val = mt9m032_read(client, reg->reg);
- if (val < 0)
- return -EIO;
-
- reg->size = 2;
- reg->val = val;
-
- return 0;
-}
-
-static int mt9m032_s_register(struct v4l2_subdev *sd,
- const struct v4l2_dbg_register *reg)
-{
- struct mt9m032 *sensor = to_mt9m032(sd);
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
-
- if (reg->reg > 0xff)
- return -EINVAL;
-
- return mt9m032_write(client, reg->reg, reg->val);
-}
-#endif
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev control operations
- */
-
-static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT)
- | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT)
- | MT9M032_READ_MODE2_ROW_BLC
- | 0x0007;
-
- return mt9m032_write(client, MT9M032_READ_MODE2, reg_val);
-}
-
-static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- int digital_gain_val; /* in 1/8th (0..127) */
- int analog_mul; /* 0 or 1 */
- int analog_gain_val; /* in 1/16th. (0..63) */
- u16 reg_val;
-
- digital_gain_val = 51; /* from setup example */
-
- if (val < 63) {
- analog_mul = 0;
- analog_gain_val = val;
- } else {
- analog_mul = 1;
- analog_gain_val = val / 2;
- }
-
- /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */
- /* overall_gain = a_gain * (1 + digital_gain_val / 8) */
-
- reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK)
- << MT9M032_GAIN_DIGITAL_SHIFT)
- | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT)
- | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK);
-
- return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val);
-}
-
-static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl)
-{
- if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) {
- /* round because of multiplier used for values >= 63 */
- ctrl->val &= ~1;
- }
-
- return 0;
-}
-
-static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9m032 *sensor =
- container_of(ctrl->handler, struct mt9m032, ctrls);
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- int ret;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- return mt9m032_set_gain(sensor, ctrl->val);
-
- case V4L2_CID_HFLIP:
- /* case V4L2_CID_VFLIP: -- In the same cluster */
- return update_read_mode2(sensor, sensor->vflip->val,
- sensor->hflip->val);
-
- case V4L2_CID_EXPOSURE:
- ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH,
- (ctrl->val >> 16) & 0xffff);
- if (ret < 0)
- return ret;
-
- return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW,
- ctrl->val & 0xffff);
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
- .s_ctrl = mt9m032_set_ctrl,
- .try_ctrl = mt9m032_try_ctrl,
-};
-
-/* -------------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops mt9m032_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9m032_g_register,
- .s_register = mt9m032_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_video_ops mt9m032_video_ops = {
- .s_stream = mt9m032_s_stream,
- .g_frame_interval = mt9m032_get_frame_interval,
- .s_frame_interval = mt9m032_set_frame_interval,
-};
-
-static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
- .enum_mbus_code = mt9m032_enum_mbus_code,
- .enum_frame_size = mt9m032_enum_frame_size,
- .get_fmt = mt9m032_get_pad_format,
- .set_fmt = mt9m032_set_pad_format,
- .set_selection = mt9m032_set_pad_selection,
- .get_selection = mt9m032_get_pad_selection,
-};
-
-static const struct v4l2_subdev_ops mt9m032_ops = {
- .core = &mt9m032_core_ops,
- .video = &mt9m032_video_ops,
- .pad = &mt9m032_pad_ops,
-};
-
-/* -----------------------------------------------------------------------------
- * Driver initialization and probing
- */
-
-static int mt9m032_probe(struct i2c_client *client)
-{
- struct mt9m032_platform_data *pdata = client->dev.platform_data;
- struct i2c_adapter *adapter = client->adapter;
- struct mt9m032 *sensor;
- int chip_version;
- int ret;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "No platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&client->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- if (!client->dev.platform_data)
- return -ENODEV;
-
- sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
- if (sensor == NULL)
- return -ENOMEM;
-
- mutex_init(&sensor->lock);
-
- sensor->pdata = pdata;
-
- v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
- sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
- if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
- dev_err(&client->dev, "MT9M032 not detected, wrong version "
- "0x%04x\n", chip_version);
- ret = -ENODEV;
- goto error_sensor;
- }
-
- dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
- client->addr);
-
- sensor->frame_interval.numerator = 1;
- sensor->frame_interval.denominator = 30;
-
- sensor->crop.left = MT9M032_COLUMN_START_DEF;
- sensor->crop.top = MT9M032_ROW_START_DEF;
- sensor->crop.width = MT9M032_COLUMN_SIZE_DEF;
- sensor->crop.height = MT9M032_ROW_SIZE_DEF;
-
- sensor->format.width = sensor->crop.width;
- sensor->format.height = sensor->crop.height;
- sensor->format.code = MEDIA_BUS_FMT_Y8_1X8;
- sensor->format.field = V4L2_FIELD_NONE;
- sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
-
- v4l2_ctrl_handler_init(&sensor->ctrls, 5);
-
- v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
- V4L2_CID_GAIN, 0, 127, 1, 64);
-
- sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
- &mt9m032_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
- &mt9m032_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
-
- v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
- V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
- MT9M032_SHUTTER_WIDTH_MAX, 1,
- MT9M032_SHUTTER_WIDTH_DEF);
- v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
- V4L2_CID_PIXEL_RATE, pdata->pix_clock,
- pdata->pix_clock, 1, pdata->pix_clock);
-
- if (sensor->ctrls.error) {
- ret = sensor->ctrls.error;
- dev_err(&client->dev, "control initialization error %d\n", ret);
- goto error_ctrl;
- }
-
- v4l2_ctrl_cluster(2, &sensor->hflip);
-
- sensor->subdev.ctrl_handler = &sensor->ctrls;
- sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
- sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
- if (ret < 0)
- goto error_ctrl;
-
- ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */
- if (ret < 0)
- goto error_entity;
- ret = mt9m032_write(client, MT9M032_RESET, 0); /* reset off */
- if (ret < 0)
- goto error_entity;
-
- ret = mt9m032_setup_pll(sensor);
- if (ret < 0)
- goto error_entity;
- usleep_range(10000, 11000);
-
- ret = v4l2_ctrl_handler_setup(&sensor->ctrls);
- if (ret < 0)
- goto error_entity;
-
- /* SIZE */
- ret = mt9m032_update_geom_timing(sensor);
- if (ret < 0)
- goto error_entity;
-
- ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */
- if (ret < 0)
- goto error_entity;
- ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */
- if (ret < 0)
- goto error_entity;
- ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */
- if (ret < 0)
- goto error_entity;
- ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */
- if (ret < 0)
- goto error_entity;
- if (sensor->pdata->invert_pixclock) {
- ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
- MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
- if (ret < 0)
- goto error_entity;
- }
-
- ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
- if (ret < 0)
- goto error_entity;
- msleep(100);
- ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
- if (ret < 0)
- goto error_entity;
- msleep(100);
- ret = update_formatter2(sensor, false);
- if (ret < 0)
- goto error_entity;
-
- return ret;
-
-error_entity:
- media_entity_cleanup(&sensor->subdev.entity);
-error_ctrl:
- v4l2_ctrl_handler_free(&sensor->ctrls);
-error_sensor:
- mutex_destroy(&sensor->lock);
- return ret;
-}
-
-static void mt9m032_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct mt9m032 *sensor = to_mt9m032(subdev);
-
- v4l2_device_unregister_subdev(subdev);
- v4l2_ctrl_handler_free(&sensor->ctrls);
- media_entity_cleanup(&subdev->entity);
- mutex_destroy(&sensor->lock);
-}
-
-static const struct i2c_device_id mt9m032_id_table[] = {
- { MT9M032_NAME, 0 },
- { }
-};
-
-MODULE_DEVICE_TABLE(i2c, mt9m032_id_table);
-
-static struct i2c_driver mt9m032_i2c_driver = {
- .driver = {
- .name = MT9M032_NAME,
- },
- .probe_new = mt9m032_probe,
- .remove = mt9m032_remove,
- .id_table = mt9m032_id_table,
-};
-
-module_i2c_driver(mt9m032_i2c_driver);
-
-MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>");
-MODULE_DESCRIPTION("MT9M032 camera sensor driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
deleted file mode 100644
index c635ed11388a..000000000000
--- a/drivers/media/i2c/mt9t001.c
+++ /dev/null
@@ -1,992 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron)
- *
- * Copyright (C) 2010-2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * Based on the MT9M001 driver,
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- */
-
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/i2c/mt9t001.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-
-#define MT9T001_PIXEL_ARRAY_HEIGHT 1568
-#define MT9T001_PIXEL_ARRAY_WIDTH 2112
-
-#define MT9T001_CHIP_VERSION 0x00
-#define MT9T001_CHIP_ID 0x1621
-#define MT9T001_ROW_START 0x01
-#define MT9T001_ROW_START_MIN 0
-#define MT9T001_ROW_START_DEF 20
-#define MT9T001_ROW_START_MAX 1534
-#define MT9T001_COLUMN_START 0x02
-#define MT9T001_COLUMN_START_MIN 0
-#define MT9T001_COLUMN_START_DEF 32
-#define MT9T001_COLUMN_START_MAX 2046
-#define MT9T001_WINDOW_HEIGHT 0x03
-#define MT9T001_WINDOW_HEIGHT_MIN 1
-#define MT9T001_WINDOW_HEIGHT_DEF 1535
-#define MT9T001_WINDOW_HEIGHT_MAX 1567
-#define MT9T001_WINDOW_WIDTH 0x04
-#define MT9T001_WINDOW_WIDTH_MIN 1
-#define MT9T001_WINDOW_WIDTH_DEF 2047
-#define MT9T001_WINDOW_WIDTH_MAX 2111
-#define MT9T001_HORIZONTAL_BLANKING 0x05
-#define MT9T001_HORIZONTAL_BLANKING_MIN 21
-#define MT9T001_HORIZONTAL_BLANKING_MAX 1023
-#define MT9T001_VERTICAL_BLANKING 0x06
-#define MT9T001_VERTICAL_BLANKING_MIN 3
-#define MT9T001_VERTICAL_BLANKING_MAX 1023
-#define MT9T001_OUTPUT_CONTROL 0x07
-#define MT9T001_OUTPUT_CONTROL_SYNC (1 << 0)
-#define MT9T001_OUTPUT_CONTROL_CHIP_ENABLE (1 << 1)
-#define MT9T001_OUTPUT_CONTROL_TEST_DATA (1 << 6)
-#define MT9T001_OUTPUT_CONTROL_DEF 0x0002
-#define MT9T001_SHUTTER_WIDTH_HIGH 0x08
-#define MT9T001_SHUTTER_WIDTH_LOW 0x09
-#define MT9T001_SHUTTER_WIDTH_MIN 1
-#define MT9T001_SHUTTER_WIDTH_DEF 1561
-#define MT9T001_SHUTTER_WIDTH_MAX (1024 * 1024)
-#define MT9T001_PIXEL_CLOCK 0x0a
-#define MT9T001_PIXEL_CLOCK_INVERT (1 << 15)
-#define MT9T001_PIXEL_CLOCK_SHIFT_MASK (7 << 8)
-#define MT9T001_PIXEL_CLOCK_SHIFT_SHIFT 8
-#define MT9T001_PIXEL_CLOCK_DIVIDE_MASK (0x7f << 0)
-#define MT9T001_FRAME_RESTART 0x0b
-#define MT9T001_SHUTTER_DELAY 0x0c
-#define MT9T001_SHUTTER_DELAY_MAX 2047
-#define MT9T001_RESET 0x0d
-#define MT9T001_READ_MODE1 0x1e
-#define MT9T001_READ_MODE_SNAPSHOT (1 << 8)
-#define MT9T001_READ_MODE_STROBE_ENABLE (1 << 9)
-#define MT9T001_READ_MODE_STROBE_WIDTH (1 << 10)
-#define MT9T001_READ_MODE_STROBE_OVERRIDE (1 << 11)
-#define MT9T001_READ_MODE2 0x20
-#define MT9T001_READ_MODE_BAD_FRAMES (1 << 0)
-#define MT9T001_READ_MODE_LINE_VALID_CONTINUOUS (1 << 9)
-#define MT9T001_READ_MODE_LINE_VALID_FRAME (1 << 10)
-#define MT9T001_READ_MODE3 0x21
-#define MT9T001_READ_MODE_GLOBAL_RESET (1 << 0)
-#define MT9T001_READ_MODE_GHST_CTL (1 << 1)
-#define MT9T001_ROW_ADDRESS_MODE 0x22
-#define MT9T001_ROW_SKIP_MASK (7 << 0)
-#define MT9T001_ROW_BIN_MASK (3 << 3)
-#define MT9T001_ROW_BIN_SHIFT 3
-#define MT9T001_COLUMN_ADDRESS_MODE 0x23
-#define MT9T001_COLUMN_SKIP_MASK (7 << 0)
-#define MT9T001_COLUMN_BIN_MASK (3 << 3)
-#define MT9T001_COLUMN_BIN_SHIFT 3
-#define MT9T001_GREEN1_GAIN 0x2b
-#define MT9T001_BLUE_GAIN 0x2c
-#define MT9T001_RED_GAIN 0x2d
-#define MT9T001_GREEN2_GAIN 0x2e
-#define MT9T001_TEST_DATA 0x32
-#define MT9T001_GLOBAL_GAIN 0x35
-#define MT9T001_GLOBAL_GAIN_MIN 8
-#define MT9T001_GLOBAL_GAIN_MAX 1024
-#define MT9T001_BLACK_LEVEL 0x49
-#define MT9T001_ROW_BLACK_DEFAULT_OFFSET 0x4b
-#define MT9T001_BLC_DELTA_THRESHOLDS 0x5d
-#define MT9T001_CAL_THRESHOLDS 0x5f
-#define MT9T001_GREEN1_OFFSET 0x60
-#define MT9T001_GREEN2_OFFSET 0x61
-#define MT9T001_BLACK_LEVEL_CALIBRATION 0x62
-#define MT9T001_BLACK_LEVEL_OVERRIDE (1 << 0)
-#define MT9T001_BLACK_LEVEL_DISABLE_OFFSET (1 << 1)
-#define MT9T001_BLACK_LEVEL_RECALCULATE (1 << 12)
-#define MT9T001_BLACK_LEVEL_LOCK_RED_BLUE (1 << 13)
-#define MT9T001_BLACK_LEVEL_LOCK_GREEN (1 << 14)
-#define MT9T001_RED_OFFSET 0x63
-#define MT9T001_BLUE_OFFSET 0x64
-
-struct mt9t001 {
- struct v4l2_subdev subdev;
- struct media_pad pad;
-
- struct clk *clk;
- struct regulator_bulk_data regulators[2];
-
- struct mutex power_lock; /* lock to protect power_count */
- int power_count;
-
- struct v4l2_mbus_framefmt format;
- struct v4l2_rect crop;
-
- struct v4l2_ctrl_handler ctrls;
- struct v4l2_ctrl *gains[4];
-
- u16 output_control;
- u16 black_level;
-};
-
-static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct mt9t001, subdev);
-}
-
-static int mt9t001_read(struct i2c_client *client, u8 reg)
-{
- return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data)
-{
- return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
- u16 set)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
- u16 value = (mt9t001->output_control & ~clear) | set;
- int ret;
-
- if (value == mt9t001->output_control)
- return 0;
-
- ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, value);
- if (ret < 0)
- return ret;
-
- mt9t001->output_control = value;
- return 0;
-}
-
-static int mt9t001_reset(struct mt9t001 *mt9t001)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
- int ret;
-
- /* Reset the chip and stop data read out */
- ret = mt9t001_write(client, MT9T001_RESET, 1);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_RESET, 0);
- if (ret < 0)
- return ret;
-
- mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
-
- return mt9t001_set_output_control(mt9t001,
- MT9T001_OUTPUT_CONTROL_CHIP_ENABLE,
- 0);
-}
-
-static int mt9t001_power_on(struct mt9t001 *mt9t001)
-{
- int ret;
-
- /* Bring up the supplies */
- ret = regulator_bulk_enable(ARRAY_SIZE(mt9t001->regulators),
- mt9t001->regulators);
- if (ret < 0)
- return ret;
-
- /* Enable clock */
- ret = clk_prepare_enable(mt9t001->clk);
- if (ret < 0)
- regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
- mt9t001->regulators);
-
- return ret;
-}
-
-static void mt9t001_power_off(struct mt9t001 *mt9t001)
-{
- regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
- mt9t001->regulators);
-
- clk_disable_unprepare(mt9t001->clk);
-}
-
-static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
- int ret;
-
- if (!on) {
- mt9t001_power_off(mt9t001);
- return 0;
- }
-
- ret = mt9t001_power_on(mt9t001);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_reset(mt9t001);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to reset the camera\n");
- goto e_power;
- }
-
- ret = v4l2_ctrl_handler_setup(&mt9t001->ctrls);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to set up control handlers\n");
- goto e_power;
- }
-
- return 0;
-
-e_power:
- mt9t001_power_off(mt9t001);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev video operations
- */
-
-static struct v4l2_mbus_framefmt *
-__mt9t001_get_pad_format(struct mt9t001 *mt9t001,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9t001->subdev, sd_state,
- pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &mt9t001->format;
- default:
- return NULL;
- }
-}
-
-static struct v4l2_rect *
-__mt9t001_get_pad_crop(struct mt9t001 *mt9t001,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9t001->subdev, sd_state,
- pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &mt9t001->crop;
- default:
- return NULL;
- }
-}
-
-static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
-{
- const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE;
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct mt9t001_platform_data *pdata = client->dev.platform_data;
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- struct v4l2_mbus_framefmt *format = &mt9t001->format;
- struct v4l2_rect *crop = &mt9t001->crop;
- unsigned int hratio;
- unsigned int vratio;
- int ret;
-
- if (!enable)
- return mt9t001_set_output_control(mt9t001, mode, 0);
-
- /* Configure the pixel clock polarity */
- if (pdata->clk_pol) {
- ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
- MT9T001_PIXEL_CLOCK_INVERT);
- if (ret < 0)
- return ret;
- }
-
- /* Configure the window size and row/column bin */
- hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
- vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
-
- ret = mt9t001_write(client, MT9T001_ROW_ADDRESS_MODE, hratio - 1);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_COLUMN_ADDRESS_MODE, vratio - 1);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_COLUMN_START, crop->left);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_ROW_START, crop->top);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_WINDOW_WIDTH, crop->width - 1);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_WINDOW_HEIGHT, crop->height - 1);
- if (ret < 0)
- return ret;
-
- /* Switch to master "normal" mode */
- return mt9t001_set_output_control(mt9t001, 0, mode);
-}
-
-static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index > 0)
- return -EINVAL;
-
- code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
- return 0;
-}
-
-static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
- return -EINVAL;
-
- fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index;
- fse->max_width = fse->min_width;
- fse->min_height = (MT9T001_WINDOW_HEIGHT_DEF + 1) / fse->index;
- fse->max_height = fse->min_height;
-
- return 0;
-}
-
-static int mt9t001_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
-
- format->format = *__mt9t001_get_pad_format(mt9t001, sd_state,
- format->pad,
- format->which);
- return 0;
-}
-
-static int mt9t001_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- struct v4l2_mbus_framefmt *__format;
- struct v4l2_rect *__crop;
- unsigned int width;
- unsigned int height;
- unsigned int hratio;
- unsigned int vratio;
-
- __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, format->pad,
- format->which);
-
- /* Clamp the width and height to avoid dividing by zero. */
- width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
- max_t(unsigned int, __crop->width / 8,
- MT9T001_WINDOW_HEIGHT_MIN + 1),
- __crop->width);
- height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
- max_t(unsigned int, __crop->height / 8,
- MT9T001_WINDOW_HEIGHT_MIN + 1),
- __crop->height);
-
- hratio = DIV_ROUND_CLOSEST(__crop->width, width);
- vratio = DIV_ROUND_CLOSEST(__crop->height, height);
-
- __format = __mt9t001_get_pad_format(mt9t001, sd_state, format->pad,
- format->which);
- __format->width = __crop->width / hratio;
- __format->height = __crop->height / vratio;
-
- format->format = *__format;
-
- return 0;
-}
-
-static int mt9t001_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- sel->r = *__mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
- sel->which);
- return 0;
-}
-
-static int mt9t001_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- struct v4l2_mbus_framefmt *__format;
- struct v4l2_rect *__crop;
- struct v4l2_rect rect;
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- /* Clamp the crop rectangle boundaries and align them to a multiple of 2
- * pixels.
- */
- rect.left = clamp(ALIGN(sel->r.left, 2),
- MT9T001_COLUMN_START_MIN,
- MT9T001_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(sel->r.top, 2),
- MT9T001_ROW_START_MIN,
- MT9T001_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
- MT9T001_WINDOW_WIDTH_MIN + 1,
- MT9T001_WINDOW_WIDTH_MAX + 1);
- rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
- MT9T001_WINDOW_HEIGHT_MIN + 1,
- MT9T001_WINDOW_HEIGHT_MAX + 1);
-
- rect.width = min_t(unsigned int, rect.width,
- MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
- rect.height = min_t(unsigned int, rect.height,
- MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
-
- __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
- sel->which);
-
- if (rect.width != __crop->width || rect.height != __crop->height) {
- /* Reset the output image size if the crop rectangle size has
- * been modified.
- */
- __format = __mt9t001_get_pad_format(mt9t001, sd_state,
- sel->pad,
- sel->which);
- __format->width = rect.width;
- __format->height = rect.height;
- }
-
- *__crop = rect;
- sel->r = rect;
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev control operations
- */
-
-#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001)
-#define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002)
-#define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003)
-#define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004)
-
-#define V4L2_CID_GAIN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1001)
-#define V4L2_CID_GAIN_GREEN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1002)
-#define V4L2_CID_GAIN_GREEN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1003)
-#define V4L2_CID_GAIN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1004)
-
-static u16 mt9t001_gain_value(s32 *gain)
-{
- /* Gain is controlled by 2 analog stages and a digital stage. Valid
- * values for the 3 stages are
- *
- * Stage Min Max Step
- * ------------------------------------------
- * First analog stage x1 x2 1
- * Second analog stage x1 x4 0.125
- * Digital stage x1 x16 0.125
- *
- * To minimize noise, the gain stages should be used in the second
- * analog stage, first analog stage, digital stage order. Gain from a
- * previous stage should be pushed to its maximum value before the next
- * stage is used.
- */
- if (*gain <= 32)
- return *gain;
-
- if (*gain <= 64) {
- *gain &= ~1;
- return (1 << 6) | (*gain >> 1);
- }
-
- *gain &= ~7;
- return ((*gain - 64) << 5) | (1 << 6) | 32;
-}
-
-static int mt9t001_ctrl_freeze(struct mt9t001 *mt9t001, bool freeze)
-{
- return mt9t001_set_output_control(mt9t001,
- freeze ? 0 : MT9T001_OUTPUT_CONTROL_SYNC,
- freeze ? MT9T001_OUTPUT_CONTROL_SYNC : 0);
-}
-
-static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- static const u8 gains[4] = {
- MT9T001_RED_GAIN, MT9T001_GREEN1_GAIN,
- MT9T001_GREEN2_GAIN, MT9T001_BLUE_GAIN
- };
-
- struct mt9t001 *mt9t001 =
- container_of(ctrl->handler, struct mt9t001, ctrls);
- struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
- unsigned int count;
- unsigned int i;
- u16 value;
- int ret;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN_RED:
- case V4L2_CID_GAIN_GREEN_RED:
- case V4L2_CID_GAIN_GREEN_BLUE:
- case V4L2_CID_GAIN_BLUE:
-
- /* Disable control updates if more than one control has changed
- * in the cluster.
- */
- for (i = 0, count = 0; i < 4; ++i) {
- struct v4l2_ctrl *gain = mt9t001->gains[i];
-
- if (gain->val != gain->cur.val)
- count++;
- }
-
- if (count > 1) {
- ret = mt9t001_ctrl_freeze(mt9t001, true);
- if (ret < 0)
- return ret;
- }
-
- /* Update the gain controls. */
- for (i = 0; i < 4; ++i) {
- struct v4l2_ctrl *gain = mt9t001->gains[i];
-
- if (gain->val == gain->cur.val)
- continue;
-
- value = mt9t001_gain_value(&gain->val);
- ret = mt9t001_write(client, gains[i], value);
- if (ret < 0) {
- mt9t001_ctrl_freeze(mt9t001, false);
- return ret;
- }
- }
-
- /* Enable control updates. */
- if (count > 1) {
- ret = mt9t001_ctrl_freeze(mt9t001, false);
- if (ret < 0)
- return ret;
- }
-
- break;
-
- case V4L2_CID_EXPOSURE:
- ret = mt9t001_write(client, MT9T001_SHUTTER_WIDTH_LOW,
- ctrl->val & 0xffff);
- if (ret < 0)
- return ret;
-
- return mt9t001_write(client, MT9T001_SHUTTER_WIDTH_HIGH,
- ctrl->val >> 16);
-
- case V4L2_CID_TEST_PATTERN:
- return mt9t001_set_output_control(mt9t001,
- ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA,
- ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0);
-
- case V4L2_CID_TEST_PATTERN_COLOR:
- return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2);
-
- case V4L2_CID_BLACK_LEVEL_AUTO:
- value = ctrl->val ? 0 : MT9T001_BLACK_LEVEL_OVERRIDE;
- ret = mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
- value);
- if (ret < 0)
- return ret;
-
- mt9t001->black_level = value;
- break;
-
- case V4L2_CID_BLACK_LEVEL_OFFSET:
- ret = mt9t001_write(client, MT9T001_GREEN1_OFFSET, ctrl->val);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_GREEN2_OFFSET, ctrl->val);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_RED_OFFSET, ctrl->val);
- if (ret < 0)
- return ret;
-
- return mt9t001_write(client, MT9T001_BLUE_OFFSET, ctrl->val);
-
- case V4L2_CID_BLACK_LEVEL_CALIBRATE:
- return mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION,
- MT9T001_BLACK_LEVEL_RECALCULATE |
- mt9t001->black_level);
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
- .s_ctrl = mt9t001_s_ctrl,
-};
-
-static const char * const mt9t001_test_pattern_menu[] = {
- "Disabled",
- "Enabled",
-};
-
-static const struct v4l2_ctrl_config mt9t001_ctrls[] = {
- {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_TEST_PATTERN_COLOR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Test Pattern Color",
- .min = 0,
- .max = 1023,
- .step = 1,
- .def = 0,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_BLACK_LEVEL_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Black Level, Auto",
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 1,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_BLACK_LEVEL_OFFSET,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Black Level, Offset",
- .min = -256,
- .max = 255,
- .step = 1,
- .def = 32,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_BLACK_LEVEL_CALIBRATE,
- .type = V4L2_CTRL_TYPE_BUTTON,
- .name = "Black Level, Calibrate",
- .min = 0,
- .max = 0,
- .step = 0,
- .def = 0,
- .flags = V4L2_CTRL_FLAG_WRITE_ONLY,
- },
-};
-
-static const struct v4l2_ctrl_config mt9t001_gains[] = {
- {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_GAIN_RED,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Red",
- .min = MT9T001_GLOBAL_GAIN_MIN,
- .max = MT9T001_GLOBAL_GAIN_MAX,
- .step = 1,
- .def = MT9T001_GLOBAL_GAIN_MIN,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_GAIN_GREEN_RED,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Green (R)",
- .min = MT9T001_GLOBAL_GAIN_MIN,
- .max = MT9T001_GLOBAL_GAIN_MAX,
- .step = 1,
- .def = MT9T001_GLOBAL_GAIN_MIN,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_GAIN_GREEN_BLUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Green (B)",
- .min = MT9T001_GLOBAL_GAIN_MIN,
- .max = MT9T001_GLOBAL_GAIN_MAX,
- .step = 1,
- .def = MT9T001_GLOBAL_GAIN_MIN,
- .flags = 0,
- }, {
- .ops = &mt9t001_ctrl_ops,
- .id = V4L2_CID_GAIN_BLUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Blue",
- .min = MT9T001_GLOBAL_GAIN_MIN,
- .max = MT9T001_GLOBAL_GAIN_MAX,
- .step = 1,
- .def = MT9T001_GLOBAL_GAIN_MIN,
- .flags = 0,
- },
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev core operations
- */
-
-static int mt9t001_set_power(struct v4l2_subdev *subdev, int on)
-{
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- int ret = 0;
-
- mutex_lock(&mt9t001->power_lock);
-
- /* If the power count is modified from 0 to != 0 or from != 0 to 0,
- * update the power state.
- */
- if (mt9t001->power_count == !on) {
- ret = __mt9t001_set_power(mt9t001, !!on);
- if (ret < 0)
- goto out;
- }
-
- /* Update the power count. */
- mt9t001->power_count += on ? 1 : -1;
- WARN_ON(mt9t001->power_count < 0);
-
-out:
- mutex_unlock(&mt9t001->power_lock);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev internal operations
- */
-
-static int mt9t001_registered(struct v4l2_subdev *subdev)
-{
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- s32 data;
- int ret;
-
- ret = mt9t001_power_on(mt9t001);
- if (ret < 0) {
- dev_err(&client->dev, "MT9T001 power up failed\n");
- return ret;
- }
-
- /* Read out the chip version register */
- data = mt9t001_read(client, MT9T001_CHIP_VERSION);
- mt9t001_power_off(mt9t001);
-
- if (data != MT9T001_CHIP_ID) {
- dev_err(&client->dev,
- "MT9T001 not detected, wrong version 0x%04x\n", data);
- return -ENODEV;
- }
-
- dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
- client->addr);
-
- return 0;
-}
-
-static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *crop;
-
- crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
- crop->left = MT9T001_COLUMN_START_DEF;
- crop->top = MT9T001_ROW_START_DEF;
- crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
- crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
-
- format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
- format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
- format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
- format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
- format->field = V4L2_FIELD_NONE;
- format->colorspace = V4L2_COLORSPACE_SRGB;
-
- return mt9t001_set_power(subdev, 1);
-}
-
-static int mt9t001_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
-{
- return mt9t001_set_power(subdev, 0);
-}
-
-static const struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = {
- .s_power = mt9t001_set_power,
-};
-
-static const struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = {
- .s_stream = mt9t001_s_stream,
-};
-
-static const struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
- .enum_mbus_code = mt9t001_enum_mbus_code,
- .enum_frame_size = mt9t001_enum_frame_size,
- .get_fmt = mt9t001_get_format,
- .set_fmt = mt9t001_set_format,
- .get_selection = mt9t001_get_selection,
- .set_selection = mt9t001_set_selection,
-};
-
-static const struct v4l2_subdev_ops mt9t001_subdev_ops = {
- .core = &mt9t001_subdev_core_ops,
- .video = &mt9t001_subdev_video_ops,
- .pad = &mt9t001_subdev_pad_ops,
-};
-
-static const struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
- .registered = mt9t001_registered,
- .open = mt9t001_open,
- .close = mt9t001_close,
-};
-
-static int mt9t001_probe(struct i2c_client *client)
-{
- struct mt9t001_platform_data *pdata = client->dev.platform_data;
- struct mt9t001 *mt9t001;
- unsigned int i;
- int ret;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "No platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&client->adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL);
- if (!mt9t001)
- return -ENOMEM;
-
- mutex_init(&mt9t001->power_lock);
- mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
-
- mt9t001->regulators[0].supply = "vdd";
- mt9t001->regulators[1].supply = "vaa";
-
- ret = devm_regulator_bulk_get(&client->dev, 2, mt9t001->regulators);
- if (ret < 0) {
- dev_err(&client->dev, "Unable to get regulators\n");
- return ret;
- }
-
- mt9t001->clk = devm_clk_get(&client->dev, NULL);
- if (IS_ERR(mt9t001->clk)) {
- dev_err(&client->dev, "Unable to get clock\n");
- return PTR_ERR(mt9t001->clk);
- }
-
- v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
- ARRAY_SIZE(mt9t001_gains) + 4);
-
- v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
- V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN,
- MT9T001_SHUTTER_WIDTH_MAX, 1,
- MT9T001_SHUTTER_WIDTH_DEF);
- v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
- V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1);
- v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
- V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk,
- 1, pdata->ext_clk);
- v4l2_ctrl_new_std_menu_items(&mt9t001->ctrls, &mt9t001_ctrl_ops,
- V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(mt9t001_test_pattern_menu) - 1, 0,
- 0, mt9t001_test_pattern_menu);
-
- for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i)
- v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL);
-
- for (i = 0; i < ARRAY_SIZE(mt9t001_gains); ++i)
- mt9t001->gains[i] = v4l2_ctrl_new_custom(&mt9t001->ctrls,
- &mt9t001_gains[i], NULL);
-
- v4l2_ctrl_cluster(ARRAY_SIZE(mt9t001_gains), mt9t001->gains);
-
- mt9t001->subdev.ctrl_handler = &mt9t001->ctrls;
-
- if (mt9t001->ctrls.error) {
- printk(KERN_INFO "%s: control initialization error %d\n",
- __func__, mt9t001->ctrls.error);
- ret = -EINVAL;
- goto done;
- }
-
- mt9t001->crop.left = MT9T001_COLUMN_START_DEF;
- mt9t001->crop.top = MT9T001_ROW_START_DEF;
- mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1;
- mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
-
- mt9t001->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
- mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1;
- mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
- mt9t001->format.field = V4L2_FIELD_NONE;
- mt9t001->format.colorspace = V4L2_COLORSPACE_SRGB;
-
- v4l2_i2c_subdev_init(&mt9t001->subdev, client, &mt9t001_subdev_ops);
- mt9t001->subdev.internal_ops = &mt9t001_subdev_internal_ops;
- mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- mt9t001->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
- mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&mt9t001->subdev.entity, 1, &mt9t001->pad);
-
-done:
- if (ret < 0) {
- v4l2_ctrl_handler_free(&mt9t001->ctrls);
- media_entity_cleanup(&mt9t001->subdev.entity);
- }
-
- return ret;
-}
-
-static void mt9t001_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct mt9t001 *mt9t001 = to_mt9t001(subdev);
-
- v4l2_ctrl_handler_free(&mt9t001->ctrls);
- v4l2_device_unregister_subdev(subdev);
- media_entity_cleanup(&subdev->entity);
-}
-
-static const struct i2c_device_id mt9t001_id[] = {
- { "mt9t001", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9t001_id);
-
-static struct i2c_driver mt9t001_driver = {
- .driver = {
- .name = "mt9t001",
- },
- .probe_new = mt9t001_probe,
- .remove = mt9t001_remove,
- .id_table = mt9t001_id,
-};
-
-module_i2c_driver(mt9t001_driver);
-
-MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
-MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
deleted file mode 100644
index 144bef2835f7..000000000000
--- a/drivers/media/i2c/noon010pc30.c
+++ /dev/null
@@ -1,821 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
- *
- * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
- *
- * Initial register configuration based on a driver authored by
- * HeungJun Kim <riverful.kim@samsung.com>.
- */
-
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <media/i2c/noon010pc30.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-mediabus.h>
-#include <media/v4l2-subdev.h>
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable.");
-
-#define MODULE_NAME "NOON010PC30"
-
-/*
- * Register offsets within a page
- * b15..b8 - page id, b7..b0 - register address
- */
-#define POWER_CTRL_REG 0x0001
-#define PAGEMODE_REG 0x03
-#define DEVICE_ID_REG 0x0004
-#define NOON010PC30_ID 0x86
-#define VDO_CTL_REG(n) (0x0010 + (n))
-#define SYNC_CTL_REG 0x0012
-/* Window size and position */
-#define WIN_ROWH_REG 0x0013
-#define WIN_ROWL_REG 0x0014
-#define WIN_COLH_REG 0x0015
-#define WIN_COLL_REG 0x0016
-#define WIN_HEIGHTH_REG 0x0017
-#define WIN_HEIGHTL_REG 0x0018
-#define WIN_WIDTHH_REG 0x0019
-#define WIN_WIDTHL_REG 0x001A
-#define HBLANKH_REG 0x001B
-#define HBLANKL_REG 0x001C
-#define VSYNCH_REG 0x001D
-#define VSYNCL_REG 0x001E
-/* VSYNC control */
-#define VS_CTL_REG(n) (0x00A1 + (n))
-/* page 1 */
-#define ISP_CTL_REG(n) (0x0110 + (n))
-#define YOFS_REG 0x0119
-#define DARK_YOFS_REG 0x011A
-#define SAT_CTL_REG 0x0120
-#define BSAT_REG 0x0121
-#define RSAT_REG 0x0122
-/* Color correction */
-#define CMC_CTL_REG 0x0130
-#define CMC_OFSGH_REG 0x0133
-#define CMC_OFSGL_REG 0x0135
-#define CMC_SIGN_REG 0x0136
-#define CMC_GOFS_REG 0x0137
-#define CMC_COEF_REG(n) (0x0138 + (n))
-#define CMC_OFS_REG(n) (0x0141 + (n))
-/* Gamma correction */
-#define GMA_CTL_REG 0x0160
-#define GMA_COEF_REG(n) (0x0161 + (n))
-/* Lens Shading */
-#define LENS_CTRL_REG 0x01D0
-#define LENS_XCEN_REG 0x01D1
-#define LENS_YCEN_REG 0x01D2
-#define LENS_RC_REG 0x01D3
-#define LENS_GC_REG 0x01D4
-#define LENS_BC_REG 0x01D5
-#define L_AGON_REG 0x01D6
-#define L_AGOFF_REG 0x01D7
-/* Page 3 - Auto Exposure */
-#define AE_CTL_REG(n) (0x0310 + (n))
-#define AE_CTL9_REG 0x032C
-#define AE_CTL10_REG 0x032D
-#define AE_YLVL_REG 0x031C
-#define AE_YTH_REG(n) (0x031D + (n))
-#define AE_WGT_REG 0x0326
-#define EXP_TIMEH_REG 0x0333
-#define EXP_TIMEM_REG 0x0334
-#define EXP_TIMEL_REG 0x0335
-#define EXP_MMINH_REG 0x0336
-#define EXP_MMINL_REG 0x0337
-#define EXP_MMAXH_REG 0x0338
-#define EXP_MMAXM_REG 0x0339
-#define EXP_MMAXL_REG 0x033A
-/* Page 4 - Auto White Balance */
-#define AWB_CTL_REG(n) (0x0410 + (n))
-#define AWB_ENABE 0x80
-#define AWB_WGHT_REG 0x0419
-#define BGAIN_PAR_REG(n) (0x044F + (n))
-/* Manual white balance, when AWB_CTL2[0]=1 */
-#define MWB_RGAIN_REG 0x0466
-#define MWB_BGAIN_REG 0x0467
-
-/* The token to mark an array end */
-#define REG_TERM 0xFFFF
-
-struct noon010_format {
- u32 code;
- enum v4l2_colorspace colorspace;
- u16 ispctl1_reg;
-};
-
-struct noon010_frmsize {
- u16 width;
- u16 height;
- int vid_ctl1;
-};
-
-static const char * const noon010_supply_name[] = {
- "vdd_core", "vddio", "vdda"
-};
-
-#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name)
-
-struct noon010_info {
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_ctrl_handler hdl;
- struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
- struct gpio_desc *reset;
- struct gpio_desc *stby;
-
- /* Protects the struct members below */
- struct mutex lock;
-
- const struct noon010_format *curr_fmt;
- const struct noon010_frmsize *curr_win;
- unsigned int apply_new_cfg:1;
- unsigned int streaming:1;
- unsigned int hflip:1;
- unsigned int vflip:1;
- unsigned int power:1;
- u8 i2c_reg_page;
-};
-
-struct i2c_regval {
- u16 addr;
- u16 val;
-};
-
-/* Supported resolutions. */
-static const struct noon010_frmsize noon010_sizes[] = {
- {
- .width = 352,
- .height = 288,
- .vid_ctl1 = 0,
- }, {
- .width = 176,
- .height = 144,
- .vid_ctl1 = 0x10,
- }, {
- .width = 88,
- .height = 72,
- .vid_ctl1 = 0x20,
- },
-};
-
-/* Supported pixel formats. */
-static const struct noon010_format noon010_formats[] = {
- {
- .code = MEDIA_BUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x03,
- }, {
- .code = MEDIA_BUS_FMT_YVYU8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x02,
- }, {
- .code = MEDIA_BUS_FMT_VYUY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0,
- }, {
- .code = MEDIA_BUS_FMT_UYVY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x01,
- }, {
- .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x40,
- },
-};
-
-static const struct i2c_regval noon010_base_regs[] = {
- { WIN_COLL_REG, 0x06 }, { HBLANKL_REG, 0x7C },
- /* Color corection and saturation */
- { ISP_CTL_REG(0), 0x30 }, { ISP_CTL_REG(2), 0x30 },
- { YOFS_REG, 0x80 }, { DARK_YOFS_REG, 0x04 },
- { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 },
- { CMC_CTL_REG, 0x0F }, { CMC_OFSGH_REG, 0x3C },
- { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x3F },
- { CMC_COEF_REG(0), 0x79 }, { CMC_OFS_REG(0), 0x00 },
- { CMC_COEF_REG(1), 0x39 }, { CMC_OFS_REG(1), 0x00 },
- { CMC_COEF_REG(2), 0x00 }, { CMC_OFS_REG(2), 0x00 },
- { CMC_COEF_REG(3), 0x11 }, { CMC_OFS_REG(3), 0x8B },
- { CMC_COEF_REG(4), 0x65 }, { CMC_OFS_REG(4), 0x07 },
- { CMC_COEF_REG(5), 0x14 }, { CMC_OFS_REG(5), 0x04 },
- { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x9C },
- { CMC_COEF_REG(7), 0x33 }, { CMC_OFS_REG(7), 0x89 },
- { CMC_COEF_REG(8), 0x74 }, { CMC_OFS_REG(8), 0x25 },
- /* Automatic white balance */
- { AWB_CTL_REG(0), 0x78 }, { AWB_CTL_REG(1), 0x2E },
- { AWB_CTL_REG(2), 0x20 }, { AWB_CTL_REG(3), 0x85 },
- /* Auto exposure */
- { AE_CTL_REG(0), 0xDC }, { AE_CTL_REG(1), 0x81 },
- { AE_CTL_REG(2), 0x30 }, { AE_CTL_REG(3), 0xA5 },
- { AE_CTL_REG(4), 0x40 }, { AE_CTL_REG(5), 0x51 },
- { AE_CTL_REG(6), 0x33 }, { AE_CTL_REG(7), 0x7E },
- { AE_CTL9_REG, 0x00 }, { AE_CTL10_REG, 0x02 },
- { AE_YLVL_REG, 0x44 }, { AE_YTH_REG(0), 0x34 },
- { AE_YTH_REG(1), 0x30 }, { AE_WGT_REG, 0xD5 },
- /* Lens shading compensation */
- { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 },
- { LENS_YCEN_REG, 0x70 }, { LENS_RC_REG, 0x53 },
- { LENS_GC_REG, 0x40 }, { LENS_BC_REG, 0x3E },
- { REG_TERM, 0 },
-};
-
-static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct noon010_info, sd);
-}
-
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct noon010_info, hdl)->sd;
-}
-
-static inline int set_i2c_page(struct noon010_info *info,
- struct i2c_client *client, unsigned int reg)
-{
- u32 page = reg >> 8 & 0xFF;
- int ret = 0;
-
- if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
- ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
- if (!ret)
- info->i2c_reg_page = page;
- }
- return ret;
-}
-
-static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct noon010_info *info = to_noon010(sd);
- int ret = set_i2c_page(info, client, reg_addr);
-
- if (ret)
- return ret;
- return i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
-}
-
-static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct noon010_info *info = to_noon010(sd);
- int ret = set_i2c_page(info, client, reg_addr);
-
- if (ret)
- return ret;
- return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val);
-}
-
-static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd,
- const struct i2c_regval *msg)
-{
- while (msg->addr != REG_TERM) {
- int ret = cam_i2c_write(sd, msg->addr, msg->val);
-
- if (ret)
- return ret;
- msg++;
- }
- return 0;
-}
-
-/* Device reset and sleep mode control */
-static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep)
-{
- struct noon010_info *info = to_noon010(sd);
- u8 reg = sleep ? 0xF1 : 0xF0;
- int ret = 0;
-
- if (reset) {
- ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
- udelay(20);
- }
- if (!ret) {
- ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
- if (reset && !ret)
- info->i2c_reg_page = -1;
- }
- return ret;
-}
-
-/* Automatic white balance control */
-static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
-{
- int ret;
-
- ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F);
- if (!ret)
- ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B);
- return ret;
-}
-
-/* Called with struct noon010_info.lock mutex held */
-static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
-{
- struct noon010_info *info = to_noon010(sd);
- int reg, ret;
-
- reg = cam_i2c_read(sd, VDO_CTL_REG(1));
- if (reg < 0)
- return reg;
-
- reg &= 0x7C;
- if (hflip)
- reg |= 0x01;
- if (vflip)
- reg |= 0x02;
-
- ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80);
- if (!ret) {
- info->hflip = hflip;
- info->vflip = vflip;
- }
- return ret;
-}
-
-/* Configure resolution and color format */
-static int noon010_set_params(struct v4l2_subdev *sd)
-{
- struct noon010_info *info = to_noon010(sd);
-
- int ret = cam_i2c_write(sd, VDO_CTL_REG(0),
- info->curr_win->vid_ctl1);
- if (ret)
- return ret;
- return cam_i2c_write(sd, ISP_CTL_REG(0),
- info->curr_fmt->ispctl1_reg);
-}
-
-/* Find nearest matching image pixel size. */
-static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf,
- const struct noon010_frmsize **size)
-{
- unsigned int min_err = ~0;
- int i = ARRAY_SIZE(noon010_sizes);
- const struct noon010_frmsize *fsize = &noon010_sizes[0],
- *match = NULL;
-
- while (i--) {
- int err = abs(fsize->width - mf->width)
- + abs(fsize->height - mf->height);
-
- if (err < min_err) {
- min_err = err;
- match = fsize;
- }
- fsize++;
- }
- if (match) {
- mf->width = match->width;
- mf->height = match->height;
- if (size)
- *size = match;
- return 0;
- }
- return -EINVAL;
-}
-
-/* Called with info.lock mutex held */
-static int power_enable(struct noon010_info *info)
-{
- int ret;
-
- if (info->power) {
- v4l2_info(&info->sd, "%s: sensor is already on\n", __func__);
- return 0;
- }
-
- /* Assert standby: line should be flagged active low in descriptor */
- if (info->stby)
- gpiod_set_value(info->stby, 1);
-
- /* Assert reset: line should be flagged active low in descriptor */
- if (info->reset)
- gpiod_set_value(info->reset, 1);
-
- ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply);
- if (ret)
- return ret;
-
- /* De-assert reset and standby */
- if (info->reset) {
- msleep(50);
- gpiod_set_value(info->reset, 0);
- }
- if (info->stby) {
- udelay(1000);
- gpiod_set_value(info->stby, 0);
- }
- /* Cycle reset: assert and deassert */
- if (info->reset) {
- udelay(1000);
- gpiod_set_value(info->reset, 1);
- msleep(100);
- gpiod_set_value(info->reset, 0);
- msleep(20);
- }
- info->power = 1;
-
- v4l2_dbg(1, debug, &info->sd, "%s: sensor is on\n", __func__);
- return 0;
-}
-
-/* Called with info.lock mutex held */
-static int power_disable(struct noon010_info *info)
-{
- int ret;
-
- if (!info->power) {
- v4l2_info(&info->sd, "%s: sensor is already off\n", __func__);
- return 0;
- }
-
- ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply);
- if (ret)
- return ret;
-
- /* Assert standby and reset */
- if (info->stby)
- gpiod_set_value(info->stby, 1);
-
- if (info->reset)
- gpiod_set_value(info->reset, 1);
-
- info->power = 0;
-
- v4l2_dbg(1, debug, &info->sd, "%s: sensor is off\n", __func__);
-
- return 0;
-}
-
-static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct noon010_info *info = to_noon010(sd);
- int ret = 0;
-
- v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
- __func__, ctrl->id, ctrl->val);
-
- mutex_lock(&info->lock);
- /*
- * If the device is not powered up by the host driver do
- * not apply any controls to H/W at this time. Instead
- * the controls will be restored right after power-up.
- */
- if (!info->power)
- goto unlock;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = noon010_enable_autowhitebalance(sd, ctrl->val);
- break;
- case V4L2_CID_BLUE_BALANCE:
- ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
- break;
- case V4L2_CID_RED_BALANCE:
- ret = cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
- break;
- default:
- ret = -EINVAL;
- }
-unlock:
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index >= ARRAY_SIZE(noon010_formats))
- return -EINVAL;
-
- code->code = noon010_formats[code->index].code;
- return 0;
-}
-
-static int noon010_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct noon010_info *info = to_noon010(sd);
- struct v4l2_mbus_framefmt *mf;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (sd_state) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- fmt->format = *mf;
- }
- return 0;
- }
- mf = &fmt->format;
-
- mutex_lock(&info->lock);
- mf->width = info->curr_win->width;
- mf->height = info->curr_win->height;
- mf->code = info->curr_fmt->code;
- mf->colorspace = info->curr_fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- mutex_unlock(&info->lock);
- return 0;
-}
-
-/* Return nearest media bus frame format. */
-static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- int i = ARRAY_SIZE(noon010_formats);
-
- while (--i)
- if (mf->code == noon010_formats[i].code)
- break;
- mf->code = noon010_formats[i].code;
-
- return &noon010_formats[i];
-}
-
-static int noon010_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct noon010_info *info = to_noon010(sd);
- const struct noon010_frmsize *size = NULL;
- const struct noon010_format *nf;
- struct v4l2_mbus_framefmt *mf;
- int ret = 0;
-
- nf = noon010_try_fmt(sd, &fmt->format);
- noon010_try_frame_size(&fmt->format, &size);
- fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
- fmt->format.field = V4L2_FIELD_NONE;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (sd_state) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- *mf = fmt->format;
- }
- return 0;
- }
- mutex_lock(&info->lock);
- if (!info->streaming) {
- info->apply_new_cfg = 1;
- info->curr_fmt = nf;
- info->curr_win = size;
- } else {
- ret = -EBUSY;
- }
- mutex_unlock(&info->lock);
- return ret;
-}
-
-/* Called with struct noon010_info.lock mutex held */
-static int noon010_base_config(struct v4l2_subdev *sd)
-{
- int ret = noon010_bulk_write_reg(sd, noon010_base_regs);
- if (!ret)
- ret = noon010_set_params(sd);
- if (!ret)
- ret = noon010_set_flip(sd, 1, 0);
-
- return ret;
-}
-
-static int noon010_s_power(struct v4l2_subdev *sd, int on)
-{
- struct noon010_info *info = to_noon010(sd);
- int ret;
-
- mutex_lock(&info->lock);
- if (on) {
- ret = power_enable(info);
- if (!ret)
- ret = noon010_base_config(sd);
- } else {
- noon010_power_ctrl(sd, false, true);
- ret = power_disable(info);
- }
- mutex_unlock(&info->lock);
-
- /* Restore the controls state */
- if (!ret && on)
- ret = v4l2_ctrl_handler_setup(&info->hdl);
-
- return ret;
-}
-
-static int noon010_s_stream(struct v4l2_subdev *sd, int on)
-{
- struct noon010_info *info = to_noon010(sd);
- int ret = 0;
-
- mutex_lock(&info->lock);
- if (!info->streaming != !on) {
- ret = noon010_power_ctrl(sd, false, !on);
- if (!ret)
- info->streaming = on;
- }
- if (!ret && on && info->apply_new_cfg) {
- ret = noon010_set_params(sd);
- if (!ret)
- info->apply_new_cfg = 0;
- }
- mutex_unlock(&info->lock);
- return ret;
-}
-
-static int noon010_log_status(struct v4l2_subdev *sd)
-{
- struct noon010_info *info = to_noon010(sd);
-
- v4l2_ctrl_handler_log_status(&info->hdl, sd->name);
- return 0;
-}
-
-static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
-
- mf->width = noon010_sizes[0].width;
- mf->height = noon010_sizes[0].height;
- mf->code = noon010_formats[0].code;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- mf->field = V4L2_FIELD_NONE;
- return 0;
-}
-
-static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
- .open = noon010_open,
-};
-
-static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
- .s_ctrl = noon010_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops noon010_core_ops = {
- .s_power = noon010_s_power,
- .log_status = noon010_log_status,
-};
-
-static const struct v4l2_subdev_pad_ops noon010_pad_ops = {
- .enum_mbus_code = noon010_enum_mbus_code,
- .get_fmt = noon010_get_fmt,
- .set_fmt = noon010_set_fmt,
-};
-
-static const struct v4l2_subdev_video_ops noon010_video_ops = {
- .s_stream = noon010_s_stream,
-};
-
-static const struct v4l2_subdev_ops noon010_ops = {
- .core = &noon010_core_ops,
- .pad = &noon010_pad_ops,
- .video = &noon010_video_ops,
-};
-
-/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */
-static int noon010_detect(struct i2c_client *client, struct noon010_info *info)
-{
- int ret;
-
- ret = power_enable(info);
- if (ret)
- return ret;
-
- ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
- if (ret < 0)
- dev_err(&client->dev, "I2C read failed: 0x%X\n", ret);
-
- power_disable(info);
-
- return ret == NOON010PC30_ID ? 0 : -ENODEV;
-}
-
-static int noon010_probe(struct i2c_client *client)
-{
- struct noon010_info *info;
- struct v4l2_subdev *sd;
- const struct noon010pc30_platform_data *pdata
- = client->dev.platform_data;
- int ret;
- int i;
-
- if (!pdata) {
- dev_err(&client->dev, "No platform data!\n");
- return -EIO;
- }
-
- info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- mutex_init(&info->lock);
- sd = &info->sd;
- v4l2_i2c_subdev_init(sd, client, &noon010_ops);
- /* Static name; NEVER use in new drivers! */
- strscpy(sd->name, MODULE_NAME, sizeof(sd->name));
-
- sd->internal_ops = &noon010_subdev_internal_ops;
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- v4l2_ctrl_handler_init(&info->hdl, 3);
-
- v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
- V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
- V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
- v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
- V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
-
- sd->ctrl_handler = &info->hdl;
-
- ret = info->hdl.error;
- if (ret)
- goto np_err;
-
- info->i2c_reg_page = -1;
- info->curr_fmt = &noon010_formats[0];
- info->curr_win = &noon010_sizes[0];
-
- /* Request reset asserted so we get put into reset */
- info->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(info->reset)) {
- ret = PTR_ERR(info->reset);
- goto np_err;
- }
- gpiod_set_consumer_name(info->reset, "NOON010PC30 NRST");
-
- /* Request standby asserted so we get put into standby */
- info->stby = devm_gpiod_get(&client->dev, "standby", GPIOD_OUT_HIGH);
- if (IS_ERR(info->stby)) {
- ret = PTR_ERR(info->stby);
- goto np_err;
- }
- gpiod_set_consumer_name(info->reset, "NOON010PC30 STBY");
-
- for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
- info->supply[i].supply = noon010_supply_name[i];
-
- ret = devm_regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
- info->supply);
- if (ret)
- goto np_err;
-
- info->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret = media_entity_pads_init(&sd->entity, 1, &info->pad);
- if (ret < 0)
- goto np_err;
-
- ret = noon010_detect(client, info);
- if (!ret)
- return 0;
-
-np_err:
- v4l2_ctrl_handler_free(&info->hdl);
- v4l2_device_unregister_subdev(sd);
- return ret;
-}
-
-static void noon010_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct noon010_info *info = to_noon010(sd);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(&info->hdl);
- media_entity_cleanup(&sd->entity);
-}
-
-static const struct i2c_device_id noon010_id[] = {
- { MODULE_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, noon010_id);
-
-
-static struct i2c_driver noon010_i2c_driver = {
- .driver = {
- .name = MODULE_NAME
- },
- .probe_new = noon010_probe,
- .remove = noon010_remove,
- .id_table = noon010_id,
-};
-
-module_i2c_driver(noon010_i2c_driver);
-
-MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
-MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c
index 549e5d93e568..c1430044fb1e 100644
--- a/drivers/media/i2c/ov13b10.c
+++ b/drivers/media/i2c/ov13b10.c
@@ -243,7 +243,6 @@ static const struct ov13b10_reg mipi_data_rate_1120mbps[] = {
{0x5047, 0xa4},
{0x5048, 0x20},
{0x5049, 0xa4},
- {0x0100, 0x01},
};
static const struct ov13b10_reg mode_4208x3120_regs[] = {
@@ -589,6 +588,9 @@ struct ov13b10 {
/* Streaming on/off */
bool streaming;
+
+ /* True if the device has been identified */
+ bool identified;
};
#define to_ov13b10(_sd) container_of(_sd, struct ov13b10, sd)
@@ -1023,12 +1025,42 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd,
return 0;
}
+/* Verify chip ID */
+static int ov13b10_identify_module(struct ov13b10 *ov13b)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
+ int ret;
+ u32 val;
+
+ if (ov13b->identified)
+ return 0;
+
+ ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID,
+ OV13B10_REG_VALUE_24BIT, &val);
+ if (ret)
+ return ret;
+
+ if (val != OV13B10_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ OV13B10_CHIP_ID, val);
+ return -EIO;
+ }
+
+ ov13b->identified = true;
+
+ return 0;
+}
+
static int ov13b10_start_streaming(struct ov13b10 *ov13b)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
const struct ov13b10_reg_list *reg_list;
int ret, link_freq_index;
+ ret = ov13b10_identify_module(ov13b);
+ if (ret)
+ return ret;
+
/* Get out of from software reset */
ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST,
OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST);
@@ -1144,27 +1176,6 @@ error:
return ret;
}
-/* Verify chip ID */
-static int ov13b10_identify_module(struct ov13b10 *ov13b)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
- int ret;
- u32 val;
-
- ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID,
- OV13B10_REG_VALUE_24BIT, &val);
- if (ret)
- return ret;
-
- if (val != OV13B10_CHIP_ID) {
- dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
- OV13B10_CHIP_ID, val);
- return -EIO;
- }
-
- return 0;
-}
-
static const struct v4l2_subdev_video_ops ov13b10_video_ops = {
.s_stream = ov13b10_set_stream,
};
@@ -1379,6 +1390,7 @@ out_err:
static int ov13b10_probe(struct i2c_client *client)
{
struct ov13b10 *ov13b;
+ bool full_power;
int ret;
/* Check HW config */
@@ -1395,11 +1407,14 @@ static int ov13b10_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
- /* Check module identity */
- ret = ov13b10_identify_module(ov13b);
- if (ret) {
- dev_err(&client->dev, "failed to find sensor: %d\n", ret);
- return ret;
+ full_power = acpi_dev_state_d0(&client->dev);
+ if (full_power) {
+ /* Check module identity */
+ ret = ov13b10_identify_module(ov13b);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d\n", ret);
+ return ret;
+ }
}
/* Set default mode to max resolution */
@@ -1431,7 +1446,10 @@ static int ov13b10_probe(struct i2c_client *client)
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
*/
- pm_runtime_set_active(&client->dev);
+
+ /* Set the device's state to active if it's in D0 state. */
+ if (full_power)
+ pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
@@ -1480,6 +1498,7 @@ static struct i2c_driver ov13b10_i2c_driver = {
},
.probe_new = ov13b10_probe,
.remove = ov13b10_remove,
+ .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
};
module_i2c_driver(ov13b10_i2c_driver);
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
index a3b524f15d89..f119a93e7c64 100644
--- a/drivers/media/i2c/ov2685.c
+++ b/drivers/media/i2c/ov2685.c
@@ -17,6 +17,7 @@
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#define CHIP_ID 0x2685
@@ -55,6 +56,9 @@
#define OV2685_REG_VALUE_16BIT 2
#define OV2685_REG_VALUE_24BIT 3
+#define OV2685_NATIVE_WIDTH 1616
+#define OV2685_NATIVE_HEIGHT 1216
+
#define OV2685_LANES 1
#define OV2685_BITS_PER_SAMPLE 10
@@ -77,6 +81,7 @@ struct ov2685_mode {
u32 exp_def;
u32 hts_def;
u32 vts_def;
+ const struct v4l2_rect *analog_crop;
const struct regval *reg_list;
};
@@ -230,6 +235,13 @@ static const int ov2685_test_pattern_val[] = {
OV2685_TEST_PATTERN_COLOR_SQUARE,
};
+static const struct v4l2_rect ov2685_analog_crop = {
+ .left = 8,
+ .top = 8,
+ .width = 1600,
+ .height = 1200,
+};
+
static const struct ov2685_mode supported_modes[] = {
{
.width = 1600,
@@ -237,6 +249,7 @@ static const struct ov2685_mode supported_modes[] = {
.exp_def = 0x04ee,
.hts_def = 0x06a4,
.vts_def = 0x050e,
+ .analog_crop = &ov2685_analog_crop,
.reg_list = ov2685_1600x1200_regs,
},
};
@@ -383,6 +396,53 @@ static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
return 0;
}
+static const struct v4l2_rect *
+__ov2685_get_pad_crop(struct ov2685 *ov2685,
+ struct v4l2_subdev_state *state, unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ const struct ov2685_mode *mode = ov2685->cur_mode;
+
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&ov2685->subdev, state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return mode->analog_crop;
+ }
+
+ return NULL;
+}
+
+static int ov2685_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov2685 *ov2685 = to_ov2685(sd);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ mutex_lock(&ov2685->mutex);
+ sel->r = *__ov2685_get_pad_crop(ov2685, sd_state, sel->pad,
+ sel->which);
+ mutex_unlock(&ov2685->mutex);
+ break;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV2685_NATIVE_WIDTH;
+ sel->r.height = OV2685_NATIVE_HEIGHT;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r = ov2685_analog_crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov2685_cal_delay(u32 cycles)
{
@@ -419,8 +479,10 @@ static int __ov2685_power_on(struct ov2685 *ov2685)
* writing register before .s_stream() as a workaround
*/
ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list);
- if (ret)
+ if (ret) {
+ dev_err(dev, "Failed to set regs for power on\n");
goto disable_supplies;
+ }
return 0;
@@ -589,6 +651,8 @@ static const struct v4l2_subdev_pad_ops ov2685_pad_ops = {
.enum_frame_size = ov2685_enum_frame_sizes,
.get_fmt = ov2685_get_fmt,
.set_fmt = ov2685_set_fmt,
+ .get_selection = ov2685_get_selection,
+ .set_selection = ov2685_get_selection,
};
static const struct v4l2_subdev_ops ov2685_subdev_ops = {
@@ -611,13 +675,14 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685)
const struct ov2685_mode *mode;
struct v4l2_ctrl_handler *handler;
struct v4l2_ctrl *ctrl;
+ struct v4l2_fwnode_device_properties props;
u64 exposure_max;
u32 pixel_rate, h_blank;
int ret;
handler = &ov2685->ctrl_handler;
mode = ov2685->cur_mode;
- ret = v4l2_ctrl_handler_init(handler, 8);
+ ret = v4l2_ctrl_handler_init(handler, 10);
if (ret)
return ret;
handler->lock = &ov2685->mutex;
@@ -659,6 +724,15 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685)
ARRAY_SIZE(ov2685_test_pattern_menu) - 1,
0, 0, ov2685_test_pattern_menu);
+ /* set properties from fwnode (e.g. rotation, orientation) */
+ ret = v4l2_fwnode_device_parse(&ov2685->client->dev, &props);
+ if (ret)
+ goto err_free_handler;
+
+ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov2685_ctrl_ops, &props);
+ if (ret)
+ goto err_free_handler;
+
if (handler->error) {
ret = handler->error;
dev_err(&ov2685->client->dev,
@@ -707,8 +781,7 @@ static int ov2685_configure_regulators(struct ov2685 *ov2685)
ov2685->supplies);
}
-static int ov2685_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ov2685_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ov2685 *ov2685;
@@ -734,7 +807,7 @@ static int ov2685_probe(struct i2c_client *client,
if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
- ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ ov2685->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov2685->reset_gpio)) {
dev_err(dev, "Failed to get reset-gpios\n");
return -EINVAL;
@@ -830,7 +903,7 @@ static struct i2c_driver ov2685_i2c_driver = {
.pm = &ov2685_pm_ops,
.of_match_table = of_match_ptr(ov2685_of_match),
},
- .probe = &ov2685_probe,
+ .probe_new = &ov2685_probe,
.remove = &ov2685_remove,
};
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 847a7bbb69c5..233576ee9503 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -58,6 +58,7 @@
#define OV5647_REG_MIPI_CTRL00 0x4800
#define OV5647_REG_MIPI_CTRL14 0x4814
#define OV5647_REG_AWB 0x5001
+#define OV5647_REG_ISPCTRL3D 0x503d
#define REG_TERM 0xfffe
#define VAL_TERM 0xfe
@@ -116,6 +117,20 @@ static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
return container_of(sd, struct ov5647, sd);
}
+static const char * const ov5647_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Color Squares",
+ "Random Data",
+};
+
+static const u8 ov5647_test_pattern_val[] = {
+ 0x00, /* Disabled */
+ 0x80, /* Color Bars */
+ 0x82, /* Color Squares */
+ 0x81, /* Random Data */
+};
+
static const struct regval_list sensor_oe_disable_regs[] = {
{0x3000, 0x00},
{0x3001, 0x00},
@@ -614,23 +629,29 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
{
- unsigned char data_w[2] = { reg >> 8, reg & 0xff };
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ struct i2c_msg msg[2];
int ret;
- ret = i2c_master_send(client, data_w, 2);
- if (ret < 0) {
- dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
- __func__, reg);
- return ret;
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags;
+ msg[0].buf = buf;
+ msg[0].len = sizeof(buf);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = 1;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret != 2) {
+ dev_err(&client->dev, "%s: i2c read error, reg: %x = %d\n",
+ __func__, reg, ret);
+ return ret >= 0 ? -EINVAL : ret;
}
- ret = i2c_master_recv(client, val, 1);
- if (ret < 0) {
- dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
- __func__, reg);
- return ret;
- }
+ *val = buf[0];
return 0;
}
@@ -1242,6 +1263,10 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
ret = ov5647_write16(sd, OV5647_REG_VTS_HI,
sensor->mode->format.height + ctrl->val);
break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov5647_write(sd, OV5647_REG_ISPCTRL3D,
+ ov5647_test_pattern_val[ctrl->val]);
+ break;
/* Read-only, but we adjust it based on mode. */
case V4L2_CID_PIXEL_RATE:
@@ -1270,7 +1295,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
int hblank, exposure_max, exposure_def;
- v4l2_ctrl_handler_init(&sensor->ctrls, 8);
+ v4l2_ctrl_handler_init(&sensor->ctrls, 9);
v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
@@ -1314,6 +1339,11 @@ static int ov5647_init_controls(struct ov5647 *sensor)
sensor->mode->vts -
sensor->mode->format.height);
+ v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &ov5647_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov5647_test_pattern_menu) - 1,
+ 0, 0, ov5647_test_pattern_menu);
+
if (sensor->ctrls.error)
goto handler_free;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index f79d908f4531..c026610d0f31 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -29,6 +29,12 @@
#define OV5670_REG_SOFTWARE_RST 0x0103
#define OV5670_SOFTWARE_RST 0x01
+#define OV5670_MIPI_SC_CTRL0_REG 0x3018
+#define OV5670_MIPI_SC_CTRL0_LANES(v) ((((v) - 1) << 5) & \
+ GENMASK(7, 5))
+#define OV5670_MIPI_SC_CTRL0_MIPI_EN BIT(4)
+#define OV5670_MIPI_SC_CTRL0_RESERVED BIT(1)
+
/* vertical-timings from sensor */
#define OV5670_REG_VTS 0x380e
#define OV5670_VTS_30FPS 0x0808 /* default for 30 fps */
@@ -92,7 +98,6 @@ struct ov5670_reg_list {
};
struct ov5670_link_freq_config {
- u32 pixel_rate;
const struct ov5670_reg_list reg_list;
};
@@ -163,7 +168,6 @@ static const struct ov5670_reg mode_2592x1944_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -429,7 +433,6 @@ static const struct ov5670_reg mode_1296x972_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -695,7 +698,6 @@ static const struct ov5670_reg mode_648x486_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -961,7 +963,6 @@ static const struct ov5670_reg mode_2560x1440_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -1226,7 +1227,6 @@ static const struct ov5670_reg mode_1280x720_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -1492,7 +1492,6 @@ static const struct ov5670_reg mode_640x360_regs[] = {
{0x3005, 0xf0},
{0x3007, 0x00},
{0x3015, 0x0f},
- {0x3018, 0x32},
{0x301a, 0xf0},
{0x301b, 0xf0},
{0x301c, 0xf0},
@@ -1762,8 +1761,6 @@ static const char * const ov5670_test_pattern_menu[] = {
#define OV5670_LINK_FREQ_422MHZ_INDEX 0
static const struct ov5670_link_freq_config link_freq_configs[] = {
{
- /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- .pixel_rate = (OV5670_LINK_FREQ_422MHZ * 2 * 2) / 10,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mipi_data_rate_840mbps),
.regs = mipi_data_rate_840mbps,
@@ -1859,6 +1856,7 @@ static const struct ov5670_mode supported_modes[] = {
struct ov5670 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct v4l2_fwnode_endpoint endpoint;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -2101,9 +2099,13 @@ static const struct v4l2_ctrl_ops ov5670_ctrl_ops = {
/* Initialize control handlers */
static int ov5670_init_controls(struct ov5670 *ov5670)
{
+ struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
+ &ov5670->endpoint.bus.mipi_csi2;
struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
+ unsigned int lanes_count;
+ s64 mipi_pixel_rate;
s64 vblank_max;
s64 vblank_def;
s64 vblank_min;
@@ -2124,12 +2126,15 @@ static int ov5670_init_controls(struct ov5670 *ov5670)
ov5670->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* By default, V4L2_CID_PIXEL_RATE is read only */
+ lanes_count = bus_mipi_csi2->num_data_lanes;
+ mipi_pixel_rate = OV5670_LINK_FREQ_422MHZ * 2 * lanes_count / 10;
+
ov5670->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops,
V4L2_CID_PIXEL_RATE,
- link_freq_configs[0].pixel_rate,
- link_freq_configs[0].pixel_rate,
+ mipi_pixel_rate,
+ mipi_pixel_rate,
1,
- link_freq_configs[0].pixel_rate);
+ mipi_pixel_rate);
vblank_max = OV5670_VTS_MAX - ov5670->cur_mode->height;
vblank_def = ov5670->cur_mode->vts_def - ov5670->cur_mode->height;
@@ -2288,8 +2293,13 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt)
{
struct ov5670 *ov5670 = to_ov5670(sd);
+ struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
+ &ov5670->endpoint.bus.mipi_csi2;
const struct ov5670_mode *mode;
+ unsigned int lanes_count;
+ s64 mipi_pixel_rate;
s32 vblank_def;
+ s64 link_freq;
s32 h_blank;
mutex_lock(&ov5670->mutex);
@@ -2306,9 +2316,14 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
} else {
ov5670->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index);
+
+ lanes_count = bus_mipi_csi2->num_data_lanes;
+ link_freq = link_freq_menu_items[mode->link_freq_index];
+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ mipi_pixel_rate = div_s64(link_freq * 2 * lanes_count, 10);
__v4l2_ctrl_s_ctrl_int64(
ov5670->pixel_rate,
- link_freq_configs[mode->link_freq_index].pixel_rate);
+ mipi_pixel_rate);
/* Update limits and set FPS to default */
vblank_def = ov5670->cur_mode->vts_def -
ov5670->cur_mode->height;
@@ -2361,6 +2376,19 @@ static int ov5670_identify_module(struct ov5670 *ov5670)
return 0;
}
+static int ov5670_mipi_configure(struct ov5670 *ov5670)
+{
+ struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
+ &ov5670->endpoint.bus.mipi_csi2;
+ unsigned int lanes_count = bus_mipi_csi2->num_data_lanes;
+
+ return ov5670_write_reg(ov5670, OV5670_MIPI_SC_CTRL0_REG,
+ OV5670_REG_VALUE_08BIT,
+ OV5670_MIPI_SC_CTRL0_LANES(lanes_count) |
+ OV5670_MIPI_SC_CTRL0_MIPI_EN |
+ OV5670_MIPI_SC_CTRL0_RESERVED);
+}
+
/* Prepare streaming by writing default values and customized values */
static int ov5670_start_streaming(struct ov5670 *ov5670)
{
@@ -2399,6 +2427,12 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
return ret;
}
+ ret = ov5670_mipi_configure(ov5670);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to configure MIPI\n", __func__);
+ return ret;
+ }
+
ret = __v4l2_ctrl_handler_setup(ov5670->sd.ctrl_handler);
if (ret)
return ret;
@@ -2647,23 +2681,20 @@ static int ov5670_gpio_probe(struct ov5670 *ov5670)
static int ov5670_probe(struct i2c_client *client)
{
+ struct fwnode_handle *handle;
struct ov5670 *ov5670;
- const char *err_msg;
u32 input_clk = 0;
bool full_power;
int ret;
ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL);
- if (!ov5670) {
- ret = -ENOMEM;
- err_msg = "devm_kzalloc() error";
- goto error_print;
- }
+ if (!ov5670)
+ return -ENOMEM;
- ov5670->xvclk = devm_clk_get(&client->dev, NULL);
+ ov5670->xvclk = devm_clk_get_optional(&client->dev, NULL);
if (!IS_ERR_OR_NULL(ov5670->xvclk))
input_clk = clk_get_rate(ov5670->xvclk);
- else if (PTR_ERR(ov5670->xvclk) == -ENOENT)
+ else if (!ov5670->xvclk || PTR_ERR(ov5670->xvclk) == -ENOENT)
device_property_read_u32(&client->dev, "clock-frequency",
&input_clk);
else
@@ -2680,29 +2711,38 @@ static int ov5670_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
ret = ov5670_regulators_probe(ov5670);
- if (ret) {
- err_msg = "Regulators probe failed";
- goto error_print;
- }
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Regulators probe failed\n");
ret = ov5670_gpio_probe(ov5670);
- if (ret) {
- err_msg = "GPIO probe failed";
- goto error_print;
- }
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "GPIO probe failed\n");
+
+ /* Graph Endpoint */
+ handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+ if (!handle)
+ return dev_err_probe(&client->dev, -ENXIO, "Endpoint for node get failed\n");
+
+ ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY;
+ ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ov5670->endpoint);
+ fwnode_handle_put(handle);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Endpoint parse failed\n");
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
ret = ov5670_runtime_resume(&client->dev);
if (ret) {
- err_msg = "Power up failed";
- goto error_print;
+ dev_err_probe(&client->dev, ret, "Power up failed\n");
+ goto error_endpoint;
}
/* Check module identity */
ret = ov5670_identify_module(ov5670);
if (ret) {
- err_msg = "ov5670_identify_module() error";
+ dev_err_probe(&client->dev, ret, "ov5670_identify_module() error\n");
goto error_power_off;
}
}
@@ -2714,7 +2754,7 @@ static int ov5670_probe(struct i2c_client *client)
ret = ov5670_init_controls(ov5670);
if (ret) {
- err_msg = "ov5670_init_controls() error";
+ dev_err_probe(&client->dev, ret, "ov5670_init_controls() error\n");
goto error_mutex_destroy;
}
@@ -2727,7 +2767,7 @@ static int ov5670_probe(struct i2c_client *client)
ov5670->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad);
if (ret) {
- err_msg = "media_entity_pads_init() error";
+ dev_err_probe(&client->dev, ret, "media_entity_pads_init() error\n");
goto error_handler_free;
}
@@ -2741,7 +2781,7 @@ static int ov5670_probe(struct i2c_client *client)
/* Async register for subdev */
ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
if (ret < 0) {
- err_msg = "v4l2_async_register_subdev() error";
+ dev_err_probe(&client->dev, ret, "v4l2_async_register_subdev() error\n");
goto error_pm_disable;
}
@@ -2764,8 +2804,8 @@ error_power_off:
if (full_power)
ov5670_runtime_suspend(&client->dev);
-error_print:
- dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
+error_endpoint:
+ v4l2_fwnode_endpoint_free(&ov5670->endpoint);
return ret;
}
@@ -2782,6 +2822,8 @@ static void ov5670_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
ov5670_runtime_suspend(&client->dev);
+
+ v4l2_fwnode_endpoint_free(&ov5670->endpoint);
}
static const struct dev_pm_ops ov5670_pm_ops = {
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
index 61906fc54e37..b287c28920a6 100644
--- a/drivers/media/i2c/ov5695.c
+++ b/drivers/media/i2c/ov5695.c
@@ -1267,8 +1267,7 @@ static int ov5695_configure_regulators(struct ov5695 *ov5695)
ov5695->supplies);
}
-static int ov5695_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ov5695_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ov5695 *ov5695;
@@ -1393,7 +1392,7 @@ static struct i2c_driver ov5695_i2c_driver = {
.pm = &ov5695_pm_ops,
.of_match_table = of_match_ptr(ov5695_of_match),
},
- .probe = &ov5695_probe,
+ .probe_new = &ov5695_probe,
.remove = &ov5695_remove,
};
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index b1bb0833571e..ecbded4f0765 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1894,14 +1894,9 @@ static int ov7670_probe(struct i2c_client *client)
info->pclk_hb_disable = true;
}
- info->clk = devm_clk_get(&client->dev, "xclk"); /* optional */
- if (IS_ERR(info->clk)) {
- ret = PTR_ERR(info->clk);
- if (ret == -ENOENT)
- info->clk = NULL;
- else
- return ret;
- }
+ info->clk = devm_clk_get_optional(&client->dev, "xclk");
+ if (IS_ERR(info->clk))
+ return PTR_ERR(info->clk);
ret = ov7670_init_gpio(client, info);
if (ret)
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index cf8384e09413..b5c7881383ca 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -1709,46 +1709,6 @@ static int ov8856_identify_module(struct ov8856 *ov8856)
return -ENXIO;
}
- ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT,
- OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING);
- if (ret)
- return ret;
-
- ret = ov8856_write_reg(ov8856, OV8856_OTP_MODE_CTRL,
- OV8856_REG_VALUE_08BIT, OV8856_OTP_MODE_AUTO);
- if (ret) {
- dev_err(&client->dev, "failed to set otp mode");
- return ret;
- }
-
- ret = ov8856_write_reg(ov8856, OV8856_OTP_LOAD_CTRL,
- OV8856_REG_VALUE_08BIT,
- OV8856_OTP_LOAD_CTRL_ENABLE);
- if (ret) {
- dev_err(&client->dev, "failed to enable load control");
- return ret;
- }
-
- ret = ov8856_read_reg(ov8856, OV8856_MODULE_REVISION,
- OV8856_REG_VALUE_08BIT, &val);
- if (ret) {
- dev_err(&client->dev, "failed to read module revision");
- return ret;
- }
-
- dev_info(&client->dev, "OV8856 revision %x (%s) at address 0x%02x\n",
- val,
- val == OV8856_2A_MODULE ? "2A" :
- val == OV8856_1B_MODULE ? "1B" : "unknown revision",
- client->addr);
-
- ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT,
- OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY);
- if (ret) {
- dev_err(&client->dev, "failed to exit streaming mode");
- return ret;
- }
-
ov8856->identified = true;
return 0;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
deleted file mode 100644
index 5996153371fc..000000000000
--- a/drivers/media/i2c/s5k6aa.c
+++ /dev/null
@@ -1,1652 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
- * with embedded SoC ISP.
- *
- * Copyright (C) 2011, Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * Based on a driver authored by Dongsoo Nathaniel Kim.
- * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/media.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-
-#include <media/media-entity.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-mediabus.h>
-#include <media/i2c/s5k6aa.h>
-
-static int debug;
-module_param(debug, int, 0644);
-
-#define DRIVER_NAME "S5K6AA"
-
-/* The token to indicate array termination */
-#define S5K6AA_TERM 0xffff
-#define S5K6AA_OUT_WIDTH_DEF 640
-#define S5K6AA_OUT_HEIGHT_DEF 480
-#define S5K6AA_WIN_WIDTH_MAX 1280
-#define S5K6AA_WIN_HEIGHT_MAX 1024
-#define S5K6AA_WIN_WIDTH_MIN 8
-#define S5K6AA_WIN_HEIGHT_MIN 8
-
-/*
- * H/W register Interface (0xD0000000 - 0xD0000FFF)
- */
-#define AHB_MSB_ADDR_PTR 0xfcfc
-#define GEN_REG_OFFSH 0xd000
-#define REG_CMDWR_ADDRH 0x0028
-#define REG_CMDWR_ADDRL 0x002a
-#define REG_CMDRD_ADDRH 0x002c
-#define REG_CMDRD_ADDRL 0x002e
-#define REG_CMDBUF0_ADDR 0x0f12
-#define REG_CMDBUF1_ADDR 0x0f10
-
-/*
- * Host S/W Register interface (0x70000000 - 0x70002000)
- * The value of the two most significant address bytes is 0x7000,
- * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
- */
-#define HOST_SWIF_OFFSH 0x7000
-
-/* Initialization parameters */
-/* Master clock frequency in KHz */
-#define REG_I_INCLK_FREQ_L 0x01b8
-#define REG_I_INCLK_FREQ_H 0x01ba
-#define MIN_MCLK_FREQ_KHZ 6000U
-#define MAX_MCLK_FREQ_KHZ 27000U
-#define REG_I_USE_NPVI_CLOCKS 0x01c6
-#define REG_I_USE_NMIPI_CLOCKS 0x01c8
-
-/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
-#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc)
-#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce)
-#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0)
-#define SYS_PLL_OUT_FREQ (48000000 / 4000)
-#define PCLK_FREQ_MIN (24000000 / 4000)
-#define PCLK_FREQ_MAX (48000000 / 4000)
-#define REG_I_INIT_PARAMS_UPDATED 0x01e0
-#define REG_I_ERROR_INFO 0x01e2
-
-/* General purpose parameters */
-#define REG_USER_BRIGHTNESS 0x01e4
-#define REG_USER_CONTRAST 0x01e6
-#define REG_USER_SATURATION 0x01e8
-#define REG_USER_SHARPBLUR 0x01ea
-
-#define REG_G_SPEC_EFFECTS 0x01ee
-#define REG_G_ENABLE_PREV 0x01f0
-#define REG_G_ENABLE_PREV_CHG 0x01f2
-#define REG_G_NEW_CFG_SYNC 0x01f8
-#define REG_G_PREVZOOM_IN_WIDTH 0x020a
-#define REG_G_PREVZOOM_IN_HEIGHT 0x020c
-#define REG_G_PREVZOOM_IN_XOFFS 0x020e
-#define REG_G_PREVZOOM_IN_YOFFS 0x0210
-#define REG_G_INPUTS_CHANGE_REQ 0x021a
-#define REG_G_ACTIVE_PREV_CFG 0x021c
-#define REG_G_PREV_CFG_CHG 0x021e
-#define REG_G_PREV_OPEN_AFTER_CH 0x0220
-#define REG_G_PREV_CFG_ERROR 0x0222
-
-/* Preview control section. n = 0...4. */
-#define PREG(n, x) ((n) * 0x26 + x)
-#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242)
-#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244)
-#define REG_P_FMT(n) PREG(n, 0x0246)
-#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248)
-#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a)
-#define REG_P_PVI_MASK(n) PREG(n, 0x024c)
-#define REG_P_CLK_INDEX(n) PREG(n, 0x024e)
-#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250)
-#define FR_RATE_DYNAMIC 0
-#define FR_RATE_FIXED 1
-#define FR_RATE_FIXED_ACCURATE 2
-#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252)
-#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */
-#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */
-/* Frame period in 0.1 ms units */
-#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254)
-#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256)
-/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
-#define US_TO_FR_TIME(__t) ((__t) / 100)
-#define S5K6AA_MIN_FR_TIME 33300 /* us */
-#define S5K6AA_MAX_FR_TIME 650000 /* us */
-#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */
-/* The below 5 registers are for "device correction" values */
-#define REG_P_COLORTEMP(n) PREG(n, 0x025e)
-#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262)
-
-/* Extended image property controls */
-/* Exposure time in 10 us units */
-#define REG_SF_USR_EXPOSURE_L 0x03c6
-#define REG_SF_USR_EXPOSURE_H 0x03c8
-#define REG_SF_USR_EXPOSURE_CHG 0x03ca
-#define REG_SF_USR_TOT_GAIN 0x03cc
-#define REG_SF_USR_TOT_GAIN_CHG 0x03ce
-#define REG_SF_RGAIN 0x03d0
-#define REG_SF_RGAIN_CHG 0x03d2
-#define REG_SF_GGAIN 0x03d4
-#define REG_SF_GGAIN_CHG 0x03d6
-#define REG_SF_BGAIN 0x03d8
-#define REG_SF_BGAIN_CHG 0x03da
-#define REG_SF_FLICKER_QUANT 0x03dc
-#define REG_SF_FLICKER_QUANT_CHG 0x03de
-
-/* Output interface (parallel/MIPI) setup */
-#define REG_OIF_EN_MIPI_LANES 0x03fa
-#define REG_OIF_EN_PACKETS 0x03fc
-#define REG_OIF_CFG_CHG 0x03fe
-
-/* Auto-algorithms enable mask */
-#define REG_DBG_AUTOALG_EN 0x0400
-#define AALG_ALL_EN_MASK (1 << 0)
-#define AALG_AE_EN_MASK (1 << 1)
-#define AALG_DIVLEI_EN_MASK (1 << 2)
-#define AALG_WB_EN_MASK (1 << 3)
-#define AALG_FLICKER_EN_MASK (1 << 5)
-#define AALG_FIT_EN_MASK (1 << 6)
-#define AALG_WRHW_EN_MASK (1 << 7)
-
-/* Firmware revision information */
-#define REG_FW_APIVER 0x012e
-#define S5K6AAFX_FW_APIVER 0x0001
-#define REG_FW_REVISION 0x0130
-
-/* For now we use only one user configuration register set */
-#define S5K6AA_MAX_PRESETS 1
-
-static const char * const s5k6aa_supply_names[] = {
- "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */
- "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */
- "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V)
- or 2.8V (2.6V to 3.0) */
- "vddio", /* I/O supply 1.8V (1.65V to 1.95V)
- or 2.8V (2.5V to 3.1V) */
-};
-#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
-
-enum s5k6aa_gpio_id {
- STBY,
- RSET,
- GPIO_NUM,
-};
-
-struct s5k6aa_regval {
- u16 addr;
- u16 val;
-};
-
-struct s5k6aa_pixfmt {
- u32 code;
- u32 colorspace;
- /* REG_P_FMT(x) register value */
- u16 reg_p_fmt;
-};
-
-struct s5k6aa_preset {
- /* output pixel format and resolution */
- struct v4l2_mbus_framefmt mbus_fmt;
- u8 clk_id;
- u8 index;
-};
-
-struct s5k6aa_ctrls {
- struct v4l2_ctrl_handler handler;
- /* Auto / manual white balance cluster */
- struct v4l2_ctrl *awb;
- struct v4l2_ctrl *gain_red;
- struct v4l2_ctrl *gain_blue;
- struct v4l2_ctrl *gain_green;
- /* Mirror cluster */
- struct v4l2_ctrl *hflip;
- struct v4l2_ctrl *vflip;
- /* Auto exposure / manual exposure and gain cluster */
- struct v4l2_ctrl *auto_exp;
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *gain;
-};
-
-struct s5k6aa_interval {
- u16 reg_fr_time;
- struct v4l2_fract interval;
- /* Maximum rectangle for the interval */
- struct v4l2_frmsize_discrete size;
-};
-
-struct s5k6aa {
- struct v4l2_subdev sd;
- struct media_pad pad;
-
- enum v4l2_mbus_type bus_type;
- u8 mipi_lanes;
-
- int (*s_power)(int enable);
- struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
- struct s5k6aa_gpio gpio[GPIO_NUM];
-
- /* external master clock frequency */
- unsigned long mclk_frequency;
- /* ISP internal master clock frequency */
- u16 clk_fop;
- /* output pixel clock frequency range */
- u16 pclk_fmin;
- u16 pclk_fmax;
-
- unsigned int inv_hflip:1;
- unsigned int inv_vflip:1;
-
- /* protects the struct members below */
- struct mutex lock;
-
- /* sensor matrix scan window */
- struct v4l2_rect ccd_rect;
-
- struct s5k6aa_ctrls ctrls;
- struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
- struct s5k6aa_preset *preset;
- const struct s5k6aa_interval *fiv;
-
- unsigned int streaming:1;
- unsigned int apply_cfg:1;
- unsigned int apply_crop:1;
- unsigned int power;
-};
-
-static struct s5k6aa_regval s5k6aa_analog_config[] = {
- /* Analog settings */
- { 0x112a, 0x0000 }, { 0x1132, 0x0000 },
- { 0x113e, 0x0000 }, { 0x115c, 0x0000 },
- { 0x1164, 0x0000 }, { 0x1174, 0x0000 },
- { 0x1178, 0x0000 }, { 0x077a, 0x0000 },
- { 0x077c, 0x0000 }, { 0x077e, 0x0000 },
- { 0x0780, 0x0000 }, { 0x0782, 0x0000 },
- { 0x0784, 0x0000 }, { 0x0786, 0x0000 },
- { 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
- { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
- { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
- { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
- { 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
- { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
-};
-
-/* TODO: Add RGB888 and Bayer format */
-static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
- /* range 16-240 */
- { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
- { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
-};
-
-static const struct s5k6aa_interval s5k6aa_intervals[] = {
- { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
- { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */
- { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */
- { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */
- { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */
-};
-
-#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
-
-static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
-}
-
-static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct s5k6aa, sd);
-}
-
-/* Set initial values for all preview presets */
-static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
-{
- struct s5k6aa_preset *preset = &s5k6aa->presets[0];
- int i;
-
- for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
- preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF;
- preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF;
- preset->mbus_fmt.code = s5k6aa_formats[0].code;
- preset->index = i;
- preset->clk_id = 0;
- preset++;
- }
-
- s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
- s5k6aa->preset = &s5k6aa->presets[0];
-}
-
-static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
-{
- u8 wbuf[2] = {addr >> 8, addr & 0xFF};
- struct i2c_msg msg[2];
- u8 rbuf[2];
- int ret;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 2;
- msg[0].buf = wbuf;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 2;
- msg[1].buf = rbuf;
-
- ret = i2c_transfer(client->adapter, msg, 2);
- *val = be16_to_cpu(*((__be16 *)rbuf));
-
- v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
-
- return ret == 2 ? 0 : ret;
-}
-
-static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
-{
- u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
-
- int ret = i2c_master_send(client, buf, 4);
- v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
-
- return ret == 4 ? 0 : ret;
-}
-
-/* The command register write, assumes Command_Wr_addH = 0x7000. */
-static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
-{
- int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
- if (ret)
- return ret;
- return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
-}
-
-/* The command register read, assumes Command_Rd_addH = 0x7000. */
-static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
-{
- int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
- if (ret)
- return ret;
- return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
-}
-
-static int s5k6aa_write_array(struct v4l2_subdev *sd,
- const struct s5k6aa_regval *msg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u16 addr_incr = 0;
- int ret = 0;
-
- while (msg->addr != S5K6AA_TERM) {
- if (addr_incr != 2)
- ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
- msg->addr);
- if (ret)
- break;
- ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
- if (ret)
- break;
- /* Assume that msg->addr is always less than 0xfffc */
- addr_incr = (msg + 1)->addr - msg->addr;
- msg++;
- }
-
- return ret;
-}
-
-/* Configure the AHB high address bytes for GTG registers access */
-static int s5k6aa_set_ahb_address(struct i2c_client *client)
-{
- int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
- if (ret)
- return ret;
- ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
- if (ret)
- return ret;
- return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
-}
-
-/**
- * s5k6aa_configure_pixel_clocks - apply ISP main clock/PLL configuration
- * @s5k6aa: pointer to &struct s5k6aa describing the device
- *
- * Configure the internal ISP PLL for the required output frequency.
- * Locking: called with s5k6aa.lock mutex held.
- */
-static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
- u16 status;
- int ret;
-
- if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
- "Invalid clock frequency: %ld\n", fmclk))
- return -EINVAL;
-
- s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
- s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
- s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
-
- /* External input clock frequency in kHz */
- ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
- /* Internal PLL frequency */
- if (!ret)
- ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
- s5k6aa->pclk_fmin);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
- s5k6aa->pclk_fmax);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
- if (!ret)
- ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
-
- return ret ? ret : (status ? -EINVAL : 0);
-}
-
-/* Set horizontal and vertical image flipping */
-static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int index = s5k6aa->preset->index;
-
- unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
- unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
-
- return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
-}
-
-/* Configure auto/manual white balance and R/G/B gains */
-static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
- u16 reg;
-
- int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &reg);
-
- if (!ret && !awb) {
- ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
- if (ret)
- return ret;
-
- ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
- if (ret)
- return ret;
-
- ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
- }
- if (!ret) {
- reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
- ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
- }
-
- return ret;
-}
-
-/* Program FW with exposure time, 'exposure' in us units */
-static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
-{
- unsigned int time = exposure / 10;
-
- int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
- if (!ret)
- ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
-}
-
-static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
-{
- int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
-}
-
-/* Set auto/manual exposure and total gain */
-static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- unsigned int exp_time = s5k6aa->ctrls.exposure->val;
- u16 auto_alg;
-
- int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
- if (ret)
- return ret;
-
- v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
- exp_time, value, auto_alg);
-
- if (value == V4L2_EXPOSURE_AUTO) {
- auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
- } else {
- ret = s5k6aa_set_user_exposure(c, exp_time);
- if (ret)
- return ret;
- ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
- if (ret)
- return ret;
- auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
- }
-
- return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
-}
-
-static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 auto_alg;
- int ret;
-
- ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
- if (ret)
- return ret;
-
- if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
- auto_alg |= AALG_FLICKER_EN_MASK;
- } else {
- auto_alg &= ~AALG_FLICKER_EN_MASK;
- /* The V4L2_CID_LINE_FREQUENCY control values match
- * the register values */
- ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
- if (ret)
- return ret;
- ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
- if (ret)
- return ret;
- }
-
- return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
-}
-
-static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- static const struct v4l2_control colorfx[] = {
- { V4L2_COLORFX_NONE, 0 },
- { V4L2_COLORFX_BW, 1 },
- { V4L2_COLORFX_NEGATIVE, 2 },
- { V4L2_COLORFX_SEPIA, 3 },
- { V4L2_COLORFX_SKY_BLUE, 4 },
- { V4L2_COLORFX_SKETCH, 5 },
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
- if (colorfx[i].id == val)
- return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
- colorfx[i].value);
- }
- return -EINVAL;
-}
-
-static int s5k6aa_preview_config_status(struct i2c_client *client)
-{
- u16 error = 0;
- int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
-
- v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
- return ret ? ret : (error ? -EINVAL : 0);
-}
-
-static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
- struct v4l2_mbus_framefmt *mf)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
- if (mf->colorspace == s5k6aa_formats[i].colorspace &&
- mf->code == s5k6aa_formats[i].code)
- return i;
- return 0;
-}
-
-static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
- struct s5k6aa_preset *preset)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
- int ret;
-
- ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
- preset->mbus_fmt.width);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
- preset->mbus_fmt.height);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FMT(preset->index),
- s5k6aa_formats[fmt_index].reg_p_fmt);
- return ret;
-}
-
-static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- struct v4l2_rect *r = &s5k6aa->ccd_rect;
- int ret;
-
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
- if (!ret)
- s5k6aa->apply_crop = 0;
-
- return ret;
-}
-
-/**
- * s5k6aa_configure_video_bus - configure the video output interface
- * @s5k6aa: pointer to &struct s5k6aa describing the device
- * @bus_type: video bus type: parallel or MIPI-CSI
- * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
- *
- * Note: Only parallel bus operation has been tested.
- */
-static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
- enum v4l2_mbus_type bus_type, int nlanes)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 cfg = 0;
- int ret;
-
- /*
- * TODO: The sensor is supposed to support BT.601 and BT.656
- * but there is nothing indicating how to switch between both
- * in the datasheet. For now default BT.601 interface is assumed.
- */
- if (bus_type == V4L2_MBUS_CSI2_DPHY)
- cfg = nlanes;
- else if (bus_type != V4L2_MBUS_PARALLEL)
- return -EINVAL;
-
- ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
-}
-
-/* This function should be called when switching to new user configuration set*/
-static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
- int cid)
-{
- unsigned long end = jiffies + msecs_to_jiffies(timeout);
- u16 reg = 1;
- int ret;
-
- ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
- if (timeout == 0)
- return ret;
-
- while (ret >= 0 && time_is_after_jiffies(end)) {
- ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, &reg);
- if (!reg)
- return 0;
- usleep_range(1000, 5000);
- }
- return ret ? ret : -ETIMEDOUT;
-}
-
-/**
- * s5k6aa_set_prev_config - write user preview register set
- * @s5k6aa: pointer to &struct s5k6aa describing the device
- * @preset: s5kaa preset to be applied
- *
- * Configure output resolution and color format, pixel clock
- * frequency range, device frame rate type and frame period range.
- */
-static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
- struct s5k6aa_preset *preset)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int idx = preset->index;
- u16 frame_rate_q;
- int ret;
-
- if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
- frame_rate_q = FR_RATE_Q_BEST_FRRATE;
- else
- frame_rate_q = FR_RATE_Q_BEST_QUALITY;
-
- ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
- s5k6aa->pclk_fmax);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
- s5k6aa->pclk_fmin);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
- preset->clk_id);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
- FR_RATE_DYNAMIC);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
- frame_rate_q);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
- s5k6aa->fiv->reg_fr_time + 33);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
- s5k6aa->fiv->reg_fr_time - 33);
- if (!ret)
- ret = s5k6aa_new_config_sync(client, 250, idx);
- if (!ret)
- ret = s5k6aa_preview_config_status(client);
- if (!ret)
- s5k6aa->apply_cfg = 0;
-
- v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
- s5k6aa->fiv->reg_fr_time, ret);
- return ret;
-}
-
-/**
- * s5k6aa_initialize_isp - basic ISP MCU initialization
- * @sd: pointer to V4L2 sub-device descriptor
- *
- * Configure AHB addresses for registers read/write; configure PLLs for
- * required output pixel clock. The ISP power supply needs to be already
- * enabled, with an optional H/W reset.
- * Locking: called with s5k6aa.lock mutex held.
- */
-static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- s5k6aa->apply_crop = 1;
- s5k6aa->apply_cfg = 1;
- msleep(100);
-
- ret = s5k6aa_set_ahb_address(client);
- if (ret)
- return ret;
- ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
- s5k6aa->mipi_lanes);
- if (ret)
- return ret;
- ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
- if (ret)
- return ret;
- msleep(20);
-
- return s5k6aa_configure_pixel_clocks(s5k6aa);
-}
-
-static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
-{
- if (!gpio_is_valid(priv->gpio[id].gpio))
- return 0;
- gpio_set_value(priv->gpio[id].gpio, !!val);
- return 1;
-}
-
-static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
-{
- return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
-}
-
-static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
-{
- return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
-}
-
-static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
-{
- int ret;
-
- ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
- if (ret)
- return ret;
- if (s5k6aa_gpio_deassert(s5k6aa, STBY))
- usleep_range(150, 200);
-
- if (s5k6aa->s_power)
- ret = s5k6aa->s_power(1);
- usleep_range(4000, 5000);
-
- if (s5k6aa_gpio_deassert(s5k6aa, RSET))
- msleep(20);
-
- return ret;
-}
-
-static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
-{
- int ret;
-
- if (s5k6aa_gpio_assert(s5k6aa, RSET))
- usleep_range(100, 150);
-
- if (s5k6aa->s_power) {
- ret = s5k6aa->s_power(0);
- if (ret)
- return ret;
- }
- if (s5k6aa_gpio_assert(s5k6aa, STBY))
- usleep_range(50, 100);
- s5k6aa->streaming = 0;
-
- return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
-}
-
-/*
- * V4L2 subdev core and video operations
- */
-static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
-
- if (s5k6aa->power == !on) {
- if (on) {
- ret = __s5k6aa_power_on(s5k6aa);
- if (!ret)
- ret = s5k6aa_initialize_isp(sd);
- } else {
- ret = __s5k6aa_power_off(s5k6aa);
- }
-
- if (!ret)
- s5k6aa->power += on ? 1 : -1;
- }
-
- mutex_unlock(&s5k6aa->lock);
-
- if (!on || ret || s5k6aa->power != 1)
- return ret;
-
- return v4l2_ctrl_handler_setup(sd->ctrl_handler);
-}
-
-static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int ret = 0;
-
- ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
- if (!ret)
- s5k6aa->streaming = enable;
-
- return ret;
-}
-
-static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
-
- if (s5k6aa->streaming == !on) {
- if (!ret && s5k6aa->apply_cfg)
- ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
- if (s5k6aa->apply_crop)
- ret = s5k6aa_set_input_params(s5k6aa);
- if (!ret)
- ret = __s5k6aa_stream(s5k6aa, !!on);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
-
- mutex_lock(&s5k6aa->lock);
- fi->interval = s5k6aa->fiv->interval;
- mutex_unlock(&s5k6aa->lock);
-
- return 0;
-}
-
-static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
- const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
- unsigned int err, min_err = UINT_MAX;
- unsigned int i, fr_time;
-
- if (fi->interval.denominator == 0)
- return -EINVAL;
-
- fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
- const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
-
- if (mbus_fmt->width > iv->size.width ||
- mbus_fmt->height > iv->size.height)
- continue;
-
- err = abs(iv->reg_fr_time - fr_time);
- if (err < min_err) {
- fiv = iv;
- min_err = err;
- }
- }
- s5k6aa->fiv = fiv;
-
- v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
- fiv->reg_fr_time * 100);
- return 0;
-}
-
-static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
- fi->interval.numerator, fi->interval.denominator);
-
- mutex_lock(&s5k6aa->lock);
- ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
- s5k6aa->apply_cfg = 1;
-
- mutex_unlock(&s5k6aa->lock);
- return ret;
-}
-
-/*
- * V4L2 subdev pad level and video operations
- */
-static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_interval_enum *fie)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- const struct s5k6aa_interval *fi;
- int ret = 0;
-
- if (fie->index >= ARRAY_SIZE(s5k6aa_intervals))
- return -EINVAL;
-
- v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &fie->height, S5K6AA_WIN_HEIGHT_MIN,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- mutex_lock(&s5k6aa->lock);
- fi = &s5k6aa_intervals[fie->index];
- if (fie->width > fi->size.width || fie->height > fi->size.height)
- ret = -EINVAL;
- else
- fie->interval = fi->interval;
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index >= ARRAY_SIZE(s5k6aa_formats))
- return -EINVAL;
-
- code->code = s5k6aa_formats[code->index].code;
- return 0;
-}
-
-static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- int i = ARRAY_SIZE(s5k6aa_formats);
-
- if (fse->index > 0)
- return -EINVAL;
-
- while (--i)
- if (fse->code == s5k6aa_formats[i].code)
- break;
-
- fse->code = s5k6aa_formats[i].code;
- fse->min_width = S5K6AA_WIN_WIDTH_MIN;
- fse->max_width = S5K6AA_WIN_WIDTH_MAX;
- fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
- fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
-
- return 0;
-}
-
-static struct v4l2_rect *
-__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &s5k6aa->ccd_rect;
-
- WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
- return v4l2_subdev_get_try_crop(&s5k6aa->sd, sd_state, 0);
-}
-
-static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
- struct v4l2_mbus_framefmt *mf)
-{
- unsigned int index;
-
- v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &mf->height, S5K6AA_WIN_HEIGHT_MIN,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
- mf->colorspace != V4L2_COLORSPACE_REC709)
- mf->colorspace = V4L2_COLORSPACE_JPEG;
-
- index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
-
- mf->colorspace = s5k6aa_formats[index].colorspace;
- mf->code = s5k6aa_formats[index].code;
- mf->field = V4L2_FIELD_NONE;
-}
-
-static int s5k6aa_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_mbus_framefmt *mf;
-
- memset(fmt->reserved, 0, sizeof(fmt->reserved));
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- fmt->format = *mf;
- return 0;
- }
-
- mutex_lock(&s5k6aa->lock);
- fmt->format = s5k6aa->preset->mbus_fmt;
- mutex_unlock(&s5k6aa->lock);
-
- return 0;
-}
-
-static int s5k6aa_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct s5k6aa_preset *preset = s5k6aa->preset;
- struct v4l2_mbus_framefmt *mf;
- struct v4l2_rect *crop;
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
- s5k6aa_try_format(s5k6aa, &fmt->format);
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
- crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
- } else {
- if (s5k6aa->streaming) {
- ret = -EBUSY;
- } else {
- mf = &preset->mbus_fmt;
- crop = &s5k6aa->ccd_rect;
- s5k6aa->apply_cfg = 1;
- }
- }
-
- if (ret == 0) {
- struct v4l2_subdev_frame_interval fiv = {
- .interval = {0, 1}
- };
-
- *mf = fmt->format;
- /*
- * Make sure the crop window is valid, i.e. its size is
- * greater than the output window, as the ISP supports
- * only down-scaling.
- */
- crop->width = clamp_t(unsigned int, crop->width, mf->width,
- S5K6AA_WIN_WIDTH_MAX);
- crop->height = clamp_t(unsigned int, crop->height, mf->height,
- S5K6AA_WIN_HEIGHT_MAX);
- crop->left = clamp_t(unsigned int, crop->left, 0,
- S5K6AA_WIN_WIDTH_MAX - crop->width);
- crop->top = clamp_t(unsigned int, crop->top, 0,
- S5K6AA_WIN_HEIGHT_MAX - crop->height);
-
- /* Reset to minimum possible frame interval */
- ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_rect *rect;
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- memset(sel->reserved, 0, sizeof(sel->reserved));
-
- mutex_lock(&s5k6aa->lock);
- rect = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
- sel->r = *rect;
- mutex_unlock(&s5k6aa->lock);
-
- v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
- rect->left, rect->top, rect->width, rect->height);
-
- return 0;
-}
-
-static int s5k6aa_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_selection *sel)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_mbus_framefmt *mf;
- unsigned int max_x, max_y;
- struct v4l2_rect *crop_r;
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- mutex_lock(&s5k6aa->lock);
- crop_r = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- mf = &s5k6aa->preset->mbus_fmt;
- s5k6aa->apply_crop = 1;
- } else {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
- }
- v4l_bound_align_image(&sel->r.width, mf->width,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &sel->r.height, mf->height,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1;
- max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1;
-
- sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x);
- sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y);
-
- *crop_r = sel->r;
-
- mutex_unlock(&s5k6aa->lock);
-
- v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
- crop_r->left, crop_r->top, crop_r->width, crop_r->height);
-
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
- .enum_mbus_code = s5k6aa_enum_mbus_code,
- .enum_frame_size = s5k6aa_enum_frame_size,
- .enum_frame_interval = s5k6aa_enum_frame_interval,
- .get_fmt = s5k6aa_get_fmt,
- .set_fmt = s5k6aa_set_fmt,
- .get_selection = s5k6aa_get_selection,
- .set_selection = s5k6aa_set_selection,
-};
-
-static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
- .g_frame_interval = s5k6aa_g_frame_interval,
- .s_frame_interval = s5k6aa_s_frame_interval,
- .s_stream = s5k6aa_s_stream,
-};
-
-/*
- * V4L2 subdev controls
- */
-
-static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int idx, err = 0;
-
- v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
-
- mutex_lock(&s5k6aa->lock);
- /*
- * If the device is not powered up by the host driver do
- * not apply any controls to H/W at this time. Instead
- * the controls will be restored right after power-up.
- */
- if (s5k6aa->power == 0)
- goto unlock;
- idx = s5k6aa->preset->index;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTO_WHITE_BALANCE:
- err = s5k6aa_set_awb(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_BRIGHTNESS:
- err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
- break;
-
- case V4L2_CID_COLORFX:
- err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_CONTRAST:
- err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
- break;
-
- case V4L2_CID_EXPOSURE_AUTO:
- err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_HFLIP:
- err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
- if (err)
- break;
- err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- break;
-
- case V4L2_CID_POWER_LINE_FREQUENCY:
- err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_SATURATION:
- err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
- break;
-
- case V4L2_CID_SHARPNESS:
- err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
- break;
-
- case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
- err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
- if (err)
- break;
- err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- break;
- }
-unlock:
- mutex_unlock(&s5k6aa->lock);
- return err;
-}
-
-static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
- .s_ctrl = s5k6aa_s_ctrl,
-};
-
-static int s5k6aa_log_status(struct v4l2_subdev *sd)
-{
- v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
- return 0;
-}
-
-#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001)
-#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002)
-#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003)
-
-static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
- {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_RED_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Red",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- }, {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_GREEN_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Green",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- }, {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_BLUE_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Blue",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- },
-};
-
-static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
-{
- const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
- struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
- struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-
- int ret = v4l2_ctrl_handler_init(hdl, 16);
- if (ret)
- return ret;
- /* Auto white balance cluster */
- ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
- 0, 1, 1, 1);
- ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
- ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
- ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
- v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
-
- ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_cluster(2, &ctrls->hflip);
-
- ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
- V4L2_CID_EXPOSURE_AUTO,
- V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
- /* Exposure time: x 1 us */
- ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
- 0, 6000000U, 1, 100000U);
- /* Total gain: 256 <=> 1x */
- ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
- 0, 256, 1, 256);
- v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
-
- v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
- V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
-
- v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
- V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
-
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
- 0, 256, 1, 0);
-
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
-
- if (hdl->error) {
- ret = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return ret;
- }
-
- s5k6aa->sd.ctrl_handler = hdl;
- return 0;
-}
-
-/*
- * V4L2 subdev internal operations
- */
-static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
-
- format->colorspace = s5k6aa_formats[0].colorspace;
- format->code = s5k6aa_formats[0].code;
- format->width = S5K6AA_OUT_WIDTH_DEF;
- format->height = S5K6AA_OUT_HEIGHT_DEF;
- format->field = V4L2_FIELD_NONE;
-
- crop->width = S5K6AA_WIN_WIDTH_MAX;
- crop->height = S5K6AA_WIN_HEIGHT_MAX;
- crop->left = 0;
- crop->top = 0;
-
- return 0;
-}
-
-static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 api_ver = 0, fw_rev = 0;
-
- int ret = s5k6aa_set_ahb_address(client);
-
- if (!ret)
- ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
- if (!ret)
- ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
- if (ret) {
- v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
- return ret;
- }
-
- v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
- api_ver, fw_rev);
-
- return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
-}
-
-static int s5k6aa_registered(struct v4l2_subdev *sd)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- mutex_lock(&s5k6aa->lock);
- ret = __s5k6aa_power_on(s5k6aa);
- if (!ret) {
- msleep(100);
- ret = s5k6aa_check_fw_revision(s5k6aa);
- __s5k6aa_power_off(s5k6aa);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
- .registered = s5k6aa_registered,
- .open = s5k6aa_open,
-};
-
-static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
- .s_power = s5k6aa_set_power,
- .log_status = s5k6aa_log_status,
-};
-
-static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
- .core = &s5k6aa_core_ops,
- .pad = &s5k6aa_pad_ops,
- .video = &s5k6aa_video_ops,
-};
-
-/*
- * GPIO setup
- */
-
-static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
- const struct s5k6aa_platform_data *pdata)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- const struct s5k6aa_gpio *gpio;
- unsigned long flags;
- int ret;
-
- s5k6aa->gpio[STBY].gpio = -EINVAL;
- s5k6aa->gpio[RSET].gpio = -EINVAL;
-
- gpio = &pdata->gpio_stby;
- if (gpio_is_valid(gpio->gpio)) {
- flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
- | GPIOF_EXPORT;
- ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
- "S5K6AA_STBY");
- if (ret < 0)
- return ret;
-
- s5k6aa->gpio[STBY] = *gpio;
- }
-
- gpio = &pdata->gpio_reset;
- if (gpio_is_valid(gpio->gpio)) {
- flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
- | GPIOF_EXPORT;
- ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
- "S5K6AA_RST");
- if (ret < 0)
- return ret;
-
- s5k6aa->gpio[RSET] = *gpio;
- }
-
- return 0;
-}
-
-static int s5k6aa_probe(struct i2c_client *client)
-{
- const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
- struct v4l2_subdev *sd;
- struct s5k6aa *s5k6aa;
- int i, ret;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "Platform data not specified\n");
- return -EINVAL;
- }
-
- if (pdata->mclk_frequency == 0) {
- dev_err(&client->dev, "MCLK frequency not specified\n");
- return -EINVAL;
- }
-
- s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL);
- if (!s5k6aa)
- return -ENOMEM;
-
- mutex_init(&s5k6aa->lock);
-
- s5k6aa->mclk_frequency = pdata->mclk_frequency;
- s5k6aa->bus_type = pdata->bus_type;
- s5k6aa->mipi_lanes = pdata->nlanes;
- s5k6aa->s_power = pdata->set_power;
- s5k6aa->inv_hflip = pdata->horiz_flip;
- s5k6aa->inv_vflip = pdata->vert_flip;
-
- sd = &s5k6aa->sd;
- v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
- /* Static name; NEVER use in new drivers! */
- strscpy(sd->name, DRIVER_NAME, sizeof(sd->name));
-
- sd->internal_ops = &s5k6aa_subdev_internal_ops;
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad);
- if (ret)
- return ret;
-
- ret = s5k6aa_configure_gpios(s5k6aa, pdata);
- if (ret)
- goto out_err;
-
- for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
- s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
-
- ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
- s5k6aa->supplies);
- if (ret) {
- dev_err(&client->dev, "Failed to get regulators\n");
- goto out_err;
- }
-
- ret = s5k6aa_initialize_ctrls(s5k6aa);
- if (ret)
- goto out_err;
-
- s5k6aa_presets_data_init(s5k6aa);
-
- s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
- s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX;
- s5k6aa->ccd_rect.left = 0;
- s5k6aa->ccd_rect.top = 0;
-
- return 0;
-
-out_err:
- media_entity_cleanup(&s5k6aa->sd.entity);
- return ret;
-}
-
-static void s5k6aa_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- media_entity_cleanup(&sd->entity);
-}
-
-static const struct i2c_device_id s5k6aa_id[] = {
- { DRIVER_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
-
-
-static struct i2c_driver s5k6aa_i2c_driver = {
- .driver = {
- .name = DRIVER_NAME
- },
- .probe_new = s5k6aa_probe,
- .remove = s5k6aa_remove,
- .id_table = s5k6aa_id,
-};
-
-module_i2c_driver(s5k6aa_i2c_driver);
-
-MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
-MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
deleted file mode 100644
index a83c8bf1c5dd..000000000000
--- a/drivers/media/i2c/sr030pc30.c
+++ /dev/null
@@ -1,762 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP
- *
- * Copyright (C) 2010 Samsung Electronics Co., Ltd
- * Author: Sylwester Nawrocki, s.nawrocki@samsung.com
- *
- * Based on original driver authored by Dongsoo Nathaniel Kim
- * and HeungJun Kim <riverful.kim@samsung.com>.
- *
- * Based on mt9v011 Micron Digital Image Sensor driver
- * Copyright (c) 2009 Mauro Carvalho Chehab
- */
-
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-mediabus.h>
-#include <media/v4l2-ctrls.h>
-#include <media/i2c/sr030pc30.h>
-
-static int debug;
-module_param(debug, int, 0644);
-
-#define MODULE_NAME "SR030PC30"
-
-/*
- * Register offsets within a page
- * b15..b8 - page id, b7..b0 - register address
- */
-#define POWER_CTRL_REG 0x0001
-#define PAGEMODE_REG 0x03
-#define DEVICE_ID_REG 0x0004
-#define NOON010PC30_ID 0x86
-#define SR030PC30_ID 0x8C
-#define VDO_CTL1_REG 0x0010
-#define SUBSAMPL_NONE_VGA 0
-#define SUBSAMPL_QVGA 0x10
-#define SUBSAMPL_QQVGA 0x20
-#define VDO_CTL2_REG 0x0011
-#define SYNC_CTL_REG 0x0012
-#define WIN_ROWH_REG 0x0020
-#define WIN_ROWL_REG 0x0021
-#define WIN_COLH_REG 0x0022
-#define WIN_COLL_REG 0x0023
-#define WIN_HEIGHTH_REG 0x0024
-#define WIN_HEIGHTL_REG 0x0025
-#define WIN_WIDTHH_REG 0x0026
-#define WIN_WIDTHL_REG 0x0027
-#define HBLANKH_REG 0x0040
-#define HBLANKL_REG 0x0041
-#define VSYNCH_REG 0x0042
-#define VSYNCL_REG 0x0043
-/* page 10 */
-#define ISP_CTL_REG(n) (0x1010 + (n))
-#define YOFS_REG 0x1040
-#define DARK_YOFS_REG 0x1041
-#define AG_ABRTH_REG 0x1050
-#define SAT_CTL_REG 0x1060
-#define BSAT_REG 0x1061
-#define RSAT_REG 0x1062
-#define AG_SAT_TH_REG 0x1063
-/* page 11 */
-#define ZLPF_CTRL_REG 0x1110
-#define ZLPF_CTRL2_REG 0x1112
-#define ZLPF_AGH_THR_REG 0x1121
-#define ZLPF_THR_REG 0x1160
-#define ZLPF_DYN_THR_REG 0x1160
-/* page 12 */
-#define YCLPF_CTL1_REG 0x1240
-#define YCLPF_CTL2_REG 0x1241
-#define YCLPF_THR_REG 0x1250
-#define BLPF_CTL_REG 0x1270
-#define BLPF_THR1_REG 0x1274
-#define BLPF_THR2_REG 0x1275
-/* page 14 - Lens Shading Compensation */
-#define LENS_CTRL_REG 0x1410
-#define LENS_XCEN_REG 0x1420
-#define LENS_YCEN_REG 0x1421
-#define LENS_R_COMP_REG 0x1422
-#define LENS_G_COMP_REG 0x1423
-#define LENS_B_COMP_REG 0x1424
-/* page 15 - Color correction */
-#define CMC_CTL_REG 0x1510
-#define CMC_OFSGH_REG 0x1514
-#define CMC_OFSGL_REG 0x1516
-#define CMC_SIGN_REG 0x1517
-/* Color correction coefficients */
-#define CMC_COEF_REG(n) (0x1530 + (n))
-/* Color correction offset coefficients */
-#define CMC_OFS_REG(n) (0x1540 + (n))
-/* page 16 - Gamma correction */
-#define GMA_CTL_REG 0x1610
-/* Gamma correction coefficients 0.14 */
-#define GMA_COEF_REG(n) (0x1630 + (n))
-/* page 20 - Auto Exposure */
-#define AE_CTL1_REG 0x2010
-#define AE_CTL2_REG 0x2011
-#define AE_FRM_CTL_REG 0x2020
-#define AE_FINE_CTL_REG(n) (0x2028 + (n))
-#define EXP_TIMEH_REG 0x2083
-#define EXP_TIMEM_REG 0x2084
-#define EXP_TIMEL_REG 0x2085
-#define EXP_MMINH_REG 0x2086
-#define EXP_MMINL_REG 0x2087
-#define EXP_MMAXH_REG 0x2088
-#define EXP_MMAXM_REG 0x2089
-#define EXP_MMAXL_REG 0x208A
-/* page 22 - Auto White Balance */
-#define AWB_CTL1_REG 0x2210
-#define AWB_ENABLE 0x80
-#define AWB_CTL2_REG 0x2211
-#define MWB_ENABLE 0x01
-/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */
-#define AWB_RGAIN_REG 0x2280
-#define AWB_GGAIN_REG 0x2281
-#define AWB_BGAIN_REG 0x2282
-#define AWB_RMAX_REG 0x2283
-#define AWB_RMIN_REG 0x2284
-#define AWB_BMAX_REG 0x2285
-#define AWB_BMIN_REG 0x2286
-/* R, B gain range in bright light conditions */
-#define AWB_RMAXB_REG 0x2287
-#define AWB_RMINB_REG 0x2288
-#define AWB_BMAXB_REG 0x2289
-#define AWB_BMINB_REG 0x228A
-/* manual white balance, when AWB_CTL2[0]=1 */
-#define MWB_RGAIN_REG 0x22B2
-#define MWB_BGAIN_REG 0x22B3
-/* the token to mark an array end */
-#define REG_TERM 0xFFFF
-
-/* Minimum and maximum exposure time in ms */
-#define EXPOS_MIN_MS 1
-#define EXPOS_MAX_MS 125
-
-struct sr030pc30_info {
- struct v4l2_subdev sd;
- struct v4l2_ctrl_handler hdl;
- const struct sr030pc30_platform_data *pdata;
- const struct sr030pc30_format *curr_fmt;
- const struct sr030pc30_frmsize *curr_win;
- unsigned int hflip:1;
- unsigned int vflip:1;
- unsigned int sleep:1;
- struct {
- /* auto whitebalance control cluster */
- struct v4l2_ctrl *awb;
- struct v4l2_ctrl *red;
- struct v4l2_ctrl *blue;
- };
- struct {
- /* auto exposure control cluster */
- struct v4l2_ctrl *autoexp;
- struct v4l2_ctrl *exp;
- };
- u8 i2c_reg_page;
-};
-
-struct sr030pc30_format {
- u32 code;
- enum v4l2_colorspace colorspace;
- u16 ispctl1_reg;
-};
-
-struct sr030pc30_frmsize {
- u16 width;
- u16 height;
- int vid_ctl1;
-};
-
-struct i2c_regval {
- u16 addr;
- u16 val;
-};
-
-/* supported resolutions */
-static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
- {
- .width = 640,
- .height = 480,
- .vid_ctl1 = SUBSAMPL_NONE_VGA,
- }, {
- .width = 320,
- .height = 240,
- .vid_ctl1 = SUBSAMPL_QVGA,
- }, {
- .width = 160,
- .height = 120,
- .vid_ctl1 = SUBSAMPL_QQVGA,
- },
-};
-
-/* supported pixel formats */
-static const struct sr030pc30_format sr030pc30_formats[] = {
- {
- .code = MEDIA_BUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x03,
- }, {
- .code = MEDIA_BUS_FMT_YVYU8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x02,
- }, {
- .code = MEDIA_BUS_FMT_VYUY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0,
- }, {
- .code = MEDIA_BUS_FMT_UYVY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x01,
- }, {
- .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .ispctl1_reg = 0x40,
- },
-};
-
-static const struct i2c_regval sr030pc30_base_regs[] = {
- /* Window size and position within pixel matrix */
- { WIN_ROWH_REG, 0x00 }, { WIN_ROWL_REG, 0x06 },
- { WIN_COLH_REG, 0x00 }, { WIN_COLL_REG, 0x06 },
- { WIN_HEIGHTH_REG, 0x01 }, { WIN_HEIGHTL_REG, 0xE0 },
- { WIN_WIDTHH_REG, 0x02 }, { WIN_WIDTHL_REG, 0x80 },
- { HBLANKH_REG, 0x01 }, { HBLANKL_REG, 0x50 },
- { VSYNCH_REG, 0x00 }, { VSYNCL_REG, 0x14 },
- { SYNC_CTL_REG, 0 },
- /* Color corection and saturation */
- { ISP_CTL_REG(0), 0x30 }, { YOFS_REG, 0x80 },
- { DARK_YOFS_REG, 0x04 }, { AG_ABRTH_REG, 0x78 },
- { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 },
- { AG_SAT_TH_REG, 0xF0 }, { 0x1064, 0x80 },
- { CMC_CTL_REG, 0x03 }, { CMC_OFSGH_REG, 0x3C },
- { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x2F },
- { CMC_COEF_REG(0), 0xCB }, { CMC_OFS_REG(0), 0x87 },
- { CMC_COEF_REG(1), 0x61 }, { CMC_OFS_REG(1), 0x18 },
- { CMC_COEF_REG(2), 0x16 }, { CMC_OFS_REG(2), 0x91 },
- { CMC_COEF_REG(3), 0x23 }, { CMC_OFS_REG(3), 0x94 },
- { CMC_COEF_REG(4), 0xCE }, { CMC_OFS_REG(4), 0x9f },
- { CMC_COEF_REG(5), 0x2B }, { CMC_OFS_REG(5), 0x33 },
- { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x00 },
- { CMC_COEF_REG(7), 0x34 }, { CMC_OFS_REG(7), 0x94 },
- { CMC_COEF_REG(8), 0x75 }, { CMC_OFS_REG(8), 0x14 },
- /* Color corection coefficients */
- { GMA_CTL_REG, 0x03 }, { GMA_COEF_REG(0), 0x00 },
- { GMA_COEF_REG(1), 0x19 }, { GMA_COEF_REG(2), 0x26 },
- { GMA_COEF_REG(3), 0x3B }, { GMA_COEF_REG(4), 0x5D },
- { GMA_COEF_REG(5), 0x79 }, { GMA_COEF_REG(6), 0x8E },
- { GMA_COEF_REG(7), 0x9F }, { GMA_COEF_REG(8), 0xAF },
- { GMA_COEF_REG(9), 0xBD }, { GMA_COEF_REG(10), 0xCA },
- { GMA_COEF_REG(11), 0xDD }, { GMA_COEF_REG(12), 0xEC },
- { GMA_COEF_REG(13), 0xF7 }, { GMA_COEF_REG(14), 0xFF },
- /* Noise reduction, Z-LPF, YC-LPF and BLPF filters setup */
- { ZLPF_CTRL_REG, 0x99 }, { ZLPF_CTRL2_REG, 0x0E },
- { ZLPF_AGH_THR_REG, 0x29 }, { ZLPF_THR_REG, 0x0F },
- { ZLPF_DYN_THR_REG, 0x63 }, { YCLPF_CTL1_REG, 0x23 },
- { YCLPF_CTL2_REG, 0x3B }, { YCLPF_THR_REG, 0x05 },
- { BLPF_CTL_REG, 0x1D }, { BLPF_THR1_REG, 0x05 },
- { BLPF_THR2_REG, 0x04 },
- /* Automatic white balance */
- { AWB_CTL1_REG, 0xFB }, { AWB_CTL2_REG, 0x26 },
- { AWB_RMAX_REG, 0x54 }, { AWB_RMIN_REG, 0x2B },
- { AWB_BMAX_REG, 0x57 }, { AWB_BMIN_REG, 0x29 },
- { AWB_RMAXB_REG, 0x50 }, { AWB_RMINB_REG, 0x43 },
- { AWB_BMAXB_REG, 0x30 }, { AWB_BMINB_REG, 0x22 },
- /* Auto exposure */
- { AE_CTL1_REG, 0x8C }, { AE_CTL2_REG, 0x04 },
- { AE_FRM_CTL_REG, 0x01 }, { AE_FINE_CTL_REG(0), 0x3F },
- { AE_FINE_CTL_REG(1), 0xA3 }, { AE_FINE_CTL_REG(3), 0x34 },
- /* Lens shading compensation */
- { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 },
- { LENS_YCEN_REG, 0x70 }, { LENS_R_COMP_REG, 0x53 },
- { LENS_G_COMP_REG, 0x40 }, { LENS_B_COMP_REG, 0x3e },
- { REG_TERM, 0 },
-};
-
-static inline struct sr030pc30_info *to_sr030pc30(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct sr030pc30_info, sd);
-}
-
-static inline int set_i2c_page(struct sr030pc30_info *info,
- struct i2c_client *client, unsigned int reg)
-{
- int ret = 0;
- u32 page = reg >> 8 & 0xFF;
-
- if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
- ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
- if (!ret)
- info->i2c_reg_page = page;
- }
- return ret;
-}
-
-static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- int ret = set_i2c_page(info, client, reg_addr);
- if (!ret)
- ret = i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
- return ret;
-}
-
-static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- int ret = set_i2c_page(info, client, reg_addr);
- if (!ret)
- ret = i2c_smbus_write_byte_data(
- client, reg_addr & 0xFF, val);
- return ret;
-}
-
-static inline int sr030pc30_bulk_write_reg(struct v4l2_subdev *sd,
- const struct i2c_regval *msg)
-{
- while (msg->addr != REG_TERM) {
- int ret = cam_i2c_write(sd, msg->addr, msg->val);
- if (ret)
- return ret;
- msg++;
- }
- return 0;
-}
-
-/* Device reset and sleep mode control */
-static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
- bool reset, bool sleep)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
- u8 reg = sleep ? 0xF1 : 0xF0;
- int ret = 0;
-
- if (reset)
- ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
- if (!ret) {
- ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
- if (!ret) {
- info->sleep = sleep;
- if (reset)
- info->i2c_reg_page = -1;
- }
- }
- return ret;
-}
-
-static int sr030pc30_set_flip(struct v4l2_subdev *sd)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- s32 reg = cam_i2c_read(sd, VDO_CTL2_REG);
- if (reg < 0)
- return reg;
-
- reg &= 0x7C;
- if (info->hflip)
- reg |= 0x01;
- if (info->vflip)
- reg |= 0x02;
- return cam_i2c_write(sd, VDO_CTL2_REG, reg | 0x80);
-}
-
-/* Configure resolution, color format and image flip */
-static int sr030pc30_set_params(struct v4l2_subdev *sd)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
- int ret;
-
- if (!info->curr_win)
- return -EINVAL;
-
- /* Configure the resolution through subsampling */
- ret = cam_i2c_write(sd, VDO_CTL1_REG,
- info->curr_win->vid_ctl1);
-
- if (!ret && info->curr_fmt)
- ret = cam_i2c_write(sd, ISP_CTL_REG(0),
- info->curr_fmt->ispctl1_reg);
- if (!ret)
- ret = sr030pc30_set_flip(sd);
-
- return ret;
-}
-
-/* Find nearest matching image pixel size. */
-static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
-{
- unsigned int min_err = ~0;
- int i = ARRAY_SIZE(sr030pc30_sizes);
- const struct sr030pc30_frmsize *fsize = &sr030pc30_sizes[0],
- *match = NULL;
- while (i--) {
- int err = abs(fsize->width - mf->width)
- + abs(fsize->height - mf->height);
- if (err < min_err) {
- min_err = err;
- match = fsize;
- }
- fsize++;
- }
- if (match) {
- mf->width = match->width;
- mf->height = match->height;
- return 0;
- }
- return -EINVAL;
-}
-
-static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct sr030pc30_info *info =
- container_of(ctrl->handler, struct sr030pc30_info, hdl);
- struct v4l2_subdev *sd = &info->sd;
- int ret = 0;
-
- v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
- __func__, ctrl->id, ctrl->val);
-
- switch (ctrl->id) {
- case V4L2_CID_AUTO_WHITE_BALANCE:
- if (ctrl->is_new) {
- ret = cam_i2c_write(sd, AWB_CTL2_REG,
- ctrl->val ? 0x2E : 0x2F);
- if (!ret)
- ret = cam_i2c_write(sd, AWB_CTL1_REG,
- ctrl->val ? 0xFB : 0x7B);
- }
- if (!ret && info->blue->is_new)
- ret = cam_i2c_write(sd, MWB_BGAIN_REG, info->blue->val);
- if (!ret && info->red->is_new)
- ret = cam_i2c_write(sd, MWB_RGAIN_REG, info->red->val);
- return ret;
-
- case V4L2_CID_EXPOSURE_AUTO:
- /* auto anti-flicker is also enabled here */
- if (ctrl->is_new)
- ret = cam_i2c_write(sd, AE_CTL1_REG,
- ctrl->val == V4L2_EXPOSURE_AUTO ? 0xDC : 0x0C);
- if (info->exp->is_new) {
- unsigned long expos = info->exp->val;
-
- expos = expos * info->pdata->clk_rate / (8 * 1000);
-
- if (!ret)
- ret = cam_i2c_write(sd, EXP_TIMEH_REG,
- expos >> 16 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_TIMEM_REG,
- expos >> 8 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_TIMEL_REG,
- expos & 0xFF);
- }
- return ret;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (!code || code->pad ||
- code->index >= ARRAY_SIZE(sr030pc30_formats))
- return -EINVAL;
-
- code->code = sr030pc30_formats[code->index].code;
- return 0;
-}
-
-static int sr030pc30_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct v4l2_mbus_framefmt *mf;
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- if (!format || format->pad)
- return -EINVAL;
-
- mf = &format->format;
-
- if (!info->curr_win || !info->curr_fmt)
- return -EINVAL;
-
- mf->width = info->curr_win->width;
- mf->height = info->curr_win->height;
- mf->code = info->curr_fmt->code;
- mf->colorspace = info->curr_fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-/* Return nearest media bus frame format. */
-static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- int i;
-
- sr030pc30_try_frame_size(mf);
-
- for (i = 0; i < ARRAY_SIZE(sr030pc30_formats); i++) {
- if (mf->code == sr030pc30_formats[i].code)
- break;
- }
- if (i == ARRAY_SIZE(sr030pc30_formats))
- i = 0;
-
- mf->code = sr030pc30_formats[i].code;
-
- return &sr030pc30_formats[i];
-}
-
-/* Return nearest media bus frame format. */
-static int sr030pc30_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct sr030pc30_info *info = sd ? to_sr030pc30(sd) : NULL;
- const struct sr030pc30_format *fmt;
- struct v4l2_mbus_framefmt *mf;
-
- if (!sd || !format)
- return -EINVAL;
-
- mf = &format->format;
- if (format->pad)
- return -EINVAL;
-
- fmt = try_fmt(sd, mf);
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *mf;
- return 0;
- }
-
- info->curr_fmt = fmt;
-
- return sr030pc30_set_params(sd);
-}
-
-static int sr030pc30_base_config(struct v4l2_subdev *sd)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
- int ret;
- unsigned long expmin, expmax;
-
- ret = sr030pc30_bulk_write_reg(sd, sr030pc30_base_regs);
- if (!ret) {
- info->curr_fmt = &sr030pc30_formats[0];
- info->curr_win = &sr030pc30_sizes[0];
- ret = sr030pc30_set_params(sd);
- }
- if (!ret)
- ret = sr030pc30_pwr_ctrl(sd, false, false);
-
- if (ret)
- return ret;
-
- expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000);
- expmax = EXPOS_MAX_MS * info->pdata->clk_rate / (8 * 1000);
-
- v4l2_dbg(1, debug, sd, "%s: expmin= %lx, expmax= %lx", __func__,
- expmin, expmax);
-
- /* Setting up manual exposure time range */
- ret = cam_i2c_write(sd, EXP_MMINH_REG, expmin >> 8 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_MMINL_REG, expmin & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_MMAXH_REG, expmax >> 16 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_MMAXM_REG, expmax >> 8 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_MMAXL_REG, expmax & 0xFF);
-
- return ret;
-}
-
-static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct sr030pc30_info *info = to_sr030pc30(sd);
- const struct sr030pc30_platform_data *pdata = info->pdata;
- int ret;
-
- if (pdata == NULL) {
- WARN(1, "No platform data!\n");
- return -EINVAL;
- }
-
- /*
- * Put sensor into power sleep mode before switching off
- * power and disabling MCLK.
- */
- if (!on)
- sr030pc30_pwr_ctrl(sd, false, true);
-
- /* set_power controls sensor's power and clock */
- if (pdata->set_power) {
- ret = pdata->set_power(&client->dev, on);
- if (ret)
- return ret;
- }
-
- if (on) {
- ret = sr030pc30_base_config(sd);
- } else {
- ret = 0;
- info->curr_win = NULL;
- info->curr_fmt = NULL;
- }
-
- return ret;
-}
-
-static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
- .s_ctrl = sr030pc30_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
- .s_power = sr030pc30_s_power,
-};
-
-static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = {
- .enum_mbus_code = sr030pc30_enum_mbus_code,
- .get_fmt = sr030pc30_get_fmt,
- .set_fmt = sr030pc30_set_fmt,
-};
-
-static const struct v4l2_subdev_ops sr030pc30_ops = {
- .core = &sr030pc30_core_ops,
- .pad = &sr030pc30_pad_ops,
-};
-
-/*
- * Detect sensor type. Return 0 if SR030PC30 was detected
- * or -ENODEV otherwise.
- */
-static int sr030pc30_detect(struct i2c_client *client)
-{
- const struct sr030pc30_platform_data *pdata
- = client->dev.platform_data;
- int ret;
-
- /* Enable sensor's power and clock */
- if (pdata->set_power) {
- ret = pdata->set_power(&client->dev, 1);
- if (ret)
- return ret;
- }
-
- ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
-
- if (pdata->set_power)
- pdata->set_power(&client->dev, 0);
-
- if (ret < 0) {
- dev_err(&client->dev, "%s: I2C read failed\n", __func__);
- return ret;
- }
-
- return ret == SR030PC30_ID ? 0 : -ENODEV;
-}
-
-
-static int sr030pc30_probe(struct i2c_client *client)
-{
- struct sr030pc30_info *info;
- struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
- const struct sr030pc30_platform_data *pdata
- = client->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_err(&client->dev, "No platform data!");
- return -EIO;
- }
-
- ret = sr030pc30_detect(client);
- if (ret)
- return ret;
-
- info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- sd = &info->sd;
- info->pdata = client->dev.platform_data;
-
- v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
-
- hdl = &info->hdl;
- v4l2_ctrl_handler_init(hdl, 6);
- info->awb = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
- V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- info->red = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
- V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
- info->blue = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
- V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
- info->autoexp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
- V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 1);
- info->exp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
- V4L2_CID_EXPOSURE, EXPOS_MIN_MS, EXPOS_MAX_MS, 1, 30);
- sd->ctrl_handler = hdl;
- if (hdl->error) {
- int err = hdl->error;
-
- v4l2_ctrl_handler_free(hdl);
- return err;
- }
- v4l2_ctrl_auto_cluster(3, &info->awb, 0, false);
- v4l2_ctrl_auto_cluster(2, &info->autoexp, V4L2_EXPOSURE_MANUAL, false);
- v4l2_ctrl_handler_setup(hdl);
-
- info->i2c_reg_page = -1;
- info->hflip = 1;
-
- return 0;
-}
-
-static void sr030pc30_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
-}
-
-static const struct i2c_device_id sr030pc30_id[] = {
- { MODULE_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, sr030pc30_id);
-
-
-static struct i2c_driver sr030pc30_i2c_driver = {
- .driver = {
- .name = MODULE_NAME
- },
- .probe_new = sr030pc30_probe,
- .remove = sr030pc30_remove,
- .id_table = sr030pc30_id,
-};
-
-module_i2c_driver(sr030pc30_i2c_driver);
-
-MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
-MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c
index 5dcabee6677d..adbd093ad190 100644
--- a/drivers/media/i2c/st-vgxy61.c
+++ b/drivers/media/i2c/st-vgxy61.c
@@ -1334,7 +1334,6 @@ static int vgxy61_init_cfg(struct v4l2_subdev *sd,
struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
struct v4l2_subdev_format fmt = { 0 };
- sensor->current_mode = sensor->default_mode;
vgxy61_fill_framefmt(sensor, sensor->current_mode, &fmt.format,
VGXY61_MEDIA_BUS_FMT_DEF);
@@ -1549,7 +1548,7 @@ static int vgxy61_tx_from_ep(struct vgxy61_dev *sensor,
sensor->nb_of_lane = l_nb;
dev_dbg(&client->dev, "tx uses %d lanes", l_nb);
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < VGXY61_NB_POLARITIES; i++) {
dev_dbg(&client->dev, "log2phy[%d] = %d\n", i, log2phy[i]);
dev_dbg(&client->dev, "phy2log[%d] = %d\n", i, phy2log[i]);
dev_dbg(&client->dev, "polarity[%d] = %d\n", i, polarities[i]);
@@ -1735,6 +1734,12 @@ static int vgxy61_power_on(struct device *dev)
}
}
+ ret = vgxy61_detect(sensor);
+ if (ret) {
+ dev_err(&client->dev, "sensor detect failed %d\n", ret);
+ goto disable_clock;
+ }
+
ret = vgxy61_patch(sensor);
if (ret) {
dev_err(&client->dev, "sensor patch failed %d\n", ret);
@@ -1861,21 +1866,15 @@ static int vgxy61_probe(struct i2c_client *client)
if (ret)
return ret;
- ret = vgxy61_detect(sensor);
- if (ret) {
- dev_err(&client->dev, "sensor detect failed %d\n", ret);
- return ret;
- }
-
vgxy61_fill_sensor_param(sensor);
vgxy61_fill_framefmt(sensor, sensor->current_mode, &sensor->fmt,
VGXY61_MEDIA_BUS_FMT_DEF);
+ mutex_init(&sensor->lock);
+
ret = vgxy61_update_hdr(sensor, sensor->hdr);
if (ret)
- return ret;
-
- mutex_init(&sensor->lock);
+ goto error_power_off;
ret = vgxy61_init_controls(sensor);
if (ret) {
@@ -1914,8 +1913,8 @@ error_pm_runtime:
media_entity_cleanup(&sensor->sd.entity);
error_handler_free:
v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
- mutex_destroy(&sensor->lock);
error_power_off:
+ mutex_destroy(&sensor->lock);
vgxy61_power_off(dev);
return ret;
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index 4063754a6732..ec1a193ba161 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -854,11 +854,11 @@ static unsigned long tc358746_find_pll_settings(struct tc358746 *tc358746,
m_best = mul;
min_delta = delta;
best_freq = tmp;
- };
+ }
if (delta == 0)
break;
- };
+ }
if (!best_freq) {
dev_err(dev, "Failed find PLL frequency\n");
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
deleted file mode 100644
index d35c5ec148f4..000000000000
--- a/drivers/media/i2c/vs6624.c
+++ /dev/null
@@ -1,854 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * vs6624.c ST VS6624 CMOS image sensor driver
- *
- * Copyright (c) 2011 Analog Devices Inc.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-mediabus.h>
-#include <media/v4l2-image-sizes.h>
-
-#include "vs6624_regs.h"
-
-#define MAX_FRAME_RATE 30
-
-struct vs6624 {
- struct v4l2_subdev sd;
- struct v4l2_ctrl_handler hdl;
- struct v4l2_fract frame_rate;
- struct v4l2_mbus_framefmt fmt;
- unsigned ce_pin;
-};
-
-static const struct vs6624_format {
- u32 mbus_code;
- enum v4l2_colorspace colorspace;
-} vs6624_formats[] = {
- {
- .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
- {
- .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
- {
- .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- },
-};
-
-static const struct v4l2_mbus_framefmt vs6624_default_fmt = {
- .width = VGA_WIDTH,
- .height = VGA_HEIGHT,
- .code = MEDIA_BUS_FMT_UYVY8_2X8,
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_JPEG,
-};
-
-static const u16 vs6624_p1[] = {
- 0x8104, 0x03,
- 0x8105, 0x01,
- 0xc900, 0x03,
- 0xc904, 0x47,
- 0xc905, 0x10,
- 0xc906, 0x80,
- 0xc907, 0x3a,
- 0x903a, 0x02,
- 0x903b, 0x47,
- 0x903c, 0x15,
- 0xc908, 0x31,
- 0xc909, 0xdc,
- 0xc90a, 0x80,
- 0xc90b, 0x44,
- 0x9044, 0x02,
- 0x9045, 0x31,
- 0x9046, 0xe2,
- 0xc90c, 0x07,
- 0xc90d, 0xe0,
- 0xc90e, 0x80,
- 0xc90f, 0x47,
- 0x9047, 0x90,
- 0x9048, 0x83,
- 0x9049, 0x81,
- 0x904a, 0xe0,
- 0x904b, 0x60,
- 0x904c, 0x08,
- 0x904d, 0x90,
- 0x904e, 0xc0,
- 0x904f, 0x43,
- 0x9050, 0x74,
- 0x9051, 0x01,
- 0x9052, 0xf0,
- 0x9053, 0x80,
- 0x9054, 0x05,
- 0x9055, 0xE4,
- 0x9056, 0x90,
- 0x9057, 0xc0,
- 0x9058, 0x43,
- 0x9059, 0xf0,
- 0x905a, 0x02,
- 0x905b, 0x07,
- 0x905c, 0xec,
- 0xc910, 0x5d,
- 0xc911, 0xca,
- 0xc912, 0x80,
- 0xc913, 0x5d,
- 0x905d, 0xa3,
- 0x905e, 0x04,
- 0x905f, 0xf0,
- 0x9060, 0xa3,
- 0x9061, 0x04,
- 0x9062, 0xf0,
- 0x9063, 0x22,
- 0xc914, 0x72,
- 0xc915, 0x92,
- 0xc916, 0x80,
- 0xc917, 0x64,
- 0x9064, 0x74,
- 0x9065, 0x01,
- 0x9066, 0x02,
- 0x9067, 0x72,
- 0x9068, 0x95,
- 0xc918, 0x47,
- 0xc919, 0xf2,
- 0xc91a, 0x81,
- 0xc91b, 0x69,
- 0x9169, 0x74,
- 0x916a, 0x02,
- 0x916b, 0xf0,
- 0x916c, 0xec,
- 0x916d, 0xb4,
- 0x916e, 0x10,
- 0x916f, 0x0a,
- 0x9170, 0x90,
- 0x9171, 0x80,
- 0x9172, 0x16,
- 0x9173, 0xe0,
- 0x9174, 0x70,
- 0x9175, 0x04,
- 0x9176, 0x90,
- 0x9177, 0xd3,
- 0x9178, 0xc4,
- 0x9179, 0xf0,
- 0x917a, 0x22,
- 0xc91c, 0x0a,
- 0xc91d, 0xbe,
- 0xc91e, 0x80,
- 0xc91f, 0x73,
- 0x9073, 0xfc,
- 0x9074, 0xa3,
- 0x9075, 0xe0,
- 0x9076, 0xf5,
- 0x9077, 0x82,
- 0x9078, 0x8c,
- 0x9079, 0x83,
- 0x907a, 0xa3,
- 0x907b, 0xa3,
- 0x907c, 0xe0,
- 0x907d, 0xfc,
- 0x907e, 0xa3,
- 0x907f, 0xe0,
- 0x9080, 0xc3,
- 0x9081, 0x9f,
- 0x9082, 0xff,
- 0x9083, 0xec,
- 0x9084, 0x9e,
- 0x9085, 0xfe,
- 0x9086, 0x02,
- 0x9087, 0x0a,
- 0x9088, 0xea,
- 0xc920, 0x47,
- 0xc921, 0x38,
- 0xc922, 0x80,
- 0xc923, 0x89,
- 0x9089, 0xec,
- 0x908a, 0xd3,
- 0x908b, 0x94,
- 0x908c, 0x20,
- 0x908d, 0x40,
- 0x908e, 0x01,
- 0x908f, 0x1c,
- 0x9090, 0x90,
- 0x9091, 0xd3,
- 0x9092, 0xd4,
- 0x9093, 0xec,
- 0x9094, 0xf0,
- 0x9095, 0x02,
- 0x9096, 0x47,
- 0x9097, 0x3d,
- 0xc924, 0x45,
- 0xc925, 0xca,
- 0xc926, 0x80,
- 0xc927, 0x98,
- 0x9098, 0x12,
- 0x9099, 0x77,
- 0x909a, 0xd6,
- 0x909b, 0x02,
- 0x909c, 0x45,
- 0x909d, 0xcd,
- 0xc928, 0x20,
- 0xc929, 0xd5,
- 0xc92a, 0x80,
- 0xc92b, 0x9e,
- 0x909e, 0x90,
- 0x909f, 0x82,
- 0x90a0, 0x18,
- 0x90a1, 0xe0,
- 0x90a2, 0xb4,
- 0x90a3, 0x03,
- 0x90a4, 0x0e,
- 0x90a5, 0x90,
- 0x90a6, 0x83,
- 0x90a7, 0xbf,
- 0x90a8, 0xe0,
- 0x90a9, 0x60,
- 0x90aa, 0x08,
- 0x90ab, 0x90,
- 0x90ac, 0x81,
- 0x90ad, 0xfc,
- 0x90ae, 0xe0,
- 0x90af, 0xff,
- 0x90b0, 0xc3,
- 0x90b1, 0x13,
- 0x90b2, 0xf0,
- 0x90b3, 0x90,
- 0x90b4, 0x81,
- 0x90b5, 0xfc,
- 0x90b6, 0xe0,
- 0x90b7, 0xff,
- 0x90b8, 0x02,
- 0x90b9, 0x20,
- 0x90ba, 0xda,
- 0xc92c, 0x70,
- 0xc92d, 0xbc,
- 0xc92e, 0x80,
- 0xc92f, 0xbb,
- 0x90bb, 0x90,
- 0x90bc, 0x82,
- 0x90bd, 0x18,
- 0x90be, 0xe0,
- 0x90bf, 0xb4,
- 0x90c0, 0x03,
- 0x90c1, 0x06,
- 0x90c2, 0x90,
- 0x90c3, 0xc1,
- 0x90c4, 0x06,
- 0x90c5, 0x74,
- 0x90c6, 0x05,
- 0x90c7, 0xf0,
- 0x90c8, 0x90,
- 0x90c9, 0xd3,
- 0x90ca, 0xa0,
- 0x90cb, 0x02,
- 0x90cc, 0x70,
- 0x90cd, 0xbf,
- 0xc930, 0x72,
- 0xc931, 0x21,
- 0xc932, 0x81,
- 0xc933, 0x3b,
- 0x913b, 0x7d,
- 0x913c, 0x02,
- 0x913d, 0x7f,
- 0x913e, 0x7b,
- 0x913f, 0x02,
- 0x9140, 0x72,
- 0x9141, 0x25,
- 0xc934, 0x28,
- 0xc935, 0xae,
- 0xc936, 0x80,
- 0xc937, 0xd2,
- 0x90d2, 0xf0,
- 0x90d3, 0x90,
- 0x90d4, 0xd2,
- 0x90d5, 0x0a,
- 0x90d6, 0x02,
- 0x90d7, 0x28,
- 0x90d8, 0xb4,
- 0xc938, 0x28,
- 0xc939, 0xb1,
- 0xc93a, 0x80,
- 0xc93b, 0xd9,
- 0x90d9, 0x90,
- 0x90da, 0x83,
- 0x90db, 0xba,
- 0x90dc, 0xe0,
- 0x90dd, 0xff,
- 0x90de, 0x90,
- 0x90df, 0xd2,
- 0x90e0, 0x08,
- 0x90e1, 0xe0,
- 0x90e2, 0xe4,
- 0x90e3, 0xef,
- 0x90e4, 0xf0,
- 0x90e5, 0xa3,
- 0x90e6, 0xe0,
- 0x90e7, 0x74,
- 0x90e8, 0xff,
- 0x90e9, 0xf0,
- 0x90ea, 0x90,
- 0x90eb, 0xd2,
- 0x90ec, 0x0a,
- 0x90ed, 0x02,
- 0x90ee, 0x28,
- 0x90ef, 0xb4,
- 0xc93c, 0x29,
- 0xc93d, 0x79,
- 0xc93e, 0x80,
- 0xc93f, 0xf0,
- 0x90f0, 0xf0,
- 0x90f1, 0x90,
- 0x90f2, 0xd2,
- 0x90f3, 0x0e,
- 0x90f4, 0x02,
- 0x90f5, 0x29,
- 0x90f6, 0x7f,
- 0xc940, 0x29,
- 0xc941, 0x7c,
- 0xc942, 0x80,
- 0xc943, 0xf7,
- 0x90f7, 0x90,
- 0x90f8, 0x83,
- 0x90f9, 0xba,
- 0x90fa, 0xe0,
- 0x90fb, 0xff,
- 0x90fc, 0x90,
- 0x90fd, 0xd2,
- 0x90fe, 0x0c,
- 0x90ff, 0xe0,
- 0x9100, 0xe4,
- 0x9101, 0xef,
- 0x9102, 0xf0,
- 0x9103, 0xa3,
- 0x9104, 0xe0,
- 0x9105, 0x74,
- 0x9106, 0xff,
- 0x9107, 0xf0,
- 0x9108, 0x90,
- 0x9109, 0xd2,
- 0x910a, 0x0e,
- 0x910b, 0x02,
- 0x910c, 0x29,
- 0x910d, 0x7f,
- 0xc944, 0x2a,
- 0xc945, 0x42,
- 0xc946, 0x81,
- 0xc947, 0x0e,
- 0x910e, 0xf0,
- 0x910f, 0x90,
- 0x9110, 0xd2,
- 0x9111, 0x12,
- 0x9112, 0x02,
- 0x9113, 0x2a,
- 0x9114, 0x48,
- 0xc948, 0x2a,
- 0xc949, 0x45,
- 0xc94a, 0x81,
- 0xc94b, 0x15,
- 0x9115, 0x90,
- 0x9116, 0x83,
- 0x9117, 0xba,
- 0x9118, 0xe0,
- 0x9119, 0xff,
- 0x911a, 0x90,
- 0x911b, 0xd2,
- 0x911c, 0x10,
- 0x911d, 0xe0,
- 0x911e, 0xe4,
- 0x911f, 0xef,
- 0x9120, 0xf0,
- 0x9121, 0xa3,
- 0x9122, 0xe0,
- 0x9123, 0x74,
- 0x9124, 0xff,
- 0x9125, 0xf0,
- 0x9126, 0x90,
- 0x9127, 0xd2,
- 0x9128, 0x12,
- 0x9129, 0x02,
- 0x912a, 0x2a,
- 0x912b, 0x48,
- 0xc900, 0x01,
- 0x0000, 0x00,
-};
-
-static const u16 vs6624_p2[] = {
- 0x806f, 0x01,
- 0x058c, 0x01,
- 0x0000, 0x00,
-};
-
-static const u16 vs6624_run_setup[] = {
- 0x1d18, 0x00, /* Enableconstrainedwhitebalance */
- VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */
- VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */
- VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */
- VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
- VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */
- VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */
- VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */
- VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
- VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */
- VS6624_NORA_USAGE, 0x04, /* Nora usage */
- VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */
- VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
- VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */
- VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */
- VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */
- VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
- VS6624_F2B_DISABLE, 0x00, /* Disable */
- 0x1d8a, 0x30, /* MAXWeightHigh */
- 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */
- 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */
- 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */
- 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */
- 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */
- 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */
- 0x1e08, 0x06, /* MAXWeightLow */
- 0x1e0a, 0x0a, /* MAXWeightHigh */
- 0x1601, 0x3a, /* Red A MSB */
- 0x1602, 0x14, /* Red A LSB */
- 0x1605, 0x3b, /* Blue A MSB */
- 0x1606, 0x85, /* BLue A LSB */
- 0x1609, 0x3b, /* RED B MSB */
- 0x160a, 0x85, /* RED B LSB */
- 0x160d, 0x3a, /* Blue B MSB */
- 0x160e, 0x14, /* Blue B LSB */
- 0x1611, 0x30, /* Max Distance from Locus MSB */
- 0x1612, 0x8f, /* Max Distance from Locus MSB */
- 0x1614, 0x01, /* Enable constrainer */
- 0x0000, 0x00,
-};
-
-static const u16 vs6624_default[] = {
- VS6624_CONTRAST0, 0x84,
- VS6624_SATURATION0, 0x75,
- VS6624_GAMMA0, 0x11,
- VS6624_CONTRAST1, 0x84,
- VS6624_SATURATION1, 0x75,
- VS6624_GAMMA1, 0x11,
- VS6624_MAN_RG, 0x80,
- VS6624_MAN_GG, 0x80,
- VS6624_MAN_BG, 0x80,
- VS6624_WB_MODE, 0x1,
- VS6624_EXPO_COMPENSATION, 0xfe,
- VS6624_EXPO_METER, 0x0,
- VS6624_LIGHT_FREQ, 0x64,
- VS6624_PEAK_GAIN, 0xe,
- VS6624_PEAK_LOW_THR, 0x28,
- VS6624_HMIRROR0, 0x0,
- VS6624_VFLIP0, 0x0,
- VS6624_ZOOM_HSTEP0_MSB, 0x0,
- VS6624_ZOOM_HSTEP0_LSB, 0x1,
- VS6624_ZOOM_VSTEP0_MSB, 0x0,
- VS6624_ZOOM_VSTEP0_LSB, 0x1,
- VS6624_PAN_HSTEP0_MSB, 0x0,
- VS6624_PAN_HSTEP0_LSB, 0xf,
- VS6624_PAN_VSTEP0_MSB, 0x0,
- VS6624_PAN_VSTEP0_LSB, 0xf,
- VS6624_SENSOR_MODE, 0x1,
- VS6624_SYNC_CODE_SETUP, 0x21,
- VS6624_DISABLE_FR_DAMPER, 0x0,
- VS6624_FR_DEN, 0x1,
- VS6624_FR_NUM_LSB, 0xf,
- VS6624_INIT_PIPE_SETUP, 0x0,
- VS6624_IMG_FMT0, 0x0,
- VS6624_YUV_SETUP, 0x1,
- VS6624_IMAGE_SIZE0, 0x2,
- 0x0000, 0x00,
-};
-
-static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct vs6624, sd);
-}
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vs6624_read(struct v4l2_subdev *sd, u16 index)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u8 buf[2];
-
- buf[0] = index >> 8;
- buf[1] = index;
- i2c_master_send(client, buf, 2);
- i2c_master_recv(client, buf, 1);
-
- return buf[0];
-}
-#endif
-
-static int vs6624_write(struct v4l2_subdev *sd, u16 index,
- u8 value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u8 buf[3];
-
- buf[0] = index >> 8;
- buf[1] = index;
- buf[2] = value;
-
- return i2c_master_send(client, buf, 3);
-}
-
-static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
-{
- u16 reg;
- u8 data;
-
- while (*regs != 0x00) {
- reg = *regs++;
- data = *regs++;
-
- vs6624_write(sd, reg, data);
- }
- return 0;
-}
-
-static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
-
- switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
- break;
- case V4L2_CID_SATURATION:
- vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
- break;
- case V4L2_CID_HFLIP:
- vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
- break;
- case V4L2_CID_VFLIP:
- vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
- return -EINVAL;
-
- code->code = vs6624_formats[code->index].mbus_code;
- return 0;
-}
-
-static int vs6624_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct vs6624 *sensor = to_vs6624(sd);
- int index;
-
- if (format->pad)
- return -EINVAL;
-
- for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
- if (vs6624_formats[index].mbus_code == fmt->code)
- break;
- if (index >= ARRAY_SIZE(vs6624_formats)) {
- /* default to first format */
- index = 0;
- fmt->code = vs6624_formats[0].mbus_code;
- }
-
- /* sensor mode is VGA */
- if (fmt->width > VGA_WIDTH)
- fmt->width = VGA_WIDTH;
- if (fmt->height > VGA_HEIGHT)
- fmt->height = VGA_HEIGHT;
- fmt->width = fmt->width & (~3);
- fmt->height = fmt->height & (~3);
- fmt->field = V4L2_FIELD_NONE;
- fmt->colorspace = vs6624_formats[index].colorspace;
-
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
- return 0;
- }
-
- /* set image format */
- switch (fmt->code) {
- case MEDIA_BUS_FMT_UYVY8_2X8:
- vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
- vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
- break;
- case MEDIA_BUS_FMT_YUYV8_2X8:
- vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
- vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
- break;
- case MEDIA_BUS_FMT_RGB565_2X8_LE:
- vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
- vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
- break;
- default:
- return -EINVAL;
- }
-
- /* set image size */
- if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
- else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
- else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
- else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
- else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
- else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
- else {
- vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
- vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
- vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
- vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
- vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
- vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
- }
-
- sensor->fmt = *fmt;
-
- return 0;
-}
-
-static int vs6624_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct vs6624 *sensor = to_vs6624(sd);
-
- if (format->pad)
- return -EINVAL;
-
- format->format = sensor->fmt;
- return 0;
-}
-
-static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
-{
- struct vs6624 *sensor = to_vs6624(sd);
-
- ival->interval.numerator = sensor->frame_rate.denominator;
- ival->interval.denominator = sensor->frame_rate.numerator;
- return 0;
-}
-
-static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
-{
- struct vs6624 *sensor = to_vs6624(sd);
- struct v4l2_fract *tpf = &ival->interval;
-
-
- if (tpf->numerator == 0 || tpf->denominator == 0
- || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
- /* reset to max frame rate */
- tpf->numerator = 1;
- tpf->denominator = MAX_FRAME_RATE;
- }
- sensor->frame_rate.numerator = tpf->denominator;
- sensor->frame_rate.denominator = tpf->numerator;
- vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
- vs6624_write(sd, VS6624_FR_NUM_MSB,
- sensor->frame_rate.numerator >> 8);
- vs6624_write(sd, VS6624_FR_NUM_LSB,
- sensor->frame_rate.numerator & 0xFF);
- vs6624_write(sd, VS6624_FR_DEN,
- sensor->frame_rate.denominator & 0xFF);
- return 0;
-}
-
-static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
-{
- if (enable)
- vs6624_write(sd, VS6624_USER_CMD, 0x2);
- else
- vs6624_write(sd, VS6624_USER_CMD, 0x4);
- udelay(100);
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
-{
- reg->val = vs6624_read(sd, reg->reg & 0xffff);
- reg->size = 1;
- return 0;
-}
-
-static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
-{
- vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
- return 0;
-}
-#endif
-
-static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
- .s_ctrl = vs6624_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops vs6624_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = vs6624_g_register,
- .s_register = vs6624_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_video_ops vs6624_video_ops = {
- .s_frame_interval = vs6624_s_frame_interval,
- .g_frame_interval = vs6624_g_frame_interval,
- .s_stream = vs6624_s_stream,
-};
-
-static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
- .enum_mbus_code = vs6624_enum_mbus_code,
- .get_fmt = vs6624_get_fmt,
- .set_fmt = vs6624_set_fmt,
-};
-
-static const struct v4l2_subdev_ops vs6624_ops = {
- .core = &vs6624_core_ops,
- .video = &vs6624_video_ops,
- .pad = &vs6624_pad_ops,
-};
-
-static int vs6624_probe(struct i2c_client *client)
-{
- struct vs6624 *sensor;
- struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
- const unsigned *ce;
- int ret;
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -EIO;
-
- ce = client->dev.platform_data;
- if (ce == NULL)
- return -EINVAL;
-
- ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
- "VS6624 Chip Enable");
- if (ret) {
- v4l_err(client, "failed to request GPIO %d\n", *ce);
- return ret;
- }
- /* wait 100ms before any further i2c writes are performed */
- msleep(100);
-
- sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
- if (sensor == NULL)
- return -ENOMEM;
-
- sd = &sensor->sd;
- v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
-
- vs6624_writeregs(sd, vs6624_p1);
- vs6624_write(sd, VS6624_MICRO_EN, 0x2);
- vs6624_write(sd, VS6624_DIO_EN, 0x1);
- usleep_range(10000, 11000);
- vs6624_writeregs(sd, vs6624_p2);
-
- vs6624_writeregs(sd, vs6624_default);
- vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
- vs6624_writeregs(sd, vs6624_run_setup);
-
- /* set frame rate */
- sensor->frame_rate.numerator = MAX_FRAME_RATE;
- sensor->frame_rate.denominator = 1;
- vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
- vs6624_write(sd, VS6624_FR_NUM_MSB,
- sensor->frame_rate.numerator >> 8);
- vs6624_write(sd, VS6624_FR_NUM_LSB,
- sensor->frame_rate.numerator & 0xFF);
- vs6624_write(sd, VS6624_FR_DEN,
- sensor->frame_rate.denominator & 0xFF);
-
- sensor->fmt = vs6624_default_fmt;
- sensor->ce_pin = *ce;
-
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- hdl = &sensor->hdl;
- v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
- v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
- V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
- v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- /* hook the control handler into the driver */
- sd->ctrl_handler = hdl;
- if (hdl->error) {
- int err = hdl->error;
-
- v4l2_ctrl_handler_free(hdl);
- return err;
- }
-
- /* initialize the hardware to the default control values */
- ret = v4l2_ctrl_handler_setup(hdl);
- if (ret)
- v4l2_ctrl_handler_free(hdl);
- return ret;
-}
-
-static void vs6624_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
-}
-
-static const struct i2c_device_id vs6624_id[] = {
- {"vs6624", 0},
- {},
-};
-
-MODULE_DEVICE_TABLE(i2c, vs6624_id);
-
-static struct i2c_driver vs6624_driver = {
- .driver = {
- .name = "vs6624",
- },
- .probe_new = vs6624_probe,
- .remove = vs6624_remove,
- .id_table = vs6624_id,
-};
-
-module_i2c_driver(vs6624_driver);
-
-MODULE_DESCRIPTION("VS6624 sensor driver");
-MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/vs6624_regs.h b/drivers/media/i2c/vs6624_regs.h
deleted file mode 100644
index 76c9ed0f2c89..000000000000
--- a/drivers/media/i2c/vs6624_regs.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * vs6624 - ST VS6624 CMOS image sensor registers
- *
- * Copyright (c) 2011 Analog Devices Inc.
- */
-
-#ifndef _VS6624_REGS_H_
-#define _VS6624_REGS_H_
-
-/* low level control registers */
-#define VS6624_MICRO_EN 0xC003 /* power enable for all MCU clock */
-#define VS6624_DIO_EN 0xC044 /* enable digital I/O */
-/* device parameters */
-#define VS6624_DEV_ID_MSB 0x0001 /* device id MSB */
-#define VS6624_DEV_ID_LSB 0x0002 /* device id LSB */
-#define VS6624_FW_VSN_MAJOR 0x0004 /* firmware version major */
-#define VS6624_FW_VSN_MINOR 0x0006 /* firmware version minor */
-#define VS6624_PATCH_VSN_MAJOR 0x0008 /* patch version major */
-#define VS6624_PATCH_VSN_MINOR 0x000A /* patch version minor */
-/* host interface manager control */
-#define VS6624_USER_CMD 0x0180 /* user level control of operating states */
-/* host interface manager status */
-#define VS6624_STATE 0x0202 /* current state of the mode manager */
-/* run mode control */
-#define VS6624_METER_ON 0x0280 /* if false AE and AWB are disabled */
-/* mode setup */
-#define VS6624_ACTIVE_PIPE_SETUP 0x0302 /* select the active bank for non view live mode */
-#define VS6624_SENSOR_MODE 0x0308 /* select the different sensor mode */
-/* pipe setup bank0 */
-#define VS6624_IMAGE_SIZE0 0x0380 /* required output dimension */
-#define VS6624_MAN_HSIZE0_MSB 0x0383 /* input required manual H size MSB */
-#define VS6624_MAN_HSIZE0_LSB 0x0384 /* input required manual H size LSB */
-#define VS6624_MAN_VSIZE0_MSB 0x0387 /* input required manual V size MSB */
-#define VS6624_MAN_VSIZE0_LSB 0x0388 /* input required manual V size LSB */
-#define VS6624_ZOOM_HSTEP0_MSB 0x038B /* set the zoom H step MSB */
-#define VS6624_ZOOM_HSTEP0_LSB 0x038C /* set the zoom H step LSB */
-#define VS6624_ZOOM_VSTEP0_MSB 0x038F /* set the zoom V step MSB */
-#define VS6624_ZOOM_VSTEP0_LSB 0x0390 /* set the zoom V step LSB */
-#define VS6624_ZOOM_CTRL0 0x0392 /* control zoon in, out and stop */
-#define VS6624_PAN_HSTEP0_MSB 0x0395 /* set the pan H step MSB */
-#define VS6624_PAN_HSTEP0_LSB 0x0396 /* set the pan H step LSB */
-#define VS6624_PAN_VSTEP0_MSB 0x0399 /* set the pan V step MSB */
-#define VS6624_PAN_VSTEP0_LSB 0x039A /* set the pan V step LSB */
-#define VS6624_PAN_CTRL0 0x039C /* control pan operation */
-#define VS6624_CROP_CTRL0 0x039E /* select cropping mode */
-#define VS6624_CROP_HSTART0_MSB 0x03A1 /* set the cropping H start address MSB */
-#define VS6624_CROP_HSTART0_LSB 0x03A2 /* set the cropping H start address LSB */
-#define VS6624_CROP_HSIZE0_MSB 0x03A5 /* set the cropping H size MSB */
-#define VS6624_CROP_HSIZE0_LSB 0x03A6 /* set the cropping H size LSB */
-#define VS6624_CROP_VSTART0_MSB 0x03A9 /* set the cropping V start address MSB */
-#define VS6624_CROP_VSTART0_LSB 0x03AA /* set the cropping V start address LSB */
-#define VS6624_CROP_VSIZE0_MSB 0x03AD /* set the cropping V size MSB */
-#define VS6624_CROP_VSIZE0_LSB 0x03AE /* set the cropping V size LSB */
-#define VS6624_IMG_FMT0 0x03B0 /* select required output image format */
-#define VS6624_BAYER_OUT_ALIGN0 0x03B2 /* set bayer output alignment */
-#define VS6624_CONTRAST0 0x03B4 /* contrast control for output */
-#define VS6624_SATURATION0 0x03B6 /* saturation control for output */
-#define VS6624_GAMMA0 0x03B8 /* gamma settings */
-#define VS6624_HMIRROR0 0x03BA /* horizontal image orientation flip */
-#define VS6624_VFLIP0 0x03BC /* vertical image orientation flip */
-#define VS6624_CHANNEL_ID0 0x03BE /* logical DMA channel number */
-/* pipe setup bank1 */
-#define VS6624_IMAGE_SIZE1 0x0400 /* required output dimension */
-#define VS6624_MAN_HSIZE1_MSB 0x0403 /* input required manual H size MSB */
-#define VS6624_MAN_HSIZE1_LSB 0x0404 /* input required manual H size LSB */
-#define VS6624_MAN_VSIZE1_MSB 0x0407 /* input required manual V size MSB */
-#define VS6624_MAN_VSIZE1_LSB 0x0408 /* input required manual V size LSB */
-#define VS6624_ZOOM_HSTEP1_MSB 0x040B /* set the zoom H step MSB */
-#define VS6624_ZOOM_HSTEP1_LSB 0x040C /* set the zoom H step LSB */
-#define VS6624_ZOOM_VSTEP1_MSB 0x040F /* set the zoom V step MSB */
-#define VS6624_ZOOM_VSTEP1_LSB 0x0410 /* set the zoom V step LSB */
-#define VS6624_ZOOM_CTRL1 0x0412 /* control zoon in, out and stop */
-#define VS6624_PAN_HSTEP1_MSB 0x0415 /* set the pan H step MSB */
-#define VS6624_PAN_HSTEP1_LSB 0x0416 /* set the pan H step LSB */
-#define VS6624_PAN_VSTEP1_MSB 0x0419 /* set the pan V step MSB */
-#define VS6624_PAN_VSTEP1_LSB 0x041A /* set the pan V step LSB */
-#define VS6624_PAN_CTRL1 0x041C /* control pan operation */
-#define VS6624_CROP_CTRL1 0x041E /* select cropping mode */
-#define VS6624_CROP_HSTART1_MSB 0x0421 /* set the cropping H start address MSB */
-#define VS6624_CROP_HSTART1_LSB 0x0422 /* set the cropping H start address LSB */
-#define VS6624_CROP_HSIZE1_MSB 0x0425 /* set the cropping H size MSB */
-#define VS6624_CROP_HSIZE1_LSB 0x0426 /* set the cropping H size LSB */
-#define VS6624_CROP_VSTART1_MSB 0x0429 /* set the cropping V start address MSB */
-#define VS6624_CROP_VSTART1_LSB 0x042A /* set the cropping V start address LSB */
-#define VS6624_CROP_VSIZE1_MSB 0x042D /* set the cropping V size MSB */
-#define VS6624_CROP_VSIZE1_LSB 0x042E /* set the cropping V size LSB */
-#define VS6624_IMG_FMT1 0x0430 /* select required output image format */
-#define VS6624_BAYER_OUT_ALIGN1 0x0432 /* set bayer output alignment */
-#define VS6624_CONTRAST1 0x0434 /* contrast control for output */
-#define VS6624_SATURATION1 0x0436 /* saturation control for output */
-#define VS6624_GAMMA1 0x0438 /* gamma settings */
-#define VS6624_HMIRROR1 0x043A /* horizontal image orientation flip */
-#define VS6624_VFLIP1 0x043C /* vertical image orientation flip */
-#define VS6624_CHANNEL_ID1 0x043E /* logical DMA channel number */
-/* view live control */
-#define VS6624_VIEW_LIVE_EN 0x0480 /* enable view live mode */
-#define VS6624_INIT_PIPE_SETUP 0x0482 /* select initial pipe setup bank */
-/* view live status */
-#define VS6624_CUR_PIPE_SETUP 0x0500 /* indicates most recently applied setup bank */
-/* power management */
-#define VS6624_TIME_TO_POWER_DOWN 0x0580 /* automatically transition time to stop mode */
-/* video timing parameter host inputs */
-#define VS6624_EXT_CLK_FREQ_NUM_MSB 0x0605 /* external clock frequency numerator MSB */
-#define VS6624_EXT_CLK_FREQ_NUM_LSB 0x0606 /* external clock frequency numerator LSB */
-#define VS6624_EXT_CLK_FREQ_DEN 0x0608 /* external clock frequency denominator */
-/* video timing control */
-#define VS6624_SYS_CLK_MODE 0x0880 /* decides system clock frequency */
-/* frame dimension parameter host inputs */
-#define VS6624_LIGHT_FREQ 0x0C80 /* AC frequency used for flicker free time */
-#define VS6624_FLICKER_COMPAT 0x0C82 /* flicker compatible frame length */
-/* static frame rate control */
-#define VS6624_FR_NUM_MSB 0x0D81 /* desired frame rate numerator MSB */
-#define VS6624_FR_NUM_LSB 0x0D82 /* desired frame rate numerator LSB */
-#define VS6624_FR_DEN 0x0D84 /* desired frame rate denominator */
-/* automatic frame rate control */
-#define VS6624_DISABLE_FR_DAMPER 0x0E80 /* defines frame rate mode */
-#define VS6624_MIN_DAMPER_OUT_MSB 0x0E8C /* minimum frame rate MSB */
-#define VS6624_MIN_DAMPER_OUT_LSB 0x0E8A /* minimum frame rate LSB */
-/* exposure controls */
-#define VS6624_EXPO_MODE 0x1180 /* exposure mode */
-#define VS6624_EXPO_METER 0x1182 /* weights to be associated with the zones */
-#define VS6624_EXPO_TIME_NUM 0x1184 /* exposure time numerator */
-#define VS6624_EXPO_TIME_DEN 0x1186 /* exposure time denominator */
-#define VS6624_EXPO_TIME_MSB 0x1189 /* exposure time for the Manual Mode MSB */
-#define VS6624_EXPO_TIME_LSB 0x118A /* exposure time for the Manual Mode LSB */
-#define VS6624_EXPO_COMPENSATION 0x1190 /* exposure compensation */
-#define VS6624_DIRECT_COARSE_MSB 0x1195 /* coarse integration lines for Direct Mode MSB */
-#define VS6624_DIRECT_COARSE_LSB 0x1196 /* coarse integration lines for Direct Mode LSB */
-#define VS6624_DIRECT_FINE_MSB 0x1199 /* fine integration pixels for Direct Mode MSB */
-#define VS6624_DIRECT_FINE_LSB 0x119A /* fine integration pixels for Direct Mode LSB */
-#define VS6624_DIRECT_ANAL_GAIN_MSB 0x119D /* analog gain for Direct Mode MSB */
-#define VS6624_DIRECT_ANAL_GAIN_LSB 0x119E /* analog gain for Direct Mode LSB */
-#define VS6624_DIRECT_DIGI_GAIN_MSB 0x11A1 /* digital gain for Direct Mode MSB */
-#define VS6624_DIRECT_DIGI_GAIN_LSB 0x11A2 /* digital gain for Direct Mode LSB */
-#define VS6624_FLASH_COARSE_MSB 0x11A5 /* coarse integration lines for Flash Gun Mode MSB */
-#define VS6624_FLASH_COARSE_LSB 0x11A6 /* coarse integration lines for Flash Gun Mode LSB */
-#define VS6624_FLASH_FINE_MSB 0x11A9 /* fine integration pixels for Flash Gun Mode MSB */
-#define VS6624_FLASH_FINE_LSB 0x11AA /* fine integration pixels for Flash Gun Mode LSB */
-#define VS6624_FLASH_ANAL_GAIN_MSB 0x11AD /* analog gain for Flash Gun Mode MSB */
-#define VS6624_FLASH_ANAL_GAIN_LSB 0x11AE /* analog gain for Flash Gun Mode LSB */
-#define VS6624_FLASH_DIGI_GAIN_MSB 0x11B1 /* digital gain for Flash Gun Mode MSB */
-#define VS6624_FLASH_DIGI_GAIN_LSB 0x11B2 /* digital gain for Flash Gun Mode LSB */
-#define VS6624_FREEZE_AE 0x11B4 /* freeze auto exposure */
-#define VS6624_MAX_INT_TIME_MSB 0x11B7 /* user maximum integration time MSB */
-#define VS6624_MAX_INT_TIME_LSB 0x11B8 /* user maximum integration time LSB */
-#define VS6624_FLASH_AG_THR_MSB 0x11BB /* recommend flash gun analog gain threshold MSB */
-#define VS6624_FLASH_AG_THR_LSB 0x11BC /* recommend flash gun analog gain threshold LSB */
-#define VS6624_ANTI_FLICKER_MODE 0x11C0 /* anti flicker mode */
-/* white balance control */
-#define VS6624_WB_MODE 0x1480 /* set white balance mode */
-#define VS6624_MAN_RG 0x1482 /* user setting for red channel gain */
-#define VS6624_MAN_GG 0x1484 /* user setting for green channel gain */
-#define VS6624_MAN_BG 0x1486 /* user setting for blue channel gain */
-#define VS6624_FLASH_RG_MSB 0x148B /* red gain for Flash Gun MSB */
-#define VS6624_FLASH_RG_LSB 0x148C /* red gain for Flash Gun LSB */
-#define VS6624_FLASH_GG_MSB 0x148F /* green gain for Flash Gun MSB */
-#define VS6624_FLASH_GG_LSB 0x1490 /* green gain for Flash Gun LSB */
-#define VS6624_FLASH_BG_MSB 0x1493 /* blue gain for Flash Gun MSB */
-#define VS6624_FLASH_BG_LSB 0x1494 /* blue gain for Flash Gun LSB */
-/* sensor setup */
-#define VS6624_BC_OFFSET 0x1990 /* Black Correction Offset */
-/* image stability */
-#define VS6624_STABLE_WB 0x1900 /* white balance stable */
-#define VS6624_STABLE_EXPO 0x1902 /* exposure stable */
-#define VS6624_STABLE 0x1906 /* system stable */
-/* flash control */
-#define VS6624_FLASH_MODE 0x1A80 /* flash mode */
-#define VS6624_FLASH_OFF_LINE_MSB 0x1A83 /* off line at flash pulse mode MSB */
-#define VS6624_FLASH_OFF_LINE_LSB 0x1A84 /* off line at flash pulse mode LSB */
-/* flash status */
-#define VS6624_FLASH_RECOM 0x1B00 /* flash gun is recommended */
-#define VS6624_FLASH_GRAB_COMPLETE 0x1B02 /* flash gun image has been grabbed */
-/* scythe filter controls */
-#define VS6624_SCYTHE_FILTER 0x1D80 /* disable scythe defect correction */
-/* jack filter controls */
-#define VS6624_JACK_FILTER 0x1E00 /* disable jack defect correction */
-/* demosaic control */
-#define VS6624_ANTI_ALIAS_FILTER 0x1E80 /* anti alias filter suppress */
-/* color matrix dampers */
-#define VS6624_CM_DISABLE 0x1F00 /* disable color matrix damper */
-#define VS6624_CM_LOW_THR_MSB 0x1F03 /* low threshold for exposure MSB */
-#define VS6624_CM_LOW_THR_LSB 0x1F04 /* low threshold for exposure LSB */
-#define VS6624_CM_HIGH_THR_MSB 0x1F07 /* high threshold for exposure MSB */
-#define VS6624_CM_HIGH_THR_LSB 0x1F08 /* high threshold for exposure LSB */
-#define VS6624_CM_MIN_OUT_MSB 0x1F0B /* minimum possible damper output MSB */
-#define VS6624_CM_MIN_OUT_LSB 0x1F0C /* minimum possible damper output LSB */
-/* peaking control */
-#define VS6624_PEAK_GAIN 0x2000 /* controls peaking gain */
-#define VS6624_PEAK_G_DISABLE 0x2002 /* disable peak gain damping */
-#define VS6624_PEAK_LOW_THR_G_MSB 0x2005 /* low threshold for exposure for gain MSB */
-#define VS6624_PEAK_LOW_THR_G_LSB 0x2006 /* low threshold for exposure for gain LSB */
-#define VS6624_PEAK_HIGH_THR_G_MSB 0x2009 /* high threshold for exposure for gain MSB */
-#define VS6624_PEAK_HIGH_THR_G_LSB 0x200A /* high threshold for exposure for gain LSB */
-#define VS6624_PEAK_MIN_OUT_G_MSB 0x200D /* minimum damper output for gain MSB */
-#define VS6624_PEAK_MIN_OUT_G_LSB 0x200E /* minimum damper output for gain LSB */
-#define VS6624_PEAK_LOW_THR 0x2010 /* adjust degree of coring */
-#define VS6624_PEAK_C_DISABLE 0x2012 /* disable coring damping */
-#define VS6624_PEAK_HIGH_THR 0x2014 /* adjust maximum gain */
-#define VS6624_PEAK_LOW_THR_C_MSB 0x2017 /* low threshold for exposure for coring MSB */
-#define VS6624_PEAK_LOW_THR_C_LSB 0x2018 /* low threshold for exposure for coring LSB */
-#define VS6624_PEAK_HIGH_THR_C_MSB 0x201B /* high threshold for exposure for coring MSB */
-#define VS6624_PEAK_HIGH_THR_C_LSB 0x201C /* high threshold for exposure for coring LSB */
-#define VS6624_PEAK_MIN_OUT_C_MSB 0x201F /* minimum damper output for coring MSB */
-#define VS6624_PEAK_MIN_OUT_C_LSB 0x2020 /* minimum damper output for coring LSB */
-/* pipe 0 RGB to YUV matrix manual control */
-#define VS6624_RYM0_MAN_CTRL 0x2180 /* enable manual RGB to YUV matrix */
-#define VS6624_RYM0_W00_MSB 0x2183 /* row 0 column 0 of YUV matrix MSB */
-#define VS6624_RYM0_W00_LSB 0x2184 /* row 0 column 0 of YUV matrix LSB */
-#define VS6624_RYM0_W01_MSB 0x2187 /* row 0 column 1 of YUV matrix MSB */
-#define VS6624_RYM0_W01_LSB 0x2188 /* row 0 column 1 of YUV matrix LSB */
-#define VS6624_RYM0_W02_MSB 0x218C /* row 0 column 2 of YUV matrix MSB */
-#define VS6624_RYM0_W02_LSB 0x218D /* row 0 column 2 of YUV matrix LSB */
-#define VS6624_RYM0_W10_MSB 0x2190 /* row 1 column 0 of YUV matrix MSB */
-#define VS6624_RYM0_W10_LSB 0x218F /* row 1 column 0 of YUV matrix LSB */
-#define VS6624_RYM0_W11_MSB 0x2193 /* row 1 column 1 of YUV matrix MSB */
-#define VS6624_RYM0_W11_LSB 0x2194 /* row 1 column 1 of YUV matrix LSB */
-#define VS6624_RYM0_W12_MSB 0x2197 /* row 1 column 2 of YUV matrix MSB */
-#define VS6624_RYM0_W12_LSB 0x2198 /* row 1 column 2 of YUV matrix LSB */
-#define VS6624_RYM0_W20_MSB 0x219B /* row 2 column 0 of YUV matrix MSB */
-#define VS6624_RYM0_W20_LSB 0x219C /* row 2 column 0 of YUV matrix LSB */
-#define VS6624_RYM0_W21_MSB 0x21A0 /* row 2 column 1 of YUV matrix MSB */
-#define VS6624_RYM0_W21_LSB 0x219F /* row 2 column 1 of YUV matrix LSB */
-#define VS6624_RYM0_W22_MSB 0x21A3 /* row 2 column 2 of YUV matrix MSB */
-#define VS6624_RYM0_W22_LSB 0x21A4 /* row 2 column 2 of YUV matrix LSB */
-#define VS6624_RYM0_YINY_MSB 0x21A7 /* Y in Y MSB */
-#define VS6624_RYM0_YINY_LSB 0x21A8 /* Y in Y LSB */
-#define VS6624_RYM0_YINCB_MSB 0x21AB /* Y in Cb MSB */
-#define VS6624_RYM0_YINCB_LSB 0x21AC /* Y in Cb LSB */
-#define VS6624_RYM0_YINCR_MSB 0x21B0 /* Y in Cr MSB */
-#define VS6624_RYM0_YINCR_LSB 0x21AF /* Y in Cr LSB */
-/* pipe 1 RGB to YUV matrix manual control */
-#define VS6624_RYM1_MAN_CTRL 0x2200 /* enable manual RGB to YUV matrix */
-#define VS6624_RYM1_W00_MSB 0x2203 /* row 0 column 0 of YUV matrix MSB */
-#define VS6624_RYM1_W00_LSB 0x2204 /* row 0 column 0 of YUV matrix LSB */
-#define VS6624_RYM1_W01_MSB 0x2207 /* row 0 column 1 of YUV matrix MSB */
-#define VS6624_RYM1_W01_LSB 0x2208 /* row 0 column 1 of YUV matrix LSB */
-#define VS6624_RYM1_W02_MSB 0x220C /* row 0 column 2 of YUV matrix MSB */
-#define VS6624_RYM1_W02_LSB 0x220D /* row 0 column 2 of YUV matrix LSB */
-#define VS6624_RYM1_W10_MSB 0x2210 /* row 1 column 0 of YUV matrix MSB */
-#define VS6624_RYM1_W10_LSB 0x220F /* row 1 column 0 of YUV matrix LSB */
-#define VS6624_RYM1_W11_MSB 0x2213 /* row 1 column 1 of YUV matrix MSB */
-#define VS6624_RYM1_W11_LSB 0x2214 /* row 1 column 1 of YUV matrix LSB */
-#define VS6624_RYM1_W12_MSB 0x2217 /* row 1 column 2 of YUV matrix MSB */
-#define VS6624_RYM1_W12_LSB 0x2218 /* row 1 column 2 of YUV matrix LSB */
-#define VS6624_RYM1_W20_MSB 0x221B /* row 2 column 0 of YUV matrix MSB */
-#define VS6624_RYM1_W20_LSB 0x221C /* row 2 column 0 of YUV matrix LSB */
-#define VS6624_RYM1_W21_MSB 0x2220 /* row 2 column 1 of YUV matrix MSB */
-#define VS6624_RYM1_W21_LSB 0x221F /* row 2 column 1 of YUV matrix LSB */
-#define VS6624_RYM1_W22_MSB 0x2223 /* row 2 column 2 of YUV matrix MSB */
-#define VS6624_RYM1_W22_LSB 0x2224 /* row 2 column 2 of YUV matrix LSB */
-#define VS6624_RYM1_YINY_MSB 0x2227 /* Y in Y MSB */
-#define VS6624_RYM1_YINY_LSB 0x2228 /* Y in Y LSB */
-#define VS6624_RYM1_YINCB_MSB 0x222B /* Y in Cb MSB */
-#define VS6624_RYM1_YINCB_LSB 0x222C /* Y in Cb LSB */
-#define VS6624_RYM1_YINCR_MSB 0x2220 /* Y in Cr MSB */
-#define VS6624_RYM1_YINCR_LSB 0x222F /* Y in Cr LSB */
-/* pipe 0 gamma manual control */
-#define VS6624_GAMMA_MAN_CTRL0 0x2280 /* enable manual gamma setup */
-#define VS6624_GAMMA_PEAK_R0 0x2282 /* peaked red channel gamma value */
-#define VS6624_GAMMA_PEAK_G0 0x2284 /* peaked green channel gamma value */
-#define VS6624_GAMMA_PEAK_B0 0x2286 /* peaked blue channel gamma value */
-#define VS6624_GAMMA_UNPEAK_R0 0x2288 /* unpeaked red channel gamma value */
-#define VS6624_GAMMA_UNPEAK_G0 0x228A /* unpeaked green channel gamma value */
-#define VS6624_GAMMA_UNPEAK_B0 0x228C /* unpeaked blue channel gamma value */
-/* pipe 1 gamma manual control */
-#define VS6624_GAMMA_MAN_CTRL1 0x2300 /* enable manual gamma setup */
-#define VS6624_GAMMA_PEAK_R1 0x2302 /* peaked red channel gamma value */
-#define VS6624_GAMMA_PEAK_G1 0x2304 /* peaked green channel gamma value */
-#define VS6624_GAMMA_PEAK_B1 0x2306 /* peaked blue channel gamma value */
-#define VS6624_GAMMA_UNPEAK_R1 0x2308 /* unpeaked red channel gamma value */
-#define VS6624_GAMMA_UNPEAK_G1 0x230A /* unpeaked green channel gamma value */
-#define VS6624_GAMMA_UNPEAK_B1 0x230C /* unpeaked blue channel gamma value */
-/* fade to black */
-#define VS6624_F2B_DISABLE 0x2480 /* disable fade to black */
-#define VS6624_F2B_BLACK_VAL_MSB 0x2483 /* black value MSB */
-#define VS6624_F2B_BLACK_VAL_LSB 0x2484 /* black value LSB */
-#define VS6624_F2B_LOW_THR_MSB 0x2487 /* low threshold for exposure MSB */
-#define VS6624_F2B_LOW_THR_LSB 0x2488 /* low threshold for exposure LSB */
-#define VS6624_F2B_HIGH_THR_MSB 0x248B /* high threshold for exposure MSB */
-#define VS6624_F2B_HIGH_THR_LSB 0x248C /* high threshold for exposure LSB */
-#define VS6624_F2B_MIN_OUT_MSB 0x248F /* minimum damper output MSB */
-#define VS6624_F2B_MIN_OUT_LSB 0x2490 /* minimum damper output LSB */
-/* output formatter control */
-#define VS6624_CODE_CK_EN 0x2580 /* code check enable */
-#define VS6624_BLANK_FMT 0x2582 /* blank format */
-#define VS6624_SYNC_CODE_SETUP 0x2584 /* sync code setup */
-#define VS6624_HSYNC_SETUP 0x2586 /* H sync setup */
-#define VS6624_VSYNC_SETUP 0x2588 /* V sync setup */
-#define VS6624_PCLK_SETUP 0x258A /* PCLK setup */
-#define VS6624_PCLK_EN 0x258C /* PCLK enable */
-#define VS6624_OPF_SP_SETUP 0x258E /* output formatter sp setup */
-#define VS6624_BLANK_DATA_MSB 0x2590 /* blank data MSB */
-#define VS6624_BLANK_DATA_LSB 0x2592 /* blank data LSB */
-#define VS6624_RGB_SETUP 0x2594 /* RGB setup */
-#define VS6624_YUV_SETUP 0x2596 /* YUV setup */
-#define VS6624_VSYNC_RIS_COARSE_H 0x2598 /* V sync rising coarse high */
-#define VS6624_VSYNC_RIS_COARSE_L 0x259A /* V sync rising coarse low */
-#define VS6624_VSYNC_RIS_FINE_H 0x259C /* V sync rising fine high */
-#define VS6624_VSYNC_RIS_FINE_L 0x259E /* V sync rising fine low */
-#define VS6624_VSYNC_FALL_COARSE_H 0x25A0 /* V sync falling coarse high */
-#define VS6624_VSYNC_FALL_COARSE_L 0x25A2 /* V sync falling coarse low */
-#define VS6624_VSYNC_FALL_FINE_H 0x25A4 /* V sync falling fine high */
-#define VS6624_VSYNC_FALL_FINE_L 0x25A6 /* V sync falling fine low */
-#define VS6624_HSYNC_RIS_H 0x25A8 /* H sync rising high */
-#define VS6624_HSYNC_RIS_L 0x25AA /* H sync rising low */
-#define VS6624_HSYNC_FALL_H 0x25AC /* H sync falling high */
-#define VS6624_HSYNC_FALL_L 0x25AE /* H sync falling low */
-#define VS6624_OUT_IF 0x25B0 /* output interface */
-#define VS6624_CCP_EXT_DATA 0x25B2 /* CCP extra data */
-/* NoRA controls */
-#define VS6624_NORA_DISABLE 0x2600 /* NoRA control mode */
-#define VS6624_NORA_USAGE 0x2602 /* usage */
-#define VS6624_NORA_SPLIT_KN 0x2604 /* split kn */
-#define VS6624_NORA_SPLIT_NI 0x2606 /* split ni */
-#define VS6624_NORA_TIGHT_G 0x2608 /* tight green */
-#define VS6624_NORA_DISABLE_NP 0x260A /* disable noro promoting */
-#define VS6624_NORA_LOW_THR_MSB 0x260D /* low threshold for exposure MSB */
-#define VS6624_NORA_LOW_THR_LSB 0x260E /* low threshold for exposure LSB */
-#define VS6624_NORA_HIGH_THR_MSB 0x2611 /* high threshold for exposure MSB */
-#define VS6624_NORA_HIGH_THR_LSB 0x2612 /* high threshold for exposure LSB */
-#define VS6624_NORA_MIN_OUT_MSB 0x2615 /* minimum damper output MSB */
-#define VS6624_NORA_MIN_OUT_LSB 0x2616 /* minimum damper output LSB */
-
-#endif
diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c
index 25020d58eb06..8cee956e38d4 100644
--- a/drivers/media/mc/mc-device.c
+++ b/drivers/media/mc/mc-device.c
@@ -756,13 +756,12 @@ int __must_check __media_device_register(struct media_device *mdev,
}
EXPORT_SYMBOL_GPL(__media_device_register);
-int __must_check media_device_register_entity_notify(struct media_device *mdev,
+void media_device_register_entity_notify(struct media_device *mdev,
struct media_entity_notify *nptr)
{
mutex_lock(&mdev->graph_mutex);
list_add_tail(&nptr->list, &mdev->entity_notify);
mutex_unlock(&mdev->graph_mutex);
- return 0;
}
EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig
index 927190281bd5..2d674dc28cec 100644
--- a/drivers/media/pci/bt8xx/Kconfig
+++ b/drivers/media/pci/bt8xx/Kconfig
@@ -15,7 +15,7 @@ config VIDEO_BT848
select RADIO_ADAPTERS
select RADIO_TEA575X
help
- Support for BT848 based frame grabber/overlay boards. This includes
+ Support for BT848 based frame grabber boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
<file:Documentation/admin-guide/media/bttv.rst> for more information.
diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c
index b3179038b900..0adbf8233e1a 100644
--- a/drivers/media/pci/bt8xx/btcx-risc.c
+++ b/drivers/media/pci/bt8xx/btcx-risc.c
@@ -75,156 +75,3 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
}
return 0;
}
-
-/* ---------------------------------------------------------- */
-/* screen overlay helpers */
-
-int
-btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
- struct v4l2_clip *clips, unsigned int n)
-{
- if (win->left < 0) {
- /* left */
- clips[n].c.left = 0;
- clips[n].c.top = 0;
- clips[n].c.width = -win->left;
- clips[n].c.height = win->height;
- n++;
- }
- if (win->left + win->width > swidth) {
- /* right */
- clips[n].c.left = swidth - win->left;
- clips[n].c.top = 0;
- clips[n].c.width = win->width - clips[n].c.left;
- clips[n].c.height = win->height;
- n++;
- }
- if (win->top < 0) {
- /* top */
- clips[n].c.left = 0;
- clips[n].c.top = 0;
- clips[n].c.width = win->width;
- clips[n].c.height = -win->top;
- n++;
- }
- if (win->top + win->height > sheight) {
- /* bottom */
- clips[n].c.left = 0;
- clips[n].c.top = sheight - win->top;
- clips[n].c.width = win->width;
- clips[n].c.height = win->height - clips[n].c.top;
- n++;
- }
- return n;
-}
-
-int
-btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
-{
- s32 nx,nw,dx;
- unsigned int i;
-
- /* fixup window */
- nx = (win->left + mask) & ~mask;
- nw = (win->width) & ~mask;
- if (nx + nw > win->left + win->width)
- nw -= mask+1;
- dx = nx - win->left;
- win->left = nx;
- win->width = nw;
- dprintk("btcx: window align %dx%d+%d+%d [dx=%d]\n",
- win->width, win->height, win->left, win->top, dx);
-
- /* fixup clips */
- for (i = 0; i < n; i++) {
- nx = (clips[i].c.left-dx) & ~mask;
- nw = (clips[i].c.width) & ~mask;
- if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
- nw += mask+1;
- clips[i].c.left = nx;
- clips[i].c.width = nw;
- dprintk("btcx: clip align %dx%d+%d+%d\n",
- clips[i].c.width, clips[i].c.height,
- clips[i].c.left, clips[i].c.top);
- }
- return 0;
-}
-
-void
-btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
-{
- int i,j,n;
-
- if (nclips < 2)
- return;
- for (i = nclips-2; i >= 0; i--) {
- for (n = 0, j = 0; j <= i; j++) {
- if (clips[j].c.left > clips[j+1].c.left) {
- swap(clips[j], clips[j + 1]);
- n++;
- }
- }
- if (0 == n)
- break;
- }
-}
-
-void
-btcx_calc_skips(int line, int width, int *maxy,
- struct btcx_skiplist *skips, unsigned int *nskips,
- const struct v4l2_clip *clips, unsigned int nclips)
-{
- unsigned int clip,skip;
- int end, maxline;
-
- skip=0;
- maxline = 9999;
- for (clip = 0; clip < nclips; clip++) {
-
- /* sanity checks */
- if (clips[clip].c.left + clips[clip].c.width <= 0)
- continue;
- if (clips[clip].c.left > (signed)width)
- break;
-
- /* vertical range */
- if (line > clips[clip].c.top+clips[clip].c.height-1)
- continue;
- if (line < clips[clip].c.top) {
- if (maxline > clips[clip].c.top-1)
- maxline = clips[clip].c.top-1;
- continue;
- }
- if (maxline > clips[clip].c.top+clips[clip].c.height-1)
- maxline = clips[clip].c.top+clips[clip].c.height-1;
-
- /* horizontal range */
- if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
- /* new one */
- skips[skip].start = clips[clip].c.left;
- if (skips[skip].start < 0)
- skips[skip].start = 0;
- skips[skip].end = clips[clip].c.left + clips[clip].c.width;
- if (skips[skip].end > width)
- skips[skip].end = width;
- skip++;
- } else {
- /* overlaps -- expand last one */
- end = clips[clip].c.left + clips[clip].c.width;
- if (skips[skip-1].end < end)
- skips[skip-1].end = end;
- if (skips[skip-1].end > width)
- skips[skip-1].end = width;
- }
- }
- *nskips = skip;
- *maxy = maxline;
-
- if (btcx_debug) {
- dprintk("btcx: skips line %d-%d:", line, maxline);
- for (skip = 0; skip < *nskips; skip++) {
- pr_cont(" %d-%d", skips[skip].start, skips[skip].end);
- }
- pr_cont("\n");
- }
-}
diff --git a/drivers/media/pci/bt8xx/btcx-risc.h b/drivers/media/pci/bt8xx/btcx-risc.h
index dc774a64cd1f..6ac79a15776f 100644
--- a/drivers/media/pci/bt8xx/btcx-risc.h
+++ b/drivers/media/pci/bt8xx/btcx-risc.h
@@ -16,12 +16,3 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
unsigned int size);
void btcx_riscmem_free(struct pci_dev *pci,
struct btcx_riscmem *risc);
-
-int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
- struct v4l2_clip *clips, unsigned int n);
-int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
- unsigned int n, int mask);
-void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, int *maxy,
- struct btcx_skiplist *skips, unsigned int *nskips,
- const struct v4l2_clip *clips, unsigned int nclips);
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index c2b5ab287dd7..ec78f7fc5e1b 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -81,7 +81,6 @@ static int pvr_boot(struct bttv *btv);
static unsigned int triton1;
static unsigned int vsfx;
static unsigned int latency = UNSET;
-int no_overlay=-1;
static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
@@ -99,7 +98,6 @@ static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
/* insmod options */
module_param(triton1, int, 0444);
module_param(vsfx, int, 0444);
-module_param(no_overlay, int, 0444);
module_param(latency, int, 0444);
module_param(gpiomask, int, 0444);
module_param(audioall, int, 0444);
@@ -127,7 +125,6 @@ MODULE_PARM_DESC(audiodev, "specify audio device:\n"
"\t\t 2 = tda7432\n"
"\t\t 3 = tvaudio");
MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
-MODULE_PARM_DESC(no_overlay, "allow override overlay default (0 disables, 1 enables) [some VIA/SIS chipsets are known to have problem with overlay]");
/* I2C addresses list */
@@ -4869,11 +4866,8 @@ static void gv800s_init(struct bttv *btv)
void __init bttv_check_chipset(void)
{
- int pcipci_fail = 0;
struct pci_dev *dev = NULL;
- if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */
- pcipci_fail = 1;
if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
triton1 = 1;
if (pci_pci_problems & PCIPCI_VSFX)
@@ -4889,15 +4883,6 @@ void __init bttv_check_chipset(void)
pr_info("Host bridge needs ETBF enabled\n");
if (vsfx)
pr_info("Host bridge needs VSFX enabled\n");
- if (pcipci_fail) {
- pr_info("bttv and your chipset may not work together\n");
- if (!no_overlay) {
- pr_info("overlay will be disabled\n");
- no_overlay = 1;
- } else {
- pr_info("overlay forced. Use this option at your own risk.\n");
- }
- }
if (UNSET != latency)
pr_info("pci latency fixup [%d]\n", latency);
while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index d40b537f4e98..734f02b91aa3 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -624,20 +624,14 @@ static const unsigned int FORMATS = ARRAY_SIZE(formats);
VIDIOC_QBUF 1) bttv_release
VIDIOCMCAPTURE 1)
- OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
- VIDIOC_OVERLAY on VIDIOC_OVERLAY off
- 3) bttv_release
-
VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
VIDIOC_QBUF 1) bttv_release
- bttv_read, bttv_poll 1) 4)
+ bttv_read, bttv_poll 1) 3)
1) The resource must be allocated when we enter buffer prepare functions
and remain allocated while buffers are in the DMA queue.
2) This is a single frame read.
- 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
- RESOURCE_OVERLAY is allocated.
- 4) This is a continuous read, implies VIDIOC_STREAMON.
+ 3) This is a continuous read, implies VIDIOC_STREAMON.
Note this driver permits video input and standard changes regardless if
resources are allocated.
@@ -645,8 +639,7 @@ static const unsigned int FORMATS = ARRAY_SIZE(formats);
#define VBI_RESOURCES (RESOURCE_VBI)
#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
- RESOURCE_VIDEO_STREAM | \
- RESOURCE_OVERLAY)
+ RESOURCE_VIDEO_STREAM)
static
int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
@@ -1492,37 +1485,6 @@ format_by_fourcc(int fourcc)
}
/* ----------------------------------------------------------------------- */
-/* misc helpers */
-
-static int
-bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
- struct bttv_buffer *new)
-{
- struct bttv_buffer *old;
- unsigned long flags;
-
- dprintk("switch_overlay: enter [new=%p]\n", new);
- if (new)
- new->vb.state = VIDEOBUF_DONE;
- spin_lock_irqsave(&btv->s_lock,flags);
- old = btv->screen;
- btv->screen = new;
- btv->loop_irq |= 1;
- bttv_set_dma(btv, 0x03);
- spin_unlock_irqrestore(&btv->s_lock,flags);
- if (NULL != old) {
- dprintk("switch_overlay: old=%p state is %d\n",
- old, old->vb.state);
- bttv_dma_free(&fh->cap,btv, old);
- kfree(old);
- }
- if (NULL == new)
- free_btres_lock(btv,fh,RESOURCE_OVERLAY);
- dprintk("switch_overlay: done\n");
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
/* video4linux (1) interface */
static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
@@ -2045,150 +2007,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,
return rc;
}
-/* Returns an error if the given overlay window dimensions are not
- possible with the current cropping parameters. If adjust_size is
- TRUE the function may adjust the window width and/or height
- instead, however it always rounds the horizontal position and
- width as btcx_align() does. If adjust_crop is TRUE the function
- may also adjust the current cropping parameters to get closer
- to the desired window size. */
-static int
-verify_window_lock(struct bttv_fh *fh, struct v4l2_window *win,
- int adjust_size, int adjust_crop)
-{
- enum v4l2_field field;
- unsigned int width_mask;
-
- if (win->w.width < 48)
- win->w.width = 48;
- if (win->w.height < 32)
- win->w.height = 32;
- if (win->clipcount > 2048)
- win->clipcount = 2048;
-
- win->chromakey = 0;
- win->global_alpha = 0;
- field = win->field;
-
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- field = V4L2_FIELD_ANY;
- break;
- }
- if (V4L2_FIELD_ANY == field) {
- __s32 height2;
-
- height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
- field = (win->w.height > height2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- win->field = field;
-
- if (NULL == fh->ovfmt)
- return -EINVAL;
- /* 4-byte alignment. */
- width_mask = ~0;
- switch (fh->ovfmt->depth) {
- case 8:
- case 24:
- width_mask = ~3;
- break;
- case 16:
- width_mask = ~1;
- break;
- case 32:
- break;
- default:
- BUG();
- }
-
- win->w.width -= win->w.left & ~width_mask;
- win->w.left = (win->w.left - width_mask - 1) & width_mask;
-
- return limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
- field, width_mask,
- /* width_bias: round down */ 0,
- adjust_size, adjust_crop);
-}
-
-static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
- struct v4l2_window *win, int fixup)
-{
- struct v4l2_clip *clips = NULL;
- int n,size,retval = 0;
-
- if (NULL == fh->ovfmt)
- return -EINVAL;
- if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
- return -EINVAL;
- retval = verify_window_lock(fh, win,
- /* adjust_size */ fixup,
- /* adjust_crop */ fixup);
- if (0 != retval)
- return retval;
-
- /* copy clips -- luckily v4l1 + v4l2 are binary
- compatible here ...*/
- n = win->clipcount;
- size = sizeof(*clips)*(n+4);
- clips = kmalloc(size,GFP_KERNEL);
- if (NULL == clips)
- return -ENOMEM;
- if (n > 0)
- memcpy(clips, win->clips, sizeof(struct v4l2_clip) * n);
-
- /* clip against screen */
- if (NULL != btv->fbuf.base)
- n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
- &win->w, clips, n);
- btcx_sort_clips(clips,n);
-
- /* 4-byte alignments */
- switch (fh->ovfmt->depth) {
- case 8:
- case 24:
- btcx_align(&win->w, clips, n, 3);
- break;
- case 16:
- btcx_align(&win->w, clips, n, 1);
- break;
- case 32:
- /* no alignment fixups needed */
- break;
- default:
- BUG();
- }
-
- kfree(fh->ov.clips);
- fh->ov.clips = clips;
- fh->ov.nclips = n;
-
- fh->ov.w = win->w;
- fh->ov.field = win->field;
- fh->ov.setup_ok = 1;
-
- btv->init.ov.w.width = win->w.width;
- btv->init.ov.w.height = win->w.height;
- btv->init.ov.field = win->field;
-
- /* update overlay if needed */
- retval = 0;
- if (check_btres(fh, RESOURCE_OVERLAY)) {
- struct bttv_buffer *new;
-
- new = videobuf_sg_alloc(sizeof(*new));
- new->crop = btv->crop[!!fh->do_crop].rect;
- bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
- retval = bttv_switch_overlay(btv,fh,new);
- }
- return retval;
-}
-
/* ----------------------------------------------------------------------- */
static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
@@ -2270,17 +2088,6 @@ static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct bttv_fh *fh = priv;
-
- f->fmt.win.w = fh->ov.w;
- f->fmt.win.field = fh->ov.field;
-
- return 0;
-}
-
static void bttv_get_width_mask_vid_cap(const struct bttv_format *fmt,
unsigned int *width_mask,
unsigned int *width_bias)
@@ -2352,17 +2159,6 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct bttv_fh *fh = priv;
-
- verify_window_lock(fh, &f->fmt.win,
- /* adjust_size */ 1,
- /* adjust_crop */ 0);
- return 0;
-}
-
static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -2410,20 +2206,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct bttv_fh *fh = priv;
- struct bttv *btv = fh->btv;
-
- if (no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
-
- return setup_window_lock(fh, btv, &f->fmt.win, 1);
-}
-
static int bttv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -2437,8 +2219,6 @@ static int bttv_querycap(struct file *file, void *priv,
strscpy(cap->card, btv->video_dev.name, sizeof(cap->card));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- if (no_overlay <= 0)
- cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
if (video_is_registered(&btv->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
if (video_is_registered(&btv->radio_dev)) {
@@ -2458,7 +2238,8 @@ static int bttv_querycap(struct file *file, void *priv,
return 0;
}
-static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
+static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
int index = -1, i;
@@ -2473,162 +2254,9 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
f->pixelformat = formats[i].fourcc;
- return i;
-}
-
-static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- int rc = bttv_enum_fmt_cap_ovr(f);
-
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- int rc;
-
- if (no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
-
- rc = bttv_enum_fmt_cap_ovr(f);
-
- if (rc < 0)
- return rc;
-
- if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
- return -EINVAL;
-
return 0;
}
-static int bttv_g_fbuf(struct file *file, void *f,
- struct v4l2_framebuffer *fb)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
-
- *fb = btv->fbuf;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- fb->flags = V4L2_FBUF_FLAG_PRIMARY;
- if (fh->ovfmt)
- fb->fmt.pixelformat = fh->ovfmt->fourcc;
- return 0;
-}
-
-static int bttv_overlay(struct file *file, void *f, unsigned int on)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
- struct bttv_buffer *new;
- int retval = 0;
-
- if (on) {
- /* verify args */
- if (unlikely(!btv->fbuf.base)) {
- return -EINVAL;
- }
- if (unlikely(!fh->ov.setup_ok)) {
- dprintk("%d: overlay: !setup_ok\n", btv->c.nr);
- retval = -EINVAL;
- }
- if (retval)
- return retval;
- }
-
- if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
- return -EBUSY;
-
- if (on) {
- fh->ov.tvnorm = btv->tvnorm;
- new = videobuf_sg_alloc(sizeof(*new));
- new->crop = btv->crop[!!fh->do_crop].rect;
- bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
- } else {
- new = NULL;
- }
-
- /* switch over */
- retval = bttv_switch_overlay(btv, fh, new);
- return retval;
-}
-
-static int bttv_s_fbuf(struct file *file, void *f,
- const struct v4l2_framebuffer *fb)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
- const struct bttv_format *fmt;
- int retval;
-
- if (!capable(CAP_SYS_ADMIN) &&
- !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = format_by_fourcc(fb->fmt.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
- if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
- return -EINVAL;
-
- retval = -EINVAL;
- if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
- __s32 width = fb->fmt.width;
- __s32 height = fb->fmt.height;
-
- retval = limit_scaled_size_lock(fh, &width, &height,
- V4L2_FIELD_INTERLACED,
- /* width_mask */ ~3,
- /* width_bias */ 2,
- /* adjust_size */ 0,
- /* adjust_crop */ 0);
- if (0 != retval)
- return retval;
- }
-
- /* ok, accept it */
- btv->fbuf.base = fb->base;
- btv->fbuf.fmt.width = fb->fmt.width;
- btv->fbuf.fmt.height = fb->fmt.height;
- if (0 != fb->fmt.bytesperline)
- btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
- else
- btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
-
- retval = 0;
- fh->ovfmt = fmt;
- btv->init.ovfmt = fmt;
- if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
- fh->ov.w.left = 0;
- fh->ov.w.top = 0;
- fh->ov.w.width = fb->fmt.width;
- fh->ov.w.height = fb->fmt.height;
- btv->init.ov.w.width = fb->fmt.width;
- btv->init.ov.w.height = fb->fmt.height;
-
- kfree(fh->ov.clips);
- fh->ov.clips = NULL;
- fh->ov.nclips = 0;
-
- if (check_btres(fh, RESOURCE_OVERLAY)) {
- struct bttv_buffer *new;
-
- new = videobuf_sg_alloc(sizeof(*new));
- new->crop = btv->crop[!!fh->do_crop].rect;
- bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
- retval = bttv_switch_overlay(btv, fh, new);
- }
- }
- return retval;
-}
-
static int bttv_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -2748,8 +2376,7 @@ static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *s
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
switch (sel->target) {
@@ -2786,8 +2413,7 @@ static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *s
__s32 b_right;
__s32 b_bottom;
- if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (sel->target != V4L2_SEL_TGT_CROP)
@@ -2977,7 +2603,6 @@ static int bttv_open(struct file *file)
v4l2_fh_init(&fh->fh, vdev);
fh->type = type;
- fh->ov.setup_ok = 0;
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
&btv->c.pci->dev, &btv->s_lock,
@@ -3021,10 +2646,6 @@ static int bttv_release(struct file *file)
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- /* turn off overlay */
- if (check_btres(fh, RESOURCE_OVERLAY))
- bttv_switch_overlay(btv,fh,NULL);
-
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
@@ -3090,10 +2711,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay,
- .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay,
- .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay,
- .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay,
.vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
@@ -3113,9 +2730,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_s_tuner = bttv_s_tuner,
.vidioc_g_selection = bttv_g_selection,
.vidioc_s_selection = bttv_s_selection,
- .vidioc_g_fbuf = bttv_g_fbuf,
- .vidioc_s_fbuf = bttv_s_fbuf,
- .vidioc_overlay = bttv_overlay,
.vidioc_g_parm = bttv_g_parm,
.vidioc_g_frequency = bttv_g_frequency,
.vidioc_s_frequency = bttv_s_frequency,
@@ -3385,9 +2999,6 @@ static void bttv_print_riscaddr(struct bttv *btv)
? (unsigned long long)btv->curr.top->top.dma : 0,
btv->curr.bottom
? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
- pr_info(" scr : o=%08llx e=%08llx\n",
- btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
- btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
bttv_risc_disasm(btv, &btv->main);
}
@@ -3508,28 +3119,9 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
}
}
- /* screen overlay ? */
- if (NULL != btv->screen) {
- if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
- if (NULL == set->top && NULL == set->bottom) {
- set->top = btv->screen;
- set->bottom = btv->screen;
- }
- } else {
- if (V4L2_FIELD_TOP == btv->screen->vb.field &&
- NULL == set->top) {
- set->top = btv->screen;
- }
- if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
- NULL == set->bottom) {
- set->bottom = btv->screen;
- }
- }
- }
-
- dprintk("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
+ dprintk("%d: next set: top=%p bottom=%p [irq=%d,%d]\n",
btv->c.nr, set->top, set->bottom,
- btv->screen, set->frame_irq, set->top_irq);
+ set->frame_irq, set->top_irq);
return 0;
}
@@ -3883,17 +3475,12 @@ static void bttv_unregister_video(struct bttv *btv)
/* register video4linux devices */
static int bttv_register_video(struct bttv *btv)
{
- if (no_overlay > 0)
- pr_notice("Overlay support disabled\n");
-
/* video */
vdev_init(btv, &btv->video_dev, &bttv_video_template, "video");
btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
if (btv->tuner_type != TUNER_ABSENT)
btv->video_dev.device_caps |= V4L2_CAP_TUNER;
- if (no_overlay <= 0)
- btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY;
if (video_register_device(&btv->video_dev, VFL_TYPE_VIDEO,
video_nr[btv->c.nr]) < 0)
@@ -4084,14 +3671,9 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
/* fill struct bttv with some useful defaults */
btv->init.btv = btv;
- btv->init.ov.w.width = 320;
- btv->init.ov.w.height = 240;
btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
btv->init.width = 320;
btv->init.height = 240;
- btv->init.ov.w.width = 320;
- btv->init.ov.w.height = 240;
- btv->init.ov.field = V4L2_FIELD_INTERLACED;
btv->input = 0;
v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c
index 32fa4a7fe76f..4fa4b9da9634 100644
--- a/drivers/media/pci/bt8xx/bttv-risc.c
+++ b/drivers/media/pci/bt8xx/bttv-risc.c
@@ -231,95 +231,6 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
return 0;
}
-static int
-bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
- const struct bttv_format *fmt, struct bttv_overlay *ov,
- int skip_even, int skip_odd)
-{
- int dwords, rc, line, maxy, start, end;
- unsigned skip, nskips;
- struct btcx_skiplist *skips;
- __le32 *rp;
- u32 ri,ra;
- u32 addr;
-
- /* skip list for window clipping */
- skips = kmalloc_array(ov->nclips, sizeof(*skips),GFP_KERNEL);
- if (NULL == skips)
- return -ENOMEM;
-
- /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
- + sync + jump (all 2 dwords) */
- dwords = (3 * ov->nclips + 2) *
- ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
- dwords += 4;
- if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
- kfree(skips);
- return rc;
- }
-
- /* sync instruction */
- rp = risc->cpu;
- *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
- *(rp++) = cpu_to_le32(0);
-
- addr = (unsigned long)btv->fbuf.base;
- addr += btv->fbuf.fmt.bytesperline * ov->w.top;
- addr += (fmt->depth >> 3) * ov->w.left;
-
- /* scan lines */
- for (maxy = -1, line = 0; line < ov->w.height;
- line++, addr += btv->fbuf.fmt.bytesperline) {
- if ((btv->opt_vcr_hack) &&
- (line >= (ov->w.height - VCR_HACK_LINES)))
- continue;
- if ((line%2) == 0 && skip_even)
- continue;
- if ((line%2) == 1 && skip_odd)
- continue;
-
- /* calculate clipping */
- if (line > maxy)
- btcx_calc_skips(line, ov->w.width, &maxy,
- skips, &nskips, ov->clips, ov->nclips);
-
- /* write out risc code */
- for (start = 0, skip = 0; start < ov->w.width; start = end) {
- if (skip >= nskips) {
- ri = BT848_RISC_WRITE;
- end = ov->w.width;
- } else if (start < skips[skip].start) {
- ri = BT848_RISC_WRITE;
- end = skips[skip].start;
- } else {
- ri = BT848_RISC_SKIP;
- end = skips[skip].end;
- skip++;
- }
- if (BT848_RISC_WRITE == ri)
- ra = addr + (fmt->depth>>3)*start;
- else
- ra = 0;
-
- if (0 == start)
- ri |= BT848_RISC_SOL;
- if (ov->w.width == end)
- ri |= BT848_RISC_EOL;
- ri |= (fmt->depth>>3) * (end-start);
-
- *(rp++)=cpu_to_le32(ri);
- if (0 != ra)
- *(rp++)=cpu_to_le32(ra);
- }
- }
-
- /* save pointer to jmp instruction address */
- risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
- kfree(skips);
- return 0;
-}
-
/* ---------------------------------------------------------- */
static void
@@ -848,45 +759,3 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->btswap = buf->fmt->btswap;
return 0;
}
-
-/* ---------------------------------------------------------- */
-
-/* calculate geometry, build risc code */
-int
-bttv_overlay_risc(struct bttv *btv,
- struct bttv_overlay *ov,
- const struct bttv_format *fmt,
- struct bttv_buffer *buf)
-{
- /* check interleave, bottom+top fields */
- dprintk("%d: overlay fields: %s format: 0x%08x size: %dx%d\n",
- btv->c.nr, v4l2_field_names[buf->vb.field],
- fmt->fourcc, ov->w.width, ov->w.height);
-
- /* calculate geometry */
- bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
- V4L2_FIELD_HAS_BOTH(ov->field),
- &bttv_tvnorms[ov->tvnorm],&buf->crop);
-
- /* build risc code */
- switch (ov->field) {
- case V4L2_FIELD_TOP:
- bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
- break;
- case V4L2_FIELD_BOTTOM:
- bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
- break;
- case V4L2_FIELD_INTERLACED:
- bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
- bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
- break;
- default:
- BUG();
- }
-
- /* copy format info */
- buf->btformat = fmt->btformat;
- buf->btswap = fmt->btswap;
- buf->vb.field = ov->field;
- return 0;
-}
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 4abf43657846..717f002a41df 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -50,7 +50,6 @@
#define RISC_SLOT_E_FIELD 12
#define RISC_SLOT_LOOP 14
-#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO_STREAM 2
#define RESOURCE_VBI 4
#define RESOURCE_VIDEO_READ 8
@@ -165,15 +164,6 @@ struct bttv_buffer_set {
unsigned int frame_irq;
};
-struct bttv_overlay {
- unsigned int tvnorm;
- struct v4l2_rect w;
- enum v4l2_field field;
- struct v4l2_clip *clips;
- int nclips;
- int setup_ok;
-};
-
struct bttv_vbi_fmt {
struct v4l2_vbi_format fmt;
@@ -216,10 +206,6 @@ struct bttv_fh {
int width;
int height;
- /* video overlay */
- const struct bttv_format *ovfmt;
- struct bttv_overlay ov;
-
/* Application called VIDIOC_S_SELECTION. */
int do_crop;
@@ -256,12 +242,6 @@ int bttv_buffer_activate_vbi(struct bttv *btv,
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
struct bttv_buffer *buf);
-/* overlay handling */
-int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
- const struct bttv_format *fmt,
- struct bttv_buffer *buf);
-
-
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
@@ -279,11 +259,6 @@ int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
/* ---------------------------------------------------------- */
-/* bttv-cards.c */
-
-extern int no_overlay;
-
-/* ---------------------------------------------------------- */
/* bttv-input.c */
extern void init_bttv_i2c_ir(struct bttv *btv);
@@ -454,7 +429,6 @@ struct bttv {
- must acquire s_lock before changing these
- only the irq handler is supported to touch top + bottom + vcurr */
struct btcx_riscmem main;
- struct bttv_buffer *screen; /* overlay */
struct list_head capture; /* video capture queue */
struct list_head vcapture; /* vbi capture queue */
struct bttv_buffer_set curr; /* active buffers */
@@ -479,7 +453,7 @@ struct bttv {
/* used to make dvb-bt8xx autoloadable */
struct work_struct request_module_wk;
- /* Default (0) and current (1) video capturing and overlay
+ /* Default (0) and current (1) video capturing
cropping parameters in bttv_tvnorm.cropcap units. Protected
by bttv.lock. */
struct bttv_crop crop[2];
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index 0ff37496c9ab..4bfbcca14f60 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -708,7 +708,6 @@ static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh,
{
struct cobalt_stream *s = video_drvdata(file);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_subdev_format sd_fmt;
pix->width = s->width;
pix->height = s->height;
@@ -718,8 +717,11 @@ static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh,
if (s->input == 1) {
pix->colorspace = V4L2_COLORSPACE_SRGB;
} else {
- sd_fmt.pad = s->pad_source;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ struct v4l2_subdev_format sd_fmt = {
+ .pad = s->pad_source,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
v4l2_fill_pix_format(pix, &sd_fmt.format);
}
@@ -735,7 +737,6 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh,
{
struct cobalt_stream *s = video_drvdata(file);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_subdev_format sd_fmt;
/* Check for min (QCIF) and max (Full HD) size */
if ((pix->width < 176) || (pix->height < 144)) {
@@ -760,8 +761,11 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh,
pix->height = 1080;
pix->colorspace = V4L2_COLORSPACE_SRGB;
} else {
- sd_fmt.pad = s->pad_source;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ struct v4l2_subdev_format sd_fmt = {
+ .pad = s->pad_source,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt);
v4l2_fill_pix_format(pix, &sd_fmt.format);
}
@@ -906,7 +910,9 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh,
{
struct cobalt_stream *s = video_drvdata(file);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_subdev_format sd_fmt = { 0 };
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
u32 code;
if (cobalt_try_fmt_vid_out(file, priv_fh, f))
@@ -937,7 +943,6 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh,
s->xfer_func = pix->xfer_func;
s->ycbcr_enc = pix->ycbcr_enc;
s->quantization = pix->quantization;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
v4l2_fill_mbus_format(&sd_fmt.format, pix, code);
v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
return 0;
diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig
index a4e32fdcfd3d..5c959bb5e233 100644
--- a/drivers/media/pci/cx18/Kconfig
+++ b/drivers/media/pci/cx18/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_DEV && DVB_CORE && PCI && I2C
select I2C_ALGOBIT
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 84260972c343..743fcc961374 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -771,11 +771,11 @@ static void cx18_init_struct2(struct cx18 *cx)
{
int i;
- for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS - 1; i++)
+ for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
if (cx->card->video_inputs[i].video_type == 0)
break;
cx->nof_inputs = i;
- for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS - 1; i++)
+ for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
if (cx->card->audio_inputs[i].audio_type == 0)
break;
cx->nof_audio_inputs = i;
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
index ef545b96121d..887d2aa36447 100644
--- a/drivers/media/pci/cx18/cx18-driver.h
+++ b/drivers/media/pci/cx18/cx18-driver.h
@@ -48,9 +48,8 @@
#include <media/dvb_net.h>
#include <media/dvbdev.h>
-/* Videobuf / YUV support */
-#include <media/videobuf-core.h>
-#include <media/videobuf-vmalloc.h>
+/* vb2 YUV support */
+#include <media/videobuf2-vmalloc.h>
#ifndef CONFIG_PCI
# error "This driver requires kernel PCI support."
@@ -284,6 +283,14 @@ struct cx18_options {
#define list_entry_is_past_end(pos, head, member) \
(&pos->member == (head))
+struct cx18_vb2_buffer {
+ /* Common video buffer sub-system struct */
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+ v4l2_std_id tvnorm; /* selected tv norm */
+ u32 bytes_used;
+};
+
struct cx18_buffer {
struct list_head list;
dma_addr_t dma_handle;
@@ -399,19 +406,12 @@ struct cx18_stream {
struct list_head vb_capture; /* video capture queue */
spinlock_t vb_lock;
struct timer_list vb_timeout;
+ u32 sequence;
- struct videobuf_queue vbuf_q;
- spinlock_t vbuf_q_lock; /* Protect vbuf_q */
+ struct vb2_queue vidq;
enum v4l2_buf_type vb_type;
};
-struct cx18_videobuf_buffer {
- /* Common video buffer sub-system struct */
- struct videobuf_buffer vb;
- v4l2_std_id tvnorm; /* selected tv norm */
- u32 bytes_used;
-};
-
struct cx18_open_id {
struct v4l2_fh fh;
u32 open_id;
diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c
index 4cf5b9ca92e7..7e742733391b 100644
--- a/drivers/media/pci/cx18/cx18-fileops.c
+++ b/drivers/media/pci/cx18/cx18-fileops.c
@@ -584,12 +584,6 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
if (rc)
return rc;
- if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
- return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
}
@@ -618,17 +612,6 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_FILE("Encoder poll started capture\n");
}
- if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
- __poll_t videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
-
- if (v4l2_event_pending(&id->fh))
- res |= EPOLLPRI;
- if (eof && videobuf_poll == EPOLLERR)
- return res | EPOLLHUP;
- return res | videobuf_poll;
- }
-
/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n");
if (v4l2_event_pending(&id->fh))
@@ -643,62 +626,20 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
return res;
}
-int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
- int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
-
- if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
-
- /* Start a capture if there is none */
- if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
- int rc;
-
- mutex_lock(&cx->serialize_lock);
- rc = cx18_start_capture(id);
- mutex_unlock(&cx->serialize_lock);
- if (rc) {
- CX18_DEBUG_INFO(
- "Could not start capture for %s (%d)\n",
- s->name, rc);
- return -EINVAL;
- }
- CX18_DEBUG_FILE("Encoder mmap started capture\n");
- }
-
- return videobuf_mmap_mapper(&s->vbuf_q, vma);
- }
-
- return -EINVAL;
-}
-
void cx18_vb_timeout(struct timer_list *t)
{
struct cx18_stream *s = from_timer(s, t, vb_timeout);
- struct cx18_videobuf_buffer *buf;
- unsigned long flags;
- /* Return all of the buffers in error state, so the vbi/vid inode
+ /*
+ * Return all of the buffers in error state, so the vbi/vid inode
* can return from blocking.
*/
- spin_lock_irqsave(&s->vb_lock, flags);
- while (!list_empty(&s->vb_capture)) {
- buf = list_entry(s->vb_capture.next,
- struct cx18_videobuf_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- }
- spin_unlock_irqrestore(&s->vb_lock, flags);
+ cx18_clear_queue(s, VB2_BUF_STATE_ERROR);
}
-void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
+void cx18_stop_capture(struct cx18_stream *s, int gop_end)
{
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
+ struct cx18 *cx = s->cx;
struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
@@ -709,7 +650,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
/* Stop capturing */
if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
CX18_DEBUG_INFO("close stopping capture\n");
- if (id->type == CX18_ENC_STREAM_TYPE_MPG) {
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
/* Stop internal use associated VBI and IDX streams */
if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
@@ -721,7 +662,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
cx18_stop_v4l2_encode_stream(s_idx, 0);
}
}
- if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
/* Also used internally, don't stop capturing */
s->id = -1;
@@ -741,13 +682,14 @@ int cx18_v4l2_close(struct file *filp)
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
+ struct video_device *vdev = &s->video_dev;
CX18_DEBUG_IOCTL("close() of %s\n", s->name);
mutex_lock(&cx->serialize_lock);
/* Stop radio */
if (id->type == CX18_ENC_STREAM_TYPE_RAD &&
- v4l2_fh_is_singular_file(filp)) {
+ v4l2_fh_is_singular_file(filp)) {
/* Closing radio device, return to TV mode */
cx18_mute(cx);
/* Mark that the radio is no longer in use */
@@ -766,12 +708,17 @@ int cx18_v4l2_close(struct file *filp)
cx18_unmute(cx);
}
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV &&
+ filp->private_data == vdev->queue->owner) {
+ vb2_queue_release(vdev->queue);
+ vdev->queue->owner = NULL;
+ }
v4l2_fh_del(fh);
v4l2_fh_exit(fh);
/* 'Unclaim' this stream */
- if (s->id == id->open_id)
- cx18_stop_capture(id, 0);
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV && s->id == id->open_id)
+ cx18_stop_capture(s, 0);
kfree(id);
mutex_unlock(&cx->serialize_lock);
return 0;
diff --git a/drivers/media/pci/cx18/cx18-fileops.h b/drivers/media/pci/cx18/cx18-fileops.h
index 1985d6422347..943057b83d94 100644
--- a/drivers/media/pci/cx18/cx18-fileops.h
+++ b/drivers/media/pci/cx18/cx18-fileops.h
@@ -16,10 +16,11 @@ ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
int cx18_v4l2_close(struct file *filp);
__poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
int cx18_start_capture(struct cx18_open_id *id);
-void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
+void cx18_stop_capture(struct cx18_stream *s, int gop_end);
void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx);
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
+void cx18_clear_queue(struct cx18_stream *s, enum vb2_buffer_state state);
void cx18_vb_timeout(struct timer_list *t);
/* Shared with cx18-alsa module */
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index c8ba7841c720..1817b9ed042c 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -27,6 +27,133 @@
#include <media/tveeprom.h>
#include <media/v4l2-event.h>
+static const struct v4l2_fmtdesc cx18_formats_yuv[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .pixelformat = V4L2_PIX_FMT_NV12_16L16,
+ },
+ {
+ .index = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+static const struct v4l2_fmtdesc cx18_formats_mpeg[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .pixelformat = V4L2_PIX_FMT_MPEG,
+ },
+};
+
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh2id(fh);
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ pixfmt->width = cx->cxhdl.width;
+ pixfmt->height = cx->cxhdl.height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = s->pixelformat;
+ pixfmt->sizeimage = s->vb_bytes_per_frame;
+ pixfmt->bytesperline = s->vb_bytes_per_line;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
+ }
+ return 0;
+}
+
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh2id(fh);
+ struct cx18 *cx = id->cx;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ int w = pixfmt->width;
+ int h = pixfmt->height;
+
+ w = min(w, 720);
+ w = max(w, 720 / 16);
+
+ h = min(h, cx->is_50hz ? 576 : 480);
+ h = max(h, (cx->is_50hz ? 576 : 480) / 8);
+
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_NV12_16L16 &&
+ pixfmt->pixelformat != V4L2_PIX_FMT_UYVY)
+ pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
+ /* YUV height must be a multiple of 32 */
+ h = round_up(h, 32);
+ /*
+ * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
+ */
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12_16L16) {
+ pixfmt->sizeimage = h * 720 * 3 / 2;
+ pixfmt->bytesperline = 720; /* First plane */
+ } else {
+ pixfmt->sizeimage = h * 720 * 2;
+ pixfmt->bytesperline = 1440; /* Packed */
+ }
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
+ }
+
+ pixfmt->width = w;
+ pixfmt->height = h;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ return 0;
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh2id(fh);
+ struct cx18 *cx = id->cx;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct cx18_stream *s = &cx->streams[id->type];
+ int ret;
+ int w, h;
+
+ ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+ if (ret)
+ return ret;
+ w = fmt->fmt.pix.width;
+ h = fmt->fmt.pix.height;
+
+ if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+ s->pixelformat == fmt->fmt.pix.pixelformat)
+ return 0;
+
+ if (atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ s->pixelformat = fmt->fmt.pix.pixelformat;
+ s->vb_bytes_per_frame = fmt->fmt.pix.sizeimage;
+ s->vb_bytes_per_line = fmt->fmt.pix.bytesperline;
+
+ format.format.width = cx->cxhdl.width = w;
+ format.format.height = cx->cxhdl.height = h;
+ format.format.code = MEDIA_BUS_FMT_FIXED;
+ v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
+ return cx18_g_fmt_vid_cap(file, fh, fmt);
+}
+
u16 cx18_service2vbi(int type)
{
switch (type) {
@@ -131,30 +258,6 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
return set;
}
-static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct cx18_open_id *id = fh2id(fh);
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
-
- pixfmt->width = cx->cxhdl.width;
- pixfmt->height = cx->cxhdl.height;
- pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- pixfmt->field = V4L2_FIELD_INTERLACED;
- if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
- pixfmt->pixelformat = s->pixelformat;
- pixfmt->sizeimage = s->vb_bytes_per_frame;
- pixfmt->bytesperline = s->vb_bytes_per_line;
- } else {
- pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
- pixfmt->sizeimage = 128 * 1024;
- pixfmt->bytesperline = 0;
- }
- return 0;
-}
-
static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
@@ -199,30 +302,6 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
return 0;
}
-static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct cx18_open_id *id = fh2id(fh);
- struct cx18 *cx = id->cx;
- int w = fmt->fmt.pix.width;
- int h = fmt->fmt.pix.height;
- int min_h = 2;
-
- w = min(w, 720);
- w = max(w, 2);
- if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
- /* YUV height must be a multiple of 32 */
- h &= ~0x1f;
- min_h = 32;
- }
- h = min(h, cx->is_50hz ? 576 : 480);
- h = max(h, min_h);
-
- fmt->fmt.pix.width = w;
- fmt->fmt.pix.height = h;
- return 0;
-}
-
static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
@@ -248,49 +327,6 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
return 0;
}
-static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct cx18_open_id *id = fh2id(fh);
- struct cx18 *cx = id->cx;
- struct v4l2_subdev_format format = {
- .which = V4L2_SUBDEV_FORMAT_ACTIVE,
- };
- struct cx18_stream *s = &cx->streams[id->type];
- int ret;
- int w, h;
-
- ret = cx18_try_fmt_vid_cap(file, fh, fmt);
- if (ret)
- return ret;
- w = fmt->fmt.pix.width;
- h = fmt->fmt.pix.height;
-
- if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
- s->pixelformat == fmt->fmt.pix.pixelformat)
- return 0;
-
- if (atomic_read(&cx->ana_capturing) > 0)
- return -EBUSY;
-
- s->pixelformat = fmt->fmt.pix.pixelformat;
- /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
- UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
- if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) {
- s->vb_bytes_per_frame = h * 720 * 3 / 2;
- s->vb_bytes_per_line = 720; /* First plane */
- } else {
- s->vb_bytes_per_frame = h * 720 * 2;
- s->vb_bytes_per_line = 1440; /* Packed */
- }
-
- format.format.width = cx->cxhdl.width = w;
- format.format.height = cx->cxhdl.height = h;
- format.format.code = MEDIA_BUS_FMT_FIXED;
- v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
- return cx18_g_fmt_vid_cap(file, fh, fmt);
-}
-
static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
@@ -463,31 +499,17 @@ static int cx18_g_selection(struct file *file, void *fh,
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
- static const struct v4l2_fmtdesc formats[] = {
- {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "HM12 (YUV 4:1:1)",
- .pixelformat = V4L2_PIX_FMT_NV12_16L16,
- },
- {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .description = "MPEG",
- .pixelformat = V4L2_PIX_FMT_MPEG,
- },
- {
- .index = 2,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "UYVY 4:2:2",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- },
- };
+ struct cx18_open_id *id = fh2id(fh);
- if (fmt->index > ARRAY_SIZE(formats) - 1)
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv))
+ return -EINVAL;
+ *fmt = cx18_formats_yuv[fmt->index];
+ return 0;
+ }
+ if (fmt->index)
return -EINVAL;
- *fmt = formats[fmt->index];
+ *fmt = cx18_formats_mpeg[0];
return 0;
}
@@ -596,6 +618,19 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id std)
cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
cx->cxhdl.width = 720;
cx->cxhdl.height = cx->is_50hz ? 576 : 480;
+ /*
+ * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
+ */
+ if (cx->streams[CX18_ENC_STREAM_TYPE_YUV].pixelformat == V4L2_PIX_FMT_NV12_16L16) {
+ cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
+ cx->cxhdl.height * 720 * 3 / 2;
+ cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 720;
+ } else {
+ cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame =
+ cx->cxhdl.height * 720 * 2;
+ cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 1440;
+ }
cx->vbi.count = cx->is_50hz ? 18 : 12;
cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
@@ -803,117 +838,6 @@ static int cx18_g_enc_index(struct file *file, void *fh,
return 0;
}
-static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
-{
- struct videobuf_queue *q = NULL;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- switch (s->vb_type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- q = &s->vbuf_q;
- break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- break;
- default:
- break;
- }
- return q;
-}
-
-static int cx18_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- /* Start the hardware only if we're the video device */
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- if (id->type != CX18_ENC_STREAM_TYPE_YUV)
- return -EINVAL;
-
- /* Establish a buffer timeout */
- mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
-
- return videobuf_streamon(cx18_vb_queue(id));
-}
-
-static int cx18_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- /* Start the hardware only if we're the video device */
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- if (id->type != CX18_ENC_STREAM_TYPE_YUV)
- return -EINVAL;
-
- return videobuf_streamoff(cx18_vb_queue(id));
-}
-
-static int cx18_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- return videobuf_reqbufs(cx18_vb_queue(id), rb);
-}
-
-static int cx18_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- return videobuf_querybuf(cx18_vb_queue(id), b);
-}
-
-static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- return videobuf_qbuf(cx18_vb_queue(id), b);
-}
-
-static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx18_open_id *id = file->private_data;
- struct cx18 *cx = id->cx;
- struct cx18_stream *s = &cx->streams[id->type];
-
- if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
-}
-
static int cx18_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
@@ -930,7 +854,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
case V4L2_ENC_CMD_STOP:
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
- cx18_stop_capture(id,
+ cx18_stop_capture(&cx->streams[id->type],
enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
break;
@@ -1106,12 +1030,15 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_s_register = cx18_s_register,
#endif
.vidioc_default = cx18_default,
- .vidioc_streamon = cx18_streamon,
- .vidioc_streamoff = cx18_streamoff,
- .vidioc_reqbufs = cx18_reqbufs,
- .vidioc_querybuf = cx18_querybuf,
- .vidioc_qbuf = cx18_qbuf,
- .vidioc_dqbuf = cx18_dqbuf,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c
index 162480ec68ca..3b283f3c6726 100644
--- a/drivers/media/pci/cx18/cx18-mailbox.c
+++ b/drivers/media/pci/cx18/cx18-mailbox.c
@@ -145,36 +145,37 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
}
}
-static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
- struct cx18_mdl *mdl)
+static void cx18_mdl_send_to_vb2(struct cx18_stream *s, struct cx18_mdl *mdl)
{
- struct cx18_videobuf_buffer *vb_buf;
+ struct cx18_vb2_buffer *vb_buf;
struct cx18_buffer *buf;
u8 *p;
u32 offset = 0;
int dispatch = 0;
+ unsigned long bsize;
if (mdl->bytesused == 0)
return;
- /* Acquire a videobuf buffer, clone to and and release it */
+ /* Acquire a vb2 buffer, clone to and release it */
spin_lock(&s->vb_lock);
if (list_empty(&s->vb_capture))
goto out;
- vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer,
- vb.queue);
+ vb_buf = list_first_entry(&s->vb_capture, struct cx18_vb2_buffer,
+ list);
- p = videobuf_to_vmalloc(&vb_buf->vb);
+ p = vb2_plane_vaddr(&vb_buf->vb.vb2_buf, 0);
if (!p)
goto out;
+ bsize = vb2_get_plane_payload(&vb_buf->vb.vb2_buf, 0);
offset = vb_buf->bytes_used;
list_for_each_entry(buf, &mdl->buf_list, list) {
if (buf->bytesused == 0)
break;
- if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
+ if ((offset + buf->bytesused) <= bsize) {
memcpy(p + offset, buf->buf, buf->bytesused);
offset += buf->bytesused;
vb_buf->bytes_used += buf->bytesused;
@@ -188,10 +189,10 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
}
if (dispatch) {
- vb_buf->vb.ts = ktime_get_ns();
- list_del(&vb_buf->vb.queue);
- vb_buf->vb.state = VIDEOBUF_DONE;
- wake_up(&vb_buf->vb.done);
+ vb_buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ vb_buf->vb.sequence = s->sequence++;
+ list_del(&vb_buf->list);
+ vb2_buffer_done(&vb_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
@@ -304,7 +305,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
cx18_enqueue(s, mdl, &s->q_full);
}
} else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
- cx18_mdl_send_to_videobuf(s, mdl);
+ cx18_mdl_send_to_vb2(s, mdl);
cx18_enqueue(s, mdl, &s->q_free);
} else {
cx18_enqueue(s, mdl, &s->q_full);
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 87ff554bb2d2..597472754c4c 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -29,7 +29,16 @@ static const struct v4l2_file_operations cx18_v4l2_enc_fops = {
.unlocked_ioctl = video_ioctl2,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
- .mmap = cx18_v4l2_mmap,
+};
+
+static const struct v4l2_file_operations cx18_v4l2_enc_yuv_fops = {
+ .owner = THIS_MODULE,
+ .open = cx18_v4l2_open,
+ .unlocked_ioctl = video_ioctl2,
+ .release = cx18_v4l2_close,
+ .poll = vb2_fop_poll,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
};
/* offset from 0 to register ts v4l2 minors on */
@@ -70,7 +79,7 @@ static struct {
VFL_TYPE_VBI, 0,
DMA_FROM_DEVICE,
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_TUNER
+ V4L2_CAP_READWRITE | V4L2_CAP_AUDIO | V4L2_CAP_TUNER
},
{ /* CX18_ENC_STREAM_TYPE_PCM */
"encoder PCM audio",
@@ -91,156 +100,142 @@ static struct {
},
};
-
-static void cx18_dma_free(struct videobuf_queue *q,
- struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
-{
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int cx18_prepare_buffer(struct videobuf_queue *q,
- struct cx18_stream *s,
- struct cx18_videobuf_buffer *buf,
- u32 pixelformat,
- unsigned int width, unsigned int height,
- enum v4l2_field field)
+static int cx18_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
{
+ struct cx18_stream *s = vb2_get_drv_priv(vq);
struct cx18 *cx = s->cx;
- int rc = 0;
-
- /* check settings */
- buf->bytes_used = 0;
-
- if ((width < 48) || (height < 32))
- return -EINVAL;
-
- buf->vb.size = (width * height * 2);
- if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
- return -EINVAL;
+ unsigned int szimage;
- /* alloc + fill struct (if changed) */
- if (buf->vb.width != width || buf->vb.height != height ||
- buf->vb.field != field || s->pixelformat != pixelformat ||
- buf->tvnorm != cx->std) {
+ /*
+ * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
+ */
+ if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
+ szimage = cx->cxhdl.height * 720 * 3 / 2;
+ else
+ szimage = cx->cxhdl.height * 720 * 2;
- buf->vb.width = width;
- buf->vb.height = height;
- buf->vb.field = field;
- buf->tvnorm = cx->std;
- s->pixelformat = pixelformat;
+ /*
+ * Let's request at least three buffers: two for the
+ * DMA engine and one for userspace.
+ */
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
- /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
- UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
- if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
- s->vb_bytes_per_frame = height * 720 * 3 / 2;
- else
- s->vb_bytes_per_frame = height * 720 * 2;
- cx18_dma_free(q, s, buf);
+ if (*nplanes) {
+ if (*nplanes != 1 || sizes[0] < szimage)
+ return -EINVAL;
+ return 0;
}
- if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
- return -EINVAL;
-
- if (buf->vb.field == 0)
- buf->vb.field = V4L2_FIELD_INTERLACED;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- buf->vb.width = width;
- buf->vb.height = height;
- buf->vb.field = field;
- buf->tvnorm = cx->std;
- s->pixelformat = pixelformat;
-
- /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
- UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
- if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
- s->vb_bytes_per_frame = height * 720 * 3 / 2;
- else
- s->vb_bytes_per_frame = height * 720 * 2;
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (rc != 0)
- goto fail;
- }
- buf->vb.state = VIDEOBUF_PREPARED;
+ sizes[0] = szimage;
+ *nplanes = 1;
return 0;
-
-fail:
- cx18_dma_free(q, s, buf);
- return rc;
-
}
-/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
- 1440 is a single line of 4:2:2 YUV at 720 luma samples wide
-*/
-#define VB_MIN_BUFFERS 32
-#define VB_MIN_BUFSIZE 4147200
+static void cx18_buf_queue(struct vb2_buffer *vb)
+{
+ struct cx18_stream *s = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct cx18_vb2_buffer *buf =
+ container_of(vbuf, struct cx18_vb2_buffer, vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->vb_lock, flags);
+ list_add_tail(&buf->list, &s->vb_capture);
+ spin_unlock_irqrestore(&s->vb_lock, flags);
+}
-static int buffer_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static int cx18_buf_prepare(struct vb2_buffer *vb)
{
- struct cx18_stream *s = q->priv_data;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct cx18_stream *s = vb2_get_drv_priv(vb->vb2_queue);
struct cx18 *cx = s->cx;
+ unsigned int size;
- *size = 2 * cx->cxhdl.width * cx->cxhdl.height;
- if (*count == 0)
- *count = VB_MIN_BUFFERS;
-
- while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
- (*count)--;
-
- q->field = V4L2_FIELD_INTERLACED;
- q->last = V4L2_FIELD_INTERLACED;
+ /*
+ * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
+ */
+ if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
+ size = cx->cxhdl.height * 720 * 3 / 2;
+ else
+ size = cx->cxhdl.height * 720 * 2;
+ if (vb2_plane_size(vb, 0) < size)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, size);
+ vbuf->field = V4L2_FIELD_INTERLACED;
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
+void cx18_clear_queue(struct cx18_stream *s, enum vb2_buffer_state state)
{
- struct cx18_videobuf_buffer *buf =
- container_of(vb, struct cx18_videobuf_buffer, vb);
- struct cx18_stream *s = q->priv_data;
- struct cx18 *cx = s->cx;
+ while (!list_empty(&s->vb_capture)) {
+ struct cx18_vb2_buffer *buf;
- return cx18_prepare_buffer(q, s, buf, s->pixelformat,
- cx->cxhdl.width, cx->cxhdl.height, field);
+ buf = list_first_entry(&s->vb_capture,
+ struct cx18_vb2_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
}
-static void buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static int cx18_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct cx18_videobuf_buffer *buf =
- container_of(vb, struct cx18_videobuf_buffer, vb);
- struct cx18_stream *s = q->priv_data;
+ struct v4l2_fh *owner = vq->owner;
+ struct cx18_stream *s = vb2_get_drv_priv(vq);
+ unsigned long flags;
+ int rc;
+
+ if (WARN_ON(!owner)) {
+ rc = -EIO;
+ goto clear_queue;
+ }
- cx18_dma_free(q, s, buf);
+ s->sequence = 0;
+ rc = cx18_start_capture(fh2id(owner));
+ if (!rc) {
+ /* Establish a buffer timeout */
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+ return 0;
+ }
+
+clear_queue:
+ spin_lock_irqsave(&s->vb_lock, flags);
+ cx18_clear_queue(s, VB2_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&s->vb_lock, flags);
+ return rc;
}
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void cx18_stop_streaming(struct vb2_queue *vq)
{
- struct cx18_videobuf_buffer *buf =
- container_of(vb, struct cx18_videobuf_buffer, vb);
- struct cx18_stream *s = q->priv_data;
-
- buf->vb.state = VIDEOBUF_QUEUED;
-
- list_add_tail(&buf->vb.queue, &s->vb_capture);
+ struct cx18_stream *s = vb2_get_drv_priv(vq);
+ unsigned long flags;
+
+ cx18_stop_capture(s, 0);
+ timer_delete_sync(&s->vb_timeout);
+ spin_lock_irqsave(&s->vb_lock, flags);
+ cx18_clear_queue(s, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&s->vb_lock, flags);
}
-static const struct videobuf_queue_ops cx18_videobuf_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+static const struct vb2_ops cx18_vb2_qops = {
+ .queue_setup = cx18_queue_setup,
+ .buf_queue = cx18_buf_queue,
+ .buf_prepare = cx18_buf_prepare,
+ .start_streaming = cx18_start_streaming,
+ .stop_streaming = cx18_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
-static void cx18_stream_init(struct cx18 *cx, int type)
+static int cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
+ int err = 0;
memset(s, 0, sizeof(*s));
@@ -275,22 +270,33 @@ static void cx18_stream_init(struct cx18 *cx, int type)
INIT_LIST_HEAD(&s->vb_capture);
timer_setup(&s->vb_timeout, cx18_vb_timeout, 0);
spin_lock_init(&s->vb_lock);
- if (type == CX18_ENC_STREAM_TYPE_YUV) {
- spin_lock_init(&s->vbuf_q_lock);
+ if (type == CX18_ENC_STREAM_TYPE_YUV) {
s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
- &cx->pci_dev->dev, &s->vbuf_q_lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx18_videobuf_buffer),
- s, &cx->serialize_lock);
/* Assume the previous pixel default */
s->pixelformat = V4L2_PIX_FMT_NV12_16L16;
s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
s->vb_bytes_per_line = 720;
+
+ s->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
+ s->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ s->vidq.drv_priv = s;
+ s->vidq.buf_struct_size = sizeof(struct cx18_vb2_buffer);
+ s->vidq.ops = &cx18_vb2_qops;
+ s->vidq.mem_ops = &vb2_vmalloc_memops;
+ s->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ s->vidq.min_buffers_needed = 2;
+ s->vidq.gfp_flags = GFP_DMA32;
+ s->vidq.dev = &cx->pci_dev->dev;
+ s->vidq.lock = &cx->serialize_lock;
+
+ err = vb2_queue_init(&s->vidq);
+ if (err)
+ v4l2_err(&cx->v4l2_dev, "cannot init vb2 queue\n");
+ s->video_dev.queue = &s->vidq;
}
+ return err;
}
static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -299,6 +305,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
u32 cap = cx->v4l2_cap;
int num_offset = cx18_stream_info[type].num_offset;
int num = cx->instance + cx18_first_minor + num_offset;
+ int err;
/*
* These five fields are always initialized.
@@ -330,7 +337,9 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
return 0;
}
- cx18_stream_init(cx, type);
+ err = cx18_stream_init(cx, type);
+ if (err)
+ return err;
/* Allocate the cx18_dvb struct only for the TS on cards with DTV */
if (type == CX18_ENC_STREAM_TYPE_TS) {
@@ -356,7 +365,10 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->video_dev.num = num;
s->video_dev.v4l2_dev = &cx->v4l2_dev;
- s->video_dev.fops = &cx18_v4l2_enc_fops;
+ if (type == CX18_ENC_STREAM_TYPE_YUV)
+ s->video_dev.fops = &cx18_v4l2_enc_yuv_fops;
+ else
+ s->video_dev.fops = &cx18_v4l2_enc_fops;
s->video_dev.release = video_device_release_empty;
if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER)
s->video_dev.tvnorms = cx->tuner_std;
@@ -525,12 +537,12 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
if (vdev->v4l2_dev == NULL)
continue;
- if (type == CX18_ENC_STREAM_TYPE_YUV)
- videobuf_mmap_free(&cx->streams[type].vbuf_q);
-
cx18_stream_free(&cx->streams[type]);
- video_unregister_device(vdev);
+ if (type == CX18_ENC_STREAM_TYPE_YUV)
+ vb2_video_unregister_device(vdev);
+ else
+ video_unregister_device(vdev);
}
}
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 9232a966bcab..2ce2914576cf 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -1325,7 +1325,9 @@ void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
{
struct cx23885_riscmem *risc = &buf->risc;
- dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma);
+ if (risc->cpu)
+ dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
}
static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 3d03f5e95786..671fc0588e43 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -342,6 +342,7 @@ static int queue_setup(struct vb2_queue *q,
static int buffer_prepare(struct vb2_buffer *vb)
{
+ int ret;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf =
@@ -358,12 +359,12 @@ static int buffer_prepare(struct vb2_buffer *vb)
switch (dev->field) {
case V4L2_FIELD_TOP:
- cx23885_risc_buffer(dev->pci, &buf->risc,
+ ret = cx23885_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, UNSET,
buf->bpl, 0, dev->height);
break;
case V4L2_FIELD_BOTTOM:
- cx23885_risc_buffer(dev->pci, &buf->risc,
+ ret = cx23885_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, UNSET, 0,
buf->bpl, 0, dev->height);
break;
@@ -391,21 +392,21 @@ static int buffer_prepare(struct vb2_buffer *vb)
line0_offset = 0;
line1_offset = buf->bpl;
}
- cx23885_risc_buffer(dev->pci, &buf->risc,
+ ret = cx23885_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, line0_offset,
line1_offset,
buf->bpl, buf->bpl,
dev->height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
- cx23885_risc_buffer(dev->pci, &buf->risc,
+ ret = cx23885_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
0, buf->bpl * (dev->height >> 1),
buf->bpl, 0,
dev->height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
- cx23885_risc_buffer(dev->pci, &buf->risc,
+ ret = cx23885_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
buf->bpl * (dev->height >> 1), 0,
buf->bpl, 0,
@@ -418,7 +419,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
buf, buf->vb.vb2_buf.index,
dev->width, dev->height, dev->fmt->depth, dev->fmt->fourcc,
(unsigned long)buf->risc.dma);
- return 0;
+ return ret;
}
static void buffer_finish(struct vb2_buffer *vb)
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 4ac645a56c14..9e9c7c071acc 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -1176,6 +1176,7 @@ static void dm1105_remove(struct pci_dev *pdev)
struct dvb_demux *dvbdemux = &dev->demux;
struct dmx_demux *dmx = &dvbdemux->dmx;
+ cancel_work_sync(&dev->ir.work);
dm1105_ir_exit(dev);
dmx->close(dmx);
dvb_net_release(&dev->dvbnet);
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
index dfefe0d8aa95..3c2accfe5455 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -29,6 +29,14 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = {
CIO2_SENSOR_CONFIG("INT347E", 1, 319200000),
/* Omnivision OV2680 */
CIO2_SENSOR_CONFIG("OVTI2680", 0),
+ /* Omnivision ov8856 */
+ CIO2_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
+ /* Omnivision ov2740 */
+ CIO2_SENSOR_CONFIG("INT3474", 1, 360000000),
+ /* Hynix hi556 */
+ CIO2_SENSOR_CONFIG("INT3537", 1, 437000000),
+ /* Omnivision ov13b10 */
+ CIO2_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
};
static const struct cio2_property_names prop_names = {
@@ -212,6 +220,7 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
struct cio2_sensor *sensor)
{
struct software_node *nodes = sensor->swnodes;
+ char vcm_name[ACPI_ID_LEN + 4];
cio2_bridge_init_swnode_names(sensor);
@@ -229,9 +238,13 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
sensor->node_names.endpoint,
&nodes[SWNODE_CIO2_PORT],
sensor->cio2_properties);
- if (sensor->ssdb.vcmtype)
- nodes[SWNODE_VCM] =
- NODE_VCM(cio2_vcm_types[sensor->ssdb.vcmtype - 1]);
+ if (sensor->ssdb.vcmtype) {
+ /* append ssdb.link to distinguish VCM nodes with same HID */
+ snprintf(vcm_name, sizeof(vcm_name), "%s-%u",
+ cio2_vcm_types[sensor->ssdb.vcmtype - 1],
+ sensor->ssdb.link);
+ nodes[SWNODE_VCM] = NODE_VCM(vcm_name);
+ }
cio2_bridge_init_swnode_group(sensor);
}
@@ -295,7 +308,6 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
}
sensor = &bridge->sensors[bridge->n_sensors];
- strscpy(sensor->name, cfg->hid, sizeof(sensor->name));
ret = cio2_bridge_read_acpi_buffer(adev, "SSDB",
&sensor->ssdb,
@@ -303,6 +315,9 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
if (ret)
goto err_put_adev;
+ snprintf(sensor->name, sizeof(sensor->name), "%s-%u",
+ cfg->hid, sensor->ssdb.link);
+
if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) {
dev_warn(&adev->dev, "Unknown VCM type %d\n",
sensor->ssdb.vcmtype);
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h
index b93b749c65bd..b76ed8a641e2 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.h
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
@@ -113,7 +113,8 @@ struct cio2_sensor_config {
};
struct cio2_sensor {
- char name[ACPI_ID_LEN];
+ /* append ssdb.link(u8) in "-%u" format as suffix of HID */
+ char name[ACPI_ID_LEN + 4];
struct acpi_device *adev;
struct i2c_client *vcm_i2c_client;
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index 3b76a9d0383a..3c84cb121632 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1305,6 +1305,7 @@ static int cio2_subdev_link_validate_get_format(struct media_pad *pad,
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
+ memset(fmt, 0, sizeof(*fmt));
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt->pad = pad->index;
return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index 99be59af3560..1280696f65f2 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -2116,7 +2116,6 @@ struct saa7134_board saa7134_boards[] = {
- Remote control doesn't initialize properly.
- Audio volume starts muted,
then gradually increases after channel change.
- - Overlay scaling problems (application error?)
- Composite S-Video untested.
From: Konrad Rzepecki <hannibal@megapolis.pl>
*/
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index cf2871306987..ea0585e43abb 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -51,10 +51,6 @@ static unsigned int latency = UNSET;
module_param(latency, int, 0444);
MODULE_PARM_DESC(latency,"pci latency timer");
-int saa7134_no_overlay=-1;
-module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
-MODULE_PARM_DESC(no_overlay, "allow override overlay default (0 disables, 1 enables) [some VIA/SIS chipsets are known to have problem with overlay]");
-
bool saa7134_userptr;
module_param(saa7134_userptr, bool, 0644);
MODULE_PARM_DESC(saa7134_userptr, "enable page-aligned userptr support");
@@ -400,13 +396,6 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
SAA7134_MAIN_CTRL_TE5;
}
- /* screen overlay -- dma 0 + video task B */
- if (dev->ovenable) {
- task |= 0x10;
- ctrl |= SAA7134_MAIN_CTRL_TE1;
- ov = dev->ovfield;
- }
-
/* vbi capture -- dma 0 + vbi task A+B */
if (dev->vbi_q.curr) {
task |= 0x22;
@@ -1066,18 +1055,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
latency = 0x0A;
}
#endif
- if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) {
- pr_info("%s: quirk: this driver and your chipset may not work together in overlay mode.\n",
- dev->name);
- if (!saa7134_no_overlay) {
- pr_info("%s: quirk: overlay mode will be disabled.\n",
- dev->name);
- saa7134_no_overlay = 1;
- } else {
- pr_info("%s: quirk: overlay mode will be forced. Use this option at your own risk.\n",
- dev->name);
- }
- }
}
if (UNSET != latency) {
pr_info("%s: setting pci latency timer to %d\n",
@@ -1198,9 +1175,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
saa_call_all(dev, core, s_power, 0);
/* register v4l devices */
- if (saa7134_no_overlay > 0)
- pr_info("%s: Overlay support disabled.\n", dev->name);
-
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
dev->video_dev->ctrl_handler = &dev->ctrl_handler;
dev->video_dev->lock = &dev->lock;
@@ -1210,9 +1184,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
dev->video_dev->device_caps |= V4L2_CAP_TUNER;
- if (saa7134_no_overlay <= 0)
- dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY;
-
err = video_register_device(dev->video_dev,VFL_TYPE_VIDEO,
video_nr[dev->nr]);
if (err < 0) {
@@ -1403,9 +1374,6 @@ static int __maybe_unused saa7134_suspend(struct device *dev_d)
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
- /* disable overlay - apps should enable it explicitly on resume*/
- dev->ovenable = 0;
-
/* Disable interrupts, DMA, and rest of the chip*/
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, 0);
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index aafbb34765b0..434fa1ee1c33 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -139,8 +139,8 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 6a5053126237..437dbe5e75e2 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -300,6 +300,7 @@ int saa7134_ts_start(struct saa7134_dev *dev)
int saa7134_ts_fini(struct saa7134_dev *dev)
{
+ del_timer_sync(&dev->ts_q.timeout);
saa7134_pgtable_free(dev->pci, &dev->ts_q.pt);
return 0;
}
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index 3f0b0933eed6..3e773690468b 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -185,6 +185,7 @@ int saa7134_vbi_init1(struct saa7134_dev *dev)
int saa7134_vbi_fini(struct saa7134_dev *dev)
{
/* nothing */
+ del_timer_sync(&dev->vbi_q.timeout);
return 0;
}
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 4d8974c9fcc9..56b4481a40e6 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -571,193 +571,6 @@ static void set_size(struct saa7134_dev *dev, int task,
/* ------------------------------------------------------------------ */
-struct cliplist {
- __u16 position;
- __u8 enable;
- __u8 disable;
-};
-
-static void set_cliplist(struct saa7134_dev *dev, int reg,
- struct cliplist *cl, int entries, char *name)
-{
- __u8 winbits = 0;
- int i;
-
- for (i = 0; i < entries; i++) {
- winbits |= cl[i].enable;
- winbits &= ~cl[i].disable;
- if (i < 15 && cl[i].position == cl[i+1].position)
- continue;
- saa_writeb(reg + 0, winbits);
- saa_writeb(reg + 2, cl[i].position & 0xff);
- saa_writeb(reg + 3, cl[i].position >> 8);
- video_dbg("clip: %s winbits=%02x pos=%d\n",
- name,winbits,cl[i].position);
- reg += 8;
- }
- for (; reg < 0x400; reg += 8) {
- saa_writeb(reg+ 0, 0);
- saa_writeb(reg + 1, 0);
- saa_writeb(reg + 2, 0);
- saa_writeb(reg + 3, 0);
- }
-}
-
-static int clip_range(int val)
-{
- if (val < 0)
- val = 0;
- return val;
-}
-
-/* Sort into smallest position first order */
-static int cliplist_cmp(const void *a, const void *b)
-{
- const struct cliplist *cla = a;
- const struct cliplist *clb = b;
- if (cla->position < clb->position)
- return -1;
- if (cla->position > clb->position)
- return 1;
- return 0;
-}
-
-static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
- int nclips, int interlace)
-{
- struct cliplist col[16], row[16];
- int cols = 0, rows = 0, i;
- int div = interlace ? 2 : 1;
-
- memset(col, 0, sizeof(col));
- memset(row, 0, sizeof(row));
- for (i = 0; i < nclips && i < 8; i++) {
- col[cols].position = clip_range(clips[i].c.left);
- col[cols].enable = (1 << i);
- cols++;
- col[cols].position = clip_range(clips[i].c.left+clips[i].c.width);
- col[cols].disable = (1 << i);
- cols++;
- row[rows].position = clip_range(clips[i].c.top / div);
- row[rows].enable = (1 << i);
- rows++;
- row[rows].position = clip_range((clips[i].c.top + clips[i].c.height)
- / div);
- row[rows].disable = (1 << i);
- rows++;
- }
- sort(col, cols, sizeof col[0], cliplist_cmp, NULL);
- sort(row, rows, sizeof row[0], cliplist_cmp, NULL);
- set_cliplist(dev,0x380,col,cols,"cols");
- set_cliplist(dev,0x384,row,rows,"rows");
- return 0;
-}
-
-static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win, bool try)
-{
- enum v4l2_field field;
- int maxw, maxh;
-
- if (!try && (dev->ovbuf.base == NULL || dev->ovfmt == NULL))
- return -EINVAL;
- if (win->w.width < 48)
- win->w.width = 48;
- if (win->w.height < 32)
- win->w.height = 32;
- if (win->clipcount > 8)
- win->clipcount = 8;
-
- win->chromakey = 0;
- win->global_alpha = 0;
- field = win->field;
- maxw = dev->crop_current.width;
- maxh = dev->crop_current.height;
-
- if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- default:
- field = V4L2_FIELD_INTERLACED;
- break;
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
- return 0;
-}
-
-static int start_preview(struct saa7134_dev *dev)
-{
- unsigned long base,control,bpl;
- int err;
-
- err = verify_preview(dev, &dev->win, false);
- if (0 != err)
- return err;
-
- dev->ovfield = dev->win.field;
- video_dbg("%s %dx%d+%d+%d 0x%08x field=%s\n", __func__,
- dev->win.w.width, dev->win.w.height,
- dev->win.w.left, dev->win.w.top,
- dev->ovfmt->fourcc, v4l2_field_names[dev->ovfield]);
-
- /* setup window + clipping */
- set_size(dev, TASK_B, dev->win.w.width, dev->win.w.height,
- V4L2_FIELD_HAS_BOTH(dev->ovfield));
- setup_clipping(dev, dev->clips, dev->nclips,
- V4L2_FIELD_HAS_BOTH(dev->ovfield));
- if (dev->ovfmt->yuv)
- saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);
- else
- saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01);
- saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20);
-
- /* dma: setup channel 1 (= Video Task B) */
- base = (unsigned long)dev->ovbuf.base;
- base += dev->ovbuf.fmt.bytesperline * dev->win.w.top;
- base += dev->ovfmt->depth/8 * dev->win.w.left;
- bpl = dev->ovbuf.fmt.bytesperline;
- control = SAA7134_RS_CONTROL_BURST_16;
- if (dev->ovfmt->bswap)
- control |= SAA7134_RS_CONTROL_BSWAP;
- if (dev->ovfmt->wswap)
- control |= SAA7134_RS_CONTROL_WSWAP;
- if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) {
- saa_writel(SAA7134_RS_BA1(1),base);
- saa_writel(SAA7134_RS_BA2(1),base+bpl);
- saa_writel(SAA7134_RS_PITCH(1),bpl*2);
- saa_writel(SAA7134_RS_CONTROL(1),control);
- } else {
- saa_writel(SAA7134_RS_BA1(1),base);
- saa_writel(SAA7134_RS_BA2(1),base);
- saa_writel(SAA7134_RS_PITCH(1),bpl);
- saa_writel(SAA7134_RS_CONTROL(1),control);
- }
-
- /* start dma */
- dev->ovenable = 1;
- saa7134_set_dmabits(dev);
-
- return 0;
-}
-
-static int stop_preview(struct saa7134_dev *dev)
-{
- dev->ovenable = 0;
- saa7134_set_dmabits(dev);
- return 0;
-}
-
/*
* Media Controller helper functions
*/
@@ -1042,8 +855,6 @@ static const struct vb2_ops vb2_qops = {
static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler);
- unsigned long flags;
- int restart_overlay = 0;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1081,15 +892,12 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_HFLIP:
dev->ctl_mirror = ctrl->val;
- restart_overlay = 1;
break;
case V4L2_CID_PRIVATE_Y_EVEN:
dev->ctl_y_even = ctrl->val;
- restart_overlay = 1;
break;
case V4L2_CID_PRIVATE_Y_ODD:
dev->ctl_y_odd = ctrl->val;
- restart_overlay = 1;
break;
case V4L2_CID_PRIVATE_AUTOMUTE:
{
@@ -1112,12 +920,6 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
default:
return -EINVAL;
}
- if (restart_overlay && dev->overlay_owner) {
- spin_lock_irqsave(&dev->slock, flags);
- stop_preview(dev);
- start_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- }
return 0;
}
@@ -1150,21 +952,11 @@ static int video_release(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
struct saa6588_command cmd;
- unsigned long flags;
mutex_lock(&dev->lock);
saa7134_tvaudio_close(dev);
- /* turn off overlay */
- if (fh == dev->overlay_owner) {
- spin_lock_irqsave(&dev->slock,flags);
- stop_preview(dev);
- spin_unlock_irqrestore(&dev->slock,flags);
- dev->overlay_owner = NULL;
- }
-
if (vdev->vfl_type == VFL_TYPE_RADIO)
v4l2_fh_release(file);
else
@@ -1261,34 +1053,6 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- u32 clipcount = f->fmt.win.clipcount;
- int i;
-
- if (saa7134_no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
- f->fmt.win = dev->win;
- if (!f->fmt.win.clips) {
- f->fmt.win.clipcount = 0;
- return 0;
- }
- if (dev->nclips < clipcount)
- clipcount = dev->nclips;
- f->fmt.win.clipcount = clipcount;
-
- for (i = 0; i < clipcount; i++) {
- memcpy(&f->fmt.win.clips[i].c, &dev->clips[i].c,
- sizeof(struct v4l2_rect));
- }
-
- return 0;
-}
-
static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -1342,21 +1106,6 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct saa7134_dev *dev = video_drvdata(file);
-
- if (saa7134_no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
-
- if (f->fmt.win.clips == NULL)
- f->fmt.win.clipcount = 0;
- return verify_preview(dev, &f->fmt.win, true);
-}
-
static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -1374,39 +1123,6 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- int err;
- unsigned long flags;
-
- if (saa7134_no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
- if (f->fmt.win.clips == NULL)
- f->fmt.win.clipcount = 0;
- err = verify_preview(dev, &f->fmt.win, true);
- if (0 != err)
- return err;
-
- dev->win = f->fmt.win;
- dev->nclips = f->fmt.win.clipcount;
-
- memcpy(dev->clips, f->fmt.win.clips,
- sizeof(struct v4l2_clip) * dev->nclips);
-
- if (priv == dev->overlay_owner) {
- spin_lock_irqsave(&dev->slock, flags);
- stop_preview(dev);
- start_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- }
-
- return 0;
-}
-
int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
{
struct saa7134_dev *dev = video_drvdata(file);
@@ -1482,8 +1198,6 @@ int saa7134_querycap(struct file *file, void *priv,
cap->capabilities |= V4L2_CAP_TUNER;
if (dev->has_rds)
cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
- if (saa7134_no_overlay <= 0)
- cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
return 0;
}
@@ -1492,17 +1206,9 @@ EXPORT_SYMBOL_GPL(saa7134_querycap);
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = video_drvdata(file);
- struct v4l2_fh *fh = priv;
- unsigned long flags;
unsigned int i;
v4l2_std_id fixup;
- if (is_empress(file) && dev->overlay_owner) {
- /* Don't change the std from the mpeg device
- if overlay is active. */
- return -EBUSY;
- }
-
for (i = 0; i < TVNORMS; i++)
if (id == tvnorms[i].id)
break;
@@ -1534,18 +1240,7 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
return -EINVAL;
}
- if (!is_empress(file) && fh == dev->overlay_owner) {
- spin_lock_irqsave(&dev->slock, flags);
- stop_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
-
- set_tvnorm(dev, &tvnorms[i]);
-
- spin_lock_irqsave(&dev->slock, flags);
- start_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- } else
- set_tvnorm(dev, &tvnorms[i]);
+ set_tvnorm(dev, &tvnorms[i]);
saa7134_tvaudio_do_scan(dev);
return 0;
@@ -1595,8 +1290,7 @@ static int saa7134_g_pixelaspect(struct file *file, void *priv,
{
struct saa7134_dev *dev = video_drvdata(file);
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (dev->tvnorm->id & V4L2_STD_525_60) {
@@ -1614,8 +1308,7 @@ static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection
{
struct saa7134_dev *dev = video_drvdata(file);
- if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
switch (sel->target) {
@@ -1640,15 +1333,12 @@ static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection
struct v4l2_rect *b = &dev->crop_bounds;
struct v4l2_rect *c = &dev->crop_current;
- if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- if (dev->overlay_owner)
- return -EBUSY;
if (vb2_is_streaming(&dev->video_vbq))
return -EBUSY;
@@ -1764,85 +1454,6 @@ static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (saa7134_no_overlay > 0) {
- pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- return -EINVAL;
- }
-
- if ((f->index >= FORMATS) || formats[f->index].planar)
- return -EINVAL;
-
- f->pixelformat = formats[f->index].fourcc;
-
- return 0;
-}
-
-static int saa7134_g_fbuf(struct file *file, void *f,
- struct v4l2_framebuffer *fb)
-{
- struct saa7134_dev *dev = video_drvdata(file);
-
- *fb = dev->ovbuf;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-
- return 0;
-}
-
-static int saa7134_s_fbuf(struct file *file, void *f,
- const struct v4l2_framebuffer *fb)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_format *fmt;
-
- if (!capable(CAP_SYS_ADMIN) &&
- !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = format_by_fourcc(fb->fmt.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- /* ok, accept it */
- dev->ovbuf = *fb;
- dev->ovfmt = fmt;
- if (0 == dev->ovbuf.fmt.bytesperline)
- dev->ovbuf.fmt.bytesperline =
- dev->ovbuf.fmt.width*fmt->depth/8;
- return 0;
-}
-
-static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- unsigned long flags;
-
- if (on) {
- if (saa7134_no_overlay > 0) {
- video_dbg("no_overlay\n");
- return -EINVAL;
- }
-
- if (dev->overlay_owner && priv != dev->overlay_owner)
- return -EBUSY;
- dev->overlay_owner = priv;
- spin_lock_irqsave(&dev->slock, flags);
- start_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- } else {
- if (priv != dev->overlay_owner)
- return -EINVAL;
- spin_lock_irqsave(&dev->slock, flags);
- stop_preview(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- dev->overlay_owner = NULL;
- }
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -1912,10 +1523,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay,
- .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay,
- .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay,
- .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay,
.vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
@@ -1937,9 +1544,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_tuner = saa7134_s_tuner,
.vidioc_g_selection = saa7134_g_selection,
.vidioc_s_selection = saa7134_s_selection,
- .vidioc_g_fbuf = saa7134_g_fbuf,
- .vidioc_s_fbuf = saa7134_s_fbuf,
- .vidioc_overlay = saa7134_overlay,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2086,13 +1690,6 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->width = 720;
dev->height = 576;
dev->field = V4L2_FIELD_INTERLACED;
- dev->win.w.width = dev->width;
- dev->win.w.height = dev->height;
- dev->win.field = V4L2_FIELD_INTERLACED;
- dev->ovbuf.fmt.width = dev->width;
- dev->ovbuf.fmt.height = dev->height;
- dev->ovbuf.fmt.pixelformat = dev->fmt->fourcc;
- dev->ovbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
if (saa7134_boards[dev->board].video_out)
saa7134_videoport_init(dev);
@@ -2146,6 +1743,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
void saa7134_video_fini(struct saa7134_dev *dev)
{
+ del_timer_sync(&dev->video_q.timeout);
/* free stuff */
saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 5c9b2912a9d1..9f27e3775c27 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -429,7 +429,6 @@ struct saa7134_board {
/* ----------------------------------------------------------- */
/* device / file handle status */
-#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
#define RESOURCE_EMPRESS 8
@@ -589,17 +588,6 @@ struct saa7134_dev {
unsigned char eedata[256];
int has_rds;
- /* video overlay */
- struct v4l2_framebuffer ovbuf;
- struct saa7134_format *ovfmt;
- unsigned int ovenable;
- enum v4l2_field ovfield;
- struct v4l2_window win;
- struct v4l2_clip clips[8];
- unsigned int nclips;
- struct v4l2_fh *overlay_owner;
-
-
/* video+ts+vbi capture */
struct saa7134_dmaqueue video_q;
struct vb2_queue video_vbq;
@@ -745,7 +733,6 @@ static inline bool is_empress(struct file *file)
extern struct list_head saa7134_devlist;
extern struct mutex saa7134_devlist_lock;
-extern int saa7134_no_overlay;
extern bool saa7134_userptr;
void saa7134_track_gpio(struct saa7134_dev *dev, const char *msg);
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 3947701cd6c7..40b35098f3ea 100644
--- a/drivers/media/pci/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -27,17 +27,18 @@ static int hexium_num;
#define HEXIUM_GEMINI 4
#define HEXIUM_GEMINI_DUAL 5
+#define HEXIUM_STD (V4L2_STD_PAL | V4L2_STD_SECAM | V4L2_STD_NTSC)
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -215,7 +216,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct hexium *hexium = (struct hexium *) dev->ext_priv;
*input = hexium->cur_input;
@@ -226,7 +227,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct hexium *hexium = (struct hexium *) dev->ext_priv;
DEB_EE("VIDIOC_S_INPUT %d\n", input);
diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index 2eb4bee16b71..a2076728c621 100644
--- a/drivers/media/pci/saa7146/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -28,17 +28,18 @@ static int hexium_num;
#define HEXIUM_ORION_1SVHS_3BNC 2
#define HEXIUM_ORION_4BNC 3
+#define HEXIUM_STD (V4L2_STD_PAL | V4L2_STD_SECAM | V4L2_STD_NTSC)
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -326,7 +327,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct hexium *hexium = (struct hexium *) dev->ext_priv;
*input = hexium->cur_input;
@@ -337,7 +338,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct hexium *hexium = (struct hexium *) dev->ext_priv;
if (input >= HEXIUM_INPUTS)
@@ -379,6 +380,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
/* the rest */
hexium->cur_input = 0;
hexium_init_done(dev);
+ hexium_set_input(hexium, 0);
return 0;
}
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 7ded8f5b05cb..a14b839098b8 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -48,6 +48,7 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+#define MXB_STD (V4L2_STD_PAL_BG | V4L2_STD_PAL_I | V4L2_STD_SECAM | V4L2_STD_NTSC)
#define MXB_INPUTS 4
enum { TUNER, AUX1, AUX3, AUX3_YC };
@@ -55,11 +56,11 @@ static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
{ TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 0x3f, 0,
V4L2_STD_PAL_BG | V4L2_STD_PAL_I, 0, V4L2_IN_CAP_STD },
{ AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
- V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ MXB_STD, 0, V4L2_IN_CAP_STD },
{ AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
- V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ MXB_STD, 0, V4L2_IN_CAP_STD },
{ AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
- V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ MXB_STD, 0, V4L2_IN_CAP_STD },
};
/* this array holds the information, which port of the saa7146 each
@@ -456,7 +457,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
*i = mxb->cur_input;
@@ -466,7 +467,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
int err = 0;
int i = 0;
@@ -512,6 +513,9 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
if (err)
return err;
+ mxb->video_dev.tvnorms = mxb_inputs[input].std;
+ mxb->vbi_dev.tvnorms = mxb_inputs[input].std;
+
/* switch video in saa7111a */
if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
@@ -528,7 +532,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (t->index) {
@@ -550,7 +554,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (t->index) {
@@ -565,14 +569,14 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
return call_all(dev, video, querystd, norm);
}
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (f->tuner)
@@ -585,9 +589,8 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
- struct saa7146_vv *vv = dev->vv_data;
if (f->tuner)
return -EINVAL;
@@ -604,15 +607,6 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq);
if (mxb->cur_audinput == 0)
mxb_update_audmode(mxb);
-
- if (mxb->cur_input)
- return 0;
-
- /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
- spin_lock(&dev->slock);
- vv->vbi_fieldcount = 0;
- spin_unlock(&dev->slock);
-
return 0;
}
@@ -626,7 +620,7 @@ static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_EE("VIDIOC_G_AUDIO\n");
@@ -636,7 +630,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
@@ -656,7 +650,7 @@ static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
return -EINVAL;
@@ -667,7 +661,7 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
return -EINVAL;
@@ -713,6 +707,17 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
#endif
+ vv_data.vbi_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data.vbi_ops.vidioc_g_input = vidioc_g_input;
+ vv_data.vbi_ops.vidioc_s_input = vidioc_s_input;
+ vv_data.vbi_ops.vidioc_querystd = vidioc_querystd;
+ vv_data.vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
+ vv_data.vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
+ vv_data.vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
+ vv_data.vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
+ vv_data.vbi_ops.vidioc_enumaudio = vidioc_enumaudio;
+ vv_data.vbi_ops.vidioc_g_audio = vidioc_g_audio;
+ vv_data.vbi_ops.vidioc_s_audio = vidioc_s_audio;
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_VIDEO)) {
ERR("cannot register capture v4l2 device. skipping.\n");
saa7146_vv_release(dev);
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 8535e49a4c4f..e4cf9d63e926 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
@@ -889,6 +890,7 @@ static int sta2x11_vip_init_controls(struct sta2x11_vip *vip)
static int vip_gpio_reserve(struct device *dev, int pin, int dir,
const char *name)
{
+ struct gpio_desc *desc = gpio_to_desc(pin);
int ret = -ENODEV;
if (!gpio_is_valid(pin))
@@ -900,7 +902,7 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
return ret;
}
- ret = gpio_direction_output(pin, dir);
+ ret = gpiod_direction_output(desc, dir);
if (ret) {
dev_err(dev, "Failed to set direction for pin %d (%s)\n",
pin, name);
@@ -908,7 +910,7 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
return ret;
}
- ret = gpio_export(pin, false);
+ ret = gpiod_export(desc, false);
if (ret) {
dev_err(dev, "Failed to export pin %d (%s)\n", pin, name);
gpio_free(pin);
@@ -928,8 +930,10 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
static void vip_gpio_release(struct device *dev, int pin, const char *name)
{
if (gpio_is_valid(pin)) {
+ struct gpio_desc *desc = gpio_to_desc(pin);
+
dev_dbg(dev, "releasing pin %d (%s)\n", pin, name);
- gpio_unexport(pin);
+ gpiod_unexport(desc);
gpio_free(pin);
}
}
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 3cb83005cf09..824529f3c74b 100644
--- a/drivers/media/pci/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -31,6 +31,7 @@
#include "dvb-pll.h"
#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
+#include <linux/etherdevice.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -1410,7 +1411,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
*i = budget_av->cur_input;
@@ -1421,7 +1422,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = video_drvdata(file);
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
dprintk(1, "VIDIOC_S_INPUT %d\n", input);
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 0cbc5b038073..773a18702d36 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -437,6 +437,7 @@ static void tw68_buf_queue(struct vb2_buffer *vb)
*/
static int tw68_buf_prepare(struct vb2_buffer *vb)
{
+ int ret;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vb2_queue *vq = vb->vb2_queue;
struct tw68_dev *dev = vb2_get_drv_priv(vq);
@@ -452,30 +453,30 @@ static int tw68_buf_prepare(struct vb2_buffer *vb)
bpl = (dev->width * dev->fmt->depth) >> 3;
switch (dev->field) {
case V4L2_FIELD_TOP:
- tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,
0, UNSET, bpl, 0, dev->height);
break;
case V4L2_FIELD_BOTTOM:
- tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,
UNSET, 0, bpl, 0, dev->height);
break;
case V4L2_FIELD_SEQ_TB:
- tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,
0, bpl * (dev->height >> 1),
bpl, 0, dev->height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
- tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,
bpl * (dev->height >> 1), 0,
bpl, 0, dev->height >> 1);
break;
case V4L2_FIELD_INTERLACED:
default:
- tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,
0, bpl, bpl, bpl, dev->height >> 1);
break;
}
- return 0;
+ return ret;
}
static void tw68_buf_finish(struct vb2_buffer *vb)
@@ -485,7 +486,8 @@ static void tw68_buf_finish(struct vb2_buffer *vb)
struct tw68_dev *dev = vb2_get_drv_priv(vq);
struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
- dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma);
+ if (buf->cpu)
+ dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma);
}
static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
diff --git a/drivers/media/pci/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h
index 237e830ae726..6d2a526789a5 100644
--- a/drivers/media/pci/zoran/zoran_device.h
+++ b/drivers/media/pci/zoran/zoran_device.h
@@ -25,8 +25,6 @@ void jpeg_codec_sleep(struct zoran *zr, int sleep);
int jpeg_codec_reset(struct zoran *zr);
/* zr360x7 access to raw capture */
-void zr36057_overlay(struct zoran *zr, int on);
-void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count);
void zr36057_set_memgrab(struct zoran *zr, int mode);
int wait_grab_pending(struct zoran *zr);
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
index 2423714afcb9..ec03e17727d7 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -3919,7 +3919,7 @@ static int allegro_probe(struct platform_device *pdev)
return 0;
}
-static int allegro_remove(struct platform_device *pdev)
+static void allegro_remove(struct platform_device *pdev)
{
struct allegro_dev *dev = platform_get_drvdata(pdev);
@@ -3935,8 +3935,6 @@ static int allegro_remove(struct platform_device *pdev)
pm_runtime_disable(&dev->plat_dev->dev);
v4l2_device_unregister(&dev->v4l2_dev);
-
- return 0;
}
static int allegro_runtime_resume(struct device *device)
@@ -4006,7 +4004,7 @@ static const struct dev_pm_ops allegro_pm_ops = {
static struct platform_driver allegro_driver = {
.probe = allegro_probe,
- .remove = allegro_remove,
+ .remove_new = allegro_remove,
.driver = {
.name = "allegro",
.of_match_table = of_match_ptr(allegro_dt_ids),
diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
index 142d421a8d76..09409908ba5d 100644
--- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
+++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
@@ -1024,7 +1024,7 @@ disable_clks:
return ret;
}
-static int ge2d_remove(struct platform_device *pdev)
+static void ge2d_remove(struct platform_device *pdev)
{
struct meson_ge2d *ge2d = platform_get_drvdata(pdev);
@@ -1032,8 +1032,6 @@ static int ge2d_remove(struct platform_device *pdev)
v4l2_m2m_release(ge2d->m2m_dev);
v4l2_device_unregister(&ge2d->v4l2_dev);
clk_disable_unprepare(ge2d->clk);
-
- return 0;
}
static const struct of_device_id meson_ge2d_match[] = {
@@ -1047,7 +1045,7 @@ MODULE_DEVICE_TABLE(of, meson_ge2d_match);
static struct platform_driver ge2d_drv = {
.probe = ge2d_probe,
- .remove = ge2d_remove,
+ .remove_new = ge2d_remove,
.driver = {
.name = "meson-ge2d",
.of_match_table = meson_ge2d_match,
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index 87f9f8e90ab1..3fa1a74a2e20 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -165,10 +165,55 @@ static const struct vpu_format vdec_formats[] = {
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
+ {
+ .pixfmt = V4L2_PIX_FMT_SPK,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
+ },
+ {
+ .pixfmt = V4L2_PIX_FMT_RV30,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
+ },
+ {
+ .pixfmt = V4L2_PIX_FMT_RV40,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
+ },
{0, 0, 0, 0},
};
+static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_inst *inst = ctrl_to_inst(ctrl);
+ struct vdec_t *vdec = inst->priv;
+ int ret = 0;
+
+ vpu_inst_lock(inst);
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
+ vdec->params.display_delay_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
+ vdec->params.display_delay = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ vpu_inst_unlock(inst);
+
+ return ret;
+}
+
static const struct v4l2_ctrl_ops vdec_ctrl_ops = {
+ .s_ctrl = vdec_op_s_ctrl,
.g_volatile_ctrl = vpu_helper_g_volatile_ctrl,
};
@@ -181,6 +226,14 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
if (ret)
return ret;
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
+ 0, 0, 1, 0);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
+ 0, 1, 1, 0);
+
ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2);
if (ctrl)
diff --git a/drivers/media/platform/amphion/vpu_codec.h b/drivers/media/platform/amphion/vpu_codec.h
index 528a93f08ecd..bac6d0d94f8a 100644
--- a/drivers/media/platform/amphion/vpu_codec.h
+++ b/drivers/media/platform/amphion/vpu_codec.h
@@ -55,7 +55,8 @@ struct vpu_encode_params {
struct vpu_decode_params {
u32 codec_format;
u32 output_format;
- u32 b_dis_reorder;
+ u32 display_delay_enable;
+ u32 display_delay;
u32 b_non_frame;
u32 frame_count;
u32 end_flag;
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index f9ec1753f7c8..de23627a119a 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -709,7 +709,7 @@ err_runtime_disable:
return ret;
}
-static int vpu_core_remove(struct platform_device *pdev)
+static void vpu_core_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct vpu_core *core = platform_get_drvdata(pdev);
@@ -728,8 +728,6 @@ static int vpu_core_remove(struct platform_device *pdev)
memunmap(core->rpc.virt);
mutex_destroy(&core->lock);
mutex_destroy(&core->cmd_lock);
-
- return 0;
}
static int __maybe_unused vpu_core_runtime_resume(struct device *dev)
@@ -864,7 +862,7 @@ MODULE_DEVICE_TABLE(of, vpu_core_dt_match);
static struct platform_driver amphion_vpu_core_driver = {
.probe = vpu_core_probe,
- .remove = vpu_core_remove,
+ .remove_new = vpu_core_remove,
.driver = {
.name = "amphion-vpu-core",
.of_match_table = vpu_core_dt_match,
diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c
index f01ce49d27e8..4187b2b5562f 100644
--- a/drivers/media/platform/amphion/vpu_drv.c
+++ b/drivers/media/platform/amphion/vpu_drv.c
@@ -157,7 +157,7 @@ err_vpu_deinit:
return ret;
}
-static int vpu_remove(struct platform_device *pdev)
+static void vpu_remove(struct platform_device *pdev)
{
struct vpu_dev *vpu = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -173,8 +173,6 @@ static int vpu_remove(struct platform_device *pdev)
media_device_cleanup(&vpu->mdev);
v4l2_device_unregister(&vpu->v4l2_dev);
mutex_destroy(&vpu->lock);
-
- return 0;
}
static int __maybe_unused vpu_runtime_resume(struct device *dev)
@@ -229,7 +227,7 @@ MODULE_DEVICE_TABLE(of, vpu_dt_match);
static struct platform_driver amphion_vpu_driver = {
.probe = vpu_probe,
- .remove = vpu_remove,
+ .remove_new = vpu_remove,
.driver = {
.name = "amphion-vpu",
.of_match_table = vpu_dt_match,
diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c
index 2c9bfc6a5a72..ef44bff9fbaf 100644
--- a/drivers/media/platform/amphion/vpu_malone.c
+++ b/drivers/media/platform/amphion/vpu_malone.c
@@ -68,6 +68,8 @@
#define STREAM_CONFIG_NUM_DBE_SET(x, y) CONFIG_SET(x, y, 30, 0x40000000)
#define STREAM_CONFIG_FS_CTRL_MODE_SET(x, y) CONFIG_SET(x, y, 31, 0x80000000)
+#define MALONE_DEC_FMT_RV_MASK BIT(21)
+
enum vpu_malone_stream_input_mode {
INVALID_MODE = 0,
FRAME_LVL,
@@ -478,6 +480,9 @@ u32 vpu_malone_get_version(struct vpu_shared_addr *shared)
{
struct malone_iface *iface = shared->iface;
+ vpu_malone_enable_format(V4L2_PIX_FMT_RV30, iface->fw_version & MALONE_DEC_FMT_RV_MASK);
+ vpu_malone_enable_format(V4L2_PIX_FMT_RV40, iface->fw_version & MALONE_DEC_FMT_RV_MASK);
+
return iface->fw_version;
}
@@ -562,8 +567,23 @@ static struct malone_fmt_mapping fmt_mappings[] = {
{V4L2_PIX_FMT_H263, MALONE_FMT_ASP},
{V4L2_PIX_FMT_JPEG, MALONE_FMT_JPG},
{V4L2_PIX_FMT_VP8, MALONE_FMT_VP8},
+ {V4L2_PIX_FMT_SPK, MALONE_FMT_SPK},
+ {V4L2_PIX_FMT_RV30, MALONE_FMT_RV},
+ {V4L2_PIX_FMT_RV40, MALONE_FMT_RV},
};
+void vpu_malone_enable_format(u32 pixelformat, int enable)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(fmt_mappings); i++) {
+ if (pixelformat == fmt_mappings[i].pixelformat) {
+ fmt_mappings[i].is_disabled = enable ? 0 : 1;
+ return;
+ }
+ }
+}
+
static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat)
{
u32 i;
@@ -641,7 +661,9 @@ static int vpu_malone_set_params(struct vpu_shared_addr *shared,
hc->jpg[instance].jpg_mjpeg_interlaced = 0;
}
- hc->codec_param[instance].disp_imm = params->b_dis_reorder ? 1 : 0;
+ hc->codec_param[instance].disp_imm = params->display_delay_enable ? 1 : 0;
+ if (malone_format != MALONE_FMT_AVC)
+ hc->codec_param[instance].disp_imm = 0;
hc->codec_param[instance].dbglog_enable = 0;
iface->dbglog_desc.level = 0;
@@ -987,6 +1009,9 @@ static const struct malone_padding_scode padding_scodes[] = {
{SCODE_PADDING_EOS, V4L2_PIX_FMT_XVID, {0xb1010000, 0x0}},
{SCODE_PADDING_EOS, V4L2_PIX_FMT_H263, {0xb1010000, 0x0}},
{SCODE_PADDING_EOS, V4L2_PIX_FMT_VP8, {0x34010000, 0x0}},
+ {SCODE_PADDING_EOS, V4L2_PIX_FMT_SPK, {0x34010000, 0x0}},
+ {SCODE_PADDING_EOS, V4L2_PIX_FMT_RV30, {0x34010000, 0x0}},
+ {SCODE_PADDING_EOS, V4L2_PIX_FMT_RV40, {0x34010000, 0x0}},
{SCODE_PADDING_EOS, V4L2_PIX_FMT_JPEG, {0xefff0000, 0x0}},
{SCODE_PADDING_ABORT, V4L2_PIX_FMT_H264, {0x0B010000, 0}},
{SCODE_PADDING_ABORT, V4L2_PIX_FMT_H264_MVC, {0x0B010000, 0}},
@@ -998,6 +1023,9 @@ static const struct malone_padding_scode padding_scodes[] = {
{SCODE_PADDING_ABORT, V4L2_PIX_FMT_XVID, {0xb1010000, 0x0}},
{SCODE_PADDING_ABORT, V4L2_PIX_FMT_H263, {0xb1010000, 0x0}},
{SCODE_PADDING_ABORT, V4L2_PIX_FMT_VP8, {0x34010000, 0x0}},
+ {SCODE_PADDING_ABORT, V4L2_PIX_FMT_SPK, {0x34010000, 0x0}},
+ {SCODE_PADDING_ABORT, V4L2_PIX_FMT_RV30, {0x34010000, 0x0}},
+ {SCODE_PADDING_ABORT, V4L2_PIX_FMT_RV40, {0x34010000, 0x0}},
{SCODE_PADDING_EOS, V4L2_PIX_FMT_JPEG, {0x0, 0x0}},
{SCODE_PADDING_BUFFLUSH, V4L2_PIX_FMT_H264, {0x15010000, 0x0}},
{SCODE_PADDING_BUFFLUSH, V4L2_PIX_FMT_H264_MVC, {0x15010000, 0x0}},
@@ -1411,6 +1439,16 @@ static int vpu_malone_insert_scode_vp8_pic(struct malone_scode_t *scode)
return size;
}
+static int vpu_malone_insert_scode_spk_seq(struct malone_scode_t *scode)
+{
+ return vpu_malone_insert_scode_seq(scode, MALONE_CODEC_ID_SPK, 0);
+}
+
+static int vpu_malone_insert_scode_spk_pic(struct malone_scode_t *scode)
+{
+ return vpu_malone_insert_scode_pic(scode, MALONE_CODEC_ID_SPK, 0);
+}
+
static const struct malone_scode_handler scode_handlers[] = {
{
/* fix me, need to swap return operation after gstreamer swap */
@@ -1427,6 +1465,11 @@ static const struct malone_scode_handler scode_handlers[] = {
.insert_scode_seq = vpu_malone_insert_scode_vp8_seq,
.insert_scode_pic = vpu_malone_insert_scode_vp8_pic,
},
+ {
+ .pixelformat = V4L2_PIX_FMT_SPK,
+ .insert_scode_seq = vpu_malone_insert_scode_spk_seq,
+ .insert_scode_pic = vpu_malone_insert_scode_spk_pic,
+ },
};
static const struct malone_scode_handler *get_scode_handler(u32 pixelformat)
diff --git a/drivers/media/platform/amphion/vpu_malone.h b/drivers/media/platform/amphion/vpu_malone.h
index 02a9d9530970..c95b53629199 100644
--- a/drivers/media/platform/amphion/vpu_malone.h
+++ b/drivers/media/platform/amphion/vpu_malone.h
@@ -41,5 +41,6 @@ int vpu_malone_post_cmd(struct vpu_shared_addr *shared, u32 instance);
int vpu_malone_init_instance(struct vpu_shared_addr *shared, u32 instance);
u32 vpu_malone_get_max_instance_count(struct vpu_shared_addr *shared);
bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt);
+void vpu_malone_enable_format(u32 pixelformat, int enable);
#endif
diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index 794d4dc3a654..374eb7781936 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -2206,7 +2206,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
return 0;
}
-static int aspeed_video_remove(struct platform_device *pdev)
+static void aspeed_video_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
@@ -2228,8 +2228,6 @@ static int aspeed_video_remove(struct platform_device *pdev)
aspeed_video_free_buf(video, &video->jpeg);
of_reserved_mem_device_release(dev);
-
- return 0;
}
static struct platform_driver aspeed_video_driver = {
@@ -2238,7 +2236,7 @@ static struct platform_driver aspeed_video_driver = {
.of_match_table = aspeed_video_of_match,
},
.probe = aspeed_video_probe,
- .remove = aspeed_video_remove,
+ .remove_new = aspeed_video_remove,
};
module_platform_driver(aspeed_video_driver);
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 4d15814e4481..c29e04864445 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -587,8 +587,8 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg = {};
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1317,7 +1317,7 @@ err_vdev_alloc:
return ret;
}
-static int atmel_isi_remove(struct platform_device *pdev)
+static void atmel_isi_remove(struct platform_device *pdev)
{
struct atmel_isi *isi = platform_get_drvdata(pdev);
@@ -1329,8 +1329,6 @@ static int atmel_isi_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&isi->notifier);
v4l2_async_nf_cleanup(&isi->notifier);
v4l2_device_unregister(&isi->v4l2_dev);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1368,7 +1366,7 @@ static struct platform_driver atmel_isi_driver = {
.pm = &atmel_isi_dev_pm_ops,
},
.probe = atmel_isi_probe,
- .remove = atmel_isi_remove,
+ .remove_new = atmel_isi_remove,
};
module_platform_driver(atmel_isi_driver);
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index cc3ebb0d96f6..9755d1c8ceb9 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -473,14 +473,12 @@ err_free_priv:
return ret;
}
-static int csi2rx_remove(struct platform_device *pdev)
+static void csi2rx_remove(struct platform_device *pdev)
{
struct csi2rx_priv *csi2rx = platform_get_drvdata(pdev);
v4l2_async_unregister_subdev(&csi2rx->subdev);
kfree(csi2rx);
-
- return 0;
}
static const struct of_device_id csi2rx_of_table[] = {
@@ -491,7 +489,7 @@ MODULE_DEVICE_TABLE(of, csi2rx_of_table);
static struct platform_driver csi2rx_driver = {
.probe = csi2rx_probe,
- .remove = csi2rx_remove,
+ .remove_new = csi2rx_remove,
.driver = {
.name = "cdns-csi2rx",
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index 58e405b69f67..1e0400b7803e 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -635,19 +635,17 @@ err_free_priv:
return ret;
}
-static int csi2tx_remove(struct platform_device *pdev)
+static void csi2tx_remove(struct platform_device *pdev)
{
struct csi2tx_priv *csi2tx = platform_get_drvdata(pdev);
v4l2_async_unregister_subdev(&csi2tx->subdev);
kfree(csi2tx);
-
- return 0;
}
static struct platform_driver csi2tx_driver = {
.probe = csi2tx_probe,
- .remove = csi2tx_remove,
+ .remove_new = csi2tx_remove,
.driver = {
.name = "cdns-csi2tx",
diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda-common.c
index af71eea04dbd..d013ea5d9d3d 100644
--- a/drivers/media/platform/chips-media/coda-common.c
+++ b/drivers/media/platform/chips-media/coda-common.c
@@ -3300,7 +3300,7 @@ err_v4l2_register:
return ret;
}
-static int coda_remove(struct platform_device *pdev)
+static void coda_remove(struct platform_device *pdev)
{
struct coda_dev *dev = platform_get_drvdata(pdev);
int i;
@@ -3322,7 +3322,6 @@ static int coda_remove(struct platform_device *pdev)
coda_free_aux_buf(dev, &dev->workbuf);
debugfs_remove_recursive(dev->debugfs_root);
ida_destroy(&dev->ida);
- return 0;
}
#ifdef CONFIG_PM
@@ -3347,7 +3346,7 @@ static const struct dev_pm_ops coda_pm_ops = {
static struct platform_driver coda_driver = {
.probe = coda_probe,
- .remove = coda_remove,
+ .remove_new = coda_remove,
.driver = {
.name = CODA_NAME,
.of_match_table = coda_dt_ids,
diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index 54270d6b6f50..9ed3c2e063de 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -1794,8 +1794,8 @@ static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -2421,7 +2421,7 @@ exit_free_dma_y:
return err;
}
-static int pxa_camera_remove(struct platform_device *pdev)
+static void pxa_camera_remove(struct platform_device *pdev)
{
struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
@@ -2437,8 +2437,6 @@ static int pxa_camera_remove(struct platform_device *pdev)
v4l2_device_unregister(&pcdev->v4l2_dev);
dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
-
- return 0;
}
static const struct dev_pm_ops pxa_camera_pm = {
@@ -2459,7 +2457,7 @@ static struct platform_driver pxa_camera_driver = {
.of_match_table = of_match_ptr(pxa_camera_of_match),
},
.probe = pxa_camera_probe,
- .remove = pxa_camera_remove,
+ .remove_new = pxa_camera_remove,
};
module_platform_driver(pxa_camera_driver);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 1f89e71cdccf..96b35a5d6174 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -984,7 +984,7 @@ rel_dma:
return ret;
}
-static int deinterlace_remove(struct platform_device *pdev)
+static void deinterlace_remove(struct platform_device *pdev)
{
struct deinterlace_dev *pcdev = platform_get_drvdata(pdev);
@@ -993,13 +993,11 @@ static int deinterlace_remove(struct platform_device *pdev)
video_unregister_device(&pcdev->vfd);
v4l2_device_unregister(&pcdev->v4l2_dev);
dma_release_channel(pcdev->dma_chan);
-
- return 0;
}
static struct platform_driver deinterlace_pdrv = {
.probe = deinterlace_probe,
- .remove = deinterlace_remove,
+ .remove_new = deinterlace_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index ad4a7922d0d7..154bdcb3f2cc 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -1351,8 +1351,8 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_pix_format *pix = &fmt->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index ef22bf8f276c..e93feefb447b 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -287,23 +287,13 @@ out:
return ret;
}
-
-static int mmpcam_remove(struct mmp_camera *cam)
+static void mmpcam_remove(struct platform_device *pdev)
{
+ struct mmp_camera *cam = platform_get_drvdata(pdev);
struct mcam_camera *mcam = &cam->mcam;
mccic_shutdown(mcam);
pm_runtime_force_suspend(mcam->dev);
- return 0;
-}
-
-static int mmpcam_platform_remove(struct platform_device *pdev)
-{
- struct mmp_camera *cam = platform_get_drvdata(pdev);
-
- if (cam == NULL)
- return -ENODEV;
- return mmpcam_remove(cam);
}
/*
@@ -369,7 +359,7 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match);
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
- .remove = mmpcam_platform_remove,
+ .remove_new = mmpcam_remove,
.driver = {
.name = "mmp-camera",
.of_match_table = of_match_ptr(mmpcam_of_match),
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 969516a940ba..6c7c5f3648df 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1004,8 +1004,8 @@ static void mtk_jpegenc_worker(struct work_struct *work)
retry_select:
hw_id = mtk_jpegenc_get_hw(ctx);
if (hw_id < 0) {
- ret = wait_event_interruptible(jpeg->enc_hw_wq,
- atomic_read(&jpeg->enchw_rdy) > 0);
+ ret = wait_event_interruptible(jpeg->hw_wq,
+ atomic_read(&jpeg->hw_rdy) > 0);
if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) {
dev_err(jpeg->dev, "%s : %d, all HW are busy\n",
__func__, __LINE__);
@@ -1016,7 +1016,7 @@ retry_select:
goto retry_select;
}
- atomic_dec(&jpeg->enchw_rdy);
+ atomic_dec(&jpeg->hw_rdy);
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
if (!src_buf)
goto getbuf_fail;
@@ -1025,9 +1025,6 @@ retry_select:
if (!dst_buf)
goto getbuf_fail;
- v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
mtk_jpegenc_set_hw_param(ctx, hw_id, src_buf, dst_buf);
@@ -1045,6 +1042,9 @@ retry_select:
goto enc_end;
}
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
@@ -1073,7 +1073,7 @@ enc_end:
v4l2_m2m_buf_done(src_buf, buf_state);
v4l2_m2m_buf_done(dst_buf, buf_state);
getbuf_fail:
- atomic_inc(&jpeg->enchw_rdy);
+ atomic_inc(&jpeg->hw_rdy);
mtk_jpegenc_put_hw(jpeg, hw_id);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
@@ -1198,8 +1198,8 @@ static void mtk_jpegdec_worker(struct work_struct *work)
retry_select:
hw_id = mtk_jpegdec_get_hw(ctx);
if (hw_id < 0) {
- ret = wait_event_interruptible_timeout(jpeg->dec_hw_wq,
- atomic_read(&jpeg->dechw_rdy) > 0,
+ ret = wait_event_interruptible_timeout(jpeg->hw_wq,
+ atomic_read(&jpeg->hw_rdy) > 0,
MTK_JPEG_HW_TIMEOUT_MSEC);
if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) {
dev_err(jpeg->dev, "%s : %d, all HW are busy\n",
@@ -1211,7 +1211,7 @@ retry_select:
goto retry_select;
}
- atomic_dec(&jpeg->dechw_rdy);
+ atomic_dec(&jpeg->hw_rdy);
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
if (!src_buf)
goto getbuf_fail;
@@ -1220,9 +1220,6 @@ retry_select:
if (!dst_buf)
goto getbuf_fail;
- v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
@@ -1231,7 +1228,7 @@ retry_select:
&jpeg_src_buf->dec_param)) {
mtk_jpeg_queue_src_chg_event(ctx);
ctx->state = MTK_JPEG_SOURCE_CHANGE;
- goto dec_end;
+ goto getbuf_fail;
}
jpeg_src_buf->curr_ctx = ctx;
@@ -1254,6 +1251,9 @@ retry_select:
goto clk_end;
}
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
@@ -1290,7 +1290,7 @@ dec_end:
v4l2_m2m_buf_done(src_buf, buf_state);
v4l2_m2m_buf_done(dst_buf, buf_state);
getbuf_fail:
- atomic_inc(&jpeg->dechw_rdy);
+ atomic_inc(&jpeg->hw_rdy);
mtk_jpegdec_put_hw(jpeg, hw_id);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
@@ -1575,12 +1575,7 @@ static int mtk_jpeg_open(struct file *file)
goto free;
}
- if (jpeg->is_jpgenc_multihw)
- INIT_WORK(&ctx->jpeg_work, mtk_jpegenc_worker);
-
- if (jpeg->is_jpgdec_multihw)
- INIT_WORK(&ctx->jpeg_work, mtk_jpegdec_worker);
-
+ INIT_WORK(&ctx->jpeg_work, jpeg->variant->jpeg_worker);
INIT_LIST_HEAD(&ctx->dst_done_queue);
spin_lock_init(&ctx->done_queue_lock);
v4l2_fh_init(&ctx->fh, vfd);
@@ -1671,10 +1666,52 @@ static void mtk_jpeg_job_timeout_work(struct work_struct *work)
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
+static int mtk_jpeg_single_core_init(struct platform_device *pdev,
+ struct mtk_jpeg_dev *jpeg_dev)
+{
+ struct mtk_jpeg_dev *jpeg = jpeg_dev;
+ int jpeg_irq, ret;
+
+ INIT_DELAYED_WORK(&jpeg->job_timeout_work,
+ mtk_jpeg_job_timeout_work);
+
+ jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(jpeg->reg_base)) {
+ ret = PTR_ERR(jpeg->reg_base);
+ return ret;
+ }
+
+ jpeg_irq = platform_get_irq(pdev, 0);
+ if (jpeg_irq < 0)
+ return jpeg_irq;
+
+ ret = devm_request_irq(&pdev->dev,
+ jpeg_irq,
+ jpeg->variant->irq_handler,
+ 0,
+ pdev->name, jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n",
+ jpeg_irq, ret);
+ return ret;
+ }
+
+ ret = devm_clk_bulk_get(jpeg->dev,
+ jpeg->variant->num_clks,
+ jpeg->variant->clks);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init clk\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int mtk_jpeg_probe(struct platform_device *pdev)
{
struct mtk_jpeg_dev *jpeg;
- int jpeg_irq;
+ struct device_node *child;
+ int num_child = 0;
int ret;
jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL);
@@ -1692,38 +1729,26 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (list_empty(&pdev->dev.devres_head)) {
- INIT_DELAYED_WORK(&jpeg->job_timeout_work,
- mtk_jpeg_job_timeout_work);
-
- jpeg->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(jpeg->reg_base)) {
- ret = PTR_ERR(jpeg->reg_base);
- return ret;
+ if (!jpeg->variant->multi_core) {
+ ret = mtk_jpeg_single_core_init(pdev, jpeg);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "mtk_jpeg_single_core_init failed.");
+ return -EINVAL;
}
+ } else {
+ init_waitqueue_head(&jpeg->hw_wq);
- jpeg_irq = platform_get_irq(pdev, 0);
- if (jpeg_irq < 0)
- return jpeg_irq;
+ for_each_child_of_node(pdev->dev.of_node, child)
+ num_child++;
- ret = devm_request_irq(&pdev->dev,
- jpeg_irq,
- jpeg->variant->irq_handler,
- 0,
- pdev->name, jpeg);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n",
- jpeg_irq, ret);
- return ret;
- }
+ atomic_set(&jpeg->hw_rdy, num_child);
+ atomic_set(&jpeg->hw_index, 0);
- ret = devm_clk_bulk_get(jpeg->dev,
- jpeg->variant->num_clks,
- jpeg->variant->clks);
- if (ret) {
- dev_err(&pdev->dev, "Failed to init clk\n");
- return ret;
- }
+ jpeg->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME,
+ WQ_MEM_RECLAIM
+ | WQ_FREEZABLE);
+ if (!jpeg->workqueue)
+ return -EINVAL;
}
ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
@@ -1757,7 +1782,7 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
jpeg->vdev->device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_M2M_MPLANE;
- if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ if (of_property_present(pdev->dev.of_node, "dma-ranges"))
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1);
@@ -1790,7 +1815,7 @@ err_m2m_init:
return ret;
}
-static int mtk_jpeg_remove(struct platform_device *pdev)
+static void mtk_jpeg_remove(struct platform_device *pdev)
{
struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
@@ -1798,8 +1823,6 @@ static int mtk_jpeg_remove(struct platform_device *pdev)
video_unregister_device(jpeg->vdev);
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);
-
- return 0;
}
static __maybe_unused int mtk_jpeg_pm_suspend(struct device *dev)
@@ -1846,6 +1869,7 @@ static const struct dev_pm_ops mtk_jpeg_pm_ops = {
SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL)
};
+#if defined(CONFIG_OF)
static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = {
.clks = mt8173_jpeg_dec_clocks,
.num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks),
@@ -1874,6 +1898,7 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = {
.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+ .multi_core = false,
};
static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
@@ -1885,6 +1910,8 @@ static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+ .multi_core = true,
+ .jpeg_worker = mtk_jpegenc_worker,
};
static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
@@ -1896,9 +1923,10 @@ static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+ .multi_core = true,
+ .jpeg_worker = mtk_jpegdec_worker,
};
-#if defined(CONFIG_OF)
static const struct of_device_id mtk_jpeg_match[] = {
{
.compatible = "mediatek,mt8173-jpgdec",
@@ -1928,7 +1956,7 @@ MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
static struct platform_driver mtk_jpeg_driver = {
.probe = mtk_jpeg_probe,
- .remove = mtk_jpeg_remove,
+ .remove_new = mtk_jpeg_remove,
.driver = {
.name = MTK_JPEG_NAME,
.of_match_table = of_match_ptr(mtk_jpeg_match),
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index b9126476be8f..8ba6e757e11a 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -60,6 +60,8 @@ enum mtk_jpeg_ctx_state {
* @ioctl_ops: the callback of jpeg v4l2_ioctl_ops
* @out_q_default_fourcc: output queue default fourcc
* @cap_q_default_fourcc: capture queue default fourcc
+ * @multi_core: mark jpeg hw is multi_core or not
+ * @jpeg_worker: jpeg dec or enc worker
*/
struct mtk_jpeg_variant {
struct clk_bulk_data *clks;
@@ -74,6 +76,8 @@ struct mtk_jpeg_variant {
const struct v4l2_ioctl_ops *ioctl_ops;
u32 out_q_default_fourcc;
u32 cap_q_default_fourcc;
+ bool multi_core;
+ void (*jpeg_worker)(struct work_struct *work);
};
struct mtk_jpeg_src_buf {
@@ -199,16 +203,12 @@ struct mtk_jpegdec_comp_dev {
* @job_timeout_work: IRQ timeout structure
* @variant: driver variant to be used
* @reg_encbase: jpg encode register base addr
- * @enc_hw_dev: jpg encode hardware device
- * @is_jpgenc_multihw: the flag of multi-hw core
- * @enc_hw_wq: jpg encode wait queue
- * @enchw_rdy: jpg encode hw ready flag
+ * @enc_hw_dev: jpg encode hardware device
+ * @hw_wq: jpg wait queue
+ * @hw_rdy: jpg hw ready flag
* @reg_decbase: jpg decode register base addr
- * @dec_hw_dev: jpg decode hardware device
- * @is_jpgdec_multihw: the flag of dec multi-hw core
- * @dec_hw_wq: jpg decode wait queue
- * @dec_workqueue: jpg decode work queue
- * @dechw_rdy: jpg decode hw ready flag
+ * @dec_hw_dev: jpg decode hardware device
+ * @hw_index: jpg hw index
*/
struct mtk_jpeg_dev {
struct mutex lock;
@@ -225,16 +225,12 @@ struct mtk_jpeg_dev {
void __iomem *reg_encbase[MTK_JPEGENC_HW_MAX];
struct mtk_jpegenc_comp_dev *enc_hw_dev[MTK_JPEGENC_HW_MAX];
- bool is_jpgenc_multihw;
- wait_queue_head_t enc_hw_wq;
- atomic_t enchw_rdy;
+ wait_queue_head_t hw_wq;
+ atomic_t hw_rdy;
void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX];
struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX];
- bool is_jpgdec_multihw;
- wait_queue_head_t dec_hw_wq;
- struct workqueue_struct *dec_workqueue;
- atomic_t dechw_rdy;
+ atomic_t hw_index;
};
/**
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index 8c07fa02fd9a..869068fac5e2 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -503,8 +503,8 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
clk_disable_unprepare(cjpeg->jdec_clk.clks->clk);
pm_runtime_put(cjpeg->dev);
cjpeg->hw_state = MTK_JPEG_HW_IDLE;
- atomic_inc(&master_jpeg->dechw_rdy);
- wake_up(&master_jpeg->dec_hw_wq);
+ atomic_inc(&master_jpeg->hw_rdy);
+ wake_up(&master_jpeg->hw_wq);
v4l2_m2m_buf_done(src_buf, buf_state);
mtk_jpegdec_put_buf(cjpeg);
}
@@ -551,8 +551,8 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
jpeg->hw_state = MTK_JPEG_HW_IDLE;
- wake_up(&master_jpeg->dec_hw_wq);
- atomic_inc(&master_jpeg->dechw_rdy);
+ wake_up(&master_jpeg->hw_wq);
+ atomic_inc(&master_jpeg->hw_rdy);
return IRQ_HANDLED;
}
@@ -608,25 +608,12 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
dev->plat_dev = pdev;
dev->dev = &pdev->dev;
- if (!master_dev->is_jpgdec_multihw) {
- master_dev->is_jpgdec_multihw = true;
- for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
- master_dev->dec_hw_dev[i] = NULL;
-
- init_waitqueue_head(&master_dev->dec_hw_wq);
- master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME,
- WQ_MEM_RECLAIM
- | WQ_FREEZABLE);
- if (!master_dev->workqueue)
- return -EINVAL;
-
- ret = devm_add_action_or_reset(&pdev->dev, mtk_jpegdec_destroy_workqueue,
- master_dev->workqueue);
- if (ret)
- return ret;
- }
+ ret = devm_add_action_or_reset(&pdev->dev,
+ mtk_jpegdec_destroy_workqueue,
+ master_dev->workqueue);
+ if (ret)
+ return ret;
- atomic_set(&master_dev->dechw_rdy, MTK_JPEGDEC_HW_MAX);
spin_lock_init(&dev->hw_lock);
dev->hw_state = MTK_JPEG_HW_IDLE;
@@ -651,14 +638,10 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"Failed to register JPEGDEC irq handler.\n");
- for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
- if (master_dev->dec_hw_dev[i])
- continue;
-
- master_dev->dec_hw_dev[i] = dev;
- master_dev->reg_decbase[i] = dev->reg_base;
- dev->master_dev = master_dev;
- }
+ i = atomic_add_return(1, &master_dev->hw_index) - 1;
+ master_dev->dec_hw_dev[i] = dev;
+ master_dev->reg_decbase[i] = dev->reg_base;
+ dev->master_dev = master_dev;
platform_set_drvdata(pdev, dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 1bbb712d78d0..71e85b4bbf12 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -248,8 +248,8 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
clk_disable_unprepare(cjpeg->venc_clk.clks->clk);
pm_runtime_put(cjpeg->dev);
cjpeg->hw_state = MTK_JPEG_HW_IDLE;
- atomic_inc(&master_jpeg->enchw_rdy);
- wake_up(&master_jpeg->enc_hw_wq);
+ atomic_inc(&master_jpeg->hw_rdy);
+ wake_up(&master_jpeg->hw_wq);
v4l2_m2m_buf_done(src_buf, buf_state);
mtk_jpegenc_put_buf(cjpeg);
}
@@ -286,14 +286,10 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
mtk_jpegenc_put_buf(jpeg);
pm_runtime_put(ctx->jpeg->dev);
clk_disable_unprepare(jpeg->venc_clk.clks->clk);
- if (!list_empty(&ctx->fh.m2m_ctx->out_q_ctx.rdy_queue) ||
- !list_empty(&ctx->fh.m2m_ctx->cap_q_ctx.rdy_queue)) {
- queue_work(master_jpeg->workqueue, &ctx->jpeg_work);
- }
jpeg->hw_state = MTK_JPEG_HW_IDLE;
- wake_up(&master_jpeg->enc_hw_wq);
- atomic_inc(&master_jpeg->enchw_rdy);
+ wake_up(&master_jpeg->hw_wq);
+ atomic_inc(&master_jpeg->hw_rdy);
return IRQ_HANDLED;
}
@@ -344,20 +340,6 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
dev->plat_dev = pdev;
dev->dev = &pdev->dev;
- if (!master_dev->is_jpgenc_multihw) {
- master_dev->is_jpgenc_multihw = true;
- for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
- master_dev->enc_hw_dev[i] = NULL;
-
- init_waitqueue_head(&master_dev->enc_hw_wq);
- master_dev->workqueue = alloc_ordered_workqueue(MTK_JPEG_NAME,
- WQ_MEM_RECLAIM
- | WQ_FREEZABLE);
- if (!master_dev->workqueue)
- return -EINVAL;
- }
-
- atomic_set(&master_dev->enchw_rdy, MTK_JPEGENC_HW_MAX);
spin_lock_init(&dev->hw_lock);
dev->hw_state = MTK_JPEG_HW_IDLE;
@@ -380,14 +362,10 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
if (ret)
return ret;
- for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
- if (master_dev->enc_hw_dev[i])
- continue;
-
- master_dev->enc_hw_dev[i] = dev;
- master_dev->reg_encbase[i] = dev->reg_base;
- dev->master_dev = master_dev;
- }
+ i = atomic_add_return(1, &master_dev->hw_index) - 1;
+ master_dev->enc_hw_dev[i] = dev;
+ master_dev->reg_encbase[i] = dev->reg_base;
+ dev->master_dev = master_dev;
platform_set_drvdata(pdev, dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
index d83c4964eaf9..77e310e588e5 100644
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
@@ -235,7 +235,7 @@ err_comp:
return ret;
}
-static int mtk_mdp_remove(struct platform_device *pdev)
+static void mtk_mdp_remove(struct platform_device *pdev)
{
struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev);
struct mtk_mdp_comp *comp, *comp_temp;
@@ -255,7 +255,6 @@ static int mtk_mdp_remove(struct platform_device *pdev)
}
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
- return 0;
}
static int __maybe_unused mtk_mdp_pm_suspend(struct device *dev)
@@ -299,7 +298,7 @@ static const struct dev_pm_ops mtk_mdp_pm_ops = {
static struct platform_driver mtk_mdp_driver = {
.probe = mtk_mdp_probe,
- .remove = mtk_mdp_remove,
+ .remove_new = mtk_mdp_remove,
.driver = {
.name = MTK_MDP_MODULE_NAME,
.pm = &mtk_mdp_pm_ops,
diff --git a/drivers/media/platform/mediatek/mdp3/Makefile b/drivers/media/platform/mediatek/mdp3/Makefile
index 63e6c87e480b..2ee24195a2dd 100644
--- a/drivers/media/platform/mediatek/mdp3/Makefile
+++ b/drivers/media/platform/mediatek/mdp3/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-mtk-mdp3-y += mtk-mdp3-core.o mtk-mdp3-vpu.o mtk-mdp3-regs.o
+mtk-mdp3-y += mdp_cfg_data.o mtk-mdp3-core.o mtk-mdp3-vpu.o mtk-mdp3-regs.o
mtk-mdp3-y += mtk-mdp3-m2m.o
mtk-mdp3-y += mtk-mdp3-comp.o mtk-mdp3-cmdq.o
diff --git a/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c
new file mode 100644
index 000000000000..502eeae0bfdc
--- /dev/null
+++ b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include "mtk-img-ipi.h"
+#include "mtk-mdp3-cfg.h"
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-comp.h"
+#include "mtk-mdp3-regs.h"
+
+enum mt8183_mdp_comp_id {
+ /* ISP */
+ MT8183_MDP_COMP_WPEI = 0,
+ MT8183_MDP_COMP_WPEO, /* 1 */
+ MT8183_MDP_COMP_WPEI2, /* 2 */
+ MT8183_MDP_COMP_WPEO2, /* 3 */
+ MT8183_MDP_COMP_ISP_IMGI, /* 4 */
+ MT8183_MDP_COMP_ISP_IMGO, /* 5 */
+ MT8183_MDP_COMP_ISP_IMG2O, /* 6 */
+
+ /* IPU */
+ MT8183_MDP_COMP_IPUI, /* 7 */
+ MT8183_MDP_COMP_IPUO, /* 8 */
+
+ /* MDP */
+ MT8183_MDP_COMP_CAMIN, /* 9 */
+ MT8183_MDP_COMP_CAMIN2, /* 10 */
+ MT8183_MDP_COMP_RDMA0, /* 11 */
+ MT8183_MDP_COMP_AAL0, /* 12 */
+ MT8183_MDP_COMP_CCORR0, /* 13 */
+ MT8183_MDP_COMP_RSZ0, /* 14 */
+ MT8183_MDP_COMP_RSZ1, /* 15 */
+ MT8183_MDP_COMP_TDSHP0, /* 16 */
+ MT8183_MDP_COMP_COLOR0, /* 17 */
+ MT8183_MDP_COMP_PATH0_SOUT, /* 18 */
+ MT8183_MDP_COMP_PATH1_SOUT, /* 19 */
+ MT8183_MDP_COMP_WROT0, /* 20 */
+ MT8183_MDP_COMP_WDMA, /* 21 */
+
+ /* Dummy Engine */
+ MT8183_MDP_COMP_RDMA1, /* 22 */
+ MT8183_MDP_COMP_RSZ2, /* 23 */
+ MT8183_MDP_COMP_TDSHP1, /* 24 */
+ MT8183_MDP_COMP_WROT1, /* 25 */
+};
+
+static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = {
+ [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" },
+ [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" },
+ [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" }
+};
+
+static const struct mdp_platform_config mt8183_plat_cfg = {
+ .rdma_support_10bit = true,
+ .rdma_rsz1_sram_sharing = true,
+ .rdma_upsample_repeat_only = true,
+ .rsz_disable_dcm_small_sample = false,
+ .wrot_filter_constraint = false,
+};
+
+static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = {
+ [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0,
+ [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0,
+ [MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1,
+ [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0,
+ [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0,
+ [MDP_COMP_WDMA] = MUTEX_MOD_IDX_MDP_WDMA,
+ [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0,
+ [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0,
+};
+
+static const struct mdp_comp_data mt8183_mdp_comp_data[MDP_MAX_COMP_COUNT] = {
+ [MDP_COMP_WPEI] = {
+ {MDP_COMP_TYPE_WPEI, 0, MT8183_MDP_COMP_WPEI},
+ {0, 0, 0}
+ },
+ [MDP_COMP_WPEO] = {
+ {MDP_COMP_TYPE_EXTO, 2, MT8183_MDP_COMP_WPEO},
+ {0, 0, 0}
+ },
+ [MDP_COMP_WPEI2] = {
+ {MDP_COMP_TYPE_WPEI, 1, MT8183_MDP_COMP_WPEI2},
+ {0, 0, 0}
+ },
+ [MDP_COMP_WPEO2] = {
+ {MDP_COMP_TYPE_EXTO, 3, MT8183_MDP_COMP_WPEO2},
+ {0, 0, 0}
+ },
+ [MDP_COMP_ISP_IMGI] = {
+ {MDP_COMP_TYPE_IMGI, 0, MT8183_MDP_COMP_ISP_IMGI},
+ {0, 0, 4}
+ },
+ [MDP_COMP_ISP_IMGO] = {
+ {MDP_COMP_TYPE_EXTO, 0, MT8183_MDP_COMP_ISP_IMGO},
+ {0, 0, 4}
+ },
+ [MDP_COMP_ISP_IMG2O] = {
+ {MDP_COMP_TYPE_EXTO, 1, MT8183_MDP_COMP_ISP_IMG2O},
+ {0, 0, 0}
+ },
+ [MDP_COMP_CAMIN] = {
+ {MDP_COMP_TYPE_DL_PATH, 0, MT8183_MDP_COMP_CAMIN},
+ {2, 2, 1}
+ },
+ [MDP_COMP_CAMIN2] = {
+ {MDP_COMP_TYPE_DL_PATH, 1, MT8183_MDP_COMP_CAMIN2},
+ {2, 4, 1}
+ },
+ [MDP_COMP_RDMA0] = {
+ {MDP_COMP_TYPE_RDMA, 0, MT8183_MDP_COMP_RDMA0},
+ {2, 0, 0}
+ },
+ [MDP_COMP_CCORR0] = {
+ {MDP_COMP_TYPE_CCORR, 0, MT8183_MDP_COMP_CCORR0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_RSZ0] = {
+ {MDP_COMP_TYPE_RSZ, 0, MT8183_MDP_COMP_RSZ0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_RSZ1] = {
+ {MDP_COMP_TYPE_RSZ, 1, MT8183_MDP_COMP_RSZ1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_TDSHP0] = {
+ {MDP_COMP_TYPE_TDSHP, 0, MT8183_MDP_COMP_TDSHP0},
+ {0, 0, 0}
+ },
+ [MDP_COMP_PATH0_SOUT] = {
+ {MDP_COMP_TYPE_PATH, 0, MT8183_MDP_COMP_PATH0_SOUT},
+ {0, 0, 0}
+ },
+ [MDP_COMP_PATH1_SOUT] = {
+ {MDP_COMP_TYPE_PATH, 1, MT8183_MDP_COMP_PATH1_SOUT},
+ {0, 0, 0}
+ },
+ [MDP_COMP_WROT0] = {
+ {MDP_COMP_TYPE_WROT, 0, MT8183_MDP_COMP_WROT0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_WDMA] = {
+ {MDP_COMP_TYPE_WDMA, 0, MT8183_MDP_COMP_WDMA},
+ {1, 0, 0}
+ },
+};
+
+static const struct of_device_id mt8183_sub_comp_dt_ids[] = {
+ {
+ .compatible = "mediatek,mt8183-mdp3-wdma",
+ .data = (void *)MDP_COMP_TYPE_PATH,
+ }, {
+ .compatible = "mediatek,mt8183-mdp3-wrot",
+ .data = (void *)MDP_COMP_TYPE_PATH,
+ },
+ {}
+};
+
+/*
+ * All 10-bit related formats are not added in the basic format list,
+ * please add the corresponding format settings before use.
+ */
+static const struct mdp_format mt8183_formats[] = {
+ {
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .mdp_color = MDP_COLOR_GREY,
+ .depth = { 8 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ .mdp_color = MDP_COLOR_BGR565,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mdp_color = MDP_COLOR_RGB565,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ .mdp_color = MDP_COLOR_RGB888,
+ .depth = { 24 },
+ .row_depth = { 24 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_BGR24,
+ .mdp_color = MDP_COLOR_BGR888,
+ .depth = { 24 },
+ .row_depth = { 24 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_ABGR32,
+ .mdp_color = MDP_COLOR_BGRA8888,
+ .depth = { 32 },
+ .row_depth = { 32 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_ARGB32,
+ .mdp_color = MDP_COLOR_ARGB8888,
+ .depth = { 32 },
+ .row_depth = { 32 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mdp_color = MDP_COLOR_UYVY,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .mdp_color = MDP_COLOR_VYUY,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mdp_color = MDP_COLOR_YUYV,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .mdp_color = MDP_COLOR_YVYU,
+ .depth = { 16 },
+ .row_depth = { 16 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .mdp_color = MDP_COLOR_I420,
+ .depth = { 12 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .mdp_color = MDP_COLOR_YV12,
+ .depth = { 12 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .mdp_color = MDP_COLOR_NV12,
+ .depth = { 12 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .mdp_color = MDP_COLOR_NV21,
+ .depth = { 12 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV16,
+ .mdp_color = MDP_COLOR_NV16,
+ .depth = { 16 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV61,
+ .mdp_color = MDP_COLOR_NV61,
+ .depth = { 16 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV24,
+ .mdp_color = MDP_COLOR_NV24,
+ .depth = { 24 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV42,
+ .mdp_color = MDP_COLOR_NV42,
+ .depth = { 24 },
+ .row_depth = { 8 },
+ .num_planes = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_MT21C,
+ .mdp_color = MDP_COLOR_420_BLK_UFO,
+ .depth = { 8, 4 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 4,
+ .halign = 5,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_MM21,
+ .mdp_color = MDP_COLOR_420_BLK,
+ .depth = { 8, 4 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 4,
+ .halign = 5,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .mdp_color = MDP_COLOR_NV12,
+ .depth = { 8, 4 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV21M,
+ .mdp_color = MDP_COLOR_NV21,
+ .depth = { 8, 4 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV16M,
+ .mdp_color = MDP_COLOR_NV16,
+ .depth = { 8, 8 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_NV61M,
+ .mdp_color = MDP_COLOR_NV61,
+ .depth = { 8, 8 },
+ .row_depth = { 8, 8 },
+ .num_planes = 2,
+ .walign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .mdp_color = MDP_COLOR_I420,
+ .depth = { 8, 2, 2 },
+ .row_depth = { 8, 4, 4 },
+ .num_planes = 3,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }, {
+ .pixelformat = V4L2_PIX_FMT_YVU420M,
+ .mdp_color = MDP_COLOR_YV12,
+ .depth = { 8, 2, 2 },
+ .row_depth = { 8, 4, 4 },
+ .num_planes = 3,
+ .walign = 1,
+ .halign = 1,
+ .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+ }
+};
+
+static const struct mdp_limit mt8183_mdp_def_limit = {
+ .out_limit = {
+ .wmin = 16,
+ .hmin = 16,
+ .wmax = 8176,
+ .hmax = 8176,
+ },
+ .cap_limit = {
+ .wmin = 2,
+ .hmin = 2,
+ .wmax = 8176,
+ .hmax = 8176,
+ },
+ .h_scale_up_max = 32,
+ .v_scale_up_max = 32,
+ .h_scale_down_max = 20,
+ .v_scale_down_max = 128,
+};
+
+static const struct mdp_pipe_info mt8183_pipe_info[] = {
+ [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, 0},
+ [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, 1},
+ [MDP_PIPE_IMGI] = {MDP_PIPE_IMGI, 2},
+ [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, 3}
+};
+
+const struct mtk_mdp_driver_data mt8183_mdp_driver_data = {
+ .mdp_plat_id = MT8183,
+ .mdp_probe_infra = mt8183_mdp_probe_infra,
+ .mdp_cfg = &mt8183_plat_cfg,
+ .mdp_mutex_table_idx = mt8183_mutex_idx,
+ .comp_data = mt8183_mdp_comp_data,
+ .comp_data_len = ARRAY_SIZE(mt8183_mdp_comp_data),
+ .mdp_sub_comp_dt_ids = mt8183_sub_comp_dt_ids,
+ .format = mt8183_formats,
+ .format_len = ARRAY_SIZE(mt8183_formats),
+ .def_limit = &mt8183_mdp_def_limit,
+ .pipe_info = mt8183_pipe_info,
+ .pipe_info_len = ARRAY_SIZE(mt8183_pipe_info),
+};
+
+s32 mdp_cfg_get_id_inner(struct mdp_dev *mdp_dev, enum mtk_mdp_comp_id id)
+{
+ if (!mdp_dev)
+ return MDP_COMP_NONE;
+ if (id <= MDP_COMP_NONE || id >= MDP_MAX_COMP_COUNT)
+ return MDP_COMP_NONE;
+
+ return mdp_dev->mdp_data->comp_data[id].match.inner_id;
+}
+
+enum mtk_mdp_comp_id mdp_cfg_get_id_public(struct mdp_dev *mdp_dev, s32 inner_id)
+{
+ enum mtk_mdp_comp_id public_id = MDP_COMP_NONE;
+ u32 i;
+
+ if (IS_ERR(mdp_dev) || !inner_id)
+ goto err_public_id;
+
+ for (i = 0; i < MDP_MAX_COMP_COUNT; i++) {
+ if (mdp_dev->mdp_data->comp_data[i].match.inner_id == inner_id) {
+ public_id = i;
+ return public_id;
+ }
+ }
+
+err_public_id:
+ return public_id;
+}
diff --git a/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8183.h b/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8183.h
new file mode 100644
index 000000000000..85637084520f
--- /dev/null
+++ b/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8183.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_SM_MT8183_H__
+#define __MDP_SM_MT8183_H__
+
+#include "mtk-mdp3-type.h"
+
+/*
+ * ISP-MDP generic output information
+ * MD5 of the target SCP prebuild:
+ * 2d995ddb5c3b0cf26e96d6a823481886
+ */
+
+#define IMG_MAX_SUBFRAMES_8183 14
+
+struct img_comp_frame_8183 {
+ u32 output_disable:1;
+ u32 bypass:1;
+ u16 in_width;
+ u16 in_height;
+ u16 out_width;
+ u16 out_height;
+ struct img_crop crop;
+ u16 in_total_width;
+ u16 out_total_width;
+} __packed;
+
+struct img_comp_subfrm_8183 {
+ u32 tile_disable:1;
+ struct img_region in;
+ struct img_region out;
+ struct img_offset luma;
+ struct img_offset chroma;
+ s16 out_vertical; /* Output vertical index */
+ s16 out_horizontal; /* Output horizontal index */
+} __packed;
+
+struct mdp_rdma_subfrm_8183 {
+ u32 offset[IMG_MAX_PLANES];
+ u32 offset_0_p;
+ u32 src;
+ u32 clip;
+ u32 clip_ofst;
+} __packed;
+
+struct mdp_rdma_data_8183 {
+ u32 src_ctrl;
+ u32 control;
+ u32 iova[IMG_MAX_PLANES];
+ u32 iova_end[IMG_MAX_PLANES];
+ u32 mf_bkgd;
+ u32 mf_bkgd_in_pxl;
+ u32 sf_bkgd;
+ u32 ufo_dec_y;
+ u32 ufo_dec_c;
+ u32 transform;
+ struct mdp_rdma_subfrm_8183 subfrms[IMG_MAX_SUBFRAMES_8183];
+} __packed;
+
+struct mdp_rsz_subfrm_8183 {
+ u32 control2;
+ u32 src;
+ u32 clip;
+} __packed;
+
+struct mdp_rsz_data_8183 {
+ u32 coeff_step_x;
+ u32 coeff_step_y;
+ u32 control1;
+ u32 control2;
+ struct mdp_rsz_subfrm_8183 subfrms[IMG_MAX_SUBFRAMES_8183];
+} __packed;
+
+struct mdp_wrot_subfrm_8183 {
+ u32 offset[IMG_MAX_PLANES];
+ u32 src;
+ u32 clip;
+ u32 clip_ofst;
+ u32 main_buf;
+} __packed;
+
+struct mdp_wrot_data_8183 {
+ u32 iova[IMG_MAX_PLANES];
+ u32 control;
+ u32 stride[IMG_MAX_PLANES];
+ u32 mat_ctrl;
+ u32 fifo_test;
+ u32 filter;
+ struct mdp_wrot_subfrm_8183 subfrms[IMG_MAX_SUBFRAMES_8183];
+} __packed;
+
+struct mdp_wdma_subfrm_8183 {
+ u32 offset[IMG_MAX_PLANES];
+ u32 src;
+ u32 clip;
+ u32 clip_ofst;
+} __packed;
+
+struct mdp_wdma_data_8183 {
+ u32 wdma_cfg;
+ u32 iova[IMG_MAX_PLANES];
+ u32 w_in_byte;
+ u32 uv_stride;
+ struct mdp_wdma_subfrm_8183 subfrms[IMG_MAX_SUBFRAMES_8183];
+} __packed;
+
+struct isp_data_8183 {
+ u64 dl_flags; /* 1 << (enum mdp_comp_type) */
+ u32 smxi_iova[4];
+ u32 cq_idx;
+ u32 cq_iova;
+ u32 tpipe_iova[IMG_MAX_SUBFRAMES_8183];
+} __packed;
+
+struct img_compparam_8183 {
+ u16 type; /* enum mdp_comp_id */
+ u16 id; /* engine alias_id */
+ u32 input;
+ u32 outputs[IMG_MAX_HW_OUTPUTS];
+ u32 num_outputs;
+ struct img_comp_frame_8183 frame;
+ struct img_comp_subfrm_8183 subfrms[IMG_MAX_SUBFRAMES_8183];
+ u32 num_subfrms;
+ union {
+ struct mdp_rdma_data_8183 rdma;
+ struct mdp_rsz_data_8183 rsz;
+ struct mdp_wrot_data_8183 wrot;
+ struct mdp_wdma_data_8183 wdma;
+ struct isp_data_8183 isp;
+ };
+} __packed;
+
+struct img_config_8183 {
+ struct img_compparam_8183 components[IMG_MAX_COMPONENTS];
+ u32 num_components;
+ struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES_8183];
+ u32 num_subfrms;
+} __packed;
+
+#endif /* __MDP_SM_MT8183_H__ */
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
index c7f231f8ea3e..22b8b9a10ef7 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
@@ -8,19 +8,11 @@
#ifndef __MTK_IMG_IPI_H__
#define __MTK_IMG_IPI_H__
-#include <linux/types.h>
+#include <linux/err.h>
+#include "mdp_sm_mt8183.h"
+#include "mtk-mdp3-type.h"
-/*
- * ISP-MDP generic input information
- * MD5 of the target SCP blob:
- * 6da52bdcf4bf76a0983b313e1d4745d6
- */
-
-#define IMG_MAX_HW_INPUTS 3
-
-#define IMG_MAX_HW_OUTPUTS 4
-
-#define IMG_MAX_PLANES 3
+/* ISP-MDP generic input information */
#define IMG_IPI_INIT 1
#define IMG_IPI_DEINIT 2
@@ -71,17 +63,6 @@ struct img_image_buffer {
#define IMG_SUBPIXEL_SHIFT 20
-struct img_crop {
- s32 left;
- s32 top;
- u32 width;
- u32 height;
- u32 left_subpix;
- u32 top_subpix;
- u32 width_subpix;
- u32 height_subpix;
-} __packed;
-
#define IMG_CTRL_FLAG_HFLIP BIT(0)
#define IMG_CTRL_FLAG_DITHER BIT(1)
#define IMG_CTRL_FLAG_SHARPNESS BIT(4)
@@ -132,159 +113,37 @@ struct img_frameparam {
struct img_ipi_frameparam frameparam;
} __packed;
-/* ISP-MDP generic output information */
+/* Platform config indicator */
+#define MT8183 8183
-struct img_comp_frame {
- u32 output_disable;
- u32 bypass;
- u32 in_width;
- u32 in_height;
- u32 out_width;
- u32 out_height;
- struct img_crop crop;
- u32 in_total_width;
- u32 out_total_width;
-} __packed;
+#define CFG_CHECK(plat, p_id) ((plat) == (p_id))
-struct img_region {
- s32 left;
- s32 right;
- s32 top;
- s32 bottom;
-} __packed;
+#define _CFG_OFST(plat, cfg, ofst) ((void *)(&((cfg)->config_##plat) + (ofst)))
+#define CFG_OFST(plat, cfg, ofst) \
+ (IS_ERR_OR_NULL(cfg) ? NULL : _CFG_OFST(plat, cfg, ofst))
-struct img_offset {
- s32 left;
- s32 top;
- u32 left_subpix;
- u32 top_subpix;
-} __packed;
-
-struct img_comp_subfrm {
- u32 tile_disable;
- struct img_region in;
- struct img_region out;
- struct img_offset luma;
- struct img_offset chroma;
- s32 out_vertical; /* Output vertical index */
- s32 out_horizontal; /* Output horizontal index */
-} __packed;
+#define _CFG_ADDR(plat, cfg, mem) (&((cfg)->config_##plat.mem))
+#define CFG_ADDR(plat, cfg, mem) \
+ (IS_ERR_OR_NULL(cfg) ? NULL : _CFG_ADDR(plat, cfg, mem))
-#define IMG_MAX_SUBFRAMES 14
+#define _CFG_GET(plat, cfg, mem) ((cfg)->config_##plat.mem)
+#define CFG_GET(plat, cfg, mem) \
+ (IS_ERR_OR_NULL(cfg) ? 0 : _CFG_GET(plat, cfg, mem))
-struct mdp_rdma_subfrm {
- u32 offset[IMG_MAX_PLANES];
- u32 offset_0_p;
- u32 src;
- u32 clip;
- u32 clip_ofst;
-} __packed;
-
-struct mdp_rdma_data {
- u32 src_ctrl;
- u32 control;
- u32 iova[IMG_MAX_PLANES];
- u32 iova_end[IMG_MAX_PLANES];
- u32 mf_bkgd;
- u32 mf_bkgd_in_pxl;
- u32 sf_bkgd;
- u32 ufo_dec_y;
- u32 ufo_dec_c;
- u32 transform;
- struct mdp_rdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
-} __packed;
-
-struct mdp_rsz_subfrm {
- u32 control2;
- u32 src;
- u32 clip;
-} __packed;
-
-struct mdp_rsz_data {
- u32 coeff_step_x;
- u32 coeff_step_y;
- u32 control1;
- u32 control2;
- struct mdp_rsz_subfrm subfrms[IMG_MAX_SUBFRAMES];
-} __packed;
+#define _CFG_COMP(plat, comp, mem) ((comp)->comp_##plat.mem)
+#define CFG_COMP(plat, comp, mem) \
+ (IS_ERR_OR_NULL(comp) ? 0 : _CFG_COMP(plat, comp, mem))
-struct mdp_wrot_subfrm {
- u32 offset[IMG_MAX_PLANES];
- u32 src;
- u32 clip;
- u32 clip_ofst;
- u32 main_buf;
-} __packed;
-
-struct mdp_wrot_data {
- u32 iova[IMG_MAX_PLANES];
- u32 control;
- u32 stride[IMG_MAX_PLANES];
- u32 mat_ctrl;
- u32 fifo_test;
- u32 filter;
- struct mdp_wrot_subfrm subfrms[IMG_MAX_SUBFRAMES];
-} __packed;
-
-struct mdp_wdma_subfrm {
- u32 offset[IMG_MAX_PLANES];
- u32 src;
- u32 clip;
- u32 clip_ofst;
-} __packed;
-
-struct mdp_wdma_data {
- u32 wdma_cfg;
- u32 iova[IMG_MAX_PLANES];
- u32 w_in_byte;
- u32 uv_stride;
- struct mdp_wdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
-} __packed;
-
-struct isp_data {
- u64 dl_flags; /* 1 << (enum mdp_comp_type) */
- u32 smxi_iova[4];
- u32 cq_idx;
- u32 cq_iova;
- u32 tpipe_iova[IMG_MAX_SUBFRAMES];
+struct img_config {
+ union {
+ struct img_config_8183 config_8183;
+ };
} __packed;
struct img_compparam {
- u32 type; /* enum mdp_comp_id */
- u32 id; /* engine alias_id */
- u32 input;
- u32 outputs[IMG_MAX_HW_OUTPUTS];
- u32 num_outputs;
- struct img_comp_frame frame;
- struct img_comp_subfrm subfrms[IMG_MAX_SUBFRAMES];
- u32 num_subfrms;
union {
- struct mdp_rdma_data rdma;
- struct mdp_rsz_data rsz;
- struct mdp_wrot_data wrot;
- struct mdp_wdma_data wdma;
- struct isp_data isp;
+ struct img_compparam_8183 comp_8183;
};
} __packed;
-#define IMG_MAX_COMPONENTS 20
-
-struct img_mux {
- u32 reg;
- u32 value;
- u32 subsys_id;
-} __packed;
-
-struct img_mmsys_ctrl {
- struct img_mux sets[IMG_MAX_COMPONENTS * 2];
- u32 num_sets;
-} __packed;
-
-struct img_config {
- struct img_compparam components[IMG_MAX_COMPONENTS];
- u32 num_components;
- struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES];
- u32 num_subfrms;
-} __packed;
-
#endif /* __MTK_IMG_IPI_H__ */
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h
new file mode 100644
index 000000000000..dee57cc4a954
--- /dev/null
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_CFG_H__
+#define __MTK_MDP3_CFG_H__
+
+#include <linux/types.h>
+
+extern const struct mtk_mdp_driver_data mt8183_mdp_driver_data;
+
+struct mdp_dev;
+enum mtk_mdp_comp_id;
+
+s32 mdp_cfg_get_id_inner(struct mdp_dev *mdp_dev, enum mtk_mdp_comp_id id);
+enum mtk_mdp_comp_id mdp_cfg_get_id_public(struct mdp_dev *mdp_dev, s32 id);
+
+#endif /* __MTK_MDP3_CFG_H__ */
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
index 124c1b96e96b..3177592490be 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
@@ -10,6 +10,7 @@
#include "mtk-mdp3-comp.h"
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-m2m.h"
+#include "mtk-img-ipi.h"
#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS
@@ -28,50 +29,62 @@ struct mdp_path {
#define call_op(ctx, op, ...) \
(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
-static bool is_output_disabled(const struct img_compparam *param, u32 count)
+static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count)
{
- return (count < param->num_subfrms) ?
- (param->frame.output_disable ||
- param->subfrms[count].tile_disable) :
- true;
+ u32 num = 0;
+ bool dis_output = false;
+ bool dis_tile = false;
+
+ if (CFG_CHECK(MT8183, p_id)) {
+ num = CFG_COMP(MT8183, param, num_subfrms);
+ dis_output = CFG_COMP(MT8183, param, frame.output_disable);
+ dis_tile = CFG_COMP(MT8183, param, frame.output_disable);
+ }
+
+ return (count < num) ? (dis_output || dis_tile) : true;
}
static int mdp_path_subfrm_require(const struct mdp_path *path,
struct mdp_cmdq_cmd *cmd,
s32 *mutex_id, u32 count)
{
- const struct img_config *config = path->config;
+ const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
const struct mdp_comp_ctx *ctx;
const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
struct device *dev = &path->mdp_dev->pdev->dev;
struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
int id, index;
+ u32 num_comp = 0;
+
+ if (CFG_CHECK(MT8183, p_id))
+ num_comp = CFG_GET(MT8183, path->config, num_components);
/* Decide which mutex to use based on the current pipeline */
- switch (path->comps[0].comp->id) {
+ switch (path->comps[0].comp->public_id) {
case MDP_COMP_RDMA0:
- *mutex_id = MDP_PIPE_RDMA0;
+ index = MDP_PIPE_RDMA0;
break;
case MDP_COMP_ISP_IMGI:
- *mutex_id = MDP_PIPE_IMGI;
+ index = MDP_PIPE_IMGI;
break;
case MDP_COMP_WPEI:
- *mutex_id = MDP_PIPE_WPEI;
+ index = MDP_PIPE_WPEI;
break;
case MDP_COMP_WPEI2:
- *mutex_id = MDP_PIPE_WPEI2;
+ index = MDP_PIPE_WPEI2;
break;
default:
dev_err(dev, "Unknown pipeline and no mutex is assigned");
return -EINVAL;
}
+ *mutex_id = data->pipe_info[index].mutex_id;
/* Set mutex mod */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
- if (is_output_disabled(ctx->param, count))
+ if (is_output_disabled(p_id, ctx->param, count))
continue;
- id = ctx->comp->id;
+ id = ctx->comp->public_id;
mtk_mutex_write_mod(mutex[*mutex_id],
data->mdp_mutex_table_idx[id], false);
}
@@ -86,11 +99,12 @@ static int mdp_path_subfrm_run(const struct mdp_path *path,
struct mdp_cmdq_cmd *cmd,
s32 *mutex_id, u32 count)
{
- const struct img_config *config = path->config;
+ const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
const struct mdp_comp_ctx *ctx;
struct device *dev = &path->mdp_dev->pdev->dev;
struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
int index;
+ u32 num_comp = 0;
s32 event;
if (-1 == *mutex_id) {
@@ -98,11 +112,14 @@ static int mdp_path_subfrm_run(const struct mdp_path *path,
return -EINVAL;
}
+ if (CFG_CHECK(MT8183, p_id))
+ num_comp = CFG_GET(MT8183, path->config, num_components);
+
/* Wait WROT SRAM shared to DISP RDMA */
/* Clear SOF event for each engine */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
- if (is_output_disabled(ctx->param, count))
+ if (is_output_disabled(p_id, ctx->param, count))
continue;
event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
if (event != MDP_GCE_NO_EVENT)
@@ -113,9 +130,9 @@ static int mdp_path_subfrm_run(const struct mdp_path *path,
mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt);
/* Wait SOF events and clear mutex modules (optional) */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
- if (is_output_disabled(ctx->param, count))
+ if (is_output_disabled(p_id, ctx->param, count))
continue;
event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
if (event != MDP_GCE_NO_EVENT)
@@ -127,16 +144,22 @@ static int mdp_path_subfrm_run(const struct mdp_path *path,
static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
{
- const struct img_config *config = path->config;
+ const int p_id = mdp->mdp_data->mdp_plat_id;
+ void *param = NULL;
int index, ret;
+ u32 num_comp = 0;
- if (config->num_components < 1)
+ if (CFG_CHECK(MT8183, p_id))
+ num_comp = CFG_GET(MT8183, path->config, num_components);
+
+ if (num_comp < 1)
return -EINVAL;
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
+ if (CFG_CHECK(MT8183, p_id))
+ param = (void *)CFG_ADDR(MT8183, path->config, components[index]);
ret = mdp_comp_ctx_config(mdp, &path->comps[index],
- &config->components[index],
- path->param);
+ param, path->param);
if (ret)
return ret;
}
@@ -147,12 +170,19 @@ static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
struct mdp_path *path, u32 count)
{
- const struct img_config *config = path->config;
- const struct img_mmsys_ctrl *ctrl = &config->ctrls[count];
+ const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
+ const struct img_mmsys_ctrl *ctrl = NULL;
const struct img_mux *set;
struct mdp_comp_ctx *ctx;
s32 mutex_id;
int index, ret;
+ u32 num_comp = 0;
+
+ if (CFG_CHECK(MT8183, p_id))
+ num_comp = CFG_GET(MT8183, path->config, num_components);
+
+ if (CFG_CHECK(MT8183, p_id))
+ ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]);
/* Acquire components */
ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count);
@@ -165,9 +195,9 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
set->value, 0xFFFFFFFF);
}
/* Config sub-frame information */
- for (index = (config->num_components - 1); index >= 0; index--) {
+ for (index = (num_comp - 1); index >= 0; index--) {
ctx = &path->comps[index];
- if (is_output_disabled(ctx->param, count))
+ if (is_output_disabled(p_id, ctx->param, count))
continue;
ret = call_op(ctx, config_subfrm, cmd, count);
if (ret)
@@ -178,16 +208,16 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
if (ret)
return ret;
/* Wait components done */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
- if (is_output_disabled(ctx->param, count))
+ if (is_output_disabled(p_id, ctx->param, count))
continue;
ret = call_op(ctx, wait_comp_event, cmd);
if (ret)
return ret;
}
/* Advance to the next sub-frame */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, advance_subfrm, cmd, count);
if (ret)
@@ -206,23 +236,35 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
struct mdp_path *path)
{
- const struct img_config *config = path->config;
+ const int p_id = mdp->mdp_data->mdp_plat_id;
struct mdp_comp_ctx *ctx;
int index, count, ret;
+ u32 num_comp = 0;
+ u32 num_sub = 0;
+
+ if (CFG_CHECK(MT8183, p_id))
+ num_comp = CFG_GET(MT8183, path->config, num_components);
+
+ if (CFG_CHECK(MT8183, p_id))
+ num_sub = CFG_GET(MT8183, path->config, num_subfrms);
/* Config path frame */
/* Reset components */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, init_comp, cmd);
if (ret)
return ret;
}
/* Config frame mode */
- for (index = 0; index < config->num_components; index++) {
- const struct v4l2_rect *compose =
- path->composes[ctx->param->outputs[0]];
+ for (index = 0; index < num_comp; index++) {
+ const struct v4l2_rect *compose;
+ u32 out = 0;
+
+ if (CFG_CHECK(MT8183, p_id))
+ out = CFG_COMP(MT8183, ctx->param, outputs[0]);
+ compose = path->composes[out];
ctx = &path->comps[index];
ret = call_op(ctx, config_frame, cmd, compose);
if (ret)
@@ -230,13 +272,13 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
}
/* Config path sub-frames */
- for (count = 0; count < config->num_subfrms; count++) {
+ for (count = 0; count < num_sub; count++) {
ret = mdp_path_config_subfrm(cmd, path, count);
if (ret)
return ret;
}
/* Post processing information */
- for (index = 0; index < config->num_components; index++) {
+ for (index = 0; index < num_comp; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, post_process, cmd);
if (ret)
@@ -286,11 +328,13 @@ static void mdp_auto_release_work(struct work_struct *work)
{
struct mdp_cmdq_cmd *cmd;
struct mdp_dev *mdp;
+ int id;
cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
mdp = cmd->mdp;
- mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
+ mtk_mutex_unprepare(mdp->mdp_mutex[id]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
@@ -310,6 +354,7 @@ static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
struct cmdq_cb_data *data;
struct mdp_dev *mdp;
struct device *dev;
+ int id;
if (!mssg) {
pr_info("%s:no callback data\n", __func__);
@@ -335,7 +380,8 @@ static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
dev_err(dev, "%s:queue_work fail!\n", __func__);
- mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
+ mtk_mutex_unprepare(mdp->mdp_mutex[id]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
@@ -356,7 +402,9 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
struct mdp_cmdq_cmd *cmd = NULL;
struct mdp_comp *comps = NULL;
struct device *dev = &mdp->pdev->dev;
+ const int p_id = mdp->mdp_data->mdp_plat_id;
int i, ret;
+ u32 num_comp = 0;
atomic_inc(&mdp->job_count);
if (atomic_read(&mdp->suspended)) {
@@ -374,8 +422,13 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
if (ret)
goto err_free_cmd;
- comps = kcalloc(param->config->num_components, sizeof(*comps),
- GFP_KERNEL);
+ if (CFG_CHECK(MT8183, p_id)) {
+ num_comp = CFG_GET(MT8183, param->config, num_components);
+ } else {
+ ret = -EINVAL;
+ goto err_destroy_pkt;
+ }
+ comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL);
if (!comps) {
ret = -ENOMEM;
goto err_destroy_pkt;
@@ -387,7 +440,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
goto err_free_comps;
}
- ret = mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
+ ret = mtk_mutex_prepare(mdp->mdp_mutex[i]);
if (ret) {
dev_err(dev, "Fail to enable mutex clk\n");
goto err_free_path;
@@ -406,7 +460,6 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
path->composes[i] = param->composes[i] ?
param->composes[i] : &path->bounds[i];
}
-
ret = mdp_path_ctx_init(mdp, path);
if (ret) {
dev_err(dev, "mdp_path_ctx_init error\n");
@@ -420,7 +473,7 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
}
cmdq_pkt_finalize(&cmd->pkt);
- for (i = 0; i < param->config->num_components; i++)
+ for (i = 0; i < num_comp; i++)
memcpy(&comps[i], path->comps[i].comp,
sizeof(struct mdp_comp));
@@ -429,7 +482,7 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cmd->user_cmdq_cb = param->cmdq_cb;
cmd->user_cb_data = param->cb_data;
cmd->comps = comps;
- cmd->num_comps = param->config->num_components;
+ cmd->num_comps = num_comp;
cmd->mdp_ctx = param->mdp_ctx;
ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
@@ -453,7 +506,8 @@ err_clock_off:
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
err_free_path:
- mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
+ i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
+ mtk_mutex_unprepare(mdp->mdp_mutex[i]);
kfree(path);
err_free_comps:
kfree(comps);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
index 091a68685590..75c92e282fa2 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
@@ -8,6 +8,7 @@
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
+#include "mtk-mdp3-cfg.h"
#include "mtk-mdp3-comp.h"
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-regs.h"
@@ -19,6 +20,7 @@
#include "mdp_reg_wdma.h"
static u32 mdp_comp_alias_id[MDP_COMP_TYPE_COUNT];
+static int p_id;
static inline const struct mdp_platform_config *
__get_plat_cfg(const struct mdp_comp_ctx *ctx)
@@ -32,12 +34,18 @@ __get_plat_cfg(const struct mdp_comp_ctx *ctx)
static s64 get_comp_flag(const struct mdp_comp_ctx *ctx)
{
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
+ u32 rdma0, rsz1;
+
+ rdma0 = mdp_cfg_get_id_inner(ctx->comp->mdp_dev, MDP_COMP_RDMA0);
+ rsz1 = mdp_cfg_get_id_inner(ctx->comp->mdp_dev, MDP_COMP_RSZ1);
+ if (!rdma0 || !rsz1)
+ return MDP_COMP_NONE;
if (mdp_cfg && mdp_cfg->rdma_rsz1_sram_sharing)
- if (ctx->comp->id == MDP_COMP_RDMA0)
- return BIT(MDP_COMP_RDMA0) | BIT(MDP_COMP_RSZ1);
+ if (ctx->comp->inner_id == rdma0)
+ return BIT(rdma0) | BIT(rsz1);
- return BIT(ctx->comp->id);
+ return BIT(ctx->comp->inner_id);
}
static int init_rdma(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd)
@@ -45,12 +53,17 @@ static int init_rdma(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd)
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ s32 rdma0;
+
+ rdma0 = mdp_cfg_get_id_inner(ctx->comp->mdp_dev, MDP_COMP_RDMA0);
+ if (!rdma0)
+ return -EINVAL;
if (mdp_cfg && mdp_cfg->rdma_support_10bit) {
struct mdp_comp *prz1 = ctx->comp->mdp_dev->comp[MDP_COMP_RSZ1];
/* Disable RSZ1 */
- if (ctx->comp->id == MDP_COMP_RDMA0 && prz1)
+ if (ctx->comp->inner_id == rdma0 && prz1)
MM_REG_WRITE(cmd, subsys_id, prz1->reg_base, PRZ_ENABLE,
0x0, BIT(0));
}
@@ -66,13 +79,13 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd,
const struct v4l2_rect *compose)
{
- const struct mdp_rdma_data *rdma = &ctx->param->rdma;
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
u32 colorformat = ctx->input->buffer.format.colorformat;
bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat);
bool en_ufo = MDP_COLOR_IS_UFP(colorformat);
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 reg = 0;
if (mdp_cfg && mdp_cfg->rdma_support_10bit) {
if (block10bit)
@@ -90,49 +103,78 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx,
0x00030071);
/* Setup source frame info */
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_CON, rdma->src_ctrl,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.src_ctrl);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_CON, reg,
0x03C8FE0F);
if (mdp_cfg)
if (mdp_cfg->rdma_support_10bit && en_ufo) {
/* Setup source buffer base */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.ufo_dec_y);
MM_REG_WRITE(cmd, subsys_id,
base, MDP_RDMA_UFO_DEC_LENGTH_BASE_Y,
- rdma->ufo_dec_y, 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.ufo_dec_c);
MM_REG_WRITE(cmd, subsys_id,
base, MDP_RDMA_UFO_DEC_LENGTH_BASE_C,
- rdma->ufo_dec_c, 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
/* Set 10bit source frame pitch */
- if (block10bit)
+ if (block10bit) {
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.mf_bkgd_in_pxl);
MM_REG_WRITE(cmd, subsys_id,
base, MDP_RDMA_MF_BKGD_SIZE_IN_PXL,
- rdma->mf_bkgd_in_pxl, 0x001FFFFF);
+ reg, 0x001FFFFF);
+ }
}
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_CON, rdma->control,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.control);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_CON, reg,
0x1110);
/* Setup source buffer base */
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_0, rdma->iova[0],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova[0]);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_0, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_1, rdma->iova[1],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova[1]);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_1, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_2, rdma->iova[2],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova[2]);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_2, reg,
0xFFFFFFFF);
/* Setup source buffer end */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[0]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_0,
- rdma->iova_end[0], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[1]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_1,
- rdma->iova_end[1], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[2]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_2,
- rdma->iova_end[2], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
/* Setup source frame pitch */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.mf_bkgd);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_BKGD_SIZE_IN_BYTE,
- rdma->mf_bkgd, 0x001FFFFF);
+ reg, 0x001FFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.sf_bkgd);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SF_BKGD_SIZE_IN_BYTE,
- rdma->sf_bkgd, 0x001FFFFF);
+ reg, 0x001FFFFF);
/* Setup color transform */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.transform);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_TRANSFORM_0,
- rdma->transform, 0x0F110000);
+ reg, 0x0F110000);
return 0;
}
@@ -140,47 +182,67 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx,
static int config_rdma_subfrm(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index)
{
- const struct mdp_rdma_subfrm *subfrm = &ctx->param->rdma.subfrms[index];
- const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
u32 colorformat = ctx->input->buffer.format.colorformat;
bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat);
bool en_ufo = MDP_COLOR_IS_UFP(colorformat);
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 csf_l = 0, csf_r = 0;
+ u32 reg = 0;
/* Enable RDMA */
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, BIT(0), BIT(0));
/* Set Y pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[0]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0,
- subfrm->offset[0], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
/* Set 10bit UFO mode */
- if (mdp_cfg)
- if (mdp_cfg->rdma_support_10bit && block10bit && en_ufo)
+ if (mdp_cfg) {
+ if (mdp_cfg->rdma_support_10bit && block10bit && en_ufo) {
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset_0_p);
MM_REG_WRITE(cmd, subsys_id, base,
MDP_RDMA_SRC_OFFSET_0_P,
- subfrm->offset_0_p, 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
+ }
+ }
/* Set U pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[1]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_1,
- subfrm->offset[1], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
/* Set V pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[2]);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_2,
- subfrm->offset[2], 0xFFFFFFFF);
+ reg, 0xFFFFFFFF);
/* Set source size */
- MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_SRC_SIZE, subfrm->src,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].src);
+ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_SRC_SIZE, reg,
0x1FFF1FFF);
/* Set target size */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].clip);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_CLIP_SIZE,
- subfrm->clip, 0x1FFF1FFF);
+ reg, 0x1FFF1FFF);
/* Set crop offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].clip_ofst);
MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_OFFSET_1,
- subfrm->clip_ofst, 0x003F001F);
+ reg, 0x003F001F);
+ if (CFG_CHECK(MT8183, p_id)) {
+ csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left);
+ csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right);
+ }
if (mdp_cfg && mdp_cfg->rdma_upsample_repeat_only)
- if ((csf->in.right - csf->in.left + 1) > 320)
+ if ((csf_r - csf_l + 1) > 320)
MM_REG_WRITE(cmd, subsys_id, base,
MDP_RDMA_RESV_DUMMY_0, BIT(2), BIT(2));
@@ -228,63 +290,97 @@ static int config_rsz_frame(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd,
const struct v4l2_rect *compose)
{
- const struct mdp_rsz_data *rsz = &ctx->param->rsz;
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ bool bypass = FALSE;
+ u32 reg = 0;
- if (ctx->param->frame.bypass) {
+ if (CFG_CHECK(MT8183, p_id))
+ bypass = CFG_COMP(MT8183, ctx->param, frame.bypass);
+
+ if (bypass) {
/* Disable RSZ */
MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x0, BIT(0));
return 0;
}
- MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, rsz->control1,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.control1);
+ MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, reg,
0x03FFFDF3);
- MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, rsz->control2,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.control2);
+ MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, reg,
0x0FFFC290);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.coeff_step_x);
MM_REG_WRITE(cmd, subsys_id, base, PRZ_HORIZONTAL_COEFF_STEP,
- rsz->coeff_step_x, 0x007FFFFF);
+ reg, 0x007FFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.coeff_step_y);
MM_REG_WRITE(cmd, subsys_id, base, PRZ_VERTICAL_COEFF_STEP,
- rsz->coeff_step_y, 0x007FFFFF);
+ reg, 0x007FFFFF);
return 0;
}
static int config_rsz_subfrm(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index)
{
- const struct mdp_rsz_subfrm *subfrm = &ctx->param->rsz.subfrms[index];
- const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 csf_l = 0, csf_r = 0;
+ u32 reg = 0;
- MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, subfrm->control2,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].control2);
+ MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, reg,
0x00003800);
- MM_REG_WRITE(cmd, subsys_id, base, PRZ_INPUT_IMAGE, subfrm->src,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].src);
+ MM_REG_WRITE(cmd, subsys_id, base, PRZ_INPUT_IMAGE, reg,
0xFFFFFFFF);
+ if (CFG_CHECK(MT8183, p_id)) {
+ csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left);
+ csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right);
+ }
if (mdp_cfg && mdp_cfg->rsz_disable_dcm_small_sample)
- if ((csf->in.right - csf->in.left + 1) <= 16)
+ if ((csf_r - csf_l + 1) <= 16)
MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1,
BIT(27), BIT(27));
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.left);
MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET,
- csf->luma.left, 0xFFFF);
+ reg, 0xFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.left_subpix);
MM_REG_WRITE(cmd, subsys_id,
base, PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET,
- csf->luma.left_subpix, 0x1FFFFF);
+ reg, 0x1FFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.top);
MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_INTEGER_OFFSET,
- csf->luma.top, 0xFFFF);
+ reg, 0xFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.top_subpix);
MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET,
- csf->luma.top_subpix, 0x1FFFFF);
+ reg, 0x1FFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].chroma.left);
MM_REG_WRITE(cmd, subsys_id,
base, PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET,
- csf->chroma.left, 0xFFFF);
+ reg, 0xFFFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, subfrms[index].chroma.left_subpix);
MM_REG_WRITE(cmd, subsys_id,
base, PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET,
- csf->chroma.left_subpix, 0x1FFFFF);
+ reg, 0x1FFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, PRZ_OUTPUT_IMAGE, subfrm->clip,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].clip);
+ MM_REG_WRITE(cmd, subsys_id, base, PRZ_OUTPUT_IMAGE, reg,
0xFFFFFFFF);
return 0;
@@ -296,11 +392,16 @@ static int advance_rsz_subfrm(struct mdp_comp_ctx *ctx,
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
if (mdp_cfg && mdp_cfg->rsz_disable_dcm_small_sample) {
- const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 csf_l = 0, csf_r = 0;
+
+ if (CFG_CHECK(MT8183, p_id)) {
+ csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left);
+ csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right);
+ }
- if ((csf->in.right - csf->in.left + 1) <= 16)
+ if ((csf_r - csf_l + 1) <= 16)
MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, 0x0,
BIT(27));
}
@@ -333,31 +434,47 @@ static int config_wrot_frame(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd,
const struct v4l2_rect *compose)
{
- const struct mdp_wrot_data *wrot = &ctx->param->wrot;
const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx);
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 reg = 0;
/* Write frame base address */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR, wrot->iova[0],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.iova[0]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_C, wrot->iova[1],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.iova[1]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_C, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_V, wrot->iova[2],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.iova[2]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_V, reg,
0xFFFFFFFF);
/* Write frame related registers */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, wrot->control,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.control);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, reg,
0xF131510F);
/* Write frame Y pitch */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE, wrot->stride[0],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.stride[0]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE, reg,
0x0000FFFF);
/* Write frame UV pitch */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_C, wrot->stride[1],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.stride[1]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_C, reg,
0xFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_V, wrot->stride[2],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.stride[2]);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_V, reg,
0xFFFF);
/* Write matrix control */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAT_CTRL, wrot->mat_ctrl, 0xF3);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.mat_ctrl);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAT_CTRL, reg, 0xF3);
/* Set the fixed ALPHA as 0xFF */
MM_REG_WRITE(cmd, subsys_id, base, VIDO_DITHER, 0xFF000000,
@@ -365,13 +482,18 @@ static int config_wrot_frame(struct mdp_comp_ctx *ctx,
/* Set VIDO_EOL_SEL */
MM_REG_WRITE(cmd, subsys_id, base, VIDO_RSV_1, BIT(31), BIT(31));
/* Set VIDO_FIFO_TEST */
- if (wrot->fifo_test != 0)
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.fifo_test);
+ if (reg != 0)
MM_REG_WRITE(cmd, subsys_id, base, VIDO_FIFO_TEST,
- wrot->fifo_test, 0xFFF);
+ reg, 0xFFF);
/* Filter enable */
- if (mdp_cfg && mdp_cfg->wrot_filter_constraint)
+ if (mdp_cfg && mdp_cfg->wrot_filter_constraint) {
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.filter);
MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE,
- wrot->filter, 0x77);
+ reg, 0x77);
+ }
return 0;
}
@@ -379,30 +501,44 @@ static int config_wrot_frame(struct mdp_comp_ctx *ctx,
static int config_wrot_subfrm(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index)
{
- const struct mdp_wrot_subfrm *subfrm = &ctx->param->wrot.subfrms[index];
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 reg = 0;
/* Write Y pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[0]);
MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR,
- subfrm->offset[0], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write U pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[1]);
MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_C,
- subfrm->offset[1], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write V pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[2]);
MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_V,
- subfrm->offset[2], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write source size */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_IN_SIZE, subfrm->src,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].src);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_IN_SIZE, reg,
0x1FFF1FFF);
/* Write target size */
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_TAR_SIZE, subfrm->clip,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].clip);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_TAR_SIZE, reg,
0x1FFF1FFF);
- MM_REG_WRITE(cmd, subsys_id, base, VIDO_CROP_OFST, subfrm->clip_ofst,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].clip_ofst);
+ MM_REG_WRITE(cmd, subsys_id, base, VIDO_CROP_OFST, reg,
0x1FFF1FFF);
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].main_buf);
MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE,
- subfrm->main_buf, 0x1FFF7F00);
+ reg, 0x1FFF7F00);
/* Enable WROT */
MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, BIT(0), BIT(0));
@@ -456,29 +592,41 @@ static int config_wdma_frame(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd,
const struct v4l2_rect *compose)
{
- const struct mdp_wdma_data *wdma = &ctx->param->wdma;
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 reg = 0;
MM_REG_WRITE(cmd, subsys_id, base, WDMA_BUF_CON2, 0x10101050,
0xFFFFFFFF);
/* Setup frame information */
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_CFG, wdma->wdma_cfg,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.wdma_cfg);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_CFG, reg,
0x0F01B8F0);
/* Setup frame base address */
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR, wdma->iova[0],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.iova[0]);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR, wdma->iova[1],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.iova[1]);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR, reg,
0xFFFFFFFF);
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR, wdma->iova[2],
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.iova[2]);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR, reg,
0xFFFFFFFF);
/* Setup Y pitch */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.w_in_byte);
MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_W_IN_BYTE,
- wdma->w_in_byte, 0x0000FFFF);
+ reg, 0x0000FFFF);
/* Setup UV pitch */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.uv_stride);
MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_UV_PITCH,
- wdma->uv_stride, 0x0000FFFF);
+ reg, 0x0000FFFF);
/* Set the fixed ALPHA as 0xFF */
MM_REG_WRITE(cmd, subsys_id, base, WDMA_ALPHA, 0x800000FF,
0x800000FF);
@@ -489,27 +637,39 @@ static int config_wdma_frame(struct mdp_comp_ctx *ctx,
static int config_wdma_subfrm(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index)
{
- const struct mdp_wdma_subfrm *subfrm = &ctx->param->wdma.subfrms[index];
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 reg = 0;
/* Write Y pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].offset[0]);
MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR_OFFSET,
- subfrm->offset[0], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write U pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].offset[1]);
MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR_OFFSET,
- subfrm->offset[1], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write V pixel offset */
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].offset[2]);
MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR_OFFSET,
- subfrm->offset[2], 0x0FFFFFFF);
+ reg, 0x0FFFFFFF);
/* Write source size */
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_SRC_SIZE, subfrm->src,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].src);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_SRC_SIZE, reg,
0x3FFF3FFF);
/* Write target size */
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_SIZE, subfrm->clip,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].clip);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_SIZE, reg,
0x3FFF3FFF);
/* Write clip offset */
- MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_COORD, subfrm->clip_ofst,
+ if (CFG_CHECK(MT8183, p_id))
+ reg = CFG_COMP(MT8183, ctx->param, wdma.subfrms[index].clip_ofst);
+ MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_COORD, reg,
0x3FFF3FFF);
/* Enable WDMA */
@@ -552,13 +712,21 @@ static int init_ccorr(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd)
static int config_ccorr_subfrm(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index)
{
- const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
phys_addr_t base = ctx->comp->reg_base;
u8 subsys_id = ctx->comp->subsys_id;
+ u32 csf_l = 0, csf_r = 0;
+ u32 csf_t = 0, csf_b = 0;
u32 hsize, vsize;
- hsize = csf->in.right - csf->in.left + 1;
- vsize = csf->in.bottom - csf->in.top + 1;
+ if (CFG_CHECK(MT8183, p_id)) {
+ csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left);
+ csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right);
+ csf_t = CFG_COMP(MT8183, ctx->param, subfrms[index].in.top);
+ csf_b = CFG_COMP(MT8183, ctx->param, subfrms[index].in.bottom);
+ }
+
+ hsize = csf_r - csf_l + 1;
+ vsize = csf_b - csf_t + 1;
MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_SIZE,
(hsize << 16) + (vsize << 0), 0x1FFF1FFF);
return 0;
@@ -578,32 +746,6 @@ static const struct mdp_comp_ops *mdp_comp_ops[MDP_COMP_TYPE_COUNT] = {
[MDP_COMP_TYPE_CCORR] = &ccorr_ops,
};
-struct mdp_comp_match {
- enum mdp_comp_type type;
- u32 alias_id;
-};
-
-static const struct mdp_comp_match mdp_comp_matches[MDP_MAX_COMP_COUNT] = {
- [MDP_COMP_WPEI] = { MDP_COMP_TYPE_WPEI, 0 },
- [MDP_COMP_WPEO] = { MDP_COMP_TYPE_EXTO, 2 },
- [MDP_COMP_WPEI2] = { MDP_COMP_TYPE_WPEI, 1 },
- [MDP_COMP_WPEO2] = { MDP_COMP_TYPE_EXTO, 3 },
- [MDP_COMP_ISP_IMGI] = { MDP_COMP_TYPE_IMGI, 0 },
- [MDP_COMP_ISP_IMGO] = { MDP_COMP_TYPE_EXTO, 0 },
- [MDP_COMP_ISP_IMG2O] = { MDP_COMP_TYPE_EXTO, 1 },
-
- [MDP_COMP_CAMIN] = { MDP_COMP_TYPE_DL_PATH, 0 },
- [MDP_COMP_CAMIN2] = { MDP_COMP_TYPE_DL_PATH, 1 },
- [MDP_COMP_RDMA0] = { MDP_COMP_TYPE_RDMA, 0 },
- [MDP_COMP_CCORR0] = { MDP_COMP_TYPE_CCORR, 0 },
- [MDP_COMP_RSZ0] = { MDP_COMP_TYPE_RSZ, 0 },
- [MDP_COMP_RSZ1] = { MDP_COMP_TYPE_RSZ, 1 },
- [MDP_COMP_PATH0_SOUT] = { MDP_COMP_TYPE_PATH, 0 },
- [MDP_COMP_PATH1_SOUT] = { MDP_COMP_TYPE_PATH, 1 },
- [MDP_COMP_WROT0] = { MDP_COMP_TYPE_WROT, 0 },
- [MDP_COMP_WDMA] = { MDP_COMP_TYPE_WDMA, 0 },
-};
-
static const struct of_device_id mdp_comp_dt_ids[] = {
{
.compatible = "mediatek,mt8183-mdp3-rdma",
@@ -624,32 +766,6 @@ static const struct of_device_id mdp_comp_dt_ids[] = {
{}
};
-static const struct of_device_id mdp_sub_comp_dt_ids[] = {
- {
- .compatible = "mediatek,mt8183-mdp3-wdma",
- .data = (void *)MDP_COMP_TYPE_PATH,
- }, {
- .compatible = "mediatek,mt8183-mdp3-wrot",
- .data = (void *)MDP_COMP_TYPE_PATH,
- },
- {}
-};
-
-/* Used to describe the item order in MDP property */
-struct mdp_comp_info {
- u32 clk_num;
- u32 clk_ofst;
- u32 dts_reg_ofst;
-};
-
-static const struct mdp_comp_info mdp_comp_dt_info[MDP_MAX_COMP_COUNT] = {
- [MDP_COMP_RDMA0] = {2, 0, 0},
- [MDP_COMP_RSZ0] = {1, 0, 0},
- [MDP_COMP_WROT0] = {1, 0, 0},
- [MDP_COMP_WDMA] = {1, 0, 0},
- [MDP_COMP_CCORR0] = {1, 0, 0},
-};
-
static inline bool is_dma_capable(const enum mdp_comp_type type)
{
return (type == MDP_COMP_TYPE_RDMA ||
@@ -666,13 +782,13 @@ static inline bool is_bypass_gce_event(const enum mdp_comp_type type)
return (type == MDP_COMP_TYPE_PATH);
}
-static int mdp_comp_get_id(enum mdp_comp_type type, int alias_id)
+static int mdp_comp_get_id(struct mdp_dev *mdp, enum mdp_comp_type type, u32 alias_id)
{
int i;
- for (i = 0; i < ARRAY_SIZE(mdp_comp_matches); i++)
- if (mdp_comp_matches[i].type == type &&
- mdp_comp_matches[i].alias_id == alias_id)
+ for (i = 0; i < mdp->mdp_data->comp_data_len; i++)
+ if (mdp->mdp_data->comp_data[i].match.type == type &&
+ mdp->mdp_data->comp_data[i].match.alias_id == alias_id)
return i;
return -ENODEV;
}
@@ -681,24 +797,25 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
{
int i, ret;
- if (comp->comp_dev) {
+ /* Only DMA capable components need the pm control */
+ if (comp->comp_dev && is_dma_capable(comp->type)) {
ret = pm_runtime_resume_and_get(comp->comp_dev);
if (ret < 0) {
dev_err(dev,
"Failed to get power, err %d. type:%d id:%d\n",
- ret, comp->type, comp->id);
+ ret, comp->type, comp->inner_id);
return ret;
}
}
- for (i = 0; i < ARRAY_SIZE(comp->clks); i++) {
+ for (i = 0; i < comp->clk_num; i++) {
if (IS_ERR_OR_NULL(comp->clks[i]))
continue;
ret = clk_prepare_enable(comp->clks[i]);
if (ret) {
dev_err(dev,
"Failed to enable clk %d. type:%d id:%d\n",
- i, comp->type, comp->id);
+ i, comp->type, comp->inner_id);
goto err_revert;
}
}
@@ -711,7 +828,7 @@ err_revert:
continue;
clk_disable_unprepare(comp->clks[i]);
}
- if (comp->comp_dev)
+ if (comp->comp_dev && is_dma_capable(comp->type))
pm_runtime_put_sync(comp->comp_dev);
return ret;
@@ -721,13 +838,13 @@ void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
{
int i;
- for (i = 0; i < ARRAY_SIZE(comp->clks); i++) {
+ for (i = 0; i < comp->clk_num; i++) {
if (IS_ERR_OR_NULL(comp->clks[i]))
continue;
clk_disable_unprepare(comp->clks[i]);
}
- if (comp->comp_dev)
+ if (comp->comp_dev && is_dma_capable(comp->type))
pm_runtime_put(comp->comp_dev);
}
@@ -752,8 +869,8 @@ void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num)
mdp_comp_clock_off(dev, &comps[i]);
}
-static int mdp_get_subsys_id(struct device *dev, struct device_node *node,
- struct mdp_comp *comp)
+static int mdp_get_subsys_id(struct mdp_dev *mdp, struct device *dev,
+ struct device_node *node, struct mdp_comp *comp)
{
struct platform_device *comp_pdev;
struct cmdq_client_reg cmdq_reg;
@@ -766,12 +883,12 @@ static int mdp_get_subsys_id(struct device *dev, struct device_node *node,
comp_pdev = of_find_device_by_node(node);
if (!comp_pdev) {
- dev_err(dev, "get comp_pdev fail! comp id=%d type=%d\n",
- comp->id, comp->type);
+ dev_err(dev, "get comp_pdev fail! comp public id=%d, inner id=%d, type=%d\n",
+ comp->public_id, comp->inner_id, comp->type);
return -ENODEV;
}
- index = mdp_comp_dt_info[comp->id].dts_reg_ofst;
+ index = mdp->mdp_data->comp_data[comp->public_id].info.dts_reg_ofst;
ret = cmdq_dev_get_client_reg(&comp_pdev->dev, &cmdq_reg, index);
if (ret != 0) {
dev_err(&comp_pdev->dev, "cmdq_dev_get_subsys fail!\n");
@@ -789,8 +906,9 @@ static void __mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
{
struct resource res;
phys_addr_t base;
- int index = mdp_comp_dt_info[comp->id].dts_reg_ofst;
+ int index;
+ index = mdp->mdp_data->comp_data[comp->public_id].info.dts_reg_ofst;
if (of_address_to_resource(node, index, &res) < 0)
base = 0L;
else
@@ -805,7 +923,7 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
struct mdp_comp *comp, enum mtk_mdp_comp_id id)
{
struct device *dev = &mdp->pdev->dev;
- int clk_num;
+ struct platform_device *pdev_c;
int clk_ofst;
int i;
s32 event;
@@ -815,22 +933,36 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
return -EINVAL;
}
- comp->id = id;
- comp->type = mdp_comp_matches[id].type;
- comp->alias_id = mdp_comp_matches[id].alias_id;
+ pdev_c = of_find_device_by_node(node);
+ if (!pdev_c) {
+ dev_warn(dev, "can't find platform device of node:%s\n",
+ node->name);
+ return -ENODEV;
+ }
+
+ comp->comp_dev = &pdev_c->dev;
+ comp->public_id = id;
+ comp->type = mdp->mdp_data->comp_data[id].match.type;
+ comp->inner_id = mdp->mdp_data->comp_data[id].match.inner_id;
+ comp->alias_id = mdp->mdp_data->comp_data[id].match.alias_id;
comp->ops = mdp_comp_ops[comp->type];
__mdp_comp_init(mdp, node, comp);
- clk_num = mdp_comp_dt_info[id].clk_num;
- clk_ofst = mdp_comp_dt_info[id].clk_ofst;
+ comp->clk_num = mdp->mdp_data->comp_data[id].info.clk_num;
+ comp->clks = devm_kzalloc(dev, sizeof(struct clk *) * comp->clk_num,
+ GFP_KERNEL);
+ if (!comp->clks)
+ return -ENOMEM;
- for (i = 0; i < clk_num; i++) {
+ clk_ofst = mdp->mdp_data->comp_data[id].info.clk_ofst;
+
+ for (i = 0; i < comp->clk_num; i++) {
comp->clks[i] = of_clk_get(node, i + clk_ofst);
if (IS_ERR(comp->clks[i]))
break;
}
- mdp_get_subsys_id(dev, node, comp);
+ mdp_get_subsys_id(mdp, dev, node, comp);
/* Set GCE SOF event */
if (is_bypass_gce_event(comp->type) ||
@@ -861,6 +993,11 @@ static void mdp_comp_deinit(struct mdp_comp *comp)
if (!comp)
return;
+ if (comp->comp_dev && comp->clks) {
+ devm_kfree(&comp->mdp_dev->pdev->dev, comp->clks);
+ comp->clks = NULL;
+ }
+
if (comp->regs)
iounmap(comp->regs);
}
@@ -888,8 +1025,8 @@ static struct mdp_comp *mdp_comp_create(struct mdp_dev *mdp,
mdp->comp[id] = comp;
mdp->comp[id]->mdp_dev = mdp;
- dev_dbg(dev, "%s type:%d alias:%d id:%d base:%#x regs:%p\n",
- dev->of_node->name, comp->type, comp->alias_id, id,
+ dev_dbg(dev, "%s type:%d alias:%d public id:%d inner id:%d base:%#x regs:%p\n",
+ dev->of_node->name, comp->type, comp->alias_id, id, comp->inner_id,
(u32)comp->reg_base, comp->regs);
return comp;
}
@@ -898,6 +1035,7 @@ static int mdp_comp_sub_create(struct mdp_dev *mdp)
{
struct device *dev = &mdp->pdev->dev;
struct device_node *node, *parent;
+ const struct mtk_mdp_driver_data *data = mdp->mdp_data;
parent = dev->of_node->parent;
@@ -907,7 +1045,7 @@ static int mdp_comp_sub_create(struct mdp_dev *mdp)
int id, alias_id;
struct mdp_comp *comp;
- of_id = of_match_node(mdp_sub_comp_dt_ids, node);
+ of_id = of_match_node(data->mdp_sub_comp_dt_ids, node);
if (!of_id)
continue;
if (!of_device_is_available(node)) {
@@ -918,7 +1056,7 @@ static int mdp_comp_sub_create(struct mdp_dev *mdp)
type = (enum mdp_comp_type)(uintptr_t)of_id->data;
alias_id = mdp_comp_alias_id[type];
- id = mdp_comp_get_id(type, alias_id);
+ id = mdp_comp_get_id(mdp, type, alias_id);
if (id < 0) {
dev_err(dev,
"Fail to get sub comp. id: type %d alias %d\n",
@@ -941,7 +1079,8 @@ void mdp_comp_destroy(struct mdp_dev *mdp)
for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) {
if (mdp->comp[i]) {
- pm_runtime_disable(mdp->comp[i]->comp_dev);
+ if (is_dma_capable(mdp->comp[i]->type))
+ pm_runtime_disable(mdp->comp[i]->comp_dev);
mdp_comp_deinit(mdp->comp[i]);
devm_kfree(mdp->comp[i]->comp_dev, mdp->comp[i]);
mdp->comp[i] = NULL;
@@ -953,10 +1092,10 @@ int mdp_comp_config(struct mdp_dev *mdp)
{
struct device *dev = &mdp->pdev->dev;
struct device_node *node, *parent;
- struct platform_device *pdev;
int ret;
memset(mdp_comp_alias_id, 0, sizeof(mdp_comp_alias_id));
+ p_id = mdp->mdp_data->mdp_plat_id;
parent = dev->of_node->parent;
/* Iterate over sibling MDP function blocks */
@@ -978,7 +1117,7 @@ int mdp_comp_config(struct mdp_dev *mdp)
type = (enum mdp_comp_type)(uintptr_t)of_id->data;
alias_id = mdp_comp_alias_id[type];
- id = mdp_comp_get_id(type, alias_id);
+ id = mdp_comp_get_id(mdp, type, alias_id);
if (id < 0) {
dev_err(dev,
"Fail to get component id: type %d alias %d\n",
@@ -994,19 +1133,8 @@ int mdp_comp_config(struct mdp_dev *mdp)
}
/* Only DMA capable components need the pm control */
- comp->comp_dev = NULL;
if (!is_dma_capable(comp->type))
continue;
-
- pdev = of_find_device_by_node(node);
- if (!pdev) {
- dev_warn(dev, "can't find platform device of node:%s\n",
- node->name);
- ret = -ENODEV;
- goto err_init_comps;
- }
-
- comp->comp_dev = &pdev->dev;
pm_runtime_enable(comp->comp_dev);
}
@@ -1026,22 +1154,47 @@ int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx,
const struct img_ipi_frameparam *frame)
{
struct device *dev = &mdp->pdev->dev;
- int i;
+ enum mtk_mdp_comp_id public_id = MDP_COMP_NONE;
+ u32 arg;
+ int i, idx;
- if (param->type < 0 || param->type >= MDP_MAX_COMP_COUNT) {
- dev_err(dev, "Invalid component id %d", param->type);
+ if (!param) {
+ dev_err(dev, "Invalid component param");
return -EINVAL;
}
- ctx->comp = mdp->comp[param->type];
+ if (CFG_CHECK(MT8183, p_id))
+ arg = CFG_COMP(MT8183, param, type);
+ else
+ return -EINVAL;
+ public_id = mdp_cfg_get_id_public(mdp, arg);
+ if (public_id < 0) {
+ dev_err(dev, "Invalid component id %d", public_id);
+ return -EINVAL;
+ }
+
+ ctx->comp = mdp->comp[public_id];
if (!ctx->comp) {
- dev_err(dev, "Uninit component id %d", param->type);
+ dev_err(dev, "Uninit component inner id %d", arg);
return -EINVAL;
}
ctx->param = param;
- ctx->input = &frame->inputs[param->input];
- for (i = 0; i < param->num_outputs; i++)
- ctx->outputs[i] = &frame->outputs[param->outputs[i]];
+ if (CFG_CHECK(MT8183, p_id))
+ arg = CFG_COMP(MT8183, param, input);
+ else
+ return -EINVAL;
+ ctx->input = &frame->inputs[arg];
+ if (CFG_CHECK(MT8183, p_id))
+ idx = CFG_COMP(MT8183, param, num_outputs);
+ else
+ return -EINVAL;
+ for (i = 0; i < idx; i++) {
+ if (CFG_CHECK(MT8183, p_id))
+ arg = CFG_COMP(MT8183, param, outputs[i]);
+ else
+ return -EINVAL;
+ ctx->outputs[i] = &frame->outputs[arg];
+ }
return 0;
}
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h
index dc48f55ac4f7..20d2bcb77ef9 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h
@@ -134,6 +134,24 @@ enum {
MDP_GCE_EVENT_MAX,
};
+struct mdp_comp_match {
+ enum mdp_comp_type type;
+ u32 alias_id;
+ s32 inner_id;
+};
+
+/* Used to describe the item order in MDP property */
+struct mdp_comp_info {
+ u32 clk_num;
+ u32 clk_ofst;
+ u32 dts_reg_ofst;
+};
+
+struct mdp_comp_data {
+ struct mdp_comp_match match;
+ struct mdp_comp_info info;
+};
+
struct mdp_comp_ops;
struct mdp_comp {
@@ -141,10 +159,12 @@ struct mdp_comp {
void __iomem *regs;
phys_addr_t reg_base;
u8 subsys_id;
- struct clk *clks[6];
+ u8 clk_num;
+ struct clk **clks;
struct device *comp_dev;
enum mdp_comp_type type;
- enum mtk_mdp_comp_id id;
+ enum mtk_mdp_comp_id public_id;
+ s32 inner_id;
u32 alias_id;
s32 gce_event[MDP_GCE_EVENT_MAX];
const struct mdp_comp_ops *ops;
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index 97edcd9d1c81..aa6c225302f0 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -12,40 +12,11 @@
#include <linux/remoteproc.h>
#include <linux/remoteproc/mtk_scp.h>
#include <media/videobuf2-dma-contig.h>
+
#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-cfg.h"
#include "mtk-mdp3-m2m.h"
-static const struct mdp_platform_config mt8183_plat_cfg = {
- .rdma_support_10bit = true,
- .rdma_rsz1_sram_sharing = true,
- .rdma_upsample_repeat_only = true,
- .rsz_disable_dcm_small_sample = false,
- .wrot_filter_constraint = false,
-};
-
-static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = {
- [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" },
- [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" },
- [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" }
-};
-
-static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = {
- [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0,
- [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0,
- [MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1,
- [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0,
- [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0,
- [MDP_COMP_WDMA] = MUTEX_MOD_IDX_MDP_WDMA,
- [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0,
- [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0,
-};
-
-static const struct mtk_mdp_driver_data mt8183_mdp_driver_data = {
- .mdp_probe_infra = mt8183_mdp_probe_infra,
- .mdp_cfg = &mt8183_plat_cfg,
- .mdp_mutex_table_idx = mt8183_mutex_idx,
-};
-
static const struct of_device_id mdp_of_ids[] = {
{ .compatible = "mediatek,mt8183-mdp3-rdma",
.data = &mt8183_mdp_driver_data,
@@ -182,7 +153,7 @@ static int mdp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mdp_dev *mdp;
struct platform_device *mm_pdev;
- int ret, i;
+ int ret, i, mutex_id;
mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
if (!mdp) {
@@ -205,10 +176,13 @@ static int mdp_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_destroy_device;
}
- for (i = 0; i < MDP_PIPE_MAX; i++) {
- mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
- if (IS_ERR(mdp->mdp_mutex[i])) {
- ret = PTR_ERR(mdp->mdp_mutex[i]);
+ for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) {
+ mutex_id = mdp->mdp_data->pipe_info[i].mutex_id;
+ if (!IS_ERR_OR_NULL(mdp->mdp_mutex[mutex_id]))
+ continue;
+ mdp->mdp_mutex[mutex_id] = mtk_mutex_get(&mm_pdev->dev);
+ if (IS_ERR(mdp->mdp_mutex[mutex_id])) {
+ ret = PTR_ERR(mdp->mdp_mutex[mutex_id]);
goto err_free_mutex;
}
}
@@ -288,7 +262,7 @@ err_destroy_job_wq:
err_deinit_comp:
mdp_comp_destroy(mdp);
err_free_mutex:
- for (i = 0; i < MDP_PIPE_MAX; i++)
+ for (i = 0; i < mdp->mdp_data->pipe_info_len; i++)
if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i]))
mtk_mutex_put(mdp->mdp_mutex[i]);
err_destroy_device:
@@ -298,14 +272,13 @@ err_return:
return ret;
}
-static int mdp_remove(struct platform_device *pdev)
+static void mdp_remove(struct platform_device *pdev)
{
struct mdp_dev *mdp = platform_get_drvdata(pdev);
v4l2_device_unregister(&mdp->v4l2_dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
- return 0;
}
static int __maybe_unused mdp_suspend(struct device *dev)
@@ -345,7 +318,7 @@ static const struct dev_pm_ops mdp_pm_ops = {
static struct platform_driver mdp_driver = {
.probe = mdp_probe,
- .remove = mdp_remove,
+ .remove_new = mdp_remove,
.driver = {
.name = MDP_MODULE_NAME,
.pm = &mdp_pm_ops,
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
index 2ef5fbc4f25a..7e21d226ceb8 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
@@ -43,17 +43,26 @@ struct mdp_platform_config {
/* indicate which mutex is used by each pipepline */
enum mdp_pipe_id {
- MDP_PIPE_RDMA0,
- MDP_PIPE_IMGI,
MDP_PIPE_WPEI,
MDP_PIPE_WPEI2,
+ MDP_PIPE_IMGI,
+ MDP_PIPE_RDMA0,
MDP_PIPE_MAX
};
struct mtk_mdp_driver_data {
+ const int mdp_plat_id;
const struct of_device_id *mdp_probe_infra;
const struct mdp_platform_config *mdp_cfg;
const u32 *mdp_mutex_table_idx;
+ const struct mdp_comp_data *comp_data;
+ unsigned int comp_data_len;
+ const struct of_device_id *mdp_sub_comp_dt_ids;
+ const struct mdp_format *format;
+ unsigned int format_len;
+ const struct mdp_limit *def_limit;
+ const struct mdp_pipe_info *pipe_info;
+ unsigned int pipe_info_len;
};
struct mdp_dev {
@@ -85,6 +94,11 @@ struct mdp_dev {
atomic_t job_count;
};
+struct mdp_pipe_info {
+ enum mdp_pipe_id pipe_id;
+ u32 mutex_id;
+};
+
int mdp_vpu_get_locked(struct mdp_dev *mdp);
void mdp_vpu_put_locked(struct mdp_dev *mdp);
int mdp_vpu_register(struct mdp_dev *mdp);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
index 5f74ea3b7a52..a298c1b15b9e 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
@@ -87,14 +87,14 @@ static void mdp_m2m_device_run(void *priv)
dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
mdp_set_dst_config(&param.outputs[0], frame, &dst_vb->vb2_buf);
- ret = mdp_vpu_process(&ctx->vpu, &param);
+ ret = mdp_vpu_process(&ctx->mdp_dev->vpu, &param);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"VPU MDP process failed: %d\n", ret);
goto worker_end;
}
- task.config = ctx->vpu.config;
+ task.config = ctx->mdp_dev->vpu.config;
task.param = &param;
task.composes[0] = &frame->compose;
task.cmdq_cb = NULL;
@@ -150,11 +150,6 @@ static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
ret = mdp_vpu_get_locked(ctx->mdp_dev);
- if (ret)
- return ret;
-
- ret = mdp_vpu_ctx_init(&ctx->vpu, &ctx->mdp_dev->vpu,
- MDP_DEV_M2M);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"VPU init failed %d\n", ret);
@@ -277,7 +272,9 @@ static int mdp_m2m_querycap(struct file *file, void *fh,
static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
- return mdp_enum_fmt_mplane(f);
+ struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+
+ return mdp_enum_fmt_mplane(ctx->mdp_dev, f);
}
static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
@@ -307,7 +304,7 @@ static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
const struct mdp_format *fmt;
struct vb2_queue *vq;
- fmt = mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id);
+ fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);
if (!fmt)
return -EINVAL;
@@ -346,7 +343,7 @@ static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
- if (!mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id))
+ if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))
return -EINVAL;
return 0;
@@ -556,6 +553,7 @@ static int mdp_m2m_open(struct file *file)
struct device *dev = &mdp->pdev->dev;
int ret;
struct v4l2_format default_format = {};
+ const struct mdp_limit *limit = mdp->mdp_data->def_limit;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -566,7 +564,11 @@ static int mdp_m2m_open(struct file *file)
goto err_free_ctx;
}
- ctx->id = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
+ ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
+ if (ret < 0)
+ goto err_unlock_mutex;
+ ctx->id = ret;
+
ctx->mdp_dev = mdp;
v4l2_fh_init(&ctx->fh, vdev);
@@ -589,7 +591,7 @@ static int mdp_m2m_open(struct file *file)
ctx->fh.m2m_ctx = ctx->m2m_ctx;
ctx->curr_param.ctx = ctx;
- ret = mdp_frameparam_init(&ctx->curr_param);
+ ret = mdp_frameparam_init(mdp, &ctx->curr_param);
if (ret) {
dev_err(dev, "Failed to initialize mdp parameter\n");
goto err_release_m2m_ctx;
@@ -599,8 +601,8 @@ static int mdp_m2m_open(struct file *file)
/* Default format */
default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- default_format.fmt.pix_mp.width = 32;
- default_format.fmt.pix_mp.height = 32;
+ default_format.fmt.pix_mp.width = limit->out_limit.wmin;
+ default_format.fmt.pix_mp.height = limit->out_limit.hmin;
default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
@@ -617,6 +619,8 @@ err_release_handler:
v4l2_fh_del(&ctx->fh);
err_exit_fh:
v4l2_fh_exit(&ctx->fh);
+ ida_free(&mdp->mdp_ida, ctx->id);
+err_unlock_mutex:
mutex_unlock(&mdp->m2m_lock);
err_free_ctx:
kfree(ctx);
@@ -632,10 +636,8 @@ static int mdp_m2m_release(struct file *file)
mutex_lock(&mdp->m2m_lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
- if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
- mdp_vpu_ctx_deinit(&ctx->vpu);
+ if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT))
mdp_vpu_put_locked(mdp);
- }
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_fh_del(&ctx->fh);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h
index 61ddbaf1bf13..dfc59e5b3b87 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h
@@ -33,7 +33,6 @@ struct mdp_m2m_ctx {
struct v4l2_ctrl_handler ctrl_handler;
struct mdp_m2m_ctrls ctrls;
struct v4l2_m2m_ctx *m2m_ctx;
- struct mdp_vpu_ctx vpu;
u32 frame_count[MDP_M2M_MAX];
struct mdp_frameparam curr_param;
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c
index 4e84a37ecdfc..9b436b911d92 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c
@@ -4,6 +4,7 @@
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
+#include <linux/math64.h>
#include <media/v4l2-common.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
@@ -11,276 +12,34 @@
#include "mtk-mdp3-regs.h"
#include "mtk-mdp3-m2m.h"
-/*
- * All 10-bit related formats are not added in the basic format list,
- * please add the corresponding format settings before use.
- */
-static const struct mdp_format mdp_formats[] = {
- {
- .pixelformat = V4L2_PIX_FMT_GREY,
- .mdp_color = MDP_COLOR_GREY,
- .depth = { 8 },
- .row_depth = { 8 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_RGB565X,
- .mdp_color = MDP_COLOR_BGR565,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_RGB565,
- .mdp_color = MDP_COLOR_RGB565,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_RGB24,
- .mdp_color = MDP_COLOR_RGB888,
- .depth = { 24 },
- .row_depth = { 24 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_BGR24,
- .mdp_color = MDP_COLOR_BGR888,
- .depth = { 24 },
- .row_depth = { 24 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_ABGR32,
- .mdp_color = MDP_COLOR_BGRA8888,
- .depth = { 32 },
- .row_depth = { 32 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_ARGB32,
- .mdp_color = MDP_COLOR_ARGB8888,
- .depth = { 32 },
- .row_depth = { 32 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_UYVY,
- .mdp_color = MDP_COLOR_UYVY,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_VYUY,
- .mdp_color = MDP_COLOR_VYUY,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_YUYV,
- .mdp_color = MDP_COLOR_YUYV,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_YVYU,
- .mdp_color = MDP_COLOR_YVYU,
- .depth = { 16 },
- .row_depth = { 16 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_YUV420,
- .mdp_color = MDP_COLOR_I420,
- .depth = { 12 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_YVU420,
- .mdp_color = MDP_COLOR_YV12,
- .depth = { 12 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV12,
- .mdp_color = MDP_COLOR_NV12,
- .depth = { 12 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV21,
- .mdp_color = MDP_COLOR_NV21,
- .depth = { 12 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV16,
- .mdp_color = MDP_COLOR_NV16,
- .depth = { 16 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV61,
- .mdp_color = MDP_COLOR_NV61,
- .depth = { 16 },
- .row_depth = { 8 },
- .num_planes = 1,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV24,
- .mdp_color = MDP_COLOR_NV24,
- .depth = { 24 },
- .row_depth = { 8 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV42,
- .mdp_color = MDP_COLOR_NV42,
- .depth = { 24 },
- .row_depth = { 8 },
- .num_planes = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_MT21C,
- .mdp_color = MDP_COLOR_420_BLK_UFO,
- .depth = { 8, 4 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 4,
- .halign = 5,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_MM21,
- .mdp_color = MDP_COLOR_420_BLK,
- .depth = { 8, 4 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 4,
- .halign = 5,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV12M,
- .mdp_color = MDP_COLOR_NV12,
- .depth = { 8, 4 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV21M,
- .mdp_color = MDP_COLOR_NV21,
- .depth = { 8, 4 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV16M,
- .mdp_color = MDP_COLOR_NV16,
- .depth = { 8, 8 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_NV61M,
- .mdp_color = MDP_COLOR_NV61,
- .depth = { 8, 8 },
- .row_depth = { 8, 8 },
- .num_planes = 2,
- .walign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT,
- }, {
- .pixelformat = V4L2_PIX_FMT_YUV420M,
- .mdp_color = MDP_COLOR_I420,
- .depth = { 8, 2, 2 },
- .row_depth = { 8, 4, 4 },
- .num_planes = 3,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }, {
- .pixelformat = V4L2_PIX_FMT_YVU420M,
- .mdp_color = MDP_COLOR_YV12,
- .depth = { 8, 2, 2 },
- .row_depth = { 8, 4, 4 },
- .num_planes = 3,
- .walign = 1,
- .halign = 1,
- .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
- }
-};
-
-static const struct mdp_limit mdp_def_limit = {
- .out_limit = {
- .wmin = 16,
- .hmin = 16,
- .wmax = 8176,
- .hmax = 8176,
- },
- .cap_limit = {
- .wmin = 2,
- .hmin = 2,
- .wmax = 8176,
- .hmax = 8176,
- },
- .h_scale_up_max = 32,
- .v_scale_up_max = 32,
- .h_scale_down_max = 20,
- .v_scale_down_max = 128,
-};
-
-static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type)
+static const struct mdp_format *mdp_find_fmt(const struct mtk_mdp_driver_data *mdp_data,
+ u32 pixelformat, u32 type)
{
u32 i, flag;
flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
MDP_FMT_FLAG_CAPTURE;
- for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
- if (!(mdp_formats[i].flags & flag))
+ for (i = 0; i < mdp_data->format_len; ++i) {
+ if (!(mdp_data->format[i].flags & flag))
continue;
- if (mdp_formats[i].pixelformat == pixelformat)
- return &mdp_formats[i];
+ if (mdp_data->format[i].pixelformat == pixelformat)
+ return &mdp_data->format[i];
}
return NULL;
}
-static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type)
+static const struct mdp_format *mdp_find_fmt_by_index(const struct mtk_mdp_driver_data *mdp_data,
+ u32 index, u32 type)
{
u32 i, flag, num = 0;
flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
MDP_FMT_FLAG_CAPTURE;
- for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
- if (!(mdp_formats[i].flags & flag))
+ for (i = 0; i < mdp_data->format_len; ++i) {
+ if (!(mdp_data->format[i].flags & flag))
continue;
if (index == num)
- return &mdp_formats[i];
+ return &mdp_data->format[i];
num++;
}
return NULL;
@@ -354,11 +113,11 @@ static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align)
return 0;
}
-int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f)
+int mdp_enum_fmt_mplane(struct mdp_dev *mdp, struct v4l2_fmtdesc *f)
{
const struct mdp_format *fmt;
- fmt = mdp_find_fmt_by_index(f->index, f->type);
+ fmt = mdp_find_fmt_by_index(mdp->mdp_data, f->index, f->type);
if (!fmt)
return -EINVAL;
@@ -366,7 +125,8 @@ int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f)
return 0;
}
-const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
+const struct mdp_format *mdp_try_fmt_mplane(struct mdp_dev *mdp,
+ struct v4l2_format *f,
struct mdp_frameparam *param,
u32 ctx_id)
{
@@ -378,9 +138,9 @@ const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
u32 org_w, org_h;
unsigned int i;
- fmt = mdp_find_fmt(pix_mp->pixelformat, f->type);
+ fmt = mdp_find_fmt(mdp->mdp_data, pix_mp->pixelformat, f->type);
if (!fmt) {
- fmt = mdp_find_fmt_by_index(0, f->type);
+ fmt = mdp_find_fmt_by_index(mdp->mdp_data, 0, f->type);
if (!fmt) {
dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id,
(pix_mp->pixelformat & 0xff),
@@ -428,14 +188,15 @@ const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
u32 bpl = pix_mp->plane_fmt[i].bytesperline;
u32 min_si, max_si;
u32 si = pix_mp->plane_fmt[i].sizeimage;
+ u64 di;
bpl = clamp(bpl, min_bpl, max_bpl);
pix_mp->plane_fmt[i].bytesperline = bpl;
- min_si = (bpl * pix_mp->height * fmt->depth[i]) /
- fmt->row_depth[i];
- max_si = (bpl * s.max_height * fmt->depth[i]) /
- fmt->row_depth[i];
+ di = (u64)bpl * pix_mp->height * fmt->depth[i];
+ min_si = (u32)div_u64(di, fmt->row_depth[i]);
+ di = (u64)bpl * s.max_height * fmt->depth[i];
+ max_si = (u32)div_u64(di, fmt->row_depth[i]);
si = clamp(si, min_si, max_si);
pix_mp->plane_fmt[i].sizeimage = si;
@@ -699,7 +460,7 @@ void mdp_set_dst_config(struct img_output *out,
mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip);
}
-int mdp_frameparam_init(struct mdp_frameparam *param)
+int mdp_frameparam_init(struct mdp_dev *mdp, struct mdp_frameparam *param)
{
struct mdp_frame *frame;
@@ -707,12 +468,12 @@ int mdp_frameparam_init(struct mdp_frameparam *param)
return -EINVAL;
INIT_LIST_HEAD(&param->list);
- param->limit = &mdp_def_limit;
+ param->limit = mdp->mdp_data->def_limit;
param->type = MDP_STREAM_TYPE_BITBLT;
frame = &param->output;
frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
+ frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0);
frame->ycbcr_prof =
mdp_map_ycbcr_prof_mplane(&frame->format,
frame->mdp_fmt->mdp_color);
@@ -721,7 +482,7 @@ int mdp_frameparam_init(struct mdp_frameparam *param)
param->num_captures = 1;
frame = &param->captures[0];
frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
+ frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0);
frame->ycbcr_prof =
mdp_map_ycbcr_prof_mplane(&frame->format,
frame->mdp_fmt->mdp_color);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h
index f995e536d45f..e9ab8ac2c0e8 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h
@@ -18,11 +18,12 @@
* V-subsample: 0, 1
* Color group: 0-RGB, 1-YUV, 2-raw
*/
-#define MDP_COLOR(PACKED, LOOSE, VIDEO, PLANE, HF, VF, BITS, GROUP, SWAP, ID)\
- (((PACKED) << 27) | ((LOOSE) << 26) | ((VIDEO) << 23) |\
+#define MDP_COLOR(COMPRESS, PACKED, LOOSE, VIDEO, PLANE, HF, VF, BITS, GROUP, SWAP, ID)\
+ (((COMPRESS) << 29) | ((PACKED) << 27) | ((LOOSE) << 26) | ((VIDEO) << 23) |\
((PLANE) << 21) | ((HF) << 19) | ((VF) << 18) | ((BITS) << 8) |\
((GROUP) << 6) | ((SWAP) << 5) | ((ID) << 0))
+#define MDP_COLOR_IS_COMPRESS(c) ((0x20000000 & (c)) >> 29)
#define MDP_COLOR_IS_10BIT_PACKED(c) ((0x08000000 & (c)) >> 27)
#define MDP_COLOR_IS_10BIT_LOOSE(c) (((0x0c000000 & (c)) >> 26) == 1)
#define MDP_COLOR_IS_10BIT_TILE(c) (((0x0c000000 & (c)) >> 26) == 3)
@@ -44,144 +45,144 @@
enum mdp_color {
MDP_COLOR_UNKNOWN = 0,
- //MDP_COLOR_FULLG8,
- MDP_COLOR_FULLG8_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 21),
- MDP_COLOR_FULLG8_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 8, 2, 0, 21),
- MDP_COLOR_FULLG8_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 8, 2, 0, 21),
- MDP_COLOR_FULLG8_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 8, 2, 0, 21),
+ /* MDP_COLOR_FULLG8 */
+ MDP_COLOR_FULLG8_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 8, 2, 0, 21),
+ MDP_COLOR_FULLG8_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 8, 2, 0, 21),
+ MDP_COLOR_FULLG8_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 8, 2, 0, 21),
+ MDP_COLOR_FULLG8_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 8, 2, 0, 21),
MDP_COLOR_FULLG8 = MDP_COLOR_FULLG8_BGGR,
- //MDP_COLOR_FULLG10,
- MDP_COLOR_FULLG10_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 21),
- MDP_COLOR_FULLG10_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2, 0, 21),
- MDP_COLOR_FULLG10_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2, 0, 21),
- MDP_COLOR_FULLG10_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2, 0, 21),
+ /* MDP_COLOR_FULLG10 */
+ MDP_COLOR_FULLG10_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 10, 2, 0, 21),
+ MDP_COLOR_FULLG10_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 10, 2, 0, 21),
+ MDP_COLOR_FULLG10_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 10, 2, 0, 21),
+ MDP_COLOR_FULLG10_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 10, 2, 0, 21),
MDP_COLOR_FULLG10 = MDP_COLOR_FULLG10_BGGR,
- //MDP_COLOR_FULLG12,
- MDP_COLOR_FULLG12_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 21),
- MDP_COLOR_FULLG12_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2, 0, 21),
- MDP_COLOR_FULLG12_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2, 0, 21),
- MDP_COLOR_FULLG12_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2, 0, 21),
+ /* MDP_COLOR_FULLG12 */
+ MDP_COLOR_FULLG12_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 12, 2, 0, 21),
+ MDP_COLOR_FULLG12_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 12, 2, 0, 21),
+ MDP_COLOR_FULLG12_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 12, 2, 0, 21),
+ MDP_COLOR_FULLG12_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 12, 2, 0, 21),
MDP_COLOR_FULLG12 = MDP_COLOR_FULLG12_BGGR,
- //MDP_COLOR_FULLG14,
- MDP_COLOR_FULLG14_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 21),
- MDP_COLOR_FULLG14_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2, 0, 21),
- MDP_COLOR_FULLG14_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2, 0, 21),
- MDP_COLOR_FULLG14_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2, 0, 21),
+ /* MDP_COLOR_FULLG14 */
+ MDP_COLOR_FULLG14_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 14, 2, 0, 21),
+ MDP_COLOR_FULLG14_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 14, 2, 0, 21),
+ MDP_COLOR_FULLG14_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 14, 2, 0, 21),
+ MDP_COLOR_FULLG14_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 14, 2, 0, 21),
MDP_COLOR_FULLG14 = MDP_COLOR_FULLG14_BGGR,
- MDP_COLOR_UFO10 = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 24),
+ MDP_COLOR_UFO10 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 10, 2, 0, 24),
- //MDP_COLOR_BAYER8,
- MDP_COLOR_BAYER8_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 20),
- MDP_COLOR_BAYER8_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 8, 2, 0, 20),
- MDP_COLOR_BAYER8_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 8, 2, 0, 20),
- MDP_COLOR_BAYER8_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 8, 2, 0, 20),
+ /* MDP_COLOR_BAYER8 */
+ MDP_COLOR_BAYER8_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 8, 2, 0, 20),
+ MDP_COLOR_BAYER8_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 8, 2, 0, 20),
+ MDP_COLOR_BAYER8_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 8, 2, 0, 20),
+ MDP_COLOR_BAYER8_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 8, 2, 0, 20),
MDP_COLOR_BAYER8 = MDP_COLOR_BAYER8_BGGR,
- //MDP_COLOR_BAYER10,
- MDP_COLOR_BAYER10_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 20),
- MDP_COLOR_BAYER10_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2, 0, 20),
- MDP_COLOR_BAYER10_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2, 0, 20),
- MDP_COLOR_BAYER10_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2, 0, 20),
+ /* MDP_COLOR_BAYER10 */
+ MDP_COLOR_BAYER10_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 10, 2, 0, 20),
+ MDP_COLOR_BAYER10_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 10, 2, 0, 20),
+ MDP_COLOR_BAYER10_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 10, 2, 0, 20),
+ MDP_COLOR_BAYER10_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 10, 2, 0, 20),
MDP_COLOR_BAYER10 = MDP_COLOR_BAYER10_BGGR,
- //MDP_COLOR_BAYER12,
- MDP_COLOR_BAYER12_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 20),
- MDP_COLOR_BAYER12_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2, 0, 20),
- MDP_COLOR_BAYER12_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2, 0, 20),
- MDP_COLOR_BAYER12_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2, 0, 20),
+ /* MDP_COLOR_BAYER12 */
+ MDP_COLOR_BAYER12_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 12, 2, 0, 20),
+ MDP_COLOR_BAYER12_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 12, 2, 0, 20),
+ MDP_COLOR_BAYER12_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 12, 2, 0, 20),
+ MDP_COLOR_BAYER12_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 12, 2, 0, 20),
MDP_COLOR_BAYER12 = MDP_COLOR_BAYER12_BGGR,
- //MDP_COLOR_BAYER14,
- MDP_COLOR_BAYER14_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 20),
- MDP_COLOR_BAYER14_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2, 0, 20),
- MDP_COLOR_BAYER14_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2, 0, 20),
- MDP_COLOR_BAYER14_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2, 0, 20),
+ /* MDP_COLOR_BAYER14 */
+ MDP_COLOR_BAYER14_RGGB = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 14, 2, 0, 20),
+ MDP_COLOR_BAYER14_GRBG = MDP_COLOR(0, 0, 0, 0, 1, 0, 1, 14, 2, 0, 20),
+ MDP_COLOR_BAYER14_GBRG = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 14, 2, 0, 20),
+ MDP_COLOR_BAYER14_BGGR = MDP_COLOR(0, 0, 0, 0, 1, 1, 1, 14, 2, 0, 20),
MDP_COLOR_BAYER14 = MDP_COLOR_BAYER14_BGGR,
- MDP_COLOR_RGB48 = MDP_COLOR(0, 0, 0, 1, 0, 0, 48, 0, 0, 23),
+ MDP_COLOR_RGB48 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 48, 0, 0, 23),
/* For bayer+mono raw-16 */
- MDP_COLOR_RGB565_RAW = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 2, 0, 0),
+ MDP_COLOR_RGB565_RAW = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 16, 2, 0, 0),
- MDP_COLOR_BAYER8_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 22),
- MDP_COLOR_BAYER10_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 22),
- MDP_COLOR_BAYER12_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 22),
- MDP_COLOR_BAYER14_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 22),
+ MDP_COLOR_BAYER8_UNPAK = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 8, 2, 0, 22),
+ MDP_COLOR_BAYER10_UNPAK = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 10, 2, 0, 22),
+ MDP_COLOR_BAYER12_UNPAK = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 12, 2, 0, 22),
+ MDP_COLOR_BAYER14_UNPAK = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 14, 2, 0, 22),
/* Unified formats */
- MDP_COLOR_GREY = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 1, 0, 7),
-
- MDP_COLOR_RGB565 = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0, 0, 0),
- MDP_COLOR_BGR565 = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0, 1, 0),
- MDP_COLOR_RGB888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0, 1, 1),
- MDP_COLOR_BGR888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0, 0, 1),
- MDP_COLOR_RGBA8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 1, 2),
- MDP_COLOR_BGRA8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 0, 2),
- MDP_COLOR_ARGB8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 1, 3),
- MDP_COLOR_ABGR8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 0, 3),
-
- MDP_COLOR_UYVY = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 0, 4),
- MDP_COLOR_VYUY = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 1, 4),
- MDP_COLOR_YUYV = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 0, 5),
- MDP_COLOR_YVYU = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 1, 5),
-
- MDP_COLOR_I420 = MDP_COLOR(0, 0, 0, 3, 1, 1, 8, 1, 0, 8),
- MDP_COLOR_YV12 = MDP_COLOR(0, 0, 0, 3, 1, 1, 8, 1, 1, 8),
- MDP_COLOR_I422 = MDP_COLOR(0, 0, 0, 3, 1, 0, 8, 1, 0, 9),
- MDP_COLOR_YV16 = MDP_COLOR(0, 0, 0, 3, 1, 0, 8, 1, 1, 9),
- MDP_COLOR_I444 = MDP_COLOR(0, 0, 0, 3, 0, 0, 8, 1, 0, 10),
- MDP_COLOR_YV24 = MDP_COLOR(0, 0, 0, 3, 0, 0, 8, 1, 1, 10),
-
- MDP_COLOR_NV12 = MDP_COLOR(0, 0, 0, 2, 1, 1, 8, 1, 0, 12),
- MDP_COLOR_NV21 = MDP_COLOR(0, 0, 0, 2, 1, 1, 8, 1, 1, 12),
- MDP_COLOR_NV16 = MDP_COLOR(0, 0, 0, 2, 1, 0, 8, 1, 0, 13),
- MDP_COLOR_NV61 = MDP_COLOR(0, 0, 0, 2, 1, 0, 8, 1, 1, 13),
- MDP_COLOR_NV24 = MDP_COLOR(0, 0, 0, 2, 0, 0, 8, 1, 0, 14),
- MDP_COLOR_NV42 = MDP_COLOR(0, 0, 0, 2, 0, 0, 8, 1, 1, 14),
+ MDP_COLOR_GREY = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 8, 1, 0, 7),
+
+ MDP_COLOR_RGB565 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 16, 0, 0, 0),
+ MDP_COLOR_BGR565 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 16, 0, 1, 0),
+ MDP_COLOR_RGB888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 24, 0, 1, 1),
+ MDP_COLOR_BGR888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 24, 0, 0, 1),
+ MDP_COLOR_RGBA8888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 32, 0, 1, 2),
+ MDP_COLOR_BGRA8888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 32, 0, 0, 2),
+ MDP_COLOR_ARGB8888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 32, 0, 1, 3),
+ MDP_COLOR_ABGR8888 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 32, 0, 0, 3),
+
+ MDP_COLOR_UYVY = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 16, 1, 0, 4),
+ MDP_COLOR_VYUY = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 16, 1, 1, 4),
+ MDP_COLOR_YUYV = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 16, 1, 0, 5),
+ MDP_COLOR_YVYU = MDP_COLOR(0, 0, 0, 0, 1, 1, 0, 16, 1, 1, 5),
+
+ MDP_COLOR_I420 = MDP_COLOR(0, 0, 0, 0, 3, 1, 1, 8, 1, 0, 8),
+ MDP_COLOR_YV12 = MDP_COLOR(0, 0, 0, 0, 3, 1, 1, 8, 1, 1, 8),
+ MDP_COLOR_I422 = MDP_COLOR(0, 0, 0, 0, 3, 1, 0, 8, 1, 0, 9),
+ MDP_COLOR_YV16 = MDP_COLOR(0, 0, 0, 0, 3, 1, 0, 8, 1, 1, 9),
+ MDP_COLOR_I444 = MDP_COLOR(0, 0, 0, 0, 3, 0, 0, 8, 1, 0, 10),
+ MDP_COLOR_YV24 = MDP_COLOR(0, 0, 0, 0, 3, 0, 0, 8, 1, 1, 10),
+
+ MDP_COLOR_NV12 = MDP_COLOR(0, 0, 0, 0, 2, 1, 1, 8, 1, 0, 12),
+ MDP_COLOR_NV21 = MDP_COLOR(0, 0, 0, 0, 2, 1, 1, 8, 1, 1, 12),
+ MDP_COLOR_NV16 = MDP_COLOR(0, 0, 0, 0, 2, 1, 0, 8, 1, 0, 13),
+ MDP_COLOR_NV61 = MDP_COLOR(0, 0, 0, 0, 2, 1, 0, 8, 1, 1, 13),
+ MDP_COLOR_NV24 = MDP_COLOR(0, 0, 0, 0, 2, 0, 0, 8, 1, 0, 14),
+ MDP_COLOR_NV42 = MDP_COLOR(0, 0, 0, 0, 2, 0, 0, 8, 1, 1, 14),
/* MediaTek proprietary formats */
/* UFO encoded block mode */
- MDP_COLOR_420_BLK_UFO = MDP_COLOR(0, 0, 5, 2, 1, 1, 256, 1, 0, 12),
+ MDP_COLOR_420_BLK_UFO = MDP_COLOR(0, 0, 0, 5, 2, 1, 1, 256, 1, 0, 12),
/* Block mode */
- MDP_COLOR_420_BLK = MDP_COLOR(0, 0, 1, 2, 1, 1, 256, 1, 0, 12),
+ MDP_COLOR_420_BLK = MDP_COLOR(0, 0, 0, 1, 2, 1, 1, 256, 1, 0, 12),
/* Block mode + field mode */
- MDP_COLOR_420_BLKI = MDP_COLOR(0, 0, 3, 2, 1, 1, 256, 1, 0, 12),
+ MDP_COLOR_420_BLKI = MDP_COLOR(0, 0, 0, 3, 2, 1, 1, 256, 1, 0, 12),
/* Block mode */
- MDP_COLOR_422_BLK = MDP_COLOR(0, 0, 1, 1, 1, 0, 512, 1, 0, 4),
+ MDP_COLOR_422_BLK = MDP_COLOR(0, 0, 0, 1, 1, 1, 0, 512, 1, 0, 4),
- MDP_COLOR_IYU2 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 1, 0, 25),
- MDP_COLOR_YUV444 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 1, 0, 30),
+ MDP_COLOR_IYU2 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 24, 1, 0, 25),
+ MDP_COLOR_YUV444 = MDP_COLOR(0, 0, 0, 0, 1, 0, 0, 24, 1, 0, 30),
/* Packed 10-bit formats */
- MDP_COLOR_RGBA1010102 = MDP_COLOR(1, 0, 0, 1, 0, 0, 32, 0, 1, 2),
- MDP_COLOR_BGRA1010102 = MDP_COLOR(1, 0, 0, 1, 0, 0, 32, 0, 0, 2),
+ MDP_COLOR_RGBA1010102 = MDP_COLOR(0, 1, 0, 0, 1, 0, 0, 32, 0, 1, 2),
+ MDP_COLOR_BGRA1010102 = MDP_COLOR(0, 1, 0, 0, 1, 0, 0, 32, 0, 0, 2),
/* Packed 10-bit UYVY */
- MDP_COLOR_UYVY_10P = MDP_COLOR(1, 0, 0, 1, 1, 0, 20, 1, 0, 4),
+ MDP_COLOR_UYVY_10P = MDP_COLOR(0, 1, 0, 0, 1, 1, 0, 20, 1, 0, 4),
/* Packed 10-bit NV21 */
- MDP_COLOR_NV21_10P = MDP_COLOR(1, 0, 0, 2, 1, 1, 10, 1, 1, 12),
+ MDP_COLOR_NV21_10P = MDP_COLOR(0, 1, 0, 0, 2, 1, 1, 10, 1, 1, 12),
/* 10-bit block mode */
- MDP_COLOR_420_BLK_10_H = MDP_COLOR(1, 0, 1, 2, 1, 1, 320, 1, 0, 12),
+ MDP_COLOR_420_BLK_10_H = MDP_COLOR(0, 1, 0, 1, 2, 1, 1, 320, 1, 0, 12),
/* 10-bit HEVC tile mode */
- MDP_COLOR_420_BLK_10_V = MDP_COLOR(1, 1, 1, 2, 1, 1, 320, 1, 0, 12),
+ MDP_COLOR_420_BLK_10_V = MDP_COLOR(0, 1, 1, 1, 2, 1, 1, 320, 1, 0, 12),
/* UFO encoded 10-bit block mode */
- MDP_COLOR_420_BLK_U10_H = MDP_COLOR(1, 0, 5, 2, 1, 1, 320, 1, 0, 12),
+ MDP_COLOR_420_BLK_U10_H = MDP_COLOR(0, 1, 0, 5, 2, 1, 1, 320, 1, 0, 12),
/* UFO encoded 10-bit HEVC tile mode */
- MDP_COLOR_420_BLK_U10_V = MDP_COLOR(1, 1, 5, 2, 1, 1, 320, 1, 0, 12),
+ MDP_COLOR_420_BLK_U10_V = MDP_COLOR(0, 1, 1, 5, 2, 1, 1, 320, 1, 0, 12),
/* Loose 10-bit formats */
- MDP_COLOR_UYVY_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 0, 4),
- MDP_COLOR_VYUY_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 1, 4),
- MDP_COLOR_YUYV_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 0, 5),
- MDP_COLOR_YVYU_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 1, 5),
- MDP_COLOR_NV12_10L = MDP_COLOR(0, 1, 0, 2, 1, 1, 10, 1, 0, 12),
- MDP_COLOR_NV21_10L = MDP_COLOR(0, 1, 0, 2, 1, 1, 10, 1, 1, 12),
- MDP_COLOR_NV16_10L = MDP_COLOR(0, 1, 0, 2, 1, 0, 10, 1, 0, 13),
- MDP_COLOR_NV61_10L = MDP_COLOR(0, 1, 0, 2, 1, 0, 10, 1, 1, 13),
- MDP_COLOR_YV12_10L = MDP_COLOR(0, 1, 0, 3, 1, 1, 10, 1, 1, 8),
- MDP_COLOR_I420_10L = MDP_COLOR(0, 1, 0, 3, 1, 1, 10, 1, 0, 8),
+ MDP_COLOR_UYVY_10L = MDP_COLOR(0, 0, 1, 0, 1, 1, 0, 20, 1, 0, 4),
+ MDP_COLOR_VYUY_10L = MDP_COLOR(0, 0, 1, 0, 1, 1, 0, 20, 1, 1, 4),
+ MDP_COLOR_YUYV_10L = MDP_COLOR(0, 0, 1, 0, 1, 1, 0, 20, 1, 0, 5),
+ MDP_COLOR_YVYU_10L = MDP_COLOR(0, 0, 1, 0, 1, 1, 0, 20, 1, 1, 5),
+ MDP_COLOR_NV12_10L = MDP_COLOR(0, 0, 1, 0, 2, 1, 1, 10, 1, 0, 12),
+ MDP_COLOR_NV21_10L = MDP_COLOR(0, 0, 1, 0, 2, 1, 1, 10, 1, 1, 12),
+ MDP_COLOR_NV16_10L = MDP_COLOR(0, 0, 1, 0, 2, 1, 0, 10, 1, 0, 13),
+ MDP_COLOR_NV61_10L = MDP_COLOR(0, 0, 1, 0, 2, 1, 0, 10, 1, 1, 13),
+ MDP_COLOR_YV12_10L = MDP_COLOR(0, 0, 1, 0, 3, 1, 1, 10, 1, 1, 8),
+ MDP_COLOR_I420_10L = MDP_COLOR(0, 0, 1, 0, 3, 1, 1, 10, 1, 0, 8),
};
static inline bool MDP_COLOR_IS_UV_COPLANE(enum mdp_color c)
@@ -353,8 +354,11 @@ struct mdp_frameparam {
enum v4l2_quantization quant;
};
-int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f);
-const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
+struct mdp_dev;
+
+int mdp_enum_fmt_mplane(struct mdp_dev *mdp, struct v4l2_fmtdesc *f);
+const struct mdp_format *mdp_try_fmt_mplane(struct mdp_dev *mdp,
+ struct v4l2_format *f,
struct mdp_frameparam *param,
u32 ctx_id);
enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
@@ -368,6 +372,6 @@ void mdp_set_src_config(struct img_input *in,
struct mdp_frame *frame, struct vb2_buffer *vb);
void mdp_set_dst_config(struct img_output *out,
struct mdp_frame *frame, struct vb2_buffer *vb);
-int mdp_frameparam_init(struct mdp_frameparam *param);
+int mdp_frameparam_init(struct mdp_dev *mdp, struct mdp_frameparam *param);
#endif /* __MTK_MDP3_REGS_H__ */
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-type.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-type.h
new file mode 100644
index 000000000000..ae0396806152
--- /dev/null
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-type.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_TYPE_H__
+#define __MTK_MDP3_TYPE_H__
+
+#include <linux/types.h>
+
+#define IMG_MAX_HW_INPUTS 3
+#define IMG_MAX_HW_OUTPUTS 4
+#define IMG_MAX_PLANES 3
+#define IMG_MAX_COMPONENTS 20
+
+struct img_crop {
+ s32 left;
+ s32 top;
+ u32 width;
+ u32 height;
+ u32 left_subpix;
+ u32 top_subpix;
+ u32 width_subpix;
+ u32 height_subpix;
+} __packed;
+
+struct img_region {
+ s32 left;
+ s32 right;
+ s32 top;
+ s32 bottom;
+} __packed;
+
+struct img_offset {
+ s32 left;
+ s32 top;
+ u32 left_subpix;
+ u32 top_subpix;
+} __packed;
+
+struct img_mux {
+ u32 reg;
+ u32 value;
+ u32 subsys_id;
+} __packed;
+
+struct img_mmsys_ctrl {
+ struct img_mux sets[IMG_MAX_COMPONENTS * 2];
+ u32 num_sets;
+} __packed;
+
+#endif /* __MTK_MDP3_TYPE_H__ */
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c
index a72bed927bb6..49fc2e9d45dd 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c
@@ -10,7 +10,6 @@
#include "mtk-mdp3-core.h"
#define MDP_VPU_MESSAGE_TIMEOUT 500U
-#define vpu_alloc_size 0x600000
static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu)
{
@@ -19,23 +18,63 @@ static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu)
static int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu)
{
- if (vpu->work && vpu->work_addr)
- return 0;
+ struct device *dev;
- vpu->work = dma_alloc_coherent(scp_get_device(vpu->scp), vpu_alloc_size,
- &vpu->work_addr, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(vpu))
+ goto err_return;
- if (!vpu->work)
- return -ENOMEM;
- else
- return 0;
+ dev = scp_get_device(vpu->scp);
+
+ if (!vpu->param) {
+ vpu->param = dma_alloc_wc(dev, vpu->param_size,
+ &vpu->param_addr, GFP_KERNEL);
+ if (!vpu->param)
+ goto err_return;
+ }
+
+ if (!vpu->work) {
+ vpu->work = dma_alloc_wc(dev, vpu->work_size,
+ &vpu->work_addr, GFP_KERNEL);
+ if (!vpu->work)
+ goto err_free_param;
+ }
+
+ if (!vpu->config) {
+ vpu->config = dma_alloc_wc(dev, vpu->config_size,
+ &vpu->config_addr, GFP_KERNEL);
+ if (!vpu->config)
+ goto err_free_work;
+ }
+
+ return 0;
+
+err_free_work:
+ dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
+ vpu->work = NULL;
+err_free_param:
+ dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
+ vpu->param = NULL;
+err_return:
+ return -ENOMEM;
}
void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu)
{
+ struct device *dev;
+
+ if (IS_ERR_OR_NULL(vpu))
+ return;
+
+ dev = scp_get_device(vpu->scp);
+
+ if (vpu->param && vpu->param_addr)
+ dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
+
if (vpu->work && vpu->work_addr)
- dma_free_coherent(scp_get_device(vpu->scp), vpu_alloc_size,
- vpu->work, vpu->work_addr);
+ dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
+
+ if (vpu->config && vpu->config_addr)
+ dma_free_wc(dev, vpu->config_size, vpu->config, vpu->config_addr);
}
static void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len,
@@ -69,16 +108,16 @@ static void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len,
struct img_sw_addr *addr = (struct img_sw_addr *)data;
struct img_ipi_frameparam *param =
(struct img_ipi_frameparam *)(unsigned long)addr->va;
- struct mdp_vpu_ctx *ctx =
- (struct mdp_vpu_ctx *)(unsigned long)param->drv_data;
+ struct mdp_vpu_dev *vpu =
+ (struct mdp_vpu_dev *)(unsigned long)param->drv_data;
if (param->state) {
- struct mdp_dev *mdp = vpu_to_mdp(ctx->vpu_dev);
+ struct mdp_dev *mdp = vpu_to_mdp(vpu);
dev_err(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state);
}
- ctx->vpu_dev->status = param->state;
- complete(&ctx->vpu_dev->ipi_acked);
+ vpu->status = param->state;
+ complete(&vpu->ipi_acked);
}
int mdp_vpu_register(struct mdp_dev *mdp)
@@ -157,9 +196,6 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
struct mdp_ipi_init_msg msg = {
.drv_data = (unsigned long)vpu,
};
- size_t mem_size;
- phys_addr_t pool;
- const size_t pool_size = sizeof(struct mdp_config_pool);
struct mdp_dev *mdp = vpu_to_mdp(vpu);
int err;
@@ -172,34 +208,29 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
goto err_work_size;
/* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */
- mem_size = vpu_alloc_size;
+ mutex_lock(vpu->lock);
+ vpu->work_size = ALIGN(vpu->work_size, 64);
+ vpu->param_size = ALIGN(sizeof(struct img_ipi_frameparam), 64);
+ vpu->config_size = ALIGN(sizeof(struct img_config), 64);
err = mdp_vpu_shared_mem_alloc(vpu);
+ mutex_unlock(vpu->lock);
if (err) {
dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
goto err_mem_alloc;
}
- pool = ALIGN((uintptr_t)vpu->work + vpu->work_size, 8);
- if (pool + pool_size - (uintptr_t)vpu->work > mem_size) {
- dev_err(&mdp->pdev->dev,
- "VPU memory insufficient: %zx + %zx > %zx",
- vpu->work_size, pool_size, mem_size);
- err = -ENOMEM;
- goto err_mem_size;
- }
-
dev_dbg(&mdp->pdev->dev,
- "VPU work:%pK pa:%pad sz:%zx pool:%pa sz:%zx (mem sz:%zx)",
+ "VPU param:%pK pa:%pad sz:%zx, work:%pK pa:%pad sz:%zx, config:%pK pa:%pad sz:%zx",
+ vpu->param, &vpu->param_addr, vpu->param_size,
vpu->work, &vpu->work_addr, vpu->work_size,
- &pool, pool_size, mem_size);
- vpu->pool = (struct mdp_config_pool *)(uintptr_t)pool;
+ vpu->config, &vpu->config_addr, vpu->config_size);
+
msg.work_addr = vpu->work_addr;
msg.work_size = vpu->work_size;
err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
if (err)
goto err_work_size;
- memset(vpu->pool, 0, sizeof(*vpu->pool));
return 0;
err_work_size:
@@ -212,7 +243,6 @@ err_work_size:
break;
}
return err;
-err_mem_size:
err_mem_alloc:
return err;
}
@@ -227,88 +257,31 @@ int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu)
return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg));
}
-static struct img_config *mdp_config_get(struct mdp_vpu_dev *vpu,
- enum mdp_config_id id, uint32_t *addr)
+int mdp_vpu_process(struct mdp_vpu_dev *vpu, struct img_ipi_frameparam *param)
{
- struct img_config *config;
-
- if (id < 0 || id >= MDP_CONFIG_POOL_SIZE)
- return ERR_PTR(-EINVAL);
+ struct mdp_dev *mdp = vpu_to_mdp(vpu);
+ struct img_sw_addr addr;
mutex_lock(vpu->lock);
- vpu->pool->cfg_count[id]++;
- config = &vpu->pool->configs[id];
- *addr = vpu->work_addr + ((uintptr_t)config - (uintptr_t)vpu->work);
- mutex_unlock(vpu->lock);
-
- return config;
-}
-
-static int mdp_config_put(struct mdp_vpu_dev *vpu,
- enum mdp_config_id id,
- const struct img_config *config)
-{
- int err = 0;
-
- if (id < 0 || id >= MDP_CONFIG_POOL_SIZE)
- return -EINVAL;
- if (vpu->lock)
- mutex_lock(vpu->lock);
- if (!vpu->pool->cfg_count[id] || config != &vpu->pool->configs[id])
- err = -EINVAL;
- else
- vpu->pool->cfg_count[id]--;
- if (vpu->lock)
+ if (mdp_vpu_shared_mem_alloc(vpu)) {
+ dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
mutex_unlock(vpu->lock);
- return err;
-}
-
-int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu,
- enum mdp_config_id id)
-{
- ctx->config = mdp_config_get(vpu, id, &ctx->inst_addr);
- if (IS_ERR(ctx->config)) {
- int err = PTR_ERR(ctx->config);
-
- ctx->config = NULL;
- return err;
+ return -ENOMEM;
}
- ctx->config_id = id;
- ctx->vpu_dev = vpu;
- return 0;
-}
-int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx)
-{
- int err = mdp_config_put(ctx->vpu_dev, ctx->config_id, ctx->config);
+ memset(vpu->param, 0, vpu->param_size);
+ memset(vpu->work, 0, vpu->work_size);
+ memset(vpu->config, 0, vpu->config_size);
- ctx->config_id = 0;
- ctx->config = NULL;
- ctx->inst_addr = 0;
- return err;
-}
+ param->self_data.va = (unsigned long)vpu->work;
+ param->self_data.pa = vpu->work_addr;
+ param->config_data.va = (unsigned long)vpu->config;
+ param->config_data.pa = vpu->config_addr;
+ param->drv_data = (unsigned long)vpu;
+ memcpy(vpu->param, param, sizeof(*param));
-int mdp_vpu_process(struct mdp_vpu_ctx *ctx, struct img_ipi_frameparam *param)
-{
- struct mdp_vpu_dev *vpu = ctx->vpu_dev;
- struct mdp_dev *mdp = vpu_to_mdp(vpu);
- struct img_sw_addr addr;
-
- if (!ctx->vpu_dev->work || !ctx->vpu_dev->work_addr) {
- if (mdp_vpu_shared_mem_alloc(vpu)) {
- dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
- return -ENOMEM;
- }
- }
- memset((void *)ctx->vpu_dev->work, 0, ctx->vpu_dev->work_size);
- memset(ctx->config, 0, sizeof(*ctx->config));
- param->config_data.va = (unsigned long)ctx->config;
- param->config_data.pa = ctx->inst_addr;
- param->drv_data = (unsigned long)ctx;
-
- memcpy((void *)ctx->vpu_dev->work, param, sizeof(*param));
- addr.pa = ctx->vpu_dev->work_addr;
- addr.va = (uintptr_t)ctx->vpu_dev->work;
- return mdp_vpu_sendmsg(ctx->vpu_dev, SCP_IPI_MDP_FRAME,
- &addr, sizeof(addr));
+ addr.pa = vpu->param_addr;
+ addr.va = (unsigned long)vpu->param;
+ mutex_unlock(vpu->lock);
+ return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_FRAME, &addr, sizeof(addr));
}
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h
index 244b3a32d689..ad3551bc0730 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h
@@ -37,42 +37,27 @@ struct mdp_ipi_deinit_msg {
u32 work_addr;
} __packed;
-enum mdp_config_id {
- MDP_DEV_M2M = 0,
- MDP_CONFIG_POOL_SIZE /* ALWAYS keep at the end */
-};
-
-struct mdp_config_pool {
- u64 cfg_count[MDP_CONFIG_POOL_SIZE];
- struct img_config configs[MDP_CONFIG_POOL_SIZE];
-};
-
struct mdp_vpu_dev {
/* synchronization protect for accessing vpu working buffer info */
struct mutex *lock;
struct mtk_scp *scp;
struct completion ipi_acked;
+ void *param;
+ dma_addr_t param_addr;
+ size_t param_size;
void *work;
dma_addr_t work_addr;
size_t work_size;
- struct mdp_config_pool *pool;
+ void *config;
+ dma_addr_t config_addr;
+ size_t config_size;
u32 status;
};
-struct mdp_vpu_ctx {
- struct mdp_vpu_dev *vpu_dev;
- u32 config_id;
- struct img_config *config;
- u32 inst_addr;
-};
-
void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu);
int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
struct mutex *lock /* for sync */);
int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu);
-int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu,
- enum mdp_config_id id);
-int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx);
-int mdp_vpu_process(struct mdp_vpu_ctx *vpu, struct img_ipi_frameparam *param);
+int mdp_vpu_process(struct mdp_vpu_dev *vpu, struct img_ipi_frameparam *param);
#endif /* __MTK_MDP3_VPU_H__ */
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
index 641f533c417f..93fcea821001 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
@@ -39,10 +39,9 @@ static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_ctx *ctx, int format_index)
{
const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
const struct mtk_video_fmt *fmt;
- struct mtk_q_data *q_data;
int num_frame_count = 0, i;
- bool ret = true;
+ fmt = &dec_pdata->vdec_formats[format_index];
for (i = 0; i < *dec_pdata->num_formats; i++) {
if (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
continue;
@@ -50,27 +49,10 @@ static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_ctx *ctx, int format_index)
num_frame_count++;
}
- if (num_frame_count == 1)
+ if (num_frame_count == 1 || fmt->fourcc == V4L2_PIX_FMT_MM21)
return true;
- fmt = &dec_pdata->vdec_formats[format_index];
- q_data = &ctx->q_data[MTK_Q_DATA_SRC];
- switch (q_data->fmt->fourcc) {
- case V4L2_PIX_FMT_VP8_FRAME:
- if (fmt->fourcc == V4L2_PIX_FMT_MM21)
- ret = true;
- break;
- case V4L2_PIX_FMT_H264_SLICE:
- case V4L2_PIX_FMT_VP9_FRAME:
- if (fmt->fourcc == V4L2_PIX_FMT_MM21)
- ret = false;
- break;
- default:
- ret = true;
- break;
- }
-
- return ret;
+ return false;
}
static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
@@ -753,6 +735,13 @@ int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
}
if (*nplanes) {
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (*nplanes != q_data->fmt->num_planes)
+ return -EINVAL;
+ } else {
+ if (*nplanes != 1)
+ return -EINVAL;
+ }
for (i = 0; i < *nplanes; i++) {
if (sizes[i] < q_data->sizeimage[i])
return -EINVAL;
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
index 174a6eec2f54..9ba5dc5df648 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
@@ -321,7 +321,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
}
}
- if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL)) {
+ if (of_property_present(pdev->dev.of_node, "dma-ranges")) {
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
if (ret) {
mtk_v4l2_err("Failed to set mask");
@@ -451,7 +451,8 @@ err_core_workq:
if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch))
destroy_workqueue(dev->core_workqueue);
err_res:
- pm_runtime_disable(dev->pm.dev);
+ if (!dev->vdec_pdata->is_subdev_supported)
+ pm_runtime_disable(dev->pm.dev);
err_dec_pm:
mtk_vcodec_fw_release(dev->fw_handler);
return ret;
@@ -487,7 +488,7 @@ static const struct of_device_id mtk_vcodec_match[] = {
MODULE_DEVICE_TABLE(of, mtk_vcodec_match);
-static int mtk_vcodec_dec_remove(struct platform_device *pdev)
+static void mtk_vcodec_dec_remove(struct platform_device *pdev)
{
struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
@@ -509,12 +510,11 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev)
if (!dev->vdec_pdata->is_subdev_supported)
pm_runtime_disable(dev->pm.dev);
mtk_vcodec_fw_release(dev->fw_handler);
- return 0;
}
static struct platform_driver mtk_vcodec_dec_driver = {
.probe = mtk_vcodec_probe,
- .remove = mtk_vcodec_dec_remove,
+ .remove_new = mtk_vcodec_dec_remove,
.driver = {
.name = MTK_VCODEC_DEC_NAME,
.of_match_table = mtk_vcodec_match,
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
index 376db0e433d7..b753bf54ebd9 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
@@ -193,8 +193,16 @@ err:
return ret;
}
+static int mtk_vdec_hw_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
static struct platform_driver mtk_vdec_driver = {
.probe = mtk_vdec_hw_probe,
+ .remove = mtk_vdec_hw_remove,
.driver = {
.name = "mtk-vdec-comp",
.of_match_table = mtk_vdec_hw_match,
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
index 035c86e7809f..29991551cf61 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
@@ -11,7 +11,7 @@
#include "mtk_vcodec_dec_pm.h"
#include "vdec_drv_if.h"
-static const struct mtk_video_fmt mtk_video_formats[] = {
+static struct mtk_video_fmt mtk_video_formats[] = {
{
.fourcc = V4L2_PIX_FMT_H264,
.type = MTK_FMT_DEC,
@@ -580,6 +580,16 @@ static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
{
+ unsigned int i;
+
+ if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED)) {
+ for (i = 0; i < num_supported_formats; i++) {
+ mtk_video_formats[i].frmsize.max_width =
+ VCODEC_DEC_4K_CODED_WIDTH;
+ mtk_video_formats[i].frmsize.max_height =
+ VCODEC_DEC_4K_CODED_HEIGHT;
+ }
+ }
}
static struct vb2_ops mtk_vdec_frame_vb2_ops = {
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
index ffbcee04dc26..3000db975e5f 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
@@ -258,8 +258,10 @@ static void mtk_vdec_worker(struct work_struct *work)
if (src_buf_req)
v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
} else {
- v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- v4l2_m2m_buf_done(vb2_v4l2_src, state);
+ if (ret != -EAGAIN) {
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ v4l2_m2m_buf_done(vb2_v4l2_src, state);
+ }
v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
}
}
@@ -390,14 +392,14 @@ static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx)
if (num_formats)
return;
- if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) {
- mtk_vcodec_add_formats(V4L2_PIX_FMT_MM21, ctx);
- cap_format_count++;
- }
if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MT21C) {
mtk_vcodec_add_formats(V4L2_PIX_FMT_MT21C, ctx);
cap_format_count++;
}
+ if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) {
+ mtk_vcodec_add_formats(V4L2_PIX_FMT_MM21, ctx);
+ cap_format_count++;
+ }
if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_H264_SLICE) {
mtk_vcodec_add_formats(V4L2_PIX_FMT_H264_SLICE, ctx);
out_format_count++;
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
index d65800a3b89d..db65e77bd373 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
@@ -943,7 +943,7 @@ err_start_stream:
* FIXME: This check is not needed as only active buffers
* can be marked as done.
*/
- if (buf->state == VB2_BUF_STATE_ACTIVE) {
+ if (buf && buf->state == VB2_BUF_STATE_ACTIVE) {
mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED",
ctx->id, i, q->type,
(int)buf->state);
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
index 9095186d5495..755f567b9e54 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
@@ -89,16 +89,24 @@ static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv)
struct mtk_vcodec_ctx *ctx;
unsigned long flags;
void __iomem *addr;
+ int core_id;
spin_lock_irqsave(&dev->irqlock, flags);
ctx = dev->curr_ctx;
spin_unlock_irqrestore(&dev->irqlock, flags);
- mtk_v4l2_debug(1, "id=%d coreid:%d", ctx->id, dev->venc_pdata->core_id);
- addr = dev->reg_base[dev->venc_pdata->core_id] +
- MTK_VENC_IRQ_ACK_OFFSET;
+ core_id = dev->venc_pdata->core_id;
+ if (core_id < 0 || core_id >= NUM_MAX_VCODEC_REG_BASE) {
+ mtk_v4l2_err("Invalid core id: %d, ctx id: %d",
+ core_id, ctx->id);
+ return IRQ_HANDLED;
+ }
+
+ mtk_v4l2_debug(1, "id: %d, core id: %d", ctx->id, core_id);
- ctx->irq_status = readl(dev->reg_base[dev->venc_pdata->core_id] +
+ addr = dev->reg_base[core_id] + MTK_VENC_IRQ_ACK_OFFSET;
+
+ ctx->irq_status = readl(dev->reg_base[core_id] +
(MTK_VENC_IRQ_STATUS_OFFSET));
clean_irq_status(ctx->irq_status, addr);
@@ -344,7 +352,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_event_workq;
}
- if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ if (of_property_present(pdev->dev.of_node, "dma-ranges"))
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1);
@@ -451,7 +459,7 @@ static const struct of_device_id mtk_vcodec_enc_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
-static int mtk_vcodec_enc_remove(struct platform_device *pdev)
+static void mtk_vcodec_enc_remove(struct platform_device *pdev)
{
struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
@@ -466,12 +474,11 @@ static int mtk_vcodec_enc_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
pm_runtime_disable(dev->pm.dev);
mtk_vcodec_fw_release(dev->fw_handler);
- return 0;
}
static struct platform_driver mtk_vcodec_enc_driver = {
.probe = mtk_vcodec_probe,
- .remove = mtk_vcodec_enc_remove,
+ .remove_new = mtk_vcodec_enc_remove,
.driver = {
.name = MTK_VCODEC_ENC_NAME,
.of_match_table = mtk_vcodec_enc_match,
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
index 955b2d0c8f53..999ce7ee5fdc 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
@@ -597,7 +597,7 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
lat_buf = vdec_msg_queue_dqbuf(&inst->ctx->msg_queue.lat_ctx);
if (!lat_buf) {
mtk_vcodec_err(inst, "failed to get lat buffer");
- return -EINVAL;
+ return -EAGAIN;
}
share_info = lat_buf->private_data;
src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer);
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
index cbb6728b8a40..cf16cf2807f0 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
@@ -2070,7 +2070,7 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
lat_buf = vdec_msg_queue_dqbuf(&instance->ctx->msg_queue.lat_ctx);
if (!lat_buf) {
mtk_vcodec_err(instance, "Failed to get VP9 lat buf\n");
- return -EBUSY;
+ return -EAGAIN;
}
pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data;
if (!pfc) {
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
index dc2004790a47..f3073d1e7f42 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c
@@ -52,9 +52,26 @@ static struct list_head *vdec_get_buf_list(int hardware_index, struct vdec_lat_b
}
}
+static void vdec_msg_queue_inc(struct vdec_msg_queue *msg_queue, int hardware_index)
+{
+ if (hardware_index == MTK_VDEC_CORE)
+ atomic_inc(&msg_queue->core_list_cnt);
+ else
+ atomic_inc(&msg_queue->lat_list_cnt);
+}
+
+static void vdec_msg_queue_dec(struct vdec_msg_queue *msg_queue, int hardware_index)
+{
+ if (hardware_index == MTK_VDEC_CORE)
+ atomic_dec(&msg_queue->core_list_cnt);
+ else
+ atomic_dec(&msg_queue->lat_list_cnt);
+}
+
int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf *buf)
{
struct list_head *head;
+ int status;
head = vdec_get_buf_list(msg_ctx->hardware_index, buf);
if (!head) {
@@ -66,11 +83,18 @@ int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf
list_add_tail(head, &msg_ctx->ready_queue);
msg_ctx->ready_num++;
- if (msg_ctx->hardware_index != MTK_VDEC_CORE)
+ vdec_msg_queue_inc(&buf->ctx->msg_queue, msg_ctx->hardware_index);
+ if (msg_ctx->hardware_index != MTK_VDEC_CORE) {
wake_up_all(&msg_ctx->ready_to_use);
- else
- queue_work(buf->ctx->dev->core_workqueue,
- &buf->ctx->msg_queue.core_work);
+ } else {
+ if (buf->ctx->msg_queue.core_work_cnt <
+ atomic_read(&buf->ctx->msg_queue.core_list_cnt)) {
+ status = queue_work(buf->ctx->dev->core_workqueue,
+ &buf->ctx->msg_queue.core_work);
+ if (status)
+ buf->ctx->msg_queue.core_work_cnt++;
+ }
+ }
mtk_v4l2_debug(3, "enqueue buf type: %d addr: 0x%p num: %d",
msg_ctx->hardware_index, buf, msg_ctx->ready_num);
@@ -127,6 +151,7 @@ struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *msg_ctx)
return NULL;
}
list_del(head);
+ vdec_msg_queue_dec(&buf->ctx->msg_queue, msg_ctx->hardware_index);
msg_ctx->ready_num--;
mtk_v4l2_debug(3, "dqueue buf type:%d addr: 0x%p num: %d",
@@ -156,11 +181,29 @@ void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t u
bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
{
+ struct vdec_lat_buf *buf, *tmp;
+ struct list_head *list_core[3];
+ struct vdec_msg_queue_ctx *core_ctx;
+ int ret, i, in_core_count = 0, count = 0;
long timeout_jiff;
- int ret;
+
+ core_ctx = &msg_queue->ctx->dev->msg_queue_core_ctx;
+ spin_lock(&core_ctx->ready_lock);
+ list_for_each_entry_safe(buf, tmp, &core_ctx->ready_queue, core_list) {
+ if (buf && buf->ctx == msg_queue->ctx) {
+ list_core[in_core_count++] = &buf->core_list;
+ list_del(&buf->core_list);
+ }
+ }
+
+ for (i = 0; i < in_core_count; i++) {
+ list_add(list_core[in_core_count - (1 + i)], &core_ctx->ready_queue);
+ queue_work(msg_queue->ctx->dev->core_workqueue, &msg_queue->core_work);
+ }
+ spin_unlock(&core_ctx->ready_lock);
timeout_jiff = msecs_to_jiffies(1000 * (NUM_BUFFER_COUNT + 2));
- ret = wait_event_timeout(msg_queue->lat_ctx.ready_to_use,
+ ret = wait_event_timeout(msg_queue->ctx->msg_queue.core_dec_done,
msg_queue->lat_ctx.ready_num == NUM_BUFFER_COUNT,
timeout_jiff);
if (ret) {
@@ -168,8 +211,20 @@ bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
msg_queue->lat_ctx.ready_num);
return true;
}
- mtk_v4l2_err("failed with lat buf isn't full: %d",
- msg_queue->lat_ctx.ready_num);
+
+ spin_lock(&core_ctx->ready_lock);
+ list_for_each_entry_safe(buf, tmp, &core_ctx->ready_queue, core_list) {
+ if (buf && buf->ctx == msg_queue->ctx) {
+ count++;
+ list_del(&buf->core_list);
+ }
+ }
+ spin_unlock(&core_ctx->ready_lock);
+
+ mtk_v4l2_err("failed with lat buf isn't full: list(%d %d) count:%d",
+ atomic_read(&msg_queue->lat_list_cnt),
+ atomic_read(&msg_queue->core_list_cnt), count);
+
return false;
}
@@ -206,6 +261,7 @@ static void vdec_msg_queue_core_work(struct work_struct *work)
container_of(msg_queue, struct mtk_vcodec_ctx, msg_queue);
struct mtk_vcodec_dev *dev = ctx->dev;
struct vdec_lat_buf *lat_buf;
+ int status;
lat_buf = vdec_msg_queue_dqbuf(&dev->msg_queue_core_ctx);
if (!lat_buf)
@@ -221,11 +277,18 @@ static void vdec_msg_queue_core_work(struct work_struct *work)
mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE);
vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);
- if (!list_empty(&dev->msg_queue_core_ctx.ready_queue)) {
- mtk_v4l2_debug(3, "re-schedule to decode for core: %d",
- dev->msg_queue_core_ctx.ready_num);
- queue_work(dev->core_workqueue, &msg_queue->core_work);
+ wake_up_all(&ctx->msg_queue.core_dec_done);
+ spin_lock(&dev->msg_queue_core_ctx.ready_lock);
+ lat_buf->ctx->msg_queue.core_work_cnt--;
+
+ if (lat_buf->ctx->msg_queue.core_work_cnt <
+ atomic_read(&lat_buf->ctx->msg_queue.core_list_cnt)) {
+ status = queue_work(lat_buf->ctx->dev->core_workqueue,
+ &lat_buf->ctx->msg_queue.core_work);
+ if (status)
+ lat_buf->ctx->msg_queue.core_work_cnt++;
}
+ spin_unlock(&dev->msg_queue_core_ctx.ready_lock);
}
int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
@@ -239,12 +302,18 @@ int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
if (msg_queue->wdma_addr.size)
return 0;
+ msg_queue->ctx = ctx;
+ msg_queue->core_work_cnt = 0;
vdec_msg_queue_init_ctx(&msg_queue->lat_ctx, MTK_VDEC_LAT0);
INIT_WORK(&msg_queue->core_work, vdec_msg_queue_core_work);
+
+ atomic_set(&msg_queue->lat_list_cnt, 0);
+ atomic_set(&msg_queue->core_list_cnt, 0);
+ init_waitqueue_head(&msg_queue->core_dec_done);
+
msg_queue->wdma_addr.size =
vde_msg_queue_get_trans_size(ctx->picinfo.buf_w,
ctx->picinfo.buf_h);
-
err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
if (err) {
mtk_v4l2_err("failed to allocate wdma_addr buf");
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h
index c43d427f5f54..a5d44bc97c16 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h
+++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h
@@ -72,6 +72,12 @@ struct vdec_lat_buf {
* @wdma_wptr_addr: ube write point
* @core_work: core hardware work
* @lat_ctx: used to store lat buffer list
+ * @ctx: point to mtk_vcodec_ctx
+ *
+ * @lat_list_cnt: used to record each instance lat list count
+ * @core_list_cnt: used to record each instance core list count
+ * @core_dec_done: core work queue decode done event
+ * @core_work_cnt: the number of core work in work queue
*/
struct vdec_msg_queue {
struct vdec_lat_buf lat_buf[NUM_BUFFER_COUNT];
@@ -82,6 +88,12 @@ struct vdec_msg_queue {
struct work_struct core_work;
struct vdec_msg_queue_ctx lat_ctx;
+ struct mtk_vcodec_ctx *ctx;
+
+ atomic_t lat_list_cnt;
+ atomic_t core_list_cnt;
+ wait_queue_head_t core_dec_done;
+ int core_work_cnt;
};
/**
diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c
index 47b684b92f81..5e2bc286f168 100644
--- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c
+++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c
@@ -953,7 +953,7 @@ static const struct of_device_id mtk_vpu_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_vpu_match);
-static int mtk_vpu_remove(struct platform_device *pdev)
+static void mtk_vpu_remove(struct platform_device *pdev)
{
struct mtk_vpu *vpu = platform_get_drvdata(pdev);
@@ -966,8 +966,6 @@ static int mtk_vpu_remove(struct platform_device *pdev)
vpu_free_ext_mem(vpu, D_FW);
mutex_destroy(&vpu->vpu_mutex);
clk_unprepare(vpu->clk);
-
- return 0;
}
static int mtk_vpu_suspend(struct device *dev)
@@ -1040,7 +1038,7 @@ static const struct dev_pm_ops mtk_vpu_pm = {
static struct platform_driver mtk_vpu_driver = {
.probe = mtk_vpu_probe,
- .remove = mtk_vpu_remove,
+ .remove_new = mtk_vpu_remove,
.driver = {
.name = "mtk_vpu",
.pm = &mtk_vpu_pm,
diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index d5b359f607ae..bfb3edcf018a 100644
--- a/drivers/media/platform/microchip/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
@@ -741,7 +741,7 @@ csi2dc_probe_cleanup_entity:
return ret;
}
-static int csi2dc_remove(struct platform_device *pdev)
+static void csi2dc_remove(struct platform_device *pdev)
{
struct csi2dc_device *csi2dc = platform_get_drvdata(pdev);
@@ -751,8 +751,6 @@ static int csi2dc_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&csi2dc->notifier);
v4l2_async_nf_cleanup(&csi2dc->notifier);
media_entity_cleanup(&csi2dc->csi2dc_sd.entity);
-
- return 0;
}
static int __maybe_unused csi2dc_runtime_suspend(struct device *dev)
@@ -782,7 +780,7 @@ MODULE_DEVICE_TABLE(of, csi2dc_of_match);
static struct platform_driver csi2dc_driver = {
.probe = csi2dc_probe,
- .remove = csi2dc_remove,
+ .remove_new = csi2dc_remove,
.driver = {
.name = "microchip-csi2dc",
.pm = &csi2dc_dev_pm_ops,
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 71758ee8474b..4e657fad33d0 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -858,8 +858,10 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
static void isc_try_fse(struct isc_device *isc,
struct v4l2_subdev_state *sd_state)
{
+ struct v4l2_subdev_frame_size_enum fse = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ };
int ret;
- struct v4l2_subdev_frame_size_enum fse = {};
/*
* If we do not know yet which format the subdev is using, we cannot
@@ -869,7 +871,6 @@ static void isc_try_fse(struct isc_device *isc,
return;
fse.code = isc->try_config.sd_format->mbus_code;
- fse.which = V4L2_SUBDEV_FORMAT_TRY;
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
sd_state, &fse);
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index ac4715d91de6..746f4a2fa9f6 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -608,7 +608,7 @@ unprepare_hclk:
return ret;
}
-static int microchip_isc_remove(struct platform_device *pdev)
+static void microchip_isc_remove(struct platform_device *pdev)
{
struct isc_device *isc = platform_get_drvdata(pdev);
@@ -624,8 +624,6 @@ static int microchip_isc_remove(struct platform_device *pdev)
clk_disable_unprepare(isc->hclock);
microchip_isc_clk_cleanup(isc);
-
- return 0;
}
static int __maybe_unused isc_runtime_suspend(struct device *dev)
@@ -668,7 +666,7 @@ MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
static struct platform_driver microchip_isc_driver = {
.probe = microchip_isc_probe,
- .remove = microchip_isc_remove,
+ .remove_new = microchip_isc_remove,
.driver = {
.name = "microchip-sama5d2-isc",
.pm = &microchip_isc_dev_pm_ops,
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index d583eafe5cc1..79ae696764d0 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -577,7 +577,7 @@ unprepare_hclk:
return ret;
}
-static int microchip_xisc_remove(struct platform_device *pdev)
+static void microchip_xisc_remove(struct platform_device *pdev)
{
struct isc_device *isc = platform_get_drvdata(pdev);
@@ -592,8 +592,6 @@ static int microchip_xisc_remove(struct platform_device *pdev)
clk_disable_unprepare(isc->hclock);
microchip_isc_clk_cleanup(isc);
-
- return 0;
}
static int __maybe_unused xisc_runtime_suspend(struct device *dev)
@@ -631,7 +629,7 @@ MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
static struct platform_driver microchip_xisc_driver = {
.probe = microchip_xisc_probe,
- .remove = microchip_xisc_remove,
+ .remove_new = microchip_xisc_remove,
.driver = {
.name = "microchip-sama7g5-xisc",
.pm = &microchip_xisc_dev_pm_ops,
diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c
index f3e863a94c5a..7157734a1550 100644
--- a/drivers/media/platform/nvidia/tegra-vde/vde.c
+++ b/drivers/media/platform/nvidia/tegra-vde/vde.c
@@ -378,7 +378,7 @@ err_gen_free:
return err;
}
-static int tegra_vde_remove(struct platform_device *pdev)
+static void tegra_vde_remove(struct platform_device *pdev)
{
struct tegra_vde *vde = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -407,8 +407,6 @@ static int tegra_vde_remove(struct platform_device *pdev)
gen_pool_free(vde->iram_pool, (unsigned long)vde->iram,
gen_pool_size(vde->iram_pool));
-
- return 0;
}
static void tegra_vde_shutdown(struct platform_device *pdev)
@@ -536,7 +534,7 @@ MODULE_DEVICE_TABLE(of, tegra_vde_of_match);
static struct platform_driver tegra_vde_driver = {
.probe = tegra_vde_probe,
- .remove = tegra_vde_remove,
+ .remove_new = tegra_vde_remove,
.shutdown = tegra_vde_shutdown,
.driver = {
.name = "tegra-vde",
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 730f39971e1c..a0ca6b297fb8 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -28,6 +28,8 @@ config VIDEO_IMX_MIPI_CSIS
Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver
v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs.
+source "drivers/media/platform/nxp/imx8-isi/Kconfig"
+
# mem2mem drivers
config VIDEO_IMX_PXP
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 1a129b58d99e..b8e672b75fed 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -2,6 +2,7 @@
obj-y += dw100/
obj-y += imx-jpeg/
+obj-y += imx8-isi/
obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c
index 189d60cd5ed1..0024d6175ad9 100644
--- a/drivers/media/platform/nxp/dw100/dw100.c
+++ b/drivers/media/platform/nxp/dw100/dw100.c
@@ -1532,7 +1532,6 @@ static int dw100_probe(struct platform_device *pdev)
{
struct dw100_device *dw_dev;
struct video_device *vfd;
- struct resource *res;
int ret, irq;
dw_dev = devm_kzalloc(&pdev->dev, sizeof(*dw_dev), GFP_KERNEL);
@@ -1547,8 +1546,7 @@ static int dw100_probe(struct platform_device *pdev)
}
dw_dev->num_clks = ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dw_dev->mmio = devm_ioremap_resource(&pdev->dev, res);
+ dw_dev->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(dw_dev->mmio))
return PTR_ERR(dw_dev->mmio);
@@ -1633,7 +1631,7 @@ err_pm:
return ret;
}
-static int dw100_remove(struct platform_device *pdev)
+static void dw100_remove(struct platform_device *pdev)
{
struct dw100_device *dw_dev = platform_get_drvdata(pdev);
@@ -1649,8 +1647,6 @@ static int dw100_remove(struct platform_device *pdev)
mutex_destroy(dw_dev->vfd.lock);
v4l2_m2m_release(dw_dev->m2m_dev);
v4l2_device_unregister(&dw_dev->v4l2_dev);
-
- return 0;
}
static int __maybe_unused dw100_runtime_suspend(struct device *dev)
@@ -1692,7 +1688,7 @@ MODULE_DEVICE_TABLE(of, dw100_dt_ids);
static struct platform_driver dw100_driver = {
.probe = dw100_probe,
- .remove = dw100_remove,
+ .remove_new = dw100_remove,
.driver = {
.name = DRV_NAME,
.pm = &dw100_pm,
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
index ef28122a5ed4..9a6e8b332e12 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
@@ -97,25 +97,31 @@ void mxc_jpeg_sw_reset(void __iomem *reg)
writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL);
}
-void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg)
+void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg, u8 extseq)
{
dev_dbg(dev, "CAST Encoder CONFIG...\n");
/*
* "Config_Mode" enabled, "Config_Mode auto clear enabled",
*/
- writel(0xa0, reg + CAST_MODE);
+ if (extseq)
+ writel(0xb0, reg + CAST_MODE);
+ else
+ writel(0xa0, reg + CAST_MODE);
/* all markers and segments */
writel(0x3ff, reg + CAST_CFG_MODE);
}
-void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg)
+void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg, u8 extseq)
{
dev_dbg(dev, "CAST Encoder GO...\n");
/*
* "GO" enabled, "GO bit auto clear" enabled
*/
- writel(0x140, reg + CAST_MODE);
+ if (extseq)
+ writel(0x150, reg + CAST_MODE);
+ else
+ writel(0x140, reg + CAST_MODE);
}
void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality)
@@ -178,3 +184,8 @@ void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot)
writel(desc | MXC_NXT_DESCPT_EN,
reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
}
+
+void mxc_jpeg_clr_desc(void __iomem *reg, int slot)
+{
+ writel(0, reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
+}
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
index ecf3b6562ba2..ed15ea348f97 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
@@ -117,8 +117,8 @@ void print_wrapper_info(struct device *dev, void __iomem *reg);
void mxc_jpeg_sw_reset(void __iomem *reg);
int mxc_jpeg_enable(void __iomem *reg);
void wait_frmdone(struct device *dev, void __iomem *reg);
-void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg);
-void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg);
+void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg, u8 extseq);
+void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg, u8 extseq);
void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality);
void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg);
int mxc_jpeg_get_slot(void __iomem *reg);
@@ -137,6 +137,7 @@ void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize);
void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h);
void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch);
void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot);
+void mxc_jpeg_clr_desc(void __iomem *reg, int slot);
void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc,
void __iomem *reg);
#endif
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index f085f14d676a..c0e49be42450 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -88,6 +88,20 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.is_rgb = 1,
},
{
+ .name = "BGR 12bit", /*12-bit BGR packed format*/
+ .fourcc = V4L2_PIX_FMT_BGR48_12,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ .nc = 3,
+ .depth = 36,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ .is_rgb = 1,
+ },
+ {
.name = "ABGR", /* ABGR packed format */
.fourcc = V4L2_PIX_FMT_ABGR32,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
@@ -102,6 +116,20 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.is_rgb = 1,
},
{
+ .name = "ABGR 12bit", /* 12-bit ABGR packed format */
+ .fourcc = V4L2_PIX_FMT_ABGR64_12,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ .nc = 4,
+ .depth = 48,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ .is_rgb = 1,
+ },
+ {
.name = "YUV420", /* 1st plane = Y, 2nd plane = UV */
.fourcc = V4L2_PIX_FMT_NV12M,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
@@ -128,6 +156,32 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.precision = 8,
},
{
+ .name = "YUV420 12bit", /* 1st plane = Y, 2nd plane = UV */
+ .fourcc = V4L2_PIX_FMT_P012M,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .nc = 3,
+ .depth = 18, /* 6 x 12 bits (4Y + UV) for 4 pixels */
+ .mem_planes = 2,
+ .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */
+ .h_align = 4,
+ .v_align = 4,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ },
+ {
+ .name = "YUV420 12bit", /* 1st plane = Y, 2nd plane = UV */
+ .fourcc = V4L2_PIX_FMT_P012,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .nc = 3,
+ .depth = 18, /* 6 x 12 bits (4Y + UV) for 4 pixels */
+ .mem_planes = 1,
+ .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */
+ .h_align = 4,
+ .v_align = 4,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ },
+ {
.name = "YUV422", /* YUYV */
.fourcc = V4L2_PIX_FMT_YUYV,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
@@ -141,6 +195,19 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.precision = 8,
},
{
+ .name = "YUV422 12bit", /* YUYV */
+ .fourcc = V4L2_PIX_FMT_Y212,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ .nc = 3,
+ .depth = 24,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .h_align = 4,
+ .v_align = 3,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ },
+ {
.name = "YUV444", /* YUVYUV */
.fourcc = V4L2_PIX_FMT_YUV24,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
@@ -154,6 +221,19 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.precision = 8,
},
{
+ .name = "YUV444 12bit", /* YUVYUV */
+ .fourcc = V4L2_PIX_FMT_YUV48_12,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ .nc = 3,
+ .depth = 36,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ },
+ {
.name = "Gray", /* Gray (Y8/Y12) or Single Comp */
.fourcc = V4L2_PIX_FMT_GREY,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
@@ -166,6 +246,19 @@ static const struct mxc_jpeg_fmt mxc_formats[] = {
.flags = MXC_JPEG_FMT_TYPE_RAW,
.precision = 8,
},
+ {
+ .name = "Gray 12bit", /* Gray (Y8/Y12) or Single Comp */
+ .fourcc = V4L2_PIX_FMT_Y012,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
+ .nc = 1,
+ .depth = 12,
+ .mem_planes = 1,
+ .comp_planes = 1,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ .precision = 12,
+ },
};
#define MXC_JPEG_NUM_FORMATS ARRAY_SIZE(mxc_formats)
@@ -229,6 +322,45 @@ static const unsigned char jpeg_dqt[] = {
0x63, 0x63, 0x63, 0x63, 0x63, 0x63
};
+static const unsigned char jpeg_dqt_extseq[] = {
+ 0xFF, 0xDB,
+ 0x01, 0x04,
+ 0x10,
+ 0x00, 0x80, 0x00, 0x58, 0x00, 0x60, 0x00, 0x70,
+ 0x00, 0x60, 0x00, 0x50, 0x00, 0x80, 0x00, 0x70,
+ 0x00, 0x68, 0x00, 0x70, 0x00, 0x90, 0x00, 0x88,
+ 0x00, 0x80, 0x00, 0x98, 0x00, 0xC0, 0x01, 0x40,
+ 0x00, 0xD0, 0x00, 0xC0, 0x00, 0xB0, 0x00, 0xB0,
+ 0x00, 0xC0, 0x01, 0x88, 0x01, 0x18, 0x01, 0x28,
+ 0x00, 0xE8, 0x01, 0x40, 0x01, 0xD0, 0x01, 0x98,
+ 0x01, 0xE8, 0x01, 0xE0, 0x01, 0xC8, 0x01, 0x98,
+ 0x01, 0xC0, 0x01, 0xB8, 0x02, 0x00, 0x02, 0x40,
+ 0x02, 0xE0, 0x02, 0x70, 0x02, 0x00, 0x02, 0x20,
+ 0x02, 0xB8, 0x02, 0x28, 0x01, 0xB8, 0x01, 0xC0,
+ 0x02, 0x80, 0x03, 0x68, 0x02, 0x88, 0x02, 0xB8,
+ 0x02, 0xF8, 0x03, 0x10, 0x03, 0x38, 0x03, 0x40,
+ 0x03, 0x38, 0x01, 0xF0, 0x02, 0x68, 0x03, 0x88,
+ 0x03, 0xC8, 0x03, 0x80, 0x03, 0x20, 0x03, 0xC0,
+ 0x02, 0xE0, 0x03, 0x28, 0x03, 0x38, 0x03, 0x18,
+ 0x11,
+ 0x00, 0x88, 0x00, 0x90, 0x00, 0x90, 0x00, 0xC0,
+ 0x00, 0xA8, 0x00, 0xC0, 0x01, 0x78, 0x00, 0xD0,
+ 0x00, 0xD0, 0x01, 0x78, 0x03, 0x18, 0x02, 0x10,
+ 0x01, 0xC0, 0x02, 0x10, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+ 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18,
+};
+
static const unsigned char jpeg_sof_maximal[] = {
0xFF, 0xC0,
0x00, 0x14, 0x08, 0x00, 0x40, 0x00, 0x40,
@@ -236,6 +368,13 @@ static const unsigned char jpeg_sof_maximal[] = {
0x03, 0x11, 0x01, 0x04, 0x11, 0x01
};
+static const unsigned char jpeg_sof_extseq[] = {
+ 0xFF, 0xC1,
+ 0x00, 0x14, 0x08, 0x00, 0x40, 0x00, 0x40,
+ 0x04, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01,
+ 0x03, 0x11, 0x01, 0x04, 0x11, 0x01
+};
+
static const unsigned char jpeg_dht[] = {
0xFF, 0xC4,
0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01,
@@ -300,6 +439,90 @@ static const unsigned char jpeg_dht[] = {
0xF6, 0xF7, 0xF8, 0xF9, 0xFA
};
+static const unsigned char jpeg_dht_extseq[] = {
+ 0xFF, 0xC4,
+ 0x02, 0x2a, 0x00, 0x00, 0x01, 0x05, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+ 0x04, 0x03, 0x05, 0x05, 0x02, 0x03, 0x02,
+ 0x00, 0x00, 0xbf, 0x01, 0x02, 0x03, 0x00,
+ 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
+ 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
+ 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
+ 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2,
+ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+ 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
+ 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ 0xf7, 0xf8, 0xf9, 0xfa, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x1b, 0x1c, 0x1d, 0x1e, 0x2b, 0x2c,
+ 0x2d, 0x2e, 0x3b, 0x3c, 0x3d, 0x3e, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x5b, 0x5c, 0x5d, 0x5e,
+ 0x6b, 0x6c, 0x6d, 0x6e, 0x7b, 0x7c, 0x7d,
+ 0x7e, 0x8b, 0x8c, 0x8d, 0x8e, 0x9b, 0x9c,
+ 0x9d, 0x9e, 0xab, 0xac, 0xad, 0xae, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xdb, 0xdc, 0xdd, 0xde, 0xeb, 0xec, 0xed,
+ 0xee, 0xfb, 0xfc, 0xfd, 0xfe, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x11, 0x00, 0x02, 0x01,
+ 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05,
+ 0x02, 0x03, 0x02, 0x00, 0x00, 0xbf, 0x01,
+ 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91,
+ 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
+ 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
+ 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+ 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+ 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4,
+ 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x2b, 0x2c, 0x2d, 0x2e, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x4b, 0x4c, 0x4d, 0x4e, 0x5b,
+ 0x5c, 0x5d, 0x5e, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x7b, 0x7c, 0x7d, 0x7e, 0x8b, 0x8c, 0x8d,
+ 0x8e, 0x9b, 0x9c, 0x9d, 0x9e, 0xab, 0xac,
+ 0xad, 0xae, 0xbb, 0xbc, 0xbd, 0xbe, 0xcb,
+ 0xcc, 0xcd, 0xce, 0xdb, 0xdc, 0xdd, 0xde,
+ 0xeb, 0xec, 0xed, 0xee, 0xfb, 0xfc, 0xfd,
+ 0xfe,
+};
+
static const unsigned char jpeg_dri[] = {
0xFF, 0xDD,
0x00, 0x04, 0x00, 0x20
@@ -420,8 +643,7 @@ static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n,
return 0;
}
-static const struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
- u32 pixelformat)
+static const struct mxc_jpeg_fmt *mxc_jpeg_find_format(u32 pixelformat)
{
unsigned int k;
@@ -438,17 +660,24 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc)
{
switch (fourcc) {
case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y012:
return MXC_JPEG_GRAY;
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_Y212:
return MXC_JPEG_YUV422;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_P012:
+ case V4L2_PIX_FMT_P012M:
return MXC_JPEG_YUV420;
case V4L2_PIX_FMT_YUV24:
+ case V4L2_PIX_FMT_YUV48_12:
return MXC_JPEG_YUV444;
case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_BGR48_12:
return MXC_JPEG_BGR;
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_ABGR64_12:
return MXC_JPEG_ABGR;
default:
return MXC_JPEG_INVALID;
@@ -484,6 +713,17 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
offset;
}
+static bool mxc_jpeg_is_extended_sequential(const struct mxc_jpeg_fmt *fmt)
+{
+ if (!fmt || !(fmt->flags & MXC_JPEG_FMT_TYPE_RAW))
+ return false;
+
+ if (fmt->precision > 8)
+ return true;
+
+ return false;
+}
+
static void notify_eos(struct mxc_jpeg_ctx *ctx)
{
const struct v4l2_event ev = {
@@ -497,10 +737,9 @@ static void notify_eos(struct mxc_jpeg_ctx *ctx)
static void notify_src_chg(struct mxc_jpeg_ctx *ctx)
{
const struct v4l2_event ev = {
- .type = V4L2_EVENT_SOURCE_CHANGE,
- .u.src_change.changes =
- V4L2_EVENT_SRC_CH_RESOLUTION,
- };
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
dev_dbg(ctx->mxc_jpeg->dev, "Notify app event SRC_CH_RESOLUTION");
v4l2_event_queue_fh(&ctx->fh, &ev);
@@ -637,6 +876,11 @@ static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no)
return q_data->sizeimage[plane_no];
size = q_data->sizeimage[fmt->mem_planes - 1];
+
+ /* Should be impossible given mxc_formats. */
+ if (WARN_ON_ONCE(fmt->comp_planes > ARRAY_SIZE(q_data->sizeimage)))
+ return size;
+
for (i = fmt->mem_planes; i < fmt->comp_planes; i++)
size += q_data->sizeimage[i];
@@ -692,7 +936,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
if (dec_ret & SLOT_STATUS_ENC_CONFIG_ERR) {
u32 ret = readl(reg + CAST_STATUS12);
- dev_err(dev, "Encoder/decoder error, status=0x%08x", ret);
+ dev_err(dev, "Encoder/decoder error, dec_ret = 0x%08x, status=0x%08x",
+ dec_ret, ret);
+ mxc_jpeg_clr_desc(reg, slot);
mxc_jpeg_sw_reset(reg);
buf_state = VB2_BUF_STATE_ERROR;
goto buffers_done;
@@ -703,10 +949,11 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
if (jpeg->mode == MXC_JPEG_ENCODE &&
ctx->enc_state == MXC_JPEG_ENC_CONF) {
+ q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
ctx->enc_state = MXC_JPEG_ENCODING;
dev_dbg(dev, "Encoder config finished. Start encoding...\n");
mxc_jpeg_enc_set_quality(dev, reg, ctx->jpeg_quality);
- mxc_jpeg_enc_mode_go(dev, reg);
+ mxc_jpeg_enc_mode_go(dev, reg, mxc_jpeg_is_extended_sequential(q_data->fmt));
goto job_unlock;
}
if (jpeg->mode == MXC_JPEG_DECODE && jpeg_src_buf->dht_needed) {
@@ -757,8 +1004,12 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
u16 w, u16 h)
{
int sof_length;
+ const struct mxc_jpeg_fmt *fmt = mxc_jpeg_find_format(fourcc);
- sof->precision = 8; /* TODO allow 8/12 bit precision*/
+ if (fmt)
+ sof->precision = fmt->precision;
+ else
+ sof->precision = 8; /* TODO allow 8/12 bit precision*/
sof->height = h;
_bswap16(&sof->height);
sof->width = w;
@@ -767,24 +1018,31 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
switch (fourcc) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_P012:
+ case V4L2_PIX_FMT_P012M:
sof->components_no = 3;
sof->comp[0].v = 0x2;
sof->comp[0].h = 0x2;
break;
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_Y212:
sof->components_no = 3;
sof->comp[0].v = 0x1;
sof->comp[0].h = 0x2;
break;
case V4L2_PIX_FMT_YUV24:
+ case V4L2_PIX_FMT_YUV48_12:
case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_BGR48_12:
default:
sof->components_no = 3;
break;
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_ABGR64_12:
sof->components_no = 4;
break;
case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y012:
sof->components_no = 1;
break;
}
@@ -804,20 +1062,27 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos,
switch (fourcc) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_P012:
+ case V4L2_PIX_FMT_P012M:
sos->components_no = 3;
break;
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_Y212:
sos->components_no = 3;
break;
case V4L2_PIX_FMT_YUV24:
+ case V4L2_PIX_FMT_YUV48_12:
case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_BGR48_12:
default:
sos->components_no = 3;
break;
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_ABGR64_12:
sos->components_no = 4;
break;
case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y012:
sos->components_no = 1;
break;
}
@@ -847,12 +1112,15 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
u8 *cfg = (u8 *)cfg_stream_vaddr;
struct mxc_jpeg_sof *sof;
struct mxc_jpeg_sos *sos;
+ const struct mxc_jpeg_fmt *fmt = mxc_jpeg_find_format(fourcc);
+
+ if (!fmt)
+ return 0;
memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi));
offset += ARRAY_SIZE(jpeg_soi);
- if (fourcc == V4L2_PIX_FMT_BGR24 ||
- fourcc == V4L2_PIX_FMT_ABGR32) {
+ if (fmt->is_rgb) {
memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14));
offset += sizeof(jpeg_app14);
} else {
@@ -860,16 +1128,28 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
offset += sizeof(jpeg_app0);
}
- memcpy(cfg + offset, jpeg_dqt, sizeof(jpeg_dqt));
- offset += sizeof(jpeg_dqt);
+ if (mxc_jpeg_is_extended_sequential(fmt)) {
+ memcpy(cfg + offset, jpeg_dqt_extseq, sizeof(jpeg_dqt_extseq));
+ offset += sizeof(jpeg_dqt_extseq);
- memcpy(cfg + offset, jpeg_sof_maximal, sizeof(jpeg_sof_maximal));
+ memcpy(cfg + offset, jpeg_sof_extseq, sizeof(jpeg_sof_extseq));
+ } else {
+ memcpy(cfg + offset, jpeg_dqt, sizeof(jpeg_dqt));
+ offset += sizeof(jpeg_dqt);
+
+ memcpy(cfg + offset, jpeg_sof_maximal, sizeof(jpeg_sof_maximal));
+ }
offset += 2; /* skip marker ID */
sof = (struct mxc_jpeg_sof *)(cfg + offset);
offset += mxc_jpeg_fixup_sof(sof, fourcc, w, h);
- memcpy(cfg + offset, jpeg_dht, sizeof(jpeg_dht));
- offset += sizeof(jpeg_dht);
+ if (mxc_jpeg_is_extended_sequential(fmt)) {
+ memcpy(cfg + offset, jpeg_dht_extseq, sizeof(jpeg_dht_extseq));
+ offset += sizeof(jpeg_dht_extseq);
+ } else {
+ memcpy(cfg + offset, jpeg_dht, sizeof(jpeg_dht));
+ offset += sizeof(jpeg_dht);
+ }
memcpy(cfg + offset, jpeg_dri, sizeof(jpeg_dri));
offset += sizeof(jpeg_dri);
@@ -918,6 +1198,10 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf,
desc->stm_ctrl &= ~STM_CTRL_IMAGE_FORMAT(0xF); /* clear image format */
desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1);
+ if (mxc_jpeg_is_extended_sequential(jpeg_src_buf->fmt))
+ desc->stm_ctrl |= STM_CTRL_PIXEL_PRECISION;
+ else
+ desc->stm_ctrl &= ~STM_CTRL_PIXEL_PRECISION;
desc->line_pitch = q_data_cap->bytesperline[0];
mxc_jpeg_addrs(desc, dst_buf, src_buf, 0);
mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(src_buf, 0), 1024));
@@ -1006,6 +1290,10 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) |
STM_CTRL_IMAGE_FORMAT(img_fmt);
desc->stm_ctrl |= STM_CTRL_BITBUF_PTR_CLR(1);
+ if (mxc_jpeg_is_extended_sequential(q_data->fmt))
+ desc->stm_ctrl |= STM_CTRL_PIXEL_PRECISION;
+ else
+ desc->stm_ctrl &= ~STM_CTRL_PIXEL_PRECISION;
mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
dev_dbg(jpeg->dev, "cfg_desc:\n");
print_descriptor_info(jpeg->dev, cfg_desc);
@@ -1206,7 +1494,9 @@ static void mxc_jpeg_device_run(void *priv)
ctx->enc_state = MXC_JPEG_ENC_CONF;
mxc_jpeg_config_enc_desc(&dst_buf->vb2_buf, ctx,
&src_buf->vb2_buf, &dst_buf->vb2_buf);
- mxc_jpeg_enc_mode_conf(dev, reg); /* start config phase */
+ /* start config phase */
+ mxc_jpeg_enc_mode_conf(dev, reg,
+ mxc_jpeg_is_extended_sequential(q_data_out->fmt));
} else {
dev_dbg(dev, "Decoding on slot %d\n", ctx->slot);
print_mxc_buf(jpeg, &src_buf->vb2_buf, 0);
@@ -1562,7 +1852,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
if (fourcc == 0)
return -EINVAL;
- jpeg_src_buf->fmt = mxc_jpeg_find_format(ctx, fourcc);
+ jpeg_src_buf->fmt = mxc_jpeg_find_format(fourcc);
jpeg_src_buf->w = header.frame.width;
jpeg_src_buf->h = header.frame.height;
ctx->header_parsed = true;
@@ -1702,11 +1992,11 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx)
int i;
if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) {
- out_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT);
- cap_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
+ out_q->fmt = mxc_jpeg_find_format(MXC_JPEG_DEFAULT_PFMT);
+ cap_q->fmt = mxc_jpeg_find_format(V4L2_PIX_FMT_JPEG);
} else {
- out_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
- cap_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT);
+ out_q->fmt = mxc_jpeg_find_format(V4L2_PIX_FMT_JPEG);
+ cap_q->fmt = mxc_jpeg_find_format(MXC_JPEG_DEFAULT_PFMT);
}
for (i = 0; i < 2; i++) {
@@ -1950,7 +2240,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f,
pix_mp->height : MXC_JPEG_MAX_HEIGHT;
int i;
- fmt = mxc_jpeg_find_format(ctx, fourcc);
+ fmt = mxc_jpeg_find_format(fourcc);
if (!fmt || fmt->flags != mxc_jpeg_get_fmt_type(ctx, f->type)) {
dev_warn(ctx->mxc_jpeg->dev, "Format not supported: %c%c%c%c, use the default.\n",
(fourcc & 0xff),
@@ -1958,7 +2248,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f,
(fourcc >> 16) & 0xff,
(fourcc >> 24) & 0xff);
fourcc = mxc_jpeg_get_default_fourcc(ctx, f->type);
- fmt = mxc_jpeg_find_format(ctx, fourcc);
+ fmt = mxc_jpeg_find_format(fourcc);
if (!fmt)
return -EINVAL;
f->fmt.pix_mp.pixelformat = fourcc;
@@ -2622,7 +2912,7 @@ static const struct dev_pm_ops mxc_jpeg_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume)
};
-static int mxc_jpeg_remove(struct platform_device *pdev)
+static void mxc_jpeg_remove(struct platform_device *pdev)
{
unsigned int slot;
struct mxc_jpeg_dev *jpeg = platform_get_drvdata(pdev);
@@ -2635,15 +2925,13 @@ static int mxc_jpeg_remove(struct platform_device *pdev)
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);
mxc_jpeg_detach_pm_domains(jpeg);
-
- return 0;
}
MODULE_DEVICE_TABLE(of, mxc_jpeg_match);
static struct platform_driver mxc_jpeg_driver = {
.probe = mxc_jpeg_probe,
- .remove = mxc_jpeg_remove,
+ .remove_new = mxc_jpeg_remove,
.driver = {
.name = "mxc-jpeg",
.of_match_table = mxc_jpeg_match,
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index be2768a47995..05d52762e792 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1503,7 +1503,7 @@ err_disable_clock:
return ret;
}
-static int mipi_csis_remove(struct platform_device *pdev)
+static void mipi_csis_remove(struct platform_device *pdev)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
@@ -1520,8 +1520,6 @@ static int mipi_csis_remove(struct platform_device *pdev)
media_entity_cleanup(&csis->sd.entity);
fwnode_handle_put(csis->sd.fwnode);
pm_runtime_set_suspended(&pdev->dev);
-
- return 0;
}
static const struct of_device_id mipi_csis_of_match[] = {
@@ -1544,7 +1542,7 @@ MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
static struct platform_driver mipi_csis_driver = {
.probe = mipi_csis_probe,
- .remove = mipi_csis_remove,
+ .remove_new = mipi_csis_remove,
.driver = {
.of_match_table = mipi_csis_of_match,
.name = CSIS_DRIVER_NAME,
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index fde3c36e5e1d..90f319857c23 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -1904,7 +1904,7 @@ err_clk:
return ret;
}
-static int pxp_remove(struct platform_device *pdev)
+static void pxp_remove(struct platform_device *pdev)
{
struct pxp_dev *dev = platform_get_drvdata(pdev);
@@ -1922,8 +1922,6 @@ static int pxp_remove(struct platform_device *pdev)
video_unregister_device(&dev->vfd);
v4l2_m2m_release(dev->m2m_dev);
v4l2_device_unregister(&dev->v4l2_dev);
-
- return 0;
}
static const struct pxp_pdata pxp_imx6ull_pdata = {
@@ -1943,7 +1941,7 @@ MODULE_DEVICE_TABLE(of, pxp_dt_ids);
static struct platform_driver pxp_driver = {
.probe = pxp_probe,
- .remove = pxp_remove,
+ .remove_new = pxp_remove,
.driver = {
.name = MEM2MEM_NAME,
.of_match_table = pxp_dt_ids,
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index c22bf5c827e7..b701e823436a 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -1214,6 +1214,9 @@ static int imx7_csi_video_g_selection(struct file *file, void *fh,
{
struct imx7_csi *csi = video_drvdata(file);
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
@@ -1610,6 +1613,7 @@ static int imx7_csi_video_init_format(struct imx7_csi *csi)
format.code = IMX7_CSI_DEF_MBUS_CODE;
format.width = IMX7_CSI_DEF_PIX_WIDTH;
format.height = IMX7_CSI_DEF_PIX_HEIGHT;
+ format.field = V4L2_FIELD_NONE;
imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &format, NULL);
csi->vdev_compose.width = format.width;
@@ -2107,18 +2111,21 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
FWNODE_GRAPH_ENDPOINT_NEXT);
- if (ep) {
- asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep,
- struct v4l2_async_subdev);
+ if (!ep) {
+ ret = dev_err_probe(csi->dev, -ENOTCONN,
+ "Failed to get remote endpoint\n");
+ goto error;
+ }
- fwnode_handle_put(ep);
+ asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep,
+ struct v4l2_async_subdev);
- if (IS_ERR(asd)) {
- ret = PTR_ERR(asd);
- /* OK if asd already exists */
- if (ret != -EEXIST)
- goto error;
- }
+ fwnode_handle_put(ep);
+
+ if (IS_ERR(asd)) {
+ ret = dev_err_probe(csi->dev, PTR_ERR(asd),
+ "Failed to add remote subdev to notifier\n");
+ goto error;
}
csi->notifier.ops = &imx7_csi_notify_ops;
@@ -2278,7 +2285,7 @@ err_media_cleanup:
return ret;
}
-static int imx7_csi_remove(struct platform_device *pdev)
+static void imx7_csi_remove(struct platform_device *pdev)
{
struct imx7_csi *csi = platform_get_drvdata(pdev);
@@ -2287,8 +2294,6 @@ static int imx7_csi_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&csi->notifier);
v4l2_async_nf_cleanup(&csi->notifier);
v4l2_async_unregister_subdev(&csi->sd);
-
- return 0;
}
static const struct of_device_id imx7_csi_of_match[] = {
@@ -2301,7 +2306,7 @@ MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
static struct platform_driver imx7_csi_driver = {
.probe = imx7_csi_probe,
- .remove = imx7_csi_remove,
+ .remove_new = imx7_csi_remove,
.driver = {
.of_match_table = imx7_csi_of_match,
.name = "imx7-csi",
diff --git a/drivers/media/platform/nxp/imx8-isi/Kconfig b/drivers/media/platform/nxp/imx8-isi/Kconfig
new file mode 100644
index 000000000000..fcff33fc2630
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_IMX8_ISI
+ tristate "i.MX8 Image Sensor Interface (ISI) driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on HAS_DMA && PM
+ depends on VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select V4L2_MEM2MEM_DEV if VIDEO_IMX8_ISI_M2M
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ V4L2 driver for the Image Sensor Interface (ISI) found in various
+ i.MX8 SoCs.
+
+config VIDEO_IMX8_ISI_M2M
+ bool "i.MX8 Image Sensor Interface (ISI) memory-to-memory support"
+ depends on VIDEO_IMX8_ISI
+ help
+ Select 'yes' here to enable support for memory-to-memory processing
+ in the ISI driver.
diff --git a/drivers/media/platform/nxp/imx8-isi/Makefile b/drivers/media/platform/nxp/imx8-isi/Makefile
new file mode 100644
index 000000000000..9bff9297686d
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+imx8-isi-y := imx8-isi-core.o imx8-isi-crossbar.o imx8-isi-hw.o \
+ imx8-isi-pipe.o imx8-isi-video.o
+imx8-isi-$(CONFIG_DEBUG_FS) += imx8-isi-debug.o
+imx8-isi-$(CONFIG_VIDEO_IMX8_ISI_M2M) += imx8-isi-m2m.o
+
+obj-$(CONFIG_VIDEO_IMX8_ISI) += imx8-isi.o
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
new file mode 100644
index 000000000000..238521622b75
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mc.h>
+
+#include "imx8-isi-core.h"
+
+/* -----------------------------------------------------------------------------
+ * V4L2 async subdevs
+ */
+
+struct mxc_isi_async_subdev {
+ struct v4l2_async_subdev asd;
+ unsigned int port;
+};
+
+static inline struct mxc_isi_async_subdev *
+asd_to_mxc_isi_async_subdev(struct v4l2_async_subdev *asd)
+{
+ return container_of(asd, struct mxc_isi_async_subdev, asd);
+};
+
+static inline struct mxc_isi_dev *
+notifier_to_mxc_isi_dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct mxc_isi_dev, notifier);
+};
+
+static int mxc_isi_async_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
+ | MEDIA_LNK_FL_ENABLED;
+ struct mxc_isi_dev *isi = notifier_to_mxc_isi_dev(notifier);
+ struct mxc_isi_async_subdev *masd = asd_to_mxc_isi_async_subdev(asd);
+ struct media_pad *pad = &isi->crossbar.pads[masd->port];
+ struct device_link *link;
+
+ dev_dbg(isi->dev, "Bound subdev %s to crossbar input %u\n", sd->name,
+ masd->port);
+
+ /*
+ * Enforce suspend/resume ordering between the source (supplier) and
+ * the ISI (consumer). The source will be suspended before and resume
+ * after the ISI.
+ */
+ link = device_link_add(isi->dev, sd->dev, DL_FLAG_STATELESS);
+ if (!link) {
+ dev_err(isi->dev,
+ "Failed to create device link to source %s\n", sd->name);
+ return -EINVAL;
+ }
+
+ return v4l2_create_fwnode_links_to_pad(sd, pad, link_flags);
+}
+
+static int mxc_isi_async_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+ struct mxc_isi_dev *isi = notifier_to_mxc_isi_dev(notifier);
+ int ret;
+
+ dev_dbg(isi->dev, "All subdevs bound\n");
+
+ ret = v4l2_device_register_subdev_nodes(&isi->v4l2_dev);
+ if (ret < 0) {
+ dev_err(isi->dev,
+ "Failed to register subdev nodes: %d\n", ret);
+ return ret;
+ }
+
+ return media_device_register(&isi->media_dev);
+}
+
+static const struct v4l2_async_notifier_operations mxc_isi_async_notifier_ops = {
+ .bound = mxc_isi_async_notifier_bound,
+ .complete = mxc_isi_async_notifier_complete,
+};
+
+static int mxc_isi_pipe_register(struct mxc_isi_pipe *pipe)
+{
+ int ret;
+
+ ret = v4l2_device_register_subdev(&pipe->isi->v4l2_dev, &pipe->sd);
+ if (ret < 0)
+ return ret;
+
+ return mxc_isi_video_register(pipe, &pipe->isi->v4l2_dev);
+}
+
+static void mxc_isi_pipe_unregister(struct mxc_isi_pipe *pipe)
+{
+ mxc_isi_video_unregister(pipe);
+}
+
+static int mxc_isi_v4l2_init(struct mxc_isi_dev *isi)
+{
+ struct fwnode_handle *node = dev_fwnode(isi->dev);
+ struct media_device *media_dev = &isi->media_dev;
+ struct v4l2_device *v4l2_dev = &isi->v4l2_dev;
+ unsigned int i;
+ int ret;
+
+ /* Initialize the media device. */
+ strscpy(media_dev->model, "FSL Capture Media Device",
+ sizeof(media_dev->model));
+ media_dev->dev = isi->dev;
+
+ media_device_init(media_dev);
+
+ /* Initialize and register the V4L2 device. */
+ v4l2_dev->mdev = media_dev;
+ strscpy(v4l2_dev->name, "mx8-img-md", sizeof(v4l2_dev->name));
+
+ ret = v4l2_device_register(isi->dev, v4l2_dev);
+ if (ret < 0) {
+ dev_err(isi->dev,
+ "Failed to register V4L2 device: %d\n", ret);
+ goto err_media;
+ }
+
+ /* Register the crossbar switch subdev. */
+ ret = mxc_isi_crossbar_register(&isi->crossbar);
+ if (ret < 0) {
+ dev_err(isi->dev, "Failed to register crossbar: %d\n", ret);
+ goto err_v4l2;
+ }
+
+ /* Register the pipeline subdevs and link them to the crossbar switch. */
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ struct mxc_isi_pipe *pipe = &isi->pipes[i];
+
+ ret = mxc_isi_pipe_register(pipe);
+ if (ret < 0) {
+ dev_err(isi->dev, "Failed to register pipe%u: %d\n", i,
+ ret);
+ goto err_v4l2;
+ }
+
+ ret = media_create_pad_link(&isi->crossbar.sd.entity,
+ isi->crossbar.num_sinks + i,
+ &pipe->sd.entity,
+ MXC_ISI_PIPE_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret < 0)
+ goto err_v4l2;
+ }
+
+ /* Register the M2M device. */
+ ret = mxc_isi_m2m_register(isi, v4l2_dev);
+ if (ret < 0) {
+ dev_err(isi->dev, "Failed to register M2M device: %d\n", ret);
+ goto err_v4l2;
+ }
+
+ /* Initialize, fill and register the async notifier. */
+ v4l2_async_nf_init(&isi->notifier);
+ isi->notifier.ops = &mxc_isi_async_notifier_ops;
+
+ for (i = 0; i < isi->pdata->num_ports; ++i) {
+ struct mxc_isi_async_subdev *masd;
+ struct fwnode_handle *ep;
+
+ ep = fwnode_graph_get_endpoint_by_id(node, i, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+
+ if (!ep)
+ continue;
+
+ masd = v4l2_async_nf_add_fwnode_remote(&isi->notifier, ep,
+ struct mxc_isi_async_subdev);
+ fwnode_handle_put(ep);
+
+ if (IS_ERR(masd)) {
+ ret = PTR_ERR(masd);
+ goto err_m2m;
+ }
+
+ masd->port = i;
+ }
+
+ ret = v4l2_async_nf_register(v4l2_dev, &isi->notifier);
+ if (ret < 0) {
+ dev_err(isi->dev,
+ "Failed to register async notifier: %d\n", ret);
+ goto err_m2m;
+ }
+
+ return 0;
+
+err_m2m:
+ mxc_isi_m2m_unregister(isi);
+ v4l2_async_nf_cleanup(&isi->notifier);
+err_v4l2:
+ v4l2_device_unregister(v4l2_dev);
+err_media:
+ media_device_cleanup(media_dev);
+ return ret;
+}
+
+static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi)
+{
+ unsigned int i;
+
+ v4l2_async_nf_unregister(&isi->notifier);
+ v4l2_async_nf_cleanup(&isi->notifier);
+
+ v4l2_device_unregister(&isi->v4l2_dev);
+ media_device_unregister(&isi->media_dev);
+
+ mxc_isi_m2m_unregister(isi);
+
+ for (i = 0; i < isi->pdata->num_channels; ++i)
+ mxc_isi_pipe_unregister(&isi->pipes[i]);
+
+ mxc_isi_crossbar_unregister(&isi->crossbar);
+
+ media_device_cleanup(&isi->media_dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Device information
+ */
+
+/* Panic will assert when the buffers are 50% full */
+
+/* For i.MX8QXP C0 and i.MX8MN ISI IER version */
+static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = {
+ .oflw_y_buf_en = { .offset = 19, .mask = 0x80000 },
+ .oflw_u_buf_en = { .offset = 21, .mask = 0x200000 },
+ .oflw_v_buf_en = { .offset = 23, .mask = 0x800000 },
+
+ .panic_y_buf_en = {.offset = 20, .mask = 0x100000 },
+ .panic_u_buf_en = {.offset = 22, .mask = 0x400000 },
+ .panic_v_buf_en = {.offset = 24, .mask = 0x1000000 },
+};
+
+/* For i.MX8MP ISI IER version */
+static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = {
+ .oflw_y_buf_en = { .offset = 18, .mask = 0x40000 },
+ .oflw_u_buf_en = { .offset = 20, .mask = 0x100000 },
+ .oflw_v_buf_en = { .offset = 22, .mask = 0x400000 },
+
+ .panic_y_buf_en = {.offset = 19, .mask = 0x80000 },
+ .panic_u_buf_en = {.offset = 21, .mask = 0x200000 },
+ .panic_v_buf_en = {.offset = 23, .mask = 0x800000 },
+};
+
+/* Panic will assert when the buffers are 50% full */
+static const struct mxc_isi_set_thd mxc_imx8_isi_thd_v1 = {
+ .panic_set_thd_y = { .mask = 0x0000f, .offset = 0, .threshold = 0x7 },
+ .panic_set_thd_u = { .mask = 0x00f00, .offset = 8, .threshold = 0x7 },
+ .panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 },
+};
+
+static const struct clk_bulk_data mxc_imx8mn_clks[] = {
+ { .id = "axi" },
+ { .id = "apb" },
+};
+
+static const struct mxc_isi_plat_data mxc_imx8mn_data = {
+ .model = MXC_ISI_IMX8MN,
+ .num_ports = 1,
+ .num_channels = 1,
+ .reg_offset = 0,
+ .ier_reg = &mxc_imx8_isi_ier_v1,
+ .set_thd = &mxc_imx8_isi_thd_v1,
+ .clks = mxc_imx8mn_clks,
+ .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
+ .buf_active_reverse = false,
+ .has_gasket = true,
+ .has_36bit_dma = false,
+};
+
+static const struct mxc_isi_plat_data mxc_imx8mp_data = {
+ .model = MXC_ISI_IMX8MP,
+ .num_ports = 2,
+ .num_channels = 2,
+ .reg_offset = 0x2000,
+ .ier_reg = &mxc_imx8_isi_ier_v2,
+ .set_thd = &mxc_imx8_isi_thd_v1,
+ .clks = mxc_imx8mn_clks,
+ .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
+ .buf_active_reverse = true,
+ .has_gasket = true,
+ .has_36bit_dma = true,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int mxc_isi_pm_suspend(struct device *dev)
+{
+ struct mxc_isi_dev *isi = dev_get_drvdata(dev);
+ unsigned int i;
+
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ struct mxc_isi_pipe *pipe = &isi->pipes[i];
+
+ mxc_isi_video_suspend(pipe);
+ }
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int mxc_isi_pm_resume(struct device *dev)
+{
+ struct mxc_isi_dev *isi = dev_get_drvdata(dev);
+ unsigned int i;
+ int err = 0;
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ struct mxc_isi_pipe *pipe = &isi->pipes[i];
+
+ ret = mxc_isi_video_resume(pipe);
+ if (ret) {
+ dev_err(dev, "Failed to resume pipeline %u (%d)\n", i,
+ ret);
+ /*
+ * Record the last error as it's as meaningful as any,
+ * and continue resuming the other pipelines.
+ */
+ err = ret;
+ }
+ }
+
+ return err;
+}
+
+static int mxc_isi_runtime_suspend(struct device *dev)
+{
+ struct mxc_isi_dev *isi = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(isi->pdata->num_clks, isi->clks);
+
+ return 0;
+}
+
+static int mxc_isi_runtime_resume(struct device *dev)
+{
+ struct mxc_isi_dev *isi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(isi->pdata->num_clks, isi->clks);
+ if (ret) {
+ dev_err(dev, "Failed to enable clocks (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops mxc_isi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_isi_pm_suspend, mxc_isi_pm_resume)
+ SET_RUNTIME_PM_OPS(mxc_isi_runtime_suspend, mxc_isi_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe, remove & driver
+ */
+
+static int mxc_isi_clk_get(struct mxc_isi_dev *isi)
+{
+ unsigned int size = isi->pdata->num_clks
+ * sizeof(*isi->clks);
+ int ret;
+
+ isi->clks = devm_kmalloc(isi->dev, size, GFP_KERNEL);
+ if (!isi->clks)
+ return -ENOMEM;
+
+ memcpy(isi->clks, isi->pdata->clks, size);
+
+ ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks,
+ isi->clks);
+ if (ret < 0) {
+ dev_err(isi->dev, "Failed to acquire clocks: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxc_isi_dev *isi;
+ unsigned int dma_size;
+ unsigned int i;
+ int ret = 0;
+
+ isi = devm_kzalloc(dev, sizeof(*isi), GFP_KERNEL);
+ if (!isi)
+ return -ENOMEM;
+
+ isi->dev = dev;
+ platform_set_drvdata(pdev, isi);
+
+ isi->pdata = of_device_get_match_data(dev);
+
+ isi->pipes = kcalloc(isi->pdata->num_channels, sizeof(isi->pipes[0]),
+ GFP_KERNEL);
+ if (!isi->pipes)
+ return -ENOMEM;
+
+ ret = mxc_isi_clk_get(isi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get clocks\n");
+ return ret;
+ }
+
+ isi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(isi->regs)) {
+ dev_err(dev, "Failed to get ISI register map\n");
+ return PTR_ERR(isi->regs);
+ }
+
+ if (isi->pdata->has_gasket) {
+ isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "fsl,blk-ctrl");
+ if (IS_ERR(isi->gasket)) {
+ ret = PTR_ERR(isi->gasket);
+ dev_err(dev, "failed to get gasket: %d\n", ret);
+ return ret;
+ }
+ }
+
+ dma_size = isi->pdata->has_36bit_dma ? 36 : 32;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
+ if (ret) {
+ dev_err(dev, "failed to set DMA mask\n");
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+
+ ret = mxc_isi_crossbar_init(isi);
+ if (ret) {
+ dev_err(dev, "Failed to initialize crossbar: %d\n", ret);
+ goto err_pm;
+ }
+
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ ret = mxc_isi_pipe_init(isi, i);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize pipe%u: %d\n", i,
+ ret);
+ goto err_xbar;
+ }
+ }
+
+ ret = mxc_isi_v4l2_init(isi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize V4L2: %d\n", ret);
+ goto err_xbar;
+ }
+
+ mxc_isi_debug_init(isi);
+
+ return 0;
+
+err_xbar:
+ mxc_isi_crossbar_cleanup(&isi->crossbar);
+err_pm:
+ pm_runtime_disable(isi->dev);
+ return ret;
+}
+
+static int mxc_isi_remove(struct platform_device *pdev)
+{
+ struct mxc_isi_dev *isi = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ mxc_isi_debug_cleanup(isi);
+
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ struct mxc_isi_pipe *pipe = &isi->pipes[i];
+
+ mxc_isi_pipe_cleanup(pipe);
+ }
+
+ mxc_isi_crossbar_cleanup(&isi->crossbar);
+ mxc_isi_v4l2_cleanup(isi);
+
+ pm_runtime_disable(isi->dev);
+
+ return 0;
+}
+
+static const struct of_device_id mxc_isi_of_match[] = {
+ { .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data },
+ { .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_isi_of_match);
+
+static struct platform_driver mxc_isi_driver = {
+ .probe = mxc_isi_probe,
+ .remove = mxc_isi_remove,
+ .driver = {
+ .of_match_table = mxc_isi_of_match,
+ .name = MXC_ISI_DRIVER_NAME,
+ .pm = &mxc_isi_pm_ops,
+ }
+};
+module_platform_driver(mxc_isi_driver);
+
+MODULE_ALIAS("ISI");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IMX8 Image Sensing Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
new file mode 100644
index 000000000000..e469788a9e6c
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
@@ -0,0 +1,394 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * V4L2 Capture ISI subdev for i.MX8QXP/QM platform
+ *
+ * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
+ * used to process image from camera sensor to memory or DC
+ * Copyright 2019-2020 NXP
+ */
+
+#ifndef __MXC_ISI_CORE_H__
+#define __MXC_ISI_CORE_H__
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+struct clk_bulk_data;
+struct dentry;
+struct device;
+struct media_intf_devnode;
+struct regmap;
+struct v4l2_m2m_dev;
+
+/* Pipeline pads */
+#define MXC_ISI_PIPE_PAD_SINK 0
+#define MXC_ISI_PIPE_PAD_SOURCE 1
+#define MXC_ISI_PIPE_PADS_NUM 2
+
+#define MXC_ISI_MIN_WIDTH 1U
+#define MXC_ISI_MIN_HEIGHT 1U
+#define MXC_ISI_MAX_WIDTH_UNCHAINED 2048U
+#define MXC_ISI_MAX_WIDTH_CHAINED 4096U
+#define MXC_ISI_MAX_HEIGHT 8191U
+
+#define MXC_ISI_DEF_WIDTH 1920U
+#define MXC_ISI_DEF_HEIGHT 1080U
+#define MXC_ISI_DEF_MBUS_CODE_SINK MEDIA_BUS_FMT_UYVY8_1X16
+#define MXC_ISI_DEF_MBUS_CODE_SOURCE MEDIA_BUS_FMT_YUV8_1X24
+#define MXC_ISI_DEF_PIXEL_FORMAT V4L2_PIX_FMT_YUYV
+#define MXC_ISI_DEF_COLOR_SPACE V4L2_COLORSPACE_SRGB
+#define MXC_ISI_DEF_YCBCR_ENC V4L2_YCBCR_ENC_601
+#define MXC_ISI_DEF_QUANTIZATION V4L2_QUANTIZATION_LIM_RANGE
+#define MXC_ISI_DEF_XFER_FUNC V4L2_XFER_FUNC_SRGB
+
+#define MXC_ISI_DRIVER_NAME "mxc-isi"
+#define MXC_ISI_CAPTURE "mxc-isi-cap"
+#define MXC_ISI_M2M "mxc-isi-m2m"
+#define MXC_MAX_PLANES 3
+
+struct mxc_isi_dev;
+struct mxc_isi_m2m_ctx;
+
+enum mxc_isi_buf_id {
+ MXC_ISI_BUF1 = 0x0,
+ MXC_ISI_BUF2,
+};
+
+enum mxc_isi_encoding {
+ MXC_ISI_ENC_RAW,
+ MXC_ISI_ENC_RGB,
+ MXC_ISI_ENC_YUV,
+};
+
+enum mxc_isi_input_id {
+ /* Inputs from the crossbar switch range from 0 to 15 */
+ MXC_ISI_INPUT_MEM = 16,
+};
+
+enum mxc_isi_video_type {
+ MXC_ISI_VIDEO_CAP = BIT(0),
+ MXC_ISI_VIDEO_M2M_OUT = BIT(1),
+ MXC_ISI_VIDEO_M2M_CAP = BIT(2),
+};
+
+struct mxc_isi_format_info {
+ u32 mbus_code;
+ u32 fourcc;
+ enum mxc_isi_video_type type;
+ u32 isi_in_format;
+ u32 isi_out_format;
+ u8 mem_planes;
+ u8 color_planes;
+ u8 depth[MXC_MAX_PLANES];
+ u8 hsub;
+ u8 vsub;
+ enum mxc_isi_encoding encoding;
+};
+
+struct mxc_isi_bus_format_info {
+ u32 mbus_code;
+ u32 output;
+ u32 pads;
+ enum mxc_isi_encoding encoding;
+};
+
+struct mxc_isi_buffer {
+ struct vb2_v4l2_buffer v4l2_buf;
+ struct list_head list;
+ dma_addr_t dma_addrs[3];
+ enum mxc_isi_buf_id id;
+ bool discard;
+};
+
+struct mxc_isi_reg {
+ u32 offset;
+ u32 mask;
+};
+
+struct mxc_isi_ier_reg {
+ /* Overflow Y/U/V trigger enable*/
+ struct mxc_isi_reg oflw_y_buf_en;
+ struct mxc_isi_reg oflw_u_buf_en;
+ struct mxc_isi_reg oflw_v_buf_en;
+
+ /* Excess overflow Y/U/V trigger enable*/
+ struct mxc_isi_reg excs_oflw_y_buf_en;
+ struct mxc_isi_reg excs_oflw_u_buf_en;
+ struct mxc_isi_reg excs_oflw_v_buf_en;
+
+ /* Panic Y/U/V trigger enable*/
+ struct mxc_isi_reg panic_y_buf_en;
+ struct mxc_isi_reg panic_v_buf_en;
+ struct mxc_isi_reg panic_u_buf_en;
+};
+
+struct mxc_isi_panic_thd {
+ u32 mask;
+ u32 offset;
+ u32 threshold;
+};
+
+struct mxc_isi_set_thd {
+ struct mxc_isi_panic_thd panic_set_thd_y;
+ struct mxc_isi_panic_thd panic_set_thd_u;
+ struct mxc_isi_panic_thd panic_set_thd_v;
+};
+
+enum model {
+ MXC_ISI_IMX8MN,
+ MXC_ISI_IMX8MP,
+};
+
+struct mxc_isi_plat_data {
+ enum model model;
+ unsigned int num_ports;
+ unsigned int num_channels;
+ unsigned int reg_offset;
+ const struct mxc_isi_ier_reg *ier_reg;
+ const struct mxc_isi_set_thd *set_thd;
+ const struct clk_bulk_data *clks;
+ unsigned int num_clks;
+ bool buf_active_reverse;
+ bool has_gasket;
+ bool has_36bit_dma;
+};
+
+struct mxc_isi_dma_buffer {
+ size_t size;
+ void *addr;
+ dma_addr_t dma;
+};
+
+struct mxc_isi_input {
+ unsigned int enable_count;
+};
+
+struct mxc_isi_crossbar {
+ struct mxc_isi_dev *isi;
+
+ unsigned int num_sinks;
+ unsigned int num_sources;
+ struct mxc_isi_input *inputs;
+
+ struct v4l2_subdev sd;
+ struct media_pad *pads;
+};
+
+struct mxc_isi_video {
+ struct mxc_isi_pipe *pipe;
+
+ struct video_device vdev;
+ struct media_pad pad;
+
+ /* Protects is_streaming, and the vdev and vb2_q operations */
+ struct mutex lock;
+ bool is_streaming;
+
+ struct v4l2_pix_format_mplane pix;
+ const struct mxc_isi_format_info *fmtinfo;
+
+ struct {
+ struct v4l2_ctrl_handler handler;
+ unsigned int alpha;
+ bool hflip;
+ bool vflip;
+ } ctrls;
+
+ struct vb2_queue vb2_q;
+ struct mxc_isi_buffer buf_discard[3];
+ struct list_head out_pending;
+ struct list_head out_active;
+ struct list_head out_discard;
+ u32 frame_count;
+ /* Protects out_pending, out_active, out_discard and frame_count */
+ spinlock_t buf_lock;
+
+ struct mxc_isi_dma_buffer discard_buffer[MXC_MAX_PLANES];
+};
+
+typedef void(*mxc_isi_pipe_irq_t)(struct mxc_isi_pipe *, u32);
+
+struct mxc_isi_pipe {
+ struct mxc_isi_dev *isi;
+ u32 id;
+ void __iomem *regs;
+
+ struct media_pipeline pipe;
+
+ struct v4l2_subdev sd;
+ struct media_pad pads[MXC_ISI_PIPE_PADS_NUM];
+
+ struct mxc_isi_video video;
+
+ /*
+ * Protects use_count, irq_handler, res_available, res_acquired,
+ * chained_res, and the CHNL_CTRL register.
+ */
+ struct mutex lock;
+ unsigned int use_count;
+ mxc_isi_pipe_irq_t irq_handler;
+
+#define MXC_ISI_CHANNEL_RES_LINE_BUF BIT(0)
+#define MXC_ISI_CHANNEL_RES_OUTPUT_BUF BIT(1)
+ u8 available_res;
+ u8 acquired_res;
+ u8 chained_res;
+ bool chained;
+};
+
+struct mxc_isi_m2m {
+ struct mxc_isi_dev *isi;
+ struct mxc_isi_pipe *pipe;
+
+ struct media_pad pad;
+ struct video_device vdev;
+ struct media_intf_devnode *intf;
+ struct v4l2_m2m_dev *m2m_dev;
+
+ /* Protects last_ctx, usage_count and chained_count */
+ struct mutex lock;
+
+ struct mxc_isi_m2m_ctx *last_ctx;
+ int usage_count;
+ int chained_count;
+};
+
+struct mxc_isi_dev {
+ struct device *dev;
+
+ const struct mxc_isi_plat_data *pdata;
+
+ void __iomem *regs;
+ struct clk_bulk_data *clks;
+ struct regmap *gasket;
+
+ struct mxc_isi_crossbar crossbar;
+ struct mxc_isi_pipe *pipes;
+ struct mxc_isi_m2m m2m;
+
+ struct media_device media_dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_async_notifier notifier;
+
+ struct dentry *debugfs_root;
+};
+
+int mxc_isi_crossbar_init(struct mxc_isi_dev *isi);
+void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar);
+int mxc_isi_crossbar_register(struct mxc_isi_crossbar *xbar);
+void mxc_isi_crossbar_unregister(struct mxc_isi_crossbar *xbar);
+
+const struct mxc_isi_bus_format_info *
+mxc_isi_bus_format_by_code(u32 code, unsigned int pad);
+const struct mxc_isi_bus_format_info *
+mxc_isi_bus_format_by_index(unsigned int index, unsigned int pad);
+const struct mxc_isi_format_info *
+mxc_isi_format_by_fourcc(u32 fourcc, enum mxc_isi_video_type type);
+const struct mxc_isi_format_info *
+mxc_isi_format_enum(unsigned int index, enum mxc_isi_video_type type);
+const struct mxc_isi_format_info *
+mxc_isi_format_try(struct mxc_isi_pipe *pipe, struct v4l2_pix_format_mplane *pix,
+ enum mxc_isi_video_type type);
+
+int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id);
+void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe);
+int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
+ mxc_isi_pipe_irq_t irq_handler);
+void mxc_isi_pipe_release(struct mxc_isi_pipe *pipe);
+int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe);
+void mxc_isi_pipe_disable(struct mxc_isi_pipe *pipe);
+
+int mxc_isi_video_register(struct mxc_isi_pipe *pipe,
+ struct v4l2_device *v4l2_dev);
+void mxc_isi_video_unregister(struct mxc_isi_pipe *pipe);
+void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe);
+int mxc_isi_video_resume(struct mxc_isi_pipe *pipe);
+int mxc_isi_video_queue_setup(const struct v4l2_pix_format_mplane *format,
+ const struct mxc_isi_format_info *info,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[]);
+void mxc_isi_video_buffer_init(struct vb2_buffer *vb2, dma_addr_t dma_addrs[3],
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *pix);
+int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2,
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *pix);
+
+#ifdef CONFIG_VIDEO_IMX8_ISI_M2M
+int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev);
+int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi);
+#else
+static inline int mxc_isi_m2m_register(struct mxc_isi_dev *isi,
+ struct v4l2_device *v4l2_dev)
+{
+ return 0;
+}
+static inline int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
+{
+ return 0;
+}
+#endif
+
+int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe,
+ mxc_isi_pipe_irq_t irq_handler, bool bypass);
+void mxc_isi_channel_release(struct mxc_isi_pipe *pipe);
+void mxc_isi_channel_get(struct mxc_isi_pipe *pipe);
+void mxc_isi_channel_put(struct mxc_isi_pipe *pipe);
+void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe);
+void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe);
+int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass);
+void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe);
+
+void mxc_isi_channel_config(struct mxc_isi_pipe *pipe,
+ enum mxc_isi_input_id input,
+ const struct v4l2_area *in_size,
+ const struct v4l2_area *scale,
+ const struct v4l2_rect *crop,
+ enum mxc_isi_encoding in_encoding,
+ enum mxc_isi_encoding out_encoding);
+
+void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe,
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *format);
+void mxc_isi_channel_set_output_format(struct mxc_isi_pipe *pipe,
+ const struct mxc_isi_format_info *info,
+ struct v4l2_pix_format_mplane *format);
+void mxc_isi_channel_m2m_start(struct mxc_isi_pipe *pipe);
+
+void mxc_isi_channel_set_alpha(struct mxc_isi_pipe *pipe, u8 alpha);
+void mxc_isi_channel_set_flip(struct mxc_isi_pipe *pipe, bool hflip, bool vflip);
+
+void mxc_isi_channel_set_inbuf(struct mxc_isi_pipe *pipe, dma_addr_t dma_addr);
+void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe,
+ const dma_addr_t dma_addrs[3],
+ enum mxc_isi_buf_id buf_id);
+
+u32 mxc_isi_channel_irq_status(struct mxc_isi_pipe *pipe, bool clear);
+void mxc_isi_channel_irq_clear(struct mxc_isi_pipe *pipe);
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+void mxc_isi_debug_init(struct mxc_isi_dev *isi);
+void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi);
+#else
+static inline void mxc_isi_debug_init(struct mxc_isi_dev *isi)
+{
+}
+static inline void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi)
+{
+}
+#endif
+
+#endif /* __MXC_ISI_CORE_H__ */
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
new file mode 100644
index 000000000000..b5ffde46f31b
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
@@ -0,0 +1,529 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * i.MX8 ISI - Input crossbar switch
+ *
+ * Copyright (c) 2022 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/media-entity.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-subdev.h>
+
+#include "imx8-isi-core.h"
+
+static inline struct mxc_isi_crossbar *to_isi_crossbar(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mxc_isi_crossbar, sd);
+}
+
+/* -----------------------------------------------------------------------------
+ * Media block control (i.MX8MN and i.MX8MP only)
+ */
+#define GASKET_BASE(n) (0x0060 + (n) * 0x30)
+
+#define GASKET_CTRL 0x0000
+#define GASKET_CTRL_DATA_TYPE(dt) ((dt) << 8)
+#define GASKET_CTRL_DATA_TYPE_MASK (0x3f << 8)
+#define GASKET_CTRL_DUAL_COMP_ENABLE BIT(1)
+#define GASKET_CTRL_ENABLE BIT(0)
+
+#define GASKET_HSIZE 0x0004
+#define GASKET_VSIZE 0x0008
+
+static int mxc_isi_crossbar_gasket_enable(struct mxc_isi_crossbar *xbar,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev *remote_sd,
+ u32 remote_pad, unsigned int port)
+{
+ struct mxc_isi_dev *isi = xbar->isi;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_mbus_frame_desc fd;
+ u32 val;
+ int ret;
+
+ if (!isi->pdata->has_gasket)
+ return 0;
+
+ /*
+ * Configure and enable the gasket with the frame size and CSI-2 data
+ * type. For YUV422 8-bit, enable dual component mode unconditionally,
+ * to match the configuration of the CSIS.
+ */
+
+ ret = v4l2_subdev_call(remote_sd, pad, get_frame_desc, remote_pad, &fd);
+ if (ret) {
+ dev_err(isi->dev,
+ "failed to get frame descriptor from '%s':%u: %d\n",
+ remote_sd->name, remote_pad, ret);
+ return ret;
+ }
+
+ if (fd.num_entries != 1) {
+ dev_err(isi->dev, "invalid frame descriptor for '%s':%u\n",
+ remote_sd->name, remote_pad);
+ return -EINVAL;
+ }
+
+ fmt = v4l2_subdev_state_get_stream_format(state, port, 0);
+ if (!fmt)
+ return -EINVAL;
+
+ regmap_write(isi->gasket, GASKET_BASE(port) + GASKET_HSIZE, fmt->width);
+ regmap_write(isi->gasket, GASKET_BASE(port) + GASKET_VSIZE, fmt->height);
+
+ val = GASKET_CTRL_DATA_TYPE(fd.entry[0].bus.csi2.dt)
+ | GASKET_CTRL_ENABLE;
+
+ if (fd.entry[0].bus.csi2.dt == MIPI_CSI2_DT_YUV422_8B)
+ val |= GASKET_CTRL_DUAL_COMP_ENABLE;
+
+ regmap_write(isi->gasket, GASKET_BASE(port) + GASKET_CTRL, val);
+
+ return 0;
+}
+
+static void mxc_isi_crossbar_gasket_disable(struct mxc_isi_crossbar *xbar,
+ unsigned int port)
+{
+ struct mxc_isi_dev *isi = xbar->isi;
+
+ if (!isi->pdata->has_gasket)
+ return;
+
+ regmap_write(isi->gasket, GASKET_BASE(port) + GASKET_CTRL, 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static const struct v4l2_mbus_framefmt mxc_isi_crossbar_default_format = {
+ .code = MXC_ISI_DEF_MBUS_CODE_SINK,
+ .width = MXC_ISI_DEF_WIDTH,
+ .height = MXC_ISI_DEF_HEIGHT,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = MXC_ISI_DEF_COLOR_SPACE,
+ .ycbcr_enc = MXC_ISI_DEF_YCBCR_ENC,
+ .quantization = MXC_ISI_DEF_QUANTIZATION,
+ .xfer_func = MXC_ISI_DEF_XFER_FUNC,
+};
+
+static int __mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ struct v4l2_subdev_route *route;
+ int ret;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_NO_N_TO_1);
+ if (ret)
+ return ret;
+
+ /* The memory input can be routed to the first pipeline only. */
+ for_each_active_route(&state->routing, route) {
+ if (route->sink_pad == xbar->num_sinks - 1 &&
+ route->source_pad != xbar->num_sinks) {
+ dev_dbg(xbar->isi->dev,
+ "invalid route from memory input (%u) to pipe %u\n",
+ route->sink_pad,
+ route->source_pad - xbar->num_sinks);
+ return -EINVAL;
+ }
+ }
+
+ return v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+ &mxc_isi_crossbar_default_format);
+}
+
+static struct v4l2_subdev *
+mxc_isi_crossbar_xlate_streams(struct mxc_isi_crossbar *xbar,
+ struct v4l2_subdev_state *state,
+ u32 source_pad, u64 source_streams,
+ u32 *__sink_pad, u64 *__sink_streams,
+ u32 *remote_pad)
+{
+ struct v4l2_subdev_route *route;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ u64 sink_streams = 0;
+ int sink_pad = -1;
+
+ /*
+ * Translate the source pad and streams to the sink side. The routing
+ * validation forbids stream merging, so all matching entries in the
+ * routing table are guaranteed to have the same sink pad.
+ *
+ * TODO: This is likely worth a helper function, it could perhaps be
+ * supported by v4l2_subdev_state_xlate_streams() with pad1 set to -1.
+ */
+ for_each_active_route(&state->routing, route) {
+ if (route->source_pad != source_pad ||
+ !(source_streams & BIT(route->source_stream)))
+ continue;
+
+ sink_streams |= BIT(route->sink_stream);
+ sink_pad = route->sink_pad;
+ }
+
+ if (sink_pad < 0) {
+ dev_dbg(xbar->isi->dev,
+ "no stream connected to pipeline %u\n",
+ source_pad - xbar->num_sinks);
+ return ERR_PTR(-EPIPE);
+ }
+
+ pad = media_pad_remote_pad_first(&xbar->pads[sink_pad]);
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (!sd) {
+ dev_dbg(xbar->isi->dev,
+ "no entity connected to crossbar input %u\n",
+ sink_pad);
+ return ERR_PTR(-EPIPE);
+ }
+
+ *__sink_pad = sink_pad;
+ *__sink_streams = sink_streams;
+ *remote_pad = pad->index;
+
+ return sd;
+}
+
+static int mxc_isi_crossbar_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ struct v4l2_subdev_krouting routing = { };
+ struct v4l2_subdev_route *routes;
+ unsigned int i;
+ int ret;
+
+ /*
+ * Create a 1:1 mapping between pixel link inputs and outputs to
+ * pipelines by default.
+ */
+ routes = kcalloc(xbar->num_sources, sizeof(*routes), GFP_KERNEL);
+ if (!routes)
+ return -ENOMEM;
+
+ for (i = 0; i < xbar->num_sources; ++i) {
+ struct v4l2_subdev_route *route = &routes[i];
+
+ route->sink_pad = i;
+ route->source_pad = i + xbar->num_sinks;
+ route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE;
+ };
+
+ routing.num_routes = xbar->num_sources;
+ routing.routes = routes;
+
+ ret = __mxc_isi_crossbar_set_routing(sd, state, &routing);
+
+ kfree(routes);
+
+ return ret;
+}
+
+static int mxc_isi_crossbar_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ const struct mxc_isi_bus_format_info *info;
+
+ if (code->pad >= xbar->num_sinks) {
+ const struct v4l2_mbus_framefmt *format;
+
+ /*
+ * The media bus code on source pads is identical to the
+ * connected sink pad.
+ */
+ if (code->index > 0)
+ return -EINVAL;
+
+ format = v4l2_subdev_state_get_opposite_stream_format(state,
+ code->pad,
+ code->stream);
+ if (!format)
+ return -EINVAL;
+
+ code->code = format->code;
+
+ return 0;
+ }
+
+ info = mxc_isi_bus_format_by_index(code->index, MXC_ISI_PIPE_PAD_SINK);
+ if (!info)
+ return -EINVAL;
+
+ code->code = info->mbus_code;
+
+ return 0;
+}
+
+static int mxc_isi_crossbar_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_subdev_route *route;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ media_pad_is_streaming(&xbar->pads[fmt->pad]))
+ return -EBUSY;
+
+ /*
+ * The source pad format is always identical to the sink pad format and
+ * can't be modified.
+ */
+ if (fmt->pad >= xbar->num_sinks)
+ return v4l2_subdev_get_fmt(sd, state, fmt);
+
+ /* Validate the requested format. */
+ if (!mxc_isi_bus_format_by_code(fmt->format.code, MXC_ISI_PIPE_PAD_SINK))
+ fmt->format.code = MXC_ISI_DEF_MBUS_CODE_SINK;
+
+ fmt->format.width = clamp_t(unsigned int, fmt->format.width,
+ MXC_ISI_MIN_WIDTH, MXC_ISI_MAX_WIDTH_CHAINED);
+ fmt->format.height = clamp_t(unsigned int, fmt->format.height,
+ MXC_ISI_MIN_HEIGHT, MXC_ISI_MAX_HEIGHT);
+ fmt->format.field = V4L2_FIELD_NONE;
+
+ /*
+ * Set the format on the sink stream and propagate it to the source
+ * streams.
+ */
+ sink_fmt = v4l2_subdev_state_get_stream_format(state, fmt->pad,
+ fmt->stream);
+ if (!sink_fmt)
+ return -EINVAL;
+
+ *sink_fmt = fmt->format;
+
+ /* TODO: A format propagation helper would be useful. */
+ for_each_active_route(&state->routing, route) {
+ struct v4l2_mbus_framefmt *source_fmt;
+
+ if (route->sink_pad != fmt->pad ||
+ route->sink_stream != fmt->stream)
+ continue;
+
+ source_fmt = v4l2_subdev_state_get_stream_format(state, route->source_pad,
+ route->source_stream);
+ if (!source_fmt)
+ return -EINVAL;
+
+ *source_fmt = fmt->format;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ media_entity_is_streaming(&sd->entity))
+ return -EBUSY;
+
+ return __mxc_isi_crossbar_set_routing(sd, state, routing);
+}
+
+static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ struct v4l2_subdev *remote_sd;
+ struct mxc_isi_input *input;
+ u64 sink_streams;
+ u32 sink_pad;
+ u32 remote_pad;
+ int ret;
+
+ remote_sd = mxc_isi_crossbar_xlate_streams(xbar, state, pad, streams_mask,
+ &sink_pad, &sink_streams,
+ &remote_pad);
+ if (IS_ERR(remote_sd))
+ return PTR_ERR(remote_sd);
+
+ input = &xbar->inputs[sink_pad];
+
+ /*
+ * TODO: Track per-stream enable counts to support multiplexed
+ * streams.
+ */
+ if (!input->enable_count) {
+ ret = mxc_isi_crossbar_gasket_enable(xbar, state, remote_sd,
+ remote_pad, sink_pad);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_enable_streams(remote_sd, remote_pad,
+ sink_streams);
+ if (ret) {
+ dev_err(xbar->isi->dev,
+ "failed to %s streams 0x%llx on '%s':%u: %d\n",
+ "enable", sink_streams, remote_sd->name,
+ remote_pad, ret);
+ mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
+ return ret;
+ }
+ }
+
+ input->enable_count++;
+
+ return 0;
+}
+
+static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
+ struct v4l2_subdev *remote_sd;
+ struct mxc_isi_input *input;
+ u64 sink_streams;
+ u32 sink_pad;
+ u32 remote_pad;
+ int ret = 0;
+
+ remote_sd = mxc_isi_crossbar_xlate_streams(xbar, state, pad, streams_mask,
+ &sink_pad, &sink_streams,
+ &remote_pad);
+ if (IS_ERR(remote_sd))
+ return PTR_ERR(remote_sd);
+
+ input = &xbar->inputs[sink_pad];
+
+ input->enable_count--;
+
+ if (!input->enable_count) {
+ ret = v4l2_subdev_disable_streams(remote_sd, remote_pad,
+ sink_streams);
+ if (ret)
+ dev_err(xbar->isi->dev,
+ "failed to %s streams 0x%llx on '%s':%u: %d\n",
+ "disable", sink_streams, remote_sd->name,
+ remote_pad, ret);
+
+ mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
+ }
+
+ return ret;
+}
+
+static const struct v4l2_subdev_pad_ops mxc_isi_crossbar_subdev_pad_ops = {
+ .init_cfg = mxc_isi_crossbar_init_cfg,
+ .enum_mbus_code = mxc_isi_crossbar_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = mxc_isi_crossbar_set_fmt,
+ .set_routing = mxc_isi_crossbar_set_routing,
+ .enable_streams = mxc_isi_crossbar_enable_streams,
+ .disable_streams = mxc_isi_crossbar_disable_streams,
+};
+
+static const struct v4l2_subdev_ops mxc_isi_crossbar_subdev_ops = {
+ .pad = &mxc_isi_crossbar_subdev_pad_ops,
+};
+
+static const struct media_entity_operations mxc_isi_cross_entity_ops = {
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+ .link_validate = v4l2_subdev_link_validate,
+ .has_pad_interdep = v4l2_subdev_has_pad_interdep,
+};
+
+/* -----------------------------------------------------------------------------
+ * Init & cleanup
+ */
+
+int mxc_isi_crossbar_init(struct mxc_isi_dev *isi)
+{
+ struct mxc_isi_crossbar *xbar = &isi->crossbar;
+ struct v4l2_subdev *sd = &xbar->sd;
+ unsigned int num_pads;
+ unsigned int i;
+ int ret;
+
+ xbar->isi = isi;
+
+ v4l2_subdev_init(sd, &mxc_isi_crossbar_subdev_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ strscpy(sd->name, "crossbar", sizeof(sd->name));
+ sd->dev = isi->dev;
+
+ sd->entity.function = MEDIA_ENT_F_VID_MUX;
+ sd->entity.ops = &mxc_isi_cross_entity_ops;
+
+ /*
+ * The subdev has one sink and one source per port, plus one sink for
+ * the memory input.
+ */
+ xbar->num_sinks = isi->pdata->num_ports + 1;
+ xbar->num_sources = isi->pdata->num_ports;
+ num_pads = xbar->num_sinks + xbar->num_sources;
+
+ xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL);
+ if (!xbar->pads)
+ return -ENOMEM;
+
+ xbar->inputs = kcalloc(xbar->num_sinks, sizeof(*xbar->inputs),
+ GFP_KERNEL);
+ if (!xbar->pads) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ for (i = 0; i < xbar->num_sinks; ++i)
+ xbar->pads[i].flags = MEDIA_PAD_FL_SINK;
+ for (i = 0; i < xbar->num_sources; ++i)
+ xbar->pads[i + xbar->num_sinks].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, num_pads, xbar->pads);
+ if (ret)
+ goto err_free;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0)
+ goto err_entity;
+
+ return 0;
+
+err_entity:
+ media_entity_cleanup(&sd->entity);
+err_free:
+ kfree(xbar->pads);
+ kfree(xbar->inputs);
+
+ return ret;
+}
+
+void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar)
+{
+ media_entity_cleanup(&xbar->sd.entity);
+ kfree(xbar->pads);
+ kfree(xbar->inputs);
+}
+
+int mxc_isi_crossbar_register(struct mxc_isi_crossbar *xbar)
+{
+ return v4l2_device_register_subdev(&xbar->isi->v4l2_dev, &xbar->sd);
+}
+
+void mxc_isi_crossbar_unregister(struct mxc_isi_crossbar *xbar)
+{
+}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c
new file mode 100644
index 000000000000..6709ab7ea1f3
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+#include "imx8-isi-core.h"
+#include "imx8-isi-regs.h"
+
+static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg)
+{
+ return readl(pipe->regs + reg);
+}
+
+static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p)
+{
+#define MXC_ISI_DEBUG_REG(name) { name, #name }
+ static const struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ MXC_ISI_DEBUG_REG(CHNL_CTRL),
+ MXC_ISI_DEBUG_REG(CHNL_IMG_CTRL),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF_CTRL),
+ MXC_ISI_DEBUG_REG(CHNL_IMG_CFG),
+ MXC_ISI_DEBUG_REG(CHNL_IER),
+ MXC_ISI_DEBUG_REG(CHNL_STS),
+ MXC_ISI_DEBUG_REG(CHNL_SCALE_FACTOR),
+ MXC_ISI_DEBUG_REG(CHNL_SCALE_OFFSET),
+ MXC_ISI_DEBUG_REG(CHNL_CROP_ULC),
+ MXC_ISI_DEBUG_REG(CHNL_CROP_LRC),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF0),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF1),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF2),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF3),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF4),
+ MXC_ISI_DEBUG_REG(CHNL_CSC_COEFF5),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_0_ALPHA),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_0_ULC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_0_LRC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_1_ALPHA),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_1_ULC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_1_LRC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_2_ALPHA),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_2_ULC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_2_LRC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_3_ALPHA),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_3_ULC),
+ MXC_ISI_DEBUG_REG(CHNL_ROI_3_LRC),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF1_ADDR_Y),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF1_ADDR_U),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF1_ADDR_V),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF_PITCH),
+ MXC_ISI_DEBUG_REG(CHNL_IN_BUF_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_IN_BUF_PITCH),
+ MXC_ISI_DEBUG_REG(CHNL_MEM_RD_CTRL),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF2_ADDR_Y),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF2_ADDR_U),
+ MXC_ISI_DEBUG_REG(CHNL_OUT_BUF2_ADDR_V),
+ MXC_ISI_DEBUG_REG(CHNL_SCL_IMG_CFG),
+ MXC_ISI_DEBUG_REG(CHNL_FLOW_CTRL),
+ };
+
+ struct mxc_isi_pipe *pipe = m->private;
+ unsigned int i;
+
+ if (!pm_runtime_get_if_in_use(pipe->isi->dev))
+ return 0;
+
+ seq_printf(m, "--- ISI pipe %u registers ---\n", pipe->id);
+
+ for (i = 0; i < ARRAY_SIZE(registers); ++i)
+ seq_printf(m, "%20s[0x%02x]: 0x%08x\n",
+ registers[i].name, registers[i].offset,
+ mxc_isi_read(pipe, registers[i].offset));
+
+ pm_runtime_put(pipe->isi->dev);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(mxc_isi_debug_dump_regs);
+
+void mxc_isi_debug_init(struct mxc_isi_dev *isi)
+{
+ unsigned int i;
+
+ isi->debugfs_root = debugfs_create_dir(dev_name(isi->dev), NULL);
+
+ for (i = 0; i < isi->pdata->num_channels; ++i) {
+ struct mxc_isi_pipe *pipe = &isi->pipes[i];
+ char name[8];
+
+ sprintf(name, "pipe%u", pipe->id);
+ debugfs_create_file(name, 0444, isi->debugfs_root, pipe,
+ &mxc_isi_debug_dump_regs_fops);
+ }
+}
+
+void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi)
+{
+ debugfs_remove_recursive(isi->debugfs_root);
+}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
new file mode 100644
index 000000000000..db538f3d88ec
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
@@ -0,0 +1,650 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "imx8-isi-core.h"
+#include "imx8-isi-regs.h"
+
+#define ISI_DOWNSCALE_THRESHOLD 0x4000
+
+static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg)
+{
+ return readl(pipe->regs + reg);
+}
+
+static inline void mxc_isi_write(struct mxc_isi_pipe *pipe, u32 reg, u32 val)
+{
+ writel(val, pipe->regs + reg);
+}
+
+/* -----------------------------------------------------------------------------
+ * Buffers & M2M operation
+ */
+
+void mxc_isi_channel_set_inbuf(struct mxc_isi_pipe *pipe, dma_addr_t dma_addr)
+{
+ mxc_isi_write(pipe, CHNL_IN_BUF_ADDR, dma_addr);
+#if CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (pipe->isi->pdata->has_36bit_dma)
+ mxc_isi_write(pipe, CHNL_IN_BUF_XTND_ADDR, dma_addr >> 32);
+#endif
+}
+
+void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe,
+ const dma_addr_t dma_addrs[3],
+ enum mxc_isi_buf_id buf_id)
+{
+ int val;
+
+ val = mxc_isi_read(pipe, CHNL_OUT_BUF_CTRL);
+
+ if (buf_id == MXC_ISI_BUF1) {
+ mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_Y, dma_addrs[0]);
+ mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_U, dma_addrs[1]);
+ mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_V, dma_addrs[2]);
+#if CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (pipe->isi->pdata->has_36bit_dma) {
+ mxc_isi_write(pipe, CHNL_Y_BUF1_XTND_ADDR,
+ dma_addrs[0] >> 32);
+ mxc_isi_write(pipe, CHNL_U_BUF1_XTND_ADDR,
+ dma_addrs[1] >> 32);
+ mxc_isi_write(pipe, CHNL_V_BUF1_XTND_ADDR,
+ dma_addrs[2] >> 32);
+ }
+#endif
+ val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR;
+ } else {
+ mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_Y, dma_addrs[0]);
+ mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_U, dma_addrs[1]);
+ mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_V, dma_addrs[2]);
+#if CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (pipe->isi->pdata->has_36bit_dma) {
+ mxc_isi_write(pipe, CHNL_Y_BUF2_XTND_ADDR,
+ dma_addrs[0] >> 32);
+ mxc_isi_write(pipe, CHNL_U_BUF2_XTND_ADDR,
+ dma_addrs[1] >> 32);
+ mxc_isi_write(pipe, CHNL_V_BUF2_XTND_ADDR,
+ dma_addrs[2] >> 32);
+ }
+#endif
+ val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR;
+ }
+
+ mxc_isi_write(pipe, CHNL_OUT_BUF_CTRL, val);
+}
+
+void mxc_isi_channel_m2m_start(struct mxc_isi_pipe *pipe)
+{
+ u32 val;
+
+ val = mxc_isi_read(pipe, CHNL_MEM_RD_CTRL);
+ val &= ~CHNL_MEM_RD_CTRL_READ_MEM;
+ mxc_isi_write(pipe, CHNL_MEM_RD_CTRL, val);
+
+ fsleep(300);
+
+ val |= CHNL_MEM_RD_CTRL_READ_MEM;
+ mxc_isi_write(pipe, CHNL_MEM_RD_CTRL, val);
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline configuration
+ */
+
+static u32 mxc_isi_channel_scaling_ratio(unsigned int from, unsigned int to,
+ u32 *dec)
+{
+ unsigned int ratio = from / to;
+
+ if (ratio < 2)
+ *dec = 1;
+ else if (ratio < 4)
+ *dec = 2;
+ else if (ratio < 8)
+ *dec = 4;
+ else
+ *dec = 8;
+
+ return min_t(u32, from * 0x1000 / (to * *dec), ISI_DOWNSCALE_THRESHOLD);
+}
+
+static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe,
+ enum mxc_isi_encoding encoding,
+ const struct v4l2_area *in_size,
+ const struct v4l2_area *out_size,
+ bool *bypass)
+{
+ u32 xscale, yscale;
+ u32 decx, decy;
+ u32 val;
+
+ dev_dbg(pipe->isi->dev, "input %ux%u, output %ux%u\n",
+ in_size->width, in_size->height,
+ out_size->width, out_size->height);
+
+ xscale = mxc_isi_channel_scaling_ratio(in_size->width, out_size->width,
+ &decx);
+ yscale = mxc_isi_channel_scaling_ratio(in_size->height, out_size->height,
+ &decy);
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_DEC_X_MASK | CHNL_IMG_CTRL_DEC_Y_MASK |
+ CHNL_IMG_CTRL_YCBCR_MODE);
+
+ val |= CHNL_IMG_CTRL_DEC_X(ilog2(decx))
+ | CHNL_IMG_CTRL_DEC_Y(ilog2(decy));
+
+ /*
+ * Contrary to what the documentation states, YCBCR_MODE does not
+ * control conversion between YCbCr and RGB, but whether the scaler
+ * operates in YUV mode or in RGB mode. It must be set when the scaler
+ * input is YUV.
+ */
+ if (encoding == MXC_ISI_ENC_YUV)
+ val |= CHNL_IMG_CTRL_YCBCR_MODE;
+
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+
+ mxc_isi_write(pipe, CHNL_SCALE_FACTOR,
+ CHNL_SCALE_FACTOR_Y_SCALE(yscale) |
+ CHNL_SCALE_FACTOR_X_SCALE(xscale));
+
+ mxc_isi_write(pipe, CHNL_SCALE_OFFSET, 0);
+
+ mxc_isi_write(pipe, CHNL_SCL_IMG_CFG,
+ CHNL_SCL_IMG_CFG_HEIGHT(out_size->height) |
+ CHNL_SCL_IMG_CFG_WIDTH(out_size->width));
+
+ *bypass = in_size->height == out_size->height &&
+ in_size->width == out_size->width;
+}
+
+static void mxc_isi_channel_set_crop(struct mxc_isi_pipe *pipe,
+ const struct v4l2_area *src,
+ const struct v4l2_rect *dst)
+{
+ u32 val, val0, val1;
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~CHNL_IMG_CTRL_CROP_EN;
+
+ if (src->height == dst->height && src->width == dst->width) {
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+ return;
+ }
+
+ val |= CHNL_IMG_CTRL_CROP_EN;
+ val0 = CHNL_CROP_ULC_X(dst->left) | CHNL_CROP_ULC_Y(dst->top);
+ val1 = CHNL_CROP_LRC_X(dst->width) | CHNL_CROP_LRC_Y(dst->height);
+
+ mxc_isi_write(pipe, CHNL_CROP_ULC, val0);
+ mxc_isi_write(pipe, CHNL_CROP_LRC, val1 + val0);
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+}
+
+/*
+ * A2,A1, B1, A3, B3, B2,
+ * C2, C1, D1, C3, D3, D2
+ */
+static const u32 mxc_isi_yuv2rgb_coeffs[6] = {
+ /* YUV -> RGB */
+ 0x0000012a, 0x012a0198, 0x0730079c,
+ 0x0204012a, 0x01f00000, 0x01800180
+};
+
+static const u32 mxc_isi_rgb2yuv_coeffs[6] = {
+ /* RGB->YUV */
+ 0x00810041, 0x07db0019, 0x007007b6,
+ 0x07a20070, 0x001007ee, 0x00800080
+};
+
+static void mxc_isi_channel_set_csc(struct mxc_isi_pipe *pipe,
+ enum mxc_isi_encoding in_encoding,
+ enum mxc_isi_encoding out_encoding,
+ bool *bypass)
+{
+ static const char * const encodings[] = {
+ [MXC_ISI_ENC_RAW] = "RAW",
+ [MXC_ISI_ENC_RGB] = "RGB",
+ [MXC_ISI_ENC_YUV] = "YUV",
+ };
+ const u32 *coeffs;
+ bool cscen = true;
+ u32 val;
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_CSC_BYPASS | CHNL_IMG_CTRL_CSC_MODE_MASK);
+
+ if (in_encoding == MXC_ISI_ENC_YUV &&
+ out_encoding == MXC_ISI_ENC_RGB) {
+ /* YUV2RGB */
+ coeffs = mxc_isi_yuv2rgb_coeffs;
+ /* YCbCr enable??? */
+ val |= CHNL_IMG_CTRL_CSC_MODE(CHNL_IMG_CTRL_CSC_MODE_YCBCR2RGB);
+ } else if (in_encoding == MXC_ISI_ENC_RGB &&
+ out_encoding == MXC_ISI_ENC_YUV) {
+ /* RGB2YUV */
+ coeffs = mxc_isi_rgb2yuv_coeffs;
+ val |= CHNL_IMG_CTRL_CSC_MODE(CHNL_IMG_CTRL_CSC_MODE_RGB2YCBCR);
+ } else {
+ /* Bypass CSC */
+ cscen = false;
+ val |= CHNL_IMG_CTRL_CSC_BYPASS;
+ }
+
+ dev_dbg(pipe->isi->dev, "CSC: %s -> %s\n",
+ encodings[in_encoding], encodings[out_encoding]);
+
+ if (cscen) {
+ mxc_isi_write(pipe, CHNL_CSC_COEFF0, coeffs[0]);
+ mxc_isi_write(pipe, CHNL_CSC_COEFF1, coeffs[1]);
+ mxc_isi_write(pipe, CHNL_CSC_COEFF2, coeffs[2]);
+ mxc_isi_write(pipe, CHNL_CSC_COEFF3, coeffs[3]);
+ mxc_isi_write(pipe, CHNL_CSC_COEFF4, coeffs[4]);
+ mxc_isi_write(pipe, CHNL_CSC_COEFF5, coeffs[5]);
+ }
+
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+
+ *bypass = !cscen;
+}
+
+void mxc_isi_channel_set_alpha(struct mxc_isi_pipe *pipe, u8 alpha)
+{
+ u32 val;
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~CHNL_IMG_CTRL_GBL_ALPHA_VAL_MASK;
+ val |= CHNL_IMG_CTRL_GBL_ALPHA_VAL(alpha) |
+ CHNL_IMG_CTRL_GBL_ALPHA_EN;
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+}
+
+void mxc_isi_channel_set_flip(struct mxc_isi_pipe *pipe, bool hflip, bool vflip)
+{
+ u32 val;
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_VFLIP_EN | CHNL_IMG_CTRL_HFLIP_EN);
+
+ if (vflip)
+ val |= CHNL_IMG_CTRL_VFLIP_EN;
+ if (hflip)
+ val |= CHNL_IMG_CTRL_HFLIP_EN;
+
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+}
+
+static void mxc_isi_channel_set_panic_threshold(struct mxc_isi_pipe *pipe)
+{
+ const struct mxc_isi_set_thd *set_thd = pipe->isi->pdata->set_thd;
+ u32 val;
+
+ val = mxc_isi_read(pipe, CHNL_OUT_BUF_CTRL);
+
+ val &= ~(set_thd->panic_set_thd_y.mask);
+ val |= set_thd->panic_set_thd_y.threshold << set_thd->panic_set_thd_y.offset;
+
+ val &= ~(set_thd->panic_set_thd_u.mask);
+ val |= set_thd->panic_set_thd_u.threshold << set_thd->panic_set_thd_u.offset;
+
+ val &= ~(set_thd->panic_set_thd_v.mask);
+ val |= set_thd->panic_set_thd_v.threshold << set_thd->panic_set_thd_v.offset;
+
+ mxc_isi_write(pipe, CHNL_OUT_BUF_CTRL, val);
+}
+
+static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe,
+ enum mxc_isi_input_id input,
+ bool bypass)
+{
+ u32 val;
+
+ mutex_lock(&pipe->lock);
+
+ val = mxc_isi_read(pipe, CHNL_CTRL);
+ val &= ~(CHNL_CTRL_CHNL_BYPASS | CHNL_CTRL_CHAIN_BUF_MASK |
+ CHNL_CTRL_BLANK_PXL_MASK | CHNL_CTRL_SRC_TYPE_MASK |
+ CHNL_CTRL_MIPI_VC_ID_MASK | CHNL_CTRL_SRC_INPUT_MASK);
+
+ /*
+ * If no scaling or color space conversion is needed, bypass the
+ * channel.
+ */
+ if (bypass)
+ val |= CHNL_CTRL_CHNL_BYPASS;
+
+ /* Chain line buffers if needed. */
+ if (pipe->chained)
+ val |= CHNL_CTRL_CHAIN_BUF(CHNL_CTRL_CHAIN_BUF_2_CHAIN);
+
+ val |= CHNL_CTRL_BLANK_PXL(0xff);
+
+ /* Input source (including VC configuration for CSI-2) */
+ if (input == MXC_ISI_INPUT_MEM) {
+ /*
+ * The memory input is connected to the last port of the
+ * crossbar switch, after all pixel link inputs. The SRC_INPUT
+ * field controls the input selection and must be set
+ * accordingly, despite being documented as ignored when using
+ * the memory input in the i.MX8MP reference manual, and
+ * reserved in the i.MX8MN reference manual.
+ */
+ val |= CHNL_CTRL_SRC_TYPE(CHNL_CTRL_SRC_TYPE_MEMORY);
+ val |= CHNL_CTRL_SRC_INPUT(pipe->isi->pdata->num_ports);
+ } else {
+ val |= CHNL_CTRL_SRC_TYPE(CHNL_CTRL_SRC_TYPE_DEVICE);
+ val |= CHNL_CTRL_SRC_INPUT(input);
+ val |= CHNL_CTRL_MIPI_VC_ID(0); /* FIXME: For CSI-2 only */
+ }
+
+ mxc_isi_write(pipe, CHNL_CTRL, val);
+
+ mutex_unlock(&pipe->lock);
+}
+
+void mxc_isi_channel_config(struct mxc_isi_pipe *pipe,
+ enum mxc_isi_input_id input,
+ const struct v4l2_area *in_size,
+ const struct v4l2_area *scale,
+ const struct v4l2_rect *crop,
+ enum mxc_isi_encoding in_encoding,
+ enum mxc_isi_encoding out_encoding)
+{
+ bool csc_bypass;
+ bool scaler_bypass;
+
+ /* Input frame size */
+ mxc_isi_write(pipe, CHNL_IMG_CFG,
+ CHNL_IMG_CFG_HEIGHT(in_size->height) |
+ CHNL_IMG_CFG_WIDTH(in_size->width));
+
+ /* Scaling */
+ mxc_isi_channel_set_scaling(pipe, in_encoding, in_size, scale,
+ &scaler_bypass);
+ mxc_isi_channel_set_crop(pipe, scale, crop);
+
+ /* CSC */
+ mxc_isi_channel_set_csc(pipe, in_encoding, out_encoding, &csc_bypass);
+
+ /* Output buffer management */
+ mxc_isi_channel_set_panic_threshold(pipe);
+
+ /* Channel control */
+ mxc_isi_channel_set_control(pipe, input, csc_bypass && scaler_bypass);
+}
+
+void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe,
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *format)
+{
+ unsigned int bpl = format->plane_fmt[0].bytesperline;
+
+ mxc_isi_write(pipe, CHNL_MEM_RD_CTRL,
+ CHNL_MEM_RD_CTRL_IMG_TYPE(info->isi_in_format));
+ mxc_isi_write(pipe, CHNL_IN_BUF_PITCH,
+ CHNL_IN_BUF_PITCH_LINE_PITCH(bpl));
+}
+
+void mxc_isi_channel_set_output_format(struct mxc_isi_pipe *pipe,
+ const struct mxc_isi_format_info *info,
+ struct v4l2_pix_format_mplane *format)
+{
+ u32 val;
+
+ /* set outbuf format */
+ dev_dbg(pipe->isi->dev, "output format %p4cc", &format->pixelformat);
+
+ val = mxc_isi_read(pipe, CHNL_IMG_CTRL);
+ val &= ~CHNL_IMG_CTRL_FORMAT_MASK;
+ val |= CHNL_IMG_CTRL_FORMAT(info->isi_out_format);
+ mxc_isi_write(pipe, CHNL_IMG_CTRL, val);
+
+ /* line pitch */
+ mxc_isi_write(pipe, CHNL_OUT_BUF_PITCH,
+ format->plane_fmt[0].bytesperline);
+}
+
+/* -----------------------------------------------------------------------------
+ * IRQ
+ */
+
+u32 mxc_isi_channel_irq_status(struct mxc_isi_pipe *pipe, bool clear)
+{
+ u32 status;
+
+ status = mxc_isi_read(pipe, CHNL_STS);
+ if (clear)
+ mxc_isi_write(pipe, CHNL_STS, status);
+
+ return status;
+}
+
+void mxc_isi_channel_irq_clear(struct mxc_isi_pipe *pipe)
+{
+ mxc_isi_write(pipe, CHNL_STS, 0xffffffff);
+}
+
+static void mxc_isi_channel_irq_enable(struct mxc_isi_pipe *pipe)
+{
+ const struct mxc_isi_ier_reg *ier_reg = pipe->isi->pdata->ier_reg;
+ u32 val;
+
+ val = CHNL_IER_FRM_RCVD_EN |
+ CHNL_IER_AXI_WR_ERR_U_EN |
+ CHNL_IER_AXI_WR_ERR_V_EN |
+ CHNL_IER_AXI_WR_ERR_Y_EN;
+
+ /* Y/U/V overflow enable */
+ val |= ier_reg->oflw_y_buf_en.mask |
+ ier_reg->oflw_u_buf_en.mask |
+ ier_reg->oflw_v_buf_en.mask;
+
+ /* Y/U/V excess overflow enable */
+ val |= ier_reg->excs_oflw_y_buf_en.mask |
+ ier_reg->excs_oflw_u_buf_en.mask |
+ ier_reg->excs_oflw_v_buf_en.mask;
+
+ /* Y/U/V panic enable */
+ val |= ier_reg->panic_y_buf_en.mask |
+ ier_reg->panic_u_buf_en.mask |
+ ier_reg->panic_v_buf_en.mask;
+
+ mxc_isi_channel_irq_clear(pipe);
+ mxc_isi_write(pipe, CHNL_IER, val);
+}
+
+static void mxc_isi_channel_irq_disable(struct mxc_isi_pipe *pipe)
+{
+ mxc_isi_write(pipe, CHNL_IER, 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Init, deinit, enable, disable
+ */
+
+static void mxc_isi_channel_sw_reset(struct mxc_isi_pipe *pipe, bool enable_clk)
+{
+ mxc_isi_write(pipe, CHNL_CTRL, CHNL_CTRL_SW_RST);
+ mdelay(5);
+ mxc_isi_write(pipe, CHNL_CTRL, enable_clk ? CHNL_CTRL_CLK_EN : 0);
+}
+
+static void __mxc_isi_channel_get(struct mxc_isi_pipe *pipe)
+{
+ if (!pipe->use_count++)
+ mxc_isi_channel_sw_reset(pipe, true);
+}
+
+void mxc_isi_channel_get(struct mxc_isi_pipe *pipe)
+{
+ mutex_lock(&pipe->lock);
+ __mxc_isi_channel_get(pipe);
+ mutex_unlock(&pipe->lock);
+}
+
+static void __mxc_isi_channel_put(struct mxc_isi_pipe *pipe)
+{
+ if (!--pipe->use_count)
+ mxc_isi_channel_sw_reset(pipe, false);
+}
+
+void mxc_isi_channel_put(struct mxc_isi_pipe *pipe)
+{
+ mutex_lock(&pipe->lock);
+ __mxc_isi_channel_put(pipe);
+ mutex_unlock(&pipe->lock);
+}
+
+void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe)
+{
+ u32 val;
+
+ mxc_isi_channel_irq_enable(pipe);
+
+ mutex_lock(&pipe->lock);
+
+ val = mxc_isi_read(pipe, CHNL_CTRL);
+ val |= CHNL_CTRL_CHNL_EN;
+ mxc_isi_write(pipe, CHNL_CTRL, val);
+
+ mutex_unlock(&pipe->lock);
+}
+
+void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe)
+{
+ u32 val;
+
+ mxc_isi_channel_irq_disable(pipe);
+
+ mutex_lock(&pipe->lock);
+
+ val = mxc_isi_read(pipe, CHNL_CTRL);
+ val &= ~CHNL_CTRL_CHNL_EN;
+ mxc_isi_write(pipe, CHNL_CTRL, val);
+
+ mutex_unlock(&pipe->lock);
+}
+
+/* -----------------------------------------------------------------------------
+ * Resource management & chaining
+ */
+int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe,
+ mxc_isi_pipe_irq_t irq_handler, bool bypass)
+{
+ u8 resources;
+ int ret = 0;
+
+ mutex_lock(&pipe->lock);
+
+ if (pipe->irq_handler) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ /*
+ * Make sure the resources we need are available. The output buffer is
+ * always needed to operate the channel, the line buffer is needed only
+ * when the channel isn't in bypass mode.
+ */
+ resources = MXC_ISI_CHANNEL_RES_OUTPUT_BUF
+ | (!bypass ? MXC_ISI_CHANNEL_RES_LINE_BUF : 0);
+ if ((pipe->available_res & resources) != resources) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ /* Acquire the channel resources. */
+ pipe->acquired_res = resources;
+ pipe->available_res &= ~resources;
+ pipe->irq_handler = irq_handler;
+
+unlock:
+ mutex_unlock(&pipe->lock);
+
+ return ret;
+}
+
+void mxc_isi_channel_release(struct mxc_isi_pipe *pipe)
+{
+ mutex_lock(&pipe->lock);
+
+ pipe->irq_handler = NULL;
+ pipe->available_res |= pipe->acquired_res;
+ pipe->acquired_res = 0;
+
+ mutex_unlock(&pipe->lock);
+}
+
+/*
+ * We currently support line buffer chaining only, for handling images with a
+ * width larger than 2048 pixels.
+ *
+ * TODO: Support secondary line buffer for downscaling YUV420 images.
+ */
+int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass)
+{
+ /* Channel chaining requires both line and output buffer. */
+ const u8 resources = MXC_ISI_CHANNEL_RES_OUTPUT_BUF
+ | MXC_ISI_CHANNEL_RES_LINE_BUF;
+ struct mxc_isi_pipe *chained_pipe = pipe + 1;
+ int ret = 0;
+
+ /*
+ * If buffer chaining is required, make sure this channel is not the
+ * last one, otherwise there's no 'next' channel to chain with. This
+ * should be prevented by checks in the set format handlers, but let's
+ * be defensive.
+ */
+ if (WARN_ON(pipe->id == pipe->isi->pdata->num_channels - 1))
+ return -EINVAL;
+
+ mutex_lock(&chained_pipe->lock);
+
+ /* Safety checks. */
+ if (WARN_ON(pipe->chained || chained_pipe->chained_res)) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if ((chained_pipe->available_res & resources) != resources) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ pipe->chained = true;
+ chained_pipe->chained_res |= resources;
+ chained_pipe->available_res &= ~resources;
+
+ __mxc_isi_channel_get(chained_pipe);
+
+unlock:
+ mutex_unlock(&chained_pipe->lock);
+
+ return ret;
+}
+
+void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_pipe *chained_pipe = pipe + 1;
+
+ if (!pipe->chained)
+ return;
+
+ pipe->chained = false;
+
+ mutex_lock(&chained_pipe->lock);
+
+ chained_pipe->available_res |= chained_pipe->chained_res;
+ chained_pipe->chained_res = 0;
+
+ __mxc_isi_channel_put(chained_pipe);
+
+ mutex_unlock(&chained_pipe->lock);
+}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
new file mode 100644
index 000000000000..9745d6219a16
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ISI V4L2 memory to memory driver for i.MX8QXP/QM platform
+ *
+ * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
+ * used to process image from camera sensor or memory to memory or DC
+ *
+ * Copyright (c) 2019 NXP Semiconductor
+ */
+
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "imx8-isi-core.h"
+
+struct mxc_isi_m2m_buffer {
+ struct v4l2_m2m_buffer buf;
+ dma_addr_t dma_addrs[3];
+};
+
+struct mxc_isi_m2m_ctx_queue_data {
+ struct v4l2_pix_format_mplane format;
+ const struct mxc_isi_format_info *info;
+ u32 sequence;
+};
+
+struct mxc_isi_m2m_ctx {
+ struct v4l2_fh fh;
+ struct mxc_isi_m2m *m2m;
+
+ /* Protects the m2m vb2 queues */
+ struct mutex vb2_lock;
+
+ struct {
+ struct mxc_isi_m2m_ctx_queue_data out;
+ struct mxc_isi_m2m_ctx_queue_data cap;
+ } queues;
+
+ struct {
+ struct v4l2_ctrl_handler handler;
+ unsigned int alpha;
+ bool hflip;
+ bool vflip;
+ } ctrls;
+
+ bool chained;
+};
+
+static inline struct mxc_isi_m2m_buffer *
+to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf)
+{
+ return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb);
+}
+
+static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh)
+{
+ return container_of(fh, struct mxc_isi_m2m_ctx, fh);
+}
+
+static inline struct mxc_isi_m2m_ctx_queue_data *
+mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx *ctx, enum v4l2_buf_type type)
+{
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return &ctx->queues.out;
+ else
+ return &ctx->queues.cap;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 M2M device operations
+ */
+
+static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe *pipe, u32 status)
+{
+ struct mxc_isi_m2m *m2m = &pipe->isi->m2m;
+ struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
+ struct mxc_isi_m2m_ctx *ctx;
+
+ ctx = v4l2_m2m_get_curr_priv(m2m->m2m_dev);
+ if (!ctx) {
+ dev_err(m2m->isi->dev,
+ "Instance released before the end of transaction\n");
+ return;
+ }
+
+ src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, false);
+
+ src_vbuf->sequence = ctx->queues.out.sequence++;
+ dst_vbuf->sequence = ctx->queues.cap.sequence++;
+
+ v4l2_m2m_buf_done(src_vbuf, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vbuf, VB2_BUF_STATE_DONE);
+
+ v4l2_m2m_job_finish(m2m->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void mxc_isi_m2m_device_run(void *priv)
+{
+ struct mxc_isi_m2m_ctx *ctx = priv;
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+ struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
+ struct mxc_isi_m2m_buffer *src_buf, *dst_buf;
+
+ mxc_isi_channel_disable(m2m->pipe);
+
+ mutex_lock(&m2m->lock);
+
+ /* If the context has changed, reconfigure the channel. */
+ if (m2m->last_ctx != ctx) {
+ const struct v4l2_area in_size = {
+ .width = ctx->queues.out.format.width,
+ .height = ctx->queues.out.format.height,
+ };
+ const struct v4l2_area scale = {
+ .width = ctx->queues.cap.format.width,
+ .height = ctx->queues.cap.format.height,
+ };
+ const struct v4l2_rect crop = {
+ .width = ctx->queues.cap.format.width,
+ .height = ctx->queues.cap.format.height,
+ };
+
+ mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM,
+ &in_size, &scale, &crop,
+ ctx->queues.out.info->encoding,
+ ctx->queues.cap.info->encoding);
+ mxc_isi_channel_set_input_format(m2m->pipe,
+ ctx->queues.out.info,
+ &ctx->queues.out.format);
+ mxc_isi_channel_set_output_format(m2m->pipe,
+ ctx->queues.cap.info,
+ &ctx->queues.cap.format);
+
+ m2m->last_ctx = ctx;
+ }
+
+ mutex_unlock(&m2m->lock);
+
+ mutex_lock(ctx->ctrls.handler.lock);
+ mxc_isi_channel_set_alpha(m2m->pipe, ctx->ctrls.alpha);
+ mxc_isi_channel_set_flip(m2m->pipe, ctx->ctrls.hflip, ctx->ctrls.vflip);
+ mutex_unlock(ctx->ctrls.handler.lock);
+
+ src_vbuf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_vbuf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ src_buf = to_isi_m2m_buffer(src_vbuf);
+ dst_buf = to_isi_m2m_buffer(dst_vbuf);
+
+ mxc_isi_channel_set_inbuf(m2m->pipe, src_buf->dma_addrs[0]);
+ mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF1);
+ mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF2);
+
+ mxc_isi_channel_enable(m2m->pipe);
+
+ mxc_isi_channel_m2m_start(m2m->pipe);
+}
+
+static const struct v4l2_m2m_ops mxc_isi_m2m_ops = {
+ .device_run = mxc_isi_m2m_device_run,
+};
+
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
+ */
+
+static int mxc_isi_m2m_vb2_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ const struct mxc_isi_m2m_ctx_queue_data *qdata =
+ mxc_isi_m2m_ctx_qdata(ctx, q->type);
+
+ return mxc_isi_video_queue_setup(&qdata->format, qdata->info,
+ num_buffers, num_planes, sizes);
+}
+
+static int mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer *vb2)
+{
+ struct vb2_queue *vq = vb2->vb2_queue;
+ struct mxc_isi_m2m_buffer *buf = to_isi_m2m_buffer(to_vb2_v4l2_buffer(vb2));
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue);
+ const struct mxc_isi_m2m_ctx_queue_data *qdata =
+ mxc_isi_m2m_ctx_qdata(ctx, vq->type);
+
+ mxc_isi_video_buffer_init(vb2, buf->dma_addrs, qdata->info,
+ &qdata->format);
+
+ return 0;
+}
+
+static int mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct vb2_queue *vq = vb2->vb2_queue;
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vq);
+ const struct mxc_isi_m2m_ctx_queue_data *qdata =
+ mxc_isi_m2m_ctx_qdata(ctx, vq->type);
+
+ return mxc_isi_video_buffer_prepare(ctx->m2m->isi, vb2, qdata->info,
+ &qdata->format);
+}
+
+static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct mxc_isi_m2m_ctx_queue_data *qdata =
+ mxc_isi_m2m_ctx_qdata(ctx, q->type);
+
+ qdata->sequence = 0;
+
+ return 0;
+}
+
+static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *vbuf;
+
+ for (;;) {
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (!vbuf)
+ break;
+
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static const struct vb2_ops mxc_isi_m2m_vb2_qops = {
+ .queue_setup = mxc_isi_m2m_vb2_queue_setup,
+ .buf_init = mxc_isi_m2m_vb2_buffer_init,
+ .buf_prepare = mxc_isi_m2m_vb2_buffer_prepare,
+ .buf_queue = mxc_isi_m2m_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = mxc_isi_m2m_vb2_start_streaming,
+ .stop_streaming = mxc_isi_m2m_vb2_stop_streaming,
+};
+
+static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct mxc_isi_m2m_ctx *ctx = priv;
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer);
+ src_vq->ops = &mxc_isi_m2m_vb2_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->vb2_lock;
+ src_vq->dev = m2m->isi->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_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer);
+ dst_vq->ops = &mxc_isi_m2m_vb2_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->vb2_lock;
+ dst_vq->dev = m2m->isi->dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static inline struct mxc_isi_m2m_ctx *
+ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct mxc_isi_m2m_ctx, ctrls.handler);
+}
+
+static int mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mxc_isi_m2m_ctx *ctx = ctrl_to_mxc_isi_m2m_ctx(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ ctx->ctrls.hflip = ctrl->val;
+ break;
+
+ case V4L2_CID_VFLIP:
+ ctx->ctrls.vflip = ctrl->val;
+ break;
+
+ case V4L2_CID_ALPHA_COMPONENT:
+ ctx->ctrls.alpha = ctrl->val;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mxc_isi_m2m_ctx_ctrl_ops = {
+ .s_ctrl = mxc_isi_m2m_ctx_s_ctrl,
+};
+
+static int mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx *ctx)
+{
+ struct v4l2_ctrl_handler *handler = &ctx->ctrls.handler;
+ int ret;
+
+ v4l2_ctrl_handler_init(handler, 3);
+
+ v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+ v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (handler->error) {
+ ret = handler->error;
+ v4l2_ctrl_handler_free(handler);
+ return ret;
+ }
+
+ ctx->fh.ctrl_handler = handler;
+
+ return 0;
+}
+
+static void mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx *ctx)
+{
+ v4l2_ctrl_handler_free(&ctx->ctrls.handler);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int mxc_isi_m2m_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, MXC_ISI_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MXC_ISI_M2M, sizeof(cap->card));
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int mxc_isi_m2m_enum_fmt_vid(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ const enum mxc_isi_video_type type =
+ f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+ MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
+ const struct mxc_isi_format_info *info;
+
+ info = mxc_isi_format_enum(f->index, type);
+ if (!info)
+ return -EINVAL;
+
+ f->pixelformat = info->fourcc;
+ f->flags |= V4L2_FMT_FLAG_CSC_COLORSPACE | V4L2_FMT_FLAG_CSC_YCBCR_ENC
+ | V4L2_FMT_FLAG_CSC_QUANTIZATION | V4L2_FMT_FLAG_CSC_XFER_FUNC;
+
+ return 0;
+}
+
+static const struct mxc_isi_format_info *
+__mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix,
+ const enum mxc_isi_video_type type)
+{
+ if (type == MXC_ISI_VIDEO_M2M_CAP) {
+ /* Downscaling only */
+ pix->width = min(pix->width, ctx->queues.out.format.width);
+ pix->height = min(pix->height, ctx->queues.out.format.height);
+ }
+
+ return mxc_isi_format_try(ctx->m2m->pipe, pix, type);
+}
+
+static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ const enum mxc_isi_video_type type =
+ f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+ MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+
+ __mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type);
+
+ return 0;
+}
+
+static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ const struct mxc_isi_m2m_ctx_queue_data *qdata =
+ mxc_isi_m2m_ctx_qdata(ctx, f->type);
+
+ f->fmt.pix_mp = qdata->format;
+
+ return 0;
+}
+
+static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ const enum mxc_isi_video_type type =
+ f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+ MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ const struct mxc_isi_format_info *info;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ info = __mxc_isi_m2m_try_fmt_vid(ctx, pix, type);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ctx->queues.out.format = *pix;
+ ctx->queues.out.info = info;
+ }
+
+ /*
+ * Always set the format on the capture side, due to either format
+ * propagation or direct setting.
+ */
+ ctx->queues.cap.format = *pix;
+ ctx->queues.cap.info = info;
+
+ return 0;
+}
+
+static int mxc_isi_m2m_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format;
+ const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format;
+ const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info;
+ const struct mxc_isi_format_info *out_info = ctx->queues.out.info;
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+ bool bypass;
+
+ int ret;
+
+ mutex_lock(&m2m->lock);
+
+ if (m2m->usage_count == INT_MAX) {
+ ret = -EOVERFLOW;
+ goto unlock;
+ }
+
+ bypass = cap_pix->width == out_pix->width &&
+ cap_pix->height == out_pix->height &&
+ cap_info->encoding == out_info->encoding;
+
+ /*
+ * Acquire the pipe and initialize the channel with the first user of
+ * the M2M device.
+ */
+ if (m2m->usage_count == 0) {
+ ret = mxc_isi_channel_acquire(m2m->pipe,
+ &mxc_isi_m2m_frame_write_done,
+ bypass);
+ if (ret)
+ goto unlock;
+
+ mxc_isi_channel_get(m2m->pipe);
+ }
+
+ m2m->usage_count++;
+
+ /*
+ * Allocate resources for the channel, counting how many users require
+ * buffer chaining.
+ */
+ if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
+ ret = mxc_isi_channel_chain(m2m->pipe, bypass);
+ if (ret)
+ goto deinit;
+
+ m2m->chained_count++;
+ ctx->chained = true;
+ }
+
+ /*
+ * Drop the lock to start the stream, as the .device_run() operation
+ * needs to acquire it.
+ */
+ mutex_unlock(&m2m->lock);
+ ret = v4l2_m2m_ioctl_streamon(file, fh, type);
+ if (ret) {
+ /* Reacquire the lock for the cleanup path. */
+ mutex_lock(&m2m->lock);
+ goto unchain;
+ }
+
+ return 0;
+
+unchain:
+ if (ctx->chained && --m2m->chained_count == 0)
+ mxc_isi_channel_unchain(m2m->pipe);
+ ctx->chained = false;
+
+deinit:
+ if (--m2m->usage_count == 0) {
+ mxc_isi_channel_put(m2m->pipe);
+ mxc_isi_channel_release(m2m->pipe);
+ }
+
+unlock:
+ mutex_unlock(&m2m->lock);
+ return ret;
+}
+
+static int mxc_isi_m2m_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
+ struct mxc_isi_m2m *m2m = ctx->m2m;
+
+ v4l2_m2m_ioctl_streamoff(file, fh, type);
+
+ mutex_lock(&m2m->lock);
+
+ /*
+ * If the last context is this one, reset it to make sure the device
+ * will be reconfigured when streaming is restarted.
+ */
+ if (m2m->last_ctx == ctx)
+ m2m->last_ctx = NULL;
+
+ /* Free the channel resources if this is the last chained context. */
+ if (ctx->chained && --m2m->chained_count == 0)
+ mxc_isi_channel_unchain(m2m->pipe);
+ ctx->chained = false;
+
+ /* Turn off the light with the last user. */
+ if (--m2m->usage_count == 0) {
+ mxc_isi_channel_disable(m2m->pipe);
+ mxc_isi_channel_put(m2m->pipe);
+ mxc_isi_channel_release(m2m->pipe);
+ }
+
+ WARN_ON(m2m->usage_count < 0);
+
+ mutex_unlock(&m2m->lock);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = {
+ .vidioc_querycap = mxc_isi_m2m_querycap,
+
+ .vidioc_enum_fmt_vid_cap = mxc_isi_m2m_enum_fmt_vid,
+ .vidioc_enum_fmt_vid_out = mxc_isi_m2m_enum_fmt_vid,
+ .vidioc_g_fmt_vid_cap_mplane = mxc_isi_m2m_g_fmt_vid,
+ .vidioc_g_fmt_vid_out_mplane = mxc_isi_m2m_g_fmt_vid,
+ .vidioc_s_fmt_vid_cap_mplane = mxc_isi_m2m_s_fmt_vid,
+ .vidioc_s_fmt_vid_out_mplane = mxc_isi_m2m_s_fmt_vid,
+ .vidioc_try_fmt_vid_cap_mplane = mxc_isi_m2m_try_fmt_vid,
+ .vidioc_try_fmt_vid_out_mplane = mxc_isi_m2m_try_fmt_vid,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+
+ .vidioc_streamon = mxc_isi_m2m_streamon,
+ .vidioc_streamoff = mxc_isi_m2m_streamoff,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------------------
+ * Video device file operations
+ */
+
+static void mxc_isi_m2m_init_format(struct mxc_isi_m2m_ctx *ctx,
+ struct mxc_isi_m2m_ctx_queue_data *qdata,
+ enum mxc_isi_video_type type)
+{
+ qdata->format.width = MXC_ISI_DEF_WIDTH;
+ qdata->format.height = MXC_ISI_DEF_HEIGHT;
+ qdata->format.pixelformat = MXC_ISI_DEF_PIXEL_FORMAT;
+
+ qdata->info = mxc_isi_format_try(ctx->m2m->pipe, &qdata->format, type);
+}
+
+static int mxc_isi_m2m_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct mxc_isi_m2m *m2m = video_drvdata(file);
+ struct mxc_isi_m2m_ctx *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->m2m = m2m;
+ mutex_init(&ctx->vb2_lock);
+
+ v4l2_fh_init(&ctx->fh, vdev);
+ file->private_data = &ctx->fh;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx,
+ &mxc_isi_m2m_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ ctx->fh.m2m_ctx = NULL;
+ goto err_fh;
+ }
+
+ mxc_isi_m2m_init_format(ctx, &ctx->queues.out, MXC_ISI_VIDEO_M2M_OUT);
+ mxc_isi_m2m_init_format(ctx, &ctx->queues.cap, MXC_ISI_VIDEO_M2M_CAP);
+
+ ret = mxc_isi_m2m_ctx_ctrls_create(ctx);
+ if (ret)
+ goto err_ctx;
+
+ ret = pm_runtime_resume_and_get(m2m->isi->dev);
+ if (ret)
+ goto err_ctrls;
+
+ v4l2_fh_add(&ctx->fh);
+
+ return 0;
+
+err_ctrls:
+ mxc_isi_m2m_ctx_ctrls_delete(ctx);
+err_ctx:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+err_fh:
+ v4l2_fh_exit(&ctx->fh);
+ mutex_destroy(&ctx->vb2_lock);
+ kfree(ctx);
+ return ret;
+}
+
+static int mxc_isi_m2m_release(struct file *file)
+{
+ struct mxc_isi_m2m *m2m = video_drvdata(file);
+ struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data);
+
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ mxc_isi_m2m_ctx_ctrls_delete(ctx);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ mutex_destroy(&ctx->vb2_lock);
+ kfree(ctx);
+
+ pm_runtime_put(m2m->isi->dev);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations mxc_isi_m2m_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_isi_m2m_open,
+ .release = mxc_isi_m2m_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * Registration
+ */
+
+int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev)
+{
+ struct mxc_isi_m2m *m2m = &isi->m2m;
+ struct video_device *vdev = &m2m->vdev;
+ struct media_link *link;
+ int ret;
+
+ m2m->isi = isi;
+ m2m->pipe = &isi->pipes[0];
+
+ mutex_init(&m2m->lock);
+
+ /* Initialize the video device and create controls. */
+ snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.m2m");
+
+ vdev->fops = &mxc_isi_m2m_fops;
+ vdev->ioctl_ops = &mxc_isi_m2m_ioctl_ops;
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->minor = -1;
+ vdev->release = video_device_release_empty;
+ vdev->vfl_dir = VFL_DIR_M2M;
+
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ video_set_drvdata(vdev, m2m);
+
+ /* Create the M2M device. */
+ m2m->m2m_dev = v4l2_m2m_init(&mxc_isi_m2m_ops);
+ if (IS_ERR(m2m->m2m_dev)) {
+ dev_err(isi->dev, "failed to initialize m2m device\n");
+ ret = PTR_ERR(m2m->m2m_dev);
+ goto err_mutex;
+ }
+
+ /* Register the video device. */
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret < 0) {
+ dev_err(isi->dev, "failed to register m2m device\n");
+ goto err_m2m;
+ }
+
+ /*
+ * Populate the media graph. We can't use the mem2mem helper
+ * v4l2_m2m_register_media_controller() as the M2M interface needs to
+ * be connected to the existing entities in the graph, so we have to
+ * wire things up manually:
+ *
+ * - The entity in the video_device, which isn't touched by the V4L2
+ * core for M2M devices, is used as the source I/O entity in the
+ * graph, connected to the crossbar switch.
+ *
+ * - The video device at the end of the pipeline provides the sink
+ * entity, and is already wired up in the graph.
+ *
+ * - A new interface is created, pointing at both entities. The sink
+ * entity will thus have two interfaces pointing to it.
+ */
+ m2m->pad.flags = MEDIA_PAD_FL_SOURCE;
+ vdev->entity.name = "mxc_isi.output";
+ vdev->entity.function = MEDIA_ENT_F_IO_V4L;
+ ret = media_entity_pads_init(&vdev->entity, 1, &m2m->pad);
+ if (ret)
+ goto err_video;
+
+ ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = media_create_pad_link(&vdev->entity, 0,
+ &m2m->isi->crossbar.sd.entity,
+ m2m->isi->crossbar.num_sinks - 1,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_entity_unreg;
+
+ m2m->intf = media_devnode_create(v4l2_dev->mdev, MEDIA_INTF_T_V4L_VIDEO,
+ 0, VIDEO_MAJOR, vdev->minor);
+ if (!m2m->intf) {
+ ret = -ENOMEM;
+ goto err_entity_unreg;
+ }
+
+ link = media_create_intf_link(&vdev->entity, &m2m->intf->intf,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ ret = -ENOMEM;
+ goto err_devnode;
+ }
+
+ link = media_create_intf_link(&m2m->pipe->video.vdev.entity,
+ &m2m->intf->intf,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ ret = -ENOMEM;
+ goto err_devnode;
+ }
+
+ return 0;
+
+err_devnode:
+ media_devnode_remove(m2m->intf);
+err_entity_unreg:
+ media_device_unregister_entity(&vdev->entity);
+err_entity_cleanup:
+ media_entity_cleanup(&vdev->entity);
+err_video:
+ video_unregister_device(vdev);
+err_m2m:
+ v4l2_m2m_release(m2m->m2m_dev);
+err_mutex:
+ mutex_destroy(&m2m->lock);
+ return ret;
+}
+
+int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
+{
+ struct mxc_isi_m2m *m2m = &isi->m2m;
+ struct video_device *vdev = &m2m->vdev;
+
+ video_unregister_device(vdev);
+
+ v4l2_m2m_release(m2m->m2m_dev);
+ media_devnode_remove(m2m->intf);
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&m2m->lock);
+
+ return 0;
+}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
new file mode 100644
index 000000000000..c4454aa1cb34
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Capture ISI subdev driver for i.MX8QXP/QM platform
+ *
+ * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
+ * used to process image from camera sensor to memory or DC
+ *
+ * Copyright (c) 2019 NXP Semiconductor
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "imx8-isi-core.h"
+#include "imx8-isi-regs.h"
+
+/*
+ * While the ISI receives data from the gasket on a 3x12-bit bus, the pipeline
+ * subdev conceptually includes the gasket in order to avoid exposing an extra
+ * subdev between the CSIS and the ISI. We thus need to expose media bus codes
+ * corresponding to the CSIS output, which is narrower.
+ */
+static const struct mxc_isi_bus_format_info mxc_isi_bus_formats[] = {
+ /* YUV formats */
+ {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .output = MEDIA_BUS_FMT_YUV8_1X24,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK),
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .output = MEDIA_BUS_FMT_YUV8_1X24,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_YUV,
+ },
+ /* RGB formats */
+ {
+ .mbus_code = MEDIA_BUS_FMT_RGB565_1X16,
+ .output = MEDIA_BUS_FMT_RGB888_1X24,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK),
+ .encoding = MXC_ISI_ENC_RGB,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .output = MEDIA_BUS_FMT_RGB888_1X24,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RGB,
+ },
+ /* RAW formats */
+ {
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .output = MEDIA_BUS_FMT_Y8_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .output = MEDIA_BUS_FMT_Y10_1X10,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y12_1X12,
+ .output = MEDIA_BUS_FMT_Y12_1X12,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y14_1X14,
+ .output = MEDIA_BUS_FMT_Y14_1X14,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .output = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .output = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .output = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .output = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .output = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .output = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .output = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .output = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .output = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .output = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .output = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .output = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .output = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .output = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .output = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .output = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ },
+ /* JPEG */
+ {
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ .output = MEDIA_BUS_FMT_JPEG_1X8,
+ .pads = BIT(MXC_ISI_PIPE_PAD_SINK)
+ | BIT(MXC_ISI_PIPE_PAD_SOURCE),
+ .encoding = MXC_ISI_ENC_RAW,
+ }
+};
+
+const struct mxc_isi_bus_format_info *
+mxc_isi_bus_format_by_code(u32 code, unsigned int pad)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_bus_formats); i++) {
+ const struct mxc_isi_bus_format_info *info =
+ &mxc_isi_bus_formats[i];
+
+ if (info->mbus_code == code && info->pads & BIT(pad))
+ return info;
+ }
+
+ return NULL;
+}
+
+const struct mxc_isi_bus_format_info *
+mxc_isi_bus_format_by_index(unsigned int index, unsigned int pad)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_bus_formats); i++) {
+ const struct mxc_isi_bus_format_info *info =
+ &mxc_isi_bus_formats[i];
+
+ if (!(info->pads & BIT(pad)))
+ continue;
+
+ if (!index)
+ return info;
+
+ index--;
+ }
+
+ return NULL;
+}
+
+static inline struct mxc_isi_pipe *to_isi_pipe(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mxc_isi_pipe, sd);
+}
+
+int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar;
+ const struct mxc_isi_bus_format_info *sink_info;
+ const struct mxc_isi_bus_format_info *src_info;
+ const struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_mbus_framefmt *src_fmt;
+ const struct v4l2_rect *compose;
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev *sd = &pipe->sd;
+ struct v4l2_area in_size, scale;
+ struct v4l2_rect crop;
+ u32 input;
+ int ret;
+
+ /*
+ * Find the connected input by inspecting the crossbar switch routing
+ * table.
+ */
+ state = v4l2_subdev_lock_and_get_active_state(&xbar->sd);
+ ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
+ xbar->num_sinks + pipe->id,
+ 0, &input, NULL);
+ v4l2_subdev_unlock_state(state);
+
+ if (ret)
+ return -EPIPE;
+
+ /* Configure the pipeline. */
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK);
+ src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+ compose = v4l2_subdev_get_try_compose(sd, state, MXC_ISI_PIPE_PAD_SINK);
+ crop = *v4l2_subdev_get_try_crop(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+
+ sink_info = mxc_isi_bus_format_by_code(sink_fmt->code,
+ MXC_ISI_PIPE_PAD_SINK);
+ src_info = mxc_isi_bus_format_by_code(src_fmt->code,
+ MXC_ISI_PIPE_PAD_SOURCE);
+
+ in_size.width = sink_fmt->width;
+ in_size.height = sink_fmt->height;
+ scale.width = compose->width;
+ scale.height = compose->height;
+
+ v4l2_subdev_unlock_state(state);
+
+ /* Configure the ISI channel. */
+ mxc_isi_channel_config(pipe, input, &in_size, &scale, &crop,
+ sink_info->encoding, src_info->encoding);
+
+ mxc_isi_channel_enable(pipe);
+
+ /* Enable streams on the crossbar switch. */
+ ret = v4l2_subdev_enable_streams(&xbar->sd, xbar->num_sinks + pipe->id,
+ BIT(0));
+ if (ret) {
+ mxc_isi_channel_disable(pipe);
+ dev_err(pipe->isi->dev, "Failed to enable pipe %u\n",
+ pipe->id);
+ return ret;
+ }
+
+ return 0;
+}
+
+void mxc_isi_pipe_disable(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar;
+ int ret;
+
+ ret = v4l2_subdev_disable_streams(&xbar->sd, xbar->num_sinks + pipe->id,
+ BIT(0));
+ if (ret)
+ dev_err(pipe->isi->dev, "Failed to disable pipe %u\n",
+ pipe->id);
+
+ mxc_isi_channel_disable(pipe);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static struct v4l2_mbus_framefmt *
+mxc_isi_pipe_get_pad_format(struct mxc_isi_pipe *pipe,
+ struct v4l2_subdev_state *state,
+ unsigned int pad)
+{
+ return v4l2_subdev_get_try_format(&pipe->sd, state, pad);
+}
+
+static struct v4l2_rect *
+mxc_isi_pipe_get_pad_crop(struct mxc_isi_pipe *pipe,
+ struct v4l2_subdev_state *state,
+ unsigned int pad)
+{
+ return v4l2_subdev_get_try_crop(&pipe->sd, state, pad);
+}
+
+static struct v4l2_rect *
+mxc_isi_pipe_get_pad_compose(struct mxc_isi_pipe *pipe,
+ struct v4l2_subdev_state *state,
+ unsigned int pad)
+{
+ return v4l2_subdev_get_try_compose(&pipe->sd, state, pad);
+}
+
+static int mxc_isi_pipe_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
+ struct v4l2_mbus_framefmt *fmt_source;
+ struct v4l2_mbus_framefmt *fmt_sink;
+ struct v4l2_rect *compose;
+ struct v4l2_rect *crop;
+
+ fmt_sink = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ fmt_source = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+
+ fmt_sink->width = MXC_ISI_DEF_WIDTH;
+ fmt_sink->height = MXC_ISI_DEF_HEIGHT;
+ fmt_sink->code = MXC_ISI_DEF_MBUS_CODE_SINK;
+ fmt_sink->field = V4L2_FIELD_NONE;
+ fmt_sink->colorspace = V4L2_COLORSPACE_JPEG;
+ fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace);
+ fmt_sink->quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace,
+ fmt_sink->ycbcr_enc);
+ fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace);
+
+ *fmt_source = *fmt_sink;
+ fmt_source->code = MXC_ISI_DEF_MBUS_CODE_SOURCE;
+
+ compose = mxc_isi_pipe_get_pad_compose(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ crop = mxc_isi_pipe_get_pad_crop(pipe, state, MXC_ISI_PIPE_PAD_SOURCE);
+
+ compose->left = 0;
+ compose->top = 0;
+ compose->width = MXC_ISI_DEF_WIDTH;
+ compose->height = MXC_ISI_DEF_HEIGHT;
+
+ *crop = *compose;
+
+ return 0;
+}
+
+static int mxc_isi_pipe_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ static const u32 output_codes[] = {
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_RGB888_1X24,
+ };
+ struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
+ const struct mxc_isi_bus_format_info *info;
+ unsigned int index;
+ unsigned int i;
+
+ if (code->pad == MXC_ISI_PIPE_PAD_SOURCE) {
+ const struct v4l2_mbus_framefmt *format;
+
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ info = mxc_isi_bus_format_by_code(format->code,
+ MXC_ISI_PIPE_PAD_SINK);
+
+ if (info->encoding == MXC_ISI_ENC_RAW) {
+ /*
+ * For RAW formats, the sink and source media bus codes
+ * must match.
+ */
+ if (code->index)
+ return -EINVAL;
+
+ code->code = info->output;
+ } else {
+ /*
+ * For RGB or YUV formats, the ISI supports format
+ * conversion. Either of the two output formats can be
+ * used regardless of the input.
+ */
+ if (code->index > 1)
+ return -EINVAL;
+
+ code->code = output_codes[code->index];
+ }
+
+ return 0;
+ }
+
+ index = code->index;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_bus_formats); ++i) {
+ info = &mxc_isi_bus_formats[i];
+
+ if (!(info->pads & BIT(MXC_ISI_PIPE_PAD_SINK)))
+ continue;
+
+ if (index == 0) {
+ code->code = info->mbus_code;
+ return 0;
+ }
+
+ index--;
+ }
+
+ return -EINVAL;
+}
+
+static int mxc_isi_pipe_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ const struct mxc_isi_bus_format_info *info;
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *rect;
+
+ if (vb2_is_busy(&pipe->video.vb2_q))
+ return -EBUSY;
+
+ if (fmt->pad == MXC_ISI_PIPE_PAD_SINK) {
+ unsigned int max_width;
+
+ info = mxc_isi_bus_format_by_code(mf->code,
+ MXC_ISI_PIPE_PAD_SINK);
+ if (!info)
+ info = mxc_isi_bus_format_by_code(MXC_ISI_DEF_MBUS_CODE_SINK,
+ MXC_ISI_PIPE_PAD_SINK);
+
+ /*
+ * Limit the max line length if there's no adjacent pipe to
+ * chain with.
+ */
+ max_width = pipe->id == pipe->isi->pdata->num_channels - 1
+ ? MXC_ISI_MAX_WIDTH_UNCHAINED
+ : MXC_ISI_MAX_WIDTH_CHAINED;
+
+ mf->code = info->mbus_code;
+ mf->width = clamp(mf->width, MXC_ISI_MIN_WIDTH, max_width);
+ mf->height = clamp(mf->height, MXC_ISI_MIN_HEIGHT,
+ MXC_ISI_MAX_HEIGHT);
+
+ /* Propagate the format to the source pad. */
+ rect = mxc_isi_pipe_get_pad_compose(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ rect->width = mf->width;
+ rect->height = mf->height;
+
+ rect = mxc_isi_pipe_get_pad_crop(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ rect->left = 0;
+ rect->top = 0;
+ rect->width = mf->width;
+ rect->height = mf->height;
+
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ format->code = info->output;
+ format->width = mf->width;
+ format->height = mf->height;
+ } else {
+ /*
+ * For RGB or YUV formats, the ISI supports RGB <-> YUV format
+ * conversion. For RAW formats, the sink and source media bus
+ * codes must match.
+ */
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ info = mxc_isi_bus_format_by_code(format->code,
+ MXC_ISI_PIPE_PAD_SINK);
+
+ if (info->encoding != MXC_ISI_ENC_RAW) {
+ if (mf->code != MEDIA_BUS_FMT_YUV8_1X24 &&
+ mf->code != MEDIA_BUS_FMT_RGB888_1X24)
+ mf->code = info->output;
+
+ info = mxc_isi_bus_format_by_code(mf->code,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ }
+
+ mf->code = info->output;
+
+ /*
+ * The width and height on the source can't be changed, they
+ * must match the crop rectangle size.
+ */
+ rect = mxc_isi_pipe_get_pad_crop(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+
+ mf->width = rect->width;
+ mf->height = rect->height;
+ }
+
+ format = mxc_isi_pipe_get_pad_format(pipe, state, fmt->pad);
+ *format = *mf;
+
+ dev_dbg(pipe->isi->dev, "pad%u: code: 0x%04x, %ux%u",
+ fmt->pad, mf->code, mf->width, mf->height);
+
+ return 0;
+}
+
+static int mxc_isi_pipe_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *rect;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SINK)
+ /* No compose rectangle on source pad. */
+ return -EINVAL;
+
+ /* The sink compose is bound by the sink format. */
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = format->width;
+ sel->r.height = format->height;
+ break;
+
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE)
+ /* No crop rectangle on sink pad. */
+ return -EINVAL;
+
+ /* The source crop is bound by the sink compose. */
+ rect = mxc_isi_pipe_get_pad_compose(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ sel->r = *rect;
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE)
+ /* No crop rectangle on sink pad. */
+ return -EINVAL;
+
+ rect = mxc_isi_pipe_get_pad_crop(pipe, state, sel->pad);
+ sel->r = *rect;
+ break;
+
+ case V4L2_SEL_TGT_COMPOSE:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SINK)
+ /* No compose rectangle on source pad. */
+ return -EINVAL;
+
+ rect = mxc_isi_pipe_get_pad_compose(pipe, state, sel->pad);
+ sel->r = *rect;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *rect;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE)
+ /* The pipeline support cropping on the source only. */
+ return -EINVAL;
+
+ /* The source crop is bound by the sink compose. */
+ rect = mxc_isi_pipe_get_pad_compose(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ sel->r.left = clamp_t(s32, sel->r.left, 0, rect->width - 1);
+ sel->r.top = clamp_t(s32, sel->r.top, 0, rect->height - 1);
+ sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH,
+ rect->width - sel->r.left);
+ sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT,
+ rect->height - sel->r.top);
+
+ rect = mxc_isi_pipe_get_pad_crop(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ *rect = sel->r;
+
+ /* Propagate the crop rectangle to the source pad. */
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ format->width = sel->r.width;
+ format->height = sel->r.height;
+ break;
+
+ case V4L2_SEL_TGT_COMPOSE:
+ if (sel->pad != MXC_ISI_PIPE_PAD_SINK)
+ /* Composing is supported on the sink only. */
+ return -EINVAL;
+
+ /* The sink crop is bound by the sink format downscaling only). */
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH,
+ format->width);
+ sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT,
+ format->height);
+
+ rect = mxc_isi_pipe_get_pad_compose(pipe, state,
+ MXC_ISI_PIPE_PAD_SINK);
+ *rect = sel->r;
+
+ /* Propagate the compose rectangle to the source pad. */
+ rect = mxc_isi_pipe_get_pad_crop(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ rect->left = 0;
+ rect->top = 0;
+ rect->width = sel->r.width;
+ rect->height = sel->r.height;
+
+ format = mxc_isi_pipe_get_pad_format(pipe, state,
+ MXC_ISI_PIPE_PAD_SOURCE);
+ format->width = sel->r.width;
+ format->height = sel->r.height;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(pipe->isi->dev, "%s, target %#x: (%d,%d)/%dx%d", __func__,
+ sel->target, sel->r.left, sel->r.top, sel->r.width,
+ sel->r.height);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops mxc_isi_pipe_subdev_pad_ops = {
+ .init_cfg = mxc_isi_pipe_init_cfg,
+ .enum_mbus_code = mxc_isi_pipe_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = mxc_isi_pipe_set_fmt,
+ .get_selection = mxc_isi_pipe_get_selection,
+ .set_selection = mxc_isi_pipe_set_selection,
+};
+
+static const struct v4l2_subdev_ops mxc_isi_pipe_subdev_ops = {
+ .pad = &mxc_isi_pipe_subdev_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * IRQ handling
+ */
+
+static irqreturn_t mxc_isi_pipe_irq_handler(int irq, void *priv)
+{
+ struct mxc_isi_pipe *pipe = priv;
+ const struct mxc_isi_ier_reg *ier_reg = pipe->isi->pdata->ier_reg;
+ u32 status;
+
+ status = mxc_isi_channel_irq_status(pipe, true);
+
+ if (status & CHNL_STS_FRM_STRD) {
+ if (!WARN_ON(!pipe->irq_handler))
+ pipe->irq_handler(pipe, status);
+ }
+
+ if (status & (CHNL_STS_AXI_WR_ERR_Y |
+ CHNL_STS_AXI_WR_ERR_U |
+ CHNL_STS_AXI_WR_ERR_V))
+ dev_dbg(pipe->isi->dev, "%s: IRQ AXI Error stat=0x%X\n",
+ __func__, status);
+
+ if (status & (ier_reg->panic_y_buf_en.mask |
+ ier_reg->panic_u_buf_en.mask |
+ ier_reg->panic_v_buf_en.mask))
+ dev_dbg(pipe->isi->dev, "%s: IRQ Panic OFLW Error stat=0x%X\n",
+ __func__, status);
+
+ if (status & (ier_reg->oflw_y_buf_en.mask |
+ ier_reg->oflw_u_buf_en.mask |
+ ier_reg->oflw_v_buf_en.mask))
+ dev_dbg(pipe->isi->dev, "%s: IRQ OFLW Error stat=0x%X\n",
+ __func__, status);
+
+ if (status & (ier_reg->excs_oflw_y_buf_en.mask |
+ ier_reg->excs_oflw_u_buf_en.mask |
+ ier_reg->excs_oflw_v_buf_en.mask))
+ dev_dbg(pipe->isi->dev, "%s: IRQ EXCS OFLW Error stat=0x%X\n",
+ __func__, status);
+
+ return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * Init & cleanup
+ */
+
+static const struct media_entity_operations mxc_isi_pipe_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id)
+{
+ struct mxc_isi_pipe *pipe = &isi->pipes[id];
+ struct v4l2_subdev *sd;
+ int irq;
+ int ret;
+
+ pipe->id = id;
+ pipe->isi = isi;
+ pipe->regs = isi->regs + id * isi->pdata->reg_offset;
+
+ mutex_init(&pipe->lock);
+
+ pipe->available_res = MXC_ISI_CHANNEL_RES_LINE_BUF
+ | MXC_ISI_CHANNEL_RES_OUTPUT_BUF;
+ pipe->acquired_res = 0;
+ pipe->chained_res = 0;
+ pipe->chained = false;
+
+ sd = &pipe->sd;
+ v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "mxc_isi.%d", pipe->id);
+ sd->dev = isi->dev;
+
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ sd->entity.ops = &mxc_isi_pipe_entity_ops;
+
+ pipe->pads[MXC_ISI_PIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pipe->pads[MXC_ISI_PIPE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, MXC_ISI_PIPE_PADS_NUM,
+ pipe->pads);
+ if (ret)
+ goto error;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0)
+ goto error;
+
+ /* Register IRQ handler. */
+ mxc_isi_channel_irq_clear(pipe);
+
+ irq = platform_get_irq(to_platform_device(isi->dev), id);
+ if (irq < 0) {
+ dev_err(pipe->isi->dev, "Failed to get IRQ (%d)\n", irq);
+ ret = irq;
+ goto error;
+ }
+
+ ret = devm_request_irq(isi->dev, irq, mxc_isi_pipe_irq_handler,
+ 0, dev_name(isi->dev), pipe);
+ if (ret < 0) {
+ dev_err(isi->dev, "failed to request IRQ (%d)\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&sd->entity);
+ mutex_destroy(&pipe->lock);
+
+ return ret;
+}
+
+void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe)
+{
+ struct v4l2_subdev *sd = &pipe->sd;
+
+ media_entity_cleanup(&sd->entity);
+ mutex_destroy(&pipe->lock);
+}
+
+int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
+ mxc_isi_pipe_irq_t irq_handler)
+{
+ const struct mxc_isi_bus_format_info *sink_info;
+ const struct mxc_isi_bus_format_info *src_info;
+ struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_mbus_framefmt *src_fmt;
+ struct v4l2_subdev *sd = &pipe->sd;
+ struct v4l2_subdev_state *state;
+ bool bypass;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK);
+ src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+ v4l2_subdev_unlock_state(state);
+
+ sink_info = mxc_isi_bus_format_by_code(sink_fmt->code,
+ MXC_ISI_PIPE_PAD_SINK);
+ src_info = mxc_isi_bus_format_by_code(src_fmt->code,
+ MXC_ISI_PIPE_PAD_SOURCE);
+
+ bypass = sink_fmt->width == src_fmt->width &&
+ sink_fmt->height == src_fmt->height &&
+ sink_info->encoding == src_info->encoding;
+
+ ret = mxc_isi_channel_acquire(pipe, irq_handler, bypass);
+ if (ret)
+ return ret;
+
+ /* Chain the channel if needed for wide resolutions. */
+ if (sink_fmt->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
+ ret = mxc_isi_channel_chain(pipe, bypass);
+ if (ret)
+ mxc_isi_channel_release(pipe);
+ }
+
+ return ret;
+}
+
+void mxc_isi_pipe_release(struct mxc_isi_pipe *pipe)
+{
+ mxc_isi_channel_release(pipe);
+ mxc_isi_channel_unchain(pipe);
+}
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h
new file mode 100644
index 000000000000..1b65eccdf0da
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h
@@ -0,0 +1,418 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+#ifndef __IMX8_ISI_REGS_H__
+#define __IMX8_ISI_REGS_H__
+
+#include <linux/bits.h>
+
+/* ISI Registers Define */
+/* Channel Control Register */
+#define CHNL_CTRL 0x0000
+#define CHNL_CTRL_CHNL_EN BIT(31)
+#define CHNL_CTRL_CLK_EN BIT(30)
+#define CHNL_CTRL_CHNL_BYPASS BIT(29)
+#define CHNL_CTRL_CHAIN_BUF(n) ((n) << 25)
+#define CHNL_CTRL_CHAIN_BUF_MASK GENMASK(26, 25)
+#define CHNL_CTRL_CHAIN_BUF_NO_CHAIN 0
+#define CHNL_CTRL_CHAIN_BUF_2_CHAIN 1
+#define CHNL_CTRL_SW_RST BIT(24)
+#define CHNL_CTRL_BLANK_PXL(n) ((n) << 16)
+#define CHNL_CTRL_BLANK_PXL_MASK GENMASK(23, 16)
+#define CHNL_CTRL_MIPI_VC_ID(n) ((n) << 6)
+#define CHNL_CTRL_MIPI_VC_ID_MASK GENMASK(7, 6)
+#define CHNL_CTRL_SRC_TYPE(n) ((n) << 4)
+#define CHNL_CTRL_SRC_TYPE_MASK BIT(4)
+#define CHNL_CTRL_SRC_TYPE_DEVICE 0
+#define CHNL_CTRL_SRC_TYPE_MEMORY 1
+#define CHNL_CTRL_SRC_INPUT(n) ((n) << 0)
+#define CHNL_CTRL_SRC_INPUT_MASK GENMASK(2, 0)
+
+/* Channel Image Control Register */
+#define CHNL_IMG_CTRL 0x0004
+#define CHNL_IMG_CTRL_FORMAT(n) ((n) << 24)
+#define CHNL_IMG_CTRL_FORMAT_MASK GENMASK(29, 24)
+#define CHNL_IMG_CTRL_FORMAT_RGBA8888 0x00
+#define CHNL_IMG_CTRL_FORMAT_ABGR8888 0x01
+#define CHNL_IMG_CTRL_FORMAT_ARGB8888 0x02
+#define CHNL_IMG_CTRL_FORMAT_RGBX888 0x03
+#define CHNL_IMG_CTRL_FORMAT_XBGR888 0x04
+#define CHNL_IMG_CTRL_FORMAT_XRGB888 0x05
+#define CHNL_IMG_CTRL_FORMAT_RGB888P 0x06
+#define CHNL_IMG_CTRL_FORMAT_BGR888P 0x07
+#define CHNL_IMG_CTRL_FORMAT_A2BGR10 0x08
+#define CHNL_IMG_CTRL_FORMAT_A2RGB10 0x09
+#define CHNL_IMG_CTRL_FORMAT_RGB565 0x0a
+#define CHNL_IMG_CTRL_FORMAT_RAW8 0x0b
+#define CHNL_IMG_CTRL_FORMAT_RAW10 0x0c
+#define CHNL_IMG_CTRL_FORMAT_RAW10P 0x0d
+#define CHNL_IMG_CTRL_FORMAT_RAW12 0x0e
+#define CHNL_IMG_CTRL_FORMAT_RAW16 0x0f
+#define CHNL_IMG_CTRL_FORMAT_YUV444_1P8P 0x10
+#define CHNL_IMG_CTRL_FORMAT_YUV444_2P8P 0x11
+#define CHNL_IMG_CTRL_FORMAT_YUV444_3P8P 0x12
+#define CHNL_IMG_CTRL_FORMAT_YUV444_1P8 0x13
+#define CHNL_IMG_CTRL_FORMAT_YUV444_1P10 0x14
+#define CHNL_IMG_CTRL_FORMAT_YUV444_2P10 0x15
+#define CHNL_IMG_CTRL_FORMAT_YUV444_3P10 0x16
+#define CHNL_IMG_CTRL_FORMAT_YUV444_1P10P 0x18
+#define CHNL_IMG_CTRL_FORMAT_YUV444_2P10P 0x19
+#define CHNL_IMG_CTRL_FORMAT_YUV444_3P10P 0x1a
+#define CHNL_IMG_CTRL_FORMAT_YUV444_1P12 0x1c
+#define CHNL_IMG_CTRL_FORMAT_YUV444_2P12 0x1d
+#define CHNL_IMG_CTRL_FORMAT_YUV444_3P12 0x1e
+#define CHNL_IMG_CTRL_FORMAT_YUV422_1P8P 0x20
+#define CHNL_IMG_CTRL_FORMAT_YUV422_2P8P 0x21
+#define CHNL_IMG_CTRL_FORMAT_YUV422_3P8P 0x22
+#define CHNL_IMG_CTRL_FORMAT_YUV422_1P10 0x24
+#define CHNL_IMG_CTRL_FORMAT_YUV422_2P10 0x25
+#define CHNL_IMG_CTRL_FORMAT_YUV422_3P10 0x26
+#define CHNL_IMG_CTRL_FORMAT_YUV422_1P10P 0x28
+#define CHNL_IMG_CTRL_FORMAT_YUV422_2P10P 0x29
+#define CHNL_IMG_CTRL_FORMAT_YUV422_3P10P 0x2a
+#define CHNL_IMG_CTRL_FORMAT_YUV422_1P12 0x2c
+#define CHNL_IMG_CTRL_FORMAT_YUV422_2P12 0x2d
+#define CHNL_IMG_CTRL_FORMAT_YUV422_3P12 0x2e
+#define CHNL_IMG_CTRL_FORMAT_YUV420_2P8P 0x31
+#define CHNL_IMG_CTRL_FORMAT_YUV420_3P8P 0x32
+#define CHNL_IMG_CTRL_FORMAT_YUV420_2P10 0x35
+#define CHNL_IMG_CTRL_FORMAT_YUV420_3P10 0x36
+#define CHNL_IMG_CTRL_FORMAT_YUV420_2P10P 0x39
+#define CHNL_IMG_CTRL_FORMAT_YUV420_3P10P 0x3a
+#define CHNL_IMG_CTRL_FORMAT_YUV420_2P12 0x3d
+#define CHNL_IMG_CTRL_FORMAT_YUV420_3P12 0x3e
+#define CHNL_IMG_CTRL_GBL_ALPHA_VAL(n) ((n) << 16)
+#define CHNL_IMG_CTRL_GBL_ALPHA_VAL_MASK GENMASK(23, 16)
+#define CHNL_IMG_CTRL_GBL_ALPHA_EN BIT(15)
+#define CHNL_IMG_CTRL_DEINT(n) ((n) << 12)
+#define CHNL_IMG_CTRL_DEINT_MASK GENMASK(14, 12)
+#define CHNL_IMG_CTRL_DEINT_WEAVE_ODD_EVEN 2
+#define CHNL_IMG_CTRL_DEINT_WEAVE_EVEN_ODD 3
+#define CHNL_IMG_CTRL_DEINT_BLEND_ODD_EVEN 4
+#define CHNL_IMG_CTRL_DEINT_BLEND_EVEN_ODD 5
+#define CHNL_IMG_CTRL_DEINT_LDOUBLE_ODD_EVEN 6
+#define CHNL_IMG_CTRL_DEINT_LDOUBLE_EVEN_ODD 7
+#define CHNL_IMG_CTRL_DEC_X(n) ((n) << 10)
+#define CHNL_IMG_CTRL_DEC_X_MASK GENMASK(11, 10)
+#define CHNL_IMG_CTRL_DEC_Y(n) ((n) << 8)
+#define CHNL_IMG_CTRL_DEC_Y_MASK GENMASK(9, 8)
+#define CHNL_IMG_CTRL_CROP_EN BIT(7)
+#define CHNL_IMG_CTRL_VFLIP_EN BIT(6)
+#define CHNL_IMG_CTRL_HFLIP_EN BIT(5)
+#define CHNL_IMG_CTRL_YCBCR_MODE BIT(3)
+#define CHNL_IMG_CTRL_CSC_MODE(n) ((n) << 1)
+#define CHNL_IMG_CTRL_CSC_MODE_MASK GENMASK(2, 1)
+#define CHNL_IMG_CTRL_CSC_MODE_YUV2RGB 0
+#define CHNL_IMG_CTRL_CSC_MODE_YCBCR2RGB 1
+#define CHNL_IMG_CTRL_CSC_MODE_RGB2YUV 2
+#define CHNL_IMG_CTRL_CSC_MODE_RGB2YCBCR 3
+#define CHNL_IMG_CTRL_CSC_BYPASS BIT(0)
+
+/* Channel Output Buffer Control Register */
+#define CHNL_OUT_BUF_CTRL 0x0008
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR BIT(15)
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR BIT(14)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V(n) ((n) << 6)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_MASK GENMASK(7, 6)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_75 3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U(n) ((n) << 3)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_MASK GENMASK(4, 3)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_75 3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y(n) ((n) << 0)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_MASK GENMASK(1, 0)
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_75 3
+
+/* Channel Image Configuration */
+#define CHNL_IMG_CFG 0x000c
+#define CHNL_IMG_CFG_HEIGHT(n) ((n) << 16)
+#define CHNL_IMG_CFG_HEIGHT_MASK GENMASK(28, 16)
+#define CHNL_IMG_CFG_WIDTH(n) ((n) << 0)
+#define CHNL_IMG_CFG_WIDTH_MASK GENMASK(12, 0)
+
+/* Channel Interrupt Enable Register */
+#define CHNL_IER 0x0010
+#define CHNL_IER_MEM_RD_DONE_EN BIT(31)
+#define CHNL_IER_LINE_RCVD_EN BIT(30)
+#define CHNL_IER_FRM_RCVD_EN BIT(29)
+#define CHNL_IER_AXI_WR_ERR_V_EN BIT(28)
+#define CHNL_IER_AXI_WR_ERR_U_EN BIT(27)
+#define CHNL_IER_AXI_WR_ERR_Y_EN BIT(26)
+#define CHNL_IER_AXI_RD_ERR_EN BIT(25)
+
+/* Channel Status Register */
+#define CHNL_STS 0x0014
+#define CHNL_STS_MEM_RD_DONE BIT(31)
+#define CHNL_STS_LINE_STRD BIT(30)
+#define CHNL_STS_FRM_STRD BIT(29)
+#define CHNL_STS_AXI_WR_ERR_V BIT(28)
+#define CHNL_STS_AXI_WR_ERR_U BIT(27)
+#define CHNL_STS_AXI_WR_ERR_Y BIT(26)
+#define CHNL_STS_AXI_RD_ERR BIT(25)
+#define CHNL_STS_OFLW_PANIC_V_BUF BIT(24)
+#define CHNL_STS_EXCS_OFLW_V_BUF BIT(23)
+#define CHNL_STS_OFLW_V_BUF BIT(22)
+#define CHNL_STS_OFLW_PANIC_U_BUF BIT(21)
+#define CHNL_STS_EXCS_OFLW_U_BUF BIT(20)
+#define CHNL_STS_OFLW_U_BUF BIT(19)
+#define CHNL_STS_OFLW_PANIC_Y_BUF BIT(18)
+#define CHNL_STS_EXCS_OFLW_Y_BUF BIT(17)
+#define CHNL_STS_OFLW_Y_BUF BIT(16)
+#define CHNL_STS_EARLY_VSYNC_ERR BIT(15)
+#define CHNL_STS_LATE_VSYNC_ERR BIT(14)
+#define CHNL_STS_MEM_RD_OFLOW BIT(10)
+#define CHNL_STS_BUF2_ACTIVE BIT(9)
+#define CHNL_STS_BUF1_ACTIVE BIT(8)
+#define CHNL_STS_OFLW_BYTES(n) ((n) << 0)
+#define CHNL_STS_OFLW_BYTES_MASK GENMASK(7, 0)
+
+/* Channel Scale Factor Register */
+#define CHNL_SCALE_FACTOR 0x0018
+#define CHNL_SCALE_FACTOR_Y_SCALE(n) ((n) << 16)
+#define CHNL_SCALE_FACTOR_Y_SCALE_MASK GENMASK(29, 16)
+#define CHNL_SCALE_FACTOR_X_SCALE(n) ((n) << 0)
+#define CHNL_SCALE_FACTOR_X_SCALE_MASK GENMASK(13, 0)
+
+/* Channel Scale Offset Register */
+#define CHNL_SCALE_OFFSET 0x001c
+#define CHNL_SCALE_OFFSET_Y_SCALE(n) ((n) << 16)
+#define CHNL_SCALE_OFFSET_Y_SCALE_MASK GENMASK(27, 16)
+#define CHNL_SCALE_OFFSET_X_SCALE(n) ((n) << 0)
+#define CHNL_SCALE_OFFSET_X_SCALE_MASK GENMASK(11, 0)
+
+/* Channel Crop Upper Left Corner Coordinate Register */
+#define CHNL_CROP_ULC 0x0020
+#define CHNL_CROP_ULC_X(n) ((n) << 16)
+#define CHNL_CROP_ULC_X_MASK GENMASK(27, 16)
+#define CHNL_CROP_ULC_Y(n) ((n) << 0)
+#define CHNL_CROP_ULC_Y_MASK GENMASK(11, 0)
+
+/* Channel Crop Lower Right Corner Coordinate Register */
+#define CHNL_CROP_LRC 0x0024
+#define CHNL_CROP_LRC_X(n) ((n) << 16)
+#define CHNL_CROP_LRC_X_MASK GENMASK(27, 16)
+#define CHNL_CROP_LRC_Y(n) ((n) << 0)
+#define CHNL_CROP_LRC_Y_MASK GENMASK(11, 0)
+
+/* Channel Color Space Conversion Coefficient Register 0 */
+#define CHNL_CSC_COEFF0 0x0028
+#define CHNL_CSC_COEFF0_A2(n) ((n) << 16)
+#define CHNL_CSC_COEFF0_A2_MASK GENMASK(26, 16)
+#define CHNL_CSC_COEFF0_A1(n) ((n) << 0)
+#define CHNL_CSC_COEFF0_A1_MASK GENMASK(10, 0)
+
+/* Channel Color Space Conversion Coefficient Register 1 */
+#define CHNL_CSC_COEFF1 0x002c
+#define CHNL_CSC_COEFF1_B1(n) ((n) << 16)
+#define CHNL_CSC_COEFF1_B1_MASK GENMASK(26, 16)
+#define CHNL_CSC_COEFF1_A3(n) ((n) << 0)
+#define CHNL_CSC_COEFF1_A3_MASK GENMASK(10, 0)
+
+/* Channel Color Space Conversion Coefficient Register 2 */
+#define CHNL_CSC_COEFF2 0x0030
+#define CHNL_CSC_COEFF2_B3(n) ((n) << 16)
+#define CHNL_CSC_COEFF2_B3_MASK GENMASK(26, 16)
+#define CHNL_CSC_COEFF2_B2(n) ((n) << 0)
+#define CHNL_CSC_COEFF2_B2_MASK GENMASK(10, 0)
+
+/* Channel Color Space Conversion Coefficient Register 3 */
+#define CHNL_CSC_COEFF3 0x0034
+#define CHNL_CSC_COEFF3_C2(n) ((n) << 16)
+#define CHNL_CSC_COEFF3_C2_MASK GENMASK(26, 16)
+#define CHNL_CSC_COEFF3_C1(n) ((n) << 0)
+#define CHNL_CSC_COEFF3_C1_MASK GENMASK(10, 0)
+
+/* Channel Color Space Conversion Coefficient Register 4 */
+#define CHNL_CSC_COEFF4 0x0038
+#define CHNL_CSC_COEFF4_D1(n) ((n) << 16)
+#define CHNL_CSC_COEFF4_D1_MASK GENMASK(24, 16)
+#define CHNL_CSC_COEFF4_C3(n) ((n) << 0)
+#define CHNL_CSC_COEFF4_C3_MASK GENMASK(10, 0)
+
+/* Channel Color Space Conversion Coefficient Register 5 */
+#define CHNL_CSC_COEFF5 0x003c
+#define CHNL_CSC_COEFF5_D3(n) ((n) << 16)
+#define CHNL_CSC_COEFF5_D3_MASK GENMASK(24, 16)
+#define CHNL_CSC_COEFF5_D2(n) ((n) << 0)
+#define CHNL_CSC_COEFF5_D2_MASK GENMASK(8, 0)
+
+/* Channel Alpha Value Register for ROI 0 */
+#define CHNL_ROI_0_ALPHA 0x0040
+#define CHNL_ROI_0_ALPHA_VAL(n) ((n) << 24)
+#define CHNL_ROI_0_ALPHA_MASK GENMASK(31, 24)
+#define CHNL_ROI_0_ALPHA_EN BIT(16)
+
+/* Channel Upper Left Coordinate Register for ROI 0 */
+#define CHNL_ROI_0_ULC 0x0044
+#define CHNL_ROI_0_ULC_X(n) ((n) << 16)
+#define CHNL_ROI_0_ULC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_0_ULC_Y(n) ((n) << 0)
+#define CHNL_ROI_0_ULC_Y_MASK GENMASK(11, 0)
+
+/* Channel Lower Right Coordinate Register for ROI 0 */
+#define CHNL_ROI_0_LRC 0x0048
+#define CHNL_ROI_0_LRC_X(n) ((n) << 16)
+#define CHNL_ROI_0_LRC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_0_LRC_Y(n) ((n) << 0)
+#define CHNL_ROI_0_LRC_Y_MASK GENMASK(11, 0)
+
+/* Channel Alpha Value Register for ROI 1 */
+#define CHNL_ROI_1_ALPHA 0x004c
+#define CHNL_ROI_1_ALPHA_VAL(n) ((n) << 24)
+#define CHNL_ROI_1_ALPHA_MASK GENMASK(31, 24)
+#define CHNL_ROI_1_ALPHA_EN BIT(16)
+
+/* Channel Upper Left Coordinate Register for ROI 1 */
+#define CHNL_ROI_1_ULC 0x0050
+#define CHNL_ROI_1_ULC_X(n) ((n) << 16)
+#define CHNL_ROI_1_ULC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_1_ULC_Y(n) ((n) << 0)
+#define CHNL_ROI_1_ULC_Y_MASK GENMASK(11, 0)
+
+/* Channel Lower Right Coordinate Register for ROI 1 */
+#define CHNL_ROI_1_LRC 0x0054
+#define CHNL_ROI_1_LRC_X(n) ((n) << 16)
+#define CHNL_ROI_1_LRC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_1_LRC_Y(n) ((n) << 0)
+#define CHNL_ROI_1_LRC_Y_MASK GENMASK(11, 0)
+
+/* Channel Alpha Value Register for ROI 2 */
+#define CHNL_ROI_2_ALPHA 0x0058
+#define CHNL_ROI_2_ALPHA_VAL(n) ((n) << 24)
+#define CHNL_ROI_2_ALPHA_MASK GENMASK(31, 24)
+#define CHNL_ROI_2_ALPHA_EN BIT(16)
+
+/* Channel Upper Left Coordinate Register for ROI 2 */
+#define CHNL_ROI_2_ULC 0x005c
+#define CHNL_ROI_2_ULC_X(n) ((n) << 16)
+#define CHNL_ROI_2_ULC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_2_ULC_Y(n) ((n) << 0)
+#define CHNL_ROI_2_ULC_Y_MASK GENMASK(11, 0)
+
+/* Channel Lower Right Coordinate Register for ROI 2 */
+#define CHNL_ROI_2_LRC 0x0060
+#define CHNL_ROI_2_LRC_X(n) ((n) << 16)
+#define CHNL_ROI_2_LRC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_2_LRC_Y(n) ((n) << 0)
+#define CHNL_ROI_2_LRC_Y_MASK GENMASK(11, 0)
+
+/* Channel Alpha Value Register for ROI 3 */
+#define CHNL_ROI_3_ALPHA 0x0064
+#define CHNL_ROI_3_ALPHA_VAL(n) ((n) << 24)
+#define CHNL_ROI_3_ALPHA_MASK GENMASK(31, 24)
+#define CHNL_ROI_3_ALPHA_EN BIT(16)
+
+/* Channel Upper Left Coordinate Register for ROI 3 */
+#define CHNL_ROI_3_ULC 0x0068
+#define CHNL_ROI_3_ULC_X(n) ((n) << 16)
+#define CHNL_ROI_3_ULC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_3_ULC_Y(n) ((n) << 0)
+#define CHNL_ROI_3_ULC_Y_MASK GENMASK(11, 0)
+
+/* Channel Lower Right Coordinate Register for ROI 3 */
+#define CHNL_ROI_3_LRC 0x006c
+#define CHNL_ROI_3_LRC_X(n) ((n) << 16)
+#define CHNL_ROI_3_LRC_X_MASK GENMASK(27, 16)
+#define CHNL_ROI_3_LRC_Y(n) ((n) << 0)
+#define CHNL_ROI_3_LRC_Y_MASK GENMASK(11, 0)
+/* Channel RGB or Luma (Y) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_Y 0x0070
+
+/* Channel Chroma (U/Cb/UV/CbCr) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_U 0x0074
+
+/* Channel Chroma (V/Cr) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_V 0x0078
+
+/* Channel Output Buffer Pitch */
+#define CHNL_OUT_BUF_PITCH 0x007c
+#define CHNL_OUT_BUF_PITCH_LINE_PITCH(n) ((n) << 0)
+#define CHNL_OUT_BUF_PITCH_LINE_PITCH_MASK GENMASK(15, 0)
+
+/* Channel Input Buffer Address */
+#define CHNL_IN_BUF_ADDR 0x0080
+
+/* Channel Input Buffer Pitch */
+#define CHNL_IN_BUF_PITCH 0x0084
+#define CHNL_IN_BUF_PITCH_FRM_PITCH(n) ((n) << 16)
+#define CHNL_IN_BUF_PITCH_FRM_PITCH_MASK GENMASK(31, 16)
+#define CHNL_IN_BUF_PITCH_LINE_PITCH(n) ((n) << 0)
+#define CHNL_IN_BUF_PITCH_LINE_PITCH_MASK GENMASK(15, 0)
+
+/* Channel Memory Read Control */
+#define CHNL_MEM_RD_CTRL 0x0088
+#define CHNL_MEM_RD_CTRL_IMG_TYPE(n) ((n) << 28)
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_MASK GENMASK(31, 28)
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_BGR8P 0x00
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_RGB8P 0x01
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8 0x02
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_RGBX8 0x03
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8 0x04
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_RGB565 0x05
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_A2BGR10 0x06
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_A2RGB10 0x07
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV444_1P8P 0x08
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV444_1P10 0x09
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV444_1P10P 0x0a
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV444_1P12 0x0b
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV444_1P8 0x0c
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV422_1P8P 0x0d
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV422_1P10 0x0e
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_YUV422_1P12 0x0f
+#define CHNL_MEM_RD_CTRL_READ_MEM BIT(0)
+
+/* Channel RGB or Luma (Y) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_Y 0x008c
+
+/* Channel Chroma (U/Cb/UV/CbCr) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_U 0x0090
+
+/* Channel Chroma (V/Cr) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_V 0x0094
+
+/* Channel scale image config */
+#define CHNL_SCL_IMG_CFG 0x0098
+#define CHNL_SCL_IMG_CFG_HEIGHT(n) ((n) << 16)
+#define CHNL_SCL_IMG_CFG_HEIGHT_MASK GENMASK(28, 16)
+#define CHNL_SCL_IMG_CFG_WIDTH(n) ((n) << 0)
+#define CHNL_SCL_IMG_CFG_WIDTH_MASK GENMASK(12, 0)
+
+/* Channel Flow Control Register */
+#define CHNL_FLOW_CTRL 0x009c
+#define CHNL_FLOW_CTRL_FC_DENOM_MASK GENMASK(7, 0)
+#define CHNL_FLOW_CTRL_FC_DENOM(n) ((n) << 0)
+#define CHNL_FLOW_CTRL_FC_NUMER_MASK GENMASK(23, 16)
+#define CHNL_FLOW_CTRL_FC_NUMER(n) ((n) << 0)
+
+/* Channel Output Y-Buffer 1 Extended Address Bits */
+#define CHNL_Y_BUF1_XTND_ADDR 0x00a0
+
+/* Channel Output U-Buffer 1 Extended Address Bits */
+#define CHNL_U_BUF1_XTND_ADDR 0x00a4
+
+/* Channel Output V-Buffer 1 Extended Address Bits */
+#define CHNL_V_BUF1_XTND_ADDR 0x00a8
+
+/* Channel Output Y-Buffer 2 Extended Address Bits */
+#define CHNL_Y_BUF2_XTND_ADDR 0x00ac
+
+/* Channel Output U-Buffer 2 Extended Address Bits */
+#define CHNL_U_BUF2_XTND_ADDR 0x00b0
+
+/* Channel Output V-Buffer 2 Extended Address Bits */
+#define CHNL_V_BUF2_XTND_ADDR 0x00b4
+
+/* Channel Input Buffer Extended Address Bits */
+#define CHNL_IN_BUF_XTND_ADDR 0x00b8
+
+#endif /* __IMX8_ISI_REGS_H__ */
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
new file mode 100644
index 000000000000..10840c9a0912
--- /dev/null
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
@@ -0,0 +1,1512 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Capture ISI subdev driver for i.MX8QXP/QM platform
+ *
+ * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
+ * used to process image from camera sensor to memory or DC
+ *
+ * Copyright (c) 2019 NXP Semiconductor
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/minmax.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "imx8-isi-core.h"
+#include "imx8-isi-regs.h"
+
+/* Keep the first entry matching MXC_ISI_DEF_PIXEL_FORMAT */
+static const struct mxc_isi_format_info mxc_isi_formats[] = {
+ /* YUV formats */
+ {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
+ | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_YUV422_1P8P,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV422_1P8P,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_YUVA32,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV444_1P8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 32 },
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV420_2P8P,
+ .color_planes = 2,
+ .mem_planes = 1,
+ .depth = { 8, 16 },
+ .hsub = 2,
+ .vsub = 2,
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV420_2P8P,
+ .mem_planes = 2,
+ .color_planes = 2,
+ .depth = { 8, 16 },
+ .hsub = 2,
+ .vsub = 2,
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV422_2P8P,
+ .color_planes = 2,
+ .mem_planes = 1,
+ .depth = { 8, 16 },
+ .hsub = 2,
+ .vsub = 1,
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV422_2P8P,
+ .mem_planes = 2,
+ .color_planes = 2,
+ .depth = { 8, 16 },
+ .hsub = 2,
+ .vsub = 1,
+ .encoding = MXC_ISI_ENC_YUV,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,
+ .fourcc = V4L2_PIX_FMT_YUV444M,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_YUV444_3P8P,
+ .mem_planes = 3,
+ .color_planes = 3,
+ .depth = { 8, 8, 8 },
+ .hsub = 1,
+ .vsub = 1,
+ .encoding = MXC_ISI_ENC_YUV,
+ },
+ /* RGB formats */
+ {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
+ | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_RGB565,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGB565,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RGB,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
+ | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_BGR8P,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_BGR888P,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 24 },
+ .encoding = MXC_ISI_ENC_RGB,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
+ | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_RGB8P,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGB888P,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 24 },
+ .encoding = MXC_ISI_ENC_RGB,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
+ | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 32 },
+ .encoding = MXC_ISI_ENC_RGB,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_ARGB8888,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 32 },
+ .encoding = MXC_ISI_ENC_RGB,
+ },
+ /*
+ * RAW formats
+ *
+ * The ISI shifts the 10-bit and 12-bit formats left by 6 and 4 bits
+ * when using CHNL_IMG_CTRL_FORMAT_RAW10 or MXC_ISI_OUT_FMT_RAW12
+ * respectively, to align the bits to the left and pad with zeros in
+ * the LSBs. The corresponding V4L2 formats are however right-aligned,
+ * we have to use CHNL_IMG_CTRL_FORMAT_RAW16 to avoid the left shift.
+ */
+ {
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y12_1X12,
+ .fourcc = V4L2_PIX_FMT_Y12,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_Y14_1X14,
+ .fourcc = V4L2_PIX_FMT_Y14,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .fourcc = V4L2_PIX_FMT_SBGGR14,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .fourcc = V4L2_PIX_FMT_SGBRG14,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .fourcc = V4L2_PIX_FMT_SGRBG14,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .fourcc = V4L2_PIX_FMT_SRGGB14,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 16 },
+ .encoding = MXC_ISI_ENC_RAW,
+ },
+ /* JPEG */
+ {
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .type = MXC_ISI_VIDEO_CAP,
+ .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW8,
+ .mem_planes = 1,
+ .color_planes = 1,
+ .depth = { 8 },
+ .encoding = MXC_ISI_ENC_RAW,
+ }
+};
+
+const struct mxc_isi_format_info *
+mxc_isi_format_by_fourcc(u32 fourcc, enum mxc_isi_video_type type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_formats); i++) {
+ const struct mxc_isi_format_info *fmt = &mxc_isi_formats[i];
+
+ if (fmt->fourcc == fourcc && fmt->type & type)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+const struct mxc_isi_format_info *
+mxc_isi_format_enum(unsigned int index, enum mxc_isi_video_type type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_formats); i++) {
+ const struct mxc_isi_format_info *fmt = &mxc_isi_formats[i];
+
+ if (!(fmt->type & type))
+ continue;
+
+ if (!index)
+ return fmt;
+
+ index--;
+ }
+
+ return NULL;
+}
+
+const struct mxc_isi_format_info *
+mxc_isi_format_try(struct mxc_isi_pipe *pipe, struct v4l2_pix_format_mplane *pix,
+ enum mxc_isi_video_type type)
+{
+ const struct mxc_isi_format_info *fmt;
+ unsigned int max_width;
+ unsigned int i;
+
+ max_width = pipe->id == pipe->isi->pdata->num_channels - 1
+ ? MXC_ISI_MAX_WIDTH_UNCHAINED
+ : MXC_ISI_MAX_WIDTH_CHAINED;
+
+ fmt = mxc_isi_format_by_fourcc(pix->pixelformat, type);
+ if (!fmt)
+ fmt = &mxc_isi_formats[0];
+
+ pix->width = clamp(pix->width, MXC_ISI_MIN_WIDTH, max_width);
+ pix->height = clamp(pix->height, MXC_ISI_MIN_HEIGHT, MXC_ISI_MAX_HEIGHT);
+ pix->pixelformat = fmt->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+
+ if (pix->colorspace == V4L2_COLORSPACE_DEFAULT) {
+ pix->colorspace = MXC_ISI_DEF_COLOR_SPACE;
+ pix->ycbcr_enc = MXC_ISI_DEF_YCBCR_ENC;
+ pix->quantization = MXC_ISI_DEF_QUANTIZATION;
+ pix->xfer_func = MXC_ISI_DEF_XFER_FUNC;
+ }
+
+ if (pix->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+ pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
+ if (pix->quantization == V4L2_QUANTIZATION_DEFAULT) {
+ bool is_rgb = fmt->encoding == MXC_ISI_ENC_RGB;
+
+ pix->quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, pix->colorspace,
+ pix->ycbcr_enc);
+ }
+ if (pix->xfer_func == V4L2_XFER_FUNC_DEFAULT)
+ pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
+
+ pix->num_planes = fmt->mem_planes;
+
+ for (i = 0; i < fmt->color_planes; ++i) {
+ struct v4l2_plane_pix_format *plane = &pix->plane_fmt[i];
+ unsigned int bpl;
+
+ /* The pitch must be identical for all planes. */
+ if (i == 0)
+ bpl = clamp(plane->bytesperline,
+ pix->width * fmt->depth[0] / 8,
+ 65535U);
+ else
+ bpl = pix->plane_fmt[0].bytesperline;
+
+ plane->bytesperline = bpl;
+
+ plane->sizeimage = plane->bytesperline * pix->height;
+ if (i >= 1)
+ plane->sizeimage /= fmt->vsub;
+ }
+
+ /*
+ * For single-planar pixel formats with multiple color planes,
+ * concatenate the size of all planes and clear all planes but the
+ * first one.
+ */
+ if (fmt->color_planes != fmt->mem_planes) {
+ for (i = 1; i < fmt->color_planes; ++i) {
+ struct v4l2_plane_pix_format *plane = &pix->plane_fmt[i];
+
+ pix->plane_fmt[0].sizeimage += plane->sizeimage;
+ plane->bytesperline = 0;
+ plane->sizeimage = 0;
+ }
+ }
+
+ return fmt;
+}
+
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
+ */
+
+static void mxc_isi_video_frame_write_done(struct mxc_isi_pipe *pipe,
+ u32 status)
+{
+ struct mxc_isi_video *video = &pipe->video;
+ struct device *dev = pipe->isi->dev;
+ struct mxc_isi_buffer *next_buf;
+ struct mxc_isi_buffer *buf;
+ enum mxc_isi_buf_id buf_id;
+
+ spin_lock(&video->buf_lock);
+
+ /*
+ * The ISI hardware handles buffers using a ping-pong mechanism with
+ * two sets of destination addresses (with shadow registers to allow
+ * programming addresses for all planes atomically) named BUF1 and
+ * BUF2. Addresses can be loaded and copied to shadow registers at any
+ * at any time.
+ *
+ * The hardware keeps track of which buffer is being written to and
+ * automatically switches to the other buffer at frame end, copying the
+ * corresponding address to another set of shadow registers that track
+ * the address being written to. The active buffer tracking bits are
+ * accessible through the CHNL_STS register.
+ *
+ * BUF1 BUF2 | Event | Action
+ * | |
+ * | | Program initial buffers
+ * | | B0 in BUF1, B1 in BUF2
+ * | Start ISI |
+ * +----+ | |
+ * | B0 | | |
+ * +----+ | |
+ * +----+ | FRM IRQ 0 | B0 complete, BUF2 now active
+ * | B1 | | | Program B2 in BUF1
+ * +----+ | |
+ * +----+ | FRM IRQ 1 | B1 complete, BUF1 now active
+ * | B2 | | | Program B3 in BUF2
+ * +----+ | |
+ * +----+ | FRM IRQ 2 | B2 complete, BUF2 now active
+ * | B3 | | | Program B4 in BUF1
+ * +----+ | |
+ * +----+ | FRM IRQ 3 | B3 complete, BUF1 now active
+ * | B4 | | | Program B5 in BUF2
+ * +----+ | |
+ * ... | |
+ *
+ * Races between address programming and buffer switching can be
+ * detected by checking if a frame end interrupt occurred after
+ * programming the addresses.
+ *
+ * As none of the shadow registers are accessible, races can occur
+ * between address programming and buffer switching. It is possible to
+ * detect the race condition by checking if a frame end interrupt
+ * occurred after programming the addresses, but impossible to
+ * determine if the race has been won or lost.
+ *
+ * In addition to this, we need to use discard buffers if no pending
+ * buffers are available. To simplify handling of discard buffer, we
+ * need to allocate three of them, as two can be active concurrently
+ * and we need to still be able to get hold of a next buffer. The logic
+ * could be improved to use two buffers only, but as all discard
+ * buffers share the same memory, an additional buffer is cheap.
+ */
+
+ /* Check which buffer has just completed. */
+ buf_id = pipe->isi->pdata->buf_active_reverse
+ ? (status & CHNL_STS_BUF1_ACTIVE ? MXC_ISI_BUF2 : MXC_ISI_BUF1)
+ : (status & CHNL_STS_BUF1_ACTIVE ? MXC_ISI_BUF1 : MXC_ISI_BUF2);
+
+ buf = list_first_entry_or_null(&video->out_active,
+ struct mxc_isi_buffer, list);
+
+ /* Safety check, this should really never happen. */
+ if (!buf) {
+ dev_warn(dev, "trying to access empty active list\n");
+ goto done;
+ }
+
+ /*
+ * If the buffer that has completed doesn't match the buffer on the
+ * front of the active list, it means we have lost one frame end
+ * interrupt (or possibly a large odd number of interrupts, although
+ * quite unlikely).
+ *
+ * For instance, if IRQ1 is lost and we handle IRQ2, both B1 and B2
+ * have been completed, but B3 hasn't been programmed, BUF2 still
+ * addresses B1 and the ISI is now writing in B1 instead of B3. We
+ * can't complete B2 as that would result in out-of-order completion.
+ *
+ * The only option is to ignore this interrupt and try again. When IRQ3
+ * will be handled, we will complete B1 and be in sync again.
+ */
+ if (buf->id != buf_id) {
+ dev_dbg(dev, "buffer ID mismatch (expected %u, got %u), skipping\n",
+ buf->id, buf_id);
+
+ /*
+ * Increment the frame count by two to account for the missed
+ * and the ignored interrupts.
+ */
+ video->frame_count += 2;
+ goto done;
+ }
+
+ /* Pick the next buffer and queue it to the hardware. */
+ next_buf = list_first_entry_or_null(&video->out_pending,
+ struct mxc_isi_buffer, list);
+ if (!next_buf) {
+ next_buf = list_first_entry_or_null(&video->out_discard,
+ struct mxc_isi_buffer, list);
+
+ /* Safety check, this should never happen. */
+ if (!next_buf) {
+ dev_warn(dev, "trying to access empty discard list\n");
+ goto done;
+ }
+ }
+
+ mxc_isi_channel_set_outbuf(pipe, next_buf->dma_addrs, buf_id);
+ next_buf->id = buf_id;
+
+ /*
+ * Check if we have raced with the end of frame interrupt. If so, we
+ * can't tell if the ISI has recorded the new address, or is still
+ * using the previous buffer. We must assume the latter as that is the
+ * worst case.
+ *
+ * For instance, if we are handling IRQ1 and now detect the FRM
+ * interrupt, assume B2 has completed and the ISI has switched to BUF2
+ * using B1 just before we programmed B3. Unlike in the previous race
+ * condition, B3 has been programmed and will be written to the next
+ * time the ISI switches to BUF2. We can however handle this exactly as
+ * the first race condition, as we'll program B3 (still at the head of
+ * the pending list) when handling IRQ3.
+ */
+ status = mxc_isi_channel_irq_status(pipe, false);
+ if (status & CHNL_STS_FRM_STRD) {
+ dev_dbg(dev, "raced with frame end interrupt\n");
+ video->frame_count += 2;
+ goto done;
+ }
+
+ /*
+ * The next buffer has been queued successfully, move it to the active
+ * list, and complete the current buffer.
+ */
+ list_move_tail(&next_buf->list, &video->out_active);
+
+ if (!buf->discard) {
+ list_del_init(&buf->list);
+ buf->v4l2_buf.sequence = video->frame_count;
+ buf->v4l2_buf.vb2_buf.timestamp = ktime_get_ns();
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_DONE);
+ } else {
+ list_move_tail(&buf->list, &video->out_discard);
+ }
+
+ video->frame_count++;
+
+done:
+ spin_unlock(&video->buf_lock);
+}
+
+static void mxc_isi_video_free_discard_buffers(struct mxc_isi_video *video)
+{
+ unsigned int i;
+
+ for (i = 0; i < video->pix.num_planes; i++) {
+ struct mxc_isi_dma_buffer *buf = &video->discard_buffer[i];
+
+ if (!buf->addr)
+ continue;
+
+ dma_free_coherent(video->pipe->isi->dev, buf->size, buf->addr,
+ buf->dma);
+ buf->addr = NULL;
+ }
+}
+
+static int mxc_isi_video_alloc_discard_buffers(struct mxc_isi_video *video)
+{
+ unsigned int i, j;
+
+ /* Allocate memory for each plane. */
+ for (i = 0; i < video->pix.num_planes; i++) {
+ struct mxc_isi_dma_buffer *buf = &video->discard_buffer[i];
+
+ buf->size = PAGE_ALIGN(video->pix.plane_fmt[i].sizeimage);
+ buf->addr = dma_alloc_coherent(video->pipe->isi->dev, buf->size,
+ &buf->dma, GFP_DMA | GFP_KERNEL);
+ if (!buf->addr) {
+ mxc_isi_video_free_discard_buffers(video);
+ return -ENOMEM;
+ }
+
+ dev_dbg(video->pipe->isi->dev,
+ "discard buffer plane %u: %zu bytes @%pad (CPU address %p)\n",
+ i, buf->size, &buf->dma, buf->addr);
+ }
+
+ /* Fill the DMA addresses in the discard buffers. */
+ for (i = 0; i < ARRAY_SIZE(video->buf_discard); ++i) {
+ struct mxc_isi_buffer *buf = &video->buf_discard[i];
+
+ buf->discard = true;
+
+ for (j = 0; j < video->pix.num_planes; ++j)
+ buf->dma_addrs[j] = video->discard_buffer[j].dma;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_video_validate_format(struct mxc_isi_video *video)
+{
+ const struct v4l2_mbus_framefmt *format;
+ const struct mxc_isi_format_info *info;
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev *sd = &video->pipe->sd;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ info = mxc_isi_format_by_fourcc(video->pix.pixelformat,
+ MXC_ISI_VIDEO_CAP);
+ format = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+
+ if (format->code != info->mbus_code ||
+ format->width != video->pix.width ||
+ format->height != video->pix.height) {
+ dev_dbg(video->pipe->isi->dev,
+ "%s: configuration mismatch, 0x%04x/%ux%u != 0x%04x/%ux%u\n",
+ __func__, format->code, format->width, format->height,
+ info->mbus_code, video->pix.width, video->pix.height);
+ ret = -EINVAL;
+ }
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static void mxc_isi_video_return_buffers(struct mxc_isi_video *video,
+ enum vb2_buffer_state state)
+{
+ struct mxc_isi_buffer *buf;
+
+ spin_lock_irq(&video->buf_lock);
+
+ while (!list_empty(&video->out_active)) {
+ buf = list_first_entry(&video->out_active,
+ struct mxc_isi_buffer, list);
+ list_del_init(&buf->list);
+ if (buf->discard)
+ continue;
+
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, state);
+ }
+
+ while (!list_empty(&video->out_pending)) {
+ buf = list_first_entry(&video->out_pending,
+ struct mxc_isi_buffer, list);
+ list_del_init(&buf->list);
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, state);
+ }
+
+ while (!list_empty(&video->out_discard)) {
+ buf = list_first_entry(&video->out_discard,
+ struct mxc_isi_buffer, list);
+ list_del_init(&buf->list);
+ }
+
+ INIT_LIST_HEAD(&video->out_active);
+ INIT_LIST_HEAD(&video->out_pending);
+ INIT_LIST_HEAD(&video->out_discard);
+
+ spin_unlock_irq(&video->buf_lock);
+}
+
+static void mxc_isi_video_queue_first_buffers(struct mxc_isi_video *video)
+{
+ unsigned int discard;
+ unsigned int i;
+
+ lockdep_assert_held(&video->buf_lock);
+
+ /*
+ * Queue two ISI channel output buffers. We are not guaranteed to have
+ * any buffer in the pending list when this function is called from the
+ * system resume handler. Use pending buffers as much as possible, and
+ * use discard buffers to fill the remaining slots.
+ */
+
+ /* How many discard buffers do we need to queue first ? */
+ discard = list_empty(&video->out_pending) ? 2
+ : list_is_singular(&video->out_pending) ? 1
+ : 0;
+
+ for (i = 0; i < 2; ++i) {
+ enum mxc_isi_buf_id buf_id = i == 0 ? MXC_ISI_BUF1
+ : MXC_ISI_BUF2;
+ struct mxc_isi_buffer *buf;
+ struct list_head *list;
+
+ list = i < discard ? &video->out_discard : &video->out_pending;
+ buf = list_first_entry(list, struct mxc_isi_buffer, list);
+
+ mxc_isi_channel_set_outbuf(video->pipe, buf->dma_addrs, buf_id);
+ buf->id = buf_id;
+ list_move_tail(&buf->list, &video->out_active);
+ }
+}
+
+static inline struct mxc_isi_buffer *to_isi_buffer(struct vb2_v4l2_buffer *v4l2_buf)
+{
+ return container_of(v4l2_buf, struct mxc_isi_buffer, v4l2_buf);
+}
+
+int mxc_isi_video_queue_setup(const struct v4l2_pix_format_mplane *format,
+ const struct mxc_isi_format_info *info,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[])
+{
+ unsigned int i;
+
+ if (*num_planes) {
+ if (*num_planes != info->mem_planes)
+ return -EINVAL;
+
+ for (i = 0; i < info->mem_planes; ++i) {
+ if (sizes[i] < format->plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ *num_planes = info->mem_planes;
+
+ for (i = 0; i < info->mem_planes; ++i)
+ sizes[i] = format->plane_fmt[i].sizeimage;
+
+ return 0;
+}
+
+void mxc_isi_video_buffer_init(struct vb2_buffer *vb2, dma_addr_t dma_addrs[3],
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *pix)
+{
+ unsigned int i;
+
+ for (i = 0; i < info->mem_planes; ++i)
+ dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb2, i);
+
+ /*
+ * For single-planar pixel formats with multiple color planes, split
+ * the buffer into color planes.
+ */
+ if (info->color_planes != info->mem_planes) {
+ unsigned int size = pix->plane_fmt[0].bytesperline * pix->height;
+
+ for (i = 1; i < info->color_planes; ++i) {
+ unsigned int vsub = i > 1 ? info->vsub : 1;
+
+ dma_addrs[i] = dma_addrs[i - 1] + size / vsub;
+ }
+ }
+}
+
+int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2,
+ const struct mxc_isi_format_info *info,
+ const struct v4l2_pix_format_mplane *pix)
+{
+ unsigned int i;
+
+ for (i = 0; i < info->mem_planes; i++) {
+ unsigned long size = pix->plane_fmt[i].sizeimage;
+
+ if (vb2_plane_size(vb2, i) < size) {
+ dev_err(isi->dev, "User buffer too small (%ld < %ld)\n",
+ vb2_plane_size(vb2, i), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb2, i, size);
+ }
+
+ return 0;
+}
+
+static int mxc_isi_vb2_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(q);
+
+ return mxc_isi_video_queue_setup(&video->pix, video->fmtinfo,
+ num_buffers, num_planes, sizes);
+}
+
+static int mxc_isi_vb2_buffer_init(struct vb2_buffer *vb2)
+{
+ struct mxc_isi_buffer *buf = to_isi_buffer(to_vb2_v4l2_buffer(vb2));
+ struct mxc_isi_video *video = vb2_get_drv_priv(vb2->vb2_queue);
+
+ mxc_isi_video_buffer_init(vb2, buf->dma_addrs, video->fmtinfo,
+ &video->pix);
+
+ return 0;
+}
+
+static int mxc_isi_vb2_buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(vb2->vb2_queue);
+
+ return mxc_isi_video_buffer_prepare(video->pipe->isi, vb2,
+ video->fmtinfo, &video->pix);
+}
+
+static void mxc_isi_vb2_buffer_queue(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb2);
+ struct mxc_isi_buffer *buf = to_isi_buffer(v4l2_buf);
+ struct mxc_isi_video *video = vb2_get_drv_priv(vb2->vb2_queue);
+
+ spin_lock_irq(&video->buf_lock);
+ list_add_tail(&buf->list, &video->out_pending);
+ spin_unlock_irq(&video->buf_lock);
+}
+
+static void mxc_isi_video_init_channel(struct mxc_isi_video *video)
+{
+ struct mxc_isi_pipe *pipe = video->pipe;
+
+ mxc_isi_channel_get(pipe);
+
+ mutex_lock(video->ctrls.handler.lock);
+ mxc_isi_channel_set_alpha(pipe, video->ctrls.alpha);
+ mxc_isi_channel_set_flip(pipe, video->ctrls.hflip, video->ctrls.vflip);
+ mutex_unlock(video->ctrls.handler.lock);
+
+ mxc_isi_channel_set_output_format(pipe, video->fmtinfo, &video->pix);
+}
+
+static int mxc_isi_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(q);
+ unsigned int i;
+ int ret;
+
+ /* Initialize the ISI channel. */
+ mxc_isi_video_init_channel(video);
+
+ spin_lock_irq(&video->buf_lock);
+
+ /* Add the discard buffers to the out_discard list. */
+ for (i = 0; i < ARRAY_SIZE(video->buf_discard); ++i) {
+ struct mxc_isi_buffer *buf = &video->buf_discard[i];
+
+ list_add_tail(&buf->list, &video->out_discard);
+ }
+
+ /* Queue the first buffers. */
+ mxc_isi_video_queue_first_buffers(video);
+
+ /* Clear frame count */
+ video->frame_count = 0;
+
+ spin_unlock_irq(&video->buf_lock);
+
+ ret = mxc_isi_pipe_enable(video->pipe);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ mxc_isi_channel_put(video->pipe);
+ mxc_isi_video_return_buffers(video, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+
+static void mxc_isi_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_video *video = vb2_get_drv_priv(q);
+
+ mxc_isi_pipe_disable(video->pipe);
+ mxc_isi_channel_put(video->pipe);
+
+ mxc_isi_video_return_buffers(video, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops mxc_isi_vb2_qops = {
+ .queue_setup = mxc_isi_vb2_queue_setup,
+ .buf_init = mxc_isi_vb2_buffer_init,
+ .buf_prepare = mxc_isi_vb2_buffer_prepare,
+ .buf_queue = mxc_isi_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = mxc_isi_vb2_start_streaming,
+ .stop_streaming = mxc_isi_vb2_stop_streaming,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static inline struct mxc_isi_video *ctrl_to_isi_video(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct mxc_isi_video, ctrls.handler);
+}
+
+static int mxc_isi_video_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mxc_isi_video *video = ctrl_to_isi_video(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ video->ctrls.alpha = ctrl->val;
+ break;
+ case V4L2_CID_VFLIP:
+ video->ctrls.vflip = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ video->ctrls.hflip = ctrl->val;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mxc_isi_video_ctrl_ops = {
+ .s_ctrl = mxc_isi_video_s_ctrl,
+};
+
+static int mxc_isi_video_ctrls_create(struct mxc_isi_video *video)
+{
+ struct v4l2_ctrl_handler *handler = &video->ctrls.handler;
+ int ret;
+
+ v4l2_ctrl_handler_init(handler, 3);
+
+ v4l2_ctrl_new_std(handler, &mxc_isi_video_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+
+ v4l2_ctrl_new_std(handler, &mxc_isi_video_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(handler, &mxc_isi_video_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ if (handler->error) {
+ ret = handler->error;
+ v4l2_ctrl_handler_free(handler);
+ return ret;
+ }
+
+ video->vdev.ctrl_handler = handler;
+
+ return 0;
+}
+
+static void mxc_isi_video_ctrls_delete(struct mxc_isi_video *video)
+{
+ v4l2_ctrl_handler_free(&video->ctrls.handler);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int mxc_isi_video_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, MXC_ISI_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MXC_ISI_CAPTURE, sizeof(cap->card));
+
+ return 0;
+}
+
+static int mxc_isi_video_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ const struct mxc_isi_format_info *fmt;
+ unsigned int index = f->index;
+ unsigned int i;
+
+ if (f->mbus_code) {
+ /*
+ * If a media bus code is specified, only enumerate formats
+ * compatible with it.
+ */
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_formats); i++) {
+ fmt = &mxc_isi_formats[i];
+ if (fmt->mbus_code != f->mbus_code)
+ continue;
+
+ if (index == 0)
+ break;
+
+ index--;
+ }
+
+ if (i == ARRAY_SIZE(mxc_isi_formats))
+ return -EINVAL;
+ } else {
+ /* Otherwise, enumerate all formatS. */
+ if (f->index >= ARRAY_SIZE(mxc_isi_formats))
+ return -EINVAL;
+
+ fmt = &mxc_isi_formats[f->index];
+ }
+
+ f->pixelformat = fmt->fourcc;
+ f->flags |= V4L2_FMT_FLAG_CSC_COLORSPACE | V4L2_FMT_FLAG_CSC_YCBCR_ENC
+ | V4L2_FMT_FLAG_CSC_QUANTIZATION | V4L2_FMT_FLAG_CSC_XFER_FUNC;
+
+ return 0;
+}
+
+static int mxc_isi_video_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+
+ f->fmt.pix_mp = video->pix;
+
+ return 0;
+}
+
+static int mxc_isi_video_try_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+
+ mxc_isi_format_try(video->pipe, &f->fmt.pix_mp, MXC_ISI_VIDEO_CAP);
+ return 0;
+}
+
+static int mxc_isi_video_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+ if (vb2_is_busy(&video->vb2_q))
+ return -EBUSY;
+
+ video->fmtinfo = mxc_isi_format_try(video->pipe, pix, MXC_ISI_VIDEO_CAP);
+ video->pix = *pix;
+
+ return 0;
+}
+
+static int mxc_isi_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ struct media_device *mdev = &video->pipe->isi->media_dev;
+ struct media_pipeline *pipe;
+ int ret;
+
+ if (vb2_queue_is_busy(&video->vb2_q, file))
+ return -EBUSY;
+
+ /*
+ * Get a pipeline for the video node and start it. This must be done
+ * here and not in the queue .start_streaming() handler, so that
+ * pipeline start errors can be reported from VIDIOC_STREAMON and not
+ * delayed until subsequent VIDIOC_QBUF calls.
+ */
+ mutex_lock(&mdev->graph_mutex);
+
+ ret = mxc_isi_pipe_acquire(video->pipe, &mxc_isi_video_frame_write_done);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
+ pipe = media_entity_pipeline(&video->vdev.entity) ? : &video->pipe->pipe;
+
+ ret = __video_device_pipeline_start(&video->vdev, pipe);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ goto err_release;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ /* Verify that the video format matches the output of the subdev. */
+ ret = mxc_isi_video_validate_format(video);
+ if (ret)
+ goto err_stop;
+
+ /* Allocate buffers for discard operation. */
+ ret = mxc_isi_video_alloc_discard_buffers(video);
+ if (ret)
+ goto err_stop;
+
+ ret = vb2_streamon(&video->vb2_q, type);
+ if (ret)
+ goto err_free;
+
+ video->is_streaming = true;
+
+ return 0;
+
+err_free:
+ mxc_isi_video_free_discard_buffers(video);
+err_stop:
+ video_device_pipeline_stop(&video->vdev);
+err_release:
+ mxc_isi_pipe_release(video->pipe);
+ return ret;
+}
+
+static void mxc_isi_video_cleanup_streaming(struct mxc_isi_video *video)
+{
+ lockdep_assert_held(&video->lock);
+
+ if (!video->is_streaming)
+ return;
+
+ mxc_isi_video_free_discard_buffers(video);
+ video_device_pipeline_stop(&video->vdev);
+ mxc_isi_pipe_release(video->pipe);
+
+ video->is_streaming = false;
+}
+
+static int mxc_isi_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ int ret;
+
+ ret = vb2_ioctl_streamoff(file, priv, type);
+ if (ret)
+ return ret;
+
+ mxc_isi_video_cleanup_streaming(video);
+
+ return 0;
+}
+
+static int mxc_isi_video_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ const struct mxc_isi_format_info *info;
+ unsigned int max_width;
+ unsigned int h_align;
+ unsigned int v_align;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ info = mxc_isi_format_by_fourcc(fsize->pixel_format, MXC_ISI_VIDEO_CAP);
+ if (!info)
+ return -EINVAL;
+
+ h_align = max_t(unsigned int, info->hsub, 1);
+ v_align = max_t(unsigned int, info->vsub, 1);
+
+ max_width = video->pipe->id == video->pipe->isi->pdata->num_channels - 1
+ ? MXC_ISI_MAX_WIDTH_UNCHAINED
+ : MXC_ISI_MAX_WIDTH_CHAINED;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = ALIGN(MXC_ISI_MIN_WIDTH, h_align);
+ fsize->stepwise.min_height = ALIGN(MXC_ISI_MIN_HEIGHT, v_align);
+ fsize->stepwise.max_width = ALIGN_DOWN(max_width, h_align);
+ fsize->stepwise.max_height = ALIGN_DOWN(MXC_ISI_MAX_HEIGHT, v_align);
+ fsize->stepwise.step_width = h_align;
+ fsize->stepwise.step_height = v_align;
+
+ /*
+ * The width can be further restricted due to line buffer sharing
+ * between pipelines when scaling, but we have no way to know here if
+ * the scaler will be used.
+ */
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mxc_isi_video_ioctl_ops = {
+ .vidioc_querycap = mxc_isi_video_querycap,
+
+ .vidioc_enum_fmt_vid_cap = mxc_isi_video_enum_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = mxc_isi_video_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = mxc_isi_video_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = mxc_isi_video_g_fmt,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+
+ .vidioc_streamon = mxc_isi_video_streamon,
+ .vidioc_streamoff = mxc_isi_video_streamoff,
+
+ .vidioc_enum_framesizes = mxc_isi_video_enum_framesizes,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------------------
+ * Video device file operations
+ */
+
+static int mxc_isi_video_open(struct file *file)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ int ret;
+
+ ret = v4l2_fh_open(file);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(video->pipe->isi->dev);
+ if (ret) {
+ v4l2_fh_release(file);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_video_release(struct file *file)
+{
+ struct mxc_isi_video *video = video_drvdata(file);
+ int ret;
+
+ ret = vb2_fop_release(file);
+ if (ret)
+ dev_err(video->pipe->isi->dev, "%s fail\n", __func__);
+
+ mutex_lock(&video->lock);
+ mxc_isi_video_cleanup_streaming(video);
+ mutex_unlock(&video->lock);
+
+ pm_runtime_put(video->pipe->isi->dev);
+ return ret;
+}
+
+static const struct v4l2_file_operations mxc_isi_video_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_isi_video_open,
+ .release = mxc_isi_video_release,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * Suspend & resume
+ */
+
+void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_video *video = &pipe->video;
+
+ if (!video->is_streaming)
+ return;
+
+ mxc_isi_pipe_disable(pipe);
+ mxc_isi_channel_put(pipe);
+
+ spin_lock_irq(&video->buf_lock);
+
+ /*
+ * Move the active buffers back to the pending or discard list. We must
+ * iterate the active list backward and move the buffers to the head of
+ * the pending list to preserve the buffer queueing order.
+ */
+ while (!list_empty(&video->out_active)) {
+ struct mxc_isi_buffer *buf =
+ list_last_entry(&video->out_active,
+ struct mxc_isi_buffer, list);
+
+ if (buf->discard)
+ list_move(&buf->list, &video->out_discard);
+ else
+ list_move(&buf->list, &video->out_pending);
+ }
+
+ spin_unlock_irq(&video->buf_lock);
+}
+
+int mxc_isi_video_resume(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_video *video = &pipe->video;
+
+ if (!video->is_streaming)
+ return 0;
+
+ mxc_isi_video_init_channel(video);
+
+ spin_lock_irq(&video->buf_lock);
+ mxc_isi_video_queue_first_buffers(video);
+ spin_unlock_irq(&video->buf_lock);
+
+ return mxc_isi_pipe_enable(pipe);
+}
+
+/* -----------------------------------------------------------------------------
+ * Registration
+ */
+
+int mxc_isi_video_register(struct mxc_isi_pipe *pipe,
+ struct v4l2_device *v4l2_dev)
+{
+ struct mxc_isi_video *video = &pipe->video;
+ struct v4l2_pix_format_mplane *pix = &video->pix;
+ struct video_device *vdev = &video->vdev;
+ struct vb2_queue *q = &video->vb2_q;
+ int ret = -ENOMEM;
+
+ video->pipe = pipe;
+
+ mutex_init(&video->lock);
+ spin_lock_init(&video->buf_lock);
+
+ pix->width = MXC_ISI_DEF_WIDTH;
+ pix->height = MXC_ISI_DEF_HEIGHT;
+ pix->pixelformat = MXC_ISI_DEF_PIXEL_FORMAT;
+ pix->colorspace = MXC_ISI_DEF_COLOR_SPACE;
+ pix->ycbcr_enc = MXC_ISI_DEF_YCBCR_ENC;
+ pix->quantization = MXC_ISI_DEF_QUANTIZATION;
+ pix->xfer_func = MXC_ISI_DEF_XFER_FUNC;
+ video->fmtinfo = mxc_isi_format_try(video->pipe, pix, MXC_ISI_VIDEO_CAP);
+
+ memset(vdev, 0, sizeof(*vdev));
+ snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.%d.capture", pipe->id);
+
+ vdev->fops = &mxc_isi_video_fops;
+ vdev->ioctl_ops = &mxc_isi_video_ioctl_ops;
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->minor = -1;
+ vdev->release = video_device_release_empty;
+ vdev->queue = q;
+ vdev->lock = &video->lock;
+
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE
+ | V4L2_CAP_IO_MC;
+ video_set_drvdata(vdev, video);
+
+ INIT_LIST_HEAD(&video->out_pending);
+ INIT_LIST_HEAD(&video->out_active);
+ INIT_LIST_HEAD(&video->out_discard);
+
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->drv_priv = video;
+ q->ops = &mxc_isi_vb2_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mxc_isi_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 2;
+ q->lock = &video->lock;
+ q->dev = pipe->isi->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto err_free_ctx;
+
+ video->pad.flags = MEDIA_PAD_FL_SINK;
+ vdev->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ ret = media_entity_pads_init(&vdev->entity, 1, &video->pad);
+ if (ret)
+ goto err_free_ctx;
+
+ ret = mxc_isi_video_ctrls_create(video);
+ if (ret)
+ goto err_me_cleanup;
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret)
+ goto err_ctrl_free;
+
+ ret = media_create_pad_link(&pipe->sd.entity,
+ MXC_ISI_PIPE_PAD_SOURCE,
+ &vdev->entity, 0,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_video_unreg;
+
+ return 0;
+
+err_video_unreg:
+ video_unregister_device(vdev);
+err_ctrl_free:
+ mxc_isi_video_ctrls_delete(video);
+err_me_cleanup:
+ media_entity_cleanup(&vdev->entity);
+err_free_ctx:
+ return ret;
+}
+
+void mxc_isi_video_unregister(struct mxc_isi_pipe *pipe)
+{
+ struct mxc_isi_video *video = &pipe->video;
+ struct video_device *vdev = &video->vdev;
+
+ mutex_lock(&video->lock);
+
+ if (video_is_registered(vdev)) {
+ video_unregister_device(vdev);
+ mxc_isi_video_ctrls_delete(video);
+ media_entity_cleanup(&vdev->entity);
+ }
+
+ mutex_unlock(&video->lock);
+}
diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c
index 3ce84d0f078c..023ed40c6b08 100644
--- a/drivers/media/platform/nxp/mx2_emmaprp.c
+++ b/drivers/media/platform/nxp/mx2_emmaprp.c
@@ -888,7 +888,7 @@ unreg_dev:
return ret;
}
-static int emmaprp_remove(struct platform_device *pdev)
+static void emmaprp_remove(struct platform_device *pdev)
{
struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
@@ -898,13 +898,11 @@ static int emmaprp_remove(struct platform_device *pdev)
v4l2_m2m_release(pcdev->m2m_dev);
v4l2_device_unregister(&pcdev->v4l2_dev);
mutex_destroy(&pcdev->dev_mutex);
-
- return 0;
}
static struct platform_driver emmaprp_pdrv = {
.probe = emmaprp_probe,
- .remove = emmaprp_remove,
+ .remove_new = emmaprp_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
index 2031bde13a93..0f8ac29d038d 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
@@ -334,13 +334,14 @@ static const struct csid_format csid_formats[] = {
},
};
-static void csid_configure_stream(struct csid_device *csid, u8 enable)
+static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc)
{
struct csid_testgen_config *tg = &csid->testgen;
u32 val;
u32 phy_sel = 0;
u8 lane_cnt = csid->phy.lane_cnt;
- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+ /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
+ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
const struct csid_format *format = csid_get_fmt_entry(csid->formats, csid->nformats,
input_format->code);
@@ -351,8 +352,7 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
phy_sel = csid->phy.csiphy_id;
if (enable) {
- u8 vc = 0; /* Virtual Channel 0 */
- u8 dt_id = vc * 4;
+ u8 dt_id = vc;
if (tg->enabled) {
/* Config Test Generator */
@@ -395,42 +395,42 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
val |= format->data_type << RDI_CFG0_DATA_TYPE;
val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
val |= dt_id << RDI_CFG0_DT_ID;
- writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+ writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
/* CSID_TIMESTAMP_STB_POST_IRQ */
val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
- writel_relaxed(val, csid->base + CSID_RDI_CFG1(0));
+ writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc));
val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(0));
+ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc));
val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(0));
+ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc));
val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(0));
+ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc));
val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(0));
+ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc));
val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(0));
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc));
val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(0));
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc));
val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(0));
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc));
val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(0));
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc));
val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+ writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
- val = readl_relaxed(csid->base + CSID_RDI_CFG0(0));
+ val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc));
val |= 1 << RDI_CFG0_ENABLE;
- writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+ writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
}
if (tg->enabled) {
@@ -456,7 +456,16 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
else
val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
- writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+ writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
+}
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+ u8 i;
+ /* Loop through all enabled VCs and configure stream for each */
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
+ if (csid->phy.en_vc & BIT(i))
+ __csid_configure_stream(csid, enable, i);
}
static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
@@ -502,6 +511,7 @@ static irqreturn_t csid_isr(int irq, void *dev)
struct csid_device *csid = dev;
u32 val;
u8 reset_done;
+ int i;
val = readl_relaxed(csid->base + CSID_TOP_IRQ_STATUS);
writel_relaxed(val, csid->base + CSID_TOP_IRQ_CLEAR);
@@ -510,8 +520,12 @@ static irqreturn_t csid_isr(int irq, void *dev)
val = readl_relaxed(csid->base + CSID_CSI2_RX_IRQ_STATUS);
writel_relaxed(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR);
- val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(0));
- writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(0));
+ /* Read and clear IRQ status for each enabled RDI channel */
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
+ if (csid->phy.en_vc & BIT(i)) {
+ val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i));
+ writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i));
+ }
val = 1 << IRQ_CMD_CLEAR;
writel_relaxed(val, csid->base + CSID_IRQ_CMD);
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 88f188e0f750..6360314f04a6 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -196,6 +196,8 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
return ret;
}
+ csid->phy.need_vc_update = true;
+
enable_irq(csid->irq);
ret = csid->ops->reset(csid);
@@ -249,7 +251,10 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
return -ENOLINK;
}
- csid->ops->configure_stream(csid, enable);
+ if (csid->phy.need_vc_update) {
+ csid->ops->configure_stream(csid, enable);
+ csid->phy.need_vc_update = false;
+ }
return 0;
}
@@ -460,6 +465,7 @@ static int csid_set_format(struct v4l2_subdev *sd,
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
+ int i;
format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
if (format == NULL)
@@ -468,14 +474,14 @@ static int csid_set_format(struct v4l2_subdev *sd,
csid_try_format(csid, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
- /* Propagate the format from sink to source */
+ /* Propagate the format from sink to source pads */
if (fmt->pad == MSM_CSID_PAD_SINK) {
- format = __csid_get_format(csid, sd_state, MSM_CSID_PAD_SRC,
- fmt->which);
+ for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i) {
+ format = __csid_get_format(csid, sd_state, i, fmt->which);
- *format = fmt->format;
- csid_try_format(csid, sd_state, MSM_CSID_PAD_SRC, format,
- fmt->which);
+ *format = fmt->format;
+ csid_try_format(csid, sd_state, i, format, fmt->which);
+ }
}
return 0;
@@ -738,7 +744,6 @@ static int csid_link_setup(struct media_entity *entity,
struct csid_device *csid;
struct csiphy_device *csiphy;
struct csiphy_lanes_cfg *lane_cfg;
- struct v4l2_subdev_format format = { 0 };
sd = media_entity_to_v4l2_subdev(entity);
csid = v4l2_get_subdevdata(sd);
@@ -761,11 +766,22 @@ static int csid_link_setup(struct media_entity *entity,
lane_cfg = &csiphy->cfg.csi2->lane_cfg;
csid->phy.lane_cnt = lane_cfg->num_data;
csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
+ }
+ /* Decide which virtual channels to enable based on which source pads are enabled */
+ if (local->flags & MEDIA_PAD_FL_SOURCE) {
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct csid_device *csid = v4l2_get_subdevdata(sd);
+ struct device *dev = csid->camss->dev;
+
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ csid->phy.en_vc |= BIT(local->index - 1);
+ else
+ csid->phy.en_vc &= ~BIT(local->index - 1);
- /* Reset format on source pad to sink pad format */
- format.pad = MSM_CSID_PAD_SRC;
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- csid_set_format(&csid->subdev, NULL, &format);
+ csid->phy.need_vc_update = true;
+
+ dev_dbg(dev, "%s: Enabled CSID virtual channels mask 0x%x\n",
+ __func__, csid->phy.en_vc);
}
return 0;
@@ -816,6 +832,7 @@ int msm_csid_register_entity(struct csid_device *csid,
struct v4l2_subdev *sd = &csid->subdev;
struct media_pad *pads = csid->pads;
struct device *dev = csid->camss->dev;
+ int i;
int ret;
v4l2_subdev_init(sd, &csid_v4l2_ops);
@@ -852,7 +869,8 @@ int msm_csid_register_entity(struct csid_device *csid,
}
pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+ for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i)
+ pads[i].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
sd->entity.ops = &csid_media_ops;
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index f06040e44c51..d4b48432a097 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -19,8 +19,13 @@
#include <media/v4l2-subdev.h>
#define MSM_CSID_PAD_SINK 0
-#define MSM_CSID_PAD_SRC 1
-#define MSM_CSID_PADS_NUM 2
+#define MSM_CSID_PAD_FIRST_SRC 1
+#define MSM_CSID_PADS_NUM 5
+
+#define MSM_CSID_PAD_SRC (MSM_CSID_PAD_FIRST_SRC)
+
+/* CSID hardware can demultiplex up to 4 outputs */
+#define MSM_CSID_MAX_SRC_STREAMS 4
#define DATA_TYPE_EMBEDDED_DATA_8BIT 0x12
#define DATA_TYPE_YUV420_8BIT 0x18
@@ -81,6 +86,8 @@ struct csid_phy_config {
u8 csiphy_id;
u8 lane_cnt;
u32 lane_assign;
+ u32 en_vc;
+ u8 need_vc_update;
};
struct csid_device;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
index 8e506a805d11..02494c89da91 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-170.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
@@ -409,7 +409,7 @@ static int vfe_get_output(struct vfe_line *line)
spin_lock_irqsave(&vfe->output_lock, flags);
output = &line->output;
- if (output->state != VFE_OUTPUT_OFF) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is running\n");
goto error;
}
@@ -462,7 +462,7 @@ static int vfe_enable_output(struct vfe_line *line)
ops->reg_update_clear(vfe, line->id);
- if (output->state != VFE_OUTPUT_OFF) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 3aa962b5663b..f70aad2e8c23 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -94,6 +94,8 @@ static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n)
#define RDI_WM(n) ((IS_LITE ? 0 : 23) + (n))
#define RDI_COMP_GROUP(n) ((IS_LITE ? 0 : 11) + (n))
+#define MAX_VFE_OUTPUT_LINES 4
+
static u32 vfe_hw_version(struct vfe_device *vfe)
{
u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
@@ -171,12 +173,26 @@ static inline void vfe_reg_update_clear(struct vfe_device *vfe,
static void vfe_enable_irq_common(struct vfe_device *vfe)
{
- /* enable only the IRQs used: rup and comp_done irqs for RDI0 */
+ /* enable reset ack IRQ and top BUS status IRQ */
writel_relaxed(IRQ_MASK_0_RESET_ACK | IRQ_MASK_0_BUS_TOP_IRQ,
vfe->base + VFE_IRQ_MASK(0));
- writel_relaxed(BUS_IRQ_MASK_0_RDI_RUP(vfe, 0) |
- BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(0)),
- vfe->base + VFE_BUS_IRQ_MASK(0));
+}
+
+static void vfe_enable_lines_irq(struct vfe_device *vfe)
+{
+ int i;
+ u32 bus_irq_mask = 0;
+
+ for (i = 0; i < MAX_VFE_OUTPUT_LINES; i++) {
+ /* Enable IRQ for newly added lines, but also keep already running lines's IRQ */
+ if (vfe->line[i].output.state == VFE_OUTPUT_RESERVED ||
+ vfe->line[i].output.state == VFE_OUTPUT_ON) {
+ bus_irq_mask |= BUS_IRQ_MASK_0_RDI_RUP(vfe, i)
+ | BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i));
+ }
+ }
+
+ writel_relaxed(bus_irq_mask, vfe->base + VFE_BUS_IRQ_MASK(0));
}
static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id);
@@ -193,6 +209,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
{
struct vfe_device *vfe = dev;
u32 status;
+ int i;
status = readl_relaxed(vfe->base + VFE_IRQ_STATUS(0));
writel_relaxed(status, vfe->base + VFE_IRQ_CLEAR(0));
@@ -207,11 +224,14 @@ static irqreturn_t vfe_isr(int irq, void *dev)
writel_relaxed(status, vfe->base + VFE_BUS_IRQ_CLEAR(0));
writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
- if (status & BUS_IRQ_MASK_0_RDI_RUP(vfe, 0))
- vfe_isr_reg_update(vfe, 0);
+ /* Loop through all WMs IRQs */
+ for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) {
+ if (status & BUS_IRQ_MASK_0_RDI_RUP(vfe, i))
+ vfe_isr_reg_update(vfe, i);
- if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(0)))
- vfe_isr_wm_done(vfe, 0);
+ if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i)))
+ vfe_isr_wm_done(vfe, i);
+ }
}
return IRQ_HANDLED;
@@ -234,24 +254,23 @@ static int vfe_get_output(struct vfe_line *line)
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output;
unsigned long flags;
- int wm_idx;
spin_lock_irqsave(&vfe->output_lock, flags);
output = &line->output;
- if (output->state != VFE_OUTPUT_OFF) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is running\n");
goto error;
}
output->wm_num = 1;
- wm_idx = vfe_reserve_wm(vfe, line->id);
- if (wm_idx < 0) {
- dev_err(vfe->camss->dev, "Can not reserve wm\n");
- goto error_get_wm;
- }
- output->wm_idx[0] = wm_idx;
+ /* Correspondence between VFE line number and WM number.
+ * line 0 -> RDI 0, line 1 -> RDI1, line 2 -> RDI2, line 3 -> PIX/RDI3
+ * Note this 1:1 mapping will not work for PIX streams.
+ */
+ output->wm_idx[0] = line->id;
+ vfe->wm_output_map[line->id] = line->id;
output->drop_update_idx = 0;
@@ -259,11 +278,9 @@ static int vfe_get_output(struct vfe_line *line)
return 0;
-error_get_wm:
- vfe_release_wm(vfe, output->wm_idx[0]);
- output->state = VFE_OUTPUT_OFF;
error:
spin_unlock_irqrestore(&vfe->output_lock, flags);
+ output->state = VFE_OUTPUT_OFF;
return -EINVAL;
}
@@ -279,7 +296,7 @@ static int vfe_enable_output(struct vfe_line *line)
vfe_reg_update_clear(vfe, line->id);
- if (output->state != VFE_OUTPUT_OFF) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags);
@@ -360,6 +377,8 @@ static int vfe_enable(struct vfe_line *line)
vfe->stream_count++;
+ vfe_enable_lines_irq(vfe);
+
mutex_unlock(&vfe->stream_lock);
ret = vfe_get_output(line);
@@ -566,7 +585,7 @@ static const struct camss_video_ops vfe_video_ops_480 = {
static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
{
vfe->video_ops = vfe_video_ops_480;
- vfe->line_num = 1;
+ vfe->line_num = MAX_VFE_OUTPUT_LINES;
}
const struct vfe_hw_ops vfe_ops_480 = {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
index 4fd265d01883..239d3d4ac666 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -194,7 +194,7 @@ static int vfe_enable_output(struct vfe_line *line)
ops->reg_update_clear(vfe, line->id);
- if (output->state != VFE_OUTPUT_RESERVED) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n", output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags);
return -EINVAL;
@@ -289,7 +289,7 @@ static int vfe_get_output(struct vfe_line *line)
spin_lock_irqsave(&vfe->output_lock, flags);
output = &line->output;
- if (output->state != VFE_OUTPUT_OFF) {
+ if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is running\n");
goto error;
}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index a26e4a5d87b6..e0832f3f4f25 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -740,6 +740,7 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
int ret;
if (enable) {
+ line->output.state = VFE_OUTPUT_RESERVED;
ret = vfe->ops->vfe_enable(line);
if (ret < 0)
dev_err(vfe->camss->dev,
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 41deda232e4a..898f32177b12 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -342,7 +342,9 @@ static struct v4l2_subdev *video_remote_subdev(struct camss_video *video,
static int video_get_subdev_format(struct camss_video *video,
struct v4l2_format *format)
{
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
u32 pad;
int ret;
@@ -351,8 +353,8 @@ static int video_get_subdev_format(struct camss_video *video,
if (subdev == NULL)
return -EPIPE;
+ memset(&fmt, 0, sizeof(fmt));
fmt.pad = pad;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
if (ret)
@@ -493,9 +495,11 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
struct v4l2_subdev *subdev;
int ret;
- ret = video_device_pipeline_start(vdev, &video->pipe);
- if (ret < 0)
+ ret = video_device_pipeline_alloc_start(vdev);
+ if (ret < 0) {
+ dev_err(video->camss->dev, "Failed to start media pipeline: %d\n", ret);
goto flush_buffers;
+ }
ret = video_check_format(video);
if (ret < 0)
@@ -537,6 +541,7 @@ static void video_stop_streaming(struct vb2_queue *q)
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
+ int ret;
entity = &vdev->entity;
while (1) {
@@ -551,7 +556,18 @@ static void video_stop_streaming(struct vb2_queue *q)
entity = pad->entity;
subdev = media_entity_to_v4l2_subdev(entity);
- v4l2_subdev_call(subdev, video, s_stream, 0);
+ ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+
+ if (entity->use_count > 1) {
+ /* Don't stop if other instances of the pipeline are still running */
+ dev_dbg(video->camss->dev, "Video pipeline still used, don't stop streaming.\n");
+ return;
+ }
+
+ if (ret) {
+ dev_err(video->camss->dev, "Video pipeline stop failed: %d\n", ret);
+ return;
+ }
}
video_device_pipeline_stop(vdev);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 9cda284f1e71..1ef26aea3eae 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1320,7 +1320,7 @@ static int camss_register_entities(struct camss *camss)
struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
ret = media_create_pad_link(&csid->entity,
- MSM_CSID_PAD_SRC,
+ MSM_CSID_PAD_FIRST_SRC + j,
&vfe->entity,
MSM_VFE_PAD_SINK,
0);
@@ -1725,7 +1725,7 @@ void camss_delete(struct camss *camss)
*
* Always returns 0.
*/
-static int camss_remove(struct platform_device *pdev)
+static void camss_remove(struct platform_device *pdev)
{
struct camss *camss = platform_get_drvdata(pdev);
@@ -1735,8 +1735,6 @@ static int camss_remove(struct platform_device *pdev)
if (atomic_read(&camss->ref_count) == 0)
camss_delete(camss);
-
- return 0;
}
static const struct of_device_id camss_dt_match[] = {
@@ -1798,7 +1796,7 @@ static const struct dev_pm_ops camss_pm_ops = {
static struct platform_driver qcom_camss_driver = {
.probe = camss_probe,
- .remove = camss_remove,
+ .remove_new = camss_remove,
.driver = {
.name = "qcom-camss",
.of_match_table = camss_dt_match,
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 990a1519f968..2ae867cb4c48 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -416,7 +416,7 @@ err_core_put:
return ret;
}
-static int venus_remove(struct platform_device *pdev)
+static void venus_remove(struct platform_device *pdev)
{
struct venus_core *core = platform_get_drvdata(pdev);
const struct venus_pm_ops *pm_ops = core->pm_ops;
@@ -447,8 +447,6 @@ static int venus_remove(struct platform_device *pdev)
mutex_destroy(&core->pm_lock);
mutex_destroy(&core->lock);
venus_dbgfs_deinit(core);
-
- return ret;
}
static void venus_core_shutdown(struct platform_device *pdev)
@@ -891,7 +889,7 @@ MODULE_DEVICE_TABLE(of, venus_dt_match);
static struct platform_driver qcom_venus_driver = {
.probe = venus_probe,
- .remove = venus_remove,
+ .remove_new = venus_remove,
.driver = {
.name = "qcom-venus",
.of_match_table = venus_dt_match,
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 32551c2602a9..4f81669986ba 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -107,7 +107,6 @@ struct venus_format {
* @vcodec1_clks: an array of vcodec1 struct clk pointers
* @video_path: an interconnect handle to video to/from memory path
* @cpucfg_path: an interconnect handle to cpu configuration path
- * @opp_table: an device OPP table handle
* @has_opp_table: does OPP table exist
* @pmdomains: an array of pmdomains struct device pointers
* @opp_dl_venus: an device-link for device OPP
@@ -317,6 +316,14 @@ enum venus_dec_state {
VENUS_DEC_STATE_DRC = 7,
};
+enum venus_enc_state {
+ VENUS_ENC_STATE_DEINIT = 0,
+ VENUS_ENC_STATE_INIT = 1,
+ VENUS_ENC_STATE_ENCODING = 2,
+ VENUS_ENC_STATE_STOPPED = 3,
+ VENUS_ENC_STATE_DRAIN = 4,
+};
+
struct venus_ts_metadata {
bool used;
u64 ts_ns;
@@ -428,6 +435,7 @@ struct venus_inst {
u8 quantization;
u8 xfer_func;
enum venus_dec_state codec_state;
+ enum venus_enc_state enc_state;
wait_queue_head_t reconf_wait;
unsigned int subscriptions;
int buf_count;
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 61ff20a7e935..cfb11c551167 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -38,8 +38,8 @@ static void venus_reset_cpu(struct venus_core *core)
writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR);
writel(0, wrapper_base + WRAPPER_CPA_START_ADDR);
writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR);
- writel(0, wrapper_base + WRAPPER_NONPIX_START_ADDR);
- writel(0, wrapper_base + WRAPPER_NONPIX_END_ADDR);
+ writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR);
+ writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR);
if (IS_V6(core)) {
/* Bring XTSS out of reset */
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index ab6a29ffc81e..a2ceab7f9ddb 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -988,8 +988,8 @@ static u32 get_framesize_raw_p010(u32 width, u32 height)
{
u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
- y_stride = ALIGN(width * 2, 256);
- uv_stride = ALIGN(width * 2, 256);
+ y_stride = ALIGN(width * 2, 128);
+ uv_stride = ALIGN(width * 2, 128);
y_sclines = ALIGN(height, 32);
uv_sclines = ALIGN((height + 1) >> 1, 16);
y_plane = y_stride * y_sclines;
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index 930b743f225e..bc3f8ff05840 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -1257,7 +1257,30 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*tm);
break;
}
+ case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2: {
+ struct hfi_quantization_range_v2 *in = pdata, *range = prop_data;
+ u32 min_qp, max_qp;
+
+ min_qp = in->min_qp.qp_packed;
+ max_qp = in->max_qp.qp_packed;
+ /* We'll be packing in the qp, so make sure we
+ * won't be losing data when masking
+ */
+ if (min_qp > 0xff || max_qp > 0xff)
+ return -ERANGE;
+
+ range->min_qp.layer_id = 0xFF;
+ range->max_qp.layer_id = 0xFF;
+ range->min_qp.qp_packed = (min_qp & 0xFF) | ((min_qp & 0xFF) << 8) |
+ ((min_qp & 0xFF) << 16);
+ range->max_qp.qp_packed = (max_qp & 0xFF) | ((max_qp & 0xFF) << 8) |
+ ((max_qp & 0xFF) << 16);
+ range->min_qp.enable = 7;
+ range->max_qp.enable = 7;
+ pkt->shdr.hdr.size += sizeof(u32) + sizeof(*range);
+ break;
+ }
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE:
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index d2d6719a2ba4..105792a68060 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -487,6 +487,11 @@
#define HFI_PROPERTY_PARAM_VENC_SESSION_QP 0x2005006
#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION 0x2005007
#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE 0x2005008
+/*
+ * Note: HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 is
+ * specific to HFI_VERSION_6XX and HFI_VERSION_4XX only
+ */
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 0x2005009
#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION 0x2005009
#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER 0x200500a
#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION 0x200500b
@@ -827,6 +832,19 @@ struct hfi_quantization_range {
u32 layer_id;
};
+struct hfi_quantization_v2 {
+ u32 qp_packed;
+ u32 layer_id;
+ u32 enable;
+ u32 reserved[3];
+};
+
+struct hfi_quantization_range_v2 {
+ struct hfi_quantization_v2 min_qp;
+ struct hfi_quantization_v2 max_qp;
+ u32 reserved[4];
+};
+
#define HFI_LTR_MODE_DISABLE 0x0
#define HFI_LTR_MODE_MANUAL 0x1
#define HFI_LTR_MODE_PERIODIC 0x2
diff --git a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c
index ea25c451222b..a9be31ec6927 100644
--- a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c
+++ b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c
@@ -93,7 +93,7 @@
#define LCU_MIN_SIZE_PELS 16
#define SIZE_SEI_USERDATA 4096
-#define H265D_MAX_SLICE 600
+#define H265D_MAX_SLICE 3600
#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T
#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(u32))
#define SIZE_H265D_VPP_CMD_PER_BUF 256
@@ -1021,7 +1021,7 @@ static u32 h264d_persist1_size(void)
static u32 h265d_persist1_size(void)
{
return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + H265_NUM_TILE
- * sizeof(u32)), HFI_DMA_ALIGNMENT);
+ * sizeof(u32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA), HFI_DMA_ALIGNMENT);
}
static u32 vp8d_persist1_size(void)
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 4ceaba37e2e5..51a53bf82bd3 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -31,15 +31,15 @@
*/
static const struct venus_format vdec_formats[] = {
{
- .pixfmt = V4L2_PIX_FMT_QC08C,
+ .pixfmt = V4L2_PIX_FMT_NV12,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
}, {
- .pixfmt = V4L2_PIX_FMT_QC10C,
+ .pixfmt = V4L2_PIX_FMT_QC08C,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
- },{
- .pixfmt = V4L2_PIX_FMT_NV12,
+ }, {
+ .pixfmt = V4L2_PIX_FMT_QC10C,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
}, {
@@ -204,8 +204,13 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
pixmp->height);
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ unsigned int stride = pixmp->width;
+
+ if (pixmp->pixelformat == V4L2_PIX_FMT_P010)
+ stride *= 2;
+
pfmt[0].sizeimage = szimage;
- pfmt[0].bytesperline = ALIGN(pixmp->width, 128);
+ pfmt[0].bytesperline = ALIGN(stride, 128);
} else {
pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M);
pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage);
@@ -526,6 +531,7 @@ static int
vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
{
struct venus_inst *inst = to_inst(file);
+ struct vb2_queue *dst_vq;
struct hfi_frame_data fdata = {0};
int ret;
@@ -556,6 +562,13 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
inst->codec_state = VENUS_DEC_STATE_DRAIN;
inst->drain_active = true;
}
+ } else if (cmd->cmd == V4L2_DEC_CMD_START &&
+ inst->codec_state == VENUS_DEC_STATE_STOPPED) {
+ dst_vq = v4l2_m2m_get_vq(inst->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ vb2_clear_last_buffer_dequeued(dst_vq);
+
+ inst->codec_state = VENUS_DEC_STATE_DECODING;
}
unlock:
@@ -1774,7 +1787,7 @@ err_vdev_release:
return ret;
}
-static int vdec_remove(struct platform_device *pdev)
+static void vdec_remove(struct platform_device *pdev)
{
struct venus_core *core = dev_get_drvdata(pdev->dev.parent);
@@ -1783,8 +1796,6 @@ static int vdec_remove(struct platform_device *pdev)
if (core->pm_ops->vdec_put)
core->pm_ops->vdec_put(core->dev_dec);
-
- return 0;
}
static __maybe_unused int vdec_runtime_suspend(struct device *dev)
@@ -1825,7 +1836,7 @@ MODULE_DEVICE_TABLE(of, vdec_dt_match);
static struct platform_driver qcom_venus_dec_driver = {
.probe = vdec_probe,
- .remove = vdec_remove,
+ .remove_new = vdec_remove,
.driver = {
.name = "qcom-venus-decoder",
.of_match_table = vdec_dt_match,
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index cdb12546c4fa..4666f42feea3 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -520,6 +520,51 @@ static int venc_subscribe_event(struct v4l2_fh *fh,
}
}
+static int
+venc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd)
+{
+ struct venus_inst *inst = to_inst(file);
+ struct hfi_frame_data fdata = {0};
+ int ret = 0;
+
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
+ if (ret)
+ return ret;
+
+ mutex_lock(&inst->lock);
+
+ if (cmd->cmd == V4L2_ENC_CMD_STOP &&
+ inst->enc_state == VENUS_ENC_STATE_ENCODING) {
+ /*
+ * Implement V4L2_ENC_CMD_STOP by enqueue an empty buffer on
+ * encoder input to signal EOS.
+ */
+ if (!(inst->streamon_out && inst->streamon_cap))
+ goto unlock;
+
+ fdata.buffer_type = HFI_BUFFER_INPUT;
+ fdata.flags |= HFI_BUFFERFLAG_EOS;
+ fdata.device_addr = 0xdeadb000;
+
+ ret = hfi_session_process_buf(inst, &fdata);
+
+ inst->enc_state = VENUS_ENC_STATE_DRAIN;
+ } else if (cmd->cmd == V4L2_ENC_CMD_START) {
+ if (inst->enc_state == VENUS_ENC_STATE_DRAIN) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ if (inst->enc_state == VENUS_ENC_STATE_STOPPED) {
+ vb2_clear_last_buffer_dequeued(&inst->fh.m2m_ctx->cap_q_ctx.q);
+ inst->enc_state = VENUS_ENC_STATE_ENCODING;
+ }
+ }
+
+unlock:
+ mutex_unlock(&inst->lock);
+ return ret;
+}
+
static const struct v4l2_ioctl_ops venc_ioctl_ops = {
.vidioc_querycap = venc_querycap,
.vidioc_enum_fmt_vid_cap = venc_enum_fmt,
@@ -548,6 +593,7 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = {
.vidioc_subscribe_event = venc_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+ .vidioc_encoder_cmd = venc_encoder_cmd,
};
static int venc_pm_get(struct venus_inst *inst)
@@ -617,6 +663,7 @@ static int venc_set_properties(struct venus_inst *inst)
struct hfi_idr_period idrp;
struct hfi_quantization quant;
struct hfi_quantization_range quant_range;
+ struct hfi_quantization_range_v2 quant_range_v2;
struct hfi_enable en;
struct hfi_ltr_mode ltr_mode;
struct hfi_intra_refresh intra_refresh = {};
@@ -825,16 +872,40 @@ static int venc_set_properties(struct venus_inst *inst)
if (ret)
return ret;
- ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
- if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
- quant_range.min_qp = ctr->hevc_min_qp;
- quant_range.max_qp = ctr->hevc_max_qp;
+ if (inst->core->res->hfi_version == HFI_VERSION_4XX ||
+ inst->core->res->hfi_version == HFI_VERSION_6XX) {
+ ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2;
+
+ if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
+ quant_range_v2.min_qp.qp_packed = ctr->hevc_min_qp;
+ quant_range_v2.max_qp.qp_packed = ctr->hevc_max_qp;
+ } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) {
+ quant_range_v2.min_qp.qp_packed = ctr->vp8_min_qp;
+ quant_range_v2.max_qp.qp_packed = ctr->vp8_max_qp;
+ } else {
+ quant_range_v2.min_qp.qp_packed = ctr->h264_min_qp;
+ quant_range_v2.max_qp.qp_packed = ctr->h264_max_qp;
+ }
+
+ ret = hfi_session_set_property(inst, ptype, &quant_range_v2);
} else {
- quant_range.min_qp = ctr->h264_min_qp;
- quant_range.max_qp = ctr->h264_max_qp;
+ ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+
+ if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
+ quant_range.min_qp = ctr->hevc_min_qp;
+ quant_range.max_qp = ctr->hevc_max_qp;
+ } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) {
+ quant_range.min_qp = ctr->vp8_min_qp;
+ quant_range.max_qp = ctr->vp8_max_qp;
+ } else {
+ quant_range.min_qp = ctr->h264_min_qp;
+ quant_range.max_qp = ctr->h264_max_qp;
+ }
+
+ quant_range.layer_id = 0;
+ ret = hfi_session_set_property(inst, ptype, &quant_range);
}
- quant_range.layer_id = 0;
- ret = hfi_session_set_property(inst, ptype, &quant_range);
+
if (ret)
return ret;
@@ -1196,6 +1267,8 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
if (ret)
goto error;
+ inst->enc_state = VENUS_ENC_STATE_ENCODING;
+
mutex_unlock(&inst->lock);
return 0;
@@ -1215,10 +1288,21 @@ error:
static void venc_vb2_buf_queue(struct vb2_buffer *vb)
{
struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
venc_pm_get_put(inst);
mutex_lock(&inst->lock);
+
+ if (inst->enc_state == VENUS_ENC_STATE_STOPPED) {
+ vbuf->sequence = inst->sequence_cap++;
+ vbuf->field = V4L2_FIELD_NONE;
+ vb2_set_plane_payload(vb, 0, 0);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->lock);
+ return;
+ }
+
venus_helper_vb2_buf_queue(vb);
mutex_unlock(&inst->lock);
}
@@ -1260,6 +1344,10 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type,
vb->planes[0].data_offset = data_offset;
vb->timestamp = timestamp_us * NSEC_PER_USEC;
vbuf->sequence = inst->sequence_cap++;
+ if ((vbuf->flags & V4L2_BUF_FLAG_LAST) &&
+ inst->enc_state == VENUS_ENC_STATE_DRAIN) {
+ inst->enc_state = VENUS_ENC_STATE_STOPPED;
+ }
} else {
vbuf->sequence = inst->sequence_out++;
}
@@ -1362,6 +1450,9 @@ static int venc_open(struct file *file)
inst->core_acquired = false;
inst->nonblock = file->f_flags & O_NONBLOCK;
+ if (inst->enc_state == VENUS_ENC_STATE_DEINIT)
+ inst->enc_state = VENUS_ENC_STATE_INIT;
+
venus_helper_init_instance(inst);
ret = venc_ctrl_init(inst);
@@ -1424,6 +1515,8 @@ static int venc_close(struct file *file)
v4l2_fh_del(&inst->fh);
v4l2_fh_exit(&inst->fh);
+ inst->enc_state = VENUS_ENC_STATE_DEINIT;
+
venc_pm_put(inst, false);
kfree(inst);
@@ -1492,7 +1585,7 @@ err_vdev_release:
return ret;
}
-static int venc_remove(struct platform_device *pdev)
+static void venc_remove(struct platform_device *pdev)
{
struct venus_core *core = dev_get_drvdata(pdev->dev.parent);
@@ -1501,8 +1594,6 @@ static int venc_remove(struct platform_device *pdev)
if (core->pm_ops->venc_put)
core->pm_ops->venc_put(core->dev_enc);
-
- return 0;
}
static __maybe_unused int venc_runtime_suspend(struct device *dev)
@@ -1543,7 +1634,7 @@ MODULE_DEVICE_TABLE(of, venc_dt_match);
static struct platform_driver qcom_venus_enc_driver = {
.probe = venc_probe,
- .remove = venc_remove,
+ .remove_new = venc_remove,
.driver = {
.name = "qcom-venus-encoder",
.of_match_table = venc_dt_match,
diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c
index eb59a3ba6d0f..bcef7b87da7c 100644
--- a/drivers/media/platform/renesas/rcar-fcp.c
+++ b/drivers/media/platform/renesas/rcar-fcp.c
@@ -144,7 +144,7 @@ static int rcar_fcp_probe(struct platform_device *pdev)
return 0;
}
-static int rcar_fcp_remove(struct platform_device *pdev)
+static void rcar_fcp_remove(struct platform_device *pdev)
{
struct rcar_fcp_device *fcp = platform_get_drvdata(pdev);
@@ -153,8 +153,6 @@ static int rcar_fcp_remove(struct platform_device *pdev)
mutex_unlock(&fcp_lock);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id rcar_fcp_of_match[] = {
@@ -166,7 +164,7 @@ MODULE_DEVICE_TABLE(of, rcar_fcp_of_match);
static struct platform_driver rcar_fcp_platform_driver = {
.probe = rcar_fcp_probe,
- .remove = rcar_fcp_remove,
+ .remove_new = rcar_fcp_remove,
.driver = {
.name = "rcar-fcp",
.of_match_table = rcar_fcp_of_match,
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index 10b3474f93a4..f666b621338d 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -419,10 +419,7 @@ static const struct media_entity_operations risp_entity_ops = {
static int risp_probe_resources(struct rcar_isp *isp,
struct platform_device *pdev)
{
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- isp->base = devm_ioremap_resource(&pdev->dev, res);
+ isp->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(isp->base))
return PTR_ERR(isp->base);
@@ -503,7 +500,7 @@ error_mutex:
return ret;
}
-static int risp_remove(struct platform_device *pdev)
+static void risp_remove(struct platform_device *pdev)
{
struct rcar_isp *isp = platform_get_drvdata(pdev);
@@ -515,8 +512,6 @@ static int risp_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mutex_destroy(&isp->lock);
-
- return 0;
}
static struct platform_driver rcar_isp_driver = {
@@ -525,7 +520,7 @@ static struct platform_driver rcar_isp_driver = {
.of_match_table = risp_of_id_table,
},
.probe = risp_probe,
- .remove = risp_remove,
+ .remove_new = risp_remove,
};
module_platform_driver(rcar_isp_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 5e53d6b7036c..ff4bde9cc0e3 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -17,7 +17,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/sys_soc.h>
#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
@@ -1183,24 +1182,6 @@ static const struct rvin_info rcar_info_r8a7795 = {
.scaler = rvin_scaler_gen3,
};
-static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = {
- { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
- { .master = 0, .csi = RVIN_CSI21, .chsel = 0x05 },
- { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
- { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 },
- { .master = 4, .csi = RVIN_CSI21, .chsel = 0x05 },
- { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 },
- { /* Sentinel */ }
-};
-
-static const struct rvin_info rcar_info_r8a7795es1 = {
- .model = RCAR_GEN3,
- .use_mc = true,
- .max_width = 4096,
- .max_height = 4096,
- .routes = rcar_info_r8a7795es1_routes,
-};
-
static const struct rvin_group_route rcar_info_r8a7796_routes[] = {
{ .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 },
{ .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
@@ -1372,17 +1353,8 @@ static const struct of_device_id rvin_of_id_table[] = {
};
MODULE_DEVICE_TABLE(of, rvin_of_id_table);
-static const struct soc_device_attribute r8a7795es1[] = {
- {
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = &rcar_info_r8a7795es1,
- },
- { /* Sentinel */ }
-};
-
static int rcar_vin_probe(struct platform_device *pdev)
{
- const struct soc_device_attribute *attr;
struct rvin_dev *vin;
int irq, ret;
@@ -1394,14 +1366,6 @@ static int rcar_vin_probe(struct platform_device *pdev)
vin->info = of_device_get_match_data(&pdev->dev);
vin->alpha = 0xff;
- /*
- * Special care is needed on r8a7795 ES1.x since it
- * uses different routing than r8a7795 ES2.0.
- */
- attr = soc_device_match(r8a7795es1);
- if (attr)
- vin->info = attr->data;
-
vin->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(vin->base))
return PTR_ERR(vin->base);
@@ -1442,7 +1406,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
return 0;
}
-static int rcar_vin_remove(struct platform_device *pdev)
+static void rcar_vin_remove(struct platform_device *pdev)
{
struct rvin_dev *vin = platform_get_drvdata(pdev);
@@ -1458,8 +1422,6 @@ static int rcar_vin_remove(struct platform_device *pdev)
rvin_parallel_cleanup(vin);
rvin_dma_unregister(vin);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume);
@@ -1472,7 +1434,7 @@ static struct platform_driver rcar_vin_driver = {
.of_match_table = rvin_of_id_table,
},
.probe = rcar_vin_probe,
- .remove = rcar_vin_remove,
+ .remove_new = rcar_vin_remove,
};
module_platform_driver(rcar_vin_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
index 174aa6176f54..e34060c2b039 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
@@ -345,7 +345,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg hsfreqrange_m3w_h3es1[] = {
+static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -1369,11 +1369,6 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
.clear_ulps = true,
};
-static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = {
- .hsfreqrange = hsfreqrange_m3w_h3es1,
- .num_channels = 4,
-};
-
static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
.init_phtw = rcsi2_init_phtw_h3es2,
.hsfreqrange = hsfreqrange_h3_v3h_m3n,
@@ -1383,12 +1378,12 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
- .hsfreqrange = hsfreqrange_m3w_h3es1,
+ .hsfreqrange = hsfreqrange_m3w,
.num_channels = 4,
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
- .hsfreqrange = hsfreqrange_m3w_h3es1,
+ .hsfreqrange = hsfreqrange_m3w,
.num_channels = 4,
};
@@ -1482,10 +1477,6 @@ MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
static const struct soc_device_attribute r8a7795[] = {
{
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = &rcar_csi2_info_r8a7795es1,
- },
- {
.soc_id = "r8a7795", .revision = "ES2.*",
.data = &rcar_csi2_info_r8a7795es2,
},
@@ -1574,7 +1565,7 @@ error_mutex:
return ret;
}
-static int rcsi2_remove(struct platform_device *pdev)
+static void rcsi2_remove(struct platform_device *pdev)
{
struct rcar_csi2 *priv = platform_get_drvdata(pdev);
@@ -1585,12 +1576,10 @@ static int rcsi2_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mutex_destroy(&priv->lock);
-
- return 0;
}
static struct platform_driver rcar_csi2_pdrv = {
- .remove = rcsi2_remove,
+ .remove_new = rcsi2_remove,
.probe = rcsi2_probe,
.driver = {
.name = "rcar-csi2",
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index 3fec41f6e964..3a92f4535c18 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -1433,19 +1433,17 @@ static int rcar_drif_probe(struct platform_device *pdev)
}
/* DRIF channel remove */
-static int rcar_drif_remove(struct platform_device *pdev)
+static void rcar_drif_remove(struct platform_device *pdev)
{
struct rcar_drif *ch = platform_get_drvdata(pdev);
struct rcar_drif_sdr *sdr = ch->sdr;
/* Channel 0 will be the SDR instance */
if (ch->num)
- return 0;
+ return;
/* SDR instance */
rcar_drif_sdr_remove(sdr);
-
- return 0;
}
/* FIXME: Implement suspend/resume support */
@@ -1476,7 +1474,7 @@ static struct platform_driver rcar_drif_driver = {
.pm = &rcar_drif_pm_ops,
},
.probe = rcar_drif_probe,
- .remove = rcar_drif_remove,
+ .remove_new = rcar_drif_remove,
};
module_platform_driver(rcar_drif_driver);
diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c
index 37ecf489d112..f43e458590b8 100644
--- a/drivers/media/platform/renesas/rcar_fdp1.c
+++ b/drivers/media/platform/renesas/rcar_fdp1.c
@@ -254,7 +254,6 @@ MODULE_PARM_DESC(debug, "activate debug info");
/* Internal Data (HW Version) */
#define FD1_IP_INTDATA 0x0800
-#define FD1_IP_H3_ES1 0x02010101
#define FD1_IP_M3W 0x02010202
#define FD1_IP_H3 0x02010203
#define FD1_IP_M3N 0x02010204
@@ -2313,8 +2312,10 @@ static int fdp1_probe(struct platform_device *pdev)
/* Determine our clock rate */
clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto put_dev;
+ }
fdp1->clk_rate = clk_get_rate(clk);
clk_put(clk);
@@ -2323,7 +2324,7 @@ static int fdp1_probe(struct platform_device *pdev)
ret = v4l2_device_register(&pdev->dev, &fdp1->v4l2_dev);
if (ret) {
v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n");
- return ret;
+ goto put_dev;
}
/* M2M registration */
@@ -2359,9 +2360,6 @@ static int fdp1_probe(struct platform_device *pdev)
hw_version = fdp1_read(fdp1, FD1_IP_INTDATA);
switch (hw_version) {
- case FD1_IP_H3_ES1:
- dprintk(fdp1, "FDP1 Version R-Car H3 ES1\n");
- break;
case FD1_IP_M3W:
dprintk(fdp1, "FDP1 Version R-Car M3-W\n");
break;
@@ -2393,10 +2391,12 @@ release_m2m:
unreg_dev:
v4l2_device_unregister(&fdp1->v4l2_dev);
+put_dev:
+ rcar_fcp_put(fdp1->fcp);
return ret;
}
-static int fdp1_remove(struct platform_device *pdev)
+static void fdp1_remove(struct platform_device *pdev)
{
struct fdp1_dev *fdp1 = platform_get_drvdata(pdev);
@@ -2404,8 +2404,7 @@ static int fdp1_remove(struct platform_device *pdev)
video_unregister_device(&fdp1->vfd);
v4l2_device_unregister(&fdp1->v4l2_dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
+ rcar_fcp_put(fdp1->fcp);
}
static int __maybe_unused fdp1_pm_runtime_suspend(struct device *dev)
@@ -2441,7 +2440,7 @@ MODULE_DEVICE_TABLE(of, fdp1_dt_ids);
static struct platform_driver fdp1_pdrv = {
.probe = fdp1_probe,
- .remove = fdp1_remove,
+ .remove_new = fdp1_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = fdp1_dt_ids,
diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c
index 2f4377cfbb42..e7f604807825 100644
--- a/drivers/media/platform/renesas/rcar_jpu.c
+++ b/drivers/media/platform/renesas/rcar_jpu.c
@@ -1702,7 +1702,7 @@ device_register_rollback:
return ret;
}
-static int jpu_remove(struct platform_device *pdev)
+static void jpu_remove(struct platform_device *pdev)
{
struct jpu *jpu = platform_get_drvdata(pdev);
@@ -1710,8 +1710,6 @@ static int jpu_remove(struct platform_device *pdev)
video_unregister_device(&jpu->vfd_encoder);
v4l2_m2m_release(jpu->m2m_dev);
v4l2_device_unregister(&jpu->v4l2_dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1746,7 +1744,7 @@ static const struct dev_pm_ops jpu_pm_ops = {
static struct platform_driver jpu_driver = {
.probe = jpu_probe,
- .remove = jpu_remove,
+ .remove_new = jpu_remove,
.driver = {
.of_match_table = jpu_dt_ids,
.name = DRV_NAME,
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index f70f91b006b7..56b9c59cfda8 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -795,8 +795,8 @@ static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt
struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
const struct ceu_fmt *ceu_fmt;
u32 mbus_code_old;
u32 mbus_code;
@@ -1709,7 +1709,7 @@ error_free_ceudev:
return ret;
}
-static int ceu_remove(struct platform_device *pdev)
+static void ceu_remove(struct platform_device *pdev)
{
struct ceu_device *ceudev = platform_get_drvdata(pdev);
@@ -1722,8 +1722,6 @@ static int ceu_remove(struct platform_device *pdev)
v4l2_device_unregister(&ceudev->v4l2_dev);
video_unregister_device(&ceudev->vdev);
-
- return 0;
}
static const struct dev_pm_ops ceu_pm_ops = {
@@ -1739,7 +1737,7 @@ static struct platform_driver ceu_driver = {
.of_match_table = of_match_ptr(ceu_of_match),
},
.probe = ceu_probe,
- .remove = ceu_remove,
+ .remove_new = ceu_remove,
};
module_platform_driver(ceu_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 5939f5165a5e..7a71370fcc32 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -298,7 +298,7 @@ error_dma_unregister:
return ret;
}
-static int rzg2l_cru_remove(struct platform_device *pdev)
+static void rzg2l_cru_remove(struct platform_device *pdev)
{
struct rzg2l_cru_dev *cru = platform_get_drvdata(pdev);
@@ -312,8 +312,6 @@ static int rzg2l_cru_remove(struct platform_device *pdev)
mutex_destroy(&cru->mdev_lock);
rzg2l_cru_dma_unregister(cru);
-
- return 0;
}
static const struct of_device_id rzg2l_cru_of_id_table[] = {
@@ -328,7 +326,7 @@ static struct platform_driver rzg2l_cru_driver = {
.of_match_table = rzg2l_cru_of_id_table,
},
.probe = rzg2l_cru_probe,
- .remove = rzg2l_cru_remove,
+ .remove_new = rzg2l_cru_remove,
};
module_platform_driver(rzg2l_cru_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 384fb54e219a..30dad7383654 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -819,7 +819,7 @@ error_pm:
return ret;
}
-static int rzg2l_csi2_remove(struct platform_device *pdev)
+static void rzg2l_csi2_remove(struct platform_device *pdev)
{
struct rzg2l_csi2 *csi2 = platform_get_drvdata(pdev);
@@ -829,8 +829,6 @@ static int rzg2l_csi2_remove(struct platform_device *pdev)
v4l2_subdev_cleanup(&csi2->subdev);
media_entity_cleanup(&csi2->subdev.entity);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev)
@@ -859,7 +857,7 @@ static const struct of_device_id rzg2l_csi2_of_table[] = {
};
static struct platform_driver rzg2l_csi2_pdrv = {
- .remove = rzg2l_csi2_remove,
+ .remove_new = rzg2l_csi2_remove,
.probe = rzg2l_csi2_probe,
.driver = {
.name = "rzg2l-csi2",
diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c
index ca4310e26c49..8fe3272a541f 100644
--- a/drivers/media/platform/renesas/sh_vou.c
+++ b/drivers/media/platform/renesas/sh_vou.c
@@ -1343,7 +1343,7 @@ ei2cgadap:
return ret;
}
-static int sh_vou_remove(struct platform_device *pdev)
+static void sh_vou_remove(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct sh_vou_device *vou_dev = container_of(v4l2_dev,
@@ -1356,11 +1356,10 @@ static int sh_vou_remove(struct platform_device *pdev)
video_unregister_device(&vou_dev->vdev);
i2c_put_adapter(client->adapter);
v4l2_device_unregister(&vou_dev->v4l2_dev);
- return 0;
}
static struct platform_driver sh_vou = {
- .remove = sh_vou_remove,
+ .remove_new = sh_vou_remove,
.driver = {
.name = "sh-vou",
},
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
index c6f25200982c..9b087bd8df7d 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
@@ -66,7 +66,9 @@ static int vsp1_du_insert_uif(struct vsp1_device *vsp1,
struct vsp1_entity *prev, unsigned int prev_pad,
struct vsp1_entity *next, unsigned int next_pad)
{
- struct v4l2_subdev_format format;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
if (!uif) {
@@ -82,8 +84,6 @@ static int vsp1_du_insert_uif(struct vsp1_device *vsp1,
prev->sink = uif;
prev->sink_pad = UIF_PAD_SINK;
- memset(&format, 0, sizeof(format));
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
format.pad = prev_pad;
ret = v4l2_subdev_call(&prev->subdev, pad, get_fmt, NULL, &format);
@@ -118,8 +118,12 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1,
struct vsp1_entity *uif,
unsigned int brx_input)
{
- struct v4l2_subdev_selection sel;
- struct v4l2_subdev_format format;
+ struct v4l2_subdev_selection sel = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
const struct v4l2_rect *crop;
int ret;
@@ -129,8 +133,6 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1,
*/
crop = &vsp1->drm->inputs[rpf->entity.index].crop;
- memset(&format, 0, sizeof(format));
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
format.pad = RWPF_PAD_SINK;
format.format.width = crop->width + crop->left;
format.format.height = crop->height + crop->top;
@@ -147,8 +149,6 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1,
__func__, format.format.width, format.format.height,
format.format.code, rpf->entity.index);
- memset(&sel, 0, sizeof(sel));
- sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sel.pad = RWPF_PAD_SINK;
sel.target = V4L2_SEL_TGT_CROP;
sel.r = *crop;
@@ -481,10 +481,11 @@ static int vsp1_du_pipeline_setup_output(struct vsp1_device *vsp1,
struct vsp1_pipeline *pipe)
{
struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
- struct v4l2_subdev_format format = { 0, };
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
format.pad = RWPF_PAD_SINK;
format.format.width = drm_pipe->width;
format.format.height = drm_pipe->height;
@@ -710,6 +711,9 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
return 0;
}
+ /* Reset the underrun counter */
+ pipe->underrun_count = 0;
+
drm_pipe->width = cfg->width;
drm_pipe->height = cfg->height;
pipe->interlaced = cfg->interlaced;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
index 5710152d6511..a9db84be4822 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
@@ -45,7 +45,8 @@
static irqreturn_t vsp1_irq_handler(int irq, void *data)
{
- u32 mask = VI6_WPF_IRQ_STA_DFE | VI6_WPF_IRQ_STA_FRE;
+ u32 mask = VI6_WPF_IRQ_STA_DFE | VI6_WPF_IRQ_STA_FRE |
+ VI6_WPF_IRQ_STA_UND;
struct vsp1_device *vsp1 = data;
irqreturn_t ret = IRQ_NONE;
unsigned int i;
@@ -60,6 +61,14 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
+ if ((status & VI6_WPF_IRQ_STA_UND) && wpf->entity.pipe) {
+ wpf->entity.pipe->underrun_count++;
+
+ dev_warn_ratelimited(vsp1->dev,
+ "Underrun occurred at WPF%u (total underruns %u)\n",
+ i, wpf->entity.pipe->underrun_count);
+ }
+
if (status & VI6_WPF_IRQ_STA_DFE) {
vsp1_pipeline_frame_end(wpf->entity.pipe);
ret = IRQ_HANDLED;
@@ -977,7 +986,7 @@ done:
return ret;
}
-static int vsp1_remove(struct platform_device *pdev)
+static void vsp1_remove(struct platform_device *pdev)
{
struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
@@ -985,8 +994,6 @@ static int vsp1_remove(struct platform_device *pdev)
rcar_fcp_put(vsp1->fcp);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id vsp1_of_match[] = {
@@ -999,7 +1006,7 @@ MODULE_DEVICE_TABLE(of, vsp1_of_match);
static struct platform_driver vsp1_platform_driver = {
.probe = vsp1_probe,
- .remove = vsp1_remove,
+ .remove_new = vsp1_remove,
.driver = {
.name = "vsp1",
.pm = &vsp1_pm_ops,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
index 4c3bd2b1ca28..c31f05a80bb5 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
@@ -184,15 +184,14 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state)
{
- struct v4l2_subdev_format format;
unsigned int pad;
for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
- memset(&format, 0, sizeof(format));
-
- format.pad = pad;
- format.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE;
+ struct v4l2_subdev_format format = {
+ .pad = pad,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format);
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
index f22724439cdc..17f98a6a972e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
@@ -130,8 +130,6 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
const struct v4l2_subdev_ops *ops, u32 function);
void vsp1_entity_destroy(struct vsp1_entity *entity);
-extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
-
int vsp1_entity_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
index ae646c9ef337..674b5748d929 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
@@ -148,6 +148,8 @@ struct vsp1_pipeline {
unsigned int partitions;
struct vsp1_partition *partition;
struct vsp1_partition *part_table;
+
+ u32 underrun_count;
};
void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_regs.h b/drivers/media/platform/renesas/vsp1/vsp1_regs.h
index d94343ae57a1..7eca82e0ba7e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_regs.h
@@ -32,10 +32,12 @@
#define VI6_STATUS_SYS_ACT(n) BIT((n) + 8)
#define VI6_WPF_IRQ_ENB(n) (0x0048 + (n) * 12)
+#define VI6_WPF_IRQ_ENB_UNDE BIT(16)
#define VI6_WPF_IRQ_ENB_DFEE BIT(1)
#define VI6_WPF_IRQ_ENB_FREE BIT(0)
#define VI6_WPF_IRQ_STA(n) (0x004c + (n) * 12)
+#define VI6_WPF_IRQ_STA_UND BIT(16)
#define VI6_WPF_IRQ_STA_DFE BIT(1)
#define VI6_WPF_IRQ_STA_FRE BIT(0)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 544012fd1fe9..e9d5027761bb 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -62,7 +62,9 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
static int vsp1_video_verify_format(struct vsp1_video *video)
{
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
int ret;
@@ -70,7 +72,6 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
if (subdev == NULL)
return -EINVAL;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
if (ret < 0)
return ret == -ENOIOCTLCMD ? -EINVAL : ret;
@@ -776,7 +777,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
video->rwpf->mem = buf->mem;
pipe->buffers_ready |= 1 << video->pipe_index;
- if (vb2_is_streaming(&video->queue) &&
+ if (vb2_start_streaming_called(&video->queue) &&
vsp1_pipeline_ready(pipe))
vsp1_video_pipeline_run(pipe);
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 61b25fcf826e..67dcf22e5ba3 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -930,7 +930,7 @@ err_put_clk:
return ret;
}
-static int rga_remove(struct platform_device *pdev)
+static void rga_remove(struct platform_device *pdev)
{
struct rockchip_rga *rga = platform_get_drvdata(pdev);
@@ -947,8 +947,6 @@ static int rga_remove(struct platform_device *pdev)
v4l2_device_unregister(&rga->v4l2_dev);
pm_runtime_disable(rga->dev);
-
- return 0;
}
static int __maybe_unused rga_runtime_suspend(struct device *dev)
@@ -986,7 +984,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rga_match);
static struct platform_driver rga_pdrv = {
.probe = rga_probe,
- .remove = rga_remove,
+ .remove_new = rga_remove,
.driver = {
.name = RGA_NAME,
.pm = &rga_pm,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index d1d1fdce03e3..8f3cba319762 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -111,6 +111,16 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .uv_swap = 0,
+ .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .uv_swap = 1,
+ .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
.fourcc = V4L2_PIX_FMT_YVU422M,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
@@ -238,6 +248,18 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = {
.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .uv_swap = 0,
+ .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
+ .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .uv_swap = 1,
+ .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
+ .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ }, {
.fourcc = V4L2_PIX_FMT_YVU422M,
.uv_swap = 1,
.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
@@ -1212,6 +1234,35 @@ static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
return -EINVAL;
}
+static int rkisp1_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ static const unsigned int max_widths[] = {
+ RKISP1_RSZ_MP_SRC_MAX_WIDTH,
+ RKISP1_RSZ_SP_SRC_MAX_WIDTH,
+ };
+ static const unsigned int max_heights[] = {
+ RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
+ RKISP1_RSZ_SP_SRC_MAX_HEIGHT,
+ };
+ struct rkisp1_capture *cap = video_drvdata(file);
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+
+ fsize->stepwise.min_width = RKISP1_RSZ_SRC_MIN_WIDTH;
+ fsize->stepwise.max_width = max_widths[cap->id];
+ fsize->stepwise.step_width = 2;
+
+ fsize->stepwise.min_height = RKISP1_RSZ_SRC_MIN_HEIGHT;
+ fsize->stepwise.max_height = max_heights[cap->id];
+ fsize->stepwise.step_height = 2;
+
+ return 0;
+}
+
static int rkisp1_s_fmt_vid_cap_mplane(struct file *file,
void *priv, struct v4l2_format *f)
{
@@ -1261,6 +1312,7 @@ static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = {
.vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane,
.vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane,
.vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_framesizes = rkisp1_enum_framesizes,
.vidioc_querycap = rkisp1_querycap,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index f2475c6235ea..4762cb32353d 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -622,7 +622,7 @@ err_pm_runtime_disable:
return ret;
}
-static int rkisp1_remove(struct platform_device *pdev)
+static void rkisp1_remove(struct platform_device *pdev)
{
struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
@@ -638,8 +638,6 @@ static int rkisp1_remove(struct platform_device *pdev)
v4l2_device_unregister(&rkisp1->v4l2_dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static struct platform_driver rkisp1_drv = {
@@ -649,7 +647,7 @@ static struct platform_driver rkisp1_drv = {
.pm = &rkisp1_pm_ops,
},
.probe = rkisp1_probe,
- .remove = rkisp1_remove,
+ .remove_new = rkisp1_remove,
};
module_platform_driver(rkisp1_drv);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index f76afd8112b2..c15ae0218118 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -123,8 +123,8 @@ rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz,
unsigned int pad, u32 which)
{
struct v4l2_subdev_state state = {
- .pads = rsz->pad_cfg
- };
+ .pads = rsz->pad_cfg,
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_format(&rsz->sd, sd_state, pad);
else
@@ -137,8 +137,8 @@ rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz,
unsigned int pad, u32 which)
{
struct v4l2_subdev_state state = {
- .pads = rsz->pad_cfg
- };
+ .pads = rsz->pad_cfg,
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_crop(&rsz->sd, sd_state, pad);
else
@@ -366,7 +366,7 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config dummy_cfg;
struct v4l2_subdev_state pad_state = {
.pads = &dummy_cfg
- };
+ };
u32 pad = code->pad;
int ret;
@@ -733,8 +733,8 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
{
struct v4l2_subdev_state state = {
- .pads = rsz->pad_cfg
- };
+ .pads = rsz->pad_cfg,
+ };
static const char * const dev_names[] = {
RKISP1_RSZ_MP_DEV_NAME,
RKISP1_RSZ_SP_DEV_NAME
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
index b147c645ae0b..1fb34de70649 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
@@ -1201,7 +1201,7 @@ err_clk:
return ret;
}
-static int gsc_remove(struct platform_device *pdev)
+static void gsc_remove(struct platform_device *pdev)
{
struct gsc_dev *gsc = platform_get_drvdata(pdev);
int i;
@@ -1220,7 +1220,6 @@ static int gsc_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
- return 0;
}
#ifdef CONFIG_PM
@@ -1311,7 +1310,7 @@ static const struct dev_pm_ops gsc_pm_ops = {
static struct platform_driver gsc_driver = {
.probe = gsc_probe,
- .remove = gsc_remove,
+ .remove_new = gsc_remove,
.driver = {
.name = GSC_MODULE_NAME,
.pm = &gsc_pm_ops,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
index e3b95a2b7e04..a0d43bf892e6 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
@@ -763,7 +763,10 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe);
struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
- struct v4l2_subdev_format sfmt;
+ struct v4l2_subdev_format sfmt = {
+ .which = set ? V4L2_SUBDEV_FORMAT_ACTIVE
+ : V4L2_SUBDEV_FORMAT_TRY,
+ };
struct v4l2_mbus_framefmt *mf = &sfmt.format;
struct media_entity *me;
struct fimc_fmt *ffmt;
@@ -774,9 +777,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
if (WARN_ON(!sd || !tfmt))
return -EINVAL;
- memset(&sfmt, 0, sizeof(sfmt));
sfmt.format = *tfmt;
- sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
me = fimc_pipeline_get_head(&sd->entity);
@@ -854,7 +855,7 @@ static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor,
struct v4l2_plane_pix_format *plane_fmt,
unsigned int num_planes, bool try)
{
- struct v4l2_mbus_frame_desc fd;
+ struct v4l2_mbus_frame_desc fd = { };
int i, ret;
int pad;
@@ -1095,7 +1096,12 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
*/
static int fimc_pipeline_validate(struct fimc_dev *fimc)
{
- struct v4l2_subdev_format sink_fmt, src_fmt;
+ struct v4l2_subdev_format sink_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_subdev_format src_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct v4l2_subdev *sd = &vc->subdev;
struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe);
@@ -1132,7 +1138,6 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
} else {
sink_fmt.pad = sink_pad->index;
- sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
@@ -1141,7 +1146,6 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
/* Retrieve format at the source pad */
sd = media_entity_to_v4l2_subdev(src_pad->entity);
src_fmt.pad = src_pad->index;
- src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
index 1791100b6935..a2034ade8b9e 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
@@ -1092,7 +1092,7 @@ static int fimc_suspend(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static int fimc_remove(struct platform_device *pdev)
+static void fimc_remove(struct platform_device *pdev)
{
struct fimc_dev *fimc = platform_get_drvdata(pdev);
@@ -1108,7 +1108,6 @@ static int fimc_remove(struct platform_device *pdev)
fimc_clk_put(fimc);
dev_info(&pdev->dev, "driver unloaded\n");
- return 0;
}
/* S5PV210, S5PC110 */
@@ -1160,7 +1159,7 @@ static const struct dev_pm_ops fimc_pm_ops = {
static struct platform_driver fimc_driver = {
.probe = fimc_probe,
- .remove = fimc_remove,
+ .remove_new = fimc_remove,
.driver = {
.of_match_table = fimc_of_match,
.name = FIMC_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.c
index 5d9f4c1cdc5e..7a48fad1df16 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.c
@@ -54,7 +54,7 @@ const char *fimc_is_param_strerr(unsigned int error)
case ERROR_DMA_INPUT_ORDER:
return "ERROR_DMA_INPUT_ORDER: Invalid order(DRC: YYCbCr,YCbYCr,FD:NO,YYCbCr,YCbYCr,CbCr,CrCb)";
case ERROR_DMA_INPUT_PLANE:
- return "ERROR_DMA_INPUT_PLANE: Invalid palne (DRC: 3, FD: 1, 2, 3)";
+ return "ERROR_DMA_INPUT_PLANE: Invalid plane (DRC: 3, FD: 1, 2, 3)";
case ERROR_OTF_OUTPUT_WIDTH:
return "ERROR_OTF_OUTPUT_WIDTH: Invalid width (DRC: 128~8192)";
case ERROR_OTF_OUTPUT_HEIGHT:
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
index 9dcbb9853ac0..809e117331c0 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
@@ -156,7 +156,7 @@ enum fimc_is_error {
ERROR_DMA_INPUT_BIT_WIDTH = 34,
/* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */
ERROR_DMA_INPUT_ORDER = 35,
- /* invalid palne (DRC: 3, FD: 1, 2, 3) */
+ /* invalid plane (DRC: 3, FD: 1, 2, 3) */
ERROR_DMA_INPUT_PLANE = 36,
ERROR_OTF_OUTPUT_NONE = ERROR_COMMON_NONE,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
index 83a28ef8e099..bef6e9b4a25e 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
@@ -82,14 +82,12 @@ err_pm_dis:
return ret;
}
-static int fimc_is_i2c_remove(struct platform_device *pdev)
+static void fimc_is_i2c_remove(struct platform_device *pdev)
{
struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
i2c_del_adapter(&isp_i2c->adapter);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -140,7 +138,7 @@ static const struct of_device_id fimc_is_i2c_of_match[] = {
static struct platform_driver fimc_is_i2c_driver = {
.probe = fimc_is_i2c_probe,
- .remove = fimc_is_i2c_remove,
+ .remove_new = fimc_is_i2c_remove,
.driver = {
.of_match_table = fimc_is_i2c_of_match,
.name = "fimc-isp-i2c",
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
index a7704ff069d6..530a148fe4d3 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
@@ -915,7 +915,7 @@ static int fimc_is_suspend(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static int fimc_is_remove(struct platform_device *pdev)
+static void fimc_is_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fimc_is *is = dev_get_drvdata(dev);
@@ -932,8 +932,6 @@ static int fimc_is_remove(struct platform_device *pdev)
fimc_is_debugfs_remove(is);
release_firmware(is->fw.f_w);
fimc_is_free_cpu_memory(is);
-
- return 0;
}
static const struct of_device_id fimc_is_of_match[] = {
@@ -950,7 +948,7 @@ static const struct dev_pm_ops fimc_is_pm_ops = {
static struct platform_driver fimc_is_driver = {
.probe = fimc_is_probe,
- .remove = fimc_is_remove,
+ .remove_new = fimc_is_remove,
.driver = {
.of_match_table = fimc_is_of_match,
.name = FIMC_IS_DRV_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
index f6a302fa8d37..8fa26969c411 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
@@ -449,17 +449,22 @@ static int isp_video_s_fmt_mplane(struct file *file, void *priv,
static int isp_video_pipeline_validate(struct fimc_isp *isp)
{
struct v4l2_subdev *sd = &isp->subdev;
- struct v4l2_subdev_format sink_fmt, src_fmt;
struct media_pad *pad;
int ret;
while (1) {
+ struct v4l2_subdev_format sink_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_subdev_format src_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
/* Retrieve format at the sink pad */
pad = &sd->entity.pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
sink_fmt.pad = pad->index;
- sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
@@ -471,7 +476,6 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp)
sd = media_entity_to_v4l2_subdev(pad->entity);
src_fmt.pad = pad->index;
- src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
index e185a40305a8..24b3dda26714 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
@@ -765,7 +765,12 @@ static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
static int fimc_pipeline_validate(struct fimc_lite *fimc)
{
struct v4l2_subdev *sd = &fimc->subdev;
- struct v4l2_subdev_format sink_fmt, src_fmt;
+ struct v4l2_subdev_format sink_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_subdev_format src_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct media_pad *pad;
int ret;
@@ -782,7 +787,6 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
sink_fmt.format.code = fimc->inp_frame.fmt->mbus_code;
} else {
sink_fmt.pad = pad->index;
- sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
&sink_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
@@ -795,7 +799,6 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
sd = media_entity_to_v4l2_subdev(pad->entity);
src_fmt.pad = pad->index;
- src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
@@ -1595,7 +1598,7 @@ static int fimc_lite_suspend(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static int fimc_lite_remove(struct platform_device *pdev)
+static void fimc_lite_remove(struct platform_device *pdev)
{
struct fimc_lite *fimc = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -1610,7 +1613,6 @@ static int fimc_lite_remove(struct platform_device *pdev)
fimc_lite_clk_put(fimc);
dev_info(dev, "Driver unloaded\n");
- return 0;
}
static const struct dev_pm_ops fimc_lite_pm_ops = {
@@ -1656,7 +1658,7 @@ MODULE_DEVICE_TABLE(of, flite_of_match);
static struct platform_driver fimc_lite_driver = {
.probe = fimc_lite_probe,
- .remove = fimc_lite_remove,
+ .remove_new = fimc_lite_remove,
.driver = {
.of_match_table = flite_of_match,
.name = FIMC_LITE_DRV_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 98a60f01129d..c9cb9a216fae 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -1440,6 +1440,10 @@ static int fimc_md_probe(struct platform_device *pdev)
if (!fmd)
return -ENOMEM;
+ ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ if (ret < 0)
+ return -ENOMEM;
+
spin_lock_init(&fmd->slock);
INIT_LIST_HEAD(&fmd->pipelines);
fmd->pdev = pdev;
@@ -1470,10 +1474,8 @@ static int fimc_md_probe(struct platform_device *pdev)
goto err_v4l2dev;
pinctrl = devm_pinctrl_get(dev);
- if (IS_ERR(pinctrl)) {
- ret = dev_err_probe(dev, PTR_ERR(pinctrl), "Failed to get pinctrl\n");
- goto err_clk;
- }
+ if (IS_ERR(pinctrl))
+ dev_dbg(dev, "Failed to get pinctrl: %pe\n", pinctrl);
platform_set_drvdata(pdev, fmd);
@@ -1530,12 +1532,12 @@ err_md:
return ret;
}
-static int fimc_md_remove(struct platform_device *pdev)
+static void fimc_md_remove(struct platform_device *pdev)
{
struct fimc_md *fmd = platform_get_drvdata(pdev);
if (!fmd)
- return 0;
+ return;
fimc_md_unregister_clk_provider(fmd);
v4l2_async_nf_unregister(&fmd->subdev_notifier);
@@ -1548,8 +1550,6 @@ static int fimc_md_remove(struct platform_device *pdev)
media_device_unregister(&fmd->media_dev);
media_device_cleanup(&fmd->media_dev);
fimc_md_put_clocks(fmd);
-
- return 0;
}
static const struct platform_device_id fimc_driver_ids[] __always_unused = {
@@ -1566,7 +1566,7 @@ MODULE_DEVICE_TABLE(of, fimc_md_of_match);
static struct platform_driver fimc_md_driver = {
.probe = fimc_md_probe,
- .remove = fimc_md_remove,
+ .remove_new = fimc_md_remove,
.driver = {
.of_match_table = of_match_ptr(fimc_md_of_match),
.name = "s5p-fimc-md",
diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
index 6a0d35f33e8c..686ca8753ba2 100644
--- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
@@ -975,7 +975,7 @@ static int s5pcsis_runtime_resume(struct device *dev)
}
#endif
-static int s5pcsis_remove(struct platform_device *pdev)
+static void s5pcsis_remove(struct platform_device *pdev)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct csis_state *state = sd_to_csis_state(sd);
@@ -987,8 +987,6 @@ static int s5pcsis_remove(struct platform_device *pdev)
s5pcsis_clk_put(state);
media_entity_cleanup(&state->sd.entity);
-
- return 0;
}
static const struct dev_pm_ops s5pcsis_pm_ops = {
@@ -1022,7 +1020,7 @@ MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
static struct platform_driver s5pcsis_driver = {
.probe = s5pcsis_probe,
- .remove = s5pcsis_remove,
+ .remove_new = s5pcsis_remove,
.driver = {
.of_match_table = s5pcsis_of_match,
.name = CSIS_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
index db106ebdf870..76634d242b10 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
@@ -806,7 +806,9 @@ static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv,
/* Only check pixel formats at the sensor and the camif subdev pads */
static int camif_pipeline_validate(struct camif_dev *camif)
{
- struct v4l2_subdev_format src_fmt;
+ struct v4l2_subdev_format src_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct media_pad *pad;
int ret;
@@ -816,7 +818,6 @@ static int camif_pipeline_validate(struct camif_dev *camif)
return -EPIPE;
src_fmt.pad = pad->index;
- src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(camif->sensor.sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c
index 6e8ef86566b7..afe1fcc37354 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-core.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c
@@ -190,7 +190,9 @@ static int camif_register_sensor(struct camif_dev *camif)
struct s3c_camif_sensor_info *sensor = &camif->pdata.sensor;
struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
struct i2c_adapter *adapter;
- struct v4l2_subdev_format format;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *sd;
int ret;
@@ -220,7 +222,6 @@ static int camif_register_sensor(struct camif_dev *camif)
/* Get initial pixel format and set it at the camif sink pad */
format.pad = 0;
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
if (ret < 0)
@@ -507,7 +508,7 @@ err_sd:
return ret;
}
-static int s3c_camif_remove(struct platform_device *pdev)
+static void s3c_camif_remove(struct platform_device *pdev)
{
struct camif_dev *camif = platform_get_drvdata(pdev);
struct s3c_camif_plat_data *pdata = &camif->pdata;
@@ -521,8 +522,6 @@ static int s3c_camif_remove(struct platform_device *pdev)
camif_clk_put(camif);
s3c_camif_unregister_subdev(camif);
pdata->gpio_put();
-
- return 0;
}
static int s3c_camif_runtime_resume(struct device *dev)
@@ -623,7 +622,7 @@ static const struct dev_pm_ops s3c_camif_pm_ops = {
static struct platform_driver s3c_camif_driver = {
.probe = s3c_camif_probe,
- .remove = s3c_camif_remove,
+ .remove_new = s3c_camif_remove,
.id_table = s3c_camif_driver_ids,
.driver = {
.name = S3C_CAMIF_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c
index dd8864779a7c..89aeba47ed07 100644
--- a/drivers/media/platform/samsung/s5p-g2d/g2d.c
+++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c
@@ -740,7 +740,7 @@ put_clk:
return ret;
}
-static int g2d_remove(struct platform_device *pdev)
+static void g2d_remove(struct platform_device *pdev)
{
struct g2d_dev *dev = platform_get_drvdata(pdev);
@@ -753,7 +753,6 @@ static int g2d_remove(struct platform_device *pdev)
clk_put(dev->gate);
clk_unprepare(dev->clk);
clk_put(dev->clk);
- return 0;
}
static struct g2d_variant g2d_drvdata_v3x = {
@@ -778,7 +777,7 @@ MODULE_DEVICE_TABLE(of, exynos_g2d_match);
static struct platform_driver g2d_pdrv = {
.probe = g2d_probe,
- .remove = g2d_remove,
+ .remove_new = g2d_remove,
.driver = {
.name = G2D_NAME,
.of_match_table = exynos_g2d_match,
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
index 55814041b8d8..c3c7e48f1b6e 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
@@ -2991,7 +2991,7 @@ device_register_rollback:
return ret;
}
-static int s5p_jpeg_remove(struct platform_device *pdev)
+static void s5p_jpeg_remove(struct platform_device *pdev)
{
struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
int i;
@@ -3008,8 +3008,6 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
clk_disable_unprepare(jpeg->clocks[i]);
}
-
- return 0;
}
#ifdef CONFIG_PM
@@ -3164,7 +3162,7 @@ static void *jpeg_get_drv_data(struct device *dev)
static struct platform_driver s5p_jpeg_driver = {
.probe = s5p_jpeg_probe,
- .remove = s5p_jpeg_remove,
+ .remove_new = s5p_jpeg_remove,
.driver = {
.of_match_table = of_match_ptr(samsung_jpeg_match),
.name = S5P_JPEG_M2M_NAME,
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index 9d2cce124a34..e30e54935d79 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -1431,7 +1431,7 @@ err_dma:
}
/* Remove the driver */
-static int s5p_mfc_remove(struct platform_device *pdev)
+static void s5p_mfc_remove(struct platform_device *pdev)
{
struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
struct s5p_mfc_ctx *ctx;
@@ -1463,7 +1463,6 @@ static int s5p_mfc_remove(struct platform_device *pdev)
s5p_mfc_unconfigure_dma_memory(dev);
s5p_mfc_final_pm(dev);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1690,7 +1689,7 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match);
static struct platform_driver s5p_mfc_driver = {
.probe = s5p_mfc_probe,
- .remove = s5p_mfc_remove,
+ .remove_new = s5p_mfc_remove,
.driver = {
.name = S5P_MFC_NAME,
.pm = &s5p_mfc_pm_ops,
diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
index dd74cc43920d..1328b4eb6b9f 100644
--- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
@@ -1257,7 +1257,7 @@ static const struct dev_pm_ops bdisp_pm_ops = {
.runtime_resume = bdisp_runtime_resume,
};
-static int bdisp_remove(struct platform_device *pdev)
+static void bdisp_remove(struct platform_device *pdev)
{
struct bdisp_dev *bdisp = platform_get_drvdata(pdev);
@@ -1277,8 +1277,6 @@ static int bdisp_remove(struct platform_device *pdev)
destroy_workqueue(bdisp->work_queue);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
-
- return 0;
}
static int bdisp_probe(struct platform_device *pdev)
@@ -1309,6 +1307,8 @@ static int bdisp_probe(struct platform_device *pdev)
init_waitqueue_head(&bdisp->irq_queue);
INIT_DELAYED_WORK(&bdisp->timeout_work, bdisp_irq_timeout);
bdisp->work_queue = create_workqueue(BDISP_NAME);
+ if (!bdisp->work_queue)
+ return -ENOMEM;
spin_lock_init(&bdisp->slock);
mutex_init(&bdisp->lock);
@@ -1411,7 +1411,7 @@ MODULE_DEVICE_TABLE(of, bdisp_match_types);
static struct platform_driver bdisp_driver = {
.probe = bdisp_probe,
- .remove = bdisp_remove,
+ .remove_new = bdisp_remove,
.driver = {
.name = BDISP_NAME,
.of_match_table = bdisp_match_types,
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
index c38b62d4f1ae..45ade7210d26 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
@@ -878,7 +878,7 @@ err_clk_disable:
return ret;
}
-static int c8sectpfe_remove(struct platform_device *pdev)
+static void c8sectpfe_remove(struct platform_device *pdev)
{
struct c8sectpfei *fei = platform_get_drvdata(pdev);
struct channel_info *channel;
@@ -910,8 +910,6 @@ static int c8sectpfe_remove(struct platform_device *pdev)
writel(0, fei->io + SYS_OTHER_CLKEN);
clk_disable_unprepare(fei->c8sectpfeclk);
-
- return 0;
}
@@ -1178,7 +1176,7 @@ static struct platform_driver c8sectpfe_driver = {
.of_match_table = of_match_ptr(c8sectpfe_match),
},
.probe = c8sectpfe_probe,
- .remove = c8sectpfe_remove,
+ .remove_new = c8sectpfe_remove,
};
module_platform_driver(c8sectpfe_driver);
diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c
index 03eaee6d15da..da402d1e9171 100644
--- a/drivers/media/platform/st/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c
@@ -1900,7 +1900,7 @@ err:
return ret;
}
-static int delta_remove(struct platform_device *pdev)
+static void delta_remove(struct platform_device *pdev)
{
struct delta_dev *delta = platform_get_drvdata(pdev);
@@ -1914,8 +1914,6 @@ static int delta_remove(struct platform_device *pdev)
pm_runtime_disable(delta->dev);
v4l2_device_unregister(&delta->v4l2_dev);
-
- return 0;
}
static int delta_runtime_suspend(struct device *dev)
@@ -1956,7 +1954,7 @@ MODULE_DEVICE_TABLE(of, delta_match_types);
static struct platform_driver delta_driver = {
.probe = delta_probe,
- .remove = delta_remove,
+ .remove_new = delta_remove,
.driver = {
.name = DELTA_NAME,
.of_match_table = delta_match_types,
diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
index bb34d6997d99..3a848ca32a0e 100644
--- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
@@ -1422,7 +1422,7 @@ err:
return ret;
}
-static int hva_remove(struct platform_device *pdev)
+static void hva_remove(struct platform_device *pdev)
{
struct hva_dev *hva = platform_get_drvdata(pdev);
struct device *dev = hva_to_dev(hva);
@@ -1440,8 +1440,6 @@ static int hva_remove(struct platform_device *pdev)
v4l2_device_unregister(&hva->v4l2_dev);
dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name);
-
- return 0;
}
/* PM ops */
@@ -1461,7 +1459,7 @@ MODULE_DEVICE_TABLE(of, hva_match_types);
static struct platform_driver hva_driver = {
.probe = hva_probe,
- .remove = hva_remove,
+ .remove_new = hva_remove,
.driver = {
.name = HVA_NAME,
.of_match_table = hva_match_types,
diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c
index 9706aa41b5d2..92f1edee58f8 100644
--- a/drivers/media/platform/st/stm32/dma2d/dma2d.c
+++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c
@@ -603,7 +603,6 @@ static int dma2d_probe(struct platform_device *pdev)
{
struct dma2d_dev *dev;
struct video_device *vfd;
- struct resource *res;
int ret = 0;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -614,9 +613,7 @@ static int dma2d_probe(struct platform_device *pdev)
mutex_init(&dev->mutex);
atomic_set(&dev->num_inst, 0);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- dev->regs = devm_ioremap_resource(&pdev->dev, res);
+ dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(dev->regs))
return PTR_ERR(dev->regs);
@@ -696,7 +693,7 @@ put_clk_gate:
return ret;
}
-static int dma2d_remove(struct platform_device *pdev)
+static void dma2d_remove(struct platform_device *pdev)
{
struct dma2d_dev *dev = platform_get_drvdata(pdev);
@@ -707,8 +704,6 @@ static int dma2d_remove(struct platform_device *pdev)
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
clk_unprepare(dev->gate);
clk_put(dev->gate);
-
- return 0;
}
static const struct of_device_id stm32_dma2d_match[] = {
@@ -722,7 +717,7 @@ MODULE_DEVICE_TABLE(of, stm32_dma2d_match);
static struct platform_driver dma2d_pdrv = {
.probe = dma2d_probe,
- .remove = dma2d_remove,
+ .remove_new = dma2d_remove,
.driver = {
.name = DMA2D_NAME,
.of_match_table = stm32_dma2d_match,
diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.h b/drivers/media/platform/st/stm32/dma2d/dma2d.h
index 3f03a7ca9ee3..af12739fc774 100644
--- a/drivers/media/platform/st/stm32/dma2d/dma2d.h
+++ b/drivers/media/platform/st/stm32/dma2d/dma2d.h
@@ -90,8 +90,6 @@ struct dma2d_ctx {
struct dma2d_frame cap;
struct dma2d_frame out;
struct dma2d_frame bg;
- /* fb_buf always point to bg address */
- struct v4l2_framebuffer fb_buf;
/*
* MODE[17:16] of DMA2D_CR
*/
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index ad8e9742e1ae..dad6e22e4ce4 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -2084,6 +2084,7 @@ static int dcmi_probe(struct platform_device *pdev)
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
+ q->allow_cache_hints = 1;
q->dev = &pdev->dev;
ret = vb2_queue_init(q);
@@ -2134,7 +2135,7 @@ err_media_device_cleanup:
return ret;
}
-static int dcmi_remove(struct platform_device *pdev)
+static void dcmi_remove(struct platform_device *pdev)
{
struct stm32_dcmi *dcmi = platform_get_drvdata(pdev);
@@ -2147,8 +2148,6 @@ static int dcmi_remove(struct platform_device *pdev)
media_device_cleanup(&dcmi->mdev);
dma_release_channel(dcmi->dma_chan);
-
- return 0;
}
static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
@@ -2202,7 +2201,7 @@ static const struct dev_pm_ops dcmi_pm_ops = {
static struct platform_driver stm32_dcmi_driver = {
.probe = dcmi_probe,
- .remove = dcmi_remove,
+ .remove_new = dcmi_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(stm32_dcmi_of_match),
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 86c5235a0c7a..d6e7d1b36083 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -260,7 +260,7 @@ err_clean_pad:
return ret;
}
-static int sun4i_csi_remove(struct platform_device *pdev)
+static void sun4i_csi_remove(struct platform_device *pdev)
{
struct sun4i_csi *csi = platform_get_drvdata(pdev);
@@ -271,8 +271,6 @@ static int sun4i_csi_remove(struct platform_device *pdev)
media_device_unregister(&csi->mdev);
sun4i_csi_dma_unregister(csi);
media_device_cleanup(&csi->mdev);
-
- return 0;
}
static const struct sun4i_csi_traits sun4i_a10_csi1_traits = {
@@ -330,7 +328,7 @@ static const struct dev_pm_ops sun4i_csi_pm_ops = {
static struct platform_driver sun4i_csi_driver = {
.probe = sun4i_csi_probe,
- .remove = sun4i_csi_remove,
+ .remove_new = sun4i_csi_remove,
.driver = {
.name = "sun4i-csi",
.of_match_table = sun4i_csi_of_match,
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index e3e6650181c8..e2723cfa4515 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -375,7 +375,7 @@ error_resources:
return ret;
}
-static int sun6i_csi_remove(struct platform_device *pdev)
+static void sun6i_csi_remove(struct platform_device *pdev)
{
struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev);
@@ -386,8 +386,6 @@ static int sun6i_csi_remove(struct platform_device *pdev)
sun6i_csi_v4l2_cleanup(csi_dev);
sun6i_csi_resources_cleanup(csi_dev);
-
- return 0;
}
static const struct sun6i_csi_variant sun6i_a31_csi_variant = {
@@ -426,7 +424,7 @@ MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
static struct platform_driver sun6i_csi_platform_driver = {
.probe = sun6i_csi_probe,
- .remove = sun6i_csi_remove,
+ .remove_new = sun6i_csi_remove,
.driver = {
.name = SUN6I_CSI_NAME,
.of_match_table = of_match_ptr(sun6i_csi_of_match),
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index a220ce849b41..dce130b4c9f6 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -737,15 +737,13 @@ error_resources:
return ret;
}
-static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev)
+static void sun6i_mipi_csi2_remove(struct platform_device *platform_dev)
{
struct sun6i_mipi_csi2_device *csi2_dev =
platform_get_drvdata(platform_dev);
sun6i_mipi_csi2_bridge_cleanup(csi2_dev);
sun6i_mipi_csi2_resources_cleanup(csi2_dev);
-
- return 0;
}
static const struct of_device_id sun6i_mipi_csi2_of_match[] = {
@@ -756,7 +754,7 @@ MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match);
static struct platform_driver sun6i_mipi_csi2_platform_driver = {
.probe = sun6i_mipi_csi2_probe,
- .remove = sun6i_mipi_csi2_remove,
+ .remove_new = sun6i_mipi_csi2_remove,
.driver = {
.name = SUN6I_MIPI_CSI2_NAME,
.of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match),
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index cd2e92ae2293..23d32e198aaa 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -804,15 +804,13 @@ error_resources:
return ret;
}
-static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev)
+static void sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev)
{
struct sun8i_a83t_mipi_csi2_device *csi2_dev =
platform_get_drvdata(platform_dev);
sun8i_a83t_mipi_csi2_bridge_cleanup(csi2_dev);
sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev);
-
- return 0;
}
static const struct of_device_id sun8i_a83t_mipi_csi2_of_match[] = {
@@ -823,7 +821,7 @@ MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match);
static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = {
.probe = sun8i_a83t_mipi_csi2_probe,
- .remove = sun8i_a83t_mipi_csi2_remove,
+ .remove_new = sun8i_a83t_mipi_csi2_remove,
.driver = {
.name = SUN8I_A83T_MIPI_CSI2_NAME,
.of_match_table = of_match_ptr(sun8i_a83t_mipi_csi2_of_match),
diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
index aa65d70b6270..e4b0fd793f55 100644
--- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
+++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
@@ -906,7 +906,7 @@ err_v4l2:
return ret;
}
-static int deinterlace_remove(struct platform_device *pdev)
+static void deinterlace_remove(struct platform_device *pdev)
{
struct deinterlace_dev *dev = platform_get_drvdata(pdev);
@@ -915,8 +915,6 @@ static int deinterlace_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
pm_runtime_force_suspend(&pdev->dev);
-
- return 0;
}
static int deinterlace_runtime_resume(struct device *device)
@@ -1002,7 +1000,7 @@ static const struct dev_pm_ops deinterlace_pm_ops = {
static struct platform_driver deinterlace_driver = {
.probe = deinterlace_probe,
- .remove = deinterlace_remove,
+ .remove_new = deinterlace_remove,
.driver = {
.name = DEINTERLACE_NAME,
.of_match_table = deinterlace_dt_match,
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
index fbcca59a0517..bd0c4257bbff 100644
--- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
@@ -833,7 +833,7 @@ err_v4l2:
return ret;
}
-static int rotate_remove(struct platform_device *pdev)
+static void rotate_remove(struct platform_device *pdev)
{
struct rotate_dev *dev = platform_get_drvdata(pdev);
@@ -842,8 +842,6 @@ static int rotate_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
pm_runtime_force_suspend(&pdev->dev);
-
- return 0;
}
static int rotate_runtime_resume(struct device *device)
@@ -907,7 +905,7 @@ static const struct dev_pm_ops rotate_pm_ops = {
static struct platform_driver rotate_driver = {
.probe = rotate_probe,
- .remove = rotate_remove,
+ .remove_new = rotate_remove,
.driver = {
.name = ROTATE_NAME,
.of_match_table = rotate_dt_match,
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index 2dfae9bc0bba..ffe1887cc429 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -1285,13 +1285,13 @@ static int __subdev_get_format(struct vpfe_device *vpfe,
struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_subdev *sd = vpfe->current_subdev->sd;
- struct v4l2_subdev_format sd_fmt;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = 0,
+ };
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sd_fmt.pad = 0;
-
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
if (ret)
return ret;
@@ -1309,12 +1309,13 @@ static int __subdev_set_format(struct vpfe_device *vpfe,
struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_subdev *sd = vpfe->current_subdev->sd;
- struct v4l2_subdev_format sd_fmt;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = 0,
+ };
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sd_fmt.pad = 0;
*mbus_fmt = *fmt;
ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt);
@@ -1393,7 +1394,9 @@ static int vpfe_try_fmt(struct file *file, void *priv,
struct vpfe_device *vpfe = video_drvdata(file);
struct v4l2_subdev *sd = vpfe->current_subdev->sd;
const struct vpfe_fmt *fmt;
- struct v4l2_subdev_frame_size_enum fse;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret, found;
fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat);
@@ -1412,7 +1415,6 @@ static int vpfe_try_fmt(struct file *file, void *priv,
found = false;
fse.pad = 0;
fse.code = fmt->code;
- fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
for (fse.index = 0; ; fse.index++) {
ret = v4l2_subdev_call(sd, pad, enum_frame_size,
NULL, &fse);
@@ -1499,7 +1501,9 @@ static int vpfe_enum_size(struct file *file, void *priv,
struct v4l2_frmsizeenum *fsize)
{
struct vpfe_device *vpfe = video_drvdata(file);
- struct v4l2_subdev_frame_size_enum fse;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *sd = vpfe->current_subdev->sd;
struct vpfe_fmt *fmt;
int ret;
@@ -1514,11 +1518,9 @@ static int vpfe_enum_size(struct file *file, void *priv,
memset(fsize->reserved, 0x0, sizeof(fsize->reserved));
- memset(&fse, 0x0, sizeof(fse));
fse.index = fsize->index;
fse.pad = 0;
fse.code = fmt->code;
- fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
if (ret)
return ret;
@@ -2146,7 +2148,6 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
{
struct vpfe_device *vpfe = container_of(notifier->v4l2_dev,
struct vpfe_device, v4l2_dev);
- struct v4l2_subdev_mbus_code_enum mbus_code;
struct vpfe_subdev_info *sdinfo;
struct vpfe_fmt *fmt;
int ret = 0;
@@ -2173,9 +2174,11 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
vpfe->num_active_fmt = 0;
for (j = 0, i = 0; (ret != -EINVAL); ++j) {
- memset(&mbus_code, 0, sizeof(mbus_code));
- mbus_code.index = j;
- mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ struct v4l2_subdev_mbus_code_enum mbus_code = {
+ .index = j,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
NULL, &mbus_code);
if (ret)
@@ -2483,7 +2486,7 @@ probe_out_cleanup:
/*
* vpfe_remove : It un-register device from V4L2 driver
*/
-static int vpfe_remove(struct platform_device *pdev)
+static void vpfe_remove(struct platform_device *pdev)
{
struct vpfe_device *vpfe = platform_get_drvdata(pdev);
@@ -2493,8 +2496,6 @@ static int vpfe_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&vpfe->notifier);
v4l2_device_unregister(&vpfe->v4l2_dev);
video_unregister_device(&vpfe->video_dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -2625,7 +2626,7 @@ MODULE_DEVICE_TABLE(of, vpfe_of_match);
static struct platform_driver vpfe_driver = {
.probe = vpfe_probe,
- .remove = vpfe_remove,
+ .remove_new = vpfe_remove,
.driver = {
.name = VPFE_MODULE_NAME,
.pm = &vpfe_pm_ops,
diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
index 4eade409d5d3..ca906a9e4222 100644
--- a/drivers/media/platform/ti/cal/cal-video.c
+++ b/drivers/media/platform/ti/cal/cal-video.c
@@ -117,13 +117,13 @@ static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv,
static int __subdev_get_format(struct cal_ctx *ctx,
struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_subdev_format sd_fmt;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = 0,
+ };
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sd_fmt.pad = 0;
-
ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt);
if (ret)
return ret;
@@ -139,12 +139,13 @@ static int __subdev_get_format(struct cal_ctx *ctx,
static int __subdev_set_format(struct cal_ctx *ctx,
struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_subdev_format sd_fmt;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = 0,
+ };
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sd_fmt.pad = 0;
*mbus_fmt = *fmt;
ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt);
@@ -190,7 +191,9 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
{
struct cal_ctx *ctx = video_drvdata(file);
const struct cal_format_info *fmtinfo;
- struct v4l2_subdev_frame_size_enum fse;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int found;
fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
@@ -209,7 +212,6 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
found = false;
fse.pad = 0;
fse.code = fmtinfo->code;
- fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
for (fse.index = 0; ; fse.index++) {
int ret;
@@ -302,7 +304,11 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
{
struct cal_ctx *ctx = video_drvdata(file);
const struct cal_format_info *fmtinfo;
- struct v4l2_subdev_frame_size_enum fse;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = fsize->index,
+ .pad = 0,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
/* check for valid format */
@@ -313,10 +319,7 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
return -EINVAL;
}
- fse.index = fsize->index;
- fse.pad = 0;
fse.code = fmtinfo->code;
- fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL,
&fse);
@@ -811,7 +814,6 @@ static const struct v4l2_file_operations cal_fops = {
static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
{
- struct v4l2_subdev_mbus_code_enum mbus_code;
struct v4l2_mbus_framefmt mbus_fmt;
const struct cal_format_info *fmtinfo;
unsigned int i, j, k;
@@ -826,10 +828,11 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
ctx->num_active_fmt = 0;
for (j = 0, i = 0; ; ++j) {
+ struct v4l2_subdev_mbus_code_enum mbus_code = {
+ .index = j,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
- memset(&mbus_code, 0, sizeof(mbus_code));
- mbus_code.index = j;
- mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
NULL, &mbus_code);
if (ret == -EINVAL)
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 1236215ec70e..9c5105223d6b 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -1293,7 +1293,7 @@ error_pm_runtime:
return ret;
}
-static int cal_remove(struct platform_device *pdev)
+static void cal_remove(struct platform_device *pdev)
{
struct cal_dev *cal = platform_get_drvdata(pdev);
unsigned int i;
@@ -1319,8 +1319,6 @@ static int cal_remove(struct platform_device *pdev)
if (ret >= 0)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static int cal_runtime_resume(struct device *dev)
@@ -1364,7 +1362,7 @@ static const struct dev_pm_ops cal_pm_ops = {
static struct platform_driver cal_pdrv = {
.probe = cal_probe,
- .remove = cal_remove,
+ .remove_new = cal_remove,
.driver = {
.name = CAL_MODULE_NAME,
.pm = &cal_pm_ops,
diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c
index 832489822706..63cdfed37bc9 100644
--- a/drivers/media/platform/ti/davinci/vpif.c
+++ b/drivers/media/platform/ti/davinci/vpif.c
@@ -538,7 +538,7 @@ err_put_rpm:
return ret;
}
-static int vpif_remove(struct platform_device *pdev)
+static void vpif_remove(struct platform_device *pdev)
{
struct vpif_data *data = platform_get_drvdata(pdev);
@@ -551,8 +551,6 @@ static int vpif_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
kfree(data);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -592,7 +590,7 @@ static struct platform_driver vpif_driver = {
.name = VPIF_DRIVER_NAME,
.pm = vpif_pm_ops,
},
- .remove = vpif_remove,
+ .remove_new = vpif_remove,
.probe = vpif_probe,
};
diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 580723333fcc..44d269d6038c 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -1714,7 +1714,7 @@ cleanup:
*
* The vidoe device is unregistered
*/
-static int vpif_remove(struct platform_device *device)
+static void vpif_remove(struct platform_device *device)
{
struct channel_obj *ch;
int i;
@@ -1732,7 +1732,6 @@ static int vpif_remove(struct platform_device *device)
video_unregister_device(&ch->video_dev);
kfree(vpif_obj.dev[i]);
}
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1815,7 +1814,7 @@ static __refdata struct platform_driver vpif_driver = {
.pm = &vpif_pm_ops,
},
.probe = vpif_probe,
- .remove = vpif_remove,
+ .remove_new = vpif_remove,
};
module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c
index b2df81603f62..f8ec2991c667 100644
--- a/drivers/media/platform/ti/davinci/vpif_display.c
+++ b/drivers/media/platform/ti/davinci/vpif_display.c
@@ -1305,7 +1305,7 @@ vpif_free:
/*
* vpif_remove: It un-register channels from V4L2 driver
*/
-static int vpif_remove(struct platform_device *device)
+static void vpif_remove(struct platform_device *device)
{
struct channel_obj *ch;
int i;
@@ -1321,8 +1321,6 @@ static int vpif_remove(struct platform_device *device)
video_unregister_device(&ch->video_dev);
}
free_vpif_objs();
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1399,7 +1397,7 @@ static __refdata struct platform_driver vpif_driver = {
.pm = &vpif_pm_ops,
},
.probe = vpif_probe,
- .remove = vpif_remove,
+ .remove_new = vpif_remove,
};
module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c
index 3e0d9af7ffec..4143274089c3 100644
--- a/drivers/media/platform/ti/omap/omap_vout.c
+++ b/drivers/media/platform/ti/omap/omap_vout.c
@@ -1569,7 +1569,7 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout)
kfree(vout);
}
-static int omap_vout_remove(struct platform_device *pdev)
+static void omap_vout_remove(struct platform_device *pdev)
{
int k;
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
@@ -1587,7 +1587,6 @@ static int omap_vout_remove(struct platform_device *pdev)
omap_dss_put_device(vid_dev->displays[k]);
}
kfree(vid_dev);
- return 0;
}
static int __init omap_vout_probe(struct platform_device *pdev)
@@ -1721,7 +1720,7 @@ static struct platform_driver omap_vout_driver = {
.driver = {
.name = VOUT_NAME,
},
- .remove = omap_vout_remove,
+ .remove_new = omap_vout_remove,
};
static int __init omap_vout_init(void)
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index e7327e38482d..f3aaa9e76492 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -1997,7 +1997,7 @@ error:
*
* Always returns 0.
*/
-static int isp_remove(struct platform_device *pdev)
+static void isp_remove(struct platform_device *pdev)
{
struct isp_device *isp = platform_get_drvdata(pdev);
@@ -2014,8 +2014,6 @@ static int isp_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&isp->notifier);
kfree(isp);
-
- return 0;
}
enum isp_of_phy {
@@ -2476,7 +2474,7 @@ MODULE_DEVICE_TABLE(of, omap3isp_of_table);
static struct platform_driver omap3isp_driver = {
.probe = isp_probe,
- .remove = isp_remove,
+ .remove_new = isp_remove,
.id_table = omap3isp_id_table,
.driver = {
.name = "omap3isp",
diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c
index 11afb8aec292..fdcdffe5fecb 100644
--- a/drivers/media/platform/ti/omap3isp/ispccdc.c
+++ b/drivers/media/platform/ti/omap3isp/ispccdc.c
@@ -1118,7 +1118,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
struct v4l2_mbus_framefmt *format;
const struct v4l2_rect *crop;
const struct isp_format_info *fmt_info;
- struct v4l2_subdev_format fmt_src;
+ struct v4l2_subdev_format fmt_src = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
unsigned int depth_out;
unsigned int depth_in = 0;
struct media_pad *pad;
@@ -1150,7 +1152,6 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
* input format is a non-BT.656 YUV variant.
*/
fmt_src.pad = pad->index;
- fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
fmt_info = omap3isp_video_format_info(fmt_src.format.code);
depth_in = fmt_info->width;
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index ddc7d08d4f96..daca689dc082 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -268,7 +268,9 @@ static int isp_video_get_graph_data(struct isp_video *video,
static int
__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
{
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
u32 pad;
int ret;
@@ -278,7 +280,6 @@ __isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
return -EINVAL;
fmt.pad = pad;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
mutex_lock(&video->mutex);
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
@@ -731,7 +732,9 @@ static int
isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
{
struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
u32 pad;
int ret;
@@ -746,7 +749,6 @@ isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
fmt.pad = pad;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
if (ret)
return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
@@ -759,7 +761,9 @@ static int
isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
{
struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev_format format;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
struct v4l2_subdev_selection sdsel = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -799,7 +803,6 @@ isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
return ret;
format.pad = pad;
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
if (ret < 0)
return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
@@ -957,7 +960,9 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
struct media_pad *source_pad;
struct media_entity *source = NULL;
struct media_entity *sink;
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;
unsigned int i;
@@ -993,7 +998,6 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
pipe->external = media_entity_to_v4l2_subdev(source);
fmt.pad = source_pad->index;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
pad, get_fmt, NULL, &fmt);
if (unlikely(ret < 0)) {
diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c
index 5b1c5d96a407..6848cbc82f52 100644
--- a/drivers/media/platform/ti/vpe/vpe.c
+++ b/drivers/media/platform/ti/vpe/vpe.c
@@ -2622,7 +2622,7 @@ v4l2_dev_unreg:
return ret;
}
-static int vpe_remove(struct platform_device *pdev)
+static void vpe_remove(struct platform_device *pdev)
{
struct vpe_dev *dev = platform_get_drvdata(pdev);
@@ -2635,8 +2635,6 @@ static int vpe_remove(struct platform_device *pdev)
vpe_set_clock_enable(dev, 0);
vpe_runtime_put(pdev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#if defined(CONFIG_OF)
@@ -2651,7 +2649,7 @@ MODULE_DEVICE_TABLE(of, vpe_of_match);
static struct platform_driver vpe_pdrv = {
.probe = vpe_probe,
- .remove = vpe_remove,
+ .remove_new = vpe_remove,
.driver = {
.name = VPE_MODULE_NAME,
.of_match_table = of_match_ptr(vpe_of_match),
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index b0aeedae7b65..09c74a573ddb 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -251,11 +251,6 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
{
- struct hantro_ctx *ctx;
-
- ctx = container_of(ctrl->handler,
- struct hantro_ctx, ctrl_handler);
-
if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) {
const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
@@ -274,8 +269,6 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
/* Only 8-bit and 10-bit are supported */
return -EINVAL;
-
- ctx->bit_depth = sps->bit_depth_luma_minus8 + 8;
} else if (ctrl->id == V4L2_CID_STATELESS_VP9_FRAME) {
const struct v4l2_ctrl_vp9_frame *dec_params = ctrl->p_new.p_vp9_frame;
@@ -314,9 +307,38 @@ static int hantro_vp9_s_ctrl(struct v4l2_ctrl *ctrl)
struct hantro_ctx, ctrl_handler);
switch (ctrl->id) {
- case V4L2_CID_STATELESS_VP9_FRAME:
- ctx->bit_depth = ctrl->p_new.p_vp9_frame->bit_depth;
- break;
+ case V4L2_CID_STATELESS_VP9_FRAME: {
+ int bit_depth = ctrl->p_new.p_vp9_frame->bit_depth;
+
+ if (ctx->bit_depth == bit_depth)
+ return 0;
+
+ return hantro_reset_raw_fmt(ctx, bit_depth);
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hantro_hevc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct hantro_ctx *ctx;
+
+ ctx = container_of(ctrl->handler,
+ struct hantro_ctx, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_STATELESS_HEVC_SPS: {
+ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+ int bit_depth = sps->bit_depth_luma_minus8 + 8;
+
+ if (ctx->bit_depth == bit_depth)
+ return 0;
+
+ return hantro_reset_raw_fmt(ctx, bit_depth);
+ }
default:
return -EINVAL;
}
@@ -336,6 +358,11 @@ static const struct v4l2_ctrl_ops hantro_vp9_ctrl_ops = {
.s_ctrl = hantro_vp9_s_ctrl,
};
+static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = {
+ .try_ctrl = hantro_try_ctrl,
+ .s_ctrl = hantro_hevc_s_ctrl,
+};
+
#define HANTRO_JPEG_ACTIVE_MARKERS (V4L2_JPEG_ACTIVE_MARKER_APP0 | \
V4L2_JPEG_ACTIVE_MARKER_COM | \
V4L2_JPEG_ACTIVE_MARKER_DQT | \
@@ -470,7 +497,7 @@ static const struct hantro_ctrl controls[] = {
.codec = HANTRO_HEVC_DECODER,
.cfg = {
.id = V4L2_CID_STATELESS_HEVC_SPS,
- .ops = &hantro_ctrl_ops,
+ .ops = &hantro_hevc_ctrl_ops,
},
}, {
.codec = HANTRO_HEVC_DECODER,
@@ -945,7 +972,7 @@ static int hantro_probe(struct platform_device *pdev)
return PTR_ERR(vpu->clocks[0].clk);
}
- vpu->resets = devm_reset_control_array_get(&pdev->dev, false, true);
+ vpu->resets = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
if (IS_ERR(vpu->resets))
return PTR_ERR(vpu->resets);
@@ -1093,7 +1120,7 @@ err_pm_disable:
return ret;
}
-static int hantro_remove(struct platform_device *pdev)
+static void hantro_remove(struct platform_device *pdev)
{
struct hantro_dev *vpu = platform_get_drvdata(pdev);
@@ -1109,7 +1136,6 @@ static int hantro_remove(struct platform_device *pdev)
reset_control_assert(vpu->resets);
pm_runtime_dont_use_autosuspend(vpu->dev);
pm_runtime_disable(vpu->dev);
- return 0;
}
#ifdef CONFIG_PM
@@ -1132,7 +1158,7 @@ static const struct dev_pm_ops hantro_pm_ops = {
static struct platform_driver hantro_driver = {
.probe = hantro_probe,
- .remove = hantro_remove,
+ .remove_new = hantro_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(of_hantro_match),
diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c
index 09d8cf942689..6437423ccf3a 100644
--- a/drivers/media/platform/verisilicon/hantro_postproc.c
+++ b/drivers/media/platform/verisilicon/hantro_postproc.c
@@ -197,7 +197,7 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx)
unsigned int i, buf_size;
/* this should always pick native format */
- fmt = hantro_get_default_fmt(ctx, false);
+ fmt = hantro_get_default_fmt(ctx, false, ctx->bit_depth);
if (!fmt)
return -EINVAL;
v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width,
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index c0d427956210..835518534e3b 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -28,6 +28,8 @@
#include "hantro_hw.h"
#include "hantro_v4l2.h"
+#define HANTRO_DEFAULT_BIT_DEPTH 8
+
static int hantro_set_fmt_out(struct hantro_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp);
static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
@@ -76,18 +78,13 @@ int hantro_get_format_depth(u32 fourcc)
}
static bool
-hantro_check_depth_match(const struct hantro_ctx *ctx,
- const struct hantro_fmt *fmt)
+hantro_check_depth_match(const struct hantro_fmt *fmt, int bit_depth)
{
- int fmt_depth, ctx_depth = 8;
+ int fmt_depth;
if (!fmt->match_depth && !fmt->postprocessed)
return true;
- /* 0 means default depth, which is 8 */
- if (ctx->bit_depth)
- ctx_depth = ctx->bit_depth;
-
fmt_depth = hantro_get_format_depth(fmt->fourcc);
/*
@@ -95,9 +92,9 @@ hantro_check_depth_match(const struct hantro_ctx *ctx,
* It may be possible to relax that on some HW.
*/
if (!fmt->match_depth)
- return fmt_depth <= ctx_depth;
+ return fmt_depth <= bit_depth;
- return fmt_depth == ctx_depth;
+ return fmt_depth == bit_depth;
}
static const struct hantro_fmt *
@@ -119,7 +116,7 @@ hantro_find_format(const struct hantro_ctx *ctx, u32 fourcc)
}
const struct hantro_fmt *
-hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream)
+hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream, int bit_depth)
{
const struct hantro_fmt *formats;
unsigned int i, num_fmts;
@@ -128,7 +125,7 @@ hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream)
for (i = 0; i < num_fmts; i++) {
if (bitstream == (formats[i].codec_mode !=
HANTRO_MODE_NONE) &&
- hantro_check_depth_match(ctx, &formats[i]))
+ hantro_check_depth_match(&formats[i], bit_depth))
return &formats[i];
}
return NULL;
@@ -204,7 +201,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
if (skip_mode_none == mode_none)
continue;
- if (!hantro_check_depth_match(ctx, fmt))
+ if (!hantro_check_depth_match(fmt, ctx->bit_depth))
continue;
if (j == f->index) {
f->pixelformat = fmt->fourcc;
@@ -224,7 +221,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
for (i = 0; i < num_fmts; i++) {
fmt = &formats[i];
- if (!hantro_check_depth_match(ctx, fmt))
+ if (!hantro_check_depth_match(fmt, ctx->bit_depth))
continue;
if (j == f->index) {
f->pixelformat = fmt->fourcc;
@@ -278,7 +275,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp,
enum v4l2_buf_type type)
{
- const struct hantro_fmt *fmt, *vpu_fmt;
+ const struct hantro_fmt *fmt;
bool capture = V4L2_TYPE_IS_CAPTURE(type);
bool coded;
@@ -292,17 +289,13 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
fmt = hantro_find_format(ctx, pix_mp->pixelformat);
if (!fmt) {
- fmt = hantro_get_default_fmt(ctx, coded);
+ fmt = hantro_get_default_fmt(ctx, coded, HANTRO_DEFAULT_BIT_DEPTH);
pix_mp->pixelformat = fmt->fourcc;
}
if (coded) {
pix_mp->num_planes = 1;
- vpu_fmt = fmt;
- } else if (ctx->is_encoder) {
- vpu_fmt = ctx->vpu_dst_fmt;
- } else {
- vpu_fmt = fmt;
+ } else if (!ctx->is_encoder) {
/*
* Width/height on the CAPTURE end of a decoder are ignored and
* replaced by the OUTPUT ones.
@@ -314,7 +307,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
pix_mp->field = V4L2_FIELD_NONE;
v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height,
- &vpu_fmt->frmsize);
+ &fmt->frmsize);
if (!coded) {
/* Fill remaining fields */
@@ -378,58 +371,55 @@ static void
hantro_reset_encoded_fmt(struct hantro_ctx *ctx)
{
const struct hantro_fmt *vpu_fmt;
- struct v4l2_pix_format_mplane *fmt;
-
- vpu_fmt = hantro_get_default_fmt(ctx, true);
+ struct v4l2_pix_format_mplane fmt;
- if (ctx->is_encoder) {
- ctx->vpu_dst_fmt = vpu_fmt;
- fmt = &ctx->dst_fmt;
- } else {
- ctx->vpu_src_fmt = vpu_fmt;
- fmt = &ctx->src_fmt;
- }
+ vpu_fmt = hantro_get_default_fmt(ctx, true, HANTRO_DEFAULT_BIT_DEPTH);
+ if (!vpu_fmt)
+ return;
- hantro_reset_fmt(fmt, vpu_fmt);
- fmt->width = vpu_fmt->frmsize.min_width;
- fmt->height = vpu_fmt->frmsize.min_height;
+ hantro_reset_fmt(&fmt, vpu_fmt);
+ fmt.width = vpu_fmt->frmsize.min_width;
+ fmt.height = vpu_fmt->frmsize.min_height;
if (ctx->is_encoder)
- hantro_set_fmt_cap(ctx, fmt);
+ hantro_set_fmt_cap(ctx, &fmt);
else
- hantro_set_fmt_out(ctx, fmt);
+ hantro_set_fmt_out(ctx, &fmt);
}
-static void
-hantro_reset_raw_fmt(struct hantro_ctx *ctx)
+int
+hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth)
{
const struct hantro_fmt *raw_vpu_fmt;
- struct v4l2_pix_format_mplane *raw_fmt, *encoded_fmt;
+ struct v4l2_pix_format_mplane raw_fmt, *encoded_fmt;
+ int ret;
- raw_vpu_fmt = hantro_get_default_fmt(ctx, false);
+ raw_vpu_fmt = hantro_get_default_fmt(ctx, false, bit_depth);
+ if (!raw_vpu_fmt)
+ return -EINVAL;
- if (ctx->is_encoder) {
- ctx->vpu_src_fmt = raw_vpu_fmt;
- raw_fmt = &ctx->src_fmt;
+ if (ctx->is_encoder)
encoded_fmt = &ctx->dst_fmt;
- } else {
- ctx->vpu_dst_fmt = raw_vpu_fmt;
- raw_fmt = &ctx->dst_fmt;
+ else
encoded_fmt = &ctx->src_fmt;
- }
- hantro_reset_fmt(raw_fmt, raw_vpu_fmt);
- raw_fmt->width = encoded_fmt->width;
- raw_fmt->height = encoded_fmt->height;
+ hantro_reset_fmt(&raw_fmt, raw_vpu_fmt);
+ raw_fmt.width = encoded_fmt->width;
+ raw_fmt.height = encoded_fmt->height;
if (ctx->is_encoder)
- hantro_set_fmt_out(ctx, raw_fmt);
+ ret = hantro_set_fmt_out(ctx, &raw_fmt);
else
- hantro_set_fmt_cap(ctx, raw_fmt);
+ ret = hantro_set_fmt_cap(ctx, &raw_fmt);
+
+ if (!ret)
+ ctx->bit_depth = bit_depth;
+
+ return ret;
}
void hantro_reset_fmts(struct hantro_ctx *ctx)
{
hantro_reset_encoded_fmt(ctx);
- hantro_reset_raw_fmt(ctx);
+ hantro_reset_raw_fmt(ctx, HANTRO_DEFAULT_BIT_DEPTH);
}
static void
@@ -529,7 +519,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
* changes to the raw format.
*/
if (!ctx->is_encoder)
- hantro_reset_raw_fmt(ctx);
+ hantro_reset_raw_fmt(ctx, hantro_get_format_depth(pix_mp->pixelformat));
/* Colorimetry information are always propagated. */
ctx->dst_fmt.colorspace = pix_mp->colorspace;
@@ -592,7 +582,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
* changes to the raw format.
*/
if (ctx->is_encoder)
- hantro_reset_raw_fmt(ctx);
+ hantro_reset_raw_fmt(ctx, HANTRO_DEFAULT_BIT_DEPTH);
/* Colorimetry information are always propagated. */
ctx->src_fmt.colorspace = pix_mp->colorspace;
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.h b/drivers/media/platform/verisilicon/hantro_v4l2.h
index 64f6f57e9d7a..9ea2fef57dcd 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.h
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.h
@@ -21,9 +21,10 @@
extern const struct v4l2_ioctl_ops hantro_ioctl_ops;
extern const struct vb2_ops hantro_queue_ops;
+int hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth);
void hantro_reset_fmts(struct hantro_ctx *ctx);
int hantro_get_format_depth(u32 fourcc);
const struct hantro_fmt *
-hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream);
+hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream, int bit_depth);
#endif /* HANTRO_V4L2_H_ */
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index b390228fd3b4..f850d8bddef6 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -152,6 +152,7 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_NV12,
.codec_mode = HANTRO_MODE_NONE,
+ .match_depth = true,
.postprocessed = true,
.frmsize = {
.min_width = FMT_MIN_WIDTH,
@@ -165,6 +166,7 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_P010,
.codec_mode = HANTRO_MODE_NONE,
+ .match_depth = true,
.postprocessed = true,
.frmsize = {
.min_width = FMT_MIN_WIDTH,
diff --git a/drivers/media/platform/via/via-camera.c b/drivers/media/platform/via/via-camera.c
index 95483c84c3f2..450254403fa8 100644
--- a/drivers/media/platform/via/via-camera.c
+++ b/drivers/media/platform/via/via-camera.c
@@ -845,8 +845,8 @@ static int viacam_do_try_fmt(struct via_camera *cam,
int ret;
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
+ .pads = &pad_cfg,
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1208,7 +1208,9 @@ static int viacam_probe(struct platform_device *pdev)
* Convince the system that we can do DMA.
*/
pdev->dev.dma_mask = &viadev->pdev->dma_mask;
- dma_set_mask(&pdev->dev, 0xffffffff);
+ ret = dma_set_mask(&pdev->dev, 0xffffffff);
+ if (ret)
+ goto out_ctrl_hdl_free;
/*
* Fire up the capture port. The write to 0x78 looks purely
* OLPCish; any system will need to tweak 0x1e.
@@ -1294,7 +1296,7 @@ out_free:
return ret;
}
-static int viacam_remove(struct platform_device *pdev)
+static void viacam_remove(struct platform_device *pdev)
{
struct via_camera *cam = via_cam_info;
struct viafb_dev *viadev = pdev->dev.platform_data;
@@ -1309,7 +1311,6 @@ static int viacam_remove(struct platform_device *pdev)
v4l2_ctrl_handler_free(&cam->ctrl_handler);
kfree(cam);
via_cam_info = NULL;
- return 0;
}
static struct platform_driver viacam_driver = {
@@ -1317,7 +1318,7 @@ static struct platform_driver viacam_driver = {
.name = "viafb-camera",
},
.probe = viacam_probe,
- .remove = viacam_remove,
+ .remove_new = viacam_remove,
};
module_platform_driver(viacam_driver);
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 71d97042a470..1d9f32e5a917 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -481,7 +481,7 @@ static int video_mux_probe(struct platform_device *pdev)
return ret;
}
-static int video_mux_remove(struct platform_device *pdev)
+static void video_mux_remove(struct platform_device *pdev)
{
struct video_mux *vmux = platform_get_drvdata(pdev);
struct v4l2_subdev *sd = &vmux->subdev;
@@ -490,8 +490,6 @@ static int video_mux_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&vmux->notifier);
v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
-
- return 0;
}
static const struct of_device_id video_mux_dt_ids[] = {
@@ -502,7 +500,7 @@ MODULE_DEVICE_TABLE(of, video_mux_dt_ids);
static struct platform_driver video_mux_driver = {
.probe = video_mux_probe,
- .remove = video_mux_remove,
+ .remove_new = video_mux_remove,
.driver = {
.of_match_table = video_mux_dt_ids,
.name = "video-mux",
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index d8a23f18cfbc..5b53745fe44e 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -1059,7 +1059,7 @@ err_clk_put:
return ret;
}
-static int xcsi2rxss_remove(struct platform_device *pdev)
+static void xcsi2rxss_remove(struct platform_device *pdev)
{
struct xcsi2rxss_state *xcsi2rxss = platform_get_drvdata(pdev);
struct v4l2_subdev *subdev = &xcsi2rxss->subdev;
@@ -1070,8 +1070,6 @@ static int xcsi2rxss_remove(struct platform_device *pdev)
mutex_destroy(&xcsi2rxss->lock);
clk_bulk_disable_unprepare(num_clks, xcsi2rxss->clks);
clk_bulk_put(num_clks, xcsi2rxss->clks);
-
- return 0;
}
static const struct of_device_id xcsi2rxss_of_id_table[] = {
@@ -1086,7 +1084,7 @@ static struct platform_driver xcsi2rxss_driver = {
.of_match_table = xcsi2rxss_of_id_table,
},
.probe = xcsi2rxss_probe,
- .remove = xcsi2rxss_remove,
+ .remove_new = xcsi2rxss_remove,
};
module_platform_driver(xcsi2rxss_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index fee02c8c85fd..80d6f5b072ea 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -56,7 +56,9 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
static int xvip_dma_verify_format(struct xvip_dma *dma)
{
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
struct v4l2_subdev *subdev;
int ret;
@@ -64,7 +66,6 @@ static int xvip_dma_verify_format(struct xvip_dma *dma)
if (subdev == NULL)
return -EPIPE;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
if (ret < 0)
return ret == -ENOIOCTLCMD ? -EINVAL : ret;
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index 0f2d5a0edf0c..80353ca44402 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -894,7 +894,7 @@ error_resource:
return ret;
}
-static int xtpg_remove(struct platform_device *pdev)
+static void xtpg_remove(struct platform_device *pdev)
{
struct xtpg_device *xtpg = platform_get_drvdata(pdev);
struct v4l2_subdev *subdev = &xtpg->xvip.subdev;
@@ -904,8 +904,6 @@ static int xtpg_remove(struct platform_device *pdev)
media_entity_cleanup(&subdev->entity);
xvip_cleanup_resources(&xtpg->xvip);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume);
@@ -923,7 +921,7 @@ static struct platform_driver xtpg_driver = {
.of_match_table = xtpg_of_id_table,
},
.probe = xtpg_probe,
- .remove = xtpg_remove,
+ .remove_new = xtpg_remove,
};
module_platform_driver(xtpg_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 0a16c218a50a..3123216b3f70 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -617,14 +617,12 @@ error:
return ret;
}
-static int xvip_composite_remove(struct platform_device *pdev)
+static void xvip_composite_remove(struct platform_device *pdev)
{
struct xvip_composite_device *xdev = platform_get_drvdata(pdev);
xvip_graph_cleanup(xdev);
xvip_composite_v4l2_cleanup(xdev);
-
- return 0;
}
static const struct of_device_id xvip_composite_of_id_table[] = {
@@ -639,7 +637,7 @@ static struct platform_driver xvip_composite_driver = {
.of_match_table = xvip_composite_of_id_table,
},
.probe = xvip_composite_probe,
- .remove = xvip_composite_remove,
+ .remove_new = xvip_composite_remove,
};
module_platform_driver(xvip_composite_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c
index 0ae0208d7529..dda70719f004 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.c
+++ b/drivers/media/platform/xilinx/xilinx-vtc.c
@@ -254,7 +254,7 @@ struct xvtc_device *xvtc_of_get(struct device_node *np)
struct xvtc_device *found = NULL;
struct xvtc_device *xvtc;
- if (!of_find_property(np, "xlnx,vtc", NULL))
+ if (!of_property_present(np, "xlnx,vtc"))
return NULL;
xvtc_node = of_parse_phandle(np, "xlnx,vtc", 0);
@@ -344,15 +344,13 @@ static int xvtc_probe(struct platform_device *pdev)
return 0;
}
-static int xvtc_remove(struct platform_device *pdev)
+static void xvtc_remove(struct platform_device *pdev)
{
struct xvtc_device *xvtc = platform_get_drvdata(pdev);
xvtc_unregister_device(xvtc);
xvip_cleanup_resources(&xvtc->xvip);
-
- return 0;
}
static const struct of_device_id xvtc_of_id_table[] = {
@@ -367,7 +365,7 @@ static struct platform_driver xvtc_driver = {
.of_match_table = xvtc_of_id_table,
},
.probe = xvtc_probe,
- .remove = xvtc_remove,
+ .remove_new = xvtc_remove,
};
module_platform_driver(xvtc_driver);
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 171f9cc9ee5e..6061506159f1 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1498,7 +1498,7 @@ exit:
return rval;
}
-static int si476x_radio_remove(struct platform_device *pdev)
+static void si476x_radio_remove(struct platform_device *pdev)
{
struct si476x_radio *radio = platform_get_drvdata(pdev);
@@ -1506,8 +1506,6 @@ static int si476x_radio_remove(struct platform_device *pdev)
video_unregister_device(&radio->videodev);
v4l2_device_unregister(&radio->v4l2dev);
debugfs_remove_recursive(radio->debugfs);
-
- return 0;
}
MODULE_ALIAS("platform:si476x-radio");
@@ -1517,7 +1515,7 @@ static struct platform_driver si476x_radio_driver = {
.name = DRIVER_NAME,
},
.probe = si476x_radio_probe,
- .remove = si476x_radio_remove,
+ .remove_new = si476x_radio_remove,
};
module_platform_driver(si476x_radio_driver);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 948ee3eec914..04daa9c358c2 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -151,13 +151,12 @@ err:
return err;
}
-static int timbradio_remove(struct platform_device *pdev)
+static void timbradio_remove(struct platform_device *pdev)
{
struct timbradio *tr = platform_get_drvdata(pdev);
video_unregister_device(&tr->video_dev);
v4l2_device_unregister(&tr->v4l2_dev);
- return 0;
}
static struct platform_driver timbradio_platform_driver = {
@@ -165,7 +164,7 @@ static struct platform_driver timbradio_platform_driver = {
.name = DRIVER_NAME,
},
.probe = timbradio_probe,
- .remove = timbradio_remove,
+ .remove_new = timbradio_remove,
};
module_platform_driver(timbradio_platform_driver);
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 484046471c03..e8166eac9efe 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1977,7 +1977,7 @@ static const struct video_device wl1273_viddev_template = {
V4L2_CAP_RDS_OUTPUT,
};
-static int wl1273_fm_radio_remove(struct platform_device *pdev)
+static void wl1273_fm_radio_remove(struct platform_device *pdev)
{
struct wl1273_device *radio = platform_get_drvdata(pdev);
struct wl1273_core *core = radio->core;
@@ -1990,8 +1990,6 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
v4l2_ctrl_handler_free(&radio->ctrl_handler);
video_unregister_device(&radio->videodev);
v4l2_device_unregister(&radio->v4l2dev);
-
- return 0;
}
static int wl1273_fm_radio_probe(struct platform_device *pdev)
@@ -2147,7 +2145,7 @@ pdata_err:
static struct platform_driver wl1273_fm_radio_driver = {
.probe = wl1273_fm_radio_probe,
- .remove = wl1273_fm_radio_remove,
+ .remove_new = wl1273_fm_radio_remove,
.driver = {
.name = "wl1273_fm_radio",
},
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index 433f9642786d..9fdaed68a962 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -190,7 +190,7 @@ exit:
}
/* radio_si4713_pdriver_remove - remove the device */
-static int radio_si4713_pdriver_remove(struct platform_device *pdev)
+static void radio_si4713_pdriver_remove(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct radio_si4713_device *rsdev;
@@ -198,8 +198,6 @@ static int radio_si4713_pdriver_remove(struct platform_device *pdev)
rsdev = container_of(v4l2_dev, struct radio_si4713_device, v4l2_dev);
video_unregister_device(&rsdev->radio_dev);
v4l2_device_unregister(&rsdev->v4l2_dev);
-
- return 0;
}
static struct platform_driver radio_si4713_pdriver = {
@@ -207,7 +205,7 @@ static struct platform_driver radio_si4713_pdriver = {
.name = "radio-si4713",
},
.probe = radio_si4713_pdriver_probe,
- .remove = radio_si4713_pdriver_remove,
+ .remove_new = radio_si4713_pdriver_remove,
};
module_platform_driver(radio_si4713_pdriver);
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8dbe780dae4e..27f55ea966c6 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -103,6 +103,8 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
rcdev->map_name = RC_MAP_EMPTY;
gpio_dev->rcdev = rcdev;
+ if (of_property_read_bool(np, "wakeup-source"))
+ device_init_wakeup(dev, true);
rc = devm_rc_register_device(dev, rcdev);
if (rc < 0) {
@@ -126,7 +128,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
"gpio-ir-recv-irq", gpio_dev);
}
-static int gpio_ir_recv_remove(struct platform_device *pdev)
+static void gpio_ir_recv_remove(struct platform_device *pdev)
{
struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
struct device *pmdev = gpio_dev->pmdev;
@@ -139,8 +141,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
pm_runtime_put_noidle(pmdev);
pm_runtime_set_suspended(pmdev);
}
-
- return 0;
}
#ifdef CONFIG_PM
@@ -202,7 +202,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
static struct platform_driver gpio_ir_recv_driver = {
.probe = gpio_ir_recv_probe,
- .remove = gpio_ir_recv_remove,
+ .remove_new = gpio_ir_recv_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(gpio_ir_recv_of_match),
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
index 6f8464872033..d87d8e14c556 100644
--- a/drivers/media/rc/img-ir/img-ir-core.c
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -152,7 +152,7 @@ err_probe:
return error;
}
-static int img_ir_remove(struct platform_device *pdev)
+static void img_ir_remove(struct platform_device *pdev)
{
struct img_ir_priv *priv = platform_get_drvdata(pdev);
@@ -164,7 +164,6 @@ static int img_ir_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->clk);
if (!IS_ERR(priv->sys_clk))
clk_disable_unprepare(priv->sys_clk);
- return 0;
}
static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume);
@@ -182,7 +181,7 @@ static struct platform_driver img_ir_driver = {
.pm = &img_ir_pmops,
},
.probe = img_ir_probe,
- .remove = img_ir_remove,
+ .remove_new = img_ir_remove,
};
module_platform_driver(img_ir_driver);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index 4ff954b11dc7..0034f615b466 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -340,13 +340,12 @@ err:
return ret;
}
-static int hix5hd2_ir_remove(struct platform_device *pdev)
+static void hix5hd2_ir_remove(struct platform_device *pdev)
{
struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev);
clk_disable_unprepare(priv->clock);
rc_unregister_device(priv->rdev);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -395,7 +394,7 @@ static struct platform_driver hix5hd2_ir_driver = {
.pm = &hix5hd2_ir_pm_ops,
},
.probe = hix5hd2_ir_probe,
- .remove = hix5hd2_ir_remove,
+ .remove_new = hix5hd2_ir_remove,
};
module_platform_driver(hix5hd2_ir_driver);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index f513ff5caf4e..f19558fdab0c 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_RC_MAP) += \
rc-avertv-303.o \
rc-azurewave-ad-tu700.o \
rc-beelink-gs1.o \
+ rc-beelink-mxiii.o \
rc-behold-columbus.o \
rc-behold.o \
rc-budget-ci-old.o \
@@ -37,6 +38,7 @@ obj-$(CONFIG_RC_MAP) += \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
+ rc-dreambox.o \
rc-dtt200u.o \
rc-dvbsky.o \
rc-dvico-mce.o \
diff --git a/drivers/media/rc/keymaps/rc-beelink-mxiii.c b/drivers/media/rc/keymaps/rc-beelink-mxiii.c
new file mode 100644
index 000000000000..01180cd92205
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-beelink-mxiii.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com>
+ *
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * Keytable for the Beelink Mini MXIII remote control
+ *
+ */
+
+static struct rc_map_table beelink_mxiii[] = {
+ { 0xb2dc, KEY_POWER },
+
+ { 0xb288, KEY_MUTE },
+ { 0xb282, KEY_HOME },
+
+ { 0xb2ca, KEY_UP },
+ { 0xb299, KEY_LEFT },
+ { 0xb2ce, KEY_OK },
+ { 0xb2c1, KEY_RIGHT },
+ { 0xb2d2, KEY_DOWN },
+
+ { 0xb2c5, KEY_MENU },
+ { 0xb29a, KEY_BACK },
+
+ { 0xb281, KEY_VOLUMEDOWN },
+ { 0xb280, KEY_VOLUMEUP },
+};
+
+static struct rc_map_list beelink_mxiii_map = {
+ .map = {
+ .scan = beelink_mxiii,
+ .size = ARRAY_SIZE(beelink_mxiii),
+ .rc_proto = RC_PROTO_NEC,
+ .name = RC_MAP_BEELINK_MXIII,
+ }
+};
+
+static int __init init_rc_map_beelink_mxiii(void)
+{
+ return rc_map_register(&beelink_mxiii_map);
+}
+
+static void __exit exit_rc_map_beelink_mxiii(void)
+{
+ rc_map_unregister(&beelink_mxiii_map);
+}
+
+module_init(init_rc_map_beelink_mxiii)
+module_exit(exit_rc_map_beelink_mxiii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-dreambox.c b/drivers/media/rc/keymaps/rc-dreambox.c
new file mode 100644
index 000000000000..dea024fa3a22
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dreambox.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Emanuel Strobel <emanuel.strobel@yahoo.com>
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * Keytable for Dreambox RC10/RC0 and RC20/RC-BT remote controls
+ *
+ * Keys that are not IR addressable:
+ *
+ * // DREAM switches to STB control mode
+ * // TV switches to TV control mode
+ * // MODE toggles STB/TV/BT control modes
+ *
+ */
+
+static struct rc_map_table dreambox[] = {
+ /* Dreambox RC10/RC0/RCU-BT remote */
+ { 0x3200, KEY_POWER },
+
+ // DREAM
+ { 0x3290, KEY_HELP },
+ // TV
+
+ { 0x3201, KEY_1 },
+ { 0x3202, KEY_2 },
+ { 0x3203, KEY_3 },
+ { 0x3204, KEY_4 },
+ { 0x3205, KEY_5 },
+ { 0x3206, KEY_6 },
+ { 0x3207, KEY_7 },
+ { 0x3208, KEY_8 },
+ { 0x3209, KEY_9 },
+ { 0x320a, KEY_PREVIOUS },
+ { 0x320b, KEY_0 },
+ { 0x320c, KEY_NEXT },
+
+ { 0x321f, KEY_RED },
+ { 0x3220, KEY_GREEN },
+ { 0x3221, KEY_YELLOW },
+ { 0x3222, KEY_BLUE },
+
+ { 0x3210, KEY_INFO },
+ { 0x3212, KEY_MENU },
+ { 0x320e, KEY_AUDIO },
+ { 0x3218, KEY_PVR },
+
+ { 0x3213, KEY_LEFT },
+ { 0x3211, KEY_UP },
+ { 0x3215, KEY_RIGHT },
+ { 0x3217, KEY_DOWN },
+ { 0x3214, KEY_OK },
+
+ { 0x3219, KEY_VOLUMEUP },
+ { 0x321c, KEY_VOLUMEDOWN },
+
+ { 0x321d, KEY_ESC }, // EXIT
+ { 0x321a, KEY_MUTE },
+
+ { 0x321b, KEY_PAGEUP },
+ { 0x321e, KEY_PAGEDOWN },
+
+ { 0x3223, KEY_PREVIOUSSONG },
+ { 0x3224, KEY_PLAYPAUSE },
+ { 0x3225, KEY_STOP },
+ { 0x3226, KEY_NEXTSONG },
+
+ { 0x3227, KEY_TV },
+ { 0x3228, KEY_RADIO },
+ { 0x3229, KEY_TEXT },
+ { 0x322a, KEY_RECORD },
+
+ /* Dreambox RC20/RC-BT */
+ { 0x3407, KEY_MUTE },
+ // MODE
+ { 0x3401, KEY_POWER },
+
+ { 0x3432, KEY_PREVIOUSSONG },
+ { 0x3433, KEY_PLAYPAUSE },
+ { 0x3435, KEY_NEXTSONG },
+
+ { 0x3436, KEY_RECORD },
+ { 0x3434, KEY_STOP },
+ { 0x3425, KEY_TEXT },
+
+ { 0x341f, KEY_RED },
+ { 0x3420, KEY_GREEN },
+ { 0x3421, KEY_YELLOW },
+ { 0x3422, KEY_BLUE },
+
+ { 0x341b, KEY_INFO },
+ { 0x341c, KEY_MENU },
+ { 0x3430, KEY_AUDIO },
+ { 0x3431, KEY_PVR },
+
+ { 0x3414, KEY_LEFT },
+ { 0x3411, KEY_UP },
+ { 0x3416, KEY_RIGHT },
+ { 0x3419, KEY_DOWN },
+ { 0x3415, KEY_OK },
+
+ { 0x3413, KEY_VOLUMEUP },
+ { 0x3418, KEY_VOLUMEDOWN },
+
+ { 0x3412, KEY_ESC }, // EXIT
+ { 0x3426, KEY_HELP }, // MIC
+
+ { 0x3417, KEY_PAGEUP },
+ { 0x341a, KEY_PAGEDOWN },
+
+ { 0x3404, KEY_1 },
+ { 0x3405, KEY_2 },
+ { 0x3406, KEY_3 },
+ { 0x3408, KEY_4 },
+ { 0x3409, KEY_5 },
+ { 0x340a, KEY_6 },
+ { 0x340c, KEY_7 },
+ { 0x340d, KEY_8 },
+ { 0x340e, KEY_9 },
+ { 0x340b, KEY_PREVIOUS },
+ { 0x3410, KEY_0 },
+ { 0x340f, KEY_NEXT },
+};
+
+static struct rc_map_list dreambox_map = {
+ .map = {
+ .scan = dreambox,
+ .size = ARRAY_SIZE(dreambox),
+ .rc_proto = RC_PROTO_NEC,
+ .name = RC_MAP_DREAMBOX,
+ }
+};
+
+static int __init init_rc_map_dreambox(void)
+{
+ return rc_map_register(&dreambox_map);
+}
+
+static void __exit exit_rc_map_dreambox(void)
+{
+ rc_map_unregister(&dreambox_map);
+}
+
+module_init(init_rc_map_dreambox)
+module_exit(exit_rc_map_dreambox)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Emanuel Strobel <emanuel.strobel@yahoo.com>");
diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c
index abdb62b16e98..6355b79893fb 100644
--- a/drivers/media/rc/meson-ir-tx.c
+++ b/drivers/media/rc/meson-ir-tx.c
@@ -372,13 +372,11 @@ static int __init meson_irtx_probe(struct platform_device *pdev)
return 0;
}
-static int meson_irtx_remove(struct platform_device *pdev)
+static void meson_irtx_remove(struct platform_device *pdev)
{
struct rc_dev *rc = platform_get_drvdata(pdev);
rc_unregister_device(rc);
-
- return 0;
}
static const struct of_device_id meson_irtx_dt_match[] = {
@@ -390,7 +388,7 @@ static const struct of_device_id meson_irtx_dt_match[] = {
MODULE_DEVICE_TABLE(of, meson_irtx_dt_match);
static struct platform_driver meson_irtx_pd = {
- .remove = meson_irtx_remove,
+ .remove_new = meson_irtx_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = meson_irtx_dt_match,
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 4b769111f78e..49aa309d1a8c 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -177,7 +177,7 @@ static int meson_ir_probe(struct platform_device *pdev)
return 0;
}
-static int meson_ir_remove(struct platform_device *pdev)
+static void meson_ir_remove(struct platform_device *pdev)
{
struct meson_ir *ir = platform_get_drvdata(pdev);
unsigned long flags;
@@ -186,8 +186,6 @@ static int meson_ir_remove(struct platform_device *pdev)
spin_lock_irqsave(&ir->lock, flags);
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
spin_unlock_irqrestore(&ir->lock, flags);
-
- return 0;
}
static void meson_ir_shutdown(struct platform_device *pdev)
@@ -226,7 +224,7 @@ MODULE_DEVICE_TABLE(of, meson_ir_match);
static struct platform_driver meson_ir_driver = {
.probe = meson_ir_probe,
- .remove = meson_ir_remove,
+ .remove_new = meson_ir_remove,
.shutdown = meson_ir_shutdown,
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
index 27b7412d02a5..df9349330a93 100644
--- a/drivers/media/rc/mtk-cir.c
+++ b/drivers/media/rc/mtk-cir.c
@@ -420,7 +420,7 @@ exit_clkdisable_clk:
return ret;
}
-static int mtk_ir_remove(struct platform_device *pdev)
+static void mtk_ir_remove(struct platform_device *pdev)
{
struct mtk_ir *ir = platform_get_drvdata(pdev);
@@ -434,13 +434,11 @@ static int mtk_ir_remove(struct platform_device *pdev)
clk_disable_unprepare(ir->bus);
clk_disable_unprepare(ir->clk);
-
- return 0;
}
static struct platform_driver mtk_ir_driver = {
.probe = mtk_ir_probe,
- .remove = mtk_ir_remove,
+ .remove_new = mtk_ir_remove,
.driver = {
.name = MTK_IR_DEV,
.of_match_table = mtk_ir_match,
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 19e987a048cc..28477aa95563 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -194,7 +194,7 @@ static int st_rc_hardware_init(struct st_rc_device *dev)
return 0;
}
-static int st_rc_remove(struct platform_device *pdev)
+static void st_rc_remove(struct platform_device *pdev)
{
struct st_rc_device *rc_dev = platform_get_drvdata(pdev);
@@ -202,7 +202,6 @@ static int st_rc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false);
clk_disable_unprepare(rc_dev->sys_clock);
rc_unregister_device(rc_dev->rdev);
- return 0;
}
static int st_rc_open(struct rc_dev *rdev)
@@ -408,7 +407,7 @@ static struct platform_driver st_rc_driver = {
.pm = &st_rc_pm_ops,
},
.probe = st_rc_probe,
- .remove = st_rc_remove,
+ .remove_new = st_rc_remove,
};
module_platform_driver(st_rc_driver);
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index b631a81e58bb..75b7aed1579c 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -364,14 +364,12 @@ exit_free_dev:
return ret;
}
-static int sunxi_ir_remove(struct platform_device *pdev)
+static void sunxi_ir_remove(struct platform_device *pdev)
{
struct sunxi_ir *ir = platform_get_drvdata(pdev);
rc_unregister_device(ir->rc);
sunxi_ir_hw_exit(&pdev->dev);
-
- return 0;
}
static void sunxi_ir_shutdown(struct platform_device *pdev)
@@ -413,7 +411,7 @@ MODULE_DEVICE_TABLE(of, sunxi_ir_match);
static struct platform_driver sunxi_ir_driver = {
.probe = sunxi_ir_probe,
- .remove = sunxi_ir_remove,
+ .remove_new = sunxi_ir_remove,
.shutdown = sunxi_ir_shutdown,
.driver = {
.name = SUNXI_IR_DEV,
diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c
index 1d1bee111732..6f0e20df74e9 100644
--- a/drivers/media/test-drivers/vicodec/vicodec-core.c
+++ b/drivers/media/test-drivers/vicodec/vicodec-core.c
@@ -2179,7 +2179,7 @@ free_dev:
return ret;
}
-static int vicodec_remove(struct platform_device *pdev)
+static void vicodec_remove(struct platform_device *pdev)
{
struct vicodec_dev *dev = platform_get_drvdata(pdev);
@@ -2196,13 +2196,11 @@ static int vicodec_remove(struct platform_device *pdev)
video_unregister_device(&dev->stateful_dec.vfd);
video_unregister_device(&dev->stateless_dec.vfd);
v4l2_device_put(&dev->v4l2_dev);
-
- return 0;
}
static struct platform_driver vicodec_pdrv = {
.probe = vicodec_probe,
- .remove = vicodec_remove,
+ .remove_new = vicodec_remove,
.driver = {
.name = VICODEC_NAME,
},
diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
index dff7265a42ca..8b04e12af286 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
@@ -528,7 +528,7 @@ err_dvb:
return ret;
}
-static int vidtv_bridge_remove(struct platform_device *pdev)
+static void vidtv_bridge_remove(struct platform_device *pdev)
{
struct vidtv_dvb *dvb;
u32 i;
@@ -552,8 +552,6 @@ static int vidtv_bridge_remove(struct platform_device *pdev)
dvb_dmx_release(&dvb->demux);
dvb_unregister_adapter(&dvb->adapter);
dev_info(&pdev->dev, "Successfully removed vidtv\n");
-
- return 0;
}
static void vidtv_bridge_dev_release(struct device *dev)
@@ -574,7 +572,7 @@ static struct platform_driver vidtv_bridge_driver = {
.name = VIDTV_PDEV_NAME,
},
.probe = vidtv_bridge_probe,
- .remove = vidtv_bridge_remove,
+ .remove_new = vidtv_bridge_remove,
};
static void __exit vidtv_bridge_exit(void)
diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c
index 7964426bf2f7..3e3b424b4860 100644
--- a/drivers/media/test-drivers/vim2m.c
+++ b/drivers/media/test-drivers/vim2m.c
@@ -1379,7 +1379,7 @@ error_free:
return ret;
}
-static int vim2m_remove(struct platform_device *pdev)
+static void vim2m_remove(struct platform_device *pdev)
{
struct vim2m_dev *dev = platform_get_drvdata(pdev);
@@ -1390,13 +1390,11 @@ static int vim2m_remove(struct platform_device *pdev)
v4l2_m2m_unregister_media_controller(dev->m2m_dev);
#endif
video_unregister_device(&dev->vfd);
-
- return 0;
}
static struct platform_driver vim2m_pdrv = {
.probe = vim2m_probe,
- .remove = vim2m_remove,
+ .remove_new = vim2m_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/test-drivers/vimc/vimc-common.c b/drivers/media/test-drivers/vimc/vimc-common.c
index 7b27153c0728..2e72974e35b4 100644
--- a/drivers/media/test-drivers/vimc/vimc-common.c
+++ b/drivers/media/test-drivers/vimc/vimc-common.c
@@ -241,13 +241,13 @@ static int vimc_get_pix_format(struct media_pad *pad,
if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
- struct v4l2_subdev_format sd_fmt;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = pad->index,
+ };
const struct vimc_pix_map *pix_map;
int ret;
- sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sd_fmt.pad = pad->index;
-
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
if (ret)
return ret;
diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
index e82cfa5ffbf4..af127476e920 100644
--- a/drivers/media/test-drivers/vimc/vimc-core.c
+++ b/drivers/media/test-drivers/vimc/vimc-core.c
@@ -387,7 +387,7 @@ static int vimc_probe(struct platform_device *pdev)
return 0;
}
-static int vimc_remove(struct platform_device *pdev)
+static void vimc_remove(struct platform_device *pdev)
{
struct vimc_device *vimc = platform_get_drvdata(pdev);
@@ -397,8 +397,6 @@ static int vimc_remove(struct platform_device *pdev)
media_device_unregister(&vimc->mdev);
v4l2_device_unregister(&vimc->v4l2_dev);
v4l2_device_put(&vimc->v4l2_dev);
-
- return 0;
}
static void vimc_dev_release(struct device *dev)
@@ -412,7 +410,7 @@ static struct platform_device vimc_pdev = {
static struct platform_driver vimc_pdrv = {
.probe = vimc_probe,
- .remove = vimc_remove,
+ .remove_new = vimc_remove,
.driver = {
.name = VIMC_PDEV_NAME,
},
diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
index 9cb60ab653bf..9970dc739ca5 100644
--- a/drivers/media/test-drivers/visl/visl-core.c
+++ b/drivers/media/test-drivers/visl/visl-core.c
@@ -480,7 +480,7 @@ error_visl_dev:
return ret;
}
-static int visl_remove(struct platform_device *pdev)
+static void visl_remove(struct platform_device *pdev)
{
struct visl_dev *dev = platform_get_drvdata(pdev);
@@ -493,13 +493,11 @@ static int visl_remove(struct platform_device *pdev)
}
#endif
video_unregister_device(&dev->vfd);
-
- return 0;
}
static struct platform_driver visl_pdrv = {
.probe = visl_probe,
- .remove = visl_remove,
+ .remove_new = visl_remove,
.driver = {
.name = VISL_NAME,
},
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index f28440e6c9f8..c2167ccfd222 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -126,7 +126,7 @@ MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the
"\t\t bit 8: Video Output node\n"
"\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 12: Radio Transmitter node\n"
- "\t\t bit 16: Framebuffer for testing overlays\n"
+ "\t\t bit 16: Framebuffer for testing output overlays\n"
"\t\t bit 17: Metadata Capture node\n"
"\t\t bit 18: Metadata Output node\n"
"\t\t bit 19: Touch Capture node\n");
@@ -326,7 +326,7 @@ static int vidioc_overlay(struct file *file, void *fh, unsigned i)
struct video_device *vdev = video_devdata(file);
if (vdev->vfl_dir == VFL_DIR_RX)
- return vivid_vid_cap_overlay(file, fh, i);
+ return -ENOTTY;
return vivid_vid_out_overlay(file, fh, i);
}
@@ -335,38 +335,16 @@ static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a
struct video_device *vdev = video_devdata(file);
if (vdev->vfl_dir == VFL_DIR_RX)
- return vivid_vid_cap_g_fbuf(file, fh, a);
+ return -ENOTTY;
return vivid_vid_out_g_fbuf(file, fh, a);
}
-/*
- * Only support the framebuffer of one of the vivid instances.
- * Anything else is rejected.
- */
-bool vivid_validate_fb(const struct v4l2_framebuffer *a)
-{
- struct vivid_dev *dev;
- int i;
-
- for (i = 0; i < n_devs; i++) {
- dev = vivid_devs[i];
- if (!dev || !dev->video_pbase)
- continue;
- if ((unsigned long)a->base == dev->video_pbase &&
- a->fmt.width <= dev->display_width &&
- a->fmt.height <= dev->display_height &&
- a->fmt.bytesperline <= dev->display_byte_stride)
- return true;
- }
- return false;
-}
-
static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
{
struct video_device *vdev = video_devdata(file);
if (vdev->vfl_dir == VFL_DIR_RX)
- return vivid_vid_cap_s_fbuf(file, fh, a);
+ return -ENOTTY;
return vivid_vid_out_s_fbuf(file, fh, a);
}
@@ -651,8 +629,6 @@ static int vivid_fop_release(struct file *file)
vivid_reconnect(dev);
}
mutex_unlock(&dev->mutex);
- if (file->private_data == dev->overlay_cap_owner)
- dev->overlay_cap_owner = NULL;
if (file->private_data == dev->radio_rx_rds_owner) {
dev->radio_rx_rds_last_block = 0;
dev->radio_rx_rds_owner = NULL;
@@ -778,10 +754,6 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
- .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
- .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
- .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
- .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
.vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_out_overlay,
.vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay,
.vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_out_overlay,
@@ -862,8 +834,6 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev)
vfree(dev->scaled_line);
vfree(dev->blended_line);
vfree(dev->edid);
- vfree(dev->bitmap_cap);
- vfree(dev->bitmap_out);
tpg_free(&dev->tpg);
kfree(dev->query_dv_timings_qmenu);
kfree(dev->query_dv_timings_qmenu_strings);
@@ -1107,7 +1077,7 @@ static void vivid_set_capabilities(struct vivid_dev *dev)
/* set up the capabilities of the video capture device */
dev->vid_cap_caps = dev->multiplanar ?
V4L2_CAP_VIDEO_CAPTURE_MPLANE :
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY;
+ V4L2_CAP_VIDEO_CAPTURE;
dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
if (dev->has_audio_inputs)
dev->vid_cap_caps |= V4L2_CAP_AUDIO;
@@ -1396,7 +1366,7 @@ static int vivid_create_queues(struct vivid_dev *dev)
}
if (dev->has_fb) {
- /* Create framebuffer for testing capture/output overlay */
+ /* Create framebuffer for testing output overlay */
ret = vivid_fb_init(dev);
if (ret)
return ret;
@@ -1892,13 +1862,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vivid_update_format_cap(dev, false);
vivid_update_format_out(dev);
- /* initialize overlay */
- dev->fb_cap.fmt.width = dev->src_rect.width;
- dev->fb_cap.fmt.height = dev->src_rect.height;
- dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
- dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
- dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
-
/* update touch configuration */
dev->timeperframe_tch_cap.numerator = 1;
dev->timeperframe_tch_cap.denominator = 10;
@@ -2058,7 +2021,7 @@ static int vivid_probe(struct platform_device *pdev)
return ret;
}
-static int vivid_remove(struct platform_device *pdev)
+static void vivid_remove(struct platform_device *pdev)
{
struct vivid_dev *dev;
unsigned int i, j;
@@ -2138,7 +2101,6 @@ static int vivid_remove(struct platform_device *pdev)
v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}
- return 0;
}
static void vivid_pdev_release(struct device *dev)
@@ -2152,7 +2114,7 @@ static struct platform_device vivid_pdev = {
static struct platform_driver vivid_pdrv = {
.probe = vivid_probe,
- .remove = vivid_remove,
+ .remove_new = vivid_remove,
.driver = {
.name = "vivid",
},
diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h
index 473f3598db5a..cfb8e66083f6 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -22,8 +22,6 @@
#define dprintk(dev, level, fmt, arg...) \
v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg)
-/* The maximum number of clip rectangles */
-#define MAX_CLIPS 16
/* The maximum number of inputs */
#define MAX_INPUTS 16
/* The maximum number of outputs */
@@ -345,17 +343,6 @@ struct vivid_dev {
u32 power_present;
- /* Capture Overlay */
- struct v4l2_framebuffer fb_cap;
- struct v4l2_fh *overlay_cap_owner;
- void *fb_vbase_cap;
- int overlay_cap_top, overlay_cap_left;
- enum v4l2_field overlay_cap_field;
- void *bitmap_cap;
- struct v4l2_clip clips_cap[MAX_CLIPS];
- struct v4l2_clip try_clips_cap[MAX_CLIPS];
- unsigned clipcount_cap;
-
/* Output */
unsigned output;
v4l2_std_id std_out;
@@ -383,10 +370,6 @@ struct vivid_dev {
void *fb_vbase_out;
bool overlay_out_enabled;
int overlay_out_top, overlay_out_left;
- void *bitmap_out;
- struct v4l2_clip clips_out[MAX_CLIPS];
- struct v4l2_clip try_clips_out[MAX_CLIPS];
- unsigned clipcount_out;
unsigned fbuf_out_flags;
u32 chromakey_out;
u8 global_alpha_out;
@@ -613,6 +596,4 @@ static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
return dev->output_type[dev->output] == HDMI;
}
-bool vivid_validate_fb(const struct v4l2_framebuffer *a);
-
#endif
diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
index ee65d20314d3..42048727d7ff 100644
--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
@@ -53,31 +53,10 @@ static void copy_pix(struct vivid_dev *dev, int win_y, int win_x,
u16 *cap, const u16 *osd)
{
u16 out;
- int left = dev->overlay_out_left;
- int top = dev->overlay_out_top;
- int fb_x = win_x + left;
- int fb_y = win_y + top;
- int i;
out = *cap;
*cap = *osd;
- if (dev->bitmap_out) {
- const u8 *p = dev->bitmap_out;
- unsigned stride = (dev->compose_out.width + 7) / 8;
- win_x -= dev->compose_out.left;
- win_y -= dev->compose_out.top;
- if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
- return;
- }
-
- for (i = 0; i < dev->clipcount_out; i++) {
- struct v4l2_rect *r = &dev->clips_out[i].c;
-
- if (fb_y >= r->top && fb_y < r->top + r->height &&
- fb_x >= r->left && fb_x < r->left + r->width)
- return;
- }
if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
*osd != dev->chromakey_out)
return;
@@ -251,7 +230,7 @@ static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned
u8 *voutbuf;
u8 *vosdbuf = NULL;
unsigned y;
- bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags;
+ bool blend = dev->fbuf_out_flags;
/* Coarse scaling with Bresenham */
unsigned vid_out_int_part;
unsigned vid_out_fract_part;
@@ -554,109 +533,6 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
}
}
-/*
- * Return true if this pixel coordinate is a valid video pixel.
- */
-static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x)
-{
- int i;
-
- if (dev->bitmap_cap) {
- /*
- * Only if the corresponding bit in the bitmap is set can
- * the video pixel be shown. Coordinates are relative to
- * the overlay window set by VIDIOC_S_FMT.
- */
- const u8 *p = dev->bitmap_cap;
- unsigned stride = (dev->compose_cap.width + 7) / 8;
-
- if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
- return false;
- }
-
- for (i = 0; i < dev->clipcount_cap; i++) {
- /*
- * Only if the framebuffer coordinate is not in any of the
- * clip rectangles will be video pixel be shown.
- */
- struct v4l2_rect *r = &dev->clips_cap[i].c;
-
- if (fb_y >= r->top && fb_y < r->top + r->height &&
- fb_x >= r->left && fb_x < r->left + r->width)
- return false;
- }
- return true;
-}
-
-/*
- * Draw the image into the overlay buffer.
- * Note that the combination of overlay and multiplanar is not supported.
- */
-static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
-{
- struct tpg_data *tpg = &dev->tpg;
- unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2;
- void *vbase = dev->fb_vbase_cap;
- void *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
- unsigned img_width = dev->compose_cap.width;
- unsigned img_height = dev->compose_cap.height;
- unsigned stride = tpg->bytesperline[0];
- /* if quick is true, then valid_pix() doesn't have to be called */
- bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
- int x, y, w, out_x = 0;
-
- /*
- * Overlay support is only supported for formats that have a twopixelsize
- * that's >= 2. Warn and bail out if that's not the case.
- */
- if (WARN_ON(pixsize == 0))
- return;
- if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
- dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
- dev->overlay_cap_field != buf->vb.field)
- return;
-
- vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride;
- x = dev->overlay_cap_left;
- w = img_width;
- if (x < 0) {
- out_x = -x;
- w = w - out_x;
- x = 0;
- } else {
- w = dev->fb_cap.fmt.width - x;
- if (w > img_width)
- w = img_width;
- }
- if (w <= 0)
- return;
- if (dev->overlay_cap_top >= 0)
- vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline;
- for (y = dev->overlay_cap_top;
- y < dev->overlay_cap_top + (int)img_height;
- y++, vbuf += stride) {
- int px;
-
- if (y < 0 || y > dev->fb_cap.fmt.height)
- continue;
- if (quick) {
- memcpy(vbase + x * pixsize,
- vbuf + out_x * pixsize, w * pixsize);
- vbase += dev->fb_cap.fmt.bytesperline;
- continue;
- }
- for (px = 0; px < w; px++) {
- if (!valid_pix(dev, y - dev->overlay_cap_top,
- px + out_x, y, px + x))
- continue;
- memcpy(vbase + (px + x) * pixsize,
- vbuf + (px + out_x) * pixsize,
- pixsize);
- }
- vbase += dev->fb_cap.fmt.bytesperline;
- }
-}
-
static void vivid_cap_update_frame_period(struct vivid_dev *dev)
{
u64 f_period;
@@ -730,11 +606,6 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
dprintk(dev, 1, "filled buffer %d\n",
vid_cap_buf->vb.vb2_buf.index);
- /* Handle overlay */
- if (dev->overlay_cap_owner && dev->fb_cap.base &&
- dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc)
- vivid_overlay(dev, vid_cap_buf);
-
v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_vid_cap);
vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index c0999581c599..801286dc1448 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -21,30 +21,6 @@
#include "vivid-kthread-cap.h"
#include "vivid-vid-cap.h"
-static const struct vivid_fmt formats_ovl[] = {
- {
- .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .vdownsampling = { 1 },
- .bit_depth = { 16 },
- .planes = 1,
- .buffers = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
- .vdownsampling = { 1 },
- .bit_depth = { 16 },
- .planes = 1,
- .buffers = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
- .vdownsampling = { 1 },
- .bit_depth = { 16 },
- .planes = 1,
- .buffers = 1,
- },
-};
-
/* The number of discrete webcam framesizes */
#define VIVID_WEBCAM_SIZES 6
/* The number of discrete webcam frameintervals */
@@ -447,18 +423,10 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
break;
}
- vfree(dev->bitmap_cap);
- dev->bitmap_cap = NULL;
vivid_update_quality(dev);
tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
dev->crop_cap = dev->src_rect;
dev->crop_bounds_cap = dev->src_rect;
- if (dev->bitmap_cap &&
- (dev->compose_cap.width != dev->crop_cap.width ||
- dev->compose_cap.height != dev->crop_cap.height)) {
- vfree(dev->bitmap_cap);
- dev->bitmap_cap = NULL;
- }
dev->compose_cap = dev->crop_cap;
if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
dev->compose_cap.height /= 2;
@@ -701,11 +669,6 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
return -EBUSY;
}
- if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) {
- dprintk(dev, 1, "overlay is active, can't change pixelformat\n");
- return -EBUSY;
- }
-
dev->fmt_cap = vivid_get_format(dev, mp->pixelformat);
if (V4L2_FIELD_HAS_T_OR_B(mp->field))
factor = 2;
@@ -927,8 +890,6 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
struct vivid_dev *dev = video_drvdata(file);
struct v4l2_rect *crop = &dev->crop_cap;
struct v4l2_rect *compose = &dev->compose_cap;
- unsigned orig_compose_w = compose->width;
- unsigned orig_compose_h = compose->height;
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
int ret;
@@ -1052,11 +1013,6 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
return -EINVAL;
}
- if (dev->bitmap_cap && (compose->width != orig_compose_w ||
- compose->height != orig_compose_h)) {
- vfree(dev->bitmap_cap);
- dev->bitmap_cap = NULL;
- }
tpg_s_crop_compose(&dev->tpg, crop, compose);
return 0;
}
@@ -1084,234 +1040,6 @@ int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv,
return 0;
}
-int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
- const struct vivid_fmt *fmt;
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- if (f->index >= ARRAY_SIZE(formats_ovl))
- return -EINVAL;
-
- fmt = &formats_ovl[f->index];
-
- f->pixelformat = fmt->fourcc;
- return 0;
-}
-
-int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
- const struct v4l2_rect *compose = &dev->compose_cap;
- struct v4l2_window *win = &f->fmt.win;
- unsigned clipcount = win->clipcount;
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- win->w.top = dev->overlay_cap_top;
- win->w.left = dev->overlay_cap_left;
- win->w.width = compose->width;
- win->w.height = compose->height;
- win->field = dev->overlay_cap_field;
- win->clipcount = dev->clipcount_cap;
- if (clipcount > dev->clipcount_cap)
- clipcount = dev->clipcount_cap;
- if (dev->bitmap_cap == NULL)
- win->bitmap = NULL;
- else if (win->bitmap) {
- if (copy_to_user(win->bitmap, dev->bitmap_cap,
- ((compose->width + 7) / 8) * compose->height))
- return -EFAULT;
- }
- if (clipcount && win->clips)
- memcpy(win->clips, dev->clips_cap,
- clipcount * sizeof(dev->clips_cap[0]));
- return 0;
-}
-
-int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
- const struct v4l2_rect *compose = &dev->compose_cap;
- struct v4l2_window *win = &f->fmt.win;
- int i, j;
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- win->w.left = clamp_t(int, win->w.left,
- -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
- win->w.top = clamp_t(int, win->w.top,
- -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
- win->w.width = compose->width;
- win->w.height = compose->height;
- if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP)
- win->field = V4L2_FIELD_ANY;
- win->chromakey = 0;
- win->global_alpha = 0;
- if (win->clipcount && !win->clips)
- win->clipcount = 0;
- if (win->clipcount > MAX_CLIPS)
- win->clipcount = MAX_CLIPS;
- if (win->clipcount) {
- memcpy(dev->try_clips_cap, win->clips,
- win->clipcount * sizeof(dev->clips_cap[0]));
- for (i = 0; i < win->clipcount; i++) {
- struct v4l2_rect *r = &dev->try_clips_cap[i].c;
-
- r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1);
- r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top);
- r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1);
- r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left);
- }
- /*
- * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
- * number and it's typically a one-time deal.
- */
- for (i = 0; i < win->clipcount - 1; i++) {
- struct v4l2_rect *r1 = &dev->try_clips_cap[i].c;
-
- for (j = i + 1; j < win->clipcount; j++) {
- struct v4l2_rect *r2 = &dev->try_clips_cap[j].c;
-
- if (v4l2_rect_overlap(r1, r2))
- return -EINVAL;
- }
- }
- memcpy(win->clips, dev->try_clips_cap,
- win->clipcount * sizeof(dev->clips_cap[0]));
- }
- return 0;
-}
-
-int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
- const struct v4l2_rect *compose = &dev->compose_cap;
- struct v4l2_window *win = &f->fmt.win;
- int ret = vidioc_try_fmt_vid_overlay(file, priv, f);
- unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
- unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]);
- void *new_bitmap = NULL;
-
- if (ret)
- return ret;
-
- if (win->bitmap) {
- new_bitmap = vzalloc(bitmap_size);
-
- if (new_bitmap == NULL)
- return -ENOMEM;
- if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
- vfree(new_bitmap);
- return -EFAULT;
- }
- }
-
- dev->overlay_cap_top = win->w.top;
- dev->overlay_cap_left = win->w.left;
- dev->overlay_cap_field = win->field;
- vfree(dev->bitmap_cap);
- dev->bitmap_cap = new_bitmap;
- dev->clipcount_cap = win->clipcount;
- if (dev->clipcount_cap)
- memcpy(dev->clips_cap, dev->try_clips_cap, clips_size);
- return 0;
-}
-
-int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
-{
- struct vivid_dev *dev = video_drvdata(file);
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- if (i && dev->fb_vbase_cap == NULL)
- return -EINVAL;
-
- if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) {
- dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n");
- return -EINVAL;
- }
-
- if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh)
- return -EBUSY;
- dev->overlay_cap_owner = i ? fh : NULL;
- return 0;
-}
-
-int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
- struct v4l2_framebuffer *a)
-{
- struct vivid_dev *dev = video_drvdata(file);
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- *a = dev->fb_cap;
- a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
- V4L2_FBUF_CAP_LIST_CLIPPING;
- a->flags = V4L2_FBUF_FLAG_PRIMARY;
- a->fmt.field = V4L2_FIELD_NONE;
- a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
- a->fmt.priv = 0;
- return 0;
-}
-
-int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
- const struct v4l2_framebuffer *a)
-{
- struct vivid_dev *dev = video_drvdata(file);
- const struct vivid_fmt *fmt;
-
- if (dev->multiplanar)
- return -ENOTTY;
-
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- if (dev->overlay_cap_owner)
- return -EBUSY;
-
- if (a->base == NULL) {
- dev->fb_cap.base = NULL;
- dev->fb_vbase_cap = NULL;
- return 0;
- }
-
- if (a->fmt.width < 48 || a->fmt.height < 32)
- return -EINVAL;
- fmt = vivid_get_format(dev, a->fmt.pixelformat);
- if (!fmt || !fmt->can_do_overlay)
- return -EINVAL;
- if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8)
- return -EINVAL;
- if (a->fmt.bytesperline > a->fmt.sizeimage / a->fmt.height)
- return -EINVAL;
-
- /*
- * Only support the framebuffer of one of the vivid instances.
- * Anything else is rejected.
- */
- if (!vivid_validate_fb(a))
- return -EINVAL;
-
- dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);
- dev->fb_cap = *a;
- dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left,
- -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
- dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top,
- -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
- return 0;
-}
-
static const struct v4l2_audio vivid_audio_inputs[] = {
{ 0, "TV", V4L2_AUDCAP_STEREO },
{ 1, "Line-In", V4L2_AUDCAP_STEREO },
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
index 1e422a59eeab..949768652d38 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
@@ -33,9 +33,6 @@ int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtd
int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
-int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i);
-int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
-int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp);
int vidioc_g_input(struct file *file, void *priv, unsigned *i);
int vidioc_s_input(struct file *file, void *priv, unsigned i);
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c
index 9f731f085179..184a6df2c29f 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c
@@ -793,11 +793,6 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
}
s->r.top *= factor;
s->r.height *= factor;
- if (dev->bitmap_out && (compose->width != s->r.width ||
- compose->height != s->r.height)) {
- vfree(dev->bitmap_out);
- dev->bitmap_out = NULL;
- }
*compose = s->r;
break;
default:
@@ -836,7 +831,6 @@ int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
struct vivid_dev *dev = video_drvdata(file);
const struct v4l2_rect *compose = &dev->compose_out;
struct v4l2_window *win = &f->fmt.win;
- unsigned clipcount = win->clipcount;
if (!dev->has_fb)
return -EINVAL;
@@ -844,22 +838,9 @@ int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
win->w.left = dev->overlay_out_left;
win->w.width = compose->width;
win->w.height = compose->height;
- win->clipcount = dev->clipcount_out;
win->field = V4L2_FIELD_ANY;
win->chromakey = dev->chromakey_out;
win->global_alpha = dev->global_alpha_out;
- if (clipcount > dev->clipcount_out)
- clipcount = dev->clipcount_out;
- if (dev->bitmap_out == NULL)
- win->bitmap = NULL;
- else if (win->bitmap) {
- if (copy_to_user(win->bitmap, dev->bitmap_out,
- ((dev->compose_out.width + 7) / 8) * dev->compose_out.height))
- return -EFAULT;
- }
- if (clipcount && win->clips)
- memcpy(win->clips, dev->clips_out,
- clipcount * sizeof(dev->clips_out[0]));
return 0;
}
@@ -869,7 +850,6 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
struct vivid_dev *dev = video_drvdata(file);
const struct v4l2_rect *compose = &dev->compose_out;
struct v4l2_window *win = &f->fmt.win;
- int i, j;
if (!dev->has_fb)
return -EINVAL;
@@ -884,38 +864,6 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
* so always set this to ANY.
*/
win->field = V4L2_FIELD_ANY;
- if (win->clipcount && !win->clips)
- win->clipcount = 0;
- if (win->clipcount > MAX_CLIPS)
- win->clipcount = MAX_CLIPS;
- if (win->clipcount) {
- memcpy(dev->try_clips_out, win->clips,
- win->clipcount * sizeof(dev->clips_out[0]));
- for (i = 0; i < win->clipcount; i++) {
- struct v4l2_rect *r = &dev->try_clips_out[i].c;
-
- r->top = clamp_t(s32, r->top, 0, dev->display_height - 1);
- r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top);
- r->left = clamp_t(u32, r->left, 0, dev->display_width - 1);
- r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left);
- }
- /*
- * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
- * number and it's typically a one-time deal.
- */
- for (i = 0; i < win->clipcount - 1; i++) {
- struct v4l2_rect *r1 = &dev->try_clips_out[i].c;
-
- for (j = i + 1; j < win->clipcount; j++) {
- struct v4l2_rect *r2 = &dev->try_clips_out[j].c;
-
- if (v4l2_rect_overlap(r1, r2))
- return -EINVAL;
- }
- }
- memcpy(win->clips, dev->try_clips_out,
- win->clipcount * sizeof(dev->clips_out[0]));
- }
return 0;
}
@@ -923,34 +871,14 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivid_dev *dev = video_drvdata(file);
- const struct v4l2_rect *compose = &dev->compose_out;
struct v4l2_window *win = &f->fmt.win;
int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f);
- unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
- unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]);
- void *new_bitmap = NULL;
if (ret)
return ret;
- if (win->bitmap) {
- new_bitmap = vzalloc(bitmap_size);
-
- if (!new_bitmap)
- return -ENOMEM;
- if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
- vfree(new_bitmap);
- return -EFAULT;
- }
- }
-
dev->overlay_out_top = win->w.top;
dev->overlay_out_left = win->w.left;
- vfree(dev->bitmap_out);
- dev->bitmap_out = new_bitmap;
- dev->clipcount_out = win->clipcount;
- if (dev->clipcount_out)
- memcpy(dev->clips_out, dev->try_clips_out, clips_size);
dev->chromakey_out = win->chromakey;
dev->global_alpha_out = win->global_alpha;
return ret;
@@ -975,8 +903,6 @@ int vivid_vid_out_g_fbuf(struct file *file, void *fh,
struct vivid_dev *dev = video_drvdata(file);
a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
- V4L2_FBUF_CAP_BITMAP_CLIPPING |
- V4L2_FBUF_CAP_LIST_CLIPPING |
V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_SRC_CHROMAKEY |
V4L2_FBUF_CAP_GLOBAL_ALPHA |
diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c
index 7696a28fe407..4d5b1c878028 100644
--- a/drivers/media/tuners/it913x.c
+++ b/drivers/media/tuners/it913x.c
@@ -419,7 +419,7 @@ err:
return ret;
}
-static int it913x_remove(struct platform_device *pdev)
+static void it913x_remove(struct platform_device *pdev)
{
struct it913x_dev *dev = platform_get_drvdata(pdev);
struct dvb_frontend *fe = dev->fe;
@@ -429,8 +429,6 @@ static int it913x_remove(struct platform_device *pdev)
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
kfree(dev);
-
- return 0;
}
static const struct platform_device_id it913x_id_table[] = {
@@ -446,7 +444,7 @@ static struct platform_driver it913x_driver = {
.suppress_bind_attrs = true,
},
.probe = it913x_probe,
- .remove = it913x_remove,
+ .remove_new = it913x_remove,
.id_table = it913x_id_table,
};
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
index 3a509038c8df..06dfab9fb8cb 100644
--- a/drivers/media/tuners/mxl5005s.c
+++ b/drivers/media/tuners/mxl5005s.c
@@ -3423,9 +3423,11 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
- highLimit = 1 << state->Init_Ctrl[i].size;
+ u16 size = min_t(u16, state->Init_Ctrl[i].size,
+ ARRAY_SIZE(state->Init_Ctrl[i].val));
+ highLimit = 1 << size;
if (value < highLimit) {
- for (j = 0; j < state->Init_Ctrl[i].size; j++) {
+ for (j = 0; j < size; j++) {
state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]),
(u8)(state->Init_Ctrl[i].bit[j]),
@@ -3442,9 +3444,11 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
- highLimit = 1 << state->CH_Ctrl[i].size;
+ u16 size = min_t(u16, state->CH_Ctrl[i].size,
+ ARRAY_SIZE(state->CH_Ctrl[i].val));
+ highLimit = 1 << size;
if (value < highLimit) {
- for (j = 0; j < state->CH_Ctrl[i].size; j++) {
+ for (j = 0; j < size; j++) {
state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]),
(u8)(state->CH_Ctrl[i].bit[j]),
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 877e85a451cb..b3a09d3ac7d2 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -211,7 +211,7 @@ static int au0828_media_device_init(struct au0828_dev *dev,
static void au0828_media_graph_notify(struct media_entity *new,
void *notify_data)
{
- struct au0828_dev *dev = (struct au0828_dev *) notify_data;
+ struct au0828_dev *dev = notify_data;
int ret;
struct media_entity *entity, *mixer = NULL, *decoder = NULL;
@@ -627,14 +627,9 @@ static int au0828_media_device_register(struct au0828_dev *dev,
/* register entity_notify callback */
dev->entity_notify.notify_data = (void *) dev;
dev->entity_notify.notify = (void *) au0828_media_graph_notify;
- ret = media_device_register_entity_notify(dev->media_dev,
+ media_device_register_entity_notify(dev->media_dev,
&dev->entity_notify);
- if (ret) {
- dev_err(&udev->dev,
- "Media Device register entity_notify Error: %d\n",
- ret);
- return ret;
- }
+
/* set enable_source */
mutex_lock(&dev->media_dev->graph_mutex);
dev->media_dev->source_priv = (void *) dev;
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 2a8691a0d7fa..09f9948c6f8e 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -273,7 +273,7 @@ static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dev *dev = demux->priv;
struct au0828_dvb *dvb = &dev->dvb;
int ret = 0;
@@ -305,7 +305,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dev *dev = demux->priv;
struct au0828_dvb *dvb = &dev->dvb;
int ret = 0;
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
index e93183ddd797..deba5224cb8d 100644
--- a/drivers/media/usb/dvb-usb/cxusb-analog.c
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -1014,7 +1014,10 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file,
{
struct dvb_usb_device *dvbdev = video_drvdata(file);
struct cxusb_medion_dev *cxdev = dvbdev->priv;
- struct v4l2_subdev_format subfmt;
+ struct v4l2_subdev_format subfmt = {
+ .which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE :
+ V4L2_SUBDEV_FORMAT_TRY,
+ };
u32 field;
int ret;
@@ -1024,9 +1027,6 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file,
field = vb2_start_streaming_called(&cxdev->videoqueue) ?
cxdev->field_order : cxusb_medion_field_order(cxdev);
- memset(&subfmt, 0, sizeof(subfmt));
- subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE :
- V4L2_SUBDEV_FORMAT_TRY;
subfmt.format.width = f->fmt.pix.width & ~1;
subfmt.format.height = f->fmt.pix.height & ~1;
subfmt.format.code = MEDIA_BUS_FMT_FIXED;
@@ -1464,7 +1464,9 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev)
.buf = tuner_analog_msg_data,
.len =
sizeof(tuner_analog_msg_data) };
- struct v4l2_subdev_format subfmt;
+ struct v4l2_subdev_format subfmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
/* switch tuner to analog mode so IF demod will become accessible */
@@ -1507,8 +1509,6 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev)
v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm);
v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
- memset(&subfmt, 0, sizeof(subfmt));
- subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
subfmt.format.width = cxdev->width;
subfmt.format.height = cxdev->height;
subfmt.format.code = MEDIA_BUS_FMT_FIXED;
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index f0794c68c622..da42c989e071 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -26,6 +26,8 @@
#include <media/dvb_ca_en50221.h>
#include "ttpci-eeprom.h"
+#include <linux/etherdevice.h>
+
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig
index f2b64e49c5a2..9501b10b31aa 100644
--- a/drivers/media/usb/pvrusb2/Kconfig
+++ b/drivers/media/usb/pvrusb2/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && DVB_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index 2308c0b4f5e7..1f7620cd2996 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -47,7 +47,7 @@
int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
{
int ret;
- int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
+ int pipe = usb_sndctrlpipe(usbtv->udev, 0);
int i;
for (i = 0; i < size; i++) {
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index d7e9ffc7aa23..b16b5f4cb91e 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -416,7 +416,8 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
/* Unbind all sub-devices in the notifier tree. */
static void
-v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
+v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
+ bool readd)
{
struct v4l2_subdev *sd, *tmp;
@@ -425,9 +426,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
v4l2_async_find_subdev_notifier(sd);
if (subdev_notifier)
- v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
+ v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
+ if (readd)
+ list_add_tail(&sd->asd->list, &notifier->waiting);
v4l2_async_cleanup(sd);
list_move(&sd->async_list, &subdev_list);
@@ -559,7 +562,7 @@ err_unbind:
/*
* On failure, unbind all sub-devices registered through this notifier.
*/
- v4l2_async_nf_unbind_all_subdevs(notifier);
+ v4l2_async_nf_unbind_all_subdevs(notifier, false);
err_unlock:
mutex_unlock(&list_lock);
@@ -609,7 +612,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
return;
- v4l2_async_nf_unbind_all_subdevs(notifier);
+ v4l2_async_nf_unbind_all_subdevs(notifier, false);
notifier->sd = NULL;
notifier->v4l2_dev = NULL;
@@ -807,7 +810,7 @@ err_unbind:
*/
subdev_notifier = v4l2_async_find_subdev_notifier(sd);
if (subdev_notifier)
- v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
+ v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
if (sd->asd)
v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 40f56e044640..3c5ab5ecd678 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -252,12 +252,16 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
/* YUV packed formats */
{ .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_UYVY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
/* YUV planar formats */
{ .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
@@ -267,6 +271,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_P012, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
@@ -292,6 +297,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV21M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_NV16M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_P012M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .hdiv = 2, .vdiv = 2 },
/* Bayer RGB formats */
{ .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 55c26e7d370e..f3bed37859a2 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -38,18 +38,13 @@
* data to the routine.
*/
-struct v4l2_clip32 {
- struct v4l2_rect c;
- compat_caddr_t next;
-};
-
struct v4l2_window32 {
struct v4l2_rect w;
__u32 field; /* enum v4l2_field */
__u32 chromakey;
- compat_caddr_t clips; /* actually struct v4l2_clip32 * */
- __u32 clipcount;
- compat_caddr_t bitmap;
+ compat_caddr_t clips; /* always NULL */
+ __u32 clipcount; /* always 0 */
+ compat_caddr_t bitmap; /* always NULL */
__u8 global_alpha;
};
@@ -65,17 +60,12 @@ static int get_v4l2_window32(struct v4l2_window *p64,
.w = w32.w,
.field = w32.field,
.chromakey = w32.chromakey,
- .clips = (void __force *)compat_ptr(w32.clips),
- .clipcount = w32.clipcount,
- .bitmap = compat_ptr(w32.bitmap),
+ .clips = NULL,
+ .clipcount = 0,
+ .bitmap = NULL,
.global_alpha = w32.global_alpha,
};
- if (p64->clipcount > 2048)
- return -EINVAL;
- if (!p64->clipcount)
- p64->clips = NULL;
-
return 0;
}
@@ -89,16 +79,13 @@ static int put_v4l2_window32(struct v4l2_window *p64,
.w = p64->w,
.field = p64->field,
.chromakey = p64->chromakey,
- .clips = (uintptr_t)p64->clips,
- .clipcount = p64->clipcount,
- .bitmap = ptr_to_compat(p64->bitmap),
+ .clips = 0,
+ .clipcount = 0,
+ .bitmap = 0,
.global_alpha = p64->global_alpha,
};
- /* copy everything except the clips pointer */
- if (copy_to_user(p32, &w32, offsetof(struct v4l2_window32, clips)) ||
- copy_to_user(&p32->clipcount, &w32.clipcount,
- sizeof(w32) - offsetof(struct v4l2_window32, clipcount)))
+ if (copy_to_user(p32, &w32, sizeof(w32)))
return -EFAULT;
return 0;
@@ -600,14 +587,11 @@ struct v4l2_framebuffer32 {
static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
struct v4l2_framebuffer32 __user *p32)
{
- compat_caddr_t tmp;
-
- if (get_user(tmp, &p32->base) ||
- get_user(p64->capability, &p32->capability) ||
+ if (get_user(p64->capability, &p32->capability) ||
get_user(p64->flags, &p32->flags) ||
copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
return -EFAULT;
- p64->base = (void __force *)compat_ptr(tmp);
+ p64->base = NULL;
return 0;
}
@@ -1043,29 +1027,6 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf,
memset(mbuf, 0, array_size);
switch (cmd) {
- case VIDIOC_G_FMT32:
- case VIDIOC_S_FMT32:
- case VIDIOC_TRY_FMT32: {
- struct v4l2_format *f64 = arg;
- struct v4l2_clip *c64 = mbuf;
- struct v4l2_clip32 __user *c32 = user_ptr;
- u32 clipcount = f64->fmt.win.clipcount;
-
- if ((f64->type != V4L2_BUF_TYPE_VIDEO_OVERLAY &&
- f64->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ||
- clipcount == 0)
- return 0;
- if (clipcount > 2048)
- return -EINVAL;
- while (clipcount--) {
- if (copy_from_user(c64, c32, sizeof(c64->c)))
- return -EFAULT;
- c64->next = NULL;
- c64++;
- c32++;
- }
- break;
- }
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
@@ -1136,28 +1097,6 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr,
int err = 0;
switch (cmd) {
- case VIDIOC_G_FMT32:
- case VIDIOC_S_FMT32:
- case VIDIOC_TRY_FMT32: {
- struct v4l2_format *f64 = arg;
- struct v4l2_clip *c64 = mbuf;
- struct v4l2_clip32 __user *c32 = user_ptr;
- u32 clipcount = f64->fmt.win.clipcount;
-
- if ((f64->type != V4L2_BUF_TYPE_VIDEO_OVERLAY &&
- f64->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ||
- clipcount == 0)
- return 0;
- if (clipcount > 2048)
- return -EINVAL;
- while (clipcount--) {
- if (copy_to_user(c32, c64, sizeof(c64->c)))
- return -EFAULT;
- c64++;
- c32++;
- }
- break;
- }
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 397d553177fa..f81279492682 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -556,6 +556,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
bool is_io_mc = vdev->device_caps & V4L2_CAP_IO_MC;
+ bool has_streaming = vdev->device_caps & V4L2_CAP_STREAMING;
bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
@@ -708,8 +709,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_out);
}
- if (is_vid || is_vbi || is_sdr || is_tch || is_meta) {
- /* ioctls valid for video, vbi, sdr, touch and metadata */
+ if (has_streaming) {
+ /* ioctls valid for streaming I/O */
SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 87f163a89c80..a858acea6547 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -310,14 +310,10 @@ static void v4l_print_format(const void *arg, bool write_only)
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
win = &p->fmt.win;
- /* Note: we can't print the clip list here since the clips
- * pointer is a userspace pointer, not a kernelspace
- * pointer. */
- pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, chromakey=0x%08x, clipcount=%u, clips=%p, bitmap=%p, global_alpha=0x%02x\n",
+ pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, chromakey=0x%08x, global_alpha=0x%02x\n",
win->w.width, win->w.height, win->w.left, win->w.top,
prt_names(win->field, v4l2_field_names),
- win->chromakey, win->clipcount, win->clips,
- win->bitmap, win->global_alpha);
+ win->chromakey, win->global_alpha);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
@@ -1302,11 +1298,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_RGBX1010102: descr = "32-bit RGBX 10-10-10-2"; break;
case V4L2_PIX_FMT_RGBA1010102: descr = "32-bit RGBA 10-10-10-2"; break;
case V4L2_PIX_FMT_ARGB2101010: descr = "32-bit ARGB 2-10-10-10"; break;
+ case V4L2_PIX_FMT_BGR48_12: descr = "12-bit Depth BGR"; break;
+ case V4L2_PIX_FMT_ABGR64_12: descr = "12-bit Depth BGRA"; break;
case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break;
case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break;
case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break;
case V4L2_PIX_FMT_Y10: descr = "10-bit Greyscale"; break;
case V4L2_PIX_FMT_Y12: descr = "12-bit Greyscale"; break;
+ case V4L2_PIX_FMT_Y012: descr = "12-bit Greyscale (bits 15-4)"; break;
case V4L2_PIX_FMT_Y14: descr = "14-bit Greyscale"; break;
case V4L2_PIX_FMT_Y16: descr = "16-bit Greyscale"; break;
case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break;
@@ -1345,6 +1344,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break;
case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break;
case V4L2_PIX_FMT_M420: descr = "YUV 4:2:0 (M420)"; break;
+ case V4L2_PIX_FMT_YUV48_12: descr = "12-bit YUV 4:4:4 Packed"; break;
case V4L2_PIX_FMT_NV12: descr = "Y/UV 4:2:0"; break;
case V4L2_PIX_FMT_NV21: descr = "Y/VU 4:2:0"; break;
case V4L2_PIX_FMT_NV16: descr = "Y/UV 4:2:2"; break;
@@ -1352,6 +1352,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV24: descr = "Y/UV 4:4:4"; break;
case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break;
case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_P012: descr = "12-bit Y/UV 4:2:0"; break;
case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break;
case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break;
@@ -1362,6 +1363,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV61M: descr = "Y/VU 4:2:2 (N-C)"; break;
case V4L2_PIX_FMT_NV12MT: descr = "Y/UV 4:2:0 (64x32 MB, N-C)"; break;
case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/UV 4:2:0 (16x16 MB, N-C)"; break;
+ case V4L2_PIX_FMT_P012M: descr = "12-bit Y/UV 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YUV420M: descr = "Planar YUV 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YVU420M: descr = "Planar YVU 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_YUV422M: descr = "Planar YUV 4:2:2 (N-C)"; break;
@@ -1479,6 +1481,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break;
case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */
case V4L2_PIX_FMT_FWHT_STATELESS: descr = "FWHT Stateless"; break; /* used in vicodec */
+ case V4L2_PIX_FMT_SPK: descr = "Sorenson Spark"; break;
+ case V4L2_PIX_FMT_RV30: descr = "RealVideo 8"; break;
+ case V4L2_PIX_FMT_RV40: descr = "RealVideo 9 & 10"; break;
case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break;
case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break;
case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break;
@@ -1618,29 +1623,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- /*
- * fmt can't be cleared for these overlay types due to the 'clips'
- * 'clipcount' and 'bitmap' pointers in struct v4l2_window.
- * Those are provided by the user. So handle these two overlay types
- * first, and then just do a simple memset for the other types.
- */
- switch (p->type) {
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
- struct v4l2_clip *clips = p->fmt.win.clips;
- u32 clipcount = p->fmt.win.clipcount;
- void __user *bitmap = p->fmt.win.bitmap;
-
- memset(&p->fmt, 0, sizeof(p->fmt));
- p->fmt.win.clips = clips;
- p->fmt.win.clipcount = clipcount;
- p->fmt.win.bitmap = bitmap;
- break;
- }
- default:
- memset(&p->fmt, 0, sizeof(p->fmt));
- break;
- }
+ memset(&p->fmt, 0, sizeof(p->fmt));
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1728,6 +1711,9 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
break;
memset_after(p, 0, fmt.win);
+ p->fmt.win.clips = NULL;
+ p->fmt.win.clipcount = 0;
+ p->fmt.win.bitmap = NULL;
return ops->vidioc_s_fmt_vid_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
@@ -1759,6 +1745,9 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
break;
memset_after(p, 0, fmt.win);
+ p->fmt.win.clips = NULL;
+ p->fmt.win.clipcount = 0;
+ p->fmt.win.bitmap = NULL;
return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_OUTPUT:
if (unlikely(!ops->vidioc_s_fmt_vbi_out))
@@ -1830,6 +1819,9 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
break;
memset_after(p, 0, fmt.win);
+ p->fmt.win.clips = NULL;
+ p->fmt.win.clipcount = 0;
+ p->fmt.win.bitmap = NULL;
return ops->vidioc_try_fmt_vid_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
@@ -1861,6 +1853,9 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
break;
memset_after(p, 0, fmt.win);
+ p->fmt.win.clips = NULL;
+ p->fmt.win.clipcount = 0;
+ p->fmt.win.bitmap = NULL;
return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg);
case V4L2_BUF_TYPE_VBI_OUTPUT:
if (unlikely(!ops->vidioc_try_fmt_vbi_out))
@@ -2074,6 +2069,15 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops,
return ops->vidioc_s_hw_freq_seek(file, fh, p);
}
+static int v4l_s_fbuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct v4l2_framebuffer *p = arg;
+
+ p->base = NULL;
+ return ops->vidioc_s_fbuf(file, fh, p);
+}
+
static int v4l_overlay(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -2793,7 +2797,6 @@ struct v4l2_ioctl_info {
}
DEFINE_V4L_STUB_FUNC(g_fbuf)
-DEFINE_V4L_STUB_FUNC(s_fbuf)
DEFINE_V4L_STUB_FUNC(expbuf)
DEFINE_V4L_STUB_FUNC(g_std)
DEFINE_V4L_STUB_FUNC(g_audio)
@@ -2827,7 +2830,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),
IOCTL_INFO(VIDIOC_G_FBUF, v4l_stub_g_fbuf, v4l_print_framebuffer, 0),
- IOCTL_INFO(VIDIOC_S_FBUF, v4l_stub_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_S_FBUF, v4l_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_EXPBUF, v4l_stub_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)),
@@ -3134,27 +3137,6 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
}
break;
}
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT: {
- struct v4l2_format *fmt = parg;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_OVERLAY &&
- fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
- break;
- if (fmt->fmt.win.clipcount > 2048)
- return -EINVAL;
- if (!fmt->fmt.win.clipcount)
- break;
-
- *user_ptr = (void __user *)fmt->fmt.win.clips;
- *kernel_ptr = (void **)&fmt->fmt.win.clips;
- *array_size = sizeof(struct v4l2_clip)
- * fmt->fmt.win.clipcount;
-
- ret = 1;
- break;
- }
case VIDIOC_SUBDEV_G_ROUTING:
case VIDIOC_SUBDEV_S_ROUTING: {
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index b01474717dca..bf0c18100664 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -313,14 +313,11 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
struct media_pad *sink, u32 flags)
{
struct fwnode_handle *endpoint;
- struct v4l2_subdev *sink_sd;
if (!(sink->flags & MEDIA_PAD_FL_SINK) ||
!is_media_entity_v4l2_subdev(sink->entity))
return -EINVAL;
- sink_sd = media_entity_to_v4l2_subdev(sink->entity);
-
fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
struct fwnode_handle *remote_ep;
int src_idx, sink_idx, ret;
@@ -340,7 +337,7 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
* ask the sink to verify it owns the remote endpoint,
* and translate to a sink pad.
*/
- sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity,
+ sink_idx = media_entity_get_fwnode_pad(sink->entity,
remote_ep,
MEDIA_PAD_FL_SINK);
fwnode_handle_put(remote_ep);
@@ -362,17 +359,17 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
if (media_entity_find_link(src, sink))
continue;
- dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n",
+ dev_dbg(src_sd->dev, "creating link %s:%d -> %s:%d\n",
src_sd->entity.name, src_idx,
- sink_sd->entity.name, sink_idx);
+ sink->entity->name, sink_idx);
ret = media_create_pad_link(&src_sd->entity, src_idx,
- &sink_sd->entity, sink_idx, flags);
+ sink->entity, sink_idx, flags);
if (ret) {
- dev_err(sink_sd->dev,
+ dev_err(src_sd->dev,
"link %s:%d -> %s:%d failed with %d\n",
src_sd->entity.name, src_idx,
- sink_sd->entity.name, sink_idx, ret);
+ sink->entity->name, sink_idx, ret);
fwnode_handle_put(endpoint);
return ret;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index b10045c02f43..2ec179cd1264 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -510,8 +510,11 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
+ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
bool streams_subdev = sd->flags & V4L2_SUBDEV_FL_STREAMS;
+ bool client_supports_streams = subdev_fh->client_caps &
+ V4L2_SUBDEV_CLIENT_CAP_STREAMS;
int rval;
switch (cmd) {
@@ -636,6 +639,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_G_FMT: {
struct v4l2_subdev_format *format = arg;
+ if (!client_supports_streams)
+ format->stream = 0;
+
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, get_fmt, state, format);
@@ -647,6 +653,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
if (format->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
return -EPERM;
+ if (!client_supports_streams)
+ format->stream = 0;
+
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, set_fmt, state, format);
@@ -656,6 +665,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
struct v4l2_subdev_crop *crop = arg;
struct v4l2_subdev_selection sel;
+ if (!client_supports_streams)
+ crop->stream = 0;
+
memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
@@ -677,6 +689,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
if (crop->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
return -EPERM;
+ if (!client_supports_streams)
+ crop->stream = 0;
+
memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
@@ -695,6 +710,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_mbus_code_enum *code = arg;
+ if (!client_supports_streams)
+ code->stream = 0;
+
memset(code->reserved, 0, sizeof(code->reserved));
return v4l2_subdev_call(sd, pad, enum_mbus_code, state,
code);
@@ -703,6 +721,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
struct v4l2_subdev_frame_size_enum *fse = arg;
+ if (!client_supports_streams)
+ fse->stream = 0;
+
memset(fse->reserved, 0, sizeof(fse->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_size, state,
fse);
@@ -711,6 +732,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
+ if (!client_supports_streams)
+ fi->stream = 0;
+
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, g_frame_interval, arg);
}
@@ -721,6 +745,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
if (ro_subdev)
return -EPERM;
+ if (!client_supports_streams)
+ fi->stream = 0;
+
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, s_frame_interval, arg);
}
@@ -728,6 +755,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval_enum *fie = arg;
+ if (!client_supports_streams)
+ fie->stream = 0;
+
memset(fie->reserved, 0, sizeof(fie->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_interval, state,
fie);
@@ -736,6 +766,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_G_SELECTION: {
struct v4l2_subdev_selection *sel = arg;
+ if (!client_supports_streams)
+ sel->stream = 0;
+
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, get_selection, state, sel);
@@ -747,6 +780,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
if (sel->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
return -EPERM;
+ if (!client_supports_streams)
+ sel->stream = 0;
+
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, set_selection, state, sel);
@@ -888,6 +924,33 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
routing->which, &krouting);
}
+ case VIDIOC_SUBDEV_G_CLIENT_CAP: {
+ struct v4l2_subdev_client_capability *client_cap = arg;
+
+ client_cap->capabilities = subdev_fh->client_caps;
+
+ return 0;
+ }
+
+ case VIDIOC_SUBDEV_S_CLIENT_CAP: {
+ struct v4l2_subdev_client_capability *client_cap = arg;
+
+ /*
+ * Clear V4L2_SUBDEV_CLIENT_CAP_STREAMS if streams API is not
+ * enabled. Remove this when streams API is no longer
+ * experimental.
+ */
+ if (!v4l2_subdev_enable_streams_api)
+ client_cap->capabilities &= ~V4L2_SUBDEV_CLIENT_CAP_STREAMS;
+
+ /* Filter out unsupported capabilities */
+ client_cap->capabilities &= V4L2_SUBDEV_CLIENT_CAP_STREAMS;
+
+ subdev_fh->client_caps = client_cap->capabilities;
+
+ return 0;
+ }
+
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
@@ -1069,32 +1132,45 @@ EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
static int
v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream,
- struct v4l2_subdev_format *fmt)
+ struct v4l2_subdev_format *fmt,
+ bool states_locked)
{
- if (is_media_entity_v4l2_subdev(pad->entity)) {
- struct v4l2_subdev *sd =
- media_entity_to_v4l2_subdev(pad->entity);
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev *sd;
+ int ret;
- fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt->pad = pad->index;
- fmt->stream = stream;
+ if (!is_media_entity_v4l2_subdev(pad->entity)) {
+ WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
+ "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
+ pad->entity->function, pad->entity->name);
- return v4l2_subdev_call(sd, pad, get_fmt,
- v4l2_subdev_get_locked_active_state(sd),
- fmt);
+ return -EINVAL;
}
- WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
- "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
- pad->entity->function, pad->entity->name);
+ sd = media_entity_to_v4l2_subdev(pad->entity);
- return -EINVAL;
+ fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt->pad = pad->index;
+ fmt->stream = stream;
+
+ if (states_locked)
+ state = v4l2_subdev_get_locked_active_state(sd);
+ else
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ ret = v4l2_subdev_call(sd, pad, get_fmt, state, fmt);
+
+ if (!states_locked && state)
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
}
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static void __v4l2_link_validate_get_streams(struct media_pad *pad,
- u64 *streams_mask)
+ u64 *streams_mask,
+ bool states_locked)
{
struct v4l2_subdev_route *route;
struct v4l2_subdev_state *state;
@@ -1104,7 +1180,11 @@ static void __v4l2_link_validate_get_streams(struct media_pad *pad,
*streams_mask = 0;
- state = v4l2_subdev_get_locked_active_state(subdev);
+ if (states_locked)
+ state = v4l2_subdev_get_locked_active_state(subdev);
+ else
+ state = v4l2_subdev_lock_and_get_active_state(subdev);
+
if (WARN_ON(!state))
return;
@@ -1125,12 +1205,16 @@ static void __v4l2_link_validate_get_streams(struct media_pad *pad,
*streams_mask |= BIT_ULL(route_stream);
}
+
+ if (!states_locked)
+ v4l2_subdev_unlock_state(state);
}
#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
static void v4l2_link_validate_get_streams(struct media_pad *pad,
- u64 *streams_mask)
+ u64 *streams_mask,
+ bool states_locked)
{
struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(pad->entity);
@@ -1141,14 +1225,14 @@ static void v4l2_link_validate_get_streams(struct media_pad *pad,
}
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- __v4l2_link_validate_get_streams(pad, streams_mask);
+ __v4l2_link_validate_get_streams(pad, streams_mask, states_locked);
#else
/* This shouldn't happen */
*streams_mask = 0;
#endif
}
-static int v4l2_subdev_link_validate_locked(struct media_link *link)
+static int v4l2_subdev_link_validate_locked(struct media_link *link, bool states_locked)
{
struct v4l2_subdev *sink_subdev =
media_entity_to_v4l2_subdev(link->sink->entity);
@@ -1163,8 +1247,8 @@ static int v4l2_subdev_link_validate_locked(struct media_link *link)
link->source->entity->name, link->source->index,
link->sink->entity->name, link->sink->index);
- v4l2_link_validate_get_streams(link->source, &source_streams_mask);
- v4l2_link_validate_get_streams(link->sink, &sink_streams_mask);
+ v4l2_link_validate_get_streams(link->source, &source_streams_mask, states_locked);
+ v4l2_link_validate_get_streams(link->sink, &sink_streams_mask, states_locked);
/*
* It is ok to have more source streams than sink streams as extra
@@ -1192,7 +1276,7 @@ static int v4l2_subdev_link_validate_locked(struct media_link *link)
link->sink->entity->name, link->sink->index, stream);
ret = v4l2_subdev_link_validate_get_format(link->source, stream,
- &source_fmt);
+ &source_fmt, states_locked);
if (ret < 0) {
dev_dbg(dev,
"Failed to get format for \"%s\":%u:%u (but that's ok)\n",
@@ -1202,7 +1286,7 @@ static int v4l2_subdev_link_validate_locked(struct media_link *link)
}
ret = v4l2_subdev_link_validate_get_format(link->sink, stream,
- &sink_fmt);
+ &sink_fmt, states_locked);
if (ret < 0) {
dev_dbg(dev,
"Failed to get format for \"%s\":%u:%u (but that's ok)\n",
@@ -1234,27 +1318,38 @@ int v4l2_subdev_link_validate(struct media_link *link)
{
struct v4l2_subdev *source_sd, *sink_sd;
struct v4l2_subdev_state *source_state, *sink_state;
+ bool states_locked;
int ret;
+ if (!is_media_entity_v4l2_subdev(link->sink->entity) ||
+ !is_media_entity_v4l2_subdev(link->source->entity)) {
+ pr_warn_once("%s of link '%s':%u->'%s':%u is not a V4L2 sub-device, driver bug!\n",
+ !is_media_entity_v4l2_subdev(link->sink->entity) ?
+ "sink" : "source",
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index);
+ return 0;
+ }
+
sink_sd = media_entity_to_v4l2_subdev(link->sink->entity);
source_sd = media_entity_to_v4l2_subdev(link->source->entity);
sink_state = v4l2_subdev_get_unlocked_active_state(sink_sd);
source_state = v4l2_subdev_get_unlocked_active_state(source_sd);
- if (sink_state)
- v4l2_subdev_lock_state(sink_state);
+ states_locked = sink_state && source_state;
- if (source_state)
+ if (states_locked) {
+ v4l2_subdev_lock_state(sink_state);
v4l2_subdev_lock_state(source_state);
+ }
- ret = v4l2_subdev_link_validate_locked(link);
+ ret = v4l2_subdev_link_validate_locked(link, states_locked);
- if (sink_state)
+ if (states_locked) {
v4l2_subdev_unlock_state(sink_state);
-
- if (source_state)
v4l2_subdev_unlock_state(source_state);
+ }
return ret;
}
@@ -1676,7 +1771,8 @@ int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
unsigned int i, j;
int ret = -EINVAL;
- if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
+ if (disallow & (V4L2_SUBDEV_ROUTING_NO_STREAM_MIX |
+ V4L2_SUBDEV_ROUTING_NO_MULTIPLEXING)) {
remote_pads = kcalloc(sd->entity.num_pads, sizeof(*remote_pads),
GFP_KERNEL);
if (!remote_pads)
@@ -1705,10 +1801,10 @@ int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
}
/*
- * V4L2_SUBDEV_ROUTING_NO_STREAM_MIX: Streams on the same pad
- * may not be routed to streams on different pads.
+ * V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX: all streams from a
+ * sink pad must be routed to a single source pad.
*/
- if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX) {
if (remote_pads[route->sink_pad] != U32_MAX &&
remote_pads[route->sink_pad] != route->source_pad) {
dev_dbg(sd->dev,
@@ -1716,7 +1812,13 @@ int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
i, "sink");
goto out;
}
+ }
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX: all streams on a
+ * source pad must originate from a single sink pad.
+ */
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX) {
if (remote_pads[route->source_pad] != U32_MAX &&
remote_pads[route->source_pad] != route->sink_pad) {
dev_dbg(sd->dev,
@@ -1724,7 +1826,37 @@ int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
i, "source");
goto out;
}
+ }
+
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_SINK_MULTIPLEXING: Pads on the sink
+ * side can not do stream multiplexing, i.e. there can be only
+ * a single stream in a sink pad.
+ */
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_SINK_MULTIPLEXING) {
+ if (remote_pads[route->sink_pad] != U32_MAX) {
+ dev_dbg(sd->dev,
+ "route %u attempts to multiplex on %s pad %u\n",
+ i, "sink", route->sink_pad);
+ goto out;
+ }
+ }
+
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING: Pads on the
+ * source side can not do stream multiplexing, i.e. there can
+ * be only a single stream in a source pad.
+ */
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING) {
+ if (remote_pads[route->source_pad] != U32_MAX) {
+ dev_dbg(sd->dev,
+ "route %u attempts to multiplex on %s pad %u\n",
+ i, "source", route->source_pad);
+ goto out;
+ }
+ }
+ if (remote_pads) {
remote_pads[route->sink_pad] = route->source_pad;
remote_pads[route->source_pad] = route->sink_pad;
}