summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@kernel.org>2023-02-15 14:40:21 +0300
committerMauro Carvalho Chehab <mchehab@kernel.org>2023-02-15 14:40:31 +0300
commit83e0f265aa8d0e37cc8e15d318b64da0ec03ff41 (patch)
tree860a02db84f093dbdb8484eb6014008bd5219768
parent94817983fb2ccd1869ed0c5a763317a45283a272 (diff)
parent05165248df6552daaacf5621e3a5e2369117a8a9 (diff)
downloadlinux-83e0f265aa8d0e37cc8e15d318b64da0ec03ff41.tar.xz
Merge git://git.linuxtv.org/media_stage into media_tree
* git://git.linuxtv.org/media_stage: (216 commits) media: v4l2-ctrls-api.c: move ctrl->is_new = 1 to the correct line media: Revert "media: saa7146: deprecate hexium_gemini/orion, mxb and ttpci" media: Revert "media: av7110: move to staging/media/deprecated/saa7146" media: imx-pxp: convert to regmap media: imx-pxp: Use non-threaded IRQ media: imx-pxp: Introduce pxp_read() and pxp_write() wrappers media: imx-pxp: Implement frame size enumeration media: imx-pxp: Pass pixel format value to find_format() media: imx-pxp: Add media controller support media: imx-pxp: Don't set bus_info manually in .querycap() media: imx-pxp: Sort headers alphabetically media: imx-pxp: add support for i.MX7D media: imx-pxp: make data_path_ctrl0 platform dependent media: imx-pxp: disable LUT block media: imx-pxp: explicitly disable unused blocks media: imx-pxp: extract helper function to setup data path media: imx-pxp: detect PXP version media: dt-bindings: media: fsl-pxp: convert to yaml media: imx-mipi-csis: Implement .init_cfg() using .set_fmt() media: imx-mipi-csis: Use V4L2 subdev active state ... Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
-rw-r--r--Documentation/admin-guide/media/cec.rst4
-rw-r--r--Documentation/devicetree/bindings/media/cec-gpio.txt42
-rw-r--r--Documentation/devicetree/bindings/media/cec.txt8
-rw-r--r--Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml (renamed from Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml)11
-rw-r--r--Documentation/devicetree/bindings/media/cec/cec-common.yaml28
-rw-r--r--Documentation/devicetree/bindings/media/cec/cec-gpio.yaml74
-rw-r--r--Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml58
-rw-r--r--Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml66
-rw-r--r--Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml66
-rw-r--r--Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml53
-rw-r--r--Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml88
-rw-r--r--Documentation/devicetree/bindings/media/fsl-pxp.txt26
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ak7375.txt8
-rw-r--r--Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml52
-rw-r--r--Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml11
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml93
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml122
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml106
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml106
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml122
-rw-r--r--Documentation/devicetree/bindings/media/s5p-cec.txt36
-rw-r--r--Documentation/devicetree/bindings/media/stih-cec.txt27
-rw-r--r--Documentation/devicetree/bindings/media/tegra-cec.txt27
-rw-r--r--Documentation/driver-api/media/mc-core.rst10
-rw-r--r--Documentation/userspace-api/media/drivers/aspeed-video.rst2
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-reserved.rst2
-rw-r--r--MAINTAINERS46
-rw-r--r--drivers/media/common/Kconfig1
-rw-r--r--drivers/media/common/Makefile2
-rw-r--r--drivers/media/common/saa7146/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/common/Kconfig)0
-rw-r--r--drivers/media/common/saa7146/Makefile (renamed from drivers/staging/media/deprecated/saa7146/common/Makefile)0
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_core.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_i2c.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_video.c)2
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c25
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c14
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c14
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c9
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c9
-rw-r--r--drivers/media/i2c/Kconfig40
-rw-r--r--drivers/media/i2c/Makefile3
-rw-r--r--drivers/media/i2c/ak7375.c38
-rw-r--r--drivers/media/i2c/imx219.c311
-rw-r--r--drivers/media/i2c/imx290.c1019
-rw-r--r--drivers/media/i2c/imx296.c1172
-rw-r--r--drivers/media/i2c/imx415.c1300
-rw-r--r--drivers/media/i2c/max9286.c1
-rw-r--r--drivers/media/i2c/ov2740.c4
-rw-r--r--drivers/media/i2c/ov5640.c86
-rw-r--r--drivers/media/i2c/ov5670.c312
-rw-r--r--drivers/media/i2c/ov5675.c198
-rw-r--r--drivers/media/i2c/ov7670.c2
-rw-r--r--drivers/media/i2c/ov772x.c3
-rw-r--r--drivers/media/i2c/ov8858.c2008
-rw-r--r--drivers/media/i2c/ov9282.c9
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c22
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c1
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h1
-rw-r--r--drivers/media/i2c/st-vgxy61.c4
-rw-r--r--drivers/media/i2c/tc358746.c9
-rw-r--r--drivers/media/mc/mc-entity.c69
-rw-r--r--drivers/media/pci/Kconfig2
-rw-r--r--drivers/media/pci/Makefile4
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2-main.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/pci/saa7146/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/saa7146/Kconfig)15
-rw-r--r--drivers/media/pci/saa7146/Makefile (renamed from drivers/staging/media/deprecated/saa7146/saa7146/Makefile)0
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c)2
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c)2
-rw-r--r--drivers/media/pci/saa7146/mxb.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/mxb.c)2
-rw-r--r--drivers/media/pci/ttpci/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/ttpci/Kconfig)17
-rw-r--r--drivers/media/pci/ttpci/Makefile (renamed from drivers/staging/media/deprecated/saa7146/ttpci/Makefile)0
-rw-r--r--drivers/media/pci/ttpci/budget-av.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c)2
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-core.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c)0
-rw-r--r--drivers/media/pci/ttpci/budget.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget.c)0
-rw-r--r--drivers/media/pci/ttpci/budget.h (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget.h)2
-rw-r--r--drivers/media/platform/amphion/venc.c18
-rw-r--r--drivers/media/platform/amphion/vpu_color.c6
-rw-r--r--drivers/media/platform/chips-media/imx-vdoa.c6
-rw-r--r--drivers/media/platform/marvell/mmp-driver.c2
-rw-r--r--drivers/media/platform/mediatek/mdp3/Kconfig7
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c3
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c7
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c6
-rw-r--r--drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c4
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c109
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c35
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h4
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c249
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c359
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c235
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c3
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c2
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c15
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is.h3
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.h1
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c4
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c1
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c4
-rw-r--r--drivers/media/platform/ti/davinci/vpbe_display.c2
-rw-r--r--drivers/media/platform/ti/davinci/vpbe_osd.c6
-rw-r--r--drivers/media/platform/ti/davinci/vpbe_venc.c6
-rw-r--r--drivers/media/platform/ti/davinci/vpif.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/ispvideo.c20
-rw-r--r--drivers/media/platform/verisilicon/hantro_drv.c2
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.c9
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c28
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c2
-rw-r--r--drivers/media/rc/ene_ir.c3
-rw-r--r--drivers/media/rc/gpio-ir-recv.c18
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_psi.c2
-rw-r--r--drivers/media/test-drivers/visl/visl-video.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c4
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c6
-rw-r--r--drivers/media/usb/siano/smsusb.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-h264.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-jpeg.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c4
-rw-r--r--drivers/staging/media/Kconfig3
-rw-r--r--drivers/staging/media/Makefile2
-rw-r--r--drivers/staging/media/atomisp/Kconfig2
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c249
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c176
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c206
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2680.c1280
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c195
-rw-r--r--drivers/staging/media/atomisp/i2c/gc0310.h10
-rw-r--r--drivers/staging/media/atomisp/i2c/gc2235.h31
-rw-r--r--drivers/staging/media/atomisp/i2c/mt9m114.h15
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h836
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2722.h36
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c195
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/ov5693.h61
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp.h50
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h2
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp_platform.h11
-rw-r--r--drivers/staging/media/atomisp/notes.txt6
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c90
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.h9
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.c41
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.h5
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.c89
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.h3
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c120
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_internal.h7
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.c60
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c171
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.h13
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_tpg.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_v4l2.c165
-rw-r--r--drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h2
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c20
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c7
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_params.c38
-rw-r--r--drivers/staging/media/av7110/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/av7110/Kconfig)20
-rw-r--r--drivers/staging/media/av7110/Makefile (renamed from drivers/staging/media/deprecated/saa7146/av7110/Makefile)3
-rw-r--r--drivers/staging/media/av7110/TODO3
-rw-r--r--drivers/staging/media/av7110/audio-bilingual-channel-select.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-channel-select.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-clear-buffer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-continue.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fclose.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fopen.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fwrite.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-get-capabilities.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-get-status.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-pause.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-play.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-select-source.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-av-sync.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-bypass-mode.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-id.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-mixer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-mute.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-streamtype.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-stop.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst)0
-rw-r--r--drivers/staging/media/av7110/audio.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio.rst)0
-rw-r--r--drivers/staging/media/av7110/audio_data_types.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst)0
-rw-r--r--drivers/staging/media/av7110/audio_function_calls.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst)0
-rw-r--r--drivers/staging/media/av7110/av7110.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110.c)0
-rw-r--r--drivers/staging/media/av7110/av7110.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110.h)2
-rw-r--r--drivers/staging/media/av7110/av7110_av.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_av.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ir.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_v4l.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c)0
-rw-r--r--drivers/staging/media/av7110/budget-patch.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h)0
-rw-r--r--drivers/staging/media/av7110/sp8870.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/sp8870.c)0
-rw-r--r--drivers/staging/media/av7110/sp8870.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/sp8870.h)0
-rw-r--r--drivers/staging/media/av7110/video-clear-buffer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst)0
-rw-r--r--drivers/staging/media/av7110/video-command.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-command.rst)0
-rw-r--r--drivers/staging/media/av7110/video-continue.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fast-forward.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fclose.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fopen.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst)0
-rw-r--r--drivers/staging/media/av7110/video-freeze.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fwrite.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-capabilities.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-event.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-frame-count.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-pts.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-size.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-status.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst)0
-rw-r--r--drivers/staging/media/av7110/video-play.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-play.rst)0
-rw-r--r--drivers/staging/media/av7110/video-select-source.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-blank.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-display-format.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-format.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-streamtype.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst)0
-rw-r--r--drivers/staging/media/av7110/video-slowmotion.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst)0
-rw-r--r--drivers/staging/media/av7110/video-stillpicture.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst)0
-rw-r--r--drivers/staging/media/av7110/video-stop.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst)0
-rw-r--r--drivers/staging/media/av7110/video-try-command.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst)0
-rw-r--r--drivers/staging/media/av7110/video.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video.rst)0
-rw-r--r--drivers/staging/media/av7110/video_function_calls.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst)0
-rw-r--r--drivers/staging/media/av7110/video_types.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video_types.rst)0
-rw-r--r--drivers/staging/media/deprecated/saa7146/Kconfig5
-rw-r--r--drivers/staging/media/deprecated/saa7146/Makefile2
-rw-r--r--drivers/staging/media/deprecated/saa7146/av7110/TODO9
-rw-r--r--drivers/staging/media/deprecated/saa7146/saa7146/TODO7
-rw-r--r--drivers/staging/media/deprecated/saa7146/ttpci/TODO7
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c7
-rw-r--r--drivers/staging/media/imx/imx-media-fim.c13
-rw-r--r--drivers/staging/media/imx/imx-media.h6
-rw-r--r--drivers/staging/media/meson/vdec/esparser.c3
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c66
-rw-r--r--include/media/drv-intf/saa7146.h (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146.h)0
-rw-r--r--include/media/drv-intf/saa7146_vv.h (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h)2
-rw-r--r--include/media/i2c/s5c73m3.h41
-rw-r--r--include/media/media-entity.h98
-rw-r--r--include/media/ov_16bit_addr_reg_helpers.h92
244 files changed, 8612 insertions, 5241 deletions
diff --git a/Documentation/admin-guide/media/cec.rst b/Documentation/admin-guide/media/cec.rst
index 5c7259371494..14ec3ff317c2 100644
--- a/Documentation/admin-guide/media/cec.rst
+++ b/Documentation/admin-guide/media/cec.rst
@@ -340,14 +340,14 @@ and IO24. Monitoring the HPD an 5V lines is not necessary, but it is helpful.
This kernel patch will hook up the cec-gpio driver correctly to
e.g. ``arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts``::
- cec-gpio@7 {
+ cec@7 {
compatible = "cec-gpio";
cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
};
- cec-gpio@8 {
+ cec@8 {
compatible = "cec-gpio";
cec-gpios = <&gpio 8 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
hpd-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
diff --git a/Documentation/devicetree/bindings/media/cec-gpio.txt b/Documentation/devicetree/bindings/media/cec-gpio.txt
deleted file mode 100644
index 47e8d73d32a3..000000000000
--- a/Documentation/devicetree/bindings/media/cec-gpio.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-* HDMI CEC GPIO driver
-
-The HDMI CEC GPIO module supports CEC implementations where the CEC line
-is hooked up to a pull-up GPIO line and - optionally - the HPD line is
-hooked up to another GPIO line.
-
-Please note: the maximum voltage for the CEC line is 3.63V, for the HPD and
-5V lines it is 5.3V. So you may need some sort of level conversion circuitry
-when connecting them to a GPIO line.
-
-Required properties:
- - compatible: value must be "cec-gpio".
- - cec-gpios: gpio that the CEC line is connected to. The line should be
- tagged as open drain.
-
-If the CEC line is associated with an HDMI receiver/transmitter, then the
-following property is also required:
-
- - hdmi-phandle - phandle to the HDMI controller, see also cec.txt.
-
-If the CEC line is not associated with an HDMI receiver/transmitter, then
-the following property is optional and can be used for debugging HPD changes:
-
- - hpd-gpios: gpio that the HPD line is connected to.
-
-This property is optional and can be used for debugging changes on the 5V line:
-
- - v5-gpios: gpio that the 5V line is connected to.
-
-Example for the Raspberry Pi 3 where the CEC line is connected to
-pin 26 aka BCM7 aka CE1 on the GPIO pin header, the HPD line is
-connected to pin 11 aka BCM17 and the 5V line is connected to pin
-15 aka BCM22 (some level shifter is needed for the HPD and 5V lines!):
-
-#include <dt-bindings/gpio/gpio.h>
-
-cec-gpio {
- compatible = "cec-gpio";
- cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
- hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
- v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/media/cec.txt b/Documentation/devicetree/bindings/media/cec.txt
deleted file mode 100644
index 22d7aae3d3d7..000000000000
--- a/Documentation/devicetree/bindings/media/cec.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Common bindings for HDMI CEC adapters
-
-- hdmi-phandle: phandle to the HDMI controller.
-
-- needs-hpd: if present the CEC support is only available when the HPD
- is high. Some boards only let the CEC pin through if the HPD is high,
- for example if there is a level converter that uses the HPD to power
- up or down.
diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml
index 8d844f4312d1..b1fab53418f9 100644
--- a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
+++ b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/media/amlogic,meson-gx-ao-cec.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/media/cec/amlogic,meson-gx-ao-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson AO-CEC Controller
@@ -33,11 +33,8 @@ properties:
interrupts:
maxItems: 1
- hdmi-phandle:
- description: phandle to the HDMI controller
- $ref: /schemas/types.yaml#/definitions/phandle
-
allOf:
+ - $ref: cec-common.yaml#
- if:
properties:
compatible:
@@ -81,7 +78,7 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/media/cec/cec-common.yaml b/Documentation/devicetree/bindings/media/cec/cec-common.yaml
new file mode 100644
index 000000000000..af6ee5f1c73f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/cec-common.yaml
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/cec-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HDMI CEC Adapters Common Properties
+
+maintainers:
+ - Hans Verkuil <hverkuil@xs4all.nl>
+
+properties:
+ $nodename:
+ pattern: "^cec(@[0-9a-f]+|-[0-9]+)?$"
+
+ hdmi-phandle:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to the HDMI controller.
+
+ needs-hpd:
+ type: boolean
+ description:
+ The CEC support is only available when the HPD is high. Some boards only
+ let the CEC pin through if the HPD is high, for example if there is a
+ level converter that uses the HPD to power up or down.
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml
new file mode 100644
index 000000000000..64d7ec057672
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/cec-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HDMI CEC GPIO
+
+maintainers:
+ - Hans Verkuil <hverkuil-cisco@xs4all.nl>
+
+description: |
+ The HDMI CEC GPIO module supports CEC implementations where the CEC line is
+ hooked up to a pull-up GPIO line and - optionally - the HPD line is hooked up
+ to another GPIO line.
+
+ Please note:: the maximum voltage for the CEC line is 3.63V, for the HPD and
+ 5V lines it is 5.3V. So you may need some sort of level conversion
+ circuitry when connecting them to a GPIO line.
+
+properties:
+ compatible:
+ const: cec-gpio
+
+ cec-gpios:
+ maxItems: 1
+ description:
+ GPIO that the CEC line is connected to. The line should be tagged as open
+ drain.
+
+ hpd-gpios:
+ maxItems: 1
+ description:
+ GPIO that the HPD line is connected to. Used for debugging HPD changes
+ when the CEC line is not associated with an HDMI receiver/transmitter.
+
+ v5-gpios:
+ maxItems: 1
+ description:
+ GPIO that the 5V line is connected to. Used for debugging changes on the
+ 5V line.
+
+required:
+ - compatible
+ - cec-gpios
+
+allOf:
+ - $ref: cec-common.yaml#
+ - if:
+ required:
+ - hdmi-phandle
+ then:
+ properties:
+ hpd-gpios: false
+
+ - if:
+ required:
+ - hpd-gpios
+ then:
+ properties:
+ hdmi-phandle: false
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ cec {
+ compatible = "cec-gpio";
+ cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+ hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+ v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml
new file mode 100644
index 000000000000..369c48fd9bf9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/nvidia,tegra114-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra HDMI CEC
+
+maintainers:
+ - Hans Verkuil <hverkuil-cisco@xs4all.nl>
+
+allOf:
+ - $ref: cec-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - nvidia,tegra114-cec
+ - nvidia,tegra124-cec
+ - nvidia,tegra210-cec
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: cec
+
+ interrupts:
+ maxItems: 1
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+ - hdmi-phandle
+ - interrupts
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra124-car.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ cec@70015000 {
+ compatible = "nvidia,tegra124-cec";
+ reg = <0x70015000 0x00001000>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&tegra_car TEGRA124_CLK_CEC>;
+ clock-names = "cec";
+ status = "disabled";
+ hdmi-phandle = <&hdmi>;
+ };
diff --git a/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml
new file mode 100644
index 000000000000..016c8a77c1a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/samsung,s5p-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S5PV210 and Exynos HDMI CEC
+
+maintainers:
+ - Krzysztof Kozlowski <krzk@kernel.org>
+ - Marek Szyprowski <m.szyprowski@samsung.com>
+
+allOf:
+ - $ref: cec-common.yaml#
+
+properties:
+ compatible:
+ const: samsung,s5p-cec
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: hdmicec
+
+ interrupts:
+ maxItems: 1
+
+ samsung,syscon-phandle:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to PMU system controller interface
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+ - hdmi-phandle
+ - interrupts
+ - samsung,syscon-phandle
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/exynos5420.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ cec@101b0000 {
+ compatible = "samsung,s5p-cec";
+ reg = <0x101B0000 0x200>;
+
+ clocks = <&clock CLK_HDMI_CEC>;
+ clock-names = "hdmicec";
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ hdmi-phandle = <&hdmi>;
+ needs-hpd;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_cec>;
+ samsung,syscon-phandle = <&pmu_system_controller>;
+ };
diff --git a/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml
new file mode 100644
index 000000000000..aeddf16ed339
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/st,stih-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STIH4xx HDMI CEC
+
+maintainers:
+ - Alain Volmat <alain.volmat@foss.st.com>
+
+allOf:
+ - $ref: cec-common.yaml#
+
+properties:
+ compatible:
+ const: st,stih-cec
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: cec-clk
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-names:
+ items:
+ - const: cec-irq
+
+ resets:
+ maxItems: 1
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - clocks
+ - hdmi-phandle
+ - interrupts
+ - resets
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/reset/stih407-resets.h>
+
+ cec@94a087c {
+ compatible = "st,stih-cec";
+ reg = <0x94a087c 0x64>;
+
+ clocks = <&clk_sysin>;
+ clock-names = "cec-clk";
+ hdmi-phandle = <&sti_hdmi>;
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cec-irq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_cec0_default>;
+ resets = <&softreset STIH407_LPM_SOFTRESET>;
+ };
diff --git a/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml
new file mode 100644
index 000000000000..2314a9a14650
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cec/st,stm32-cec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 CEC
+
+maintainers:
+ - Yannick Fertre <yannick.fertre@foss.st.com>
+
+properties:
+ compatible:
+ const: st,stm32-cec
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Module Clock
+ - description: Bus Clock
+
+ clock-names:
+ items:
+ - const: cec
+ - const: hdmi-cec
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/stm32mp1-clks.h>
+ cec: cec@40006c00 {
+ compatible = "st,stm32-cec";
+ reg = <0x40006c00 0x400>;
+ interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CEC_K>, <&clk_lse>;
+ clock-names = "cec", "hdmi-cec";
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml
new file mode 100644
index 000000000000..84a5e894ace4
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/fsl,imx6ull-pxp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Pixel Pipeline
+
+maintainers:
+ - Philipp Zabel <p.zabel@pengutronix.de>
+ - Michael Tretter <m.tretter@pengutronix.de>
+
+description:
+ The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine
+ that supports scaling, colorspace conversion, alpha blending, rotation, and
+ pixel conversion via lookup table. Different versions are present on various
+ i.MX SoCs from i.MX23 to i.MX7.
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - fsl,imx6ul-pxp
+ - fsl,imx6ull-pxp
+ - fsl,imx7d-pxp
+ - items:
+ - enum:
+ - fsl,imx6sll-pxp
+ - fsl,imx6sx-pxp
+ - const: fsl,imx6ull-pxp
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ minItems: 1
+ maxItems: 2
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: axi
+
+ power-domains:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx6sx-pxp
+ - fsl,imx6ul-pxp
+ then:
+ properties:
+ interrupts:
+ maxItems: 1
+ else:
+ properties:
+ interrupts:
+ minItems: 2
+ maxItems: 2
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx6ul-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ pxp: pxp@21cc000 {
+ compatible = "fsl,imx6ull-pxp";
+ reg = <0x021cc000 0x4000>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "axi";
+ clocks = <&clks IMX6UL_CLK_PXP>;
+ };
diff --git a/Documentation/devicetree/bindings/media/fsl-pxp.txt b/Documentation/devicetree/bindings/media/fsl-pxp.txt
deleted file mode 100644
index f8090e06530d..000000000000
--- a/Documentation/devicetree/bindings/media/fsl-pxp.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Freescale Pixel Pipeline
-========================
-
-The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine
-that supports scaling, colorspace conversion, alpha blending, rotation, and
-pixel conversion via lookup table. Different versions are present on various
-i.MX SoCs from i.MX23 to i.MX7.
-
-Required properties:
-- compatible: should be "fsl,<soc>-pxp", where SoC can be one of imx23, imx28,
- imx6dl, imx6sl, imx6sll, imx6ul, imx6sx, imx6ull, or imx7d.
-- reg: the register base and size for the device registers
-- interrupts: the PXP interrupt, two interrupts for imx6ull and imx7d.
-- clock-names: should be "axi"
-- clocks: the PXP AXI clock
-
-Example:
-
-pxp@21cc000 {
- compatible = "fsl,imx6ull-pxp";
- reg = <0x021cc000 0x4000>;
- interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
- clock-names = "axi";
- clocks = <&clks IMX6UL_CLK_PXP>;
-};
diff --git a/Documentation/devicetree/bindings/media/i2c/ak7375.txt b/Documentation/devicetree/bindings/media/i2c/ak7375.txt
deleted file mode 100644
index aa3e24b41241..000000000000
--- a/Documentation/devicetree/bindings/media/i2c/ak7375.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Asahi Kasei Microdevices AK7375 voice coil lens driver
-
-AK7375 is a camera voice coil lens.
-
-Mandatory properties:
-
-- compatible: "asahi-kasei,ak7375"
-- reg: I2C slave address
diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
new file mode 100644
index 000000000000..22a810fc7222
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/asahi-kasei,ak7375.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Asahi Kasei Microdevices AK7375 voice coil lens actuator
+
+maintainers:
+ - Tianshu Qiu <tian.shu.qiu@intel.com>
+
+description:
+ AK7375 is a voice coil motor (VCM) camera lens actuator that
+ is controlled over I2C.
+
+properties:
+ compatible:
+ const: asahi-kasei,ak7375
+
+ reg:
+ maxItems: 1
+
+ vdd-supply:
+ description: VDD supply
+
+ vio-supply:
+ description: I/O pull-up supply
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vio-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ak7375: camera-lens@c {
+ compatible = "asahi-kasei,ak7375";
+ reg = <0x0c>;
+
+ vdd-supply = <&vreg_l23a_2p8>;
+ vio-supply = <&vreg_lvs1a_1p8>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml
index 63e5b89d2e0b..af8ada55b3f2 100644
--- a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml
@@ -13,6 +13,9 @@ description:
The Chrontel CH7322 is a discrete HDMI-CEC controller. It is
programmable through I2C and drives a single CEC line.
+allOf:
+ - $ref: /schemas/media/cec/cec-common.yaml#
+
properties:
compatible:
const: chrontel,ch7322
@@ -40,16 +43,12 @@ properties:
if in auto mode.
maxItems: 1
- # see ../cec.txt
- hdmi-phandle:
- description: phandle to the HDMI controller
-
required:
- compatible
- reg
- interrupts
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -58,7 +57,7 @@ examples:
i2c {
#address-cells = <1>;
#size-cells = <0>;
- ch7322@75 {
+ cec@75 {
compatible = "chrontel,ch7322";
reg = <0x75>;
interrupts = <47 IRQ_TYPE_EDGE_RISING>;
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml
new file mode 100644
index 000000000000..6e089fe1d613
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov5670.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Omnivision OV5670 5 Megapixels raw image sensor
+
+maintainers:
+ - Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+
+description: |-
+ The OV5670 is a 5 Megapixels raw image sensor which provides images in 10-bits
+ RAW BGGR Bayer format on a 2 data lanes MIPI CSI-2 serial interface and is
+ controlled through an I2C compatible control bus.
+
+properties:
+ compatible:
+ const: ovti,ov5670
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description: System clock. From 6 to 27 MHz.
+ maxItems: 1
+
+ powerdown-gpios:
+ description: Reference to the GPIO connected to the PWDNB pin. Active low.
+
+ reset-gpios:
+ description: Reference to the GPIO connected to the XSHUTDOWN pin. Active low.
+ maxItems: 1
+
+ avdd-supply:
+ description: Analog circuit power. Typically 2.8V.
+
+ dvdd-supply:
+ description: Digital circuit power. Typically 1.2V.
+
+ dovdd-supply:
+ description: Digital I/O circuit power. Typically 2.8V or 1.8V.
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ additionalProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 2
+ items:
+ enum: [1, 2]
+
+ clock-noncontinuous: true
+ remote-endpoint: true
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ov5670: sensor@36 {
+ compatible = "ovti,ov5670";
+ reg = <0x36>;
+
+ clocks = <&sensor_xclk>;
+
+ port {
+ ov5670_ep: endpoint {
+ remote-endpoint = <&csi_ep>;
+ data-lanes = <1 2>;
+ clock-noncontinuous;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml
new file mode 100644
index 000000000000..ad07204057f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2022 Theobroma Systems Design und Consulting GmbH
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov5675.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Omnivision OV5675 CMOS Sensor
+
+maintainers:
+ - Quentin Schulz <quentin.schulz@theobroma-systems.com>
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+description: |
+ The Omnivision OV5675 is a high performance, 1/5-inch, 5 megapixel, CMOS
+ image sensor that delivers 2592x1944 at 30fps. It provides full-frame,
+ sub-sampled, and windowed 10-bit MIPI images in various formats via the
+ Serial Camera Control Bus (SCCB) interface.
+
+ This chip is programmable through I2C and two-wire SCCB. The sensor output
+ is available via CSI-2 serial data output (up to 2-lane).
+
+properties:
+ compatible:
+ const: ovti,ov5675
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description:
+ System input clock (aka XVCLK). From 6 to 27 MHz.
+ maxItems: 1
+
+ dovdd-supply:
+ description:
+ Digital I/O voltage supply, 1.8 volts.
+
+ avdd-supply:
+ description:
+ Analog voltage supply, 2.8 volts.
+
+ dvdd-supply:
+ description:
+ Digital core voltage supply, 1.2 volts.
+
+ reset-gpios:
+ description:
+ The phandle and specifier for the GPIO that controls sensor reset.
+ This corresponds to the hardware pin XSHUTDN which is physically
+ active low.
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 2
+
+ # Supports max data transfer of 900 Mbps per lane
+ link-frequencies: true
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - dovdd-supply
+ - avdd-supply
+ - dvdd-supply
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/px30-cru.h>
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/pinctrl/rockchip.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ov5675: camera@36 {
+ compatible = "ovti,ov5675";
+ reg = <0x36>;
+
+ reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cif_clkout_m0>;
+
+ clocks = <&cru SCLK_CIF_OUT>;
+ assigned-clocks = <&cru SCLK_CIF_OUT>;
+ assigned-clock-rates = <19200000>;
+
+ avdd-supply = <&vcc_1v8>;
+ dvdd-supply = <&vcc_1v2>;
+ dovdd-supply = <&vcc_2v8>;
+
+ rotation = <90>;
+ orientation = <0>;
+
+ port {
+ ucam_out: endpoint {
+ remote-endpoint = <&mipi_in_ucam>;
+ data-lanes = <1 2>;
+ link-frequencies = /bits/ 64 <450000000>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml
new file mode 100644
index 000000000000..a65f921ec0fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov8858.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OV8858 Image Sensor
+
+maintainers:
+ - Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+ - Nicholas Roth <nicholas@rothemail.net>
+
+description: |
+ The OmniVision OV8858 is a color CMOS 8 Megapixels (3264x2448) image sensor
+ controlled through an I2C-compatible SCCB bus. The sensor transmits images
+ on a MIPI CSI-2 output interface with up to 4 data lanes.
+
+properties:
+ compatible:
+ const: ovti,ov8858
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: XVCLK external clock
+
+ clock-names:
+ const: xvclk
+
+ dvdd-supply:
+ description: Digital Domain Power Supply
+
+ avdd-supply:
+ description: Analog Domain Power Supply
+
+ dovdd-supply:
+ description: I/O Domain Power Supply
+
+ powerdown-gpios:
+ description: PWDNB powerdown GPIO (active low)
+
+ reset-gpios:
+ maxItems: 1
+ description: XSHUTDN reset GPIO (active low)
+
+ port:
+ description: MIPI CSI-2 transmitter port
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+
+ required:
+ - data-lanes
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/rockchip.h>
+ #include <dt-bindings/clock/rk3399-cru.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ov8858: camera@36 {
+ compatible = "ovti,ov8858";
+ reg = <0x36>;
+
+ clocks = <&cru SCLK_CIF_OUT>;
+ clock-names = "xvclk";
+ assigned-clocks = <&cru SCLK_CIF_OUT>;
+ assigned-clock-rates = <24000000>;
+
+ dovdd-supply = <&vcc1v8_dvp>;
+
+ reset-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_LOW>;
+ powerdown-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>;
+
+ port {
+ ucam_out: endpoint {
+ remote-endpoint = <&mipi_in_ucam>;
+ data-lanes = <1 2 3 4>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml
new file mode 100644
index 000000000000..65ad9c100e45
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx296.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX296 1/2.8-Inch CMOS Image Sensor
+
+maintainers:
+ - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+description: |-
+ The Sony IMX296 is a 1/2.9-Inch active pixel type CMOS Solid-state image
+ sensor with square pixel array and 1.58 M effective pixels. This chip
+ features a global shutter with variable charge-integration time. It is
+ programmable through I2C and 4-wire interfaces. The sensor output is
+ available via CSI-2 serial data output (1 Lane).
+
+properties:
+ compatible:
+ enum:
+ - sony,imx296
+ - sony,imx296ll
+ - sony,imx296lq
+ description:
+ The IMX296 sensor exists in two different models, a colour variant
+ (IMX296LQ) and a monochrome variant (IMX296LL). The device exposes the
+ model through registers, allowing for auto-detection with a common
+ "sony,imx296" compatible string. However, some camera modules disable the
+ ability to read the sensor model register, which disables this feature.
+ In those cases, the exact model needs to be specified as "sony,imx296ll"
+ or "sony,imx296lq".
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ description: Input clock (37.125 MHz, 54 MHz or 74.25 MHz)
+ items:
+ - const: inck
+
+ avdd-supply:
+ description: Analog power supply (3.3V)
+
+ dvdd-supply:
+ description: Digital power supply (1.2V)
+
+ ovdd-supply:
+ description: Interface power supply (1.8V)
+
+ reset-gpios:
+ description: Sensor reset (XCLR) GPIO
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/properties/port
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - avdd-supply
+ - dvdd-supply
+ - ovdd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ imx296: camera-sensor@1a {
+ compatible = "sony,imx296";
+ reg = <0x1a>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_rear_default>;
+
+ clocks = <&gcc 90>;
+ clock-names = "inck";
+
+ avdd-supply = <&camera_vdda_3v3>;
+ dvdd-supply = <&camera_vddd_1v2>;
+ ovdd-supply = <&camera_vddo_1v8>;
+
+ reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>;
+
+ port {
+ imx296_ep: endpoint {
+ remote-endpoint = <&csiphy0_ep>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
new file mode 100644
index 000000000000..ffccf5f3c9e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx415.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX415 CMOS Image Sensor
+
+maintainers:
+ - Michael Riesch <michael.riesch@wolfvision.net>
+
+description: |-
+ The Sony IMX415 is a diagonal 6.4 mm (Type 1/2.8) CMOS active pixel type
+ solid-state image sensor with a square pixel array and 8.46 M effective
+ pixels. This chip operates with analog 2.9 V, digital 1.1 V, and interface
+ 1.8 V triple power supply, and has low power consumption.
+ The IMX415 is programmable through I2C interface. The sensor output is
+ available via CSI-2 serial data output (two or four lanes).
+
+allOf:
+ - $ref: ../video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: sony,imx415
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description: Input clock (24 MHz, 27 MHz, 37.125 MHz, 72 MHz or 74.25 MHz)
+ maxItems: 1
+
+ avdd-supply:
+ description: Analog power supply (2.9 V)
+
+ dvdd-supply:
+ description: Digital power supply (1.1 V)
+
+ ovdd-supply:
+ description: Interface power supply (1.8 V)
+
+ reset-gpios:
+ description: Sensor reset (XCLR) GPIO
+ maxItems: 1
+
+ flash-leds: true
+
+ lens-focus: true
+
+ orientation: true
+
+ rotation: true
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ oneOf:
+ - items:
+ - const: 1
+ - const: 2
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - avdd-supply
+ - dvdd-supply
+ - ovdd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ imx415: camera-sensor@1a {
+ compatible = "sony,imx415";
+ reg = <0x1a>;
+ avdd-supply = <&vcc2v9_cam>;
+ clocks = <&clock_cam>;
+ dvdd-supply = <&vcc1v1_cam>;
+ lens-focus = <&vcm>;
+ orientation = <2>;
+ ovdd-supply = <&vcc1v8_cam>;
+ reset-gpios = <&gpio_expander 14 GPIO_ACTIVE_LOW>;
+ rotation = <180>;
+
+ port {
+ imx415_ep: endpoint {
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <445500000>;
+ remote-endpoint = <&mipi_in>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt
deleted file mode 100644
index e847291d4aff..000000000000
--- a/Documentation/devicetree/bindings/media/s5p-cec.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-* Samsung HDMI CEC driver
-
-The HDMI CEC module is present is Samsung SoCs and its purpose is to
-handle communication between HDMI connected devices over the CEC bus.
-
-Required properties:
- - compatible : value should be following
- "samsung,s5p-cec"
-
- - reg : Physical base address of the IP registers and length of memory
- mapped region.
-
- - interrupts : HDMI CEC interrupt number to the CPU.
- - clocks : from common clock binding: handle to HDMI CEC clock.
- - clock-names : from common clock binding: must contain "hdmicec",
- corresponding to entry in the clocks property.
- - samsung,syscon-phandle - phandle to the PMU system controller
- - hdmi-phandle - phandle to the HDMI controller, see also cec.txt.
-
-Optional:
- - needs-hpd : if present the CEC support is only available when the HPD
- is high. See cec.txt for more details.
-
-Example:
-
-hdmicec: cec@100b0000 {
- compatible = "samsung,s5p-cec";
- reg = <0x100B0000 0x200>;
- interrupts = <0 114 0>;
- clocks = <&clock CLK_HDMI_CEC>;
- clock-names = "hdmicec";
- samsung,syscon-phandle = <&pmu_system_controller>;
- hdmi-phandle = <&hdmi>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_cec>;
-};
diff --git a/Documentation/devicetree/bindings/media/stih-cec.txt b/Documentation/devicetree/bindings/media/stih-cec.txt
deleted file mode 100644
index ece0832fdeaf..000000000000
--- a/Documentation/devicetree/bindings/media/stih-cec.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-STMicroelectronics STIH4xx HDMI CEC driver
-
-Required properties:
- - compatible : value should be "st,stih-cec"
- - reg : Physical base address of the IP registers and length of memory
- mapped region.
- - clocks : from common clock binding: handle to HDMI CEC clock
- - interrupts : HDMI CEC interrupt number to the CPU.
- - pinctrl-names: Contains only one value - "default"
- - pinctrl-0: Specifies the pin control groups used for CEC hardware.
- - resets: Reference to a reset controller
- - hdmi-phandle: Phandle to the HDMI controller, see also cec.txt.
-
-Example for STIH407:
-
-sti-cec@94a087c {
- compatible = "st,stih-cec";
- reg = <0x94a087c 0x64>;
- clocks = <&clk_sysin>;
- clock-names = "cec-clk";
- interrupts = <GIC_SPI 140 IRQ_TYPE_NONE>;
- interrupt-names = "cec-irq";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_cec0_default>;
- resets = <&softreset STIH407_LPM_SOFTRESET>;
- hdmi-phandle = <&hdmi>;
-};
diff --git a/Documentation/devicetree/bindings/media/tegra-cec.txt b/Documentation/devicetree/bindings/media/tegra-cec.txt
deleted file mode 100644
index c503f06f3b84..000000000000
--- a/Documentation/devicetree/bindings/media/tegra-cec.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* Tegra HDMI CEC hardware
-
-The HDMI CEC module is present in Tegra SoCs and its purpose is to
-handle communication between HDMI connected devices over the CEC bus.
-
-Required properties:
- - compatible : value should be one of the following:
- "nvidia,tegra114-cec"
- "nvidia,tegra124-cec"
- "nvidia,tegra210-cec"
- - reg : Physical base address of the IP registers and length of memory
- mapped region.
- - interrupts : HDMI CEC interrupt number to the CPU.
- - clocks : from common clock binding: handle to HDMI CEC clock.
- - clock-names : from common clock binding: must contain "cec",
- corresponding to the entry in the clocks property.
- - hdmi-phandle : phandle to the HDMI controller, see also cec.txt.
-
-Example:
-
-cec@70015000 {
- compatible = "nvidia,tegra124-cec";
- reg = <0x0 0x70015000 0x0 0x00001000>;
- interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&tegra_car TEGRA124_CLK_CEC>;
- clock-names = "cec";
-};
diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
index 400b8ca29367..2456950ce8ff 100644
--- a/Documentation/driver-api/media/mc-core.rst
+++ b/Documentation/driver-api/media/mc-core.rst
@@ -232,12 +232,10 @@ prevent link states from being modified during streaming by calling
The function will mark all the pads which are part of the pipeline as streaming.
-The struct media_pipeline instance pointed to by
-the pipe argument will be stored in every pad in the pipeline.
-Drivers should embed the struct media_pipeline
-in higher-level pipeline structures and can then access the
-pipeline through the struct media_pad
-pipe field.
+The struct media_pipeline instance pointed to by the pipe argument will be
+stored in every pad in the pipeline. Drivers should embed the struct
+media_pipeline in higher-level pipeline structures and can then access the
+pipeline through the struct media_pad pipe field.
Calls to :c:func:`media_pipeline_start()` can be nested.
The pipeline pointer must be identical for all nested calls to the function.
diff --git a/Documentation/userspace-api/media/drivers/aspeed-video.rst b/Documentation/userspace-api/media/drivers/aspeed-video.rst
index 1b0cb1e3eba8..567387aca6b0 100644
--- a/Documentation/userspace-api/media/drivers/aspeed-video.rst
+++ b/Documentation/userspace-api/media/drivers/aspeed-video.rst
@@ -23,7 +23,7 @@ proprietary mode.
More details on the ASPEED video hardware operations can be found in
*chapter 6.2.16 KVM Video Driver* of SDK_User_Guide which available on
-AspeedTech-BMC/openbmc/releases.
+`github <https://github.com/AspeedTech-BMC/openbmc/releases/>`__.
The ASPEED video driver implements the following driver-specific control:
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
index 73cd99828010..58f6ae25b2e7 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
@@ -271,7 +271,7 @@ please make a proposal on the linux-media mailing list.
The implementation is based on AST2600 A3 datasheet, revision 0.9, which
is not publicly available. Or you can reference Video stream data format
– ASPEED mode compression of SDK_User_Guide which available on
- AspeedTech-BMC/openbmc/releases.
+ `github <https://github.com/AspeedTech-BMC/openbmc/releases/>`__.
Decoder's implementation can be found here,
`aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
diff --git a/MAINTAINERS b/MAINTAINERS
index f4fe807b30d0..7f4678dba495 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2872,7 +2872,7 @@ M: Marek Szyprowski <m.szyprowski@samsung.com>
L: linux-samsung-soc@vger.kernel.org
L: linux-media@vger.kernel.org
S: Maintained
-F: Documentation/devicetree/bindings/media/s5p-cec.txt
+F: Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml
F: drivers/media/cec/platform/s5p/
ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
@@ -3005,7 +3005,7 @@ M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
L: linux-tegra@vger.kernel.org
L: linux-media@vger.kernel.org
S: Maintained
-F: Documentation/devicetree/bindings/media/tegra-cec.txt
+F: Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml
F: drivers/media/cec/platform/tegra/
ARM/TESLA FSD SoC SUPPORT
@@ -3228,7 +3228,7 @@ M: Tianshu Qiu <tian.shu.qiu@intel.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/i2c/ak7375.txt
+F: Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
F: drivers/media/i2c/ak7375.c
ASAHI KASEI AK8974 DRIVER
@@ -4837,7 +4837,7 @@ S: Supported
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: Documentation/ABI/testing/debugfs-cec-error-inj
-F: Documentation/devicetree/bindings/media/cec.txt
+F: Documentation/devicetree/bindings/media/cec/cec-common.yaml
F: Documentation/driver-api/media/cec-core.rst
F: Documentation/userspace-api/media/cec
F: drivers/media/cec/
@@ -4853,7 +4853,7 @@ L: linux-media@vger.kernel.org
S: Supported
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/cec-gpio.txt
+F: Documentation/devicetree/bindings/media/cec/cec-gpio.yaml
F: drivers/media/cec/platform/cec-gpio/
CELL BROADBAND ENGINE ARCHITECTURE
@@ -13572,7 +13572,7 @@ L: linux-amlogic@lists.infradead.org
S: Supported
W: http://linux-meson.com/
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
+F: Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml
F: drivers/media/cec/platform/meson/ao-cec-g12a.c
F: drivers/media/cec/platform/meson/ao-cec.c
@@ -15467,6 +15467,7 @@ M: Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml
F: drivers/media/i2c/ov5670.c
OMNIVISION OV5675 SENSOR DRIVER
@@ -15474,6 +15475,7 @@ M: Shawn Tu <shawnx.tu@intel.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml
F: drivers/media/i2c/ov5675.c
OMNIVISION OV5693 SENSOR DRIVER
@@ -15523,6 +15525,15 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml
F: drivers/media/i2c/ov8856.c
+OMNIVISION OV8858 SENSOR DRIVER
+M: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+M: Nicholas Roth <nicholas@rothemail.net>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml
+F: drivers/media/i2c/ov8858.c
+
OMNIVISION OV9282 SENSOR DRIVER
M: Paul J. Murphy <paul.j.murphy@intel.com>
M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
@@ -18403,7 +18414,9 @@ M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: drivers/staging/media/deprecated/saa7146/
+F: drivers/media/common/saa7146/
+F: drivers/media/pci/saa7146/
+F: include/media/drv-intf/saa7146*
SAFESETID SECURITY MODULE
M: Micah Morton <mortonm@chromium.org>
@@ -19472,6 +19485,15 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
F: drivers/media/i2c/imx290.c
+SONY IMX296 SENSOR DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml
+F: drivers/media/i2c/imx296.c
+
SONY IMX319 SENSOR DRIVER
M: Bingbu Cao <bingbu.cao@intel.com>
L: linux-media@vger.kernel.org
@@ -19513,6 +19535,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
F: drivers/media/i2c/imx412.c
+SONY IMX415 SENSOR DRIVER
+M: Michael Riesch <michael.riesch@wolfvision.net>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
+F: drivers/media/i2c/imx415.c
+
SONY MEMORYSTICK SUBSYSTEM
M: Maxim Levitsky <maximlevitsky@gmail.com>
M: Alex Dubov <oakad@yahoo.com>
@@ -19951,7 +19981,7 @@ F: sound/soc/sti/
STI CEC DRIVER
M: Alain Volmat <alain.volmat@foss.st.com>
S: Maintained
-F: Documentation/devicetree/bindings/media/stih-cec.txt
+F: Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml
F: drivers/media/cec/platform/sti/
STK1160 USB VIDEO CAPTURE DRIVER
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 852b7d92fbdd..a2ae71270054 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -22,6 +22,7 @@ config VIDEO_TVEEPROM
depends on I2C
source "drivers/media/common/b2c2/Kconfig"
+source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
source "drivers/media/common/v4l2-tpg/Kconfig"
source "drivers/media/common/videobuf2/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index d78a0df15478..ad0b1e95fb12 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/
+obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
# Please keep it alphabetically sorted by Kconfig name
# (e. g. LC_ALL=C sort Makefile)
diff --git a/drivers/staging/media/deprecated/saa7146/common/Kconfig b/drivers/media/common/saa7146/Kconfig
index a0aa155e5d85..a0aa155e5d85 100644
--- a/drivers/staging/media/deprecated/saa7146/common/Kconfig
+++ b/drivers/media/common/saa7146/Kconfig
diff --git a/drivers/staging/media/deprecated/saa7146/common/Makefile b/drivers/media/common/saa7146/Makefile
index 2a6337feaec8..2a6337feaec8 100644
--- a/drivers/staging/media/deprecated/saa7146/common/Makefile
+++ b/drivers/media/common/saa7146/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index da21d346b870..e50fa0ff7c5d 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -8,8 +8,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146.h>
#include <linux/module.h>
-#include "saa7146.h"
static int saa7146_num;
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index aa14698a9c54..e9a15de6126e 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
-#include "saa7146_vv.h"
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index b1222a4cfa4a..6c9946a402ee 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -3,7 +3,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
{
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
index 7a33fe51775a..df9ebe2a168c 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
{
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index 2d4a05d7bc5b..bd442b984423 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static int vbi_pixel_to_capture = 720 * 2;
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 4598a44231fa..2296765079a4 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -1,10 +1,10 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146_vv.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "saa7146_vv.h"
static int max_memory = 32;
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 53e495223ea0..cf6727d9c81f 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -502,27 +502,11 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
* related information, if no buffers are left return the queue to an
* uninitialized state. Might be called even if the queue has already been freed.
*/
-static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
+static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
{
unsigned int buffer;
- /*
- * Sanity check: when preparing a buffer the queue lock is released for
- * a short while (see __buf_prepare for the details), which would allow
- * a race with a reqbufs which can call this function. Removing the
- * buffers from underneath __buf_prepare is obviously a bad idea, so we
- * check if any of the buffers is in the state PREPARING, and if so we
- * just return -EAGAIN.
- */
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- if (q->bufs[buffer] == NULL)
- continue;
- if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) {
- dprintk(q, 1, "preparing buffers, cannot free\n");
- return -EAGAIN;
- }
- }
+ lockdep_assert_held(&q->mmap_lock);
/* Call driver-provided cleanup function for each buffer, if provided */
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
@@ -616,7 +600,6 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
q->memory = VB2_MEMORY_UNKNOWN;
INIT_LIST_HEAD(&q->queued_list);
}
- return 0;
}
bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
@@ -798,10 +781,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
* queued without ever calling STREAMON.
*/
__vb2_queue_cancel(q);
- ret = __vb2_queue_free(q, q->num_buffers);
+ __vb2_queue_free(q, q->num_buffers);
mutex_unlock(&q->mmap_lock);
- if (ret)
- return ret;
/*
* In case of REQBUFS(0) return immediately without calling
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
index 4cf2d7cfd3f5..0a1f3899d72c 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -2162,11 +2162,11 @@ int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
else
*task_completed = 0;
- return ret;
+ return 0;
}
if (cpu_status != 0) {
*task_completed = 0;
- return ret;
+ return 0;
}
ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
index fe3c6f8b1b3e..c7e79da8c432 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -833,12 +833,12 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (sync_stat == 6) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
}
ret =
@@ -854,7 +854,7 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
@@ -893,15 +893,15 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (ts_lock) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
} else if (!unlock_detected) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
ret =
@@ -915,5 +915,5 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
index dd32004a12d8..a9ab983348c8 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -1024,12 +1024,12 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (sync_stat == 6) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
}
ret =
@@ -1045,7 +1045,7 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
@@ -1084,15 +1084,15 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (ts_lock) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
} else if (!unlock_detected) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
ret =
@@ -1106,7 +1106,7 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 1dff59ca21a1..6bf6559b127f 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -9539,7 +9539,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod)
qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM256 << 2;
break;
default:
- return -EIO;
+ rc = -EIO;
+ goto rw_error;
}
/* ------------------------------ */
@@ -10916,7 +10917,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
break;
case DRX_STANDARD_AUTO:
default:
- return -EINVAL;
+ rc = -EINVAL;
+ goto rw_error;
}
/*
@@ -11463,7 +11465,8 @@ static int drxj_open(struct drx_demod_instance *demod)
if (DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode)) {
pr_err("Should powerup before loading the firmware.");
- return -EINVAL;
+ rc = -EINVAL;
+ goto rw_error;
}
rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_UPLOAD);
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 2505f1e5794e..d3e29937cf4c 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -1498,6 +1498,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct mb86a16_state *state = fe->demodulator_priv;
+ int ret = -EREMOTEIO;
int i;
u8 regs;
@@ -1510,8 +1511,10 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
regs = 0x18;
- if (cmd->msg_len > 5 || cmd->msg_len < 4)
- return -EINVAL;
+ if (cmd->msg_len > 5 || cmd->msg_len < 4) {
+ ret = -EINVAL;
+ goto err;
+ }
for (i = 0; i < cmd->msg_len; i++) {
if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
@@ -1532,7 +1535,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
err:
dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
- return -EREMOTEIO;
+ return ret;
}
static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe,
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 833241897d63..c3d5952ca27e 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -162,6 +162,19 @@ config VIDEO_IMX290
To compile this driver as a module, choose M here: the
module will be called imx290.
+config VIDEO_IMX296
+ tristate "Sony IMX296 sensor support"
+ depends on I2C && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX296 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx296.
+
config VIDEO_IMX319
tristate "Sony IMX319 sensor support"
depends on I2C && VIDEO_DEV
@@ -228,6 +241,20 @@ config VIDEO_IMX412
To compile this driver as a module, choose M here: the
module will be called imx412.
+config VIDEO_IMX415
+ tristate "Sony IMX415 sensor support"
+ depends on OF_GPIO
+ depends on I2C && VIDEO_DEV
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX415 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx415.
+
config VIDEO_MAX9271_LIB
tristate
@@ -645,6 +672,19 @@ config VIDEO_OV8856
To compile this driver as a module, choose M here: the
module will be called ov8856.
+config VIDEO_OV8858
+ tristate "OmniVision OV8858 sensor support"
+ depends on I2C && PM && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for OmniVision
+ OV8858 camera sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov8858.
+
config VIDEO_OV8865
tristate "OmniVision OV8865 sensor support"
depends on I2C && PM && VIDEO_DEV
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 4d6c052bb5a7..4f5e9d9cee85 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -43,11 +43,13 @@ obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
+obj-$(CONFIG_VIDEO_IMX296) += imx296.o
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
obj-$(CONFIG_VIDEO_IMX334) += imx334.o
obj-$(CONFIG_VIDEO_IMX335) += imx335.o
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
obj-$(CONFIG_VIDEO_IMX412) += imx412.o
+obj-$(CONFIG_VIDEO_IMX415) += imx415.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
@@ -96,6 +98,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
+obj-$(CONFIG_VIDEO_OV8858) += ov8858.o
obj-$(CONFIG_VIDEO_OV8865) += ov8865.o
obj-$(CONFIG_VIDEO_OV9282) += ov9282.o
obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c
index 1af9f698eecf..e7cec45bc271 100644
--- a/drivers/media/i2c/ak7375.c
+++ b/drivers/media/i2c/ak7375.c
@@ -6,6 +6,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -23,17 +24,29 @@
*/
#define AK7375_CTRL_STEPS 64
#define AK7375_CTRL_DELAY_US 1000
+/*
+ * The vcm may take up 10 ms (tDELAY) to power on and start taking
+ * I2C messages. Based on AK7371 datasheet.
+ */
+#define AK7375_POWER_DELAY_US 10000
#define AK7375_REG_POSITION 0x0
#define AK7375_REG_CONT 0x2
#define AK7375_MODE_ACTIVE 0x0
#define AK7375_MODE_STANDBY 0x40
+static const char * const ak7375_supply_names[] = {
+ "vdd",
+ "vio",
+};
+
/* ak7375 device structure */
struct ak7375_device {
struct v4l2_ctrl_handler ctrls_vcm;
struct v4l2_subdev sd;
struct v4l2_ctrl *focus;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ak7375_supply_names)];
+
/* active or standby mode */
bool active;
};
@@ -133,12 +146,24 @@ static int ak7375_probe(struct i2c_client *client)
{
struct ak7375_device *ak7375_dev;
int ret;
+ unsigned int i;
ak7375_dev = devm_kzalloc(&client->dev, sizeof(*ak7375_dev),
GFP_KERNEL);
if (!ak7375_dev)
return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++)
+ ak7375_dev->supplies[i].supply = ak7375_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
+ return ret;
+ }
+
v4l2_i2c_subdev_init(&ak7375_dev->sd, client, &ak7375_ops);
ak7375_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ak7375_dev->sd.internal_ops = &ak7375_int_ops;
@@ -208,6 +233,11 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev)
if (ret)
dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
+ ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret)
+ return ret;
+
ak7375_dev->active = false;
return 0;
@@ -228,6 +258,14 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev)
if (ak7375_dev->active)
return 0;
+ ret = regulator_bulk_enable(ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret)
+ return ret;
+
+ /* Wait for vcm to become ready */
+ usleep_range(AK7375_POWER_DELAY_US, AK7375_POWER_DELAY_US + 500);
+
ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT,
AK7375_MODE_ACTIVE, 1);
if (ret) {
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 77bd79a5954e..f9471c9e3a74 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -42,10 +42,16 @@
/* External clock frequency is 24.0M */
#define IMX219_XCLK_FREQ 24000000
-/* Pixel rate is fixed at 182.4M for all the modes */
+/* Pixel rate is fixed for all the modes */
#define IMX219_PIXEL_RATE 182400000
+#define IMX219_PIXEL_RATE_4LANE 280800000
#define IMX219_DEFAULT_LINK_FREQ 456000000
+#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000
+
+#define IMX219_REG_CSI_LANE_MODE 0x0114
+#define IMX219_CSI_2_LANE_MODE 0x01
+#define IMX219_CSI_4_LANE_MODE 0x03
/* V_TIMING internal */
#define IMX219_REG_VTS 0x0160
@@ -89,6 +95,12 @@
#define IMX219_REG_ORIENTATION 0x0172
+/* Binning Mode */
+#define IMX219_REG_BINNING_MODE 0x0174
+#define IMX219_BINNING_NONE 0x0000
+#define IMX219_BINNING_2X2 0x0101
+#define IMX219_BINNING_2X2_ANALOG 0x0303
+
/* Test Pattern Control */
#define IMX219_REG_TEST_PATTERN 0x0600
#define IMX219_TEST_PATTERN_DISABLE 0
@@ -143,25 +155,66 @@ struct imx219_mode {
/* Default register values */
struct imx219_reg_list reg_list;
+
+ /* 2x2 binning is used */
+ bool binning;
};
-/*
- * Register sets lifted off the i2C interface from the Raspberry Pi firmware
- * driver.
- * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
- */
-static const struct imx219_reg mode_3280x2464_regs[] = {
- {0x0100, 0x00},
+static const struct imx219_reg imx219_common_regs[] = {
+ {0x0100, 0x00}, /* Mode Select */
+
+ /* To Access Addresses 3000-5fff, send the following commands */
{0x30eb, 0x0c},
{0x30eb, 0x05},
{0x300a, 0xff},
{0x300b, 0xff},
{0x30eb, 0x05},
{0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
+
+ /* PLL Clock Table */
+ {0x0301, 0x05}, /* VTPXCK_DIV */
+ {0x0303, 0x01}, /* VTSYSCK_DIV */
+ {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */
+ {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */
+ {0x0306, 0x00}, /* PLL_VT_MPY */
+ {0x0307, 0x39},
+ {0x030b, 0x01}, /* OP_SYS_CLK_DIV */
+ {0x030c, 0x00}, /* PLL_OP_MPY */
+ {0x030d, 0x72},
+
+ /* Undocumented registers */
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+
+ /* Frame Bank Register Group "A" */
+ {0x0162, 0x0d}, /* Line_Length_A */
+ {0x0163, 0x78},
+ {0x0170, 0x01}, /* X_ODD_INC_A */
+ {0x0171, 0x01}, /* Y_ODD_INC_A */
+
+ /* Output setup registers */
+ {0x0114, 0x01}, /* CSI 2-Lane Mode */
+ {0x0128, 0x00}, /* DPHY Auto Mode */
+ {0x012a, 0x18}, /* EXCK_Freq */
{0x012b, 0x00},
+};
+
+/*
+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
+ * driver.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
+ */
+static const struct imx219_reg mode_3280x2464_regs[] = {
{0x0164, 0x00},
{0x0165, 0x00},
{0x0166, 0x0c},
@@ -174,53 +227,13 @@ static const struct imx219_reg mode_3280x2464_regs[] = {
{0x016d, 0xd0},
{0x016e, 0x09},
{0x016f, 0xa0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x00},
- {0x0175, 0x00},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x0c},
{0x0625, 0xd0},
{0x0626, 0x09},
{0x0627, 0xa0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
- {0x0162, 0x0d},
- {0x0163, 0x78},
};
static const struct imx219_reg mode_1920_1080_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x05},
- {0x30eb, 0x0c},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
- {0x0162, 0x0d},
- {0x0163, 0x78},
{0x0164, 0x02},
{0x0165, 0xa8},
{0x0166, 0x0a},
@@ -233,49 +246,13 @@ static const struct imx219_reg mode_1920_1080_regs[] = {
{0x016d, 0x80},
{0x016e, 0x04},
{0x016f, 0x38},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x00},
- {0x0175, 0x00},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x07},
{0x0625, 0x80},
{0x0626, 0x04},
{0x0627, 0x38},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
};
static const struct imx219_reg mode_1640_1232_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x0c},
- {0x30eb, 0x05},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
{0x0164, 0x00},
{0x0165, 0x00},
{0x0166, 0x0c},
@@ -288,53 +265,13 @@ static const struct imx219_reg mode_1640_1232_regs[] = {
{0x016d, 0x68},
{0x016e, 0x04},
{0x016f, 0xd0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x01},
- {0x0175, 0x01},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x06},
{0x0625, 0x68},
{0x0626, 0x04},
{0x0627, 0xd0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
- {0x0162, 0x0d},
- {0x0163, 0x78},
};
static const struct imx219_reg mode_640_480_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x05},
- {0x30eb, 0x0c},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
- {0x0162, 0x0d},
- {0x0163, 0x78},
{0x0164, 0x03},
{0x0165, 0xe8},
{0x0166, 0x08},
@@ -347,35 +284,10 @@ static const struct imx219_reg mode_640_480_regs[] = {
{0x016d, 0x80},
{0x016e, 0x01},
{0x016f, 0xe0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x03},
- {0x0175, 0x03},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x06},
{0x0625, 0x68},
{0x0626, 0x04},
{0x0627, 0xd0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
};
static const struct imx219_reg raw8_framefmt_regs[] = {
@@ -394,6 +306,10 @@ static const s64 imx219_link_freq_menu[] = {
IMX219_DEFAULT_LINK_FREQ,
};
+static const s64 imx219_link_freq_4lane_menu[] = {
+ IMX219_DEFAULT_LINK_FREQ_4LANE,
+};
+
static const char * const imx219_test_pattern_menu[] = {
"Disabled",
"Color Bars",
@@ -485,6 +401,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
.regs = mode_3280x2464_regs,
},
+ .binning = false,
},
{
/* 1080P 30fps cropped */
@@ -501,6 +418,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
.regs = mode_1920_1080_regs,
},
+ .binning = false,
},
{
/* 2x2 binned 30fps mode */
@@ -517,6 +435,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
.regs = mode_1640_1232_regs,
},
+ .binning = true,
},
{
/* 640x480 30fps mode */
@@ -533,6 +452,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_640_480_regs),
.regs = mode_640_480_regs,
},
+ .binning = true,
},
};
@@ -569,6 +489,9 @@ struct imx219 {
/* Streaming on/off */
bool streaming;
+
+ /* Two or Four lanes */
+ u8 lanes;
};
static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
@@ -979,6 +902,35 @@ static int imx219_set_framefmt(struct imx219 *imx219)
return -EINVAL;
}
+static int imx219_set_binning(struct imx219 *imx219)
+{
+ if (!imx219->mode->binning) {
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_NONE);
+ }
+
+ switch (imx219->fmt.code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_2X2_ANALOG);
+
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_2X2);
+ }
+
+ return -EINVAL;
+}
+
static const struct v4l2_rect *
__imx219_get_pad_crop(struct imx219 *imx219,
struct v4l2_subdev_state *sd_state,
@@ -1031,6 +983,13 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
+static int imx219_configure_lanes(struct imx219 *imx219)
+{
+ return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE,
+ IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ?
+ IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
+};
+
static int imx219_start_streaming(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -1041,6 +1000,20 @@ static int imx219_start_streaming(struct imx219 *imx219)
if (ret < 0)
return ret;
+ /* Send all registers that are common to all modes */
+ ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs));
+ if (ret) {
+ dev_err(&client->dev, "%s failed to send mfg header\n", __func__);
+ goto err_rpm_put;
+ }
+
+ /* Configure two or four Lane mode */
+ ret = imx219_configure_lanes(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to configure lanes\n", __func__);
+ goto err_rpm_put;
+ }
+
/* Apply default values of current mode */
reg_list = &imx219->mode->reg_list;
ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
@@ -1056,6 +1029,13 @@ static int imx219_start_streaming(struct imx219 *imx219)
goto err_rpm_put;
}
+ ret = imx219_set_binning(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set binning: %d\n",
+ __func__, ret);
+ goto err_rpm_put;
+ }
+
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
if (ret)
@@ -1272,6 +1252,11 @@ static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
.open = imx219_open,
};
+static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
+{
+ return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
+}
+
/* Initialize control handlers */
static int imx219_init_controls(struct imx219 *imx219)
{
@@ -1293,15 +1278,16 @@ static int imx219_init_controls(struct imx219 *imx219)
/* By default, PIXEL_RATE is read only */
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_PIXEL_RATE,
- IMX219_PIXEL_RATE,
- IMX219_PIXEL_RATE, 1,
- IMX219_PIXEL_RATE);
+ imx219_get_pixel_rate(imx219),
+ imx219_get_pixel_rate(imx219), 1,
+ imx219_get_pixel_rate(imx219));
imx219->link_freq =
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
- imx219_link_freq_menu);
+ (imx219->lanes == 2) ? imx219_link_freq_menu :
+ imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -1396,7 +1382,7 @@ static void imx219_free_controls(struct imx219 *imx219)
mutex_destroy(&imx219->mutex);
}
-static int imx219_check_hwcfg(struct device *dev)
+static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
{
struct fwnode_handle *endpoint;
struct v4l2_fwnode_endpoint ep_cfg = {
@@ -1416,10 +1402,12 @@ static int imx219_check_hwcfg(struct device *dev)
}
/* Check the number of MIPI CSI2 data lanes */
- if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
- dev_err(dev, "only 2 data lanes are currently supported\n");
+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
+ ep_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ dev_err(dev, "only 2 or 4 data lanes are currently supported\n");
goto error_out;
}
+ imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;
/* Check the link frequency set in device tree */
if (!ep_cfg.nr_of_link_frequencies) {
@@ -1428,7 +1416,8 @@ static int imx219_check_hwcfg(struct device *dev)
}
if (ep_cfg.nr_of_link_frequencies != 1 ||
- ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
+ (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
+ IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
dev_err(dev, "Link frequency not supported: %lld\n",
ep_cfg.link_frequencies[0]);
goto error_out;
@@ -1456,7 +1445,7 @@ static int imx219_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
/* Check the hardware configuration in device tree */
- if (imx219_check_hwcfg(dev))
+ if (imx219_check_hwcfg(dev, imx219))
return -EINVAL;
/* Get system clock (xclk) */
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 218ded13fd80..49d6c8bdec41 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -152,13 +152,10 @@
#define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920
#define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080
-static const char * const imx290_supply_name[] = {
- "vdda",
- "vddd",
- "vdddo",
-};
+/* Equivalent value for 16bpp */
+#define IMX290_BLACK_LEVEL_DEFAULT 3840
-#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name)
+#define IMX290_NUM_SUPPLIES 3
struct imx290_regval {
u32 reg;
@@ -180,11 +177,10 @@ struct imx290 {
struct clk *xclk;
struct regmap *regmap;
u8 nlanes;
- u8 bpp;
struct v4l2_subdev sd;
struct media_pad pad;
- struct v4l2_mbus_framefmt current_format;
+
const struct imx290_mode *current_mode;
struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES];
@@ -195,35 +191,16 @@ struct imx290 {
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
-
- struct mutex lock;
-};
-
-struct imx290_pixfmt {
- u32 code;
- u8 bpp;
-};
-
-static const struct imx290_pixfmt imx290_formats[] = {
- { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
- { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
};
-static const struct regmap_config imx290_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
-};
+static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx290, sd);
+}
-static const char * const imx290_test_pattern_menu[] = {
- "Disabled",
- "Sequence Pattern 1",
- "Horizontal Color-bar Chart",
- "Vertical Color-bar Chart",
- "Sequence Pattern 2",
- "Gradation Pattern 1",
- "Gradation Pattern 2",
- "000/555h Toggle Pattern",
-};
+/* -----------------------------------------------------------------------------
+ * Modes and formats
+ */
static const struct imx290_regval imx290_global_init_settings[] = {
{ IMX290_CTRL_07, IMX290_WINMODE_1080P },
@@ -338,7 +315,6 @@ static const struct imx290_regval imx290_10bit_settings[] = {
{ IMX290_ADBIT2, IMX290_ADBIT2_10BIT },
{ IMX290_ADBIT3, IMX290_ADBIT3_10BIT },
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 },
- { IMX290_BLKLEVEL, 60 },
};
static const struct imx290_regval imx290_12bit_settings[] = {
@@ -348,7 +324,6 @@ static const struct imx290_regval imx290_12bit_settings[] = {
{ IMX290_ADBIT2, IMX290_ADBIT2_12BIT },
{ IMX290_ADBIT3, IMX290_ADBIT3_12BIT },
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 },
- { IMX290_BLKLEVEL, 240 },
};
/* supported link frequencies */
@@ -438,11 +413,45 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
return ARRAY_SIZE(imx290_modes_4lanes);
}
-static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
+struct imx290_format_info {
+ u32 code;
+ u8 bpp;
+ const struct imx290_regval *regs;
+ unsigned int num_regs;
+};
+
+static const struct imx290_format_info imx290_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .bpp = 10,
+ .regs = imx290_10bit_settings,
+ .num_regs = ARRAY_SIZE(imx290_10bit_settings),
+ }, {
+ .code = MEDIA_BUS_FMT_SRGGB12_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)
{
- return container_of(_sd, struct imx290, sd);
+ 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)
+ return info;
+ }
+
+ return NULL;
}
+/* -----------------------------------------------------------------------------
+ * Register access
+ */
+
static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value)
{
u8 data[3] = { 0, 0, 0 };
@@ -501,28 +510,82 @@ static int imx290_set_register_array(struct imx290 *imx290,
return 0;
}
-/* Stop streaming */
-static int imx290_stop_streaming(struct imx290 *imx290)
+static int imx290_set_data_lanes(struct imx290 *imx290)
{
int ret = 0;
+ u32 frsel;
- imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
+ switch (imx290->nlanes) {
+ case 2:
+ default:
+ frsel = 0x02;
+ break;
+ case 4:
+ frsel = 0x01;
+ break;
+ }
- msleep(30);
+ 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);
- return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
+ return ret;
+}
+
+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;
+
+ return imx290_write(imx290, IMX290_BLKLEVEL,
+ black_level >> (16 - bpp), err);
+}
+
+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);
+
+ ret = imx290_set_register_array(imx290, info->regs, info->num_regs);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set format registers\n");
+ return ret;
+ }
+
+ return imx290_set_black_level(imx290, format,
+ IMX290_BLACK_LEVEL_DEFAULT, &ret);
}
+/* ----------------------------------------------------------------------------
+ * Controls
+ */
+
static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx290 *imx290 = container_of(ctrl->handler,
struct imx290, ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
int ret = 0;
+ /*
+ * Return immediately for controls that don't need to be applied to the
+ * device.
+ */
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return 0;
+
/* V4L2 controls values will be applied only when power is already up */
if (!pm_runtime_get_if_in_use(imx290->dev))
return 0;
+ state = v4l2_subdev_get_locked_active_state(&imx290->sd);
+ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL);
@@ -535,7 +598,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
- imx290_write(imx290, IMX290_BLKLEVEL, 0, &ret);
+ imx290_set_black_level(imx290, format, 0, &ret);
usleep_range(10000, 11000);
imx290_write(imx290, IMX290_PGCTRL,
(u8)(IMX290_PGCTRL_REGEN |
@@ -544,20 +607,18 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
} else {
imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret);
usleep_range(10000, 11000);
- if (imx290->bpp == 10)
- imx290_write(imx290, IMX290_BLKLEVEL, 0x3c,
- &ret);
- else /* 12 bits per pixel */
- imx290_write(imx290, IMX290_BLKLEVEL, 0xf0,
- &ret);
+ imx290_set_black_level(imx290, format,
+ IMX290_BLACK_LEVEL_DEFAULT, &ret);
}
break;
+
default:
ret = -EINVAL;
break;
}
- pm_runtime_put(imx290->dev);
+ pm_runtime_mark_last_busy(imx290->dev);
+ pm_runtime_put_autosuspend(imx290->dev);
return ret;
}
@@ -566,14 +627,217 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
.s_ctrl = imx290_set_ctrl,
};
-static struct v4l2_mbus_framefmt *
-imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state,
- u32 which)
+static const char * const imx290_test_pattern_menu[] = {
+ "Disabled",
+ "Sequence Pattern 1",
+ "Horizontal Color-bar Chart",
+ "Vertical Color-bar Chart",
+ "Sequence Pattern 2",
+ "Gradation Pattern 1",
+ "Gradation Pattern 2",
+ "000/555h Toggle Pattern",
+};
+
+static void imx290_ctrl_update(struct imx290 *imx290,
+ const struct v4l2_mbus_framefmt *format,
+ const struct imx290_mode *mode)
{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &imx290->current_format;
- else
- return v4l2_subdev_get_try_format(&imx290->sd, state, 0);
+ 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);
+
+ __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);
+}
+
+static int imx290_ctrl_init(struct imx290 *imx290)
+{
+ struct v4l2_fwnode_device_properties props;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(imx290->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&imx290->ctrls, 9);
+
+ /*
+ * The sensor has an analog gain and a digital gain, both controlled
+ * through a single gain value, expressed in 0.3dB increments. Values
+ * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
+ * up to 72.0dB (240) add further digital gain. Limit the range to
+ * analog gain only, support for digital gain can be added separately
+ * if needed.
+ *
+ * The IMX327 and IMX462 are largely compatible with the IMX290, but
+ * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
+ * gain. When support for those sensors gets added to the driver, the
+ * gain control should be adjusted accordingly.
+ */
+ 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);
+
+ /*
+ * Set the link frequency, pixel rate, horizontal blanking and vertical
+ * blanking to hardcoded values, they will be updated by
+ * imx290_ctrl_update().
+ */
+ imx290->link_freq =
+ v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ imx290_link_freqs_num(imx290) - 1, 0,
+ imx290_link_freqs_ptr(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_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx290_test_pattern_menu) - 1,
+ 0, 0, imx290_test_pattern_menu);
+
+ 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;
+
+ v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
+ &props);
+
+ imx290->sd.ctrl_handler = &imx290->ctrls;
+
+ if (imx290->ctrls.error) {
+ ret = imx290->ctrls.error;
+ v4l2_ctrl_handler_free(&imx290->ctrls);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Subdev operations
+ */
+
+/* Start streaming */
+static int imx290_start_streaming(struct imx290 *imx290,
+ struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ int ret;
+
+ /* Set init register settings */
+ ret = imx290_set_register_array(imx290, 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 data lane count */
+ ret = imx290_set_data_lanes(imx290);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set data lanes\n");
+ return ret;
+ }
+
+ /* Apply the register values related to current frame format */
+ 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");
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ 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");
+ 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");
+ return ret;
+ }
+
+ imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
+
+ msleep(30);
+
+ /* Start streaming */
+ return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
+}
+
+/* Stop streaming */
+static int imx290_stop_streaming(struct imx290 *imx290)
+{
+ int ret = 0;
+
+ imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
+
+ msleep(30);
+
+ return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
+}
+
+static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx290 *imx290 = to_imx290(sd);
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(imx290->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx290_start_streaming(imx290, state);
+ if (ret) {
+ dev_err(imx290->dev, "Start stream failed\n");
+ pm_runtime_put_sync(imx290->dev);
+ goto unlock;
+ }
+ } else {
+ imx290_stop_streaming(imx290);
+ pm_runtime_mark_last_busy(imx290->dev);
+ pm_runtime_put_autosuspend(imx290->dev);
+ }
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+ return ret;
}
static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
@@ -595,8 +859,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 ((fse->code != imx290_formats[0].code) &&
- (fse->code != imx290_formats[1].code))
+ if (!imx290_format_info(fse->code))
return -EINVAL;
if (fse->index >= imx290_modes_num(imx290))
@@ -610,47 +873,6 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int imx290_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct imx290 *imx290 = to_imx290(sd);
- struct v4l2_mbus_framefmt *framefmt;
-
- mutex_lock(&imx290->lock);
-
- framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which);
- fmt->format = *framefmt;
-
- mutex_unlock(&imx290->lock);
-
- return 0;
-}
-
-static inline u8 imx290_get_link_freq_index(struct imx290 *imx290)
-{
- return imx290->current_mode->link_freq_index;
-}
-
-static s64 imx290_get_link_freq(struct imx290 *imx290)
-{
- u8 index = imx290_get_link_freq_index(imx290);
-
- return *(imx290_link_freqs_ptr(imx290) + index);
-}
-
-static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
-{
- s64 link_freq = imx290_get_link_freq(imx290);
- u8 nlanes = imx290->nlanes;
- u64 pixel_rate;
-
- /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- pixel_rate = link_freq * 2 * nlanes;
- do_div(pixel_rate, imx290->bpp);
- return pixel_rate;
-}
-
static int imx290_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -658,9 +880,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *mode;
struct v4l2_mbus_framefmt *format;
- unsigned int i;
-
- mutex_lock(&imx290->lock);
mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290),
imx290_modes_num(imx290), width, height,
@@ -669,48 +888,21 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- for (i = 0; i < ARRAY_SIZE(imx290_formats); i++)
- if (imx290_formats[i].code == fmt->format.code)
- break;
-
- if (i >= ARRAY_SIZE(imx290_formats))
- i = 0;
+ if (!imx290_format_info(fmt->format.code))
+ fmt->format.code = imx290_formats[0].code;
- fmt->format.code = imx290_formats[i].code;
fmt->format.field = V4L2_FIELD_NONE;
- format = imx290_get_pad_format(imx290, sd_state, fmt->which);
+ format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
imx290->current_mode = mode;
- imx290->bpp = imx290_formats[i].bpp;
-
- if (imx290->link_freq)
- __v4l2_ctrl_s_ctrl(imx290->link_freq,
- imx290_get_link_freq_index(imx290));
- if (imx290->pixel_rate)
- __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
- imx290_calc_pixel_rate(imx290));
-
- if (imx290->hblank) {
- unsigned int hblank = mode->hmax - mode->width;
-
- __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank,
- 1, hblank);
- }
-
- if (imx290->vblank) {
- unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height;
- __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank,
- 1, vblank);
- }
+ imx290_ctrl_update(imx290, &fmt->format, mode);
}
*format = fmt->format;
- mutex_unlock(&imx290->lock);
-
return 0;
}
@@ -718,14 +910,11 @@ 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 = imx290_get_pad_format(imx290, sd_state, sel->which);
-
- mutex_lock(&imx290->lock);
+ format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP
+ (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2;
@@ -734,7 +923,6 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
sel->r.width = format->width;
sel->r.height = format->height;
- mutex_unlock(&imx290->lock);
return 0;
}
@@ -763,179 +951,116 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state)
{
- struct v4l2_subdev_format fmt = { 0 };
-
- fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.format.width = 1920;
- fmt.format.height = 1080;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = {
+ .width = 1920,
+ .height = 1080,
+ },
+ };
imx290_set_fmt(subdev, sd_state, &fmt);
return 0;
}
-static int imx290_write_current_format(struct imx290 *imx290)
-{
- int ret;
+static const struct v4l2_subdev_video_ops imx290_video_ops = {
+ .s_stream = imx290_set_stream,
+};
- switch (imx290->current_format.code) {
- case MEDIA_BUS_FMT_SRGGB10_1X10:
- ret = imx290_set_register_array(imx290, imx290_10bit_settings,
- ARRAY_SIZE(
- imx290_10bit_settings));
- if (ret < 0) {
- dev_err(imx290->dev, "Could not set format registers\n");
- return ret;
- }
- break;
- case MEDIA_BUS_FMT_SRGGB12_1X12:
- ret = imx290_set_register_array(imx290, imx290_12bit_settings,
- ARRAY_SIZE(
- imx290_12bit_settings));
- if (ret < 0) {
- dev_err(imx290->dev, "Could not set format registers\n");
- return ret;
- }
- break;
- default:
- dev_err(imx290->dev, "Unknown pixel format\n");
- return -EINVAL;
- }
+static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
+ .init_cfg = imx290_entity_init_cfg,
+ .enum_mbus_code = imx290_enum_mbus_code,
+ .enum_frame_size = imx290_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx290_set_fmt,
+ .get_selection = imx290_get_selection,
+};
- return 0;
-}
+static const struct v4l2_subdev_ops imx290_subdev_ops = {
+ .video = &imx290_video_ops,
+ .pad = &imx290_pad_ops,
+};
-/* Start streaming */
-static int imx290_start_streaming(struct imx290 *imx290)
+static const struct media_entity_operations imx290_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int imx290_subdev_init(struct imx290 *imx290)
{
+ struct i2c_client *client = to_i2c_client(imx290->dev);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
int ret;
- /* Set init register settings */
- ret = imx290_set_register_array(imx290, 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;
- }
+ imx290->current_mode = &imx290_modes_ptr(imx290)[0];
- /* Apply the register values related to current frame format */
- ret = imx290_write_current_format(imx290);
+ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
+ imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx290->sd.dev = imx290->dev;
+ imx290->sd.entity.ops = &imx290_subdev_entity_ops;
+ imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ imx290->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set frame format\n");
+ dev_err(imx290->dev, "Could not register media entity\n");
return ret;
}
- /* Apply default values of current mode */
- ret = imx290_set_register_array(imx290, imx290->current_mode->data,
- imx290->current_mode->data_size);
+ ret = imx290_ctrl_init(imx290);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set current mode\n");
- return ret;
+ dev_err(imx290->dev, "Control initialization error %d\n", ret);
+ goto err_media;
}
- ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
- NULL);
- if (ret)
- return ret;
+ imx290->sd.state_lock = imx290->ctrls.lock;
- /* 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");
- return ret;
+ ret = v4l2_subdev_init_finalize(&imx290->sd);
+ if (ret < 0) {
+ dev_err(imx290->dev, "subdev initialization error %d\n", ret);
+ goto err_ctrls;
}
- imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
-
- msleep(30);
-
- /* Start streaming */
- return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
-}
-
-static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct imx290 *imx290 = to_imx290(sd);
- int ret = 0;
+ state = v4l2_subdev_lock_and_get_active_state(&imx290->sd);
+ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+ imx290_ctrl_update(imx290, format, imx290->current_mode);
+ v4l2_subdev_unlock_state(state);
- if (enable) {
- ret = pm_runtime_resume_and_get(imx290->dev);
- if (ret < 0)
- goto unlock_and_return;
-
- ret = imx290_start_streaming(imx290);
- if (ret) {
- dev_err(imx290->dev, "Start stream failed\n");
- pm_runtime_put(imx290->dev);
- goto unlock_and_return;
- }
- } else {
- imx290_stop_streaming(imx290);
- pm_runtime_put(imx290->dev);
- }
-
-unlock_and_return:
+ return 0;
+err_ctrls:
+ v4l2_ctrl_handler_free(&imx290->ctrls);
+err_media:
+ media_entity_cleanup(&imx290->sd.entity);
return ret;
}
-static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
+static void imx290_subdev_cleanup(struct imx290 *imx290)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
- imx290->supplies[i].supply = imx290_supply_name[i];
-
- return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
- imx290->supplies);
+ v4l2_subdev_cleanup(&imx290->sd);
+ media_entity_cleanup(&imx290->sd.entity);
+ v4l2_ctrl_handler_free(&imx290->ctrls);
}
-static int imx290_set_data_lanes(struct imx290 *imx290)
-{
- int ret = 0, laneval, frsel;
-
- switch (imx290->nlanes) {
- case 2:
- laneval = 0x01;
- frsel = 0x02;
- break;
- case 4:
- laneval = 0x03;
- frsel = 0x01;
- break;
- default:
- /*
- * We should never hit this since the data lane count is
- * validated in probe itself
- */
- dev_err(imx290->dev, "Lane configuration not supported\n");
- return -EINVAL;
- }
-
- imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret);
- imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret);
- imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
-
- return ret;
-}
+/* ----------------------------------------------------------------------------
+ * Power management
+ */
-static int imx290_power_on(struct device *dev)
+static int imx290_power_on(struct imx290 *imx290)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct imx290 *imx290 = to_imx290(sd);
int ret;
ret = clk_prepare_enable(imx290->xclk);
if (ret) {
- dev_err(dev, "Failed to enable clock\n");
+ dev_err(imx290->dev, "Failed to enable clock\n");
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies),
imx290->supplies);
if (ret) {
- dev_err(dev, "Failed to enable regulators\n");
+ dev_err(imx290->dev, "Failed to enable regulators\n");
clk_disable_unprepare(imx290->xclk);
return ret;
}
@@ -944,123 +1069,86 @@ static int imx290_power_on(struct device *dev)
gpiod_set_value_cansleep(imx290->rst_gpio, 0);
usleep_range(30000, 31000);
- /* Set data lane count */
- imx290_set_data_lanes(imx290);
-
return 0;
}
-static int imx290_power_off(struct device *dev)
+static void imx290_power_off(struct imx290 *imx290)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct imx290 *imx290 = to_imx290(sd);
-
clk_disable_unprepare(imx290->xclk);
gpiod_set_value_cansleep(imx290->rst_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies);
+}
+
+static int imx290_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx290 *imx290 = to_imx290(sd);
+
+ return imx290_power_on(imx290);
+}
+
+static int imx290_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx290 *imx290 = to_imx290(sd);
+
+ imx290_power_off(imx290);
return 0;
}
static const struct dev_pm_ops imx290_pm_ops = {
- SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL)
-};
-
-static const struct v4l2_subdev_video_ops imx290_video_ops = {
- .s_stream = imx290_set_stream,
+ SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL)
};
-static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
- .init_cfg = imx290_entity_init_cfg,
- .enum_mbus_code = imx290_enum_mbus_code,
- .enum_frame_size = imx290_enum_frame_size,
- .get_fmt = imx290_get_fmt,
- .set_fmt = imx290_set_fmt,
- .get_selection = imx290_get_selection,
-};
+/* ----------------------------------------------------------------------------
+ * Probe & remove
+ */
-static const struct v4l2_subdev_ops imx290_subdev_ops = {
- .video = &imx290_video_ops,
- .pad = &imx290_pad_ops,
+static const struct regmap_config imx290_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
};
-static const struct media_entity_operations imx290_subdev_entity_ops = {
- .link_validate = v4l2_subdev_link_validate,
+static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = {
+ "vdda",
+ "vddd",
+ "vdddo",
};
-static int imx290_ctrl_init(struct imx290 *imx290)
+static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
{
- struct v4l2_fwnode_device_properties props;
- unsigned int blank;
- int ret;
-
- ret = v4l2_fwnode_device_parse(imx290->dev, &props);
- if (ret < 0)
- return ret;
-
- v4l2_ctrl_handler_init(&imx290->ctrls, 9);
- imx290->ctrls.lock = &imx290->lock;
-
- /*
- * The sensor has an analog gain and a digital gain, both controlled
- * through a single gain value, expressed in 0.3dB increments. Values
- * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
- * up to 72.0dB (240) add further digital gain. Limit the range to
- * analog gain only, support for digital gain can be added separately
- * if needed.
- *
- * The IMX327 and IMX462 are largely compatible with the IMX290, but
- * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
- * gain. When support for those sensors gets added to the driver, the
- * gain control should be adjusted accordingly.
- */
- 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);
-
- imx290->link_freq =
- v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_LINK_FREQ,
- imx290_link_freqs_num(imx290) - 1, 0,
- imx290_link_freqs_ptr(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,
- imx290_calc_pixel_rate(imx290));
+ unsigned int i;
- 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);
+ for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
+ imx290->supplies[i].supply = imx290_supply_name[i];
- blank = imx290->current_mode->hmax - imx290->current_mode->width;
- imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_HBLANK, blank, blank, 1,
- blank);
- if (imx290->hblank)
- imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
+ imx290->supplies);
+}
- blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height;
- imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_VBLANK, blank, blank, 1,
- blank);
- if (imx290->vblank)
- imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+static int imx290_init_clk(struct imx290 *imx290)
+{
+ u32 xclk_freq;
+ int ret;
- v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
- &props);
+ ret = fwnode_property_read_u32(dev_fwnode(imx290->dev),
+ "clock-frequency", &xclk_freq);
+ if (ret) {
+ dev_err(imx290->dev, "Could not get xclk frequency\n");
+ return ret;
+ }
- imx290->sd.ctrl_handler = &imx290->ctrls;
+ /* external clock must be 37.125 MHz */
+ if (xclk_freq != 37125000) {
+ dev_err(imx290->dev, "External clock frequency %u is not supported\n",
+ xclk_freq);
+ return -EINVAL;
+ }
- if (imx290->ctrls.error) {
- ret = imx290->ctrls.error;
- v4l2_ctrl_handler_free(&imx290->ctrls);
+ ret = clk_set_rate(imx290->xclk, xclk_freq);
+ if (ret) {
+ dev_err(imx290->dev, "Could not set xclk frequency\n");
return ret;
}
@@ -1089,171 +1177,159 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290,
return 0;
}
-static int imx290_probe(struct i2c_client *client)
+static int imx290_parse_dt(struct imx290 *imx290)
{
- struct device *dev = &client->dev;
- struct fwnode_handle *endpoint;
/* Only CSI2 is supported for now: */
struct v4l2_fwnode_endpoint ep = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
- struct imx290 *imx290;
- u32 xclk_freq;
- s64 fq;
+ struct fwnode_handle *endpoint;
int ret;
+ s64 fq;
- imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL);
- if (!imx290)
- return -ENOMEM;
-
- imx290->dev = dev;
- imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config);
- if (IS_ERR(imx290->regmap)) {
- dev_err(dev, "Unable to initialize I2C\n");
- return -ENODEV;
- }
-
- endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL);
if (!endpoint) {
- dev_err(dev, "Endpoint node not found\n");
+ dev_err(imx290->dev, "Endpoint node not found\n");
return -EINVAL;
}
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
fwnode_handle_put(endpoint);
if (ret == -ENXIO) {
- dev_err(dev, "Unsupported bus type, should be CSI2\n");
- goto free_err;
+ dev_err(imx290->dev, "Unsupported bus type, should be CSI2\n");
+ goto done;
} else if (ret) {
- dev_err(dev, "Parsing endpoint node failed\n");
- goto free_err;
+ dev_err(imx290->dev, "Parsing endpoint node failed\n");
+ goto done;
}
/* Get number of data lanes */
imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes;
if (imx290->nlanes != 2 && imx290->nlanes != 4) {
- dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes);
+ dev_err(imx290->dev, "Invalid data lanes: %d\n", imx290->nlanes);
ret = -EINVAL;
- goto free_err;
+ goto done;
}
- dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
+ dev_dbg(imx290->dev, "Using %u data lanes\n", imx290->nlanes);
if (!ep.nr_of_link_frequencies) {
- dev_err(dev, "link-frequency property not found in DT\n");
+ dev_err(imx290->dev, "link-frequency property not found in DT\n");
ret = -EINVAL;
- goto free_err;
+ goto done;
}
/* Check that link frequences for all the modes are in device tree */
fq = imx290_check_link_freqs(imx290, &ep);
if (fq) {
- dev_err(dev, "Link frequency of %lld is not supported\n", fq);
+ dev_err(imx290->dev, "Link frequency of %lld is not supported\n",
+ fq);
ret = -EINVAL;
- goto free_err;
+ goto done;
}
- /* get system clock (xclk) */
- imx290->xclk = devm_clk_get(dev, "xclk");
- if (IS_ERR(imx290->xclk)) {
- dev_err(dev, "Could not get xclk");
- ret = PTR_ERR(imx290->xclk);
- goto free_err;
- }
+ ret = 0;
- ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
- &xclk_freq);
- if (ret) {
- dev_err(dev, "Could not get xclk frequency\n");
- goto free_err;
- }
+done:
+ v4l2_fwnode_endpoint_free(&ep);
+ return ret;
+}
- /* external clock must be 37.125 MHz */
- if (xclk_freq != 37125000) {
- dev_err(dev, "External clock frequency %u is not supported\n",
- xclk_freq);
- ret = -EINVAL;
- goto free_err;
- }
+static int imx290_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx290 *imx290;
+ int ret;
- ret = clk_set_rate(imx290->xclk, xclk_freq);
- if (ret) {
- dev_err(dev, "Could not set xclk frequency\n");
- goto free_err;
+ imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL);
+ if (!imx290)
+ return -ENOMEM;
+
+ imx290->dev = dev;
+ imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config);
+ if (IS_ERR(imx290->regmap)) {
+ dev_err(dev, "Unable to initialize I2C\n");
+ return -ENODEV;
}
+ ret = imx290_parse_dt(imx290);
+ if (ret)
+ return ret;
+
+ /* Acquire resources. */
+ 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");
+
ret = imx290_get_regulators(dev, imx290);
- if (ret < 0) {
- dev_err(dev, "Cannot get regulators\n");
- goto free_err;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Cannot get regulators\n");
imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(imx290->rst_gpio)) {
- dev_err(dev, "Cannot get reset gpio\n");
- ret = PTR_ERR(imx290->rst_gpio);
- goto free_err;
- }
+ if (IS_ERR(imx290->rst_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio),
+ "Cannot get reset gpio\n");
- mutex_init(&imx290->lock);
+ /* Initialize external clock frequency. */
+ ret = imx290_init_clk(imx290);
+ if (ret)
+ return ret;
/*
- * Initialize the frame format. In particular, imx290->current_mode
- * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call
- * below relies on these fields.
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here.
*/
- imx290_entity_init_cfg(&imx290->sd, NULL);
-
- ret = imx290_ctrl_init(imx290);
+ ret = imx290_power_on(imx290);
if (ret < 0) {
- dev_err(dev, "Control initialization error %d\n", ret);
- goto free_mutex;
+ dev_err(dev, "Could not power on the device\n");
+ return ret;
}
- v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
- imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- imx290->sd.dev = &client->dev;
- imx290->sd.entity.ops = &imx290_subdev_entity_ops;
- imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ /*
+ * Enable runtime PM with autosuspend. As the device has been powered
+ * manually, mark it as active, and increase the usage count without
+ * resuming the device.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
- imx290->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad);
- if (ret < 0) {
- dev_err(dev, "Could not register media entity\n");
- goto free_ctrl;
- }
+ /* Initialize the V4L2 subdev. */
+ ret = imx290_subdev_init(imx290);
+ if (ret)
+ goto err_pm;
+ /*
+ * Finally, register the V4L2 subdev. This must be done after
+ * initializing everything as the subdev can be used immediately after
+ * being registered.
+ */
ret = v4l2_async_register_subdev(&imx290->sd);
if (ret < 0) {
dev_err(dev, "Could not register v4l2 device\n");
- goto free_entity;
- }
-
- /* Power on the device to match runtime PM state below */
- ret = imx290_power_on(dev);
- if (ret < 0) {
- dev_err(dev, "Could not power on the device\n");
- goto free_entity;
+ goto err_subdev;
}
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_runtime_idle(dev);
-
- v4l2_fwnode_endpoint_free(&ep);
+ /*
+ * Decrease the PM usage count. The device will get suspended after the
+ * autosuspend delay, turning the power off.
+ */
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return 0;
-free_entity:
- media_entity_cleanup(&imx290->sd.entity);
-free_ctrl:
- v4l2_ctrl_handler_free(&imx290->ctrls);
-free_mutex:
- mutex_destroy(&imx290->lock);
-free_err:
- v4l2_fwnode_endpoint_free(&ep);
-
+err_subdev:
+ imx290_subdev_cleanup(imx290);
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ imx290_power_off(imx290);
return ret;
}
@@ -1263,14 +1339,15 @@ static void imx290_remove(struct i2c_client *client)
struct imx290 *imx290 = to_imx290(sd);
v4l2_async_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
-
- mutex_destroy(&imx290->lock);
+ imx290_subdev_cleanup(imx290);
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
pm_runtime_disable(imx290->dev);
if (!pm_runtime_status_suspended(imx290->dev))
- imx290_power_off(imx290->dev);
+ imx290_power_off(imx290);
pm_runtime_set_suspended(imx290->dev);
}
diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c
new file mode 100644
index 000000000000..3c12b6edeac9
--- /dev/null
+++ b/drivers/media/i2c/imx296.c
@@ -0,0 +1,1172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for IMX296 CMOS Image Sensor from Sony
+ *
+ * Copyright 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <linux/clk.h>
+#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 <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define IMX296_PIXEL_ARRAY_WIDTH 1456
+#define IMX296_PIXEL_ARRAY_HEIGHT 1088
+
+#define IMX296_REG_8BIT(n) ((1 << 16) | (n))
+#define IMX296_REG_16BIT(n) ((2 << 16) | (n))
+#define IMX296_REG_24BIT(n) ((3 << 16) | (n))
+#define IMX296_REG_SIZE_SHIFT 16
+#define IMX296_REG_ADDR_MASK 0xffff
+
+#define IMX296_CTRL00 IMX296_REG_8BIT(0x3000)
+#define IMX296_CTRL00_STANDBY BIT(0)
+#define IMX296_CTRL08 IMX296_REG_8BIT(0x3008)
+#define IMX296_CTRL08_REGHOLD BIT(0)
+#define IMX296_CTRL0A IMX296_REG_8BIT(0x300a)
+#define IMX296_CTRL0A_XMSTA BIT(0)
+#define IMX296_CTRL0B IMX296_REG_8BIT(0x300b)
+#define IMX296_CTRL0B_TRIGEN BIT(0)
+#define IMX296_CTRL0D IMX296_REG_8BIT(0x300d)
+#define IMX296_CTRL0D_WINMODE_ALL (0 << 0)
+#define IMX296_CTRL0D_WINMODE_FD_BINNING (2 << 0)
+#define IMX296_CTRL0D_HADD_ON_BINNING BIT(5)
+#define IMX296_CTRL0D_SAT_CNT BIT(6)
+#define IMX296_CTRL0E IMX296_REG_8BIT(0x300e)
+#define IMX296_CTRL0E_VREVERSE BIT(0)
+#define IMX296_CTRL0E_HREVERSE BIT(1)
+#define IMX296_VMAX IMX296_REG_24BIT(0x3010)
+#define IMX296_HMAX IMX296_REG_16BIT(0x3014)
+#define IMX296_TMDCTRL IMX296_REG_8BIT(0x301d)
+#define IMX296_TMDCTRL_LATCH BIT(0)
+#define IMX296_TMDOUT IMX296_REG_16BIT(0x301e)
+#define IMX296_TMDOUT_MASK 0x3ff
+#define IMX296_WDSEL IMX296_REG_8BIT(0x3021)
+#define IMX296_WDSEL_NORMAL (0 << 0)
+#define IMX296_WDSEL_MULTI_2 (1 << 0)
+#define IMX296_WDSEL_MULTI_4 (3 << 0)
+#define IMX296_BLKLEVELAUTO IMX296_REG_8BIT(0x3022)
+#define IMX296_BLKLEVELAUTO_ON 0x01
+#define IMX296_BLKLEVELAUTO_OFF 0xf0
+#define IMX296_SST IMX296_REG_8BIT(0x3024)
+#define IMX296_SST_EN BIT(0)
+#define IMX296_CTRLTOUT IMX296_REG_8BIT(0x3026)
+#define IMX296_CTRLTOUT_TOUT1SEL_LOW (0 << 0)
+#define IMX296_CTRLTOUT_TOUT1SEL_PULSE (3 << 0)
+#define IMX296_CTRLTOUT_TOUT2SEL_LOW (0 << 2)
+#define IMX296_CTRLTOUT_TOUT2SEL_PULSE (3 << 2)
+#define IMX296_CTRLTRIG IMX296_REG_8BIT(0x3029)
+#define IMX296_CTRLTRIG_TOUT1_SEL_LOW (0 << 0)
+#define IMX296_CTRLTRIG_TOUT1_SEL_PULSE1 (1 << 0)
+#define IMX296_CTRLTRIG_TOUT2_SEL_LOW (0 << 4)
+#define IMX296_CTRLTRIG_TOUT2_SEL_PULSE2 (2 << 4)
+#define IMX296_SYNCSEL IMX296_REG_8BIT(0x3036)
+#define IMX296_SYNCSEL_NORMAL 0xc0
+#define IMX296_SYNCSEL_HIZ 0xf0
+#define IMX296_PULSE1 IMX296_REG_8BIT(0x306d)
+#define IMX296_PULSE1_EN_NOR BIT(0)
+#define IMX296_PULSE1_EN_TRIG BIT(1)
+#define IMX296_PULSE1_POL_HIGH (0 << 2)
+#define IMX296_PULSE1_POL_LOW (1 << 2)
+#define IMX296_PULSE1_UP IMX296_REG_24BIT(0x3070)
+#define IMX296_PULSE1_DN IMX296_REG_24BIT(0x3074)
+#define IMX296_PULSE2 IMX296_REG_8BIT(0x3079)
+#define IMX296_PULSE2_EN_NOR BIT(0)
+#define IMX296_PULSE2_EN_TRIG BIT(1)
+#define IMX296_PULSE2_POL_HIGH (0 << 2)
+#define IMX296_PULSE2_POL_LOW (1 << 2)
+#define IMX296_PULSE2_UP IMX296_REG_24BIT(0x307c)
+#define IMX296_PULSE2_DN IMX296_REG_24BIT(0x3080)
+#define IMX296_INCKSEL(n) IMX296_REG_8BIT(0x3089 + (n))
+#define IMX296_SHS1 IMX296_REG_24BIT(0x308d)
+#define IMX296_SHS2 IMX296_REG_24BIT(0x3090)
+#define IMX296_SHS3 IMX296_REG_24BIT(0x3094)
+#define IMX296_SHS4 IMX296_REG_24BIT(0x3098)
+#define IMX296_VBLANKLP IMX296_REG_8BIT(0x309c)
+#define IMX296_VBLANKLP_NORMAL 0x04
+#define IMX296_VBLANKLP_LOW_POWER 0x2c
+#define IMX296_EXP_CNT IMX296_REG_8BIT(0x30a3)
+#define IMX296_EXP_CNT_RESET BIT(0)
+#define IMX296_EXP_MAX IMX296_REG_16BIT(0x30a6)
+#define IMX296_VINT IMX296_REG_8BIT(0x30aa)
+#define IMX296_VINT_EN BIT(0)
+#define IMX296_LOWLAGTRG IMX296_REG_8BIT(0x30ae)
+#define IMX296_LOWLAGTRG_FAST BIT(0)
+#define IMX296_I2CCTRL IMX296_REG_8BIT(0x30ef)
+#define IMX296_I2CCTRL_I2CACKEN BIT(0)
+
+#define IMX296_SENSOR_INFO IMX296_REG_16BIT(0x3148)
+#define IMX296_SENSOR_INFO_MONO BIT(15)
+#define IMX296_SENSOR_INFO_IMX296LQ 0x4a00
+#define IMX296_SENSOR_INFO_IMX296LL 0xca00
+#define IMX296_S_SHSA IMX296_REG_16BIT(0x31ca)
+#define IMX296_S_SHSB IMX296_REG_16BIT(0x31d2)
+/*
+ * Registers 0x31c8 to 0x31cd, 0x31d0 to 0x31d5, 0x31e2, 0x31e3, 0x31ea and
+ * 0x31eb are related to exposure mode but otherwise not documented.
+ */
+
+#define IMX296_GAINCTRL IMX296_REG_8BIT(0x3200)
+#define IMX296_GAINCTRL_WD_GAIN_MODE_NORMAL 0x01
+#define IMX296_GAINCTRL_WD_GAIN_MODE_MULTI 0x41
+#define IMX296_GAIN IMX296_REG_16BIT(0x3204)
+#define IMX296_GAIN_MIN 0
+#define IMX296_GAIN_MAX 480
+#define IMX296_GAIN1 IMX296_REG_16BIT(0x3208)
+#define IMX296_GAIN2 IMX296_REG_16BIT(0x320c)
+#define IMX296_GAIN3 IMX296_REG_16BIT(0x3210)
+#define IMX296_GAINDLY IMX296_REG_8BIT(0x3212)
+#define IMX296_GAINDLY_NONE 0x08
+#define IMX296_GAINDLY_1FRAME 0x09
+#define IMX296_PGCTRL IMX296_REG_8BIT(0x3238)
+#define IMX296_PGCTRL_REGEN BIT(0)
+#define IMX296_PGCTRL_THRU BIT(1)
+#define IMX296_PGCTRL_CLKEN BIT(2)
+#define IMX296_PGCTRL_MODE(n) ((n) << 3)
+#define IMX296_PGHPOS IMX296_REG_16BIT(0x3239)
+#define IMX296_PGVPOS IMX296_REG_16BIT(0x323c)
+#define IMX296_PGHPSTEP IMX296_REG_8BIT(0x323e)
+#define IMX296_PGVPSTEP IMX296_REG_8BIT(0x323f)
+#define IMX296_PGHPNUM IMX296_REG_8BIT(0x3240)
+#define IMX296_PGVPNUM IMX296_REG_8BIT(0x3241)
+#define IMX296_PGDATA1 IMX296_REG_16BIT(0x3244)
+#define IMX296_PGDATA2 IMX296_REG_16BIT(0x3246)
+#define IMX296_PGHGSTEP IMX296_REG_8BIT(0x3249)
+#define IMX296_BLKLEVEL IMX296_REG_16BIT(0x3254)
+
+#define IMX296_FID0_ROI IMX296_REG_8BIT(0x3300)
+#define IMX296_FID0_ROIH1ON BIT(0)
+#define IMX296_FID0_ROIV1ON BIT(1)
+#define IMX296_FID0_ROIPH1 IMX296_REG_16BIT(0x3310)
+#define IMX296_FID0_ROIPV1 IMX296_REG_16BIT(0x3312)
+#define IMX296_FID0_ROIWH1 IMX296_REG_16BIT(0x3314)
+#define IMX296_FID0_ROIWH1_MIN 80
+#define IMX296_FID0_ROIWV1 IMX296_REG_16BIT(0x3316)
+#define IMX296_FID0_ROIWV1_MIN 4
+
+#define IMX296_CM_HSST_STARTTMG IMX296_REG_16BIT(0x4018)
+#define IMX296_CM_HSST_ENDTMG IMX296_REG_16BIT(0x401a)
+#define IMX296_DA_HSST_STARTTMG IMX296_REG_16BIT(0x404d)
+#define IMX296_DA_HSST_ENDTMG IMX296_REG_16BIT(0x4050)
+#define IMX296_LM_HSST_STARTTMG IMX296_REG_16BIT(0x4094)
+#define IMX296_LM_HSST_ENDTMG IMX296_REG_16BIT(0x4096)
+#define IMX296_SST_SIEASTA1_SET IMX296_REG_8BIT(0x40c9)
+#define IMX296_SST_SIEASTA1PRE_1U IMX296_REG_16BIT(0x40cc)
+#define IMX296_SST_SIEASTA1PRE_1D IMX296_REG_16BIT(0x40ce)
+#define IMX296_SST_SIEASTA1PRE_2U IMX296_REG_16BIT(0x40d0)
+#define IMX296_SST_SIEASTA1PRE_2D IMX296_REG_16BIT(0x40d2)
+#define IMX296_HSST IMX296_REG_8BIT(0x40dc)
+#define IMX296_HSST_EN BIT(2)
+
+#define IMX296_CKREQSEL IMX296_REG_8BIT(0x4101)
+#define IMX296_CKREQSEL_HS BIT(2)
+#define IMX296_GTTABLENUM IMX296_REG_8BIT(0x4114)
+#define IMX296_CTRL418C IMX296_REG_8BIT(0x418c)
+
+struct imx296_clk_params {
+ unsigned int freq;
+ u8 incksel[4];
+ u8 ctrl418c;
+};
+
+static const struct imx296_clk_params imx296_clk_params[] = {
+ { 37125000, { 0x80, 0x0b, 0x80, 0x08 }, 116 },
+ { 54000000, { 0xb0, 0x0f, 0xb0, 0x0c }, 168 },
+ { 74250000, { 0x80, 0x0f, 0x80, 0x0c }, 232 },
+};
+
+static const char * const imx296_supply_names[] = {
+ "dvdd",
+ "ovdd",
+ "avdd",
+};
+
+struct imx296 {
+ struct device *dev;
+ struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)];
+ struct gpio_desc *reset;
+ struct regmap *regmap;
+
+ const struct imx296_clk_params *clk_params;
+ bool mono;
+
+ bool streaming;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+};
+
+static inline struct imx296 *to_imx296(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx296, subdev);
+}
+
+static int imx296_read(struct imx296 *sensor, u32 addr)
+{
+ u8 data[3] = { 0, 0, 0 };
+ int ret;
+
+ ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data,
+ (addr >> IMX296_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ return ret;
+
+ return (data[2] << 16) | (data[1] << 8) | data[0];
+}
+
+static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err)
+{
+ u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
+ int ret;
+
+ if (err && *err)
+ return *err;
+
+ ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK,
+ data, (addr >> IMX296_REG_SIZE_SHIFT) & 3);
+ if (ret < 0) {
+ dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n",
+ ((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX296_REG_ADDR_MASK, ret);
+ if (err)
+ *err = ret;
+ }
+
+ return ret;
+}
+
+static int imx296_power_on(struct imx296 *sensor)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret < 0)
+ return ret;
+
+ udelay(1);
+
+ ret = gpiod_direction_output(sensor->reset, 0);
+ if (ret < 0)
+ goto err_supply;
+
+ udelay(1);
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret < 0)
+ goto err_reset;
+
+ /*
+ * The documentation doesn't explicitly say how much time is required
+ * after providing a clock and before starting I2C communication. It
+ * mentions a delay of 20µs in 4-wire mode, but tests showed that a
+ * delay of 100µs resulted in I2C communication failures, while 500µs
+ * seems to be enough. Be conservative.
+ */
+ usleep_range(1000, 2000);
+
+ return 0;
+
+err_reset:
+ gpiod_direction_output(sensor->reset, 1);
+err_supply:
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+ return ret;
+}
+
+static void imx296_power_off(struct imx296 *sensor)
+{
+ clk_disable_unprepare(sensor->clk);
+ gpiod_direction_output(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+}
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static const char * const imx296_test_pattern_menu[] = {
+ "Disabled",
+ "Multiple Pixels",
+ "Sequence 1",
+ "Sequence 2",
+ "Gradient",
+ "Row",
+ "Column",
+ "Cross",
+ "Stripe",
+ "Checks",
+};
+
+static int imx296_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx296 *sensor = container_of(ctrl->handler, struct imx296, ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ unsigned int vmax;
+ int ret = 0;
+
+ if (!sensor->streaming)
+ return 0;
+
+ state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* Clamp the exposure value to VMAX. */
+ vmax = format->height + sensor->vblank->cur.val;
+ ctrl->val = min_t(int, ctrl->val, vmax);
+ imx296_write(sensor, IMX296_SHS1, vmax - ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ imx296_write(sensor, IMX296_GAIN, ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_VBLANK:
+ imx296_write(sensor, IMX296_VMAX, format->height + ctrl->val,
+ &ret);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ if (ctrl->val) {
+ imx296_write(sensor, IMX296_PGHPOS, 8, &ret);
+ imx296_write(sensor, IMX296_PGVPOS, 8, &ret);
+ imx296_write(sensor, IMX296_PGHPSTEP, 8, &ret);
+ imx296_write(sensor, IMX296_PGVPSTEP, 8, &ret);
+ imx296_write(sensor, IMX296_PGHPNUM, 100, &ret);
+ imx296_write(sensor, IMX296_PGVPNUM, 100, &ret);
+ imx296_write(sensor, IMX296_PGDATA1, 0x300, &ret);
+ imx296_write(sensor, IMX296_PGDATA2, 0x100, &ret);
+ imx296_write(sensor, IMX296_PGHGSTEP, 0, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0, &ret);
+ imx296_write(sensor, IMX296_BLKLEVELAUTO,
+ IMX296_BLKLEVELAUTO_OFF, &ret);
+ imx296_write(sensor, IMX296_PGCTRL,
+ IMX296_PGCTRL_REGEN |
+ IMX296_PGCTRL_CLKEN |
+ IMX296_PGCTRL_MODE(ctrl->val - 1), &ret);
+ } else {
+ imx296_write(sensor, IMX296_PGCTRL,
+ IMX296_PGCTRL_CLKEN, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0x3c, &ret);
+ imx296_write(sensor, IMX296_BLKLEVELAUTO,
+ IMX296_BLKLEVELAUTO_ON, &ret);
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx296_ctrl_ops = {
+ .s_ctrl = imx296_s_ctrl,
+};
+
+static int imx296_ctrls_init(struct imx296 *sensor)
+{
+ struct v4l2_fwnode_device_properties props;
+ unsigned int hblank;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(sensor->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&sensor->ctrls, 9);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 1048575, 1, 1104);
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
+ IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
+
+ /*
+ * Horizontal blanking is controlled through the HMAX register, which
+ * contains a line length in INCK clock units. The INCK frequency is
+ * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100,
+ * convert it to a number of pixels based on the nominal pixel rate.
+ */
+ hblank = 1100 * 1188000000ULL / 10 / 74250000
+ - IMX296_PIXEL_ARRAY_WIDTH;
+ sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1,
+ hblank);
+ if (sensor->hblank)
+ sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_VBLANK, 30,
+ 1048575 - IMX296_PIXEL_ARRAY_HEIGHT,
+ 1, 30);
+ /*
+ * The sensor calculates the MIPI timings internally to achieve a bit
+ * rate between 1122 and 1198 Mbps. The exact value is unfortunately not
+ * reported, at least according to the documentation. Report a nominal
+ * rate of 1188 Mbps as that is used by the datasheet in multiple
+ * examples.
+ */
+ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE,
+ 1122000000 / 10, 1198000000 / 10, 1, 1188000000 / 10);
+ v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx296_test_pattern_menu) - 1,
+ 0, 0, imx296_test_pattern_menu);
+
+ v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx296_ctrl_ops,
+ &props);
+
+ if (sensor->ctrls.error) {
+ dev_err(sensor->dev, "failed to add controls (%d)\n",
+ sensor->ctrls.error);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return sensor->ctrls.error;
+ }
+
+ sensor->subdev.ctrl_handler = &sensor->ctrls;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ */
+
+/*
+ * This table is extracted from vendor data that is entirely undocumented. The
+ * first register write is required to activate the CSI-2 output. The other
+ * entries may or may not be optional?
+ */
+static const struct {
+ unsigned int reg;
+ unsigned int value;
+} imx296_init_table[] = {
+ { IMX296_REG_8BIT(0x3005), 0xf0 },
+ { IMX296_REG_8BIT(0x309e), 0x04 },
+ { IMX296_REG_8BIT(0x30a0), 0x04 },
+ { IMX296_REG_8BIT(0x30a1), 0x3c },
+ { IMX296_REG_8BIT(0x30a4), 0x5f },
+ { IMX296_REG_8BIT(0x30a8), 0x91 },
+ { IMX296_REG_8BIT(0x30ac), 0x28 },
+ { IMX296_REG_8BIT(0x30af), 0x09 },
+ { IMX296_REG_8BIT(0x30df), 0x00 },
+ { IMX296_REG_8BIT(0x3165), 0x00 },
+ { IMX296_REG_8BIT(0x3169), 0x10 },
+ { IMX296_REG_8BIT(0x316a), 0x02 },
+ { IMX296_REG_8BIT(0x31c8), 0xf3 }, /* Exposure-related */
+ { IMX296_REG_8BIT(0x31d0), 0xf4 }, /* Exposure-related */
+ { IMX296_REG_8BIT(0x321a), 0x00 },
+ { IMX296_REG_8BIT(0x3226), 0x02 },
+ { IMX296_REG_8BIT(0x3256), 0x01 },
+ { IMX296_REG_8BIT(0x3541), 0x72 },
+ { IMX296_REG_8BIT(0x3516), 0x77 },
+ { IMX296_REG_8BIT(0x350b), 0x7f },
+ { IMX296_REG_8BIT(0x3758), 0xa3 },
+ { IMX296_REG_8BIT(0x3759), 0x00 },
+ { IMX296_REG_8BIT(0x375a), 0x85 },
+ { IMX296_REG_8BIT(0x375b), 0x00 },
+ { IMX296_REG_8BIT(0x3832), 0xf5 },
+ { IMX296_REG_8BIT(0x3833), 0x00 },
+ { IMX296_REG_8BIT(0x38a2), 0xf6 },
+ { IMX296_REG_8BIT(0x38a3), 0x00 },
+ { IMX296_REG_8BIT(0x3a00), 0x80 },
+ { IMX296_REG_8BIT(0x3d48), 0xa3 },
+ { IMX296_REG_8BIT(0x3d49), 0x00 },
+ { IMX296_REG_8BIT(0x3d4a), 0x85 },
+ { IMX296_REG_8BIT(0x3d4b), 0x00 },
+ { IMX296_REG_8BIT(0x400e), 0x58 },
+ { IMX296_REG_8BIT(0x4014), 0x1c },
+ { IMX296_REG_8BIT(0x4041), 0x2a },
+ { IMX296_REG_8BIT(0x40a2), 0x06 },
+ { IMX296_REG_8BIT(0x40c1), 0xf6 },
+ { IMX296_REG_8BIT(0x40c7), 0x0f },
+ { IMX296_REG_8BIT(0x40c8), 0x00 },
+ { IMX296_REG_8BIT(0x4174), 0x00 },
+};
+
+static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
+ unsigned int i;
+ int ret = 0;
+
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+ crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0);
+
+ for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i)
+ imx296_write(sensor, imx296_init_table[i].reg,
+ imx296_init_table[i].value, &ret);
+
+ if (crop->width != IMX296_PIXEL_ARRAY_WIDTH ||
+ crop->height != IMX296_PIXEL_ARRAY_HEIGHT) {
+ imx296_write(sensor, IMX296_FID0_ROI,
+ IMX296_FID0_ROIH1ON | IMX296_FID0_ROIV1ON, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIPH1, crop->left, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret);
+ } else {
+ imx296_write(sensor, IMX296_FID0_ROI, 0, &ret);
+ }
+
+ imx296_write(sensor, IMX296_CTRL0D,
+ (crop->width != format->width ?
+ IMX296_CTRL0D_HADD_ON_BINNING : 0) |
+ (crop->height != format->height ?
+ IMX296_CTRL0D_WINMODE_FD_BINNING : 0),
+ &ret);
+
+ /*
+ * HMAX and VMAX configure horizontal and vertical blanking by
+ * specifying the total line time and frame time respectively. The line
+ * time is specified in operational clock units (which appears to be the
+ * output of an internal PLL, fixed at 74.25 MHz regardless of the
+ * exernal clock frequency), while the frame time is specified as a
+ * number of lines.
+ *
+ * In the vertical direction the sensor outputs the following:
+ *
+ * - one line for the FS packet
+ * - two lines of embedded data (DT 0x12)
+ * - six null lines (DT 0x10)
+ * - four lines of vertical effective optical black (DT 0x37)
+ * - 8 to 1088 lines of active image data (RAW10, DT 0x2b)
+ * - one line for the FE packet
+ * - 16 or more lines of vertical blanking
+ */
+ imx296_write(sensor, IMX296_HMAX, 1100, &ret);
+ imx296_write(sensor, IMX296_VMAX,
+ format->height + sensor->vblank->cur.val, &ret);
+
+ for (i = 0; i < ARRAY_SIZE(sensor->clk_params->incksel); ++i)
+ imx296_write(sensor, IMX296_INCKSEL(i),
+ sensor->clk_params->incksel[i], &ret);
+ imx296_write(sensor, IMX296_GTTABLENUM, 0xc5, &ret);
+ imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c,
+ &ret);
+
+ imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret);
+
+ return ret;
+}
+
+static int imx296_stream_on(struct imx296 *sensor)
+{
+ int ret = 0;
+
+ imx296_write(sensor, IMX296_CTRL00, 0, &ret);
+ usleep_range(2000, 5000);
+ imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
+
+ return ret;
+}
+
+static int imx296_stream_off(struct imx296 *sensor)
+{
+ int ret = 0;
+
+ imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret);
+ imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret);
+
+ return ret;
+}
+
+static int imx296_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx296 *sensor = to_imx296(sd);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (!enable) {
+ ret = imx296_stream_off(sensor);
+
+ pm_runtime_mark_last_busy(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ sensor->streaming = false;
+
+ goto unlock;
+ }
+
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx296_setup(sensor, state);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set
+ * the controls. The flag is reset to false further down if an error
+ * occurs.
+ */
+ sensor->streaming = true;
+
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls);
+ if (ret < 0)
+ goto err_pm;
+
+ ret = imx296_stream_on(sensor);
+ if (ret)
+ goto err_pm;
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+
+err_pm:
+ /*
+ * In case of error, turn the power off synchronously as the device
+ * likely has no other chance to recover.
+ */
+ pm_runtime_put_sync(sensor->dev);
+ sensor->streaming = false;
+
+ goto unlock;
+}
+
+static int imx296_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx296 *sensor = to_imx296(sd);
+
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
+ : MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int imx296_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+
+ if (fse->index >= 2 || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1);
+ fse->max_width = fse->min_width;
+ fse->min_height = IMX296_PIXEL_ARRAY_HEIGHT / (fse->index + 1);
+ fse->max_height = fse->min_height;
+
+ 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)
+{
+ struct imx296 *sensor = to_imx296(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad);
+ format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ /*
+ * Binning is only allowed when cropping is disabled according to the
+ * documentation. This should be double-checked.
+ */
+ if (crop->width == IMX296_PIXEL_ARRAY_WIDTH &&
+ crop->height == IMX296_PIXEL_ARRAY_HEIGHT) {
+ unsigned int width;
+ unsigned int height;
+ unsigned int hratio;
+ unsigned int vratio;
+
+ /* Clamp the width and height to avoid dividing by zero. */
+ width = clamp_t(unsigned int, fmt->format.width,
+ crop->width / 2, crop->width);
+ height = clamp_t(unsigned int, fmt->format.height,
+ crop->height / 2, crop->height);
+
+ hratio = DIV_ROUND_CLOSEST(crop->width, width);
+ vratio = DIV_ROUND_CLOSEST(crop->height, height);
+
+ format->width = crop->width / hratio;
+ format->height = crop->height / vratio;
+ } else {
+ format->width = crop->width;
+ format->height = crop->height;
+ }
+
+ format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
+ : MEDIA_BUS_FMT_SBGGR10_1X10;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int imx296_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+ break;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = IMX296_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX296_PIXEL_ARRAY_HEIGHT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int imx296_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ 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 4
+ * pixels to satisfy hardware requirements.
+ */
+ rect.left = clamp(ALIGN(sel->r.left, 4), 0,
+ IMX296_PIXEL_ARRAY_WIDTH - IMX296_FID0_ROIWH1_MIN);
+ rect.top = clamp(ALIGN(sel->r.top, 4), 0,
+ IMX296_PIXEL_ARRAY_HEIGHT - IMX296_FID0_ROIWV1_MIN);
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4),
+ IMX296_FID0_ROIWH1_MIN, IMX296_PIXEL_ARRAY_WIDTH);
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 4),
+ IMX296_FID0_ROIWV1_MIN, IMX296_PIXEL_ARRAY_HEIGHT);
+
+ rect.width = min_t(unsigned int, rect.width,
+ IMX296_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min_t(unsigned int, rect.height,
+ IMX296_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+
+ if (rect.width != crop->width || rect.height != crop->height) {
+ /*
+ * Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ format = v4l2_subdev_get_pad_format(sd, state, sel->pad);
+ format->width = rect.width;
+ format->height = rect.height;
+ }
+
+ *crop = rect;
+ sel->r = rect;
+
+ return 0;
+}
+
+static int imx296_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_selection sel = {
+ .target = V4L2_SEL_TGT_CROP,
+ .r.width = IMX296_PIXEL_ARRAY_WIDTH,
+ .r.height = IMX296_PIXEL_ARRAY_HEIGHT,
+ };
+ struct v4l2_subdev_format format = {
+ .format = {
+ .width = IMX296_PIXEL_ARRAY_WIDTH,
+ .height = IMX296_PIXEL_ARRAY_HEIGHT,
+ },
+ };
+
+ imx296_set_selection(sd, state, &sel);
+ imx296_set_format(sd, state, &format);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = {
+ .s_stream = imx296_s_stream,
+};
+
+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,
+ .set_fmt = imx296_set_format,
+ .get_selection = imx296_get_selection,
+ .set_selection = imx296_set_selection,
+ .init_cfg = imx296_init_cfg,
+};
+
+static const struct v4l2_subdev_ops imx296_subdev_ops = {
+ .video = &imx296_subdev_video_ops,
+ .pad = &imx296_subdev_pad_ops,
+};
+
+static int imx296_subdev_init(struct imx296 *sensor)
+{
+ struct i2c_client *client = to_i2c_client(sensor->dev);
+ int ret;
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops);
+
+ ret = imx296_ctrls_init(sensor);
+ if (ret < 0)
+ return ret;
+
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return ret;
+ }
+
+ sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock;
+
+ v4l2_subdev_init_finalize(&sensor->subdev);
+
+ return ret;
+}
+
+static void imx296_subdev_cleanup(struct imx296 *sensor)
+{
+ media_entity_cleanup(&sensor->subdev.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int __maybe_unused imx296_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ return imx296_power_on(sensor);
+}
+
+static int __maybe_unused imx296_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ imx296_power_off(sensor);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx296_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx296_runtime_suspend, imx296_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int imx296_read_temperature(struct imx296 *sensor, int *temp)
+{
+ int tmdout;
+ int ret;
+
+ ret = imx296_write(sensor, IMX296_TMDCTRL, IMX296_TMDCTRL_LATCH, NULL);
+ if (ret < 0)
+ return ret;
+
+ tmdout = imx296_read(sensor, IMX296_TMDOUT) & IMX296_TMDOUT_MASK;
+ if (tmdout < 0)
+ return tmdout;
+
+ /* T(°C) = 246.312 - 0.304 * TMDOUT */;
+ *temp = 246312 - 304 * tmdout;
+
+ return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL);
+}
+
+static int imx296_identify_model(struct imx296 *sensor)
+{
+ unsigned int model;
+ int temp = 0;
+ int ret;
+
+ model = (uintptr_t)of_device_get_match_data(sensor->dev);
+ if (model) {
+ dev_dbg(sensor->dev,
+ "sensor model auto-detection disabled, forcing 0x%04x\n",
+ model);
+ sensor->mono = model & IMX296_SENSOR_INFO_MONO;
+ return 0;
+ }
+
+ /*
+ * While most registers can be read when the sensor is in standby, this
+ * is not the case of the sensor info register :-(
+ */
+ ret = imx296_write(sensor, IMX296_CTRL00, 0, NULL);
+ if (ret < 0) {
+ dev_err(sensor->dev,
+ "failed to get sensor out of standby (%d)\n", ret);
+ return ret;
+ }
+
+ ret = imx296_read(sensor, IMX296_SENSOR_INFO);
+ if (ret < 0) {
+ dev_err(sensor->dev, "failed to read sensor information (%d)\n",
+ ret);
+ goto done;
+ }
+
+ model = (ret >> 6) & 0x1ff;
+
+ switch (model) {
+ case 296:
+ sensor->mono = ret & IMX296_SENSOR_INFO_MONO;
+ break;
+ /*
+ * The IMX297 seems to share features with the IMX296, it may be
+ * possible to support it in the same driver.
+ */
+ case 297:
+ default:
+ dev_err(sensor->dev, "invalid device model 0x%04x\n", ret);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = imx296_read_temperature(sensor, &temp);
+ if (ret < 0)
+ goto done;
+
+ dev_info(sensor->dev, "found IMX%u%s (%u.%uC)\n", model,
+ sensor->mono ? "LL" : "LQ", temp / 1000, (temp / 100) % 10);
+
+done:
+ imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, NULL);
+ return ret;
+}
+
+static const struct regmap_config imx296_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+
+ .wr_table = &(const struct regmap_access_table) {
+ .no_ranges = (const struct regmap_range[]) {
+ {
+ .range_min = IMX296_SENSOR_INFO & 0xffff,
+ .range_max = (IMX296_SENSOR_INFO & 0xffff) + 1,
+ },
+ },
+ .n_no_ranges = 1,
+ },
+};
+
+static int imx296_probe(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ unsigned long clk_rate;
+ struct imx296 *sensor;
+ unsigned int i;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+ return -EIO;
+ }
+
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->dev = &client->dev;
+
+ /* Acquire resources. */
+ for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i)
+ sensor->supplies[i].supply = imx296_supply_names[i];
+
+ ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret) {
+ dev_err_probe(sensor->dev, ret, "failed to get supplies\n");
+ return ret;
+ }
+
+ sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->reset))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
+ "failed to get reset GPIO\n");
+
+ sensor->clk = devm_clk_get(sensor->dev, "inck");
+ if (IS_ERR(sensor->clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
+ "failed to get clock\n");
+
+ clk_rate = clk_get_rate(sensor->clk);
+ for (i = 0; i < ARRAY_SIZE(imx296_clk_params); ++i) {
+ if (clk_rate == imx296_clk_params[i].freq) {
+ sensor->clk_params = &imx296_clk_params[i];
+ break;
+ }
+ }
+
+ if (!sensor->clk_params) {
+ dev_err(sensor->dev, "unsupported clock rate %lu\n", clk_rate);
+ return -EINVAL;
+ }
+
+ sensor->regmap = devm_regmap_init_i2c(client, &imx296_regmap_config);
+ if (IS_ERR(sensor->regmap))
+ return PTR_ERR(sensor->regmap);
+
+ /*
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here, identify it, and fully initialize it.
+ */
+ ret = imx296_power_on(sensor);
+ if (ret < 0)
+ return ret;
+
+ ret = imx296_identify_model(sensor);
+ if (ret < 0)
+ goto err_power;
+
+ /* Initialize the V4L2 subdev. */
+ ret = imx296_subdev_init(sensor);
+ if (ret < 0)
+ goto err_power;
+
+ /*
+ * Enable runtime PM. As the device has been powered manually, mark it
+ * as active, and increase the usage count without resuming the device.
+ */
+ pm_runtime_set_active(sensor->dev);
+ pm_runtime_get_noresume(sensor->dev);
+ pm_runtime_enable(sensor->dev);
+
+ /* Register the V4L2 subdev. */
+ ret = v4l2_async_register_subdev(&sensor->subdev);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Finally, enable autosuspend and decrease the usage count. The device
+ * will get suspended after the autosuspend delay, turning the power
+ * off.
+ */
+ pm_runtime_set_autosuspend_delay(sensor->dev, 1000);
+ pm_runtime_use_autosuspend(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(sensor->dev);
+ pm_runtime_put_noidle(sensor->dev);
+ imx296_subdev_cleanup(sensor);
+err_power:
+ imx296_power_off(sensor);
+ return ret;
+}
+
+static void imx296_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ v4l2_async_unregister_subdev(subdev);
+
+ imx296_subdev_cleanup(sensor);
+
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(sensor->dev);
+ if (!pm_runtime_status_suspended(sensor->dev))
+ imx296_power_off(sensor);
+ pm_runtime_set_suspended(sensor->dev);
+}
+
+static const struct of_device_id imx296_of_match[] = {
+ { .compatible = "sony,imx296", .data = NULL },
+ { .compatible = "sony,imx296ll", .data = (void *)IMX296_SENSOR_INFO_IMX296LL },
+ { .compatible = "sony,imx296lq", .data = (void *)IMX296_SENSOR_INFO_IMX296LQ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx296_of_match);
+
+static struct i2c_driver imx296_i2c_driver = {
+ .driver = {
+ .of_match_table = imx296_of_match,
+ .name = "imx296",
+ .pm = &imx296_pm_ops
+ },
+ .probe_new = imx296_probe,
+ .remove = imx296_remove,
+};
+
+module_i2c_driver(imx296_i2c_driver);
+
+MODULE_DESCRIPTION("Sony IMX296 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c
new file mode 100644
index 000000000000..d90392df98c7
--- /dev/null
+++ b/drivers/media/i2c/imx415.c
@@ -0,0 +1,1300 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the Sony IMX415 CMOS Image Sensor.
+ *
+ * Copyright (C) 2023 WolfVision GmbH.
+ */
+
+#include <linux/clk.h>
+#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 <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define IMX415_PIXEL_ARRAY_TOP 0
+#define IMX415_PIXEL_ARRAY_LEFT 0
+#define IMX415_PIXEL_ARRAY_WIDTH 3864
+#define IMX415_PIXEL_ARRAY_HEIGHT 2192
+#define IMX415_PIXEL_ARRAY_VBLANK 58
+
+#define IMX415_NUM_CLK_PARAM_REGS 11
+
+#define IMX415_REG_8BIT(n) ((1 << 16) | (n))
+#define IMX415_REG_16BIT(n) ((2 << 16) | (n))
+#define IMX415_REG_24BIT(n) ((3 << 16) | (n))
+#define IMX415_REG_SIZE_SHIFT 16
+#define IMX415_REG_ADDR_MASK 0xffff
+
+#define IMX415_MODE IMX415_REG_8BIT(0x3000)
+#define IMX415_MODE_OPERATING (0)
+#define IMX415_MODE_STANDBY BIT(0)
+#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001)
+#define IMX415_REGHOLD_INVALID (0)
+#define IMX415_REGHOLD_VALID BIT(0)
+#define IMX415_XMSTA IMX415_REG_8BIT(0x3002)
+#define IMX415_XMSTA_START (0)
+#define IMX415_XMSTA_STOP BIT(0)
+#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008)
+#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A)
+#define IMX415_WINMODE IMX415_REG_8BIT(0x301C)
+#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022)
+#define IMX415_REVERSE IMX415_REG_8BIT(0x3030)
+#define IMX415_HREVERSE_SHIFT (0)
+#define IMX415_VREVERSE_SHIFT BIT(0)
+#define IMX415_ADBIT IMX415_REG_8BIT(0x3031)
+#define IMX415_MDBIT IMX415_REG_8BIT(0x3032)
+#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033)
+#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0)
+#define IMX415_DRV IMX415_REG_8BIT(0x30C1)
+#define IMX415_VMAX IMX415_REG_24BIT(0x3024)
+#define IMX415_HMAX IMX415_REG_16BIT(0x3028)
+#define IMX415_SHR0 IMX415_REG_24BIT(0x3050)
+#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090)
+#define IMX415_AGAIN_MIN 0
+#define IMX415_AGAIN_MAX 100
+#define IMX415_AGAIN_STEP 1
+#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2)
+#define IMX415_BLKLEVEL_DEFAULT 50
+#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4)
+#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6)
+#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8)
+#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110)
+#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115)
+#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116)
+#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118)
+#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A)
+#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E)
+#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8)
+#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390)
+#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12)
+#define IMX415_SENSOR_INFO_MASK 0xFFF
+#define IMX415_CHIP_ID 0x514
+#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001)
+#define IMX415_LANEMODE_2 1
+#define IMX415_LANEMODE_4 3
+#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004)
+#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C)
+#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018)
+#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A)
+#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C)
+#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E)
+#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020)
+#define IMX415_THSZERO IMX415_REG_16BIT(0x4022)
+#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024)
+#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026)
+#define IMX415_TLPX IMX415_REG_16BIT(0x4028)
+#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074)
+
+struct imx415_reg {
+ u32 address;
+ u32 val;
+};
+
+static const char *const imx415_supply_names[] = {
+ "dvdd",
+ "ovdd",
+ "avdd",
+};
+
+/*
+ * The IMX415 data sheet uses lane rates but v4l2 uses link frequency to
+ * describe MIPI CSI-2 speed. This driver uses lane rates wherever possible
+ * and converts them to link frequencies by a factor of two when needed.
+ */
+static const s64 link_freq_menu_items[] = {
+ 594000000 / 2, 720000000 / 2, 891000000 / 2,
+ 1440000000 / 2, 1485000000 / 2,
+};
+
+struct imx415_clk_params {
+ u64 lane_rate;
+ u64 inck;
+ struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS];
+};
+
+/* INCK Settings - includes all lane rate and INCK dependent registers */
+static const struct imx415_clk_params imx415_clk_params[] = {
+ {
+ .lane_rate = 594000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x7 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x084 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 720000000,
+ .inck = 24000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
+ .regs[2] = { IMX415_SYS_MODE, 0x9 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0B4 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0FC },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
+ },
+ {
+ .lane_rate = 891000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x5 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C6 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 1440000000,
+ .inck = 24000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0B4 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0FC },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
+ },
+ {
+ .lane_rate = 1485000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A5 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+};
+
+/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */
+static const struct imx415_reg imx415_mode_2_720[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x07F0 },
+ { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+ { IMX415_TCLKPOST, 0x006F },
+ { IMX415_TCLKPREPARE, 0x002F },
+ { IMX415_TCLKTRAIL, 0x002F },
+ { IMX415_TCLKZERO, 0x00BF },
+ { IMX415_THSPREPARE, 0x002F },
+ { IMX415_THSZERO, 0x0057 },
+ { IMX415_THSTRAIL, 0x002F },
+ { IMX415_THSEXIT, 0x004F },
+ { IMX415_TLPX, 0x0027 },
+};
+
+/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */
+static const struct imx415_reg imx415_mode_2_1440[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x042A },
+ { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+ { IMX415_TCLKPOST, 0x009F },
+ { IMX415_TCLKPREPARE, 0x0057 },
+ { IMX415_TCLKTRAIL, 0x0057 },
+ { IMX415_TCLKZERO, 0x0187 },
+ { IMX415_THSPREPARE, 0x005F },
+ { IMX415_THSZERO, 0x00A7 },
+ { IMX415_THSTRAIL, 0x005F },
+ { IMX415_THSEXIT, 0x0097 },
+ { IMX415_TLPX, 0x004F },
+};
+
+/* all-pixel 4-lane 891 Mbps 30 Hz mode */
+static const struct imx415_reg imx415_mode_4_891[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x044C },
+ { IMX415_LANEMODE, IMX415_LANEMODE_4 },
+ { IMX415_TCLKPOST, 0x007F },
+ { IMX415_TCLKPREPARE, 0x0037 },
+ { IMX415_TCLKTRAIL, 0x0037 },
+ { IMX415_TCLKZERO, 0x00F7 },
+ { IMX415_THSPREPARE, 0x003F },
+ { IMX415_THSZERO, 0x006F },
+ { IMX415_THSTRAIL, 0x003F },
+ { IMX415_THSEXIT, 0x005F },
+ { IMX415_TLPX, 0x002F },
+};
+
+struct imx415_mode_reg_list {
+ u32 num_of_regs;
+ const struct imx415_reg *regs;
+};
+
+/*
+ * Mode : number of lanes, lane rate and frame rate dependent settings
+ *
+ * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl
+ * interface. These values can not be found in the data sheet and should be
+ * treated as virtual values. Use following table when adding new modes.
+ *
+ * lane_rate lanes fps hmax_pix pixel_rate
+ *
+ * 594 2 10.000 4400 99000000
+ * 891 2 15.000 4400 148500000
+ * 720 2 15.748 4064 144000000
+ * 1782 2 30.000 4400 297000000
+ * 2079 2 30.000 4400 297000000
+ * 1440 2 30.019 4510 304615385
+ *
+ * 594 4 20.000 5500 247500000
+ * 594 4 25.000 4400 247500000
+ * 720 4 25.000 4400 247500000
+ * 720 4 30.019 4510 304615385
+ * 891 4 30.000 4400 297000000
+ * 1440 4 30.019 4510 304615385
+ * 1440 4 60.038 4510 609230769
+ * 1485 4 60.000 4400 594000000
+ * 1782 4 60.000 4400 594000000
+ * 2079 4 60.000 4400 594000000
+ * 2376 4 90.164 4392 891000000
+ */
+struct imx415_mode {
+ u64 lane_rate;
+ u32 lanes;
+ u32 hmax_pix;
+ u64 pixel_rate;
+ struct imx415_mode_reg_list reg_list;
+};
+
+/* mode configs */
+static const struct imx415_mode supported_modes[] = {
+ {
+ .lane_rate = 720000000,
+ .lanes = 2,
+ .hmax_pix = 4064,
+ .pixel_rate = 144000000,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_2_720),
+ .regs = imx415_mode_2_720,
+ },
+ },
+ {
+ .lane_rate = 1440000000,
+ .lanes = 2,
+ .hmax_pix = 4510,
+ .pixel_rate = 304615385,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440),
+ .regs = imx415_mode_2_1440,
+ },
+ },
+ {
+ .lane_rate = 891000000,
+ .lanes = 4,
+ .hmax_pix = 4400,
+ .pixel_rate = 297000000,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_4_891),
+ .regs = imx415_mode_4_891,
+ },
+ },
+};
+
+static const struct regmap_config imx415_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+};
+
+static const char *const imx415_test_pattern_menu[] = {
+ "disabled",
+ "solid black",
+ "solid white",
+ "solid dark gray",
+ "solid light gray",
+ "stripes light/dark grey",
+ "stripes dark/light grey",
+ "stripes black/dark grey",
+ "stripes dark grey/black",
+ "stripes black/white",
+ "stripes white/black",
+ "horizontal color bar",
+ "vertical color bar",
+};
+
+struct imx415 {
+ struct device *dev;
+ struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)];
+ struct gpio_desc *reset;
+ struct regmap *regmap;
+
+ const struct imx415_clk_params *clk_params;
+
+ bool streaming;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+
+ unsigned int cur_mode;
+ unsigned int num_data_lanes;
+};
+
+/*
+ * This table includes fixed register settings and a bunch of undocumented
+ * registers that have to be set to another value than default.
+ */
+static const struct imx415_reg imx415_init_table[] = {
+ /* use all-pixel readout mode, no flip */
+ { IMX415_WINMODE, 0x00 },
+ { IMX415_ADDMODE, 0x00 },
+ { IMX415_REVERSE, 0x00 },
+ /* use RAW 10-bit mode */
+ { IMX415_ADBIT, 0x00 },
+ { IMX415_MDBIT, 0x00 },
+ /* output VSYNC on XVS and low on XHS */
+ { IMX415_OUTSEL, 0x22 },
+ { IMX415_DRV, 0x00 },
+
+ /* SONY magic registers */
+ { IMX415_REG_8BIT(0x32D4), 0x21 },
+ { IMX415_REG_8BIT(0x32EC), 0xA1 },
+ { IMX415_REG_8BIT(0x3452), 0x7F },
+ { IMX415_REG_8BIT(0x3453), 0x03 },
+ { IMX415_REG_8BIT(0x358A), 0x04 },
+ { IMX415_REG_8BIT(0x35A1), 0x02 },
+ { IMX415_REG_8BIT(0x36BC), 0x0C },
+ { IMX415_REG_8BIT(0x36CC), 0x53 },
+ { IMX415_REG_8BIT(0x36CD), 0x00 },
+ { IMX415_REG_8BIT(0x36CE), 0x3C },
+ { IMX415_REG_8BIT(0x36D0), 0x8C },
+ { IMX415_REG_8BIT(0x36D1), 0x00 },
+ { IMX415_REG_8BIT(0x36D2), 0x71 },
+ { IMX415_REG_8BIT(0x36D4), 0x3C },
+ { IMX415_REG_8BIT(0x36D6), 0x53 },
+ { IMX415_REG_8BIT(0x36D7), 0x00 },
+ { IMX415_REG_8BIT(0x36D8), 0x71 },
+ { IMX415_REG_8BIT(0x36DA), 0x8C },
+ { IMX415_REG_8BIT(0x36DB), 0x00 },
+ { IMX415_REG_8BIT(0x3724), 0x02 },
+ { IMX415_REG_8BIT(0x3726), 0x02 },
+ { IMX415_REG_8BIT(0x3732), 0x02 },
+ { IMX415_REG_8BIT(0x3734), 0x03 },
+ { IMX415_REG_8BIT(0x3736), 0x03 },
+ { IMX415_REG_8BIT(0x3742), 0x03 },
+ { IMX415_REG_8BIT(0x3862), 0xE0 },
+ { IMX415_REG_8BIT(0x38CC), 0x30 },
+ { IMX415_REG_8BIT(0x38CD), 0x2F },
+ { IMX415_REG_8BIT(0x395C), 0x0C },
+ { IMX415_REG_8BIT(0x3A42), 0xD1 },
+ { IMX415_REG_8BIT(0x3A4C), 0x77 },
+ { IMX415_REG_8BIT(0x3AE0), 0x02 },
+ { IMX415_REG_8BIT(0x3AEC), 0x0C },
+ { IMX415_REG_8BIT(0x3B00), 0x2E },
+ { IMX415_REG_8BIT(0x3B06), 0x29 },
+ { IMX415_REG_8BIT(0x3B98), 0x25 },
+ { IMX415_REG_8BIT(0x3B99), 0x21 },
+ { IMX415_REG_8BIT(0x3B9B), 0x13 },
+ { IMX415_REG_8BIT(0x3B9C), 0x13 },
+ { IMX415_REG_8BIT(0x3B9D), 0x13 },
+ { IMX415_REG_8BIT(0x3B9E), 0x13 },
+ { IMX415_REG_8BIT(0x3BA1), 0x00 },
+ { IMX415_REG_8BIT(0x3BA2), 0x06 },
+ { IMX415_REG_8BIT(0x3BA3), 0x0B },
+ { IMX415_REG_8BIT(0x3BA4), 0x10 },
+ { IMX415_REG_8BIT(0x3BA5), 0x14 },
+ { IMX415_REG_8BIT(0x3BA6), 0x18 },
+ { IMX415_REG_8BIT(0x3BA7), 0x1A },
+ { IMX415_REG_8BIT(0x3BA8), 0x1A },
+ { IMX415_REG_8BIT(0x3BA9), 0x1A },
+ { IMX415_REG_8BIT(0x3BAC), 0xED },
+ { IMX415_REG_8BIT(0x3BAD), 0x01 },
+ { IMX415_REG_8BIT(0x3BAE), 0xF6 },
+ { IMX415_REG_8BIT(0x3BAF), 0x02 },
+ { IMX415_REG_8BIT(0x3BB0), 0xA2 },
+ { IMX415_REG_8BIT(0x3BB1), 0x03 },
+ { IMX415_REG_8BIT(0x3BB2), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB3), 0x03 },
+ { IMX415_REG_8BIT(0x3BB4), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB5), 0x03 },
+ { IMX415_REG_8BIT(0x3BB6), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB7), 0x03 },
+ { IMX415_REG_8BIT(0x3BB8), 0xE0 },
+ { IMX415_REG_8BIT(0x3BBA), 0xE0 },
+ { IMX415_REG_8BIT(0x3BBC), 0xDA },
+ { IMX415_REG_8BIT(0x3BBE), 0x88 },
+ { IMX415_REG_8BIT(0x3BC0), 0x44 },
+ { IMX415_REG_8BIT(0x3BC2), 0x7B },
+ { IMX415_REG_8BIT(0x3BC4), 0xA2 },
+ { IMX415_REG_8BIT(0x3BC8), 0xBD },
+ { IMX415_REG_8BIT(0x3BCA), 0xBD },
+};
+
+static inline struct imx415 *to_imx415(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx415, subdev);
+}
+
+static int imx415_read(struct imx415 *sensor, u32 addr)
+{
+ u8 data[3] = { 0 };
+ int ret;
+
+ ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data,
+ (addr >> IMX415_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ return ret;
+
+ return (data[2] << 16) | (data[1] << 8) | data[0];
+}
+
+static int imx415_write(struct imx415 *sensor, u32 addr, u32 value)
+{
+ u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
+ int ret;
+
+ ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK,
+ data, (addr >> IMX415_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ dev_err_ratelimited(sensor->dev,
+ "%u-bit write to 0x%04x failed: %d\n",
+ ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX415_REG_ADDR_MASK, ret);
+
+ return 0;
+}
+
+static int imx415_set_testpattern(struct imx415 *sensor, int val)
+{
+ int ret;
+
+ if (val) {
+ ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00);
+ } else {
+ ret = imx415_write(sensor, IMX415_BLKLEVEL,
+ IMX415_BLKLEVEL_DEFAULT);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01);
+ }
+ return 0;
+}
+
+static int imx415_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx415 *sensor = container_of(ctrl->handler, struct imx415,
+ ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ unsigned int vmax;
+ unsigned int flip;
+
+ if (!sensor->streaming)
+ return 0;
+
+ state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* clamp the exposure value to VMAX. */
+ vmax = format->height + sensor->vblank->cur.val;
+ ctrl->val = min_t(int, ctrl->val, vmax);
+ return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val);
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ /* analogue gain in 0.3 dB step size */
+ return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val);
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) |
+ (sensor->vflip->val << IMX415_VREVERSE_SHIFT);
+ return imx415_write(sensor, IMX415_REVERSE, flip);
+
+ case V4L2_CID_TEST_PATTERN:
+ return imx415_set_testpattern(sensor, ctrl->val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ctrl_ops imx415_ctrl_ops = {
+ .s_ctrl = imx415_s_ctrl,
+};
+
+static int imx415_ctrls_init(struct imx415 *sensor)
+{
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *ctrl;
+ u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate;
+ u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate;
+ u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT +
+ IMX415_PIXEL_ARRAY_VBLANK - 8;
+ u32 hblank;
+ unsigned int i;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(sensor->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&sensor->ctrls, 10);
+
+ for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); ++i) {
+ if (lane_rate == link_freq_menu_items[i] * 2)
+ break;
+ }
+ if (i == ARRAY_SIZE(link_freq_menu_items)) {
+ return dev_err_probe(sensor->dev, -EINVAL,
+ "lane rate %llu not supported\n",
+ lane_rate);
+ }
+
+ ctrl = v4l2_ctrl_new_int_menu(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq_menu_items) - 1, i,
+ link_freq_menu_items);
+
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE,
+ 4, exposure_max, 1, exposure_max);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN,
+ IMX415_AGAIN_MAX, IMX415_AGAIN_STEP,
+ IMX415_AGAIN_MIN);
+
+ hblank = supported_modes[sensor->cur_mode].hmax_pix -
+ IMX415_PIXEL_ARRAY_WIDTH;
+ ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_VBLANK,
+ IMX415_PIXEL_ARRAY_VBLANK,
+ IMX415_PIXEL_ARRAY_VBLANK, 1,
+ IMX415_PIXEL_ARRAY_VBLANK);
+ if (sensor->vblank)
+ sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /*
+ * The pixel rate used here is a virtual value and can be used for
+ * calculating the frame rate together with hblank. It may not
+ * necessarily be the physically correct pixel clock.
+ */
+ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx415_test_pattern_menu) - 1,
+ 0, 0, imx415_test_pattern_menu);
+
+ v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx415_ctrl_ops,
+ &props);
+
+ if (sensor->ctrls.error) {
+ dev_err_probe(sensor->dev, sensor->ctrls.error,
+ "failed to add controls\n");
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return sensor->ctrls.error;
+ }
+ sensor->subdev.ctrl_handler = &sensor->ctrls;
+
+ return 0;
+}
+
+static int imx415_set_mode(struct imx415 *sensor, int mode)
+{
+ const struct imx415_reg *reg;
+ unsigned int i;
+ int ret = 0;
+
+ if (mode >= ARRAY_SIZE(supported_modes)) {
+ dev_err(sensor->dev, "Mode %d not supported\n", mode);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) {
+ reg = &supported_modes[mode].reg_list.regs[i];
+ ret = imx415_write(sensor, reg->address, reg->val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) {
+ reg = &sensor->clk_params->regs[i];
+ ret = imx415_write(sensor, reg->address, reg->val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) {
+ ret = imx415_write(sensor, imx415_init_table[i].address,
+ imx415_init_table[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return imx415_set_mode(sensor, sensor->cur_mode);
+}
+
+static int imx415_wakeup(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING);
+ if (ret)
+ return ret;
+
+ /*
+ * According to the datasheet we have to wait at least 63 us after
+ * leaving standby mode. But this doesn't work even after 30 ms.
+ * So probably this should be 63 ms and therefore we wait for 80 ms.
+ */
+ msleep(80);
+
+ return 0;
+}
+
+static int imx415_stream_on(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_wakeup(sensor);
+ if (ret)
+ return ret;
+
+ return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START);
+}
+
+static int imx415_stream_off(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP);
+ if (ret)
+ return ret;
+
+ return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY);
+}
+
+static int imx415_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx415 *sensor = to_imx415(sd);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (!enable) {
+ ret = imx415_stream_off(sensor);
+
+ pm_runtime_mark_last_busy(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ sensor->streaming = false;
+
+ goto unlock;
+ }
+
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx415_setup(sensor, state);
+ if (ret)
+ goto err_pm;
+
+ /*
+ * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set
+ * the controls. The flag is reset to false further down if an error
+ * occurs.
+ */
+ sensor->streaming = true;
+
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls);
+ if (ret < 0)
+ goto err_pm;
+
+ ret = imx415_stream_on(sensor);
+ if (ret)
+ goto err_pm;
+
+ ret = 0;
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+
+err_pm:
+ /*
+ * In case of error, turn the power off synchronously as the device
+ * likely has no other chance to recover.
+ */
+ pm_runtime_put_sync(sensor->dev);
+ sensor->streaming = false;
+
+ goto unlock;
+}
+
+static int imx415_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SGBRG10_1X10;
+
+ return 0;
+}
+
+static int imx415_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+
+ if (fse->index > 0 || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = IMX415_PIXEL_ARRAY_WIDTH;
+ fse->max_width = fse->min_width;
+ fse->min_height = IMX415_PIXEL_ARRAY_HEIGHT;
+ fse->max_height = fse->min_height;
+ return 0;
+}
+
+static int imx415_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 imx415_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ format->width = fmt->format.width;
+ format->height = fmt->format.height;
+ format->code = MEDIA_BUS_FMT_SGBRG10_1X10;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ fmt->format = *format;
+ return 0;
+}
+
+static int imx415_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:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX415_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX415_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX415_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX415_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx415_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_format format = {
+ .format = {
+ .width = IMX415_PIXEL_ARRAY_WIDTH,
+ .height = IMX415_PIXEL_ARRAY_HEIGHT,
+ },
+ };
+
+ imx415_set_format(sd, state, &format);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = {
+ .s_stream = imx415_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = {
+ .enum_mbus_code = imx415_enum_mbus_code,
+ .enum_frame_size = imx415_enum_frame_size,
+ .get_fmt = imx415_get_format,
+ .set_fmt = imx415_set_format,
+ .get_selection = imx415_get_selection,
+ .init_cfg = imx415_init_cfg,
+};
+
+static const struct v4l2_subdev_ops imx415_subdev_ops = {
+ .video = &imx415_subdev_video_ops,
+ .pad = &imx415_subdev_pad_ops,
+};
+
+static int imx415_subdev_init(struct imx415 *sensor)
+{
+ struct i2c_client *client = to_i2c_client(sensor->dev);
+ int ret;
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops);
+
+ ret = imx415_ctrls_init(sensor);
+ if (ret)
+ return ret;
+
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return ret;
+ }
+
+ sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock;
+ v4l2_subdev_init_finalize(&sensor->subdev);
+
+ return 0;
+}
+
+static void imx415_subdev_cleanup(struct imx415 *sensor)
+{
+ media_entity_cleanup(&sensor->subdev.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+}
+
+static int imx415_power_on(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret < 0)
+ return ret;
+
+ gpiod_set_value_cansleep(sensor->reset, 0);
+
+ udelay(1);
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret < 0)
+ goto err_reset;
+
+ /*
+ * Data sheet states that 20 us are required before communication start,
+ * but this doesn't work in all cases. Use 100 us to be on the safe
+ * side.
+ */
+ usleep_range(100, 200);
+
+ return 0;
+
+err_reset:
+ gpiod_set_value_cansleep(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+ return ret;
+}
+
+static void imx415_power_off(struct imx415 *sensor)
+{
+ clk_disable_unprepare(sensor->clk);
+ gpiod_set_value_cansleep(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+}
+
+static int imx415_identify_model(struct imx415 *sensor)
+{
+ int model, ret;
+
+ /*
+ * While most registers can be read when the sensor is in standby, this
+ * is not the case of the sensor info register :-(
+ */
+ ret = imx415_wakeup(sensor);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to get sensor out of standby\n");
+
+ ret = imx415_read(sensor, IMX415_SENSOR_INFO);
+ if (ret < 0) {
+ dev_err_probe(sensor->dev, ret,
+ "failed to read sensor information\n");
+ goto done;
+ }
+
+ model = ret & IMX415_SENSOR_INFO_MASK;
+
+ switch (model) {
+ case IMX415_CHIP_ID:
+ dev_info(sensor->dev, "Detected IMX415 image sensor\n");
+ break;
+ default:
+ ret = dev_err_probe(sensor->dev, -ENODEV,
+ "invalid device model 0x%04x\n", model);
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY);
+ return ret;
+}
+
+static int imx415_check_inck(unsigned long inck, u64 link_frequency)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) {
+ if ((imx415_clk_params[i].lane_rate == link_frequency * 2) &&
+ imx415_clk_params[i].inck == inck)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(imx415_clk_params))
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static int imx415_parse_hw_config(struct imx415 *sensor)
+{
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *ep;
+ u64 lane_rate;
+ unsigned long inck;
+ unsigned int i, j;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i)
+ sensor->supplies[i].supply = imx415_supply_names[i];
+
+ ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to get supplies\n");
+
+ sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->reset))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
+ "failed to get reset GPIO\n");
+
+ sensor->clk = devm_clk_get(sensor->dev, "inck");
+ if (IS_ERR(sensor->clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
+ "failed to get clock\n");
+
+ ep = fwnode_graph_get_next_endpoint(dev_fwnode(sensor->dev), NULL);
+ if (!ep)
+ return -ENXIO;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return ret;
+
+ switch (bus_cfg.bus.mipi_csi2.num_data_lanes) {
+ case 2:
+ case 4:
+ sensor->num_data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+ break;
+ default:
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "invalid number of CSI2 data lanes %d\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ goto done_endpoint_free;
+ }
+
+ if (!bus_cfg.nr_of_link_frequencies) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "no link frequencies defined");
+ goto done_endpoint_free;
+ }
+
+ /*
+ * Check if there exists a sensor mode defined for current INCK,
+ * number of lanes and given lane rates.
+ */
+ inck = clk_get_rate(sensor->clk);
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; ++i) {
+ if (imx415_check_inck(inck, bus_cfg.link_frequencies[i])) {
+ dev_dbg(sensor->dev,
+ "INCK %lu Hz not supported for this link freq",
+ inck);
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) {
+ if (sensor->num_data_lanes != supported_modes[j].lanes)
+ continue;
+ if (bus_cfg.link_frequencies[i] * 2 !=
+ supported_modes[j].lane_rate)
+ continue;
+ sensor->cur_mode = j;
+ break;
+ }
+ if (j < ARRAY_SIZE(supported_modes))
+ break;
+ }
+ if (i == bus_cfg.nr_of_link_frequencies) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "no valid sensor mode defined\n");
+ goto done_endpoint_free;
+ }
+
+ lane_rate = supported_modes[sensor->cur_mode].lane_rate;
+ for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) {
+ if (lane_rate == imx415_clk_params[i].lane_rate &&
+ inck == imx415_clk_params[i].inck) {
+ sensor->clk_params = &imx415_clk_params[i];
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(imx415_clk_params)) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "Mode %d not supported\n",
+ sensor->cur_mode);
+ goto done_endpoint_free;
+ }
+
+ ret = 0;
+ dev_dbg(sensor->dev, "clock: %lu Hz, lane_rate: %llu bps, lanes: %d\n",
+ inck, lane_rate, sensor->num_data_lanes);
+
+done_endpoint_free:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int imx415_probe(struct i2c_client *client)
+{
+ struct imx415 *sensor;
+ int ret;
+
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->dev = &client->dev;
+
+ ret = imx415_parse_hw_config(sensor);
+ if (ret)
+ return ret;
+
+ sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config);
+ if (IS_ERR(sensor->regmap))
+ return PTR_ERR(sensor->regmap);
+
+ /*
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here, identify it, and fully initialize it.
+ */
+ ret = imx415_power_on(sensor);
+ if (ret)
+ return ret;
+
+ ret = imx415_identify_model(sensor);
+ if (ret)
+ goto err_power;
+
+ ret = imx415_subdev_init(sensor);
+ if (ret)
+ goto err_power;
+
+ /*
+ * Enable runtime PM. As the device has been powered manually, mark it
+ * as active, and increase the usage count without resuming the device.
+ */
+ pm_runtime_set_active(sensor->dev);
+ pm_runtime_get_noresume(sensor->dev);
+ pm_runtime_enable(sensor->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&sensor->subdev);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Finally, enable autosuspend and decrease the usage count. The device
+ * will get suspended after the autosuspend delay, turning the power
+ * off.
+ */
+ pm_runtime_set_autosuspend_delay(sensor->dev, 1000);
+ pm_runtime_use_autosuspend(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(sensor->dev);
+ pm_runtime_put_noidle(sensor->dev);
+ imx415_subdev_cleanup(sensor);
+err_power:
+ imx415_power_off(sensor);
+ return ret;
+}
+
+static void imx415_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ v4l2_async_unregister_subdev(subdev);
+
+ imx415_subdev_cleanup(sensor);
+
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(sensor->dev);
+ if (!pm_runtime_status_suspended(sensor->dev))
+ imx415_power_off(sensor);
+ pm_runtime_set_suspended(sensor->dev);
+}
+
+static int imx415_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ return imx415_power_on(sensor);
+}
+
+static int imx415_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ imx415_power_off(sensor);
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx415_pm_ops, imx415_runtime_suspend,
+ imx415_runtime_resume, NULL);
+
+static const struct of_device_id imx415_of_match[] = {
+ { .compatible = "sony,imx415" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, imx415_of_match);
+
+static struct i2c_driver imx415_driver = {
+ .probe_new = imx415_probe,
+ .remove = imx415_remove,
+ .driver = {
+ .name = "imx415",
+ .of_match_table = imx415_of_match,
+ .pm = pm_ptr(&imx415_pm_ops),
+ },
+};
+
+module_i2c_driver(imx415_driver);
+
+MODULE_DESCRIPTION("Sony IMX415 image sensor driver");
+MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>");
+MODULE_AUTHOR("Michael Riesch <michael.riesch@wolfvision.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index dd6477548f29..701038d6d19b 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -1113,6 +1113,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
err_put_node:
fwnode_handle_put(ep);
err_async:
+ v4l2_ctrl_handler_free(&priv->ctrls);
max9286_v4l2_notifier_unregister(priv);
return ret;
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index f3731f932a94..89d126240c34 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -629,8 +629,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov2740_test_pattern_menu) - 1,
0, 0, ov2740_test_pattern_menu);
- if (ctrl_hdlr->error)
+ if (ctrl_hdlr->error) {
+ v4l2_ctrl_handler_free(ctrl_hdlr);
return ctrl_hdlr->error;
+ }
ov2740->sd.ctrl_handler = ctrl_hdlr;
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index e0f908af581b..1536649b9e90 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -50,6 +50,7 @@
#define OV5640_REG_SYS_CTRL0 0x3008
#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
#define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02
+#define OV5640_REG_SYS_CTRL0_SW_RST 0x82
#define OV5640_REG_CHIP_ID 0x300a
#define OV5640_REG_IO_MIPI_CTRL00 0x300e
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
@@ -520,7 +521,18 @@ static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
*/
/* YUV422 UYVY VGA@30fps */
-static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
+static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .width = 640,
+ .height = 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .field = V4L2_FIELD_NONE,
+};
+
+static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = {
.code = MEDIA_BUS_FMT_UYVY8_2X8,
.width = 640,
.height = 480,
@@ -532,7 +544,7 @@ static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
};
static const struct reg_value ov5640_init_setting[] = {
- {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+ {0x3103, 0x11, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
@@ -2424,24 +2436,48 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable)
gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
}
-static void ov5640_reset(struct ov5640_dev *sensor)
+/*
+ * From section 2.7 power up sequence:
+ * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down
+ * t3 >= 1ms Delay from PWDN pull down to RESETB pull up
+ * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable
+ *
+ * Some modules don't expose RESETB/PWDN pins directly, instead providing a
+ * "PWUP" GPIO which is wired through appropriate delays and inverters to the
+ * pins.
+ *
+ * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we
+ * should still toggle the pwdn_gpio below with the appropriate delays, while
+ * the calls to reset_gpio will be ignored.
+ */
+static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
{
- if (!sensor->reset_gpio)
- return;
-
- gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ if (sensor->pwdn_gpio) {
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
- /* camera power cycle */
- ov5640_power(sensor, false);
- usleep_range(5000, 10000);
- ov5640_power(sensor, true);
- usleep_range(5000, 10000);
+ /* camera power cycle */
+ ov5640_power(sensor, false);
+ usleep_range(5000, 10000);
+ ov5640_power(sensor, true);
+ usleep_range(5000, 10000);
- gpiod_set_value_cansleep(sensor->reset_gpio, 1);
- usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
+ usleep_range(1000, 2000);
- gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ } else {
+ /* software reset */
+ ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
+ OV5640_REG_SYS_CTRL0_SW_RST);
+ }
usleep_range(20000, 25000);
+
+ /*
+ * software standby: allows registers programming;
+ * exit at restore_mode() for CSI, s_stream(1) for DVP
+ */
+ ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
+ OV5640_REG_SYS_CTRL0_SW_PWDN);
}
static int ov5640_set_power_on(struct ov5640_dev *sensor)
@@ -2464,8 +2500,7 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
goto xclk_off;
}
- ov5640_reset(sensor);
- ov5640_power(sensor, true);
+ ov5640_powerup_sequence(sensor);
ret = ov5640_init_slave_id(sensor);
if (ret)
@@ -3316,6 +3351,7 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
break;
}
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
return 0;
@@ -3391,6 +3427,7 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
return ret;
@@ -3458,7 +3495,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
/* Auto/manual gain */
ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
0, 1, 1, 1);
- ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
0, 1023, 1, 0);
ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
@@ -3710,8 +3747,10 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
out:
mutex_unlock(&sensor->lock);
- if (!enable || ret)
+ if (!enable || ret) {
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
+ }
return ret;
}
@@ -3719,11 +3758,13 @@ out:
static int ov5640_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
struct v4l2_mbus_framefmt *fmt =
v4l2_subdev_get_try_format(sd, state, 0);
struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
- *fmt = ov5640_default_fmt;
+ *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
+ ov5640_dvp_default_fmt;
crop->left = OV5640_PIXEL_ARRAY_LEFT;
crop->top = OV5640_PIXEL_ARRAY_TOP;
@@ -3812,7 +3853,6 @@ static int ov5640_probe(struct i2c_client *client)
* default init sequence initialize sensor to
* YUV422 UYVY VGA@30fps
*/
- sensor->fmt = ov5640_default_fmt;
sensor->frame_interval.numerator = 1;
sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
sensor->current_fr = OV5640_30_FPS;
@@ -3845,6 +3885,9 @@ static int ov5640_probe(struct i2c_client *client)
return -EINVAL;
}
+ sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
+ ov5640_dvp_default_fmt;
+
/* get system clock (xclk) */
sensor->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(sensor->xclk)) {
@@ -3912,6 +3955,7 @@ static int ov5640_probe(struct i2c_client *client)
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index bc9fc3bc90c2..f79d908f4531 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1,15 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Intel Corporation.
+#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
+#define OV5670_XVCLK_FREQ 19200000
+
#define OV5670_REG_CHIP_ID 0x300a
#define OV5670_CHIP_ID 0x005670
@@ -65,6 +74,10 @@
#define OV5670_REG_VALUE_16BIT 2
#define OV5670_REG_VALUE_24BIT 3
+/* Pixel Array */
+#define OV5670_NATIVE_WIDTH 2624
+#define OV5670_NATIVE_HEIGHT 1980
+
/* Initial number of frames to skip to avoid possible garbage */
#define OV5670_NUM_OF_SKIP_FRAMES 2
@@ -83,6 +96,14 @@ struct ov5670_link_freq_config {
const struct ov5670_reg_list reg_list;
};
+static const char * const ov5670_supply_names[] = {
+ "avdd", /* Analog power */
+ "dvdd", /* Digital power */
+ "dovdd", /* Digital output power */
+};
+
+#define OV5670_NUM_SUPPLIES ARRAY_SIZE(ov5670_supply_names)
+
struct ov5670_mode {
/* Frame width in pixels */
u32 width;
@@ -99,10 +120,25 @@ struct ov5670_mode {
/* Link frequency needed for this resolution */
u32 link_freq_index;
+ /* Analog crop rectangle */
+ const struct v4l2_rect *analog_crop;
+
/* Sensor register settings for this resolution */
const struct ov5670_reg_list reg_list;
};
+/*
+ * All the modes supported by the driver are obtained by subsampling the
+ * full pixel array. The below values are reflected in registers from
+ * 0x3800-0x3807 in the modes register-value tables.
+ */
+static const struct v4l2_rect ov5670_analog_crop = {
+ .left = 12,
+ .top = 4,
+ .width = 2600,
+ .height = 1952,
+};
+
static const struct ov5670_reg mipi_data_rate_840mbps[] = {
{0x0300, 0x04},
{0x0301, 0x00},
@@ -1750,66 +1786,73 @@ static const struct ov5670_mode supported_modes[] = {
.height = 1944,
.vts_def = OV5670_VTS_30FPS,
.vts_min = OV5670_VTS_30FPS,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2592x1944_regs),
.regs = mode_2592x1944_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 1296,
.height = 972,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 996,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1296x972_regs),
.regs = mode_1296x972_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 648,
.height = 486,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 516,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_648x486_regs),
.regs = mode_648x486_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 2560,
.height = 1440,
.vts_def = OV5670_VTS_30FPS,
.vts_min = OV5670_VTS_30FPS,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2560x1440_regs),
.regs = mode_2560x1440_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 1280,
.height = 720,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 1020,
+
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
.regs = mode_1280x720_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 640,
.height = 360,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 510,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_640x360_regs),
.regs = mode_640x360_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
}
};
@@ -1828,6 +1871,16 @@ struct ov5670 {
/* Current mode */
const struct ov5670_mode *cur_mode;
+ /* xvclk input clock */
+ struct clk *xvclk;
+
+ /* Regulators */
+ struct regulator_bulk_data supplies[OV5670_NUM_SUPPLIES];
+
+ /* Power-down and reset gpios. */
+ struct gpio_desc *pwdn_gpio; /* PWDNB pin. */
+ struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */
+
/* To serialize asynchronus callbacks */
struct mutex mutex;
@@ -1935,27 +1988,6 @@ static int ov5670_write_reg_list(struct ov5670 *ov5670,
return ov5670_write_regs(ov5670, r_list->regs, r_list->num_of_regs);
}
-/* Open sub-device */
-static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct ov5670 *ov5670 = to_ov5670(sd);
- struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
-
- mutex_lock(&ov5670->mutex);
-
- /* Initialize try_fmt */
- try_fmt->width = ov5670->cur_mode->width;
- try_fmt->height = ov5670->cur_mode->height;
- try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
- try_fmt->field = V4L2_FIELD_NONE;
-
- /* No crop or compose */
- mutex_unlock(&ov5670->mutex);
-
- return 0;
-}
-
static int ov5670_update_digital_gain(struct ov5670 *ov5670, u32 d_gain)
{
int ret;
@@ -2006,7 +2038,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
struct ov5670, ctrl_handler);
struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
s64 max;
- int ret = 0;
+ int ret;
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
@@ -2045,7 +2077,13 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
ret = ov5670_enable_test_pattern(ov5670, ctrl->val);
break;
+ case V4L2_CID_HBLANK:
+ case V4L2_CID_LINK_FREQ:
+ case V4L2_CID_PIXEL_RATE:
+ ret = 0;
+ break;
default:
+ ret = -EINVAL;
dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
break;
@@ -2155,6 +2193,28 @@ error:
return ret;
}
+static int ov5670_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_get_try_format(sd, state, 0);
+ const struct ov5670_mode *default_mode = &supported_modes[0];
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+
+ fmt->width = default_mode->width;
+ fmt->height = default_mode->height;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB);
+
+ *crop = *default_mode->analog_crop;
+
+ return 0;
+}
+
static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -2404,6 +2464,49 @@ unlock_and_return:
return ret;
}
+static int __maybe_unused ov5670_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5670 *ov5670 = to_ov5670(sd);
+ unsigned long delay_us;
+ int ret;
+
+ ret = clk_prepare_enable(ov5670->xvclk);
+ if (ret)
+ return ret;
+
+ ret = regulator_bulk_enable(OV5670_NUM_SUPPLIES, ov5670->supplies);
+ if (ret) {
+ clk_disable_unprepare(ov5670->xvclk);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov5670->pwdn_gpio, 0);
+ gpiod_set_value_cansleep(ov5670->reset_gpio, 0);
+
+ /* 8192 * 2 clock pulses before the first SCCB transaction. */
+ delay_us = DIV_ROUND_UP(8192 * 2 * 1000,
+ DIV_ROUND_UP(OV5670_XVCLK_FREQ, 1000));
+ fsleep(delay_us);
+
+ return 0;
+}
+
+static int __maybe_unused ov5670_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5670 *ov5670 = to_ov5670(sd);
+
+ gpiod_set_value_cansleep(ov5670->reset_gpio, 1);
+ gpiod_set_value_cansleep(ov5670->pwdn_gpio, 1);
+ regulator_bulk_disable(OV5670_NUM_SUPPLIES, ov5670->supplies);
+ clk_disable_unprepare(ov5670->xvclk);
+
+ return 0;
+}
+
static int __maybe_unused ov5670_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -2438,15 +2541,64 @@ static const struct v4l2_subdev_core_ops ov5670_core_ops = {
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
+static const struct v4l2_rect *
+__ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ const struct ov5670_mode *mode = sensor->cur_mode;
+
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return mode->analog_crop;
+ }
+
+ return NULL;
+}
+
+static int ov5670_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov5670 *sensor = to_ov5670(subdev);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ mutex_lock(&sensor->mutex);
+ sel->r = *__ov5670_get_pad_crop(sensor, state, sel->pad,
+ sel->which);
+ mutex_unlock(&sensor->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 = OV5670_NATIVE_WIDTH;
+ sel->r.height = OV5670_NATIVE_HEIGHT;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r = ov5670_analog_crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct v4l2_subdev_video_ops ov5670_video_ops = {
.s_stream = ov5670_set_stream,
};
static const struct v4l2_subdev_pad_ops ov5670_pad_ops = {
+ .init_cfg = ov5670_init_cfg,
.enum_mbus_code = ov5670_enum_mbus_code,
.get_fmt = ov5670_get_pad_format,
.set_fmt = ov5670_set_pad_format,
.enum_frame_size = ov5670_enum_frame_size,
+ .get_selection = ov5670_get_selection,
+ .set_selection = ov5670_get_selection,
};
static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = {
@@ -2464,9 +2616,34 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
-static const struct v4l2_subdev_internal_ops ov5670_internal_ops = {
- .open = ov5670_open,
-};
+static int ov5670_regulators_probe(struct ov5670 *ov5670)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
+ unsigned int i;
+
+ for (i = 0; i < OV5670_NUM_SUPPLIES; i++)
+ ov5670->supplies[i].supply = ov5670_supply_names[i];
+
+ return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES,
+ ov5670->supplies);
+}
+
+static int ov5670_gpio_probe(struct ov5670 *ov5670)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
+
+ ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov5670->pwdn_gpio))
+ return PTR_ERR(ov5670->pwdn_gpio);
+
+ ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov5670->reset_gpio))
+ return PTR_ERR(ov5670->reset_gpio);
+
+ return 0;
+}
static int ov5670_probe(struct i2c_client *client)
{
@@ -2476,10 +2653,6 @@ static int ov5670_probe(struct i2c_client *client)
bool full_power;
int ret;
- device_property_read_u32(&client->dev, "clock-frequency", &input_clk);
- if (input_clk != 19200000)
- return -EINVAL;
-
ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL);
if (!ov5670) {
ret = -ENOMEM;
@@ -2487,16 +2660,50 @@ static int ov5670_probe(struct i2c_client *client)
goto error_print;
}
+ ov5670->xvclk = devm_clk_get(&client->dev, NULL);
+ if (!IS_ERR_OR_NULL(ov5670->xvclk))
+ input_clk = clk_get_rate(ov5670->xvclk);
+ else if (PTR_ERR(ov5670->xvclk) == -ENOENT)
+ device_property_read_u32(&client->dev, "clock-frequency",
+ &input_clk);
+ else
+ return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk),
+ "error getting clock\n");
+
+ if (input_clk != OV5670_XVCLK_FREQ) {
+ dev_err(&client->dev,
+ "Unsupported clock frequency %u\n", input_clk);
+ return -EINVAL;
+ }
+
/* Initialize subdev */
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;
+ }
+
+ ret = ov5670_gpio_probe(ov5670);
+ if (ret) {
+ err_msg = "GPIO probe failed";
+ goto error_print;
+ }
+
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;
+ }
+
/* Check module identity */
ret = ov5670_identify_module(ov5670);
if (ret) {
err_msg = "ov5670_identify_module() error";
- goto error_print;
+ goto error_power_off;
}
}
@@ -2511,7 +2718,6 @@ static int ov5670_probe(struct i2c_client *client)
goto error_mutex_destroy;
}
- ov5670->sd.internal_ops = &ov5670_internal_ops;
ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
ov5670->sd.entity.ops = &ov5670_subdev_entity_ops;
@@ -2525,24 +2731,27 @@ static int ov5670_probe(struct i2c_client *client)
goto error_handler_free;
}
- /* Async register for subdev */
- ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
- if (ret < 0) {
- err_msg = "v4l2_async_register_subdev() error";
- goto error_entity_cleanup;
- }
-
ov5670->streaming = false;
/* 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);
+
+ /* Async register for subdev */
+ ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
+ if (ret < 0) {
+ err_msg = "v4l2_async_register_subdev() error";
+ goto error_pm_disable;
+ }
+
pm_runtime_idle(&client->dev);
return 0;
-error_entity_cleanup:
+error_pm_disable:
+ pm_runtime_disable(&client->dev);
+
media_entity_cleanup(&ov5670->sd.entity);
error_handler_free:
@@ -2551,6 +2760,10 @@ error_handler_free:
error_mutex_destroy:
mutex_destroy(&ov5670->mutex);
+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);
@@ -2568,10 +2781,12 @@ static void ov5670_remove(struct i2c_client *client)
mutex_destroy(&ov5670->mutex);
pm_runtime_disable(&client->dev);
+ ov5670_runtime_suspend(&client->dev);
}
static const struct dev_pm_ops ov5670_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume)
+ SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL)
};
#ifdef CONFIG_ACPI
@@ -2583,11 +2798,18 @@ static const struct acpi_device_id ov5670_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ov5670_acpi_ids);
#endif
+static const struct of_device_id ov5670_of_ids[] = {
+ { .compatible = "ovti,ov5670" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov5670_of_ids);
+
static struct i2c_driver ov5670_i2c_driver = {
.driver = {
.name = "ov5670",
.pm = &ov5670_pm_ops,
.acpi_match_table = ACPI_PTR(ov5670_acpi_ids),
+ .of_match_table = ov5670_of_ids,
},
.probe_new = ov5670_probe,
.remove = ov5670_remove,
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index 94dc8cb7a7c0..d55180b3b7aa 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -3,10 +3,14 @@
#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@@ -17,7 +21,7 @@
#define OV5675_LINK_FREQ_450MHZ 450000000ULL
#define OV5675_SCLK 90000000LL
-#define OV5675_MCLK 19200000
+#define OV5675_XVCLK_19_2 19200000
#define OV5675_DATA_LANES 2
#define OV5675_RGB_DEPTH 10
@@ -76,6 +80,14 @@
#define to_ov5675(_sd) container_of(_sd, struct ov5675, sd)
+static const char * const ov5675_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV5675_NUM_SUPPLIES ARRAY_SIZE(ov5675_supply_names)
+
enum {
OV5675_LINK_FREQ_900MBPS,
};
@@ -484,6 +496,9 @@ struct ov5675 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[OV5675_NUM_SUPPLIES];
/* V4L2 Controls */
struct v4l2_ctrl *link_freq;
@@ -764,12 +779,14 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = {
static int ov5675_init_controls(struct ov5675 *ov5675)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
+ struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
s64 exposure_max, h_blank;
int ret;
ctrl_hdlr = &ov5675->ctrl_handler;
- ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
if (ret)
return ret;
@@ -820,12 +837,28 @@ static int ov5675_init_controls(struct ov5675 *ov5675)
v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- if (ctrl_hdlr->error)
+ if (ctrl_hdlr->error) {
+ v4l2_ctrl_handler_free(ctrl_hdlr);
return ctrl_hdlr->error;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov5675_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
ov5675->sd.ctrl_handler = ctrl_hdlr;
return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
}
static void ov5675_update_pad_format(const struct ov5675_mode *mode,
@@ -944,6 +977,56 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
+static int ov5675_power_off(struct device *dev)
+{
+ /* 512 xvclk cycles after the last SCCB transation or MIPI frame end */
+ u32 delay_us = DIV_ROUND_UP(512, OV5675_XVCLK_19_2 / 1000 / 1000);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5675 *ov5675 = to_ov5675(sd);
+
+ usleep_range(delay_us, delay_us * 2);
+
+ clk_disable_unprepare(ov5675->xvclk);
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
+ regulator_bulk_disable(OV5675_NUM_SUPPLIES, ov5675->supplies);
+
+ return 0;
+}
+
+static int ov5675_power_on(struct device *dev)
+{
+ u32 delay_us = DIV_ROUND_UP(8192, OV5675_XVCLK_19_2 / 1000 / 1000);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5675 *ov5675 = to_ov5675(sd);
+ int ret;
+
+ ret = clk_prepare_enable(ov5675->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable xvclk: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(OV5675_NUM_SUPPLIES, ov5675->supplies);
+ if (ret) {
+ clk_disable_unprepare(ov5675->xvclk);
+ return ret;
+ }
+
+ /* Reset pulse should be at least 2ms and reset gpio released only once
+ * regulators are stable.
+ */
+ usleep_range(2000, 2200);
+
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 0);
+
+ /* 8192 xvclk cycles prior to the first SCCB transation */
+ usleep_range(delay_us, delay_us * 2);
+
+ return 0;
+}
+
static int __maybe_unused ov5675_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -1040,6 +1123,31 @@ static int ov5675_get_format(struct v4l2_subdev *sd,
return 0;
}
+static int ov5675_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = 2624;
+ sel->r.height = 2000;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = 16;
+ sel->r.left = 16;
+ sel->r.width = 2592;
+ sel->r.height = 1944;
+ return 0;
+ }
+ return -EINVAL;
+}
+
static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -1089,6 +1197,7 @@ static const struct v4l2_subdev_video_ops ov5675_video_ops = {
static const struct v4l2_subdev_pad_ops ov5675_pad_ops = {
.set_fmt = ov5675_set_format,
.get_fmt = ov5675_get_format,
+ .get_selection = ov5675_get_selection,
.enum_mbus_code = ov5675_enum_mbus_code,
.enum_frame_size = ov5675_enum_frame_size,
};
@@ -1106,32 +1215,60 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = {
.open = ov5675_open,
};
-static int ov5675_check_hwcfg(struct device *dev)
+static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev)
{
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
- u32 mclk;
+ u32 xvclk_rate;
int ret;
unsigned int i, j;
if (!fwnode)
return -ENXIO;
- ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
+ ov5675->xvclk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(ov5675->xvclk))
+ return dev_err_probe(dev, PTR_ERR(ov5675->xvclk),
+ "failed to get xvclk: %ld\n",
+ PTR_ERR(ov5675->xvclk));
- if (ret) {
- dev_err(dev, "can't get clock frequency");
- return ret;
+ if (ov5675->xvclk) {
+ xvclk_rate = clk_get_rate(ov5675->xvclk);
+ } else {
+ ret = fwnode_property_read_u32(fwnode, "clock-frequency",
+ &xvclk_rate);
+
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ return ret;
+ }
}
- if (mclk != OV5675_MCLK) {
- dev_err(dev, "external clock %d is not supported", mclk);
+ if (xvclk_rate != OV5675_XVCLK_19_2) {
+ dev_err(dev, "external clock rate %u is unsupported",
+ xvclk_rate);
return -EINVAL;
}
+ ov5675->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov5675->reset_gpio)) {
+ ret = PTR_ERR(ov5675->reset_gpio);
+ dev_err(dev, "failed to get reset-gpios: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < OV5675_NUM_SUPPLIES; i++)
+ ov5675->supplies[i].supply = ov5675_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, OV5675_NUM_SUPPLIES,
+ ov5675->supplies);
+ if (ret)
+ return ret;
+
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
return -ENXIO;
@@ -1185,6 +1322,10 @@ static void ov5675_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(&client->dev);
mutex_destroy(&ov5675->mutex);
+
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov5675_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
}
static int ov5675_probe(struct i2c_client *client)
@@ -1193,25 +1334,31 @@ static int ov5675_probe(struct i2c_client *client)
bool full_power;
int ret;
- ret = ov5675_check_hwcfg(&client->dev);
+ ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL);
+ if (!ov5675)
+ return -ENOMEM;
+
+ ret = ov5675_get_hwcfg(ov5675, &client->dev);
if (ret) {
- dev_err(&client->dev, "failed to check HW configuration: %d",
+ dev_err(&client->dev, "failed to get HW configuration: %d",
ret);
return ret;
}
- ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL);
- if (!ov5675)
- return -ENOMEM;
-
v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops);
+ ret = ov5675_power_on(&client->dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to power on: %d\n", ret);
+ return ret;
+ }
+
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
ret = ov5675_identify_module(ov5675);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d", ret);
- return ret;
+ goto probe_power_off;
}
}
@@ -1241,11 +1388,6 @@ static int ov5675_probe(struct i2c_client *client)
goto probe_error_media_entity_cleanup;
}
- /*
- * Device is already turned on by i2c-core with ACPI domain PM.
- * Enable runtime PM and turn off the device.
- */
-
/* Set the device's state to active if it's in D0 state. */
if (full_power)
pm_runtime_set_active(&client->dev);
@@ -1260,12 +1402,15 @@ probe_error_media_entity_cleanup:
probe_error_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler);
mutex_destroy(&ov5675->mutex);
+probe_power_off:
+ ov5675_power_off(&client->dev);
return ret;
}
static const struct dev_pm_ops ov5675_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume)
+ SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL)
};
#ifdef CONFIG_ACPI
@@ -1277,11 +1422,18 @@ static const struct acpi_device_id ov5675_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids);
#endif
+static const struct of_device_id ov5675_of_match[] = {
+ { .compatible = "ovti,ov5675", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov5675_of_match);
+
static struct i2c_driver ov5675_i2c_driver = {
.driver = {
.name = "ov5675",
.pm = &ov5675_pm_ops,
.acpi_match_table = ACPI_PTR(ov5675_acpi_ids),
+ .of_match_table = ov5675_of_match,
},
.probe_new = ov5675_probe,
.remove = ov5675_remove,
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 27db0a07de1f..b1bb0833571e 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1840,7 +1840,7 @@ static int ov7670_parse_dt(struct device *dev,
if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
dev_err(dev, "Unsupported media bus type\n");
- return ret;
+ return -EINVAL;
}
info->mbus_config = bus_cfg.bus.parallel.flags;
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 4189e3fc3d53..a238e63425f8 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -1462,7 +1462,7 @@ static int ov772x_probe(struct i2c_client *client)
priv->subdev.ctrl_handler = &priv->hdl;
if (priv->hdl.error) {
ret = priv->hdl.error;
- goto error_mutex_destroy;
+ goto error_ctrl_free;
}
priv->clk = clk_get(&client->dev, NULL);
@@ -1515,7 +1515,6 @@ error_clk_put:
clk_put(priv->clk);
error_ctrl_free:
v4l2_ctrl_handler_free(&priv->hdl);
-error_mutex_destroy:
mutex_destroy(&priv->lock);
return ret;
diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c
new file mode 100644
index 000000000000..9ca8a17bfbb9
--- /dev/null
+++ b/drivers/media/i2c/ov8858.c
@@ -0,0 +1,2008 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+ * Copyright (C) 2022 Nicholas Roth <nicholas@rothemail.net>
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define OV8858_LINK_FREQ 360000000U
+#define OV8858_XVCLK_FREQ 24000000
+
+#define OV8858_REG_SIZE_SHIFT 16
+#define OV8858_REG_ADDR_MASK 0xffff
+#define OV8858_REG_8BIT(n) ((1U << OV8858_REG_SIZE_SHIFT) | (n))
+#define OV8858_REG_16BIT(n) ((2U << OV8858_REG_SIZE_SHIFT) | (n))
+#define OV8858_REG_24BIT(n) ((3U << OV8858_REG_SIZE_SHIFT) | (n))
+
+#define OV8858_REG_SC_CTRL0100 OV8858_REG_8BIT(0x0100)
+#define OV8858_MODE_SW_STANDBY 0x0
+#define OV8858_MODE_STREAMING 0x1
+
+#define OV8858_REG_CHIP_ID OV8858_REG_24BIT(0x300a)
+#define OV8858_CHIP_ID 0x008858
+
+#define OV8858_REG_SUB_ID OV8858_REG_8BIT(0x302a)
+#define OV8858_R1A 0xb0
+#define OV8858_R2A 0xb2
+
+#define OV8858_REG_LONG_EXPO OV8858_REG_24BIT(0x3500)
+#define OV8858_EXPOSURE_MIN 4
+#define OV8858_EXPOSURE_STEP 1
+#define OV8858_EXPOSURE_MARGIN 4
+
+#define OV8858_REG_LONG_GAIN OV8858_REG_16BIT(0x3508)
+#define OV8858_LONG_GAIN_MIN 0x0
+#define OV8858_LONG_GAIN_MAX 0x7ff
+#define OV8858_LONG_GAIN_STEP 1
+#define OV8858_LONG_GAIN_DEFAULT 0x80
+
+#define OV8858_REG_LONG_DIGIGAIN OV8858_REG_16BIT(0x350a)
+#define OV8858_LONG_DIGIGAIN_H_MASK 0x3fc0
+#define OV8858_LONG_DIGIGAIN_L_MASK 0x3f
+#define OV8858_LONG_DIGIGAIN_H_SHIFT 2
+#define OV8858_LONG_DIGIGAIN_MIN 0x0
+#define OV8858_LONG_DIGIGAIN_MAX 0x3fff
+#define OV8858_LONG_DIGIGAIN_STEP 1
+#define OV8858_LONG_DIGIGAIN_DEFAULT 0x200
+
+#define OV8858_REG_VTS OV8858_REG_16BIT(0x380e)
+#define OV8858_VTS_MAX 0x7fff
+
+#define OV8858_REG_TEST_PATTERN OV8858_REG_8BIT(0x5e00)
+#define OV8858_TEST_PATTERN_ENABLE 0x80
+#define OV8858_TEST_PATTERN_DISABLE 0x0
+
+#define REG_NULL 0xffff
+
+static const char * const ov8858_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+struct regval {
+ u16 addr;
+ u8 val;
+};
+
+struct regval_modes {
+ const struct regval *mode_2lanes;
+ const struct regval *mode_4lanes;
+};
+
+struct ov8858_mode {
+ u32 width;
+ u32 height;
+ u32 hts_def;
+ u32 vts_def;
+ u32 exp_def;
+ const struct regval_modes reg_modes;
+};
+
+struct ov8858 {
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *pwdn_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ov8858_supply_names)];
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+
+ const struct regval *global_regs;
+
+ unsigned int num_lanes;
+};
+
+static inline struct ov8858 *sd_to_ov8858(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov8858, subdev);
+}
+
+static const struct regval ov8858_global_regs_r1a[] = {
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0302, 0x1e},
+ {0x0303, 0x00},
+ {0x0304, 0x03},
+ {0x030e, 0x00},
+ {0x030f, 0x09},
+ {0x0312, 0x01},
+ {0x031e, 0x0c},
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x30},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x06},
+ {0x360c, 0xdc},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0xb0},
+ {0x3618, 0x56},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x00},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0c},
+ {0x3634, 0x0c},
+ {0x3635, 0x0c},
+ {0x3636, 0x0c},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x01},
+ {0x3018, 0x32},
+ {0x3020, 0x93},
+ {0x3022, 0x01},
+ {0x3031, 0x0a},
+ {0x3034, 0x00},
+ {0x3106, 0x01},
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00},
+ {0x3501, 0x4d},
+ {0x3502, 0x40},
+ {0x3503, 0x00},
+ {0x3505, 0x80},
+ {0x3508, 0x04},
+ {0x3509, 0x00},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3700, 0x18},
+ {0x3701, 0x0c},
+ {0x3702, 0x28},
+ {0x3703, 0x19},
+ {0x3704, 0x14},
+ {0x3705, 0x00},
+ {0x3706, 0x35},
+ {0x3707, 0x04},
+ {0x3708, 0x24},
+ {0x3709, 0x33},
+ {0x370a, 0x00},
+ {0x370b, 0xb5},
+ {0x370c, 0x04},
+ {0x3718, 0x12},
+ {0x3719, 0x31},
+ {0x3712, 0x42},
+ {0x3714, 0x24},
+ {0x371e, 0x19},
+ {0x371f, 0x40},
+ {0x3720, 0x05},
+ {0x3721, 0x05},
+ {0x3724, 0x06},
+ {0x3725, 0x01},
+ {0x3726, 0x06},
+ {0x3728, 0x05},
+ {0x3729, 0x02},
+ {0x372a, 0x03},
+ {0x372b, 0x53},
+ {0x372c, 0xa3},
+ {0x372d, 0x53},
+ {0x372e, 0x06},
+ {0x372f, 0x10},
+ {0x3730, 0x01},
+ {0x3731, 0x06},
+ {0x3732, 0x14},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x20},
+ {0x373a, 0x05},
+ {0x373b, 0x06},
+ {0x373c, 0x0a},
+ {0x373e, 0x03},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x06},
+ {0x375b, 0x13},
+ {0x375c, 0x20},
+ {0x375d, 0x02},
+ {0x375e, 0x00},
+ {0x375f, 0x14},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x23},
+ {0x3773, 0x02},
+ {0x3774, 0x16},
+ {0x3775, 0x12},
+ {0x3776, 0x04},
+ {0x3777, 0x00},
+ {0x3778, 0x1b},
+ {0x37a0, 0x44},
+ {0x37a1, 0x3d},
+ {0x37a2, 0x3d},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x44},
+ {0x37a8, 0x4c},
+ {0x37a9, 0x4c},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x44},
+ {0x37ab, 0x2e},
+ {0x37ac, 0x2e},
+ {0x37ad, 0x33},
+ {0x37ae, 0x0d},
+ {0x37af, 0x0d},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x42},
+ {0x37b4, 0x42},
+ {0x37b5, 0x33},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00},
+ {0x3801, 0x0c},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xd3},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x06},
+ {0x3809, 0x60},
+ {0x380a, 0x04},
+ {0x380b, 0xc8},
+ {0x380c, 0x07},
+ {0x380d, 0x88},
+ {0x380e, 0x04},
+ {0x380f, 0xdc},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3813, 0x02},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3820, 0x00},
+ {0x3821, 0x67},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff},
+ {0x3846, 0x48},
+ {0x3d85, 0x14},
+ {0x3f08, 0x08},
+ {0x3f0a, 0x80},
+ {0x4000, 0xf1},
+ {0x4001, 0x10},
+ {0x4005, 0x10},
+ {0x4002, 0x27},
+ {0x4009, 0x81},
+ {0x400b, 0x0c},
+ {0x401b, 0x00},
+ {0x401d, 0x00},
+ {0x4020, 0x00},
+ {0x4021, 0x04},
+ {0x4022, 0x04},
+ {0x4023, 0xb9},
+ {0x4024, 0x05},
+ {0x4025, 0x2a},
+ {0x4026, 0x05},
+ {0x4027, 0x2b},
+ {0x4028, 0x00},
+ {0x4029, 0x02},
+ {0x402a, 0x04},
+ {0x402b, 0x04},
+ {0x402c, 0x02},
+ {0x402d, 0x02},
+ {0x402e, 0x08},
+ {0x402f, 0x02},
+ {0x401f, 0x00},
+ {0x4034, 0x3f},
+ {0x403d, 0x04},
+ {0x4300, 0xff},
+ {0x4301, 0x00},
+ {0x4302, 0x0f},
+ {0x4316, 0x00},
+ {0x4500, 0x38},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32},
+ {0x4837, 0x16},
+ {0x4850, 0x10},
+ {0x4851, 0x32},
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04},
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff},
+ {0x5000, 0x7e},
+ {0x5001, 0x01},
+ {0x5002, 0x08},
+ {0x5003, 0x20},
+ {0x5046, 0x12},
+ {0x5901, 0x00},
+ {0x5e00, 0x00},
+ {0x5e01, 0x41},
+ {0x382d, 0x7f},
+ {0x4825, 0x3a},
+ {0x4826, 0x40},
+ {0x4808, 0x25},
+ {REG_NULL, 0x00},
+};
+
+static const struct regval ov8858_global_regs_r2a_2lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0103, 0x01}, /* software reset */
+ {0x0100, 0x00}, /* software standby */
+ {0x0302, 0x1e}, /* pll1_multi */
+ {0x0303, 0x00}, /* pll1_divm */
+ {0x0304, 0x03}, /* pll1_div_mipi */
+ {0x030e, 0x02}, /* pll2_rdiv */
+ {0x030f, 0x04}, /* pll2_divsp */
+ {0x0312, 0x03}, /* pll2_pre_div0, pll2_r_divdac */
+ {0x031e, 0x0c}, /* pll1_no_lat */
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x20},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x05},
+ {0x360c, 0xd4},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0x90},
+ {0x3618, 0x5a},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x0a},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0f},
+ {0x3634, 0x0f},
+ {0x3635, 0x0f},
+ {0x3636, 0x12},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x00},
+ {0x3018, 0x32}, /* MIPI 2 lane */
+ {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
+ {0x3022, 0x01}, /* pd_mipi enable when rst_sync */
+ {0x3031, 0x0a}, /* MIPI 10-bit mode */
+ {0x3034, 0x00},
+ {0x3106, 0x01}, /* sclk_div, sclk_pre_div */
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00}, /* exposure H */
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
+ {0x3505, 0x80}, /* gain option */
+ {0x3508, 0x02}, /* gain H */
+ {0x3509, 0x00}, /* gain L */
+ {0x350c, 0x00}, /* short gain H */
+ {0x350d, 0x80}, /* short gain L */
+ {0x3510, 0x00}, /* short exposure H */
+ {0x3511, 0x02}, /* short exposure M */
+ {0x3512, 0x00}, /* short exposure L */
+ {0x3700, 0x18},
+ {0x3701, 0x0c},
+ {0x3702, 0x28},
+ {0x3703, 0x19},
+ {0x3704, 0x14},
+ {0x3705, 0x00},
+ {0x3706, 0x82},
+ {0x3707, 0x04},
+ {0x3708, 0x24},
+ {0x3709, 0x33},
+ {0x370a, 0x01},
+ {0x370b, 0x82},
+ {0x370c, 0x04},
+ {0x3718, 0x12},
+ {0x3719, 0x31},
+ {0x3712, 0x42},
+ {0x3714, 0x24},
+ {0x371e, 0x19},
+ {0x371f, 0x40},
+ {0x3720, 0x05},
+ {0x3721, 0x05},
+ {0x3724, 0x06},
+ {0x3725, 0x01},
+ {0x3726, 0x06},
+ {0x3728, 0x05},
+ {0x3729, 0x02},
+ {0x372a, 0x03},
+ {0x372b, 0x53},
+ {0x372c, 0xa3},
+ {0x372d, 0x53},
+ {0x372e, 0x06},
+ {0x372f, 0x10},
+ {0x3730, 0x01},
+ {0x3731, 0x06},
+ {0x3732, 0x14},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x20},
+ {0x373a, 0x05},
+ {0x373b, 0x06},
+ {0x373c, 0x0a},
+ {0x373e, 0x03},
+ {0x3750, 0x0a},
+ {0x3751, 0x0e},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x06},
+ {0x375b, 0x13},
+ {0x375c, 0x20},
+ {0x375d, 0x02},
+ {0x375e, 0x00},
+ {0x375f, 0x14},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x23},
+ {0x3773, 0x02},
+ {0x3774, 0x16},
+ {0x3775, 0x12},
+ {0x3776, 0x04},
+ {0x3777, 0x00},
+ {0x3778, 0x17},
+ {0x37a0, 0x44},
+ {0x37a1, 0x3d},
+ {0x37a2, 0x3d},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x44},
+ {0x37a8, 0x4c},
+ {0x37a9, 0x4c},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x44},
+ {0x37ab, 0x2e},
+ {0x37ac, 0x2e},
+ {0x37ad, 0x33},
+ {0x37ae, 0x0d},
+ {0x37af, 0x0d},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x42},
+ {0x37b4, 0x42},
+ {0x37b5, 0x31},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00}, /* x start H */
+ {0x3801, 0x0c}, /* x start L */
+ {0x3802, 0x00}, /* y start H */
+ {0x3803, 0x0c}, /* y start L */
+ {0x3804, 0x0c}, /* x end H */
+ {0x3805, 0xd3}, /* x end L */
+ {0x3806, 0x09}, /* y end H */
+ {0x3807, 0xa3}, /* y end L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3810, 0x00}, /* ISP x win H */
+ {0x3811, 0x04}, /* ISP x win L */
+ {0x3813, 0x02}, /* ISP y win L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3815, 0x01}, /* x even inc */
+ {0x3820, 0x00}, /* vflip off */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x382b, 0x01}, /* y even inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff}, /* window auto size enable */
+ {0x3846, 0x48},
+ {0x3d85, 0x16}, /* OTP power up load data enable with BIST */
+ {0x3d8c, 0x73}, /* OTP setting start High */
+ {0x3d8d, 0xde}, /* OTP setting start Low */
+ {0x3f08, 0x08},
+ {0x3f0a, 0x00},
+ {0x4000, 0xf1}, /* out_range_trig, format_chg_trig */
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4005, 0x10}, /* BLC target L */
+ {0x4002, 0x27}, /* value used to limit BLC offset */
+ {0x4009, 0x81}, /* final BLC offset limitation enable */
+ {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
+ {0x401b, 0x00}, /* zero line R coefficient */
+ {0x401d, 0x00}, /* zoro line T coefficient */
+ {0x4020, 0x00}, /* Anchor left start H */
+ {0x4021, 0x04}, /* Anchor left start L */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4024, 0x0f}, /* Anchor right start H */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4026, 0x0f}, /* Anchor right end H */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x4028, 0x00}, /* top zero line start */
+ {0x4029, 0x02}, /* top zero line number */
+ {0x402a, 0x04}, /* top black line start */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402c, 0x00}, /* bottom zero line start */
+ {0x402d, 0x02}, /* bottom zoro line number */
+ {0x402e, 0x04}, /* bottom black line start */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
+ {0x4034, 0x3f},
+ {0x403d, 0x04}, /* md_precision_en */
+ {0x4300, 0xff}, /* clip max H */
+ {0x4301, 0x00}, /* clip min H */
+ {0x4302, 0x0f}, /* clip min L, clip max L */
+ {0x4316, 0x00},
+ {0x4500, 0x58},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32}, /* clk prepare min */
+ {0x4837, 0x16}, /* global timing */
+ {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
+ {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04}, /* temperature sensor */
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff}, /* temperature sensor */
+ {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
+ {0x5001, 0x01}, /* BLC on */
+ {0x5002, 0x08}, /* H scale off, WBMATCH off, OTP_DPC */
+ {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
+ {0x501e, 0x93}, /* enable digital gain */
+ {0x5046, 0x12},
+ {0x5780, 0x3e}, /* DPC */
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x00},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3}, /* DPC */
+ {0x5871, 0x0d}, /* Lenc */
+ {0x5870, 0x18},
+ {0x586e, 0x10},
+ {0x586f, 0x08},
+ {0x58f7, 0x01},
+ {0x58f8, 0x3d}, /* Lenc */
+ {0x5901, 0x00}, /* H skip off, V skip off */
+ {0x5b00, 0x02}, /* OTP DPC start address */
+ {0x5b01, 0x10}, /* OTP DPC start address */
+ {0x5b02, 0x03}, /* OTP DPC end address */
+ {0x5b03, 0xcf}, /* OTP DPC end address */
+ {0x5b05, 0x6c}, /* recover method = 2b11, */
+ {0x5e00, 0x00}, /* use 0x3ff to test pattern off */
+ {0x5e01, 0x41}, /* window cut enable */
+ {0x382d, 0x7f},
+ {0x4825, 0x3a}, /* lpx_p_min */
+ {0x4826, 0x40}, /* hs_prepare_min */
+ {0x4808, 0x25}, /* wake up delay in 1/1024 s */
+ {0x3763, 0x18},
+ {0x3768, 0xcc},
+ {0x470b, 0x28},
+ {0x4202, 0x00},
+ {0x400d, 0x10}, /* BLC offset trigger L */
+ {0x4040, 0x04}, /* BLC gain th2 */
+ {0x403e, 0x04}, /* BLC gain th1 */
+ {0x4041, 0xc6}, /* BLC */
+ {0x3007, 0x80},
+ {0x400a, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 30fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_1632x1224_regs_2lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0100, 0x00},
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3778, 0x17},
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3f0a, 0x00},
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x382d, 0x7f},
+ {0x0100, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 15fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_3264x2448_regs_2lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x9a}, /* exposure M */
+ {0x3502, 0x20}, /* exposure L */
+ {0x3778, 0x1a},
+ {0x3808, 0x0c}, /* x output size H */
+ {0x3809, 0xc0}, /* x output size L */
+ {0x380a, 0x09}, /* y output size H */
+ {0x380b, 0x90}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x94}, /* HTS L */
+ {0x380e, 0x09}, /* VTS H */
+ {0x380f, 0xaa}, /* VTS L */
+ {0x3814, 0x01}, /* x odd inc */
+ {0x3821, 0x46}, /* mirror on, bin off */
+ {0x382a, 0x01}, /* y odd inc */
+ {0x3830, 0x06},
+ {0x3836, 0x01},
+ {0x3f0a, 0x00},
+ {0x4001, 0x00}, /* total 256 black column */
+ {0x4022, 0x0c}, /* Anchor left end H */
+ {0x4023, 0x60}, /* Anchor left end L */
+ {0x4025, 0x36}, /* Anchor right start L */
+ {0x4027, 0x37}, /* Anchor right end L */
+ {0x402b, 0x08}, /* top black line number */
+ {0x402f, 0x08}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x01},
+ {0x4601, 0x97},
+ {0x382d, 0xff},
+ {REG_NULL, 0x00},
+};
+
+static const struct regval ov8858_global_regs_r2a_4lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0103, 0x01}, /* software reset for OVTATool only */
+ {0x0103, 0x01}, /* software reset */
+ {0x0100, 0x00}, /* software standby */
+ {0x0302, 0x1e}, /* pll1_multi */
+ {0x0303, 0x00}, /* pll1_divm */
+ {0x0304, 0x03}, /* pll1_div_mipi */
+ {0x030e, 0x00}, /* pll2_rdiv */
+ {0x030f, 0x04}, /* pll2_divsp */
+ {0x0312, 0x01}, /* pll2_pre_div0, pll2_r_divdac */
+ {0x031e, 0x0c}, /* pll1_no_lat */
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x20},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x05},
+ {0x360c, 0xd4},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0x90},
+ {0x3618, 0x5a},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x0a},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0f},
+ {0x3634, 0x0f},
+ {0x3635, 0x0f},
+ {0x3636, 0x12},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x01},
+ {0x3018, 0x72}, /* MIPI 4 lane */
+ {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
+ {0x3022, 0x01}, /* pd_mipi enable when rst_sync */
+ {0x3031, 0x0a}, /* MIPI 10-bit mode */
+ {0x3034, 0x00},
+ {0x3106, 0x01}, /* sclk_div, sclk_pre_div */
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00}, /* exposure H */
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
+ {0x3505, 0x80}, /* gain option */
+ {0x3508, 0x02}, /* gain H */
+ {0x3509, 0x00}, /* gain L */
+ {0x350c, 0x00}, /* short gain H */
+ {0x350d, 0x80}, /* short gain L */
+ {0x3510, 0x00}, /* short exposure H */
+ {0x3511, 0x02}, /* short exposure M */
+ {0x3512, 0x00}, /* short exposure L */
+ {0x3700, 0x30},
+ {0x3701, 0x18},
+ {0x3702, 0x50},
+ {0x3703, 0x32},
+ {0x3704, 0x28},
+ {0x3705, 0x00},
+ {0x3706, 0x82},
+ {0x3707, 0x08},
+ {0x3708, 0x48},
+ {0x3709, 0x66},
+ {0x370a, 0x01},
+ {0x370b, 0x82},
+ {0x370c, 0x07},
+ {0x3718, 0x14},
+ {0x3719, 0x31},
+ {0x3712, 0x44},
+ {0x3714, 0x24},
+ {0x371e, 0x31},
+ {0x371f, 0x7f},
+ {0x3720, 0x0a},
+ {0x3721, 0x0a},
+ {0x3724, 0x0c},
+ {0x3725, 0x02},
+ {0x3726, 0x0c},
+ {0x3728, 0x0a},
+ {0x3729, 0x03},
+ {0x372a, 0x06},
+ {0x372b, 0xa6},
+ {0x372c, 0xa6},
+ {0x372d, 0xa6},
+ {0x372e, 0x0c},
+ {0x372f, 0x20},
+ {0x3730, 0x02},
+ {0x3731, 0x0c},
+ {0x3732, 0x28},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x30},
+ {0x373a, 0x0a},
+ {0x373b, 0x0b},
+ {0x373c, 0x14},
+ {0x373e, 0x06},
+ {0x3750, 0x0a},
+ {0x3751, 0x0e},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x0c},
+ {0x375b, 0x26},
+ {0x375c, 0x20},
+ {0x375d, 0x04},
+ {0x375e, 0x00},
+ {0x375f, 0x28},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x46},
+ {0x3773, 0x04},
+ {0x3774, 0x2c},
+ {0x3775, 0x13},
+ {0x3776, 0x08},
+ {0x3777, 0x00},
+ {0x3778, 0x17},
+ {0x37a0, 0x88},
+ {0x37a1, 0x7a},
+ {0x37a2, 0x7a},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x88},
+ {0x37a8, 0x98},
+ {0x37a9, 0x98},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x88},
+ {0x37ab, 0x5c},
+ {0x37ac, 0x5c},
+ {0x37ad, 0x55},
+ {0x37ae, 0x19},
+ {0x37af, 0x19},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x84},
+ {0x37b4, 0x84},
+ {0x37b5, 0x60},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00}, /* x start H */
+ {0x3801, 0x0c}, /* x start L */
+ {0x3802, 0x00}, /* y start H */
+ {0x3803, 0x0c}, /* y start L */
+ {0x3804, 0x0c}, /* x end H */
+ {0x3805, 0xd3}, /* x end L */
+ {0x3806, 0x09}, /* y end H */
+ {0x3807, 0xa3}, /* y end L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3810, 0x00}, /* ISP x win H */
+ {0x3811, 0x04}, /* ISP x win L */
+ {0x3813, 0x02}, /* ISP y win L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3815, 0x01}, /* x even inc */
+ {0x3820, 0x00}, /* vflip off */
+ {0x3821, 0x67}, /* mirror on, bin o */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x382b, 0x01}, /* y even inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff}, /* window auto size enable */
+ {0x3846, 0x48},
+ {0x3d85, 0x16}, /* OTP power up load data/setting enable */
+ {0x3d8c, 0x73}, /* OTP setting start High */
+ {0x3d8d, 0xde}, /* OTP setting start Low */
+ {0x3f08, 0x10},
+ {0x3f0a, 0x00},
+ {0x4000, 0xf1}, /* out_range/format_chg/gain/exp_chg trig enable */
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4005, 0x10}, /* BLC target L */
+ {0x4002, 0x27}, /* value used to limit BLC offset */
+ {0x4009, 0x81}, /* final BLC offset limitation enable */
+ {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
+ {0x401b, 0x00}, /* zero line R coefficient */
+ {0x401d, 0x00}, /* zoro line T coefficient */
+ {0x4020, 0x00}, /* Anchor left start H */
+ {0x4021, 0x04}, /* Anchor left start L */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4024, 0x0f}, /* Anchor right start H */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4026, 0x0f}, /* Anchor right end H */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x4028, 0x00}, /* top zero line start */
+ {0x4029, 0x02}, /* top zero line number */
+ {0x402a, 0x04}, /* top black line start */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402c, 0x00}, /* bottom zero line start */
+ {0x402d, 0x02}, /* bottom zoro line number */
+ {0x402e, 0x04}, /* bottom black line start */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
+ {0x4034, 0x3f},
+ {0x403d, 0x04}, /* md_precision_en */
+ {0x4300, 0xff}, /* clip max H */
+ {0x4301, 0x00}, /* clip min H */
+ {0x4302, 0x0f}, /* clip min L, clip max L */
+ {0x4316, 0x00},
+ {0x4500, 0x58},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32}, /* clk prepare min */
+ {0x4837, 0x16}, /* global timing */
+ {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
+ {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04}, /* temperature sensor */
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff}, /* temperature sensor */
+ {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
+ {0x5001, 0x01}, /* BLC on */
+ {0x5002, 0x08}, /* WBMATCH sensor's gain, H scale/WBMATCH/OTP_DPC off */
+ {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
+ {0x501e, 0x93}, /* enable digital gain */
+ {0x5046, 0x12},
+ {0x5780, 0x3e}, /* DPC */
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x00},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3}, /* DPC */
+ {0x5871, 0x0d}, /* Lenc */
+ {0x5870, 0x18},
+ {0x586e, 0x10},
+ {0x586f, 0x08},
+ {0x58f7, 0x01},
+ {0x58f8, 0x3d}, /* Lenc */
+ {0x5901, 0x00}, /* H skip off, V skip off */
+ {0x5b00, 0x02}, /* OTP DPC start address */
+ {0x5b01, 0x10}, /* OTP DPC start address */
+ {0x5b02, 0x03}, /* OTP DPC end address */
+ {0x5b03, 0xcf}, /* OTP DPC end address */
+ {0x5b05, 0x6c}, /* recover method = 2b11 */
+ {0x5e00, 0x00}, /* use 0x3ff to test pattern off */
+ {0x5e01, 0x41}, /* window cut enable */
+ {0x382d, 0x7f},
+ {0x4825, 0x3a}, /* lpx_p_min */
+ {0x4826, 0x40}, /* hs_prepare_min */
+ {0x4808, 0x25}, /* wake up delay in 1/1024 s */
+ {0x3763, 0x18},
+ {0x3768, 0xcc},
+ {0x470b, 0x28},
+ {0x4202, 0x00},
+ {0x400d, 0x10}, /* BLC offset trigger L */
+ {0x4040, 0x04}, /* BLC gain th2 */
+ {0x403e, 0x04}, /* BLC gain th1 */
+ {0x4041, 0xc6}, /* BLC */
+ {0x3007, 0x80},
+ {0x400a, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 60fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_1632x1224_regs_4lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3f0a, 0x00},
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x382d, 0x7f},
+ {0x0100, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 30fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_3264x2448_regs_4lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x9a}, /* exposure M */
+ {0x3502, 0x20}, /* exposure L */
+ {0x3808, 0x0c}, /* x output size H */
+ {0x3809, 0xc0}, /* x output size L */
+ {0x380a, 0x09}, /* y output size H */
+ {0x380b, 0x90}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x94}, /* HTS L */
+ {0x380e, 0x09}, /* VTS H */
+ {0x380f, 0xaa}, /* VTS L */
+ {0x3814, 0x01}, /* x odd inc */
+ {0x3821, 0x46}, /* mirror on, bin off */
+ {0x382a, 0x01}, /* y odd inc */
+ {0x3830, 0x06},
+ {0x3836, 0x01},
+ {0x3f0a, 0x00},
+ {0x4001, 0x00}, /* total 256 black column */
+ {0x4022, 0x0c}, /* Anchor left end H */
+ {0x4023, 0x60}, /* Anchor left end L */
+ {0x4025, 0x36}, /* Anchor right start L */
+ {0x4027, 0x37}, /* Anchor right end L */
+ {0x402b, 0x08}, /* top black line number */
+ {0x402f, 0x08}, /* interpolation x/y disable, Anchor one disable */
+ {0x4500, 0x58},
+ {0x4600, 0x01},
+ {0x4601, 0x97},
+ {0x382d, 0xff},
+ {REG_NULL, 0x00},
+};
+
+static const struct ov8858_mode ov8858_modes[] = {
+ {
+ .width = 3264,
+ .height = 2448,
+ .exp_def = 2464,
+ .hts_def = 1940 * 2,
+ .vts_def = 2472,
+ .reg_modes = {
+ .mode_2lanes = ov8858_3264x2448_regs_2lane,
+ .mode_4lanes = ov8858_3264x2448_regs_4lane,
+ },
+ },
+ {
+ .width = 1632,
+ .height = 1224,
+ .exp_def = 1232,
+ .hts_def = 1928 * 2,
+ .vts_def = 1244,
+ .reg_modes = {
+ .mode_2lanes = ov8858_1632x1224_regs_2lane,
+ .mode_4lanes = ov8858_1632x1224_regs_4lane,
+ },
+ },
+};
+
+static const s64 link_freq_menu_items[] = {
+ OV8858_LINK_FREQ
+};
+
+static const char * const ov8858_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+ "Vertical Color Bar Type 2",
+ "Vertical Color Bar Type 3",
+ "Vertical Color Bar Type 4"
+};
+
+/* ----------------------------------------------------------------------------
+ * HW access
+ */
+
+static int ov8858_write(struct ov8858 *ov8858, u32 reg, u32 val, int *err)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
+ u16 addr = reg & OV8858_REG_ADDR_MASK;
+ u8 buf[6];
+ int ret;
+
+ if (err && *err)
+ return *err;
+
+ put_unaligned_be16(addr, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+
+ ret = i2c_master_send(client, buf, len + 2);
+ if (ret != len + 2) {
+ ret = ret < 0 ? ret : -EIO;
+ if (err)
+ *err = ret;
+
+ dev_err(&client->dev,
+ "Failed to write reg %u: %d\n", addr, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ov8858_write_array(struct ov8858 *ov8858, const struct regval *regs)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; ++i) {
+ ov8858_write(ov8858, OV8858_REG_8BIT(regs[i].addr),
+ regs[i].val, &ret);
+ }
+
+ return ret;
+}
+
+static int ov8858_read(struct ov8858 *ov8858, u32 reg, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ __be16 reg_addr_be = cpu_to_be16(reg & OV8858_REG_ADDR_MASK);
+ unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
+ struct i2c_msg msgs[2];
+ __be32 data_be = 0;
+ u8 *data_be_p;
+ int ret;
+
+ data_be_p = (u8 *)&data_be;
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs)) {
+ ret = ret < 0 ? ret : -EIO;
+ dev_err(&client->dev,
+ "Failed to read reg %u: %d\n", reg, ret);
+ return ret;
+ }
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Streaming
+ */
+
+static int ov8858_start_stream(struct ov8858 *ov8858,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *format;
+ const struct ov8858_mode *mode;
+ const struct regval *reg_list;
+ int ret;
+
+ ret = ov8858_write_array(ov8858, ov8858->global_regs);
+ if (ret)
+ return ret;
+
+ format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+ mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
+ width, height, format->width,
+ format->height);
+
+ reg_list = ov8858->num_lanes == 4
+ ? mode->reg_modes.mode_4lanes
+ : mode->reg_modes.mode_2lanes;
+
+ ret = ov8858_write_array(ov8858, reg_list);
+ if (ret)
+ return ret;
+
+ /* 200 usec max to let PLL stabilize. */
+ fsleep(200);
+
+ ret = __v4l2_ctrl_handler_setup(&ov8858->ctrl_handler);
+ if (ret)
+ return ret;
+
+ ret = ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
+ OV8858_MODE_STREAMING, NULL);
+ if (ret)
+ return ret;
+
+ /* t5 (fixed) = 10msec before entering streaming state */
+ fsleep(10000);
+
+ return 0;
+}
+
+static int ov8858_stop_stream(struct ov8858 *ov8858)
+{
+ return ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
+ OV8858_MODE_SW_STANDBY, NULL);
+}
+
+static int ov8858_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (on) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ goto unlock_and_return;
+
+ ret = ov8858_start_stream(ov8858, state);
+ if (ret) {
+ dev_err(&client->dev, "Failed to start streaming\n");
+ pm_runtime_put_sync(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ ov8858_stop_stream(ov8858);
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+ }
+
+unlock_and_return:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ov8858_video_ops = {
+ .s_stream = ov8858_s_stream,
+};
+
+/* ----------------------------------------------------------------------------
+ * Pad ops
+ */
+
+static int ov8858_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+ const struct ov8858_mode *mode;
+ s64 h_blank, vblank_def;
+
+ mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
+ width, height, fmt->format.width,
+ fmt->format.height);
+
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+
+ /* Store the format in the current subdev state. */
+ *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ /* Adjust control limits when a new mode is applied. */
+ h_blank = mode->hts_def - mode->width;
+ __v4l2_ctrl_modify_range(ov8858->hblank, h_blank, h_blank, 1,
+ h_blank);
+
+ vblank_def = mode->vts_def - mode->height;
+ __v4l2_ctrl_modify_range(ov8858->vblank, vblank_def,
+ OV8858_VTS_MAX - mode->height, 1,
+ vblank_def);
+
+ return 0;
+}
+
+static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(ov8858_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+ return -EINVAL;
+
+ fse->min_width = ov8858_modes[fse->index].width;
+ fse->max_width = ov8858_modes[fse->index].width;
+ fse->max_height = ov8858_modes[fse->index].height;
+ fse->min_height = ov8858_modes[fse->index].height;
+
+ return 0;
+}
+
+static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov8858_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ const struct ov8858_mode *def_mode = &ov8858_modes[0];
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = {
+ .width = def_mode->width,
+ .height = def_mode->height,
+ },
+ };
+
+ ov8858_set_fmt(sd, sd_state, &fmt);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
+ .init_cfg = ov8858_init_cfg,
+ .enum_mbus_code = ov8858_enum_mbus_code,
+ .enum_frame_size = ov8858_enum_frame_sizes,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ov8858_set_fmt,
+};
+
+static const struct v4l2_subdev_core_ops ov8858_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops ov8858_subdev_ops = {
+ .core = &ov8858_core_ops,
+ .video = &ov8858_video_ops,
+ .pad = &ov8858_pad_ops,
+};
+
+/* ----------------------------------------------------------------------------
+ * Controls handling
+ */
+
+static int ov8858_enable_test_pattern(struct ov8858 *ov8858, u32 pattern)
+{
+ u32 val;
+
+ if (pattern)
+ val = (pattern - 1) | OV8858_TEST_PATTERN_ENABLE;
+ else
+ val = OV8858_TEST_PATTERN_DISABLE;
+
+ return ov8858_write(ov8858, OV8858_REG_TEST_PATTERN, val, NULL);
+}
+
+static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov8858 *ov8858 = container_of(ctrl->handler,
+ struct ov8858, ctrl_handler);
+
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ u16 digi_gain;
+ s64 max_exp;
+ int ret;
+
+ /*
+ * The control handler and the subdev state use the same mutex and the
+ * mutex is guaranteed to be locked:
+ * - by the core when s_ctrl is called int the VIDIOC_S_CTRL call path
+ * - by the driver when s_ctrl is called in the s_stream(1) call path
+ */
+ state = v4l2_subdev_get_locked_active_state(&ov8858->subdev);
+ format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max_exp = format->height + ctrl->val - OV8858_EXPOSURE_MARGIN;
+ __v4l2_ctrl_modify_range(ov8858->exposure,
+ ov8858->exposure->minimum, max_exp,
+ ov8858->exposure->step,
+ ov8858->exposure->default_value);
+ break;
+ }
+
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* 4 least significant bits of exposure are fractional part */
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_EXPO,
+ ctrl->val << 4, NULL);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_GAIN,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ /*
+ * Digital gain is assembled as:
+ * 0x350a[7:0] = dgain[13:6]
+ * 0x350b[5:0] = dgain[5:0]
+ * Reassemble the control value to write it in one go.
+ */
+ digi_gain = (ctrl->val & OV8858_LONG_DIGIGAIN_L_MASK)
+ | ((ctrl->val & OV8858_LONG_DIGIGAIN_H_MASK) <<
+ OV8858_LONG_DIGIGAIN_H_SHIFT);
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_DIGIGAIN,
+ digi_gain, NULL);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov8858_write(ov8858, OV8858_REG_VTS,
+ ctrl->val + format->height, NULL);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov8858_enable_test_pattern(ov8858, ctrl->val);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_warn(&client->dev, "%s Unhandled id: 0x%x\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov8858_ctrl_ops = {
+ .s_ctrl = ov8858_set_ctrl,
+};
+
+/* ----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int ov8858_power_on(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct device *dev = &client->dev;
+ unsigned long delay_us;
+ int ret;
+
+ if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ)
+ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
+
+ ret = clk_prepare_enable(ov8858->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ /*
+ * The chip manual only suggests 8192 cycles prior to first SCCB
+ * transaction, but a double sleep between the release of gpios
+ * helps with sporadic failures observed at probe time.
+ */
+ delay_us = DIV_ROUND_UP(8192, OV8858_XVCLK_FREQ / 1000 / 1000);
+
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
+ fsleep(delay_us);
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0);
+ fsleep(delay_us);
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(ov8858->xvclk);
+
+ return ret;
+}
+
+static void ov8858_power_off(struct ov8858 *ov8858)
+{
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1);
+ clk_disable_unprepare(ov8858->xvclk);
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+}
+
+static int ov8858_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ return ov8858_power_on(ov8858);
+}
+
+static int ov8858_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ ov8858_power_off(ov8858);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ov8858_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov8858_runtime_suspend,
+ ov8858_runtime_resume, NULL)
+};
+
+/* ----------------------------------------------------------------------------
+ * Probe and initialization
+ */
+
+static int ov8858_init_ctrls(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct v4l2_ctrl_handler *handler = &ov8858->ctrl_handler;
+ const struct ov8858_mode *mode = &ov8858_modes[0];
+ struct v4l2_fwnode_device_properties props;
+ s64 exposure_max, vblank_def;
+ unsigned int pixel_rate;
+ struct v4l2_ctrl *ctrl;
+ u32 h_blank;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(handler, 10);
+ if (ret)
+ return ret;
+
+ ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* pixel rate = link frequency * 2 * lanes / bpp */
+ pixel_rate = OV8858_LINK_FREQ * 2 * ov8858->num_lanes / 10;
+ v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, pixel_rate, 1, pixel_rate);
+
+ h_blank = mode->hts_def - mode->width;
+ ov8858->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+ h_blank, h_blank, 1, h_blank);
+ if (ov8858->hblank)
+ ov8858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank_def = mode->vts_def - mode->height;
+ ov8858->vblank = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_def,
+ OV8858_VTS_MAX - mode->height,
+ 1, vblank_def);
+
+ exposure_max = mode->vts_def - OV8858_EXPOSURE_MARGIN;
+ ov8858->exposure = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ OV8858_EXPOSURE_MIN,
+ exposure_max, OV8858_EXPOSURE_STEP,
+ mode->exp_def);
+
+ v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ OV8858_LONG_GAIN_MIN, OV8858_LONG_GAIN_MAX,
+ OV8858_LONG_GAIN_STEP, OV8858_LONG_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ OV8858_LONG_DIGIGAIN_MIN, OV8858_LONG_DIGIGAIN_MAX,
+ OV8858_LONG_DIGIGAIN_STEP,
+ OV8858_LONG_DIGIGAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(handler, &ov8858_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov8858_test_pattern_menu) - 1,
+ 0, 0, ov8858_test_pattern_menu);
+
+ if (handler->error) {
+ ret = handler->error;
+ goto err_free_handler;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto err_free_handler;
+
+ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov8858_ctrl_ops,
+ &props);
+ if (ret)
+ goto err_free_handler;
+
+ ov8858->subdev.ctrl_handler = handler;
+
+ return 0;
+
+err_free_handler:
+ dev_err(&client->dev, "Failed to init controls: %d\n", ret);
+ v4l2_ctrl_handler_free(handler);
+
+ return ret;
+}
+
+static int ov8858_check_sensor_id(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ u32 id = 0;
+ int ret;
+
+ ret = ov8858_read(ov8858, OV8858_REG_CHIP_ID, &id);
+ if (ret)
+ return ret;
+
+ if (id != OV8858_CHIP_ID) {
+ dev_err(&client->dev, "Unexpected sensor id 0x%x\n", id);
+ return -ENODEV;
+ }
+
+ ret = ov8858_read(ov8858, OV8858_REG_SUB_ID, &id);
+ if (ret)
+ return ret;
+
+ dev_info(&client->dev, "Detected OV8858 sensor, revision 0x%x\n", id);
+
+ if (id == OV8858_R2A) {
+ /* R2A supports 2 and 4 lanes modes. */
+ ov8858->global_regs = ov8858->num_lanes == 4
+ ? ov8858_global_regs_r2a_4lane
+ : ov8858_global_regs_r2a_2lane;
+ } else if (ov8858->num_lanes == 2) {
+ /*
+ * R1A only supports 2 lanes mode and it's only partially
+ * supported.
+ */
+ ov8858->global_regs = ov8858_global_regs_r1a;
+ dev_warn(&client->dev, "R1A may not work well!\n");
+ } else {
+ dev_err(&client->dev,
+ "Unsupported number of data lanes for R1A revision.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ov8858_configure_regulators(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov8858_supply_names); i++)
+ ov8858->supplies[i].supply = ov8858_supply_names[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+}
+
+static int ov8858_parse_of(struct ov8858 *ov8858)
+{
+ struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct device *dev = &client->dev;
+ struct fwnode_handle *endpoint;
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint) {
+ dev_err(dev, "Failed to get endpoint\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(endpoint, &vep);
+ if (ret) {
+ dev_err(dev, "Failed to parse endpoint: %d\n", ret);
+ fwnode_handle_put(endpoint);
+ return ret;
+ }
+
+ ov8858->num_lanes = vep.bus.mipi_csi2.num_data_lanes;
+ switch (ov8858->num_lanes) {
+ case 4:
+ case 2:
+ break;
+ default:
+ dev_err(dev, "Unsupported number of data lanes %u\n",
+ ov8858->num_lanes);
+ fwnode_handle_put(endpoint);
+ return -EINVAL;
+ }
+
+ ov8858->subdev.fwnode = endpoint;
+
+ return 0;
+}
+
+static int ov8858_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd;
+ struct ov8858 *ov8858;
+ int ret;
+
+ ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL);
+ if (!ov8858)
+ return -ENOMEM;
+
+ ov8858->xvclk = devm_clk_get(dev, "xvclk");
+ if (IS_ERR(ov8858->xvclk))
+ return dev_err_probe(dev, PTR_ERR(ov8858->xvclk),
+ "Failed to get xvclk\n");
+
+ ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov8858->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov8858->pwdn_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio),
+ "Failed to get powerdown gpio\n");
+
+ v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops);
+
+ ret = ov8858_configure_regulators(ov8858);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = ov8858_parse_of(ov8858);
+ if (ret)
+ return ret;
+
+ ret = ov8858_init_ctrls(ov8858);
+ if (ret)
+ goto err_put_fwnode;
+
+ sd = &ov8858->subdev;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ ov8858->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad);
+ if (ret < 0)
+ goto err_free_handler;
+
+ sd->state_lock = ov8858->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0) {
+ dev_err(&client->dev, "Subdev initialization error %d\n", ret);
+ goto err_clean_entity;
+ }
+
+ ret = ov8858_power_on(ov8858);
+ if (ret)
+ goto err_clean_entity;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+
+ ret = ov8858_check_sensor_id(ov8858);
+ if (ret)
+ goto err_power_off;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = v4l2_async_register_subdev_sensor(sd);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_power_off;
+ }
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+
+err_power_off:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ ov8858_power_off(ov8858);
+err_clean_entity:
+ media_entity_cleanup(&sd->entity);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
+err_put_fwnode:
+ fwnode_handle_put(ov8858->subdev.fwnode);
+
+ return ret;
+}
+
+static void ov8858_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
+ fwnode_handle_put(ov8858->subdev.fwnode);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov8858_power_off(ov8858);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id ov8858_of_match[] = {
+ { .compatible = "ovti,ov8858" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov8858_of_match);
+
+static struct i2c_driver ov8858_i2c_driver = {
+ .driver = {
+ .name = "ov8858",
+ .pm = &ov8858_pm_ops,
+ .of_match_table = ov8858_of_match,
+ },
+ .probe_new = &ov8858_probe,
+ .remove = &ov8858_remove,
+};
+
+module_i2c_driver(ov8858_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision OV8858 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c
index 37a55d53af56..7f46cac38aab 100644
--- a/drivers/media/i2c/ov9282.c
+++ b/drivers/media/i2c/ov9282.c
@@ -148,7 +148,6 @@ struct ov9282_mode {
/**
* struct ov9282 - ov9282 sensor device structure
* @dev: Pointer to generic device
- * @client: Pointer to i2c client
* @sd: V4L2 sub-device
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
@@ -170,7 +169,6 @@ struct ov9282_mode {
*/
struct ov9282 {
struct device *dev;
- struct i2c_client *client;
struct v4l2_subdev sd;
struct media_pad pad;
struct gpio_desc *reset_gpio;
@@ -1144,10 +1142,9 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282)
}
ret = ov9282_configure_regulators(ov9282);
- if (ret) {
- dev_err(ov9282->dev, "Failed to get power regulators\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(ov9282->dev, ret,
+ "Failed to get power regulators\n");
rate = clk_get_rate(ov9282->inclk);
if (rate != OV9282_INCLK_RATE) {
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 59b03b0860d5..7938a3327d3e 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -26,7 +26,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/i2c/s5c73m3.h>
#include <media/v4l2-fwnode.h>
#include "s5c73m3.h"
@@ -436,7 +435,7 @@ static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd,
state->streaming = !!on;
if (!on)
- return ret;
+ return 0;
if (state->apply_fiv) {
ret = s5c73m3_set_frame_rate(state);
@@ -1522,25 +1521,16 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
.video = &s5c73m3_oif_video_ops,
};
-static int s5c73m3_get_platform_data(struct s5c73m3 *state)
+static int s5c73m3_get_dt_data(struct s5c73m3 *state)
{
- struct i2c_client *c = state->i2c_client;
- struct device *dev = &c->dev;
- const struct s5c73m3_platform_data *pdata = dev->platform_data;
+ struct device *dev = &state->i2c_client->dev;
struct device_node *node = dev->of_node;
struct device_node *node_ep;
struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int ret;
- if (!node) {
- if (!pdata) {
- dev_err(dev, "Platform data not specified\n");
- return -EINVAL;
- }
-
- state->mclk_frequency = pdata->mclk_frequency;
- return 0;
- }
+ if (!node)
+ return -EINVAL;
state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME);
if (IS_ERR(state->clock))
@@ -1603,7 +1593,7 @@ static int s5c73m3_probe(struct i2c_client *client)
return -ENOMEM;
state->i2c_client = client;
- ret = s5c73m3_get_platform_data(state);
+ ret = s5c73m3_get_dt_data(state);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index e3543ae384ed..1c8103670fa2 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -23,7 +23,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/i2c/s5c73m3.h>
#include "s5c73m3.h"
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index 1fc7df41c5ee..627e80cf5b72 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -16,7 +16,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/i2c/s5c73m3.h>
#define DRIVER_NAME "S5C73M3"
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c
index 826baf4e064d..5dcabee6677d 100644
--- a/drivers/media/i2c/st-vgxy61.c
+++ b/drivers/media/i2c/st-vgxy61.c
@@ -5,7 +5,6 @@
* Copyright (C) 2022 STMicroelectronics SA
*/
-#include <asm-generic/unaligned.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -15,6 +14,9 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
#include <media/mipi-csi2.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index d1f552bd81d4..4063754a6732 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -406,7 +406,7 @@ tc358746_apply_pll_config(struct tc358746 *tc358746)
val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN;
mask = PLL_FRS_MASK | RESETB | PLL_EN;
- tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val);
+ err = tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val);
if (err)
return err;
@@ -988,6 +988,8 @@ static int __maybe_unused
tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
struct tc358746 *tc358746 = to_tc358746(sd);
+ u32 val;
+ int err;
/* 32-bit registers starting from CLW_DPHYCONTTX */
reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4;
@@ -995,12 +997,13 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
if (!pm_runtime_get_if_in_use(sd->dev))
return 0;
- tc358746_read(tc358746, reg->reg, (u32 *)&reg->val);
+ err = tc358746_read(tc358746, reg->reg, &val);
+ reg->val = val;
pm_runtime_mark_last_busy(sd->dev);
pm_runtime_put_sync_autosuspend(sd->dev);
- return 0;
+ return err;
}
static int __maybe_unused
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index 6ec2092d7f80..e7216a985ba6 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -716,7 +716,7 @@ done:
__must_check int __media_pipeline_start(struct media_pad *pad,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
struct media_pipeline_pad *err_ppad;
struct media_pipeline_pad *ppad;
int ret;
@@ -724,8 +724,8 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
lockdep_assert_held(&mdev->graph_mutex);
/*
- * If the entity is already part of a pipeline, that pipeline must
- * be the same as the pipe given to media_pipeline_start().
+ * If the pad is already part of a pipeline, that pipeline must be the
+ * same as the pipe given to media_pipeline_start().
*/
if (WARN_ON(pad->pipe && pad->pipe != pipe))
return -EINVAL;
@@ -864,7 +864,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_start);
__must_check int media_pipeline_start(struct media_pad *pad,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
int ret;
mutex_lock(&mdev->graph_mutex);
@@ -901,7 +901,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_stop);
void media_pipeline_stop(struct media_pad *pad)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
mutex_lock(&mdev->graph_mutex);
__media_pipeline_stop(pad);
@@ -911,7 +911,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_stop);
__must_check int media_pipeline_alloc_start(struct media_pad *pad)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
struct media_pipeline *new_pipe = NULL;
struct media_pipeline *pipe;
int ret;
@@ -919,7 +919,7 @@ __must_check int media_pipeline_alloc_start(struct media_pad *pad)
mutex_lock(&mdev->graph_mutex);
/*
- * Is the entity already part of a pipeline? If not, we need to allocate
+ * Is the pad already part of a pipeline? If not, we need to allocate
* a pipe.
*/
pipe = media_pad_pipeline(pad);
@@ -945,6 +945,61 @@ out:
}
EXPORT_SYMBOL_GPL(media_pipeline_alloc_start);
+struct media_pad *
+__media_pipeline_pad_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_pad_iter *iter,
+ struct media_pad *pad)
+{
+ if (!pad)
+ iter->cursor = pipe->pads.next;
+
+ if (iter->cursor == &pipe->pads)
+ return NULL;
+
+ pad = list_entry(iter->cursor, struct media_pipeline_pad, list)->pad;
+ iter->cursor = iter->cursor->next;
+
+ return pad;
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next);
+
+int media_pipeline_entity_iter_init(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter)
+{
+ return media_entity_enum_init(&iter->ent_enum, pipe->mdev);
+}
+EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_init);
+
+void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter)
+{
+ media_entity_enum_cleanup(&iter->ent_enum);
+}
+EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_cleanup);
+
+struct media_entity *
+__media_pipeline_entity_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter,
+ struct media_entity *entity)
+{
+ if (!entity)
+ iter->cursor = pipe->pads.next;
+
+ while (iter->cursor != &pipe->pads) {
+ struct media_pipeline_pad *ppad;
+ struct media_entity *entity;
+
+ ppad = list_entry(iter->cursor, struct media_pipeline_pad, list);
+ entity = ppad->pad->entity;
+ iter->cursor = iter->cursor->next;
+
+ if (!media_entity_enum_test_and_set(&iter->ent_enum, entity))
+ return entity;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_entity_iter_next);
+
/* -----------------------------------------------------------------------------
* Links management
*/
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index dff0b450f387..480194543d05 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -27,6 +27,7 @@ if MEDIA_ANALOG_TV_SUPPORT
source "drivers/media/pci/dt3155/Kconfig"
source "drivers/media/pci/ivtv/Kconfig"
+source "drivers/media/pci/saa7146/Kconfig"
endif
@@ -57,6 +58,7 @@ source "drivers/media/pci/pluto2/Kconfig"
source "drivers/media/pci/pt1/Kconfig"
source "drivers/media/pci/pt3/Kconfig"
source "drivers/media/pci/smipcie/Kconfig"
+source "drivers/media/pci/ttpci/Kconfig"
endif
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index 8f887a8a7f17..8bed619b7130 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -5,7 +5,8 @@
# Please keep it alphabetically sorted by directory
# (e. g. LC_ALL=C sort Makefile)
-obj-y += b2c2/ \
+obj-y += ttpci/ \
+ b2c2/ \
pluto2/ \
dm1105/ \
pt1/ \
@@ -13,6 +14,7 @@ obj-y += b2c2/ \
mantis/ \
ngene/ \
ddbridge/ \
+ saa7146/ \
smipcie/ \
netup_unidvb/ \
intel/
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index 390bd5ea3472..3b76a9d0383a 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1843,6 +1843,9 @@ static void cio2_pci_remove(struct pci_dev *pci_dev)
v4l2_device_unregister(&cio2->v4l2_dev);
media_device_cleanup(&cio2->media_dev);
mutex_destroy(&cio2->lock);
+
+ pm_runtime_forbid(&pci_dev->dev);
+ pm_runtime_get_noresume(&pci_dev->dev);
}
static int __maybe_unused cio2_runtime_suspend(struct device *dev)
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 96328b0af164..cf2871306987 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -978,7 +978,7 @@ static void saa7134_unregister_video(struct saa7134_dev *dev)
}
if (dev->radio_dev) {
if (video_is_registered(dev->radio_dev))
- vb2_video_unregister_device(dev->radio_dev);
+ video_unregister_device(dev->radio_dev);
else
video_device_release(dev->radio_dev);
dev->radio_dev = NULL;
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig
index 228e8d3f8d2b..3bbb68a0ed7b 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig
+++ b/drivers/media/pci/saa7146/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_HEXIUM_GEMINI
- tristate "Hexium Gemini frame grabber (DEPRECATED)"
+ tristate "Hexium Gemini frame grabber"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
help
@@ -8,28 +8,22 @@ config VIDEO_HEXIUM_GEMINI
grabber card by Hexium. Please note that the Gemini Dual
card is *not* fully supported.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
config VIDEO_HEXIUM_ORION
- tristate "Hexium HV-PCI6 and Orion frame grabber (DEPRECATED)"
+ tristate "Hexium HV-PCI6 and Orion frame grabber"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
help
This is a video4linux driver for the Hexium HV-PCI6 and
Orion frame grabber cards by Hexium.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called hexium_orion.
config VIDEO_MXB
- tristate "Siemens-Nixdorf 'Multimedia eXtension Board' (DEPRECATED)"
+ tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
select VIDEO_TUNER
@@ -41,8 +35,5 @@ config VIDEO_MXB
This is a video4linux driver for the 'Multimedia eXtension Board'
TV card by Siemens-Nixdorf.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called mxb.
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile
index 37c9336f83d5..37c9336f83d5 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile
+++ b/drivers/media/pci/saa7146/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 124e82bd4507..3947701cd6c7 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -13,9 +13,9 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
static int debug;
module_param(debug, int, 0);
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index ebd63998ac79..2eb4bee16b71 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -13,9 +13,9 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
static int debug;
module_param(debug, int, 0);
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 3e568f952dae..7ded8f5b05cb 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -13,13 +13,13 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/i2c/saa7115.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
#include "tea6415c.h"
#include "tea6420.h"
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 8c85ed58e938..65a6832a6b96 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config DVB_BUDGET_CORE
- tristate "SAA7146 DVB cards (aka Budget, Nova-PCI) (DEPRECATED)"
+ tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
depends on DVB_CORE && PCI && I2C
select VIDEO_SAA7146
select TTPCI_EEPROM
@@ -10,7 +10,7 @@ config DVB_BUDGET_CORE
MPEG2 decoder.
config DVB_BUDGET
- tristate "Budget cards (DEPRECATED)"
+ tristate "Budget cards"
depends on DVB_BUDGET_CORE && I2C
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
@@ -30,16 +30,13 @@ config DVB_BUDGET
or Nova-PCI cards) without onboard MPEG2 decoder, and without
analog inputs or an onboard Common Interface connector.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
module will be called budget.
config DVB_BUDGET_CI
- tristate "Budget cards with onboard CI connector (DEPRECATED)"
+ tristate "Budget cards with onboard CI connector"
depends on DVB_BUDGET_CORE && I2C
select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
@@ -60,16 +57,13 @@ config DVB_BUDGET_CI
Note: The Common Interface is not yet supported by this driver
due to lack of information from the vendor.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
module will be called budget-ci.
config DVB_BUDGET_AV
- tristate "Budget cards with analog video inputs (DEPRECATED)"
+ tristate "Budget cards with analog video inputs"
depends on DVB_BUDGET_CORE && I2C
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
@@ -86,9 +80,6 @@ config DVB_BUDGET_AV
(so called Budget- or Nova-PCI cards) without onboard
MPEG2 decoder, but with one or more analog video inputs.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index b0708f6e40cc..b0708f6e40cc 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 0c61a2dec221..3cb83005cf09 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -29,7 +29,7 @@
#include "tda1004x.h"
#include "tua6100.h"
#include "dvb-pll.h"
-#include "../common/saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index d59d18647371..d59d18647371 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index 5d5796f24469..5d5796f24469 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
index a88711a3ac7f..a88711a3ac7f 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c
+++ b/drivers/media/pci/ttpci/budget.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index 82cc0df492b3..bd87432e6cde 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
-#include "../common/saa7146.h"
+#include <media/drv-intf/saa7146.h>
extern int budget_debug;
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 3cbe8ce637e5..e6e8fe45fc7c 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -250,19 +250,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
}
if (V4L2_TYPE_IS_OUTPUT(f->type)) {
- if (!vpu_color_check_primaries(pix_mp->colorspace)) {
- venc->params.color.primaries = pix_mp->colorspace;
- vpu_color_get_default(venc->params.color.primaries,
- &venc->params.color.transfer,
- &venc->params.color.matrix,
- &venc->params.color.full_range);
- }
- if (!vpu_color_check_transfers(pix_mp->xfer_func))
- venc->params.color.transfer = pix_mp->xfer_func;
- if (!vpu_color_check_matrix(pix_mp->ycbcr_enc))
- venc->params.color.matrix = pix_mp->ycbcr_enc;
- if (!vpu_color_check_full_range(pix_mp->quantization))
- venc->params.color.full_range = pix_mp->quantization;
+ venc->params.color.primaries = pix_mp->colorspace;
+ venc->params.color.transfer = pix_mp->xfer_func;
+ venc->params.color.matrix = pix_mp->ycbcr_enc;
+ venc->params.color.full_range = pix_mp->quantization;
}
pix_mp->colorspace = venc->params.color.primaries;
@@ -1281,7 +1272,6 @@ static void venc_init(struct file *file)
f.fmt.pix_mp.width = 1280;
f.fmt.pix_mp.height = 720;
f.fmt.pix_mp.field = V4L2_FIELD_NONE;
- f.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
venc_s_fmt(file, &inst->fh, &f);
memset(&f, 0, sizeof(f));
diff --git a/drivers/media/platform/amphion/vpu_color.c b/drivers/media/platform/amphion/vpu_color.c
index 80b9a53fd1c1..4ae435cbc5cd 100644
--- a/drivers/media/platform/amphion/vpu_color.c
+++ b/drivers/media/platform/amphion/vpu_color.c
@@ -17,7 +17,7 @@
#include "vpu_helpers.h"
static const u8 colorprimaries[] = {
- 0,
+ V4L2_COLORSPACE_LAST,
V4L2_COLORSPACE_REC709, /*Rec. ITU-R BT.709-6*/
0,
0,
@@ -31,7 +31,7 @@ static const u8 colorprimaries[] = {
};
static const u8 colortransfers[] = {
- 0,
+ V4L2_XFER_FUNC_LAST,
V4L2_XFER_FUNC_709, /*Rec. ITU-R BT.709-6*/
0,
0,
@@ -53,7 +53,7 @@ static const u8 colortransfers[] = {
};
static const u8 colormatrixcoefs[] = {
- 0,
+ V4L2_YCBCR_ENC_LAST,
V4L2_YCBCR_ENC_709, /*Rec. ITU-R BT.709-6*/
0,
0,
diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/imx-vdoa.c
index c70871bae193..c3561fcecb98 100644
--- a/drivers/media/platform/chips-media/imx-vdoa.c
+++ b/drivers/media/platform/chips-media/imx-vdoa.c
@@ -324,11 +324,6 @@ static int vdoa_probe(struct platform_device *pdev)
return 0;
}
-static int vdoa_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id vdoa_dt_ids[] = {
{ .compatible = "fsl,imx6q-vdoa" },
{}
@@ -337,7 +332,6 @@ MODULE_DEVICE_TABLE(of, vdoa_dt_ids);
static struct platform_driver vdoa_driver = {
.probe = vdoa_probe,
- .remove = vdoa_remove,
.driver = {
.name = VDOA_NAME,
.of_match_table = vdoa_dt_ids,
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index df16899ab1cb..ef22bf8f276c 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -254,7 +254,7 @@ static int mmpcam_probe(struct platform_device *pdev)
*/
ret = mccic_register(mcam);
if (ret)
- return ret;
+ goto out;
/*
* Add OF clock provider.
diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig
index 846e759a8f6a..602329c44750 100644
--- a/drivers/media/platform/mediatek/mdp3/Kconfig
+++ b/drivers/media/platform/mediatek/mdp3/Kconfig
@@ -3,14 +3,13 @@ config VIDEO_MEDIATEK_MDP3
tristate "MediaTek MDP v3 driver"
depends on MTK_IOMMU || COMPILE_TEST
depends on VIDEO_DEV
- depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
depends on REMOTEPROC
+ depends on MTK_MMSYS
+ depends on MTK_CMDQ
+ depends on MTK_SCP
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- select MTK_MMSYS
- select MTK_CMDQ
- select MTK_SCP
default n
help
It is a v4l2 driver and present in MediaTek MT8183 SoC.
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
index 7bc05f42a23c..091a68685590 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
@@ -1002,7 +1002,8 @@ int mdp_comp_config(struct mdp_dev *mdp)
if (!pdev) {
dev_warn(dev, "can't find platform device of node:%s\n",
node->name);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_init_comps;
}
comp->comp_dev = &pdev->dev;
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index 2d1f6ae9f080..97edcd9d1c81 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -207,8 +207,8 @@ static int mdp_probe(struct platform_device *pdev)
}
for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
- if (!mdp->mdp_mutex[i]) {
- ret = -ENODEV;
+ if (IS_ERR(mdp->mdp_mutex[i])) {
+ ret = PTR_ERR(mdp->mdp_mutex[i]);
goto err_free_mutex;
}
}
@@ -289,7 +289,8 @@ err_deinit_comp:
mdp_comp_destroy(mdp);
err_free_mutex:
for (i = 0; i < MDP_PIPE_MAX; i++)
- mtk_mutex_put(mdp->mdp_mutex[i]);
+ if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i]))
+ mtk_mutex_put(mdp->mdp_mutex[i]);
err_destroy_device:
kfree(mdp);
err_return:
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
index 4305e4eb9900..777d445999e9 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
@@ -72,9 +72,9 @@ static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
{
int ret;
- ret = pm_runtime_put_sync(pm->dev);
- if (ret)
- mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
+ ret = pm_runtime_put(pm->dev);
+ if (ret && ret != -EAGAIN)
+ mtk_v4l2_err("pm_runtime_put fail %d", ret);
}
static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
diff --git a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
index 13c4f860fa69..60fd165c0d94 100644
--- a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
@@ -565,7 +565,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
*bs_size);
++inst->frm_cnt;
++inst->skip_frm_cnt;
- return ret;
+ return 0;
}
irq_status = h264_enc_wait_venc_done(inst);
@@ -580,7 +580,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-",
inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm);
- return ret;
+ return 0;
}
static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e2994d48f10c..71758ee8474b 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,10 +32,6 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
-
#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
@@ -114,8 +110,8 @@ static int isc_buffer_prepare(struct vb2_buffer *vb)
unsigned long size = isc->fmt.fmt.pix.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
- v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
- vb2_plane_size(vb, 0), size);
+ dev_err(isc->dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
return -EINVAL;
}
@@ -346,15 +342,14 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
/* Enable stream on the sub device */
ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
if (ret && ret != -ENOIOCTLCMD) {
- v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n",
- ret);
+ dev_err(isc->dev, "stream on failed in subdev %d\n", ret);
goto err_start_stream;
}
ret = pm_runtime_resume_and_get(isc->dev);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
- ret);
+ dev_err(isc->dev, "RPM resume failed in subdev %d\n",
+ ret);
goto err_pm_get;
}
@@ -423,8 +418,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
/* Wait until the end of the current frame */
if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
- v4l2_err(&isc->v4l2_dev,
- "Timeout waiting for end of the capture\n");
+ dev_err(isc->dev, "Timeout waiting for end of the capture\n");
mutex_unlock(&isc->awb_mutex);
@@ -436,7 +430,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
/* Disable stream on the sub device */
ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
if (ret && ret != -ENOIOCTLCMD)
- v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
+ dev_err(isc->dev, "stream off failed in subdev\n");
/* Release all active buffers */
spin_lock_irqsave(&isc->dma_queue_lock, flags);
@@ -620,28 +614,28 @@ static int isc_try_validate_formats(struct isc_device *isc)
break;
default:
/* any other different formats are not supported */
- v4l2_err(&isc->v4l2_dev, "Requested unsupported format.\n");
+ dev_err(isc->dev, "Requested unsupported format.\n");
ret = -EINVAL;
}
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
- rgb, yuv, grey, bayer);
+ dev_dbg(isc->dev,
+ "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
+ rgb, yuv, grey, bayer);
if (bayer &&
!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot output RAW if we do not receive RAW.\n");
+ dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n");
return -EINVAL;
}
if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
!ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
+ dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
return -EINVAL;
}
if ((rgb || bayer || yuv) &&
ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot convert GREY to another format.\n");
+ dev_err(isc->dev, "Cannot convert GREY to another format.\n");
return -EINVAL;
}
@@ -936,9 +930,9 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
isc->config = isc->try_config;
isc->fmt = isc->try_fmt;
- v4l2_dbg(1, debug, &isc->v4l2_dev, "ISC set_fmt to %.4s @%dx%d\n",
- (char *)&f->fmt.pix.pixelformat,
- f->fmt.pix.width, f->fmt.pix.height);
+ dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
+ (char *)&f->fmt.pix.pixelformat,
+ f->fmt.pix.width, f->fmt.pix.height);
return 0;
}
@@ -973,9 +967,9 @@ static int isc_validate(struct isc_device *isc)
/* Check if the format is not supported */
if (!sd_fmt) {
- v4l2_err(&isc->v4l2_dev,
- "Current subdevice is streaming a media bus code that is not supported 0x%x\n",
- format.format.code);
+ dev_err(isc->dev,
+ "Current subdevice is streaming a media bus code that is not supported 0x%x\n",
+ format.format.code);
return -EPIPE;
}
@@ -993,16 +987,16 @@ static int isc_validate(struct isc_device *isc)
/* Check if the frame size is the same. Otherwise we may overflow */
if (pixfmt->height != format.format.height ||
pixfmt->width != format.format.width) {
- v4l2_err(&isc->v4l2_dev,
- "ISC not configured with the proper frame size: %dx%d\n",
- format.format.width, format.format.height);
+ dev_err(isc->dev,
+ "ISC not configured with the proper frame size: %dx%d\n",
+ format.format.width, format.format.height);
return -EPIPE;
}
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "Identified subdev using format %.4s with %dx%d %d bpp\n",
- (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
- isc->try_config.bpp);
+ dev_dbg(isc->dev,
+ "Identified subdev using format %.4s with %dx%d %d bpp\n",
+ (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
+ isc->try_config.bpp);
/* Reset and restart AWB if the subdevice changed the format */
if (isc->try_config.sd_format && isc->config.sd_format &&
@@ -1027,7 +1021,7 @@ static int isc_validate(struct isc_device *isc)
isc->config = isc->try_config;
- v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n");
+ dev_dbg(isc->dev, "New ISC configuration in place\n");
return 0;
}
@@ -1294,9 +1288,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
if (!*min)
*min = 1;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: hist_id %u, hist_count %u",
- ctrls->hist_id, *hist_count);
+ dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u",
+ ctrls->hist_id, *hist_count);
}
static void isc_wb_update(struct isc_ctrls *ctrls)
@@ -1318,8 +1311,7 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
(u64)hist_count[ISC_HIS_CFG_MODE_GB];
avg >>= 1;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: green components average %llu\n", avg);
+ dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
/* Green histogram is null, nothing to do */
if (!avg)
@@ -1373,9 +1365,9 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
else
gw_gain[c] = 1 << 9;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: component %d, s_gain %u, gw_gain %u\n",
- c, s_gain[c], gw_gain[c]);
+ dev_dbg(isc->dev,
+ "isc wb: component %d, s_gain %u, gw_gain %u\n",
+ c, s_gain[c], gw_gain[c]);
/* multiply both gains and adjust for decimals */
ctrls->gain[c] = s_gain[c] * gw_gain[c];
ctrls->gain[c] >>= 9;
@@ -1383,9 +1375,8 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
/* make sure we are not out of range */
ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: component %d, final gain %u\n",
- c, ctrls->gain[c]);
+ dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
+ c, ctrls->gain[c]);
}
}
@@ -1406,8 +1397,8 @@ static void isc_awb_work(struct work_struct *w)
isc_hist_count(isc, &min, &max);
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
+ dev_dbg(isc->dev,
+ "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
@@ -1446,8 +1437,8 @@ static void isc_awb_work(struct work_struct *w)
* we are basically done.
*/
if (ctrls->awb == ISC_WB_ONETIME) {
- v4l2_info(&isc->v4l2_dev,
- "Completed one time white-balance adjustment.\n");
+ dev_info(isc->dev,
+ "Completed one time white-balance adjustment.\n");
/* update the v4l2 controls values */
isc_update_v4l2_ctrls(isc);
ctrls->awb = ISC_WB_NONE;
@@ -1580,8 +1571,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
V4L2_CTRL_FLAG_INACTIVE)) {
ctrls->awb = ISC_WB_ONETIME;
isc_set_histogram(isc, true);
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "One time white-balance started.\n");
+ dev_dbg(isc->dev, "One time white-balance started.\n");
}
return 0;
}
@@ -1730,7 +1720,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
int pad;
if (video_is_registered(&isc->video_dev)) {
- v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
+ dev_err(isc->dev, "only supports one sub-device.\n");
return -EBUSY;
}
@@ -1739,8 +1729,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
MEDIA_PAD_FL_SOURCE);
if (pad < 0) {
- v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n",
- subdev->name);
+ dev_err(isc->dev, "failed to find pad for %s\n", subdev->name);
return pad;
}
@@ -1813,7 +1802,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
+ dev_err(isc->dev, "Failed to register subdev nodes\n");
return ret;
}
@@ -1838,8 +1827,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = vb2_queue_init(q);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev,
- "vb2_queue_init() failed: %d\n", ret);
+ dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret);
goto isc_async_complete_err;
}
@@ -1850,13 +1838,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = isc_set_default_fmt(isc);
if (ret) {
- v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
+ dev_err(isc->dev, "Could not set default format\n");
goto isc_async_complete_err;
}
ret = isc_ctrl_init(isc);
if (ret) {
- v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
+ dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret);
goto isc_async_complete_err;
}
@@ -1876,8 +1864,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev,
- "video_register_device failed: %d\n", ret);
+ dev_err(isc->dev, "video_register_device failed: %d\n", ret);
goto isc_async_complete_err;
}
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 6cd015a35f7c..f085f14d676a 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -2472,19 +2472,12 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
jpeg->mode = mode;
/* Get clocks */
- jpeg->clk_ipg = devm_clk_get(dev, "ipg");
- if (IS_ERR(jpeg->clk_ipg)) {
- dev_err(dev, "failed to get clock: ipg\n");
- ret = PTR_ERR(jpeg->clk_ipg);
- goto err_clk;
- }
-
- jpeg->clk_per = devm_clk_get(dev, "per");
- if (IS_ERR(jpeg->clk_per)) {
- dev_err(dev, "failed to get clock: per\n");
- ret = PTR_ERR(jpeg->clk_per);
+ ret = devm_clk_bulk_get_all(&pdev->dev, &jpeg->clks);
+ if (ret < 0) {
+ dev_err(dev, "failed to get clock\n");
goto err_clk;
}
+ jpeg->num_clks = ret;
ret = mxc_jpeg_attach_pm_domains(jpeg);
if (ret < 0) {
@@ -2581,32 +2574,20 @@ static int mxc_jpeg_runtime_resume(struct device *dev)
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(jpeg->clk_ipg);
- if (ret < 0) {
- dev_err(dev, "failed to enable clock: ipg\n");
- goto err_ipg;
- }
-
- ret = clk_prepare_enable(jpeg->clk_per);
+ ret = clk_bulk_prepare_enable(jpeg->num_clks, jpeg->clks);
if (ret < 0) {
- dev_err(dev, "failed to enable clock: per\n");
- goto err_per;
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
}
return 0;
-
-err_per:
- clk_disable_unprepare(jpeg->clk_ipg);
-err_ipg:
- return ret;
}
static int mxc_jpeg_runtime_suspend(struct device *dev)
{
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
- clk_disable_unprepare(jpeg->clk_ipg);
- clk_disable_unprepare(jpeg->clk_per);
+ clk_bulk_disable_unprepare(jpeg->num_clks, jpeg->clks);
return 0;
}
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
index 8fa8c0aec5a2..87157db78082 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
@@ -120,8 +120,8 @@ struct mxc_jpeg_dev {
spinlock_t hw_lock; /* hardware access lock */
unsigned int mode;
struct mutex lock; /* v4l2 ioctls serialization */
- struct clk *clk_ipg;
- struct clk *clk_per;
+ struct clk_bulk_data *clks;
+ int num_clks;
struct platform_device *pdev;
struct device *dev;
void __iomem *base_reg;
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 905072871ed2..e99633565463 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -327,10 +327,6 @@ struct mipi_csis_device {
u32 hs_settle;
u32 clk_settle;
- struct mutex lock; /* Protect csis_fmt and format_mbus */
- const struct csis_pix_format *csis_fmt;
- struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM];
-
spinlock_t slock; /* Protect events */
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
struct dentry *debugfs_root;
@@ -559,10 +555,10 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on)
mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val);
}
-/* Called with the csis.lock mutex held */
-static void __mipi_csis_set_format(struct mipi_csis_device *csis)
+static void __mipi_csis_set_format(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
- struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK];
u32 val;
/* Color format */
@@ -583,25 +579,26 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis)
*
* TODO: Verify which other formats require DUAL (or QUAD) modes.
*/
- if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
+ if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
- val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type);
+ val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type);
mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
- val = mf->width | (mf->height << 16);
+ val = format->width | (format->height << 16);
mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val);
}
-static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
+static int mipi_csis_calculate_params(struct mipi_csis_device *csis,
+ const struct csis_pix_format *csis_fmt)
{
s64 link_freq;
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler,
- csis->csis_fmt->width,
+ csis_fmt->width,
csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
dev_err(csis->dev, "Unable to obtain link frequency: %d\n",
@@ -643,7 +640,9 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
return 0;
}
-static void mipi_csis_set_params(struct mipi_csis_device *csis)
+static void mipi_csis_set_params(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
int lanes = csis->bus.num_data_lanes;
u32 val;
@@ -655,7 +654,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis)
val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
- __mipi_csis_set_format(csis);
+ __mipi_csis_set_format(csis, format, csis_fmt);
mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL,
MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) |
@@ -728,10 +727,12 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis)
return ret;
}
-static void mipi_csis_start_stream(struct mipi_csis_device *csis)
+static void mipi_csis_start_stream(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
mipi_csis_sw_reset(csis);
- mipi_csis_set_params(csis);
+ mipi_csis_set_params(csis, format, csis_fmt);
mipi_csis_system_enable(csis, true);
mipi_csis_enable_interrupts(csis, true);
}
@@ -935,120 +936,63 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev)
static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
+ const struct v4l2_mbus_framefmt *format;
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_subdev_state *state;
int ret;
if (!enable) {
- mutex_lock(&csis->lock);
-
v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
mipi_csis_stop_stream(csis);
if (csis->debug.enable)
mipi_csis_log_counters(csis, true);
- mutex_unlock(&csis->lock);
-
pm_runtime_put(csis->dev);
return 0;
}
- ret = mipi_csis_calculate_params(csis);
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK);
+ csis_fmt = find_csis_format(format->code);
+
+ ret = mipi_csis_calculate_params(csis, csis_fmt);
if (ret < 0)
- return ret;
+ goto err_unlock;
mipi_csis_clear_counters(csis);
ret = pm_runtime_resume_and_get(csis->dev);
if (ret < 0)
- return ret;
+ goto err_unlock;
- mutex_lock(&csis->lock);
+ mipi_csis_start_stream(csis, format, csis_fmt);
- mipi_csis_start_stream(csis);
ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
if (ret < 0)
- goto error;
+ goto err_stop;
mipi_csis_log_counters(csis, true);
- mutex_unlock(&csis->lock);
+ v4l2_subdev_unlock_state(state);
return 0;
-error:
+err_stop:
mipi_csis_stop_stream(csis);
- mutex_unlock(&csis->lock);
pm_runtime_put(csis->dev);
+err_unlock:
+ v4l2_subdev_unlock_state(state);
return ret;
}
-static struct v4l2_mbus_framefmt *
-mipi_csis_get_format(struct mipi_csis_device *csis,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which,
- unsigned int pad)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad);
-
- return &csis->format_mbus[pad];
-}
-
-static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
-{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- struct v4l2_mbus_framefmt *fmt_sink;
- struct v4l2_mbus_framefmt *fmt_source;
- enum v4l2_subdev_format_whence which;
-
- which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK);
-
- fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16;
- fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
- fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT;
- fmt_sink->field = V4L2_FIELD_NONE;
-
- fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace);
- 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_source = mipi_csis_get_format(csis, sd_state, which,
- CSIS_PAD_SOURCE);
- *fmt_source = *fmt_sink;
-
- return 0;
-}
-
-static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- struct v4l2_mbus_framefmt *fmt;
-
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- sdformat->pad);
-
- mutex_lock(&csis->lock);
- sdformat->format = *fmt;
- mutex_unlock(&csis->lock);
-
- return 0;
-}
-
static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
-
/*
* The CSIS can't transcode in any way, the source format is identical
* to the sink format.
@@ -1059,8 +1003,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = mipi_csis_get_format(csis, sd_state, code->which,
- code->pad);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
code->code = fmt->code;
return 0;
}
@@ -1080,7 +1023,6 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
unsigned int align;
@@ -1090,7 +1032,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
* modified.
*/
if (sdformat->pad == CSIS_PAD_SOURCE)
- return mipi_csis_get_fmt(sd, sd_state, sdformat);
+ return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
if (sdformat->pad != CSIS_PAD_SINK)
return -EINVAL;
@@ -1128,14 +1070,12 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
&sdformat->format.height, 1,
CSIS_MAX_PIX_HEIGHT, 0, 0);
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- sdformat->pad);
-
- mutex_lock(&csis->lock);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
fmt->height = sdformat->format.height;
+ fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = sdformat->format.colorspace;
fmt->quantization = sdformat->format.quantization;
fmt->xfer_func = sdformat->format.xfer_func;
@@ -1144,48 +1084,65 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- CSIS_PAD_SOURCE);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);
*fmt = sdformat->format;
/* The format on the source pad might change due to unpacking. */
fmt->code = csis_fmt->output;
- /* Store the CSIS format descriptor for active formats. */
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csis->csis_fmt = csis_fmt;
-
- mutex_unlock(&csis->lock);
-
return 0;
}
static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_frame_desc *fd)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0];
+ const struct csis_pix_format *csis_fmt;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_state *state;
if (pad != CSIS_PAD_SOURCE)
return -EINVAL;
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE);
+ csis_fmt = find_csis_format(fmt->code);
+ v4l2_subdev_unlock_state(state);
+
fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
fd->num_entries = 1;
memset(entry, 0, sizeof(*entry));
- mutex_lock(&csis->lock);
-
entry->flags = 0;
- entry->pixelcode = csis->csis_fmt->code;
+ entry->pixelcode = csis_fmt->code;
entry->bus.csi2.vc = 0;
- entry->bus.csi2.dt = csis->csis_fmt->data_type;
-
- mutex_unlock(&csis->lock);
+ entry->bus.csi2.dt = csis_fmt->data_type;
return 0;
}
+static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = {
+ .pad = CSIS_PAD_SINK,
+ };
+
+ fmt.format.code = mipi_csis_formats[0].code;
+ fmt.format.width = MIPI_CSIS_DEF_PIX_WIDTH;
+ fmt.format.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+
+ fmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt.format.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt.format.colorspace);
+ fmt.format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt.format.colorspace);
+ fmt.format.quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace,
+ fmt.format.ycbcr_enc);
+
+ return mipi_csis_set_fmt(sd, sd_state, &fmt);
+}
+
static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
@@ -1208,7 +1165,7 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
.init_cfg = mipi_csis_init_cfg,
.enum_mbus_code = mipi_csis_enum_mbus_code,
- .get_fmt = mipi_csis_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mipi_csis_set_fmt,
.get_frame_desc = mipi_csis_get_frame_desc,
};
@@ -1348,40 +1305,34 @@ static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_disable(csis);
if (ret)
- goto unlock;
+ return -EAGAIN;
mipi_csis_clk_disable(csis);
-unlock:
- mutex_unlock(&csis->lock);
-
- return ret ? -EAGAIN : 0;
+ return 0;
}
static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_enable(csis);
if (ret)
- goto unlock;
+ return -EAGAIN;
- mipi_csis_clk_enable(csis);
-
-unlock:
- mutex_unlock(&csis->lock);
+ ret = mipi_csis_clk_enable(csis);
+ if (ret) {
+ mipi_csis_phy_disable(csis);
+ return ret;
+ }
- return ret ? -EAGAIN : 0;
+ return 0;
}
static const struct dev_pm_ops mipi_csis_pm_ops = {
@@ -1396,6 +1347,7 @@ static const struct dev_pm_ops mipi_csis_pm_ops = {
static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
{
struct v4l2_subdev *sd = &csis->sd;
+ int ret;
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
sd->owner = THIS_MODULE;
@@ -1417,15 +1369,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
return -ENOENT;
}
- csis->csis_fmt = &mipi_csis_formats[0];
- mipi_csis_init_cfg(sd, NULL);
-
csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
| MEDIA_PAD_FL_MUST_CONNECT;
- return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
- csis->pads);
+ ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret) {
+ media_entity_cleanup(&sd->entity);
+ return ret;
+ }
+
+ return 0;
}
static int mipi_csis_parse_dt(struct mipi_csis_device *csis)
@@ -1450,7 +1408,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (!csis)
return -ENOMEM;
- mutex_init(&csis->lock);
spin_lock_init(&csis->slock);
csis->dev = dev;
@@ -1496,20 +1453,20 @@ static int mipi_csis_probe(struct platform_device *pdev)
dev_name(dev), csis);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
- goto disable_clock;
+ goto err_disable_clock;
}
/* Initialize and register the subdev. */
ret = mipi_csis_subdev_init(csis);
if (ret < 0)
- goto disable_clock;
+ goto err_disable_clock;
platform_set_drvdata(pdev, &csis->sd);
ret = mipi_csis_async_register(csis);
if (ret < 0) {
dev_err(dev, "async register failed: %d\n", ret);
- goto cleanup;
+ goto err_cleanup;
}
/* Initialize debugfs. */
@@ -1520,7 +1477,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (!pm_runtime_enabled(dev)) {
ret = mipi_csis_runtime_resume(dev);
if (ret < 0)
- goto unregister_all;
+ goto err_unregister_all;
}
dev_info(dev, "lanes: %d, freq: %u\n",
@@ -1528,17 +1485,17 @@ static int mipi_csis_probe(struct platform_device *pdev)
return 0;
-unregister_all:
+err_unregister_all:
mipi_csis_debugfs_exit(csis);
-cleanup:
+err_cleanup:
+ v4l2_subdev_cleanup(&csis->sd);
media_entity_cleanup(&csis->sd.entity);
v4l2_async_nf_unregister(&csis->notifier);
v4l2_async_nf_cleanup(&csis->notifier);
v4l2_async_unregister_subdev(&csis->sd);
-disable_clock:
+err_disable_clock:
mipi_csis_clk_disable(csis);
fwnode_handle_put(csis->sd.fwnode);
- mutex_destroy(&csis->lock);
return ret;
}
@@ -1556,9 +1513,9 @@ static int mipi_csis_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mipi_csis_runtime_suspend(&pdev->dev);
mipi_csis_clk_disable(csis);
+ v4l2_subdev_cleanup(&csis->sd);
media_entity_cleanup(&csis->sd.entity);
fwnode_handle_put(csis->sd.fwnode);
- mutex_destroy(&csis->lock);
pm_runtime_set_suspended(&pdev->dev);
return 0;
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index 689ae5e6ac62..fde3c36e5e1d 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -10,6 +10,7 @@
* Pawel Osciak, <pawel@osciak.com>
* Marek Szyprowski, <m.szyprowski@samsung.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -18,15 +19,18 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
+#include <media/media-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>
#include "imx-pxp.h"
@@ -52,6 +56,11 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define MEM2MEM_HFLIP (1 << 0)
#define MEM2MEM_VFLIP (1 << 1)
+#define PXP_VERSION_MAJOR(version) \
+ FIELD_GET(BM_PXP_VERSION_MAJOR, version)
+#define PXP_VERSION_MINOR(version) \
+ FIELD_GET(BM_PXP_VERSION_MINOR, version)
+
#define dprintk(dev, fmt, arg...) \
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
@@ -168,14 +177,21 @@ enum {
V4L2_M2M_DST = 1,
};
-static struct pxp_fmt *find_format(struct v4l2_format *f)
+static const struct regmap_config pxp_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = HW_PXP_VERSION,
+};
+
+static struct pxp_fmt *find_format(unsigned int pixelformat)
{
struct pxp_fmt *fmt;
unsigned int k;
for (k = 0; k < NUM_FORMATS; k++) {
fmt = &formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == pixelformat)
break;
}
@@ -185,12 +201,23 @@ static struct pxp_fmt *find_format(struct v4l2_format *f)
return &formats[k];
}
+struct pxp_ctx;
+
+struct pxp_pdata {
+ u32 (*data_path_ctrl0)(struct pxp_ctx *ctx);
+};
+
struct pxp_dev {
struct v4l2_device v4l2_dev;
struct video_device vfd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+#endif
struct clk *clk;
- void __iomem *mmio;
+ struct regmap *regmap;
+
+ const struct pxp_pdata *pdata;
atomic_t num_inst;
struct mutex dev_mutex;
@@ -234,6 +261,20 @@ static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
return &ctx->q_data[V4L2_M2M_DST];
}
+static inline u32 pxp_read(struct pxp_dev *dev, u32 reg)
+{
+ u32 value;
+
+ regmap_read(dev->regmap, reg, &value);
+
+ return value;
+}
+
+static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value)
+{
+ regmap_write(dev->regmap, reg, value);
+}
+
static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
{
switch (v4l2_pix_fmt) {
@@ -486,11 +527,11 @@ static void pxp_setup_csc(struct pxp_ctx *ctx)
csc1_coef = csc1_coef_smpte240m_lim;
}
- writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0);
- writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1);
- writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2);
+ pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]);
+ pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]);
+ pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]);
} else {
- writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0);
+ pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS);
}
if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
@@ -706,18 +747,95 @@ static void pxp_setup_csc(struct pxp_ctx *ctx)
BP_PXP_CSC2_CTRL_CSC_MODE;
}
- writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL);
- writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0);
- writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1);
- writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2);
- writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3);
- writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4);
- writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5);
+ pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl);
+ pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]);
+ pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]);
+ pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]);
+ pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]);
+ pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]);
+ pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]);
} else {
- writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL);
+ pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS);
}
}
+static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx)
+{
+ u32 ctrl0;
+
+ ctrl0 = 0;
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
+ /* Bypass Dithering x3CH */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
+ /* Select Rotation */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0);
+ /* Bypass LUT */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
+ /* Select CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
+ /* Bypass Rotation 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
+
+ return ctrl0;
+}
+
+static u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx)
+{
+ u32 ctrl0;
+
+ ctrl0 = 0;
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
+ /* Select Rotation 0 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
+ /* Select MUX11 for Rotation 0 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1);
+ /* Bypass LUT */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
+ /* Select CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
+ /* Select Composite Alpha Blending/Color Key 0 for CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
+ /* Bypass Rotation 1 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
+
+ return ctrl0;
+}
+
+static void pxp_set_data_path(struct pxp_ctx *ctx)
+{
+ struct pxp_dev *dev = ctx->dev;
+ u32 ctrl0;
+ u32 ctrl1;
+
+ ctrl0 = dev->pdata->data_path_ctrl0(ctx);
+
+ ctrl1 = 0;
+ ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3);
+ ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3);
+
+ pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0);
+ pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1);
+}
+
static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
struct vb2_v4l2_buffer *out_vb)
{
@@ -871,67 +989,48 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
BF_PXP_PS_SCALE_XSCALE(xscale);
ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
- writel(ctrl, dev->mmio + HW_PXP_CTRL);
+ pxp_write(dev, HW_PXP_CTRL, ctrl);
/* skip STAT */
- writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL);
- writel(out_buf, dev->mmio + HW_PXP_OUT_BUF);
- writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2);
- writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH);
- writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC);
- writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC);
- writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC);
- writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC);
- writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC);
- writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL);
- writel(ps_buf, dev->mmio + HW_PXP_PS_BUF);
- writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF);
- writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF);
- writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH);
- writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0);
- writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE);
- writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET);
+ pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl);
+ pxp_write(dev, HW_PXP_OUT_BUF, out_buf);
+ pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2);
+ pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch);
+ pxp_write(dev, HW_PXP_OUT_LRC, out_lrc);
+ pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc);
+ pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc);
+ pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc);
+ pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc);
+ pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl);
+ pxp_write(dev, HW_PXP_PS_BUF, ps_buf);
+ pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf);
+ pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf);
+ pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch);
+ pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_PS_SCALE, ps_scale);
+ pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset);
/* disable processed surface color keying */
- writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0);
- writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0);
+ pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000);
/* disable alpha surface color keying */
- writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0);
- writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0);
+ pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000);
/* setup CSC */
pxp_setup_csc(ctx);
/* bypass LUT */
- writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL);
-
- writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)|
- BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)|
- BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0),
- dev->mmio + HW_PXP_DATA_PATH_CTRL0);
- writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) |
- BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1),
- dev->mmio + HW_PXP_DATA_PATH_CTRL1);
-
- writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK);
+ pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS);
+
+ pxp_set_data_path(ctx);
+
+ pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff);
/* ungate, enable PS/AS/OUT and PXP operation */
- writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET);
- writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
- BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 |
- BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE);
+ pxp_write(dev, HW_PXP_CTRL_SET,
+ BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
+ BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT);
return 0;
}
@@ -1004,23 +1103,23 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
struct pxp_dev *dev = dev_id;
u32 stat;
- stat = readl(dev->mmio + HW_PXP_STAT);
+ stat = pxp_read(dev, HW_PXP_STAT);
if (stat & BM_PXP_STAT_IRQ0) {
/* we expect x = 0, y = height, irq0 = 1 */
if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
BM_PXP_STAT_IRQ0))
dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
- writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR);
+ pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0);
pxp_job_finish(dev);
} else {
- u32 irq = readl(dev->mmio + HW_PXP_IRQ);
+ u32 irq = pxp_read(dev, HW_PXP_IRQ);
dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
- writel(irq, dev->mmio + HW_PXP_IRQ_CLR);
+ pxp_write(dev, HW_PXP_IRQ_CLR, irq);
}
return IRQ_HANDLED;
@@ -1034,8 +1133,6 @@ static int pxp_querycap(struct file *file, void *priv,
{
strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info),
- "platform:%s", MEM2MEM_NAME);
return 0;
}
@@ -1181,10 +1278,10 @@ static int pxp_try_fmt_vid_cap(struct file *file, void *priv,
struct pxp_fmt *fmt;
struct pxp_ctx *ctx = file2ctx(file);
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
if (!fmt) {
f->fmt.pix.pixelformat = formats[0].fourcc;
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
}
if (!(fmt->types & MEM2MEM_CAPTURE)) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1209,10 +1306,10 @@ static int pxp_try_fmt_vid_out(struct file *file, void *priv,
struct pxp_fmt *fmt;
struct pxp_ctx *ctx = file2ctx(file);
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
if (!fmt) {
f->fmt.pix.pixelformat = formats[0].fourcc;
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
}
if (!(fmt->types & MEM2MEM_OUTPUT)) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1245,7 +1342,7 @@ static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
return -EBUSY;
}
- q_data->fmt = find_format(f);
+ q_data->fmt = find_format(f->fmt.pix.pixelformat);
q_data->width = f->fmt.pix.width;
q_data->height = f->fmt.pix.height;
q_data->bytesperline = f->fmt.pix.bytesperline;
@@ -1304,6 +1401,26 @@ static int pxp_s_fmt_vid_out(struct file *file, void *priv,
return 0;
}
+static int pxp_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index > 0)
+ return -EINVAL;
+
+ if (!find_format(fsize->pixel_format))
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = MIN_W;
+ fsize->stepwise.max_width = MAX_W;
+ fsize->stepwise.step_width = 1 << ALIGN_W;
+ fsize->stepwise.min_height = MIN_H;
+ fsize->stepwise.max_height = MAX_H;
+ fsize->stepwise.step_height = 1 << ALIGN_H;
+
+ return 0;
+}
+
static u8 pxp_degrees_to_rot_mode(u32 degrees)
{
switch (degrees) {
@@ -1372,6 +1489,8 @@ static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
.vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out,
+ .vidioc_enum_framesizes = pxp_enum_framesizes,
+
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
@@ -1644,18 +1763,18 @@ static int pxp_soft_reset(struct pxp_dev *dev)
int ret;
u32 val;
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
- ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
- val & BM_PXP_CTRL_CLKGATE, 0, 100);
+ ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val,
+ val & BM_PXP_CTRL_CLKGATE, 0, 100);
if (ret < 0)
return ret;
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
return 0;
}
@@ -1664,13 +1783,17 @@ static int pxp_probe(struct platform_device *pdev)
{
struct pxp_dev *dev;
struct video_device *vfd;
+ u32 hw_version;
int irq;
int ret;
+ void __iomem *mmio;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
+ dev->pdata = of_device_get_match_data(&pdev->dev);
+
dev->clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
@@ -1678,9 +1801,11 @@ static int pxp_probe(struct platform_device *pdev)
return ret;
}
- dev->mmio = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(dev->mmio))
- return PTR_ERR(dev->mmio);
+ mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+ dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio,
+ &pxp_regmap_config);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -1688,8 +1813,8 @@ static int pxp_probe(struct platform_device *pdev)
spin_lock_init(&dev->irqlock);
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
- IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+ ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0,
+ dev_name(&pdev->dev), dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
return ret;
@@ -1705,6 +1830,10 @@ static int pxp_probe(struct platform_device *pdev)
goto err_clk;
}
+ hw_version = pxp_read(dev, HW_PXP_VERSION);
+ dev_dbg(&pdev->dev, "PXP Version %u.%u\n",
+ PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version));
+
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
goto err_clk;
@@ -1737,8 +1866,34 @@ static int pxp_probe(struct platform_device *pdev)
goto err_m2m;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->mdev.dev = &pdev->dev;
+ strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model));
+ media_device_init(&dev->mdev);
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
+ MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize media device\n");
+ goto err_vfd;
+ }
+
+ ret = media_device_register(&dev->mdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register media device\n");
+ goto err_m2m_mc;
+ }
+#endif
+
return 0;
+#ifdef CONFIG_MEDIA_CONTROLLER
+err_m2m_mc:
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+err_vfd:
+ video_unregister_device(vfd);
+#endif
err_m2m:
v4l2_m2m_release(dev->m2m_dev);
err_v4l2:
@@ -1753,12 +1908,17 @@ static int pxp_remove(struct platform_device *pdev)
{
struct pxp_dev *dev = platform_get_drvdata(pdev);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET);
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
clk_disable_unprepare(dev->clk);
v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_unregister(&dev->mdev);
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+#endif
video_unregister_device(&dev->vfd);
v4l2_m2m_release(dev->m2m_dev);
v4l2_device_unregister(&dev->v4l2_dev);
@@ -1766,8 +1926,17 @@ static int pxp_remove(struct platform_device *pdev)
return 0;
}
+static const struct pxp_pdata pxp_imx6ull_pdata = {
+ .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0,
+};
+
+static const struct pxp_pdata pxp_imx7d_pdata = {
+ .data_path_ctrl0 = pxp_imx7d_data_path_ctrl0,
+};
+
static const struct of_device_id pxp_dt_ids[] = {
- { .compatible = "fsl,imx6ull-pxp", .data = NULL },
+ { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata },
+ { .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata },
{ },
};
MODULE_DEVICE_TABLE(of, pxp_dt_ids);
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 1ef92c8c0098..c22bf5c827e7 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -211,7 +211,6 @@ struct imx7_csi {
int irq;
struct clk *mclk;
- struct mutex lock; /* Protects is_streaming, format_mbus, cc */
spinlock_t irqlock; /* Protects last_eof */
/* Media and V4L2 device */
@@ -227,9 +226,6 @@ struct imx7_csi {
struct v4l2_subdev sd;
struct media_pad pad[IMX7_CSI_PADS_NUM];
- struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
- const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM];
-
/* Video device */
struct video_device *vdev; /* Video device */
struct media_pad vdev_pad; /* Video device pad */
@@ -510,7 +506,8 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi)
imx7_csi_hw_disable_irq(csi);
}
-static void imx7_csi_configure(struct imx7_csi *csi)
+static void imx7_csi_configure(struct imx7_csi *csi,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_pix_format *out_pix = &csi->vdev_fmt;
int width = out_pix->width;
@@ -541,12 +538,17 @@ static void imx7_csi_configure(struct imx7_csi *csi)
out_pix->pixelformat == V4L2_PIX_FMT_YUYV)
width *= 2;
} else {
+ const struct v4l2_mbus_framefmt *sink_fmt;
+
+ sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state,
+ IMX7_CSI_PAD_SINK);
+
cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC
| BIT_MCLKDIV(1) | BIT_MCLKEN;
cr18 |= BIT_DATA_FROM_MIPI;
- switch (csi->format_mbus[IMX7_CSI_PAD_SINK].code) {
+ switch (sink_fmt->code) {
case MEDIA_BUS_FMT_Y8_1X8:
case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
@@ -627,7 +629,8 @@ static void imx7_csi_configure(struct imx7_csi *csi)
imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA);
}
-static int imx7_csi_init(struct imx7_csi *csi)
+static int imx7_csi_init(struct imx7_csi *csi,
+ struct v4l2_subdev_state *sd_state)
{
int ret;
@@ -635,7 +638,7 @@ static int imx7_csi_init(struct imx7_csi *csi)
if (ret < 0)
return ret;
- imx7_csi_configure(csi);
+ imx7_csi_configure(csi, sd_state);
ret = imx7_csi_dma_setup(csi);
if (ret < 0) {
@@ -1413,14 +1416,15 @@ static void imx7_csi_video_buf_queue(struct vb2_buffer *vb)
static int imx7_csi_video_validate_fmt(struct imx7_csi *csi)
{
- struct v4l2_subdev_format fmt_src;
+ struct v4l2_subdev_format fmt_src = {
+ .pad = IMX7_CSI_PAD_SRC,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
const struct imx7_csi_pixfmt *cc;
int ret;
/* Retrieve the media bus format on the source subdev. */
- fmt_src.pad = IMX7_CSI_PAD_SRC;
- fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src);
+ ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src);
if (ret)
return ret;
@@ -1601,17 +1605,15 @@ static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi)
static int imx7_csi_video_init_format(struct imx7_csi *csi)
{
- struct v4l2_subdev_format fmt_src = {
- .pad = IMX7_CSI_PAD_SRC,
- .which = V4L2_SUBDEV_FORMAT_ACTIVE,
- };
- fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE;
- fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH;
- fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT;
+ struct v4l2_mbus_framefmt format = { };
+
+ format.code = IMX7_CSI_DEF_MBUS_CODE;
+ format.width = IMX7_CSI_DEF_PIX_WIDTH;
+ format.height = IMX7_CSI_DEF_PIX_HEIGHT;
- imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL);
- csi->vdev_compose.width = fmt_src.format.width;
- csi->vdev_compose.height = fmt_src.format.height;
+ imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &format, NULL);
+ csi->vdev_compose.width = format.width;
+ csi->vdev_compose.height = format.height;
csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat);
@@ -1730,20 +1732,13 @@ static int imx7_csi_video_init(struct imx7_csi *csi)
static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev_state *sd_state;
int ret = 0;
- mutex_lock(&csi->lock);
-
- if (!csi->src_sd) {
- ret = -EPIPE;
- goto out_unlock;
- }
-
- if (csi->is_streaming == !!enable)
- goto out_unlock;
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
if (enable) {
- ret = imx7_csi_init(csi);
+ ret = imx7_csi_init(csi, sd_state);
if (ret < 0)
goto out_unlock;
@@ -1765,29 +1760,14 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
csi->is_streaming = !!enable;
out_unlock:
- mutex_unlock(&csi->lock);
+ v4l2_subdev_unlock_state(sd_state);
return ret;
}
-static struct v4l2_mbus_framefmt *
-imx7_csi_get_format(struct imx7_csi *csi,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
-
- return &csi->format_mbus[pad];
-}
-
static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
- const enum v4l2_subdev_format_whence which =
- sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
const struct imx7_csi_pixfmt *cc;
int i;
@@ -1795,7 +1775,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
struct v4l2_mbus_framefmt *mf =
- imx7_csi_get_format(csi, sd_state, i, which);
+ v4l2_subdev_get_pad_format(sd, sd_state, i);
mf->code = IMX7_CSI_DEF_MBUS_CODE;
mf->width = IMX7_CSI_DEF_PIX_WIDTH;
@@ -1807,8 +1787,6 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace);
mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv,
mf->colorspace, mf->ycbcr_enc);
-
- csi->cc[i] = cc;
}
return 0;
@@ -1818,59 +1796,30 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *in_fmt;
int ret = 0;
- mutex_lock(&csi->lock);
-
- in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
- code->which);
+ in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
switch (code->pad) {
case IMX7_CSI_PAD_SINK:
ret = imx7_csi_enum_mbus_formats(&code->code, code->index);
break;
+
case IMX7_CSI_PAD_SRC:
if (code->index != 0) {
ret = -EINVAL;
- goto out_unlock;
+ break;
}
code->code = in_fmt->code;
break;
- default:
- ret = -EINVAL;
- }
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
- return ret;
-}
-
-static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *fmt;
- int ret = 0;
-
- mutex_lock(&csi->lock);
- fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
- sdformat->which);
- if (!fmt) {
+ default:
ret = -EINVAL;
- goto out_unlock;
+ break;
}
- sdformat->format = *fmt;
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
return ret;
}
@@ -1920,19 +1869,16 @@ static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt)
tryfmt->ycbcr_enc);
}
-static int imx7_csi_try_fmt(struct imx7_csi *csi,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat,
- const struct imx7_csi_pixfmt **cc)
+static void imx7_csi_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *sdformat,
+ const struct imx7_csi_pixfmt **cc)
{
const struct imx7_csi_pixfmt *in_cc;
struct v4l2_mbus_framefmt *in_fmt;
u32 code;
- in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
- sdformat->which);
- if (!in_fmt)
- return -EINVAL;
+ in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
switch (sdformat->pad) {
case IMX7_CSI_PAD_SRC:
@@ -1949,6 +1895,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
sdformat->format.quantization = in_fmt->quantization;
sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
break;
+
case IMX7_CSI_PAD_SINK:
*cc = imx7_csi_find_mbus_format(sdformat->format.code);
if (!*cc) {
@@ -1960,13 +1907,9 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
if (sdformat->format.field != V4L2_FIELD_INTERLACED)
sdformat->format.field = V4L2_FIELD_NONE;
break;
- default:
- return -EINVAL;
}
imx7_csi_try_colorimetry(&sdformat->format);
-
- return 0;
}
static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
@@ -1979,28 +1922,13 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
const struct imx7_csi_pixfmt *cc;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_subdev_format format;
- int ret = 0;
-
- if (sdformat->pad >= IMX7_CSI_PADS_NUM)
- return -EINVAL;
- mutex_lock(&csi->lock);
-
- if (csi->is_streaming) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ if (csi->is_streaming)
+ return -EBUSY;
- ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
- if (ret < 0)
- goto out_unlock;
+ imx7_csi_try_fmt(sd, sd_state, sdformat, &cc);
- fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
- sdformat->which);
- if (!fmt) {
- ret = -EINVAL;
- goto out_unlock;
- }
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
*fmt = sdformat->format;
@@ -2009,25 +1937,14 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
format.pad = IMX7_CSI_PAD_SRC;
format.which = sdformat->which;
format.format = sdformat->format;
- if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) {
- ret = -EINVAL;
- goto out_unlock;
- }
- outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC,
- sdformat->which);
- *outfmt = format.format;
+ imx7_csi_try_fmt(sd, sd_state, &format, &outcc);
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csi->cc[IMX7_CSI_PAD_SRC] = outcc;
+ outfmt = v4l2_subdev_get_pad_format(sd, sd_state,
+ IMX7_CSI_PAD_SRC);
+ *outfmt = format.format;
}
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csi->cc[sdformat->pad] = cc;
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
- return ret;
+ return 0;
}
static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
@@ -2040,9 +1957,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
unsigned int i;
int ret;
- if (!csi->src_sd)
- return -EPIPE;
-
/*
* Validate the source link, and record whether the source uses the
* parallel input or the CSI-2 receiver.
@@ -2130,7 +2044,7 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
.init_cfg = imx7_csi_init_cfg,
.enum_mbus_code = imx7_csi_enum_mbus_code,
- .get_fmt = imx7_csi_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx7_csi_set_fmt,
.link_validate = imx7_csi_pad_link_validate,
};
@@ -2203,7 +2117,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ret = PTR_ERR(asd);
/* OK if asd already exists */
if (ret != -EEXIST)
- return ret;
+ goto error;
}
}
@@ -2211,15 +2125,20 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier);
if (ret)
- return ret;
+ goto error;
return 0;
+
+error:
+ v4l2_async_nf_cleanup(&csi->notifier);
+ return ret;
}
static void imx7_csi_media_cleanup(struct imx7_csi *csi)
{
v4l2_device_unregister(&csi->v4l2_dev);
media_device_unregister(&csi->mdev);
+ v4l2_subdev_cleanup(&csi->sd);
media_device_cleanup(&csi->mdev);
}
@@ -2287,6 +2206,10 @@ static int imx7_csi_media_init(struct imx7_csi *csi)
if (ret)
goto error;
+ ret = v4l2_subdev_init_finalize(&csi->sd);
+ if (ret)
+ goto error;
+
ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd);
if (ret)
goto error;
@@ -2312,27 +2235,22 @@ static int imx7_csi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, csi);
spin_lock_init(&csi->irqlock);
- mutex_init(&csi->lock);
/* Acquire resources and install interrupt handler. */
csi->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(csi->mclk)) {
ret = PTR_ERR(csi->mclk);
dev_err(dev, "Failed to get mclk: %d", ret);
- goto destroy_mutex;
+ return ret;
}
csi->irq = platform_get_irq(pdev, 0);
- if (csi->irq < 0) {
- ret = csi->irq;
- goto destroy_mutex;
- }
+ if (csi->irq < 0)
+ return csi->irq;
csi->regbase = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(csi->regbase)) {
- ret = PTR_ERR(csi->regbase);
- goto destroy_mutex;
- }
+ if (IS_ERR(csi->regbase))
+ return PTR_ERR(csi->regbase);
csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev);
@@ -2340,34 +2258,23 @@ static int imx7_csi_probe(struct platform_device *pdev)
(void *)csi);
if (ret < 0) {
dev_err(dev, "Request CSI IRQ failed.\n");
- goto destroy_mutex;
+ return ret;
}
/* Initialize all the media device infrastructure. */
ret = imx7_csi_media_init(csi);
if (ret)
- goto destroy_mutex;
-
- /* Set the default mbus formats. */
- ret = imx7_csi_init_cfg(&csi->sd, NULL);
- if (ret)
- goto media_cleanup;
+ return ret;
ret = imx7_csi_async_register(csi);
if (ret)
- goto subdev_notifier_cleanup;
+ goto err_media_cleanup;
return 0;
-subdev_notifier_cleanup:
- v4l2_async_nf_unregister(&csi->notifier);
- v4l2_async_nf_cleanup(&csi->notifier);
-media_cleanup:
+err_media_cleanup:
imx7_csi_media_cleanup(csi);
-destroy_mutex:
- mutex_destroy(&csi->lock);
-
return ret;
}
@@ -2381,8 +2288,6 @@ static int imx7_csi_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&csi->notifier);
v4l2_async_unregister_subdev(&csi->sd);
- mutex_destroy(&csi->lock);
-
return 0;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
index 451a4c9b3d30..04baa80494c6 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
@@ -429,7 +429,8 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy,
array_size = ARRAY_SIZE(lane_regs_sm8250[0]);
break;
default:
- unreachable();
+ WARN(1, "unknown cspi version\n");
+ return;
}
for (l = 0; l < 5; l++) {
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 33e08efa3039..384fb54e219a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -406,7 +406,7 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS))
break;
usleep_range(100, 200);
- };
+ }
if (!timeout)
dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n");
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 91b57c7c2e56..e6eedd65b71d 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -404,7 +404,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
break;
usleep_range(10, 20);
- };
+ }
/* Notify that AXI bus can not stop here */
if (!retries)
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index d4540684ea9a..d1d1fdce03e3 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -1131,10 +1131,12 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap,
const struct rkisp1_capture_config *config = cap->config;
const struct rkisp1_capture_fmt_cfg *fmt;
const struct v4l2_format_info *info;
- const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH,
- RKISP1_RSZ_SP_SRC_MAX_WIDTH };
- const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
- RKISP1_RSZ_SP_SRC_MAX_HEIGHT};
+ 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
+ };
fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat);
if (!fmt) {
@@ -1336,8 +1338,9 @@ void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1)
static int rkisp1_register_capture(struct rkisp1_capture *cap)
{
- const char * const dev_names[] = {RKISP1_MP_DEV_NAME,
- RKISP1_SP_DEV_NAME};
+ static const char * const dev_names[] = {
+ RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME
+ };
struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev;
struct video_device *vdev = &cap->vnode.vdev;
struct rkisp1_vdev_node *node;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.h b/drivers/media/platform/samsung/exynos4-is/fimc-is.h
index 06586e455b1d..c126b779aafc 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is.h
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.h
@@ -14,7 +14,6 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
@@ -231,7 +230,6 @@ struct chain_config {
/**
* struct fimc_is - fimc-is data structure
* @pdev: pointer to FIMC-IS platform device
- * @pctrl: pointer to pinctrl structure for this device
* @v4l2_dev: pointer to the top level v4l2_device
* @fw: data structure describing the FIMC-IS firmware binary
* @memory: memory region assigned for the FIMC-IS (firmware)
@@ -262,7 +260,6 @@ struct chain_config {
*/
struct fimc_is {
struct platform_device *pdev;
- struct pinctrl *pctrl;
struct v4l2_device *v4l2_dev;
struct fimc_is_firmware fw;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h
index 62ad5d7e035a..079105d88bab 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.h
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h
@@ -11,7 +11,6 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index f3e4cdac1ef3..9d2cce124a34 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -1021,8 +1021,8 @@ static __poll_t s5p_mfc_poll(struct file *file,
* means either in driver already or waiting for driver to claim it
* and start processing.
*/
- if ((!src_q->streaming || list_empty(&src_q->queued_list))
- && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+ if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) &&
+ (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) {
rc = EPOLLERR;
goto end;
}
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 18e6c65f4737..86c5235a0c7a 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -264,6 +264,7 @@ static int sun4i_csi_remove(struct platform_device *pdev)
{
struct sun4i_csi *csi = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
v4l2_async_nf_unregister(&csi->notifier);
v4l2_async_nf_cleanup(&csi->notifier);
vb2_video_unregister_device(&csi->vdev);
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
index a3e826a755fc..95b5633b7914 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -245,7 +245,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
* We need a scratch buffer in case where we'll not have any
* more buffer queued so that we don't error out. One of those
* cases is when you end up at the last frame to capture, you
- * don't havea any buffer queued any more, and yet it doesn't
+ * don't have any buffer queued any more, and yet it doesn't
* really matter since you'll never reach the next buffer.
*
* Since we support the multi-planar API, we need to have a
@@ -311,7 +311,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG);
/* Clear the pending interrupts */
- writel(CSI_INT_FRM_DONE, csi->regs + 0x34);
+ writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_STA_REG);
/* Enable frame done interrupt */
writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG);
diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c
index 9ea70817538e..ea2d0795d1e2 100644
--- a/drivers/media/platform/ti/davinci/vpbe_display.c
+++ b/drivers/media/platform/ti/davinci/vpbe_display.c
@@ -1149,7 +1149,7 @@ static int vpbe_display_open(struct file *file)
/* leaving if layer is already initialized */
if (!v4l2_fh_is_singular_file(file))
- return err;
+ return 0;
if (!layer->usrs) {
if (mutex_lock_interruptible(&layer->opslock))
diff --git a/drivers/media/platform/ti/davinci/vpbe_osd.c b/drivers/media/platform/ti/davinci/vpbe_osd.c
index 32f7ef547c82..f6ea71c081d4 100644
--- a/drivers/media/platform/ti/davinci/vpbe_osd.c
+++ b/drivers/media/platform/ti/davinci/vpbe_osd.c
@@ -1561,14 +1561,8 @@ static int osd_probe(struct platform_device *pdev)
return 0;
}
-static int osd_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver osd_driver = {
.probe = osd_probe,
- .remove = osd_remove,
.driver = {
.name = MODULE_NAME,
},
diff --git a/drivers/media/platform/ti/davinci/vpbe_venc.c b/drivers/media/platform/ti/davinci/vpbe_venc.c
index 4c8e31de12b1..6bde6517cba5 100644
--- a/drivers/media/platform/ti/davinci/vpbe_venc.c
+++ b/drivers/media/platform/ti/davinci/vpbe_venc.c
@@ -655,14 +655,8 @@ static int venc_probe(struct platform_device *pdev)
return 0;
}
-static int venc_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver venc_driver = {
.probe = venc_probe,
- .remove = venc_remove,
.driver = {
.name = MODULE_NAME,
},
diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c
index da27da4c165a..832489822706 100644
--- a/drivers/media/platform/ti/davinci/vpif.c
+++ b/drivers/media/platform/ti/davinci/vpif.c
@@ -480,7 +480,7 @@ static int vpif_probe(struct platform_device *pdev)
ret = irq;
goto err_put_rpm;
}
- res_irq = (struct resource)DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node));
+ res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node));
res_irq.flags |= irq_get_trigger_type(irq);
pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL);
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index 3e5348c63773..ddc7d08d4f96 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -221,22 +221,16 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
static int isp_video_get_graph_data(struct isp_video *video,
struct isp_pipeline *pipe)
{
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_entity_iter iter;
+ struct media_entity *entity;
struct isp_video *far_end = NULL;
int ret;
- mutex_lock(&mdev->graph_mutex);
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
+ ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter);
+ if (ret)
return ret;
- }
- media_graph_walk_start(&graph, entity);
-
- while ((entity = media_graph_walk_next(&graph))) {
+ media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) {
struct isp_video *__video;
media_entity_enum_set(&pipe->ent_enum, entity);
@@ -255,9 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
far_end = __video;
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
+ media_pipeline_entity_iter_cleanup(&iter);
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
pipe->input = far_end;
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 8cb4a68c9119..b0aeedae7b65 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -1050,8 +1050,6 @@ static int hantro_probe(struct platform_device *pdev)
vpu->mdev.dev = vpu->dev;
strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
- strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME,
- sizeof(vpu->mdev.bus_info));
media_device_init(&vpu->mdev);
vpu->mdev.ops = &hantro_m2m_media_ops;
vpu->v4l2_dev.mdev = &vpu->mdev;
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 2c7a805289e7..c0d427956210 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -142,8 +142,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
strscpy(cap->card, vdev->name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
- vpu->dev->driver->name);
return 0;
}
@@ -161,8 +159,11 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
}
/* For non-coded formats check if postprocessing scaling is possible */
- if (fmt->codec_mode == HANTRO_MODE_NONE && hantro_needs_postproc(ctx, fmt)) {
- return hanto_postproc_enum_framesizes(ctx, fsize);
+ if (fmt->codec_mode == HANTRO_MODE_NONE) {
+ if (hantro_needs_postproc(ctx, fmt))
+ return hanto_postproc_enum_framesizes(ctx, fsize);
+ else
+ return -ENOTTY;
} else if (fsize->index != 0) {
vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
fsize->index);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 0a7fd8642a65..fee02c8c85fd 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -173,31 +173,19 @@ done:
static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
struct xvip_dma *start)
{
- struct media_graph graph;
- struct media_entity *entity = &start->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_pad_iter iter;
unsigned int num_inputs = 0;
unsigned int num_outputs = 0;
- int ret;
-
- mutex_lock(&mdev->graph_mutex);
-
- /* Walk the graph to locate the video nodes. */
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- return ret;
- }
-
- media_graph_walk_start(&graph, entity);
+ struct media_pad *pad;
- while ((entity = media_graph_walk_next(&graph))) {
+ /* Locate the video nodes in the pipeline. */
+ media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) {
struct xvip_dma *dma;
- if (entity->function != MEDIA_ENT_F_IO_V4L)
+ if (pad->entity->function != MEDIA_ENT_F_IO_V4L)
continue;
- dma = to_xvip_dma(media_entity_to_video_device(entity));
+ dma = to_xvip_dma(media_entity_to_video_device(pad->entity));
if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
pipe->output = dma;
@@ -207,10 +195,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
}
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
-
/* We need exactly one output and zero or one input. */
if (num_outputs != 1 || num_inputs > 1)
return -EPIPE;
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 8a316de70e6c..cbd49dff6d74 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -1442,7 +1442,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
{
struct fmdev *fmdev;
- fmdev = (struct fmdev *)arg;
+ fmdev = arg;
if (skb == NULL) {
fmerr("Invalid SKB received from ST\n");
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index e09270916fbc..11ee21a7db8f 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1106,6 +1106,8 @@ static void ene_remove(struct pnp_dev *pnp_dev)
struct ene_device *dev = pnp_get_drvdata(pnp_dev);
unsigned long flags;
+ rc_unregister_device(dev->rdev);
+ del_timer_sync(&dev->tx_sim_timer);
spin_lock_irqsave(&dev->hw_lock, flags);
ene_rx_disable(dev);
ene_rx_restore_hw_buffer(dev);
@@ -1113,7 +1115,6 @@ static void ene_remove(struct pnp_dev *pnp_dev)
free_irq(dev->irq, dev);
release_region(dev->hw_io, ENE_IO_SIZE);
- rc_unregister_device(dev->rdev);
kfree(dev);
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8f1fff7af6c9..8dbe780dae4e 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -126,6 +126,23 @@ 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)
+{
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+ struct device *pmdev = gpio_dev->pmdev;
+
+ if (pmdev) {
+ pm_runtime_get_sync(pmdev);
+ cpu_latency_qos_remove_request(&gpio_dev->qos);
+
+ pm_runtime_disable(pmdev);
+ pm_runtime_put_noidle(pmdev);
+ pm_runtime_set_suspended(pmdev);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int gpio_ir_recv_suspend(struct device *dev)
{
@@ -185,6 +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,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(gpio_ir_recv_of_match),
diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c
index a5875380ef40..ce0b7a6e92dc 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_psi.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c
@@ -1940,7 +1940,7 @@ u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args)
struct vidtv_psi_table_eit_event
*vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id)
{
- const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */
+ static const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */
struct vidtv_psi_table_eit_event *e;
struct timespec64 ts;
struct tm time;
diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c
index b08664dfbe5f..7cac6a6456eb 100644
--- a/drivers/media/test-drivers/visl/visl-video.c
+++ b/drivers/media/test-drivers/visl/visl-video.c
@@ -687,7 +687,7 @@ static void visl_buf_request_complete(struct vb2_buffer *vb)
v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
}
-const struct vb2_ops visl_qops = {
+static const struct vb2_ops visl_qops = {
.queue_setup = visl_queue_setup,
.buf_out_validate = visl_buf_out_validate,
.buf_prepare = visl_buf_prepare,
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index d33514acc2b5..4014f7d07330 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1165,7 +1165,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
/* If any of these are non-zero, assume invalid data */
if (buf[1] || buf[2] || buf[3]) {
dev_dbg(&intf->dev, "invalid data\n");
- return ret;
+ return 0;
}
/* Check for repeat of previous code */
@@ -1174,7 +1174,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
dev_dbg(&intf->dev, "key repeated\n");
rc_repeat(d->rc_dev);
state->rc_repeat = buf[6];
- return ret;
+ return 0;
}
/* Only process key if canary killed */
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index b2edc4deaca3..13256565b034 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -404,16 +404,13 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
go->next_seq = 0;
go->active_buf = NULL;
go->modet_event_status = 0;
- q->streaming = 1;
if (go7007_start_encoder(go) < 0)
ret = -EIO;
else
ret = 0;
mutex_unlock(&go->hw_lock);
- if (ret) {
- q->streaming = 0;
+ if (ret)
return ret;
- }
call_all(&go->v4l2_dev, video, s_stream, 1);
v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
@@ -430,7 +427,6 @@ static void go7007_stop_streaming(struct vb2_queue *q)
struct go7007 *go = vb2_get_drv_priv(q);
unsigned long flags;
- q->streaming = 0;
go7007_stream_stop(go);
mutex_lock(&go->hw_lock);
go7007_reset_encoder(go);
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index fe9c7b3a950e..6f443c542c6d 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -179,6 +179,7 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev)
for (i = 0; i < MAX_URBS; i++) {
usb_kill_urb(&dev->surbs[i].urb);
+ cancel_work_sync(&dev->surbs[i].wq);
if (dev->surbs[i].cb) {
smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c
index 72bd64f65198..c00197d095e7 100644
--- a/drivers/media/v4l2-core/v4l2-h264.c
+++ b/drivers/media/v4l2-core/v4l2-h264.c
@@ -305,6 +305,8 @@ static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *bui
int n = 0, i;
*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
+ if (!(*out_str))
+ return NULL;
n += snprintf(*out_str + n, tmp_str_size - n, "|");
@@ -343,6 +345,8 @@ static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *bui
int n = 0, i;
*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
+ if (!(*out_str))
+ return NULL;
n += snprintf(*out_str + n, tmp_str_size - n, "|");
diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c
index c2513b775f6a..94435a7b6816 100644
--- a/drivers/media/v4l2-core/v4l2-jpeg.c
+++ b/drivers/media/v4l2-core/v4l2-jpeg.c
@@ -460,7 +460,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream,
/* Check for "Adobe\0" in Ap1..6 */
if (stream->curr + 6 > stream->end ||
strncmp(stream->curr, "Adobe\0", 6))
- return -EINVAL;
+ return jpeg_skip(stream, lp - 2);
/* get to Ap12 */
ret = jpeg_skip(stream, 11);
@@ -474,7 +474,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream,
*tf = ret;
/* skip the rest of the segment, this ensures at least it is complete */
- skip = lp - 2 - 11;
+ skip = lp - 2 - 11 - 1;
return jpeg_skip(stream, skip);
}
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index be7fde1ed3ea..0cc30397fbad 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -922,9 +922,9 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file,
* means either in driver already or waiting for driver to claim it
* and start processing.
*/
- if ((!src_q->streaming || src_q->error ||
+ if ((!vb2_is_streaming(src_q) || src_q->error ||
list_empty(&src_q->queued_list)) &&
- (!dst_q->streaming || dst_q->error ||
+ (!vb2_is_streaming(dst_q) || dst_q->error ||
(list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued)))
return EPOLLERR;
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index d71ee9a5d04b..bc6c7b248f86 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -22,6 +22,8 @@ if STAGING_MEDIA && MEDIA_SUPPORT
# Please keep them in alphabetic order
source "drivers/staging/media/atomisp/Kconfig"
+source "drivers/staging/media/av7110/Kconfig"
+
source "drivers/staging/media/imx/Kconfig"
source "drivers/staging/media/ipu3/Kconfig"
@@ -52,7 +54,6 @@ menuconfig STAGING_MEDIA_DEPRECATED
if STAGING_MEDIA_DEPRECATED
source "drivers/staging/media/deprecated/atmel/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/Kconfig"
endif
endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 1a01c1af3224..1a4c3a062e3d 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
-obj-y += deprecated/saa7146/
+obj-$(CONFIG_DVB_AV7110) += av7110/
diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig
index 2c8d7fdcc5f7..c9bff98e5309 100644
--- a/drivers/staging/media/atomisp/Kconfig
+++ b/drivers/staging/media/atomisp/Kconfig
@@ -14,7 +14,7 @@ config VIDEO_ATOMISP
depends on VIDEO_DEV && INTEL_ATOMISP
depends on PMIC_OPREGION
select IOSF_MBI
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
select VIDEO_V4L2_SUBDEV_API
help
Say Y here if your platform supports Intel Atom SoC
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 87a634bf9ff5..0d90683ed227 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -241,179 +241,6 @@ static int gc0310_write_reg_array(struct i2c_client *client,
return __gc0310_flush_reg_array(client, &ctrl);
}
-static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) |
- (GC0310_F_NUMBER_DEM << 16) |
- (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
-
- *val = dev->res->bin_factor_x;
-
- return 0;
-}
-
-static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
-
- *val = dev->res->bin_factor_y;
-
- return 0;
-}
-
-static int gc0310_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct gc0310_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct gc0310_device *dev = to_gc0310_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- u16 val;
- u8 reg_val;
- int ret;
- unsigned int hori_blanking;
- unsigned int vert_blanking;
- unsigned int sh_delay;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock calculattion */
- dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
- buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
- dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
-
- /* get integration time */
- buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- GC0310_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- GC0310_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- /* Getting crop_horizontal_start */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_CROP_START_L, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start);
-
- /* Getting crop_vertical_start */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_CROP_START_L, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start);
-
- /* Getting output_width */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_width = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "output_width=%d\n", buf->output_width);
-
- /* Getting output_height */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_height = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "output_height=%d\n", buf->output_height);
-
- buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
- buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
- dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end);
- dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end);
-
- /* Getting line_length_pck */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_BLANKING_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_BLANKING_L, &reg_val);
- if (ret)
- return ret;
- hori_blanking = val | (reg_val & 0xFF);
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_SH_DELAY, &reg_val);
- if (ret)
- return ret;
- sh_delay = reg_val;
- buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
- dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
- sh_delay, buf->line_length_pck);
-
- /* Getting frame_length_lines */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_BLANKING_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_BLANKING_L, &reg_val);
- if (ret)
- return ret;
- vert_blanking = val | (reg_val & 0xFF);
- buf->frame_length_lines = buf->output_height + vert_blanking;
- dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
- buf->frame_length_lines);
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
{
@@ -596,21 +423,6 @@ static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = gc0310_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = gc0310_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = gc0310_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -655,61 +467,6 @@ static const struct v4l2_ctrl_config gc0310_controls[] = {
.step = 1,
.def = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = GC0310_FOCAL_LENGTH_DEFAULT,
- .max = GC0310_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = GC0310_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = GC0310_F_NUMBER_DEFAULT,
- .max = GC0310_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = GC0310_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = GC0310_F_NUMBER_RANGE,
- .max = GC0310_F_NUMBER_RANGE,
- .step = 0x01,
- .def = GC0310_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = GC0310_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = GC0310_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
};
static int gc0310_init(struct v4l2_subdev *sd)
@@ -952,12 +709,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- ret = gc0310_get_intg_factor(client, gc0310_info, dev->res);
- if (ret) {
- dev_err(&client->dev, "failed to get integration_factor\n");
- goto err;
- }
-
err:
mutex_unlock(&dev->input_lock);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 4d5a7e335f85..cb4c79b483ca 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -220,135 +220,6 @@ static int gc2235_write_reg_array(struct i2c_client *client,
return __gc2235_flush_reg_array(client, &ctrl);
}
-static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /* const f number for imx */
- *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) |
- (GC2235_F_NUMBER_DEM << 16) |
- (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc2235_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct gc2235_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct gc2235_device *dev = to_gc2235_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- u16 reg_val, reg_val_h;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock calculattion */
- buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000;
-
- /* get integration time */
- buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- GC2235_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- GC2235_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_CROP_START_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_CROP_START_L, &reg_val);
- if (ret)
- return ret;
-
- buf->crop_horizontal_start = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_CROP_START_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_CROP_START_L, &reg_val);
- if (ret)
- return ret;
-
- buf->crop_vertical_start = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_OUTSIZE_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_width = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_OUTSIZE_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_height = (reg_val_h << 8) | reg_val;
-
- buf->crop_horizontal_end = buf->crop_horizontal_start +
- buf->output_width - 1;
- buf->crop_vertical_end = buf->crop_vertical_start +
- buf->output_height - 1;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_HB_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_HB_L, &reg_val);
- if (ret)
- return ret;
-
-#if 0
- u16 dummy = (reg_val_h << 8) | reg_val;
-#endif
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_SH_DELAY_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_SH_DELAY_L, &reg_val);
-
-#if 0
- buf->line_length_pck = buf->output_width + 16 + dummy +
- (((u16)reg_val_h << 8) | (u16)reg_val) + 4;
-#endif
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_VB_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_VB_L, &reg_val);
- if (ret)
- return ret;
-
-#if 0
- buf->frame_length_lines = buf->output_height + 32 +
- (((u16)reg_val_h << 8) | (u16)reg_val);
-#endif
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -467,15 +338,6 @@ static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = gc2235_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = gc2235_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = gc2235_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -499,39 +361,6 @@ static struct v4l2_ctrl_config gc2235_controls[] = {
.def = 0x00,
.flags = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = GC2235_FOCAL_LENGTH_DEFAULT,
- .max = GC2235_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = GC2235_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = GC2235_F_NUMBER_DEFAULT,
- .max = GC2235_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = GC2235_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = GC2235_F_NUMBER_RANGE,
- .max = GC2235_F_NUMBER_RANGE,
- .step = 0x01,
- .def = GC2235_F_NUMBER_RANGE,
- .flags = 0,
- },
};
static int __gc2235_init(struct v4l2_subdev *sd)
@@ -743,11 +572,6 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- ret = gc2235_get_intg_factor(client, gc2235_info,
- dev->res);
- if (ret)
- dev_err(&client->dev, "failed to get integration_factor\n");
-
err:
mutex_unlock(&dev->input_lock);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index a0e8e94b2412..0e5a981dd331 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -612,96 +612,6 @@ static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size)
return 0;
}
-static int mt9m114_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct mt9m114_res_struct *res)
-{
- struct atomisp_sensor_mode_data *buf;
- u32 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- buf = &info->data;
-
- ret = mt9m114_read_reg(client, MISENSOR_32BIT,
- REG_PIXEL_CLK, &reg_val);
- if (ret)
- return ret;
- buf->vt_pix_clk_freq_mhz = reg_val;
-
- /* get integration time */
- buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- MT9M114_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- MT9M114_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN;
-
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_H_START, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_V_START, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_H_END, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_V_END, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_WIDTH, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_HEIGHT, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_TIMING_HTS, &reg_val);
- if (ret)
- return ret;
- buf->line_length_pck = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_TIMING_VTS, &reg_val);
- if (ret)
- return ret;
- buf->frame_length_lines = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static int mt9m114_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -823,12 +733,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
mt9m114_res[index].used = false;
}
}
- ret = mt9m114_get_intg_factor(c, mt9m114_info,
- &mt9m114_res[res->res]);
- if (ret) {
- dev_err(&c->dev, "failed to get integration_factor\n");
- return -EINVAL;
- }
/*
* mt9m114 - we don't poll for context switch
* because it does not happen with streaming disabled.
@@ -841,28 +745,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-/* TODO: Update to SOC functions, remove exposure and gain */
-static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /* const f number for mt9m114 */
- *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
- return 0;
-}
-
-static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) |
- (MT9M114_F_NUMBER_DEM << 16) |
- (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM;
- return 0;
-}
-
/* Horizontal flip the image. */
static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val)
{
@@ -1134,24 +1016,6 @@ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
- *val = mt9m114_res[dev->res].bin_factor_x;
-
- return 0;
-}
-
-static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
- *val = mt9m114_res[dev->res].bin_factor_y;
-
- return 0;
-}
-
static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
{
struct i2c_client *c = v4l2_get_subdevdata(sd);
@@ -1271,27 +1135,12 @@ static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_HFLIP:
ret = mt9m114_g_hflip(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = mt9m114_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = mt9m114_g_exposure(&dev->sd, &ctrl->val);
break;
case V4L2_CID_EXPOSURE_ZONE_NUM:
ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_EXPOSURE:
ret = mt9m114_g_ev(&dev->sd, &ctrl->val);
break;
@@ -1333,39 +1182,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .name = "focal length",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_FOCAL_LENGTH_DEFAULT,
- .max = MT9M114_FOCAL_LENGTH_DEFAULT,
- .step = 1,
- .def = MT9M114_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .name = "f-number",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_F_NUMBER_DEFAULT,
- .max = MT9M114_F_NUMBER_DEFAULT,
- .step = 1,
- .def = MT9M114_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .name = "f-number range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_F_NUMBER_RANGE,
- .max = MT9M114_F_NUMBER_RANGE,
- .step = 1,
- .def = MT9M114_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_EXPOSURE_ABSOLUTE,
.name = "exposure",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1399,28 +1215,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .name = "horizontal binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = MT9M114_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .name = "vertical binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = MT9M114_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_EXPOSURE,
.name = "exposure biasx",
.type = V4L2_CTRL_TYPE_INTEGER,
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
index fa1de45b7a2d..aeb38599fe13 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
@@ -15,30 +15,22 @@
*
*/
-#include <asm/unaligned.h>
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
+#include <linux/acpi.h>
#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/i2c.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#include <media/ov_16bit_addr_reg_helpers.h>
#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include <linux/acpi.h>
+
#include "../include/linux/atomisp_gmin_platform.h"
#include "ov2680.h"
-static int h_flag;
-static int v_flag;
static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
atomisp_bayer_order_bggr,
atomisp_bayer_order_grbg,
@@ -46,64 +38,6 @@ static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
atomisp_bayer_order_rggb,
};
-/* i2c read/write stuff */
-static int ov2680_read_reg(struct i2c_client *client,
- int len, u16 reg, u32 *val)
-{
- struct i2c_msg msgs[2];
- u8 addr_buf[2] = { reg >> 8, reg & 0xff };
- u8 data_buf[4] = { 0, };
- int ret;
-
- if (len > 4)
- return -EINVAL;
-
- msgs[0].addr = client->addr;
- msgs[0].flags = 0;
- msgs[0].len = ARRAY_SIZE(addr_buf);
- msgs[0].buf = addr_buf;
-
- msgs[1].addr = client->addr;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = len;
- msgs[1].buf = &data_buf[4 - len];
-
- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (ret != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret);
- return -EIO;
- }
-
- *val = get_unaligned_be32(data_buf);
-
- return 0;
-}
-
-static int ov2680_write_reg(struct i2c_client *client, unsigned int len,
- u16 reg, u16 val)
-{
- u8 buf[6];
- int ret;
-
- if (len == 2)
- put_unaligned_be16(val, buf + 2);
- else if (len == 1)
- buf[2] = val;
- else
- return -EINVAL;
-
- put_unaligned_be16(reg, buf);
-
- ret = i2c_master_send(client, buf, len + 2);
- if (ret != len + 2) {
- dev_err(&client->dev, "write error %d reg 0x%04x, val 0x%02x: buf sent: %*ph\n",
- ret, reg, val, len + 2, &buf);
- return -EIO;
- }
-
- return 0;
-}
-
static int ov2680_write_reg_array(struct i2c_client *client,
const struct ov2680_reg *reglist)
{
@@ -111,7 +45,7 @@ static int ov2680_write_reg_array(struct i2c_client *client,
int ret;
for (; next->reg != 0; next++) {
- ret = ov2680_write_reg(client, 1, next->reg, next->val);
+ ret = ov_write_reg8(client, next->reg, next->val);
if (ret)
return ret;
}
@@ -119,518 +53,127 @@ static int ov2680_write_reg_array(struct i2c_client *client,
return 0;
}
-static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt)
{
- /* const f number for ov2680 */
-
- *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
- return 0;
-}
+ static const int ov2680_hv_flip_bayer_order[] = {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ };
+ struct camera_mipi_info *ov2680_info;
+ int hv_flip = 0;
-static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) |
- (OV2680_F_NUMBER_DEM << 16) |
- (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM;
- return 0;
-}
+ if (sensor->ctrls.vflip->val)
+ hv_flip += 1;
-static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (sensor->ctrls.hflip->val)
+ hv_flip += 2;
- dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n");
- *val = dev->res->bin_factor_x;
+ fmt->code = ov2680_hv_flip_bayer_order[hv_flip];
- return 0;
+ /* TODO atomisp specific custom API, should be removed */
+ ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd);
+ if (ov2680_info)
+ ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip];
}
-static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- *val = dev->res->bin_factor_y;
- dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n");
- return 0;
-}
-
-static int ov2680_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov2680_resolution *res)
-{
- struct atomisp_sensor_mode_data *buf = &info->data;
- unsigned int pix_clk_freq_hz;
- u32 reg_val;
int ret;
- dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n");
- if (!info)
- return -EINVAL;
-
- /* pixel clock */
- pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV2680_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV2680_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
+ if (sensor->is_streaming)
+ return -EBUSY;
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT1, BIT(2), val ? BIT(2) : 0);
+ if (ret < 0)
return ret;
- buf->output_width = reg_val;
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- (res->bin_factor_x * 2) : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- (res->bin_factor_y * 2) : 1;
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
return 0;
}
-static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
- int gain, int digitgain)
-
+static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- u16 vts;
- int ret, exp_val;
-
- dev_dbg(&client->dev,
- "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",
- coarse_itg, gain, digitgain);
-
- vts = dev->res->lines_per_frame;
-
- /* group hold */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0x00);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_GROUP_ACCESS);
- return ret;
- }
-
- /* Increase the VTS to match exposure + MARGIN */
- if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN)
- vts = (u16)coarse_itg + OV2680_INTEGRATION_TIME_MARGIN;
-
- ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_TIMING_VTS_H);
- return ret;
- }
-
- /* set exposure */
-
- /* Lower four bit should be 0*/
- exp_val = coarse_itg << 4;
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_L, exp_val & 0xFF);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_L);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_M);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_H);
- return ret;
- }
-
- /* Analog gain */
- ret = ov2680_write_reg(client, 2, OV2680_AGC_H, gain);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_AGC_H);
- return ret;
- }
- /* Digital gain */
- if (digitgain) {
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_RED_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_GREEN_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_BLUE_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
- }
+ int ret;
- /* End group */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0x10);
- if (ret)
- return ret;
+ if (sensor->is_streaming)
+ return -EBUSY;
- /* Delay launch group */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0xa0);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT2, BIT(2), val ? BIT(2) : 0);
+ if (ret < 0)
return ret;
- return ret;
-}
-
-static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure,
- int gain, int digitgain)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- int ret = 0;
-
- mutex_lock(&dev->input_lock);
-
- dev->exposure = exposure;
- dev->gain = gain;
- dev->digitgain = digitgain;
- if (dev->power_on)
- ret = __ov2680_set_exposure(sd, exposure, gain, digitgain);
-
- mutex_unlock(&dev->input_lock);
-
- return ret;
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
+ return 0;
}
-static long ov2680_s_exposure(struct v4l2_subdev *sd,
- struct atomisp_exposure *exposure)
+static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp)
{
- u16 coarse_itg = exposure->integration_time[0];
- u16 analog_gain = exposure->gain[0];
- u16 digital_gain = exposure->gain[1];
-
- /* we should not accept the invalid value below */
- if (analog_gain == 0) {
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- v4l2_err(client, "%s: invalid value\n", __func__);
- return -EINVAL;
- }
-
- return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
+ return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4);
}
-static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain)
{
- switch (cmd) {
- case ATOMISP_IOC_S_EXPOSURE:
- return ov2680_s_exposure(sd, arg);
-
- default:
- return -EINVAL;
- }
- return 0;
+ return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain);
}
-/*
- * This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
+static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 reg_val;
int ret;
- /* get exposure */
- ret = ov2680_read_reg(client, 3, OV2680_EXPOSURE_H, &reg_val);
- if (ret)
- return ret;
-
- /* Lower four bits are not part of the exposure val (always 0) */
- *value = reg_val >> 4;
- return 0;
-}
+ if (!value)
+ return ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), 0);
-static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
-{
- struct camera_mipi_info *ov2680_info = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u32 val;
- u8 index;
-
- dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
- ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, 0x03, value - 1);
+ if (ret < 0)
return ret;
- if (value)
- val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
- else
- val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
- ret = ov2680_write_reg(client, 1,
- OV2680_FLIP_REG, val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), BIT(7));
+ if (ret < 0)
return ret;
- index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT :
- 0);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (ov2680_info) {
- ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
- }
- return ret;
+
+ return 0;
}
-static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value)
+static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct camera_mipi_info *ov2680_info = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
int ret;
- u32 val;
- u8 index;
-
- dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
-
- ret = ov2680_read_reg(client, 1, OV2680_MIRROR_REG, &val);
- if (ret)
- return ret;
- if (value)
- val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
- else
- val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
- ret = ov2680_write_reg(client, 1,
- OV2680_MIRROR_REG, val);
- if (ret)
- return ret;
- index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT :
- 0);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (ov2680_info) {
- ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
+ /* Only apply changes to the controls if the device is powered up */
+ if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
+ return 0;
}
- return ret;
-}
-
-static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov2680_device *dev =
- container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
- int ret = 0;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
- dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
- __func__, ctrl->val);
- ret = ov2680_v_flip(&dev->sd, ctrl->val);
+ ret = ov2680_set_vflip(sensor, ctrl->val);
break;
case V4L2_CID_HFLIP:
- dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
- __func__, ctrl->val);
- ret = ov2680_h_flip(&dev->sd, ctrl->val);
+ ret = ov2680_set_hflip(sensor, ctrl->val);
break;
- default:
- ret = -EINVAL;
- }
- return ret;
-}
-
-static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov2680_device *dev =
- container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE_ABSOLUTE:
- ret = ov2680_q_exposure(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov2680_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov2680_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val);
+ case V4L2_CID_EXPOSURE:
+ ret = ov2680_exposure_set(sensor, ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val);
+ case V4L2_CID_GAIN:
+ ret = ov2680_gain_set(sensor, ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val);
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov2680_test_pattern_set(sensor, ctrl->val);
break;
default:
ret = -EINVAL;
}
+ pm_runtime_put(sensor->sd.dev);
return ret;
}
-static const struct v4l2_ctrl_ops ctrl_ops = {
+static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
.s_ctrl = ov2680_s_ctrl,
- .g_volatile_ctrl = ov2680_g_volatile_ctrl
-};
-
-static const struct v4l2_ctrl_config ov2680_controls[] = {
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_EXPOSURE_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .min = 0x0,
- .max = 0xffff,
- .step = 0x01,
- .def = 0x00,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV2680_FOCAL_LENGTH_DEFAULT,
- .max = OV2680_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV2680_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV2680_F_NUMBER_DEFAULT,
- .max = OV2680_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV2680_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV2680_F_NUMBER_RANGE,
- .max = OV2680_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV2680_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = OV2680_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = OV2680_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flip",
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
- },
};
static int ov2680_init_registers(struct v4l2_subdev *sd)
@@ -638,288 +181,191 @@ static int ov2680_init_registers(struct v4l2_subdev *sd)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- ret = ov2680_write_reg(client, 1, OV2680_SW_RESET, 0x01);
+ ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01);
ret |= ov2680_write_reg_array(client, ov2680_global_setting);
return ret;
}
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+static struct v4l2_mbus_framefmt *
+__ov2680_get_pad_format(struct ov2680_device *sensor,
+ struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
{
- int ret = 0;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!dev || !dev->platform_data)
- return -ENODEV;
-
- dev_dbg(&client->dev, "%s: %s", __func__, flag ? "on" : "off");
-
- if (flag) {
- ret |= dev->platform_data->v1p8_ctrl(sd, 1);
- ret |= dev->platform_data->v2p8_ctrl(sd, 1);
- usleep_range(10000, 15000);
- }
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&sensor->sd, state, pad);
- if (!flag || ret) {
- ret |= dev->platform_data->v1p8_ctrl(sd, 0);
- ret |= dev->platform_data->v2p8_ctrl(sd, 0);
- }
- return ret;
+ return &sensor->mode.fmt;
}
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+static void ov2680_fill_format(struct ov2680_device *sensor,
+ struct v4l2_mbus_framefmt *fmt,
+ unsigned int width, unsigned int height)
{
- int ret;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->width = width;
+ fmt->height = height;
+ fmt->field = V4L2_FIELD_NONE;
+ ov2680_set_bayer_order(sensor, fmt);
+}
- if (!dev || !dev->platform_data)
- return -ENODEV;
+static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height)
+{
+ int orig_width = width;
+ int orig_height = height;
- /*
- * The OV2680 documents only one GPIO input (#XSHUTDN), but
- * existing integrations often wire two (reset/power_down)
- * because that is the way other sensors work. There is no
- * way to tell how it is wired internally, so existing
- * firmwares expose both and we drive them symmetrically.
- */
- if (flag) {
- ret = dev->platform_data->gpio0_ctrl(sd, 1);
- usleep_range(10000, 15000);
- /* Ignore return from second gpio, it may not be there */
- dev->platform_data->gpio1_ctrl(sd, 1);
- usleep_range(10000, 15000);
+ if (width <= (OV2680_NATIVE_WIDTH / 2) &&
+ height <= (OV2680_NATIVE_HEIGHT / 2)) {
+ sensor->mode.binning = true;
+ width *= 2;
+ height *= 2;
} else {
- dev->platform_data->gpio1_ctrl(sd, 0);
- ret = dev->platform_data->gpio0_ctrl(sd, 0);
+ sensor->mode.binning = false;
}
- return ret;
+
+ sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1;
+ sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1;
+ sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1,
+ OV2680_NATIVE_WIDTH - 1);
+ sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1,
+ OV2680_NATIVE_HEIGHT - 1);
+ sensor->mode.h_output_size = orig_width;
+ sensor->mode.v_output_size = orig_height;
+ sensor->mode.hts = OV2680_PIXELS_PER_LINE;
+ sensor->mode.vts = OV2680_LINES_PER_FRAME;
}
-static int power_up(struct v4l2_subdev *sd)
+static int ov2680_set_mode(struct ov2680_device *sensor)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct i2c_client *client = sensor->client;
+ u8 pll_div, unknown, inc, fmt1, fmt2;
int ret;
- if (!dev->platform_data) {
- dev_err(&client->dev,
- "no camera_sensor_platform_data");
- return -ENODEV;
+ if (sensor->mode.binning) {
+ pll_div = 1;
+ unknown = 0x23;
+ inc = 0x31;
+ fmt1 = 0xc2;
+ fmt2 = 0x01;
+ } else {
+ pll_div = 0;
+ unknown = 0x21;
+ inc = 0x11;
+ fmt1 = 0xc0;
+ fmt2 = 0x00;
}
- if (dev->power_on)
- return 0; /* Already on */
-
- /* power control */
- ret = power_ctrl(sd, 1);
+ ret = ov_write_reg8(client, 0x3086, pll_div);
if (ret)
- goto fail_power;
-
- /* according to DS, at least 5ms is needed between DOVDD and PWDN */
- usleep_range(5000, 6000);
-
- /* gpio ctrl */
- ret = gpio_ctrl(sd, 1);
- if (ret) {
- ret = gpio_ctrl(sd, 1);
- if (ret)
- goto fail_power;
- }
+ return ret;
- /* flis clock control */
- ret = dev->platform_data->flisclk_ctrl(sd, 1);
+ ret = ov_write_reg8(client, 0x370a, unknown);
if (ret)
- goto fail_clk;
-
- /* according to DS, 20ms is needed between PWDN and i2c access */
- msleep(20);
+ return ret;
- ret = ov2680_init_registers(sd);
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_START_H, sensor->mode.h_start);
if (ret)
- goto fail_init_registers;
+ return ret;
- ret = __ov2680_set_exposure(sd, dev->exposure, dev->gain, dev->digitgain);
+ ret = ov_write_reg16(client, OV2680_VERTICAL_START_H, sensor->mode.v_start);
if (ret)
- goto fail_init_registers;
+ return ret;
- dev->power_on = true;
- return 0;
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_END_H, sensor->mode.h_end);
+ if (ret)
+ return ret;
-fail_init_registers:
- dev->platform_data->flisclk_ctrl(sd, 0);
-fail_clk:
- gpio_ctrl(sd, 0);
-fail_power:
- power_ctrl(sd, 0);
- dev_err(&client->dev, "sensor power-up failed\n");
+ ret = ov_write_reg16(client, OV2680_VERTICAL_END_H, sensor->mode.v_end);
+ if (ret)
+ return ret;
- return ret;
-}
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_OUTPUT_SIZE_H,
+ sensor->mode.h_output_size);
+ if (ret)
+ return ret;
-static int power_down(struct v4l2_subdev *sd)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
+ ret = ov_write_reg16(client, OV2680_VERTICAL_OUTPUT_SIZE_H,
+ sensor->mode.v_output_size);
+ if (ret)
+ return ret;
- h_flag = 0;
- v_flag = 0;
- if (!dev->platform_data) {
- dev_err(&client->dev,
- "no camera_sensor_platform_data");
- return -ENODEV;
- }
+ ret = ov_write_reg16(client, OV2680_HTS, sensor->mode.hts);
+ if (ret)
+ return ret;
- if (!dev->power_on)
- return 0; /* Already off */
+ ret = ov_write_reg16(client, OV2680_VTS, sensor->mode.vts);
+ if (ret)
+ return ret;
- ret = dev->platform_data->flisclk_ctrl(sd, 0);
+ ret = ov_write_reg16(client, OV2680_ISP_X_WIN, 0);
if (ret)
- dev_err(&client->dev, "flisclk failed\n");
+ return ret;
- /* gpio ctrl */
- ret = gpio_ctrl(sd, 0);
- if (ret) {
- ret = gpio_ctrl(sd, 0);
- if (ret)
- dev_err(&client->dev, "gpio failed 2\n");
- }
+ ret = ov_write_reg16(client, OV2680_ISP_Y_WIN, 0);
+ if (ret)
+ return ret;
- /* power control */
- ret = power_ctrl(sd, 0);
- if (ret) {
- dev_err(&client->dev, "vprog failed.\n");
+ ret = ov_write_reg8(client, OV2680_X_INC, inc);
+ if (ret)
return ret;
- }
- dev->power_on = false;
- return 0;
-}
+ ret = ov_write_reg8(client, OV2680_Y_INC, inc);
+ if (ret)
+ return ret;
-static int ov2680_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- int ret;
+ ret = ov_write_reg16(client, OV2680_X_WIN, sensor->mode.h_output_size);
+ if (ret)
+ return ret;
- mutex_lock(&dev->input_lock);
+ ret = ov_write_reg16(client, OV2680_Y_WIN, sensor->mode.v_output_size);
+ if (ret)
+ return ret;
- if (on == 0) {
- ret = power_down(sd);
- } else {
- ret = power_up(sd);
- }
+ ret = ov_write_reg8(client, OV2680_REG_FORMAT1, fmt1);
+ if (ret)
+ return ret;
- mutex_unlock(&dev->input_lock);
+ ret = ov_write_reg8(client, OV2680_REG_FORMAT2, fmt2);
+ if (ret)
+ return ret;
- return ret;
+ return 0;
}
static int ov2680_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 ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct camera_mipi_info *ov2680_info = NULL;
- struct ov2680_resolution *res;
- int vts, ret = 0;
-
- dev_dbg(&client->dev, "%s: %s: pad: %d, fmt: %p\n",
- __func__,
- (format->which == V4L2_SUBDEV_FORMAT_TRY) ? "try" : "set",
- format->pad, fmt);
-
- if (format->pad)
- return -EINVAL;
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ unsigned int width, height;
- if (!fmt)
- return -EINVAL;
+ width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH);
+ height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (!ov2680_info)
- return -EINVAL;
+ fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
+ ov2680_fill_format(sensor, fmt, width, height);
- res = v4l2_find_nearest_size(ov2680_res_preview,
- ARRAY_SIZE(ov2680_res_preview), width,
- height, fmt->width, fmt->height);
- if (!res)
- res = &ov2680_res_preview[N_RES_PREVIEW - 1];
+ format->format = *fmt;
- fmt->width = res->width;
- fmt->height = res->height;
-
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- }
-
- dev_dbg(&client->dev, "%s: %dx%d\n",
- __func__, fmt->width, fmt->height);
- mutex_lock(&dev->input_lock);
-
- /* s_power has not been called yet for std v4l2 clients (camorama) */
- power_up(sd);
- ret = ov2680_write_reg_array(client, dev->res->regs);
- if (ret) {
- dev_err(&client->dev,
- "ov2680 write resolution register err: %d\n", ret);
- goto err;
- }
-
- vts = dev->res->lines_per_frame;
-
- /* If necessary increase the VTS to match exposure + MARGIN */
- if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN)
- vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN;
-
- ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts);
- if (ret) {
- dev_err(&client->dev, "ov2680 write vts err: %d\n", ret);
- goto err;
- }
-
- ret = ov2680_get_intg_factor(client, ov2680_info, res);
- if (ret) {
- dev_err(&client->dev, "failed to get integration factor\n");
- goto err;
- }
-
- /*
- * recall flip functions to avoid flip registers
- * were overridden by default setting
- */
- if (h_flag)
- ov2680_h_flip(sd, h_flag);
- if (v_flag)
- ov2680_v_flip(sd, v_flag);
-
- dev->res = res;
-err:
- mutex_unlock(&dev->input_lock);
- return ret;
+ mutex_lock(&sensor->input_lock);
+ ov2680_calc_mode(sensor, fmt->width, fmt->height);
+ mutex_unlock(&sensor->input_lock);
+ return 0;
}
static int ov2680_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
- if (format->pad)
- return -EINVAL;
-
- if (!fmt)
- return -EINVAL;
-
- fmt->width = dev->res->width;
- fmt->height = dev->res->height;
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
+ format->format = *fmt;
return 0;
}
@@ -934,14 +380,12 @@ static int ov2680_detect(struct i2c_client *client)
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -ENODEV;
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_CHIP_ID_H, &high);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high);
if (ret) {
dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
return -ENODEV;
}
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_CHIP_ID_L, &low);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low);
id = ((((u16)high) << 8) | (u16)low);
if (id != OV2680_ID) {
@@ -949,8 +393,7 @@ static int ov2680_detect(struct i2c_client *client)
return -ENODEV;
}
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_SUB_ID, &high);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_SUB_ID, &high);
revision = (u8)high & 0x0f;
dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n",
@@ -961,88 +404,79 @@ static int ov2680_detect(struct i2c_client *client)
static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
+ int ret = 0;
+
+ mutex_lock(&sensor->input_lock);
+
+ if (sensor->is_streaming == enable) {
+ dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped");
+ goto error_unlock;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(sensor->sd.dev);
+ if (ret < 0)
+ goto error_unlock;
+
+ ret = ov2680_set_mode(sensor);
+ if (ret)
+ goto error_power_down;
- mutex_lock(&dev->input_lock);
- if (enable)
- dev_dbg(&client->dev, "ov2680_s_stream one\n");
- else
- dev_dbg(&client->dev, "ov2680_s_stream off\n");
+ /* Restore value of all ctrls */
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
+ if (ret)
+ goto error_power_down;
- ret = ov2680_write_reg(client, 1, OV2680_SW_STREAM,
- enable ? OV2680_START_STREAMING :
- OV2680_STOP_STREAMING);
+ ret = ov_write_reg8(client, OV2680_SW_STREAM, OV2680_START_STREAMING);
+ if (ret)
+ goto error_power_down;
+ } else {
+ ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING);
+ pm_runtime_put(sensor->sd.dev);
+ }
- //otp valid at stream on state
- //if(!dev->otp_data)
- // dev->otp_data = ov2680_otp_read(sd);
+ sensor->is_streaming = enable;
+ v4l2_ctrl_activate(sensor->ctrls.vflip, !enable);
+ v4l2_ctrl_activate(sensor->ctrls.hflip, !enable);
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&sensor->input_lock);
+ return 0;
+error_power_down:
+ pm_runtime_put(sensor->sd.dev);
+error_unlock:
+ mutex_unlock(&sensor->input_lock);
return ret;
}
-static int ov2680_s_config(struct v4l2_subdev *sd,
- int irq, void *platform_data)
+static int ov2680_s_config(struct v4l2_subdev *sd)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
-
- if (!platform_data)
- return -ENODEV;
-
- dev->platform_data =
- (struct camera_sensor_platform_data *)platform_data;
-
- mutex_lock(&dev->input_lock);
+ int ret;
- ret = power_up(sd);
- if (ret) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
dev_err(&client->dev, "ov2680 power-up err.\n");
goto fail_power_on;
}
- ret = dev->platform_data->csi_cfg(sd, 1);
- if (ret)
- goto fail_csi_cfg;
-
/* config & detect sensor */
ret = ov2680_detect(client);
- if (ret) {
+ if (ret)
dev_err(&client->dev, "ov2680_detect err s_config.\n");
- goto fail_csi_cfg;
- }
- /* turn off sensor, after probed */
- ret = power_down(sd);
- if (ret) {
- dev_err(&client->dev, "ov2680 power-off err.\n");
- goto fail_csi_cfg;
- }
- mutex_unlock(&dev->input_lock);
-
- return 0;
-
-fail_csi_cfg:
- dev->platform_data->csi_cfg(sd, 0);
fail_power_on:
- power_down(sd);
- dev_err(&client->dev, "sensor power-gating failed\n");
- mutex_unlock(&dev->input_lock);
+ pm_runtime_put(&client->dev);
return ret;
}
static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
interval->interval.numerator = 1;
- interval->interval.denominator = dev->res->fps;
-
+ interval->interval.denominator = OV2680_FPS;
return 0;
}
@@ -1050,7 +484,8 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index >= MAX_FMTS)
+ /* We support only a single format */
+ if (code->index)
return -EINVAL;
code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
@@ -1061,15 +496,25 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
+ static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = {
+ { 1616, 1216 },
+ { 1616, 1096 },
+ { 1616, 916 },
+ { 1456, 1096 },
+ { 1296, 976 },
+ { 1296, 736 },
+ { 784, 592 },
+ { 656, 496 },
+ };
int index = fse->index;
- if (index >= N_RES_PREVIEW)
+ if (index >= ARRAY_SIZE(ov2680_frame_sizes))
return -EINVAL;
- fse->min_width = ov2680_res_preview[index].width;
- fse->min_height = ov2680_res_preview[index].height;
- fse->max_width = ov2680_res_preview[index].width;
- fse->max_height = ov2680_res_preview[index].height;
+ fse->min_width = ov2680_frame_sizes[index].width;
+ fse->min_height = ov2680_frame_sizes[index].height;
+ fse->max_width = ov2680_frame_sizes[index].width;
+ fse->max_height = ov2680_frame_sizes[index].height;
return 0;
}
@@ -1078,30 +523,18 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
- struct v4l2_fract fract;
-
- if (fie->index >= N_RES_PREVIEW ||
- fie->width > ov2680_res_preview[0].width ||
- fie->height > ov2680_res_preview[0].height ||
- fie->which > V4L2_SUBDEV_FORMAT_ACTIVE)
+ /* Only 1 framerate */
+ if (fie->index)
return -EINVAL;
- fract.denominator = ov2680_res_preview[fie->index].fps;
- fract.numerator = 1;
-
- fie->interval = fract;
-
+ fie->interval.numerator = 1;
+ fie->interval.denominator = OV2680_FPS;
return 0;
}
static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
- mutex_lock(&dev->input_lock);
- *frames = dev->res->skip_frames;
- mutex_unlock(&dev->input_lock);
-
+ *frames = OV2680_SKIP_FRAMES;
return 0;
}
@@ -1114,11 +547,6 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = {
.g_skip_frames = ov2680_g_skip_frames,
};
-static const struct v4l2_subdev_core_ops ov2680_core_ops = {
- .s_power = ov2680_s_power,
- .ioctl = ov2680_ioctl,
-};
-
static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
.enum_mbus_code = ov2680_enum_mbus_code,
.enum_frame_size = ov2680_enum_frame_size,
@@ -1128,98 +556,173 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
};
static const struct v4l2_subdev_ops ov2680_ops = {
- .core = &ov2680_core_ops,
.video = &ov2680_video_ops,
.pad = &ov2680_pad_ops,
.sensor = &ov2680_sensor_ops,
};
+static int ov2680_init_controls(struct ov2680_device *sensor)
+{
+ static const char * const test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Random Data",
+ "Square",
+ "Black Image",
+ };
+ const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
+ struct ov2680_ctrls *ctrls = &sensor->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN;
+
+ v4l2_ctrl_handler_init(hdl, 4);
+
+ hdl->lock = &sensor->input_lock;
+
+ 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);
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+ 0, exp_max, 1, exp_max);
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250);
+ ctrls->test_pattern =
+ v4l2_ctrl_new_std_menu_items(hdl,
+ &ov2680_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ 0, 0, test_pattern_menu);
+
+ ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ if (hdl->error)
+ return hdl->error;
+
+ sensor->sd.ctrl_handler = hdl;
+ return 0;
+}
+
static void ov2680_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
dev_dbg(&client->dev, "ov2680_remove...\n");
- dev->platform_data->csi_cfg(sd, 0);
-
+ atomisp_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&dev->sd.entity);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- kfree(dev);
+ media_entity_cleanup(&sensor->sd.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+ pm_runtime_disable(&client->dev);
}
+/*
+ * Unlike other sensors which have both a rest and powerdown input pins,
+ * the OV2680 only has a powerdown input. But some ACPI tables still list
+ * 2 GPIOs for the OV2680 and it is unclear which to use. So try to get
+ * up to 2 GPIOs (1 mandatory, 1 optional) and control them in sync.
+ */
+static const struct acpi_gpio_params ov2680_first_gpio = { 0, 0, true };
+static const struct acpi_gpio_params ov2680_second_gpio = { 1, 0, true };
+
+static const struct acpi_gpio_mapping ov2680_gpio_mapping[] = {
+ { "powerdown-gpios", &ov2680_first_gpio, 1 },
+ { "powerdown-alt-gpios", &ov2680_second_gpio, 1 },
+ { },
+};
+
static int ov2680_probe(struct i2c_client *client)
{
- struct ov2680_device *dev;
+ struct device *dev = &client->dev;
+ struct ov2680_device *sensor;
int ret;
- void *pdata;
- unsigned int i;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
return -ENOMEM;
- mutex_init(&dev->input_lock);
+ mutex_init(&sensor->input_lock);
- dev->res = &ov2680_res_preview[0];
- dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN;
- dev->gain = 250; /* 0-2047 */
- v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops);
+ sensor->client = client;
+ v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops);
- pdata = gmin_camera_platform_data(&dev->sd,
- ATOMISP_INPUT_FORMAT_RAW_10,
- atomisp_bayer_order_bggr);
- if (!pdata) {
- ret = -EINVAL;
- goto out_free;
- }
-
- ret = ov2680_s_config(&dev->sd, client->irq, pdata);
+ ret = devm_acpi_dev_add_driver_gpios(&client->dev, ov2680_gpio_mapping);
if (ret)
- goto out_free;
+ return ret;
+
+ sensor->powerdown = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->powerdown))
+ return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n");
+
+ sensor->powerdown_alt = devm_gpiod_get_optional(dev, "powerdown-alt", GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->powerdown_alt))
+ return dev_err_probe(dev, PTR_ERR(sensor->powerdown_alt), "getting powerdown-alt GPIO\n");
- ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = ov2680_s_config(&sensor->sd);
if (ret)
- goto out_free;
-
- dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- dev->pad.flags = MEDIA_PAD_FL_SOURCE;
- dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret =
- v4l2_ctrl_handler_init(&dev->ctrl_handler,
- ARRAY_SIZE(ov2680_controls));
+ return ret;
+
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = ov2680_init_controls(sensor);
if (ret) {
ov2680_remove(client);
return ret;
}
- for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++)
- v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i],
- NULL);
-
- if (dev->ctrl_handler.error) {
+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+ if (ret) {
ov2680_remove(client);
- return dev->ctrl_handler.error;
+ return ret;
}
- /* Use same lock for controls as for everything else. */
- dev->ctrl_handler.lock = &dev->input_lock;
- dev->sd.ctrl_handler = &dev->ctrl_handler;
+ ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT);
- ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+ ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10,
+ atomisp_bayer_order_bggr);
if (ret) {
ov2680_remove(client);
- dev_dbg(&client->dev, "+++ remove ov2680\n");
+ return ret;
}
- return ret;
-out_free:
- dev_dbg(&client->dev, "+++ out free\n");
- v4l2_device_unregister_subdev(&dev->sd);
- kfree(dev);
- return ret;
+
+ return 0;
}
+static int ov2680_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+
+ gpiod_set_value_cansleep(sensor->powerdown, 1);
+ gpiod_set_value_cansleep(sensor->powerdown_alt, 1);
+ return 0;
+}
+
+static int ov2680_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+
+ /* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */
+ usleep_range(5000, 6000);
+
+ gpiod_set_value_cansleep(sensor->powerdown, 0);
+ gpiod_set_value_cansleep(sensor->powerdown_alt, 0);
+
+ /* according to DS, 20ms is needed between PWDN and i2c access */
+ msleep(20);
+
+ ov2680_init_registers(sd);
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL);
+
static const struct acpi_device_id ov2680_acpi_match[] = {
{"XXOV2680"},
{"OVTI2680"},
@@ -1230,6 +733,7 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
static struct i2c_driver ov2680_driver = {
.driver = {
.name = "ov2680",
+ .pm = pm_sleep_ptr(&ov2680_pm_ops),
.acpi_match_table = ov2680_acpi_match,
},
.probe_new = ov2680_probe,
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 887b6f99f6ca..5d2e6e2e72f0 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -261,134 +261,6 @@ static int ov2722_write_reg_array(struct i2c_client *client,
return __ov2722_flush_reg_array(client, &ctrl);
}
-static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) |
- (OV2722_F_NUMBER_DEM << 16) |
- (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov2722_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov2722_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov2722_device *dev = NULL;
- struct atomisp_sensor_mode_data *buf = &info->data;
- const unsigned int ext_clk_freq_hz = 19200000;
- const unsigned int pll_invariant_div = 10;
- unsigned int pix_clk_freq_hz;
- u16 pre_pll_clk_div;
- u16 pll_multiplier;
- u16 op_pix_clk_div;
- u16 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- dev = to_ov2722_sensor(sd);
-
- /* pixel clock calculattion */
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div);
- if (ret)
- return ret;
-
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier);
- if (ret)
- return ret;
-
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div);
- if (ret)
- return ret;
-
- pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4;
- if (!pre_pll_clk_div)
- return -EINVAL;
-
- pll_multiplier = pll_multiplier & 0x7f;
- op_pix_clk_div = op_pix_clk_div & 0x03;
- pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier
- * op_pix_clk_div / pll_invariant_div;
-
- dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV2722_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV2722_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_CROP_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_CROP_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -547,15 +419,6 @@ static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = ov2722_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov2722_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov2722_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_LINK_FREQ:
val = dev->res->mipi_freq;
if (val == 0)
@@ -588,39 +451,6 @@ static const struct v4l2_ctrl_config ov2722_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV2722_FOCAL_LENGTH_DEFAULT,
- .max = OV2722_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV2722_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV2722_F_NUMBER_DEFAULT,
- .max = OV2722_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV2722_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV2722_F_NUMBER_RANGE,
- .max = OV2722_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV2722_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_LINK_FREQ,
.name = "Link Frequency",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -682,10 +512,7 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
* before PWDN# when turning it on or off.
*/
ret = dev->platform_data->gpio0_ctrl(sd, flag);
- /*
- *ov2722 PWDN# active high when pull down,opposite to the convention
- */
- ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
+ ret |= dev->platform_data->gpio1_ctrl(sd, flag);
return ret;
}
@@ -701,6 +528,9 @@ static int power_up(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (dev->power_on == 1)
+ return 0; /* Already on */
+
/* power control */
ret = power_ctrl(sd, 1);
if (ret)
@@ -725,6 +555,7 @@ static int power_up(struct v4l2_subdev *sd)
/* according to DS, 20ms is needed between PWDN and i2c access */
msleep(20);
+ dev->power_on = 1;
return 0;
fail_clk:
@@ -748,6 +579,9 @@ static int power_down(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (dev->power_on == 0)
+ return 0; /* Already off */
+
ret = dev->platform_data->flisclk_ctrl(sd, 0);
if (ret)
dev_err(&client->dev, "flisclk failed\n");
@@ -765,6 +599,7 @@ static int power_down(struct v4l2_subdev *sd)
if (ret)
dev_err(&client->dev, "vprog failed.\n");
+ dev->power_on = 0;
return ret;
}
@@ -824,7 +659,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
if (!ov2722_info)
return -EINVAL;
- mutex_lock(&dev->input_lock);
res = v4l2_find_nearest_size(ov2722_res_preview,
ARRAY_SIZE(ov2722_res_preview), width,
height, fmt->width, fmt->height);
@@ -838,10 +672,13 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
sd_state->pads->try_fmt = *fmt;
- mutex_unlock(&dev->input_lock);
return 0;
}
+ mutex_lock(&dev->input_lock);
+
+ /* s_power has not been called yet for std v4l2 clients (camorama) */
+ power_up(sd);
dev->pixels_per_line = dev->res->pixels_per_line;
dev->lines_per_frame = dev->res->lines_per_frame;
@@ -875,10 +712,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
}
}
- ret = ov2722_get_intg_factor(client, ov2722_info, dev->res);
- if (ret)
- dev_err(&client->dev, "failed to get integration_factor\n");
-
err:
mutex_unlock(&dev->input_lock);
return ret;
@@ -1137,6 +970,7 @@ static int ov2722_probe(struct i2c_client *client)
return -ENOMEM;
mutex_init(&dev->input_lock);
+ dev->power_on = -1;
dev->res = &ov2722_res_preview[0];
v4l2_i2c_subdev_init(&dev->sd, client, &ov2722_ops);
@@ -1168,6 +1002,7 @@ out_ctrl_handler_free:
v4l2_ctrl_handler_free(&dev->ctrl_handler);
out_free:
+ atomisp_gmin_remove_subdev(&dev->sd);
v4l2_device_unregister_subdev(&dev->sd);
kfree(dev);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h
index 4b9ce681bd93..cae480ae6fba 100644
--- a/drivers/staging/media/atomisp/i2c/gc0310.h
+++ b/drivers/staging/media/atomisp/i2c/gc0310.h
@@ -38,9 +38,6 @@
#define I2C_RETRY_COUNT 5
#define GC0310_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define GC0310_FOCAL_LENGTH_DEM 100
-#define GC0310_F_NUMBER_DEFAULT_NUM 26
-#define GC0310_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -126,9 +123,6 @@ struct gc0310_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -149,7 +143,6 @@ struct gc0310_device {
struct v4l2_ctrl_handler ctrl_handler;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
struct gc0310_resolution *res;
u8 type;
bool power_on;
@@ -390,9 +383,6 @@ static struct gc0310_resolution gc0310_res_preview[] = {
.pixels_per_line = 0x0314,
.lines_per_frame = 0x0213,
#endif
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 2,
.regs = gc0310_VGA_30fps,
},
diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h
index 806be5dff7a5..55ea422291ba 100644
--- a/drivers/staging/media/atomisp/i2c/gc2235.h
+++ b/drivers/staging/media/atomisp/i2c/gc2235.h
@@ -44,9 +44,6 @@
#define I2C_RETRY_COUNT 5
#define GC2235_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define GC2235_FOCAL_LENGTH_DEM 100
-#define GC2235_F_NUMBER_DEFAULT_NUM 26
-#define GC2235_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -137,9 +134,6 @@ struct gc2235_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -161,7 +155,6 @@ struct gc2235_device {
struct gc2235_resolution *res;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
u8 type;
};
@@ -540,9 +533,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1068,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1600_900_30fps,
},
@@ -556,9 +546,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1082_30fps,
},
@@ -571,9 +558,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1216_30fps,
},
@@ -597,9 +581,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1068,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1600_900_30fps,
},
@@ -612,9 +593,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1082_30fps,
},
@@ -627,9 +605,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1216_30fps,
},
@@ -648,9 +623,6 @@ static struct gc2235_resolution gc2235_res_video[] = {
.used = 0,
.pixels_per_line = 1828,
.lines_per_frame = 888,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1296_736_30fps,
},
@@ -663,9 +635,6 @@ static struct gc2235_resolution gc2235_res_video[] = {
.used = 0,
.pixels_per_line = 1492,
.lines_per_frame = 792,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_960_640_30fps,
},
diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h
index bcce18b65fa6..b0cd1b724394 100644
--- a/drivers/staging/media/atomisp/i2c/mt9m114.h
+++ b/drivers/staging/media/atomisp/i2c/mt9m114.h
@@ -136,9 +136,6 @@
#define MT9M114_BPAT_BGBGGRGR BIT(3)
#define MT9M114_FOCAL_LENGTH_NUM 208 /*2.08mm*/
-#define MT9M114_FOCAL_LENGTH_DEM 100
-#define MT9M114_F_NUMBER_DEFAULT_NUM 24
-#define MT9M114_F_NUMBER_DEM 10
#define MT9M114_WAIT_STAT_TIMEOUT 100
#define MT9M114_FLICKER_MODE_50HZ 1
#define MT9M114_FLICKER_MODE_60HZ 2
@@ -319,9 +316,6 @@ struct mt9m114_res_struct {
struct regval_list *regs;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
};
/* 2 bytes used for address: 256 bytes total */
@@ -353,9 +347,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0640,
.lines_per_frame = 0x0307,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
{
.desc = "848P",
@@ -369,9 +360,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0640,
.lines_per_frame = 0x03E8,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
{
.desc = "960P",
@@ -385,9 +373,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0644, /* consistent with regs arrays */
.lines_per_frame = 0x03E5, /* consistent with regs arrays */
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
};
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index 7ab337b859ad..a37af0a74a53 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -32,53 +32,22 @@
#include "../include/linux/atomisp_platform.h"
-/* Defines for register writes and register array processing */
-#define I2C_MSG_LENGTH 0x2
-#define I2C_RETRY_COUNT 5
+#define OV2680_NATIVE_WIDTH 1616
+#define OV2680_NATIVE_HEIGHT 1216
-#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/
-#define OV2680_FOCAL_LENGTH_DEM 100
-#define OV2680_F_NUMBER_DEFAULT_NUM 24
-#define OV2680_F_NUMBER_DEM 10
+/* 1704 * 1294 * 30fps = 66MHz pixel clock */
+#define OV2680_PIXELS_PER_LINE 1704
+#define OV2680_LINES_PER_FRAME 1294
+#define OV2680_FPS 30
+#define OV2680_SKIP_FRAMES 3
-#define OV2680_BIN_FACTOR_MAX 4
+/* If possible send 16 extra rows / lines to the ISP as padding */
+#define OV2680_END_MARGIN 16
-#define MAX_FMTS 1
+#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/
-/* sensor_mode_data read_mode adaptation */
-#define OV2680_READ_MODE_BINNING_ON 0x0400
-#define OV2680_READ_MODE_BINNING_OFF 0x00
-#define OV2680_INTEGRATION_TIME_MARGIN 8
-
-#define OV2680_MAX_EXPOSURE_VALUE 0xFFF1
-#define OV2680_MAX_GAIN_VALUE 0xFF
-
-/*
- * focal length bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV2680_FOCAL_LENGTH_DEFAULT 0x1B70064
-
-/*
- * current f-number bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV2680_F_NUMBER_DEFAULT 0x18000a
-
-/*
- * f-number range bits definition:
- * bits 31-24: max f-number numerator
- * bits 23-16: max f-number denominator
- * bits 15-8: min f-number numerator
- * bits 7-0: min f-number denominator
- */
-#define OV2680_F_NUMBER_RANGE 0x180a180a
-#define OV2680_ID 0x2680
-
-#define OV2680_FINE_INTG_TIME_MIN 0
-#define OV2680_FINE_INTG_TIME_MAX_MARGIN 0
-#define OV2680_COARSE_INTG_TIME_MIN 1
-#define OV2680_COARSE_INTG_TIME_MAX_MARGIN 6
+#define OV2680_INTEGRATION_TIME_MARGIN 8
+#define OV2680_ID 0x2680
/*
* OV2680 System control registers
@@ -92,74 +61,49 @@
#define OV2680_SC_CMMN_SCCB_ID 0x302B /* 0x300C*/
#define OV2680_SC_CMMN_SUB_ID 0x302A /* process, version*/
-#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/
-
-#define OV2680_EXPOSURE_H 0x3500 /*Bit[3:0] Bit[19:16] of exposure, remaining 16 bits lies in Reg0x3501&Reg0x3502*/
-#define OV2680_EXPOSURE_M 0x3501
-#define OV2680_EXPOSURE_L 0x3502
-#define OV2680_AGC_H 0x350A /*Bit[1:0] means Bit[9:8] of gain*/
-#define OV2680_AGC_L 0x350B /*Bit[7:0] of gain*/
-
-#define OV2680_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/
-#define OV2680_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/
-#define OV2680_VERTICAL_START_H 0x3802 /*Bit[11:8]*/
-#define OV2680_VERTICAL_START_L 0x3803 /*Bit[7:0]*/
-#define OV2680_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/
-#define OV2680_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/
-#define OV2680_VERTICAL_END_H 0x3806 /*Bit[11:8]*/
-#define OV2680_VERTICAL_END_L 0x3807 /*Bit[7:0]*/
-#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/
-#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/
-#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/
-#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/
-#define OV2680_TIMING_HTS_H 0x380C /*High 8-bit, and low 8-bit HTS address is 0x380d*/
-#define OV2680_TIMING_HTS_L 0x380D /*High 8-bit, and low 8-bit HTS address is 0x380d*/
-#define OV2680_TIMING_VTS_H 0x380e /*High 8-bit, and low 8-bit HTS address is 0x380f*/
-#define OV2680_TIMING_VTS_L 0x380f /*High 8-bit, and low 8-bit HTS address is 0x380f*/
-#define OV2680_FRAME_OFF_NUM 0x4202
+#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/
+
+#define OV2680_REG_EXPOSURE_PK_HIGH 0x3500
+#define OV2680_REG_GAIN_PK 0x350a
+
+#define OV2680_HORIZONTAL_START_H 0x3800 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_START_L 0x3801 /* Bit[7:0] */
+#define OV2680_VERTICAL_START_H 0x3802 /* Bit[11:8] */
+#define OV2680_VERTICAL_START_L 0x3803 /* Bit[7:0] */
+#define OV2680_HORIZONTAL_END_H 0x3804 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_END_L 0x3805 /* Bit[7:0] */
+#define OV2680_VERTICAL_END_H 0x3806 /* Bit[11:8] */
+#define OV2680_VERTICAL_END_L 0x3807 /* Bit[7:0] */
+#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /* Bit[7:0] */
+#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /* Bit[11:8] */
+#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /* Bit[7:0] */
+#define OV2680_HTS 0x380c
+#define OV2680_VTS 0x380e
+#define OV2680_ISP_X_WIN 0x3810
+#define OV2680_ISP_Y_WIN 0x3812
+#define OV2680_X_INC 0x3814
+#define OV2680_Y_INC 0x3815
+
+#define OV2680_FRAME_OFF_NUM 0x4202
/*Flip/Mirror*/
-#define OV2680_FLIP_REG 0x3820
-#define OV2680_MIRROR_REG 0x3821
-#define OV2680_FLIP_BIT 1
-#define OV2680_MIRROR_BIT 2
-#define OV2680_FLIP_MIRROR_BIT_ENABLE 4
+#define OV2680_REG_FORMAT1 0x3820
+#define OV2680_REG_FORMAT2 0x3821
#define OV2680_MWB_RED_GAIN_H 0x5004/*0x3400*/
#define OV2680_MWB_GREEN_GAIN_H 0x5006/*0x3402*/
#define OV2680_MWB_BLUE_GAIN_H 0x5008/*0x3404*/
-#define OV2680_MWB_GAIN_MAX 0x0fff
-
-#define OV2680_START_STREAMING 0x01
-#define OV2680_STOP_STREAMING 0x00
-
-#define OV2680_INVALID_CONFIG 0xffffffff
+#define OV2680_MWB_GAIN_MAX 0x0fff
-struct regval_list {
- u16 reg_num;
- u8 value;
-};
+#define OV2680_REG_ISP_CTRL00 0x5080
-struct ov2680_resolution {
- const struct ov2680_reg *regs;
- int res;
- int width;
- int height;
- int fps;
- int pix_clk_freq;
- u32 skip_frames;
- u16 pixels_per_line;
- u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
-};
+#define OV2680_X_WIN 0x5704
+#define OV2680_Y_WIN 0x5706
+#define OV2680_WIN_CONTROL 0x5708
-struct ov2680_format {
- u8 *desc;
- u32 pixelformat;
- struct ov2680_reg *regs;
-};
+#define OV2680_START_STREAMING 0x01
+#define OV2680_STOP_STREAMING 0x00
/*
* ov2680 device structure.
@@ -168,13 +112,32 @@ struct ov2680_device {
struct v4l2_subdev sd;
struct media_pad pad;
struct mutex input_lock;
- struct v4l2_ctrl_handler ctrl_handler;
- struct ov2680_resolution *res;
- struct camera_sensor_platform_data *platform_data;
- bool power_on;
- u16 exposure;
- u16 gain;
- u16 digitgain;
+ struct i2c_client *client;
+ struct gpio_desc *powerdown;
+ struct gpio_desc *powerdown_alt;
+ bool is_streaming;
+
+ struct ov2680_mode {
+ struct v4l2_mbus_framefmt fmt;
+ bool binning;
+ u16 h_start;
+ u16 v_start;
+ u16 h_end;
+ u16 v_end;
+ u16 h_output_size;
+ u16 v_output_size;
+ u16 hts;
+ u16 vts;
+ } mode;
+
+ struct ov2680_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *test_pattern;
+ } ctrls;
};
/**
@@ -192,17 +155,13 @@ struct ov2680_reg {
#define to_ov2680_sensor(x) container_of(x, struct ov2680_device, sd)
-#define OV2680_MAX_WRITE_BUF_SIZE 30
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ struct ov2680_device *sensor =
+ container_of(ctrl->handler, struct ov2680_device, ctrls.handler);
-struct ov2680_write_buffer {
- u16 addr;
- u8 data[OV2680_MAX_WRITE_BUF_SIZE];
-};
-
-struct ov2680_write_ctrl {
- int index;
- struct ov2680_write_buffer buffer;
-};
+ return &sensor->sd;
+}
static struct ov2680_reg const ov2680_global_setting[] = {
{0x0103, 0x01},
@@ -240,6 +199,8 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x3819, 0x04},
{0x4000, 0x81},
{0x4001, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x03},
{0x4602, 0x02},
{0x481f, 0x36},
{0x4825, 0x36},
@@ -252,6 +213,8 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x5008, 0x04},
{0x5009, 0x00},
{0x5080, 0x00},
+ {0x5081, 0x41},
+ {0x5708, 0x01}, /* add for full size flip off and mirror off 2014/09/11 */
{0x3701, 0x64}, //add on 14/05/13
{0x3784, 0x0c}, //based OV2680_R1A_AM10.ovt add on 14/06/13
{0x5780, 0x3e}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
@@ -276,642 +239,7 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x5793, 0x00},
{0x5794, 0x03}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
{0x0100, 0x00}, //stream off
-
- {}
-};
-
-/*
- * 176x144 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_QCIF_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x05},
- {0x3805, 0xaf},
- {0x3806, 0x04},
- {0x3807, 0x47},
- {0x3808, 0x00},
- {0x3809, 0xC0},
- {0x380a, 0x00},
- {0x380b, 0xa0},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4000, 0x81},
- {0x4001, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 352x288 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_CIF_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x03},
- {0x3805, 0x8f},
- {0x3806, 0x02},
- {0x3807, 0xe7},
- {0x3808, 0x01},
- {0x3809, 0x70},
- {0x380a, 0x01},
- {0x380b, 0x30},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
{}
};
-/*
- * 336x256 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_QVGA_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x03},
- {0x3805, 0x4f},
- {0x3806, 0x02},
- {0x3807, 0x87},
- {0x3808, 0x01},
- {0x3809, 0x50},
- {0x380a, 0x01},
- {0x380b, 0x00},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 656x496 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_656x496_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x05},
- {0x3805, 0xcf},
- {0x3806, 0x04},
- {0x3807, 0x67},
- {0x3808, 0x02},
- {0x3809, 0x90},
- {0x380a, 0x01},
- {0x380b, 0xf0},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 720x592 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_720x592_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0x00}, // X_ADDR_START;
- {0x3802, 0x00},
- {0x3803, 0x00}, // Y_ADDR_START;
- {0x3804, 0x05},
- {0x3805, 0xaf}, // X_ADDR_END;
- {0x3806, 0x04},
- {0x3807, 0xaf}, // Y_ADDR_END;
- {0x3808, 0x02},
- {0x3809, 0xd0}, // X_OUTPUT_SIZE;
- {0x380a, 0x02},
- {0x380b, 0x50}, // Y_OUTPUT_SIZE;
- {0x380c, 0x06},
- {0x380d, 0xac}, // HTS;
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5708, 0x00},
- {0x5704, 0x02},
- {0x5705, 0xd0}, // X_WIN;
- {0x5706, 0x02},
- {0x5707, 0x50}, // Y_WIN;
- {0x3820, 0xc2}, // FLIP_FORMAT;
- {0x3821, 0x01}, // MIRROR_FORMAT;
- {0x5090, 0x00}, // PRE ISP CTRL16, default value is 0x0C;
- // BIT[3]: Mirror order, BG or GB;
- // BIT[2]: Flip order, BR or RB;
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 800x600 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_800x600_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0x00}, /* hstart 0 */
- {0x3802, 0x00},
- {0x3803, 0x00}, /* vstart 0 */
- {0x3804, 0x06},
- {0x3805, 0x4f}, /* hend 1615 */
- {0x3806, 0x04},
- {0x3807, 0xbf}, /* vend 1215 */
- {0x3808, 0x03},
- {0x3809, 0x20}, /* hsize 800 */
- {0x380a, 0x02},
- {0x380b, 0x58}, /* vsize 600 */
- {0x380c, 0x06},
- {0x380d, 0xac}, /* htotal 1708 */
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x5708, 0x00},
- {0x5704, 0x03},
- {0x5705, 0x20},
- {0x5706, 0x02},
- {0x5707, 0x58},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- {0x5090, 0x00},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 720p=1280*720 30fps VBlanking 1lane 10Bit (no-Scaling)
- */
-static struct ov2680_reg const ov2680_720p_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0xa0}, /* hstart 160 */
- {0x3802, 0x00},
- {0x3803, 0xf2}, /* vstart 242 */
- {0x3804, 0x05},
- {0x3805, 0xbf}, /* hend 1471 */
- {0x3806, 0x03},
- {0x3807, 0xdd}, /* vend 989 */
- {0x3808, 0x05},
- {0x3809, 0x10}, /* hsize 1296 */
- {0x380a, 0x02},
- {0x380b, 0xe0}, /* vsize 736 */
- {0x380c, 0x06},
- {0x380d, 0xa8}, /* htotal 1704 */
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x06},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 1296x976 30fps VBlanking 1lane 10Bit(no-scaling)
- */
-static struct ov2680_reg const ov2680_1296x976_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0xa0}, /* hstart 160 */
- {0x3802, 0x00},
- {0x3803, 0x78}, /* vstart 120 */
- {0x3804, 0x05},
- {0x3805, 0xbf}, /* hend 1471 */
- {0x3806, 0x04},
- {0x3807, 0x57}, /* vend 1111 */
- {0x3808, 0x05},
- {0x3809, 0x10}, /* hsize 1296 */
- {0x380a, 0x03},
- {0x380b, 0xd0}, /* vsize 976 */
- {0x380c, 0x06},
- {0x380d, 0xa8}, /* htotal 1704 */
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x08},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00}, //mirror/flip
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 1456*1096 30fps VBlanking 1lane 10bit(no-scaling)
- */
-static struct ov2680_reg const ov2680_1456x1096_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x90},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xC0},
- {0x3808, 0x05},
- {0x3809, 0xb0},
- {0x380a, 0x04},
- {0x380b, 0x48},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- *1616x916 30fps VBlanking 1lane 10bit
- */
-
-static struct ov2680_reg const ov2680_1616x916_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x96},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0x39},
- {0x3808, 0x06},
- {0x3809, 0x50},
- {0x380a, 0x03},
- {0x380b, 0x94},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x08},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x03},
- {0x5707, 0x94},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {}
-};
-
-/*
- * 1616x1082 30fps VBlanking 1lane 10Bit
- */
-static struct ov2680_reg const ov2680_1616x1082_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x86},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xbf},
- {0x3808, 0x06},
- {0x3809, 0x50},
- {0x380a, 0x04},
- {0x380b, 0x3a},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x04},
- {0x5707, 0x3a},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 1616x1216 30fps VBlanking 1lane 10Bit
- */
-static struct ov2680_reg const ov2680_1616x1216_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x00},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xbf},
- {0x3808, 0x06},
- {0x3809, 0x50},//50},//4line for mirror and flip
- {0x380a, 0x04},
- {0x380b, 0xc0},//c0},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x00},
- {0x4009, 0x0b},
- {0x5081, 0x01},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x04},
- {0x5707, 0xcc},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {}
-};
-
-static struct ov2680_resolution ov2680_res_preview[] = {
- {
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 66,
- .fps = 30,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1216_30fps,
- },
- {
- .width = 1616,
- .height = 1082,
- .pix_clk_freq = 66,
- .fps = 30,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1082_30fps,
- },
- {
- .width = 1616,
- .height = 916,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x916_30fps,
- },
- {
- .width = 1456,
- .height = 1096,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1456x1096_30fps,
- },
- {
- .width = 1296,
- .height = 976,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1296x976_30fps,
- },
- {
- .width = 1296,
- .height = 736,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_720p_30fps,
- },
- {
- .width = 800,
- .height = 600,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_800x600_30fps,
- },
- {
- .width = 720,
- .height = 592,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_720x592_30fps,
- },
- {
- .width = 656,
- .height = 496,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_656x496_30fps,
- },
- {
- .width = 336,
- .height = 256,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_QVGA_30fps,
- },
- {
- .width = 352,
- .height = 288,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_CIF_30fps,
- },
- {
- .width = 176,
- .height = 144,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_QCIF_30fps,
- },
-};
-
-#define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview))
-
#endif
diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h
index d6e2510bc01c..640d3ffcaa5c 100644
--- a/drivers/staging/media/atomisp/i2c/ov2722.h
+++ b/drivers/staging/media/atomisp/i2c/ov2722.h
@@ -39,9 +39,6 @@
#define I2C_RETRY_COUNT 5
#define OV2722_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define OV2722_FOCAL_LENGTH_DEM 100
-#define OV2722_F_NUMBER_DEFAULT_NUM 26
-#define OV2722_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -180,9 +177,6 @@ struct ov2722_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
int mipi_freq;
};
@@ -204,8 +198,7 @@ struct ov2722_device {
struct ov2722_resolution *res;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
- int run_mode;
+ int power_on;
u16 pixels_per_line;
u16 lines_per_frame;
u8 type;
@@ -1113,9 +1106,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1632_1092_30fps,
.mipi_freq = 422400,
@@ -1129,9 +1119,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1452_1092_30fps,
.mipi_freq = 422400,
@@ -1145,9 +1132,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
@@ -1171,9 +1155,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1632_1092_30fps,
.mipi_freq = 422400,
@@ -1187,9 +1168,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1452_1092_30fps,
.mipi_freq = 422400,
@@ -1203,9 +1181,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
@@ -1224,9 +1199,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2048,
.lines_per_frame = 1184,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_QVGA_30fps,
.mipi_freq = 364800,
@@ -1240,9 +1212,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2048,
.lines_per_frame = 1184,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_480P_30fps,
},
@@ -1255,9 +1224,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
index c1cd631455e6..da8c3b1d3bcd 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
+++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
@@ -415,123 +415,6 @@ static int ov5693_write_reg_array(struct i2c_client *client,
return __ov5693_flush_reg_array(client, &ctrl);
}
-static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
- (OV5693_F_NUMBER_DEM << 16) |
- (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
-
- *val = ov5693_res[dev->fmt_idx].bin_factor_x;
-
- return 0;
-}
-
-static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
-
- *val = ov5693_res[dev->fmt_idx].bin_factor_y;
-
- return 0;
-}
-
-static int ov5693_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov5693_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov5693_device *dev = to_ov5693_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- unsigned int pix_clk_freq_hz;
- u16 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock */
- pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
- dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV5693_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV5693_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -1107,27 +990,12 @@ static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov5693_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_FOCUS_ABSOLUTE:
ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
break;
case V4L2_CID_FOCUS_STATUS:
ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -1154,39 +1022,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV5693_FOCAL_LENGTH_DEFAULT,
- .max = OV5693_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV5693_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV5693_F_NUMBER_DEFAULT,
- .max = OV5693_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV5693_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV5693_F_NUMBER_RANGE,
- .max = OV5693_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV5693_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_FOCUS_ABSOLUTE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "focus move absolute",
@@ -1240,28 +1075,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = {
.def = 0,
.flags = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = OV5693_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = OV5693_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
};
static int ov5693_init(struct v4l2_subdev *sd)
@@ -1659,18 +1472,10 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
if (ret)
dev_warn(&client->dev, "ov5693 stream off err\n");
- ret = ov5693_get_intg_factor(client, ov5693_info,
- &ov5693_res[dev->fmt_idx]);
- if (ret) {
- dev_err(&client->dev, "failed to get integration_factor\n");
- goto err;
- }
-
ov5693_info->metadata_width = fmt->width * 10 / 8;
ov5693_info->metadata_height = 1;
ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size;
-err:
mutex_unlock(&dev->input_lock);
return ret;
}
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
index a1366666f49c..5e17eaf8fd6e 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
+++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
@@ -198,9 +198,6 @@ struct ov5693_resolution {
int pix_clk_freq;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -228,7 +225,6 @@ struct ov5693_device {
struct camera_sensor_platform_data *platform_data;
ktime_t timestamp_t_focus_abs;
- int vt_pix_clk_freq_mhz;
int fmt_idx;
int run_mode;
int otp_size;
@@ -1110,9 +1106,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_736x496_30fps,
},
{
@@ -1124,9 +1117,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1616x1216_30fps,
},
{
@@ -1138,9 +1128,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2576x1456_30fps,
},
{
@@ -1152,9 +1139,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2576x1936_30fps,
},
};
@@ -1176,9 +1160,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_736x496_30fps,
},
{
@@ -1190,9 +1171,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1424x1168_30fps,
},
{
@@ -1204,9 +1182,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1616x1216_30fps,
},
{
@@ -1218,9 +1193,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1456_30fps,
},
{
@@ -1232,9 +1204,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1944_30fps,
},
};
@@ -1251,9 +1220,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_736x496,
},
{
@@ -1265,9 +1231,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_336x256,
},
{
@@ -1279,9 +1242,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_368x304,
},
{
@@ -1293,9 +1253,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_192x160,
},
{
@@ -1307,9 +1264,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 0,
.regs = ov5693_1296x736,
},
{
@@ -1321,9 +1275,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 0,
.regs = ov5693_1296x976,
},
{
@@ -1335,9 +1286,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1636p_30fps,
},
{
@@ -1349,9 +1297,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1940x1096,
},
{
@@ -1363,9 +1308,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1456_30fps,
},
{
@@ -1377,9 +1319,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1944_30fps,
},
};
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h
index 3f602b5aaff9..63b1bcd35399 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp.h
@@ -586,20 +586,6 @@ struct atomisp_shading_table {
__u16 *data[ATOMISP_NUM_SC_COLORS];
};
-struct atomisp_makernote_info {
- /* bits 31-16: numerator, bits 15-0: denominator */
- unsigned int focal_length;
- /* bits 31-16: numerator, bits 15-0: denominator*/
- unsigned int f_number_curr;
- /*
- * bits 31-24: max f-number numerator
- * bits 23-16: max f-number denominator
- * bits 15-8: min f-number numerator
- * bits 7-0: min f-number denominator
- */
- unsigned int f_number_range;
-};
-
/* parameter for MACC */
#define ATOMISP_NUM_MACC_AXES 16
struct atomisp_macc_table {
@@ -650,28 +636,6 @@ struct atomisp_overlay {
unsigned int overlay_start_y;
};
-/* Sensor resolution specific data for AE calculation.*/
-struct atomisp_sensor_mode_data {
- unsigned int coarse_integration_time_min;
- unsigned int coarse_integration_time_max_margin;
- unsigned int fine_integration_time_min;
- unsigned int fine_integration_time_max_margin;
- unsigned int fine_integration_time_def;
- unsigned int frame_length_lines;
- unsigned int line_length_pck;
- unsigned int read_mode;
- unsigned int vt_pix_clk_freq_mhz;
- unsigned int crop_horizontal_start; /* Sensor crop start cord. (x0,y0)*/
- unsigned int crop_vertical_start;
- unsigned int crop_horizontal_end; /* Sensor crop end cord. (x1,y1)*/
- unsigned int crop_vertical_end;
- unsigned int output_width; /* input size to ISP after binning/scaling */
- unsigned int output_height;
- u8 binning_factor_x; /* horizontal binning factor used */
- u8 binning_factor_y; /* vertical binning factor used */
- u16 hts;
-};
-
struct atomisp_exposure {
unsigned int integration_time[8];
unsigned int shutter_speed[8];
@@ -914,8 +878,6 @@ struct atomisp_sensor_ae_bracketing_lut {
_IOR('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table)
#define ATOMISP_IOC_S_ISP_GDC_TAB \
_IOW('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table)
-#define ATOMISP_IOC_ISP_MAKERNOTE \
- _IOWR('v', BASE_VIDIOC_PRIVATE + 11, struct atomisp_makernote_info)
/* macc parameter control*/
#define ATOMISP_IOC_G_ISP_MACC \
@@ -961,10 +923,6 @@ struct atomisp_sensor_ae_bracketing_lut {
#define ATOMISP_IOC_CAMERA_BRIDGE \
_IOWR('v', BASE_VIDIOC_PRIVATE + 19, struct atomisp_bc_video_package)
-/* Sensor resolution specific info for AE */
-#define ATOMISP_IOC_G_SENSOR_MODE_DATA \
- _IOR('v', BASE_VIDIOC_PRIVATE + 20, struct atomisp_sensor_mode_data)
-
#define ATOMISP_IOC_S_EXPOSURE \
_IOW('v', BASE_VIDIOC_PRIVATE + 21, struct atomisp_exposure)
@@ -1093,10 +1051,6 @@ struct atomisp_sensor_ae_bracketing_lut {
* Exposure, Flash and privacy (indicator) light controls, to be upstreamed */
#define V4L2_CID_CAMERA_LASTP1 (V4L2_CID_CAMERA_CLASS_BASE + 1024)
-#define V4L2_CID_FOCAL_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 0)
-#define V4L2_CID_FNUMBER_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 1)
-#define V4L2_CID_FNUMBER_RANGE (V4L2_CID_CAMERA_LASTP1 + 2)
-
/* Flash related CIDs, see also:
* http://linuxtv.org/downloads/v4l-dvb-apis/extended-controls.html\
* #flash-controls */
@@ -1117,10 +1071,6 @@ struct atomisp_sensor_ae_bracketing_lut {
/* Query Focus Status */
#define V4L2_CID_FOCUS_STATUS (V4L2_CID_CAMERA_LASTP1 + 14)
-/* Query sensor's binning factor */
-#define V4L2_CID_BIN_FACTOR_HORZ (V4L2_CID_CAMERA_LASTP1 + 15)
-#define V4L2_CID_BIN_FACTOR_VERT (V4L2_CID_CAMERA_LASTP1 + 16)
-
/* number of frames to skip at stream start */
#define V4L2_CID_G_SKIP_FRAMES (V4L2_CID_CAMERA_LASTP1 + 17)
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
index 5463d11d4295..64bd54835c32 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
@@ -21,8 +21,6 @@
int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
struct camera_sensor_platform_data *plat_data,
enum intel_v4l2_subdev_type type);
-struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter,
- struct i2c_board_info *board_info);
int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd);
int gmin_get_var_int(struct device *dev, bool is_gmin,
const char *var, int def);
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
index 0253661d4332..539b21d39d3b 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
@@ -125,13 +125,7 @@ struct intel_v4l2_subdev_id {
enum atomisp_camera_port port;
};
-struct intel_v4l2_subdev_i2c_board_info {
- struct i2c_board_info board_info;
- int i2c_adapter_id;
-};
-
struct intel_v4l2_subdev_table {
- struct intel_v4l2_subdev_i2c_board_info v4l2_subdev;
enum intel_v4l2_subdev_type type;
enum atomisp_camera_port port;
struct v4l2_subdev *subdev;
@@ -210,7 +204,6 @@ struct camera_mipi_info {
unsigned int num_lanes;
enum atomisp_input_format input_format;
enum atomisp_bayer_order raw_bayer_order;
- struct atomisp_sensor_mode_data data;
enum atomisp_input_format metadata_format;
u32 metadata_width;
u32 metadata_height;
@@ -218,6 +211,10 @@ struct camera_mipi_info {
};
const struct atomisp_platform_data *atomisp_get_platform_data(void);
+int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes,
+ enum atomisp_input_format format,
+ enum atomisp_bayer_order bayer_order);
+void atomisp_unregister_subdev(struct v4l2_subdev *subdev);
/* API from old platform_camera.h, new CPUID implementation */
#define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \
diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt
index d3cf6ed547ae..c04c283ff438 100644
--- a/drivers/staging/media/atomisp/notes.txt
+++ b/drivers/staging/media/atomisp/notes.txt
@@ -36,12 +36,6 @@ a camera_mipi_info struct. This struct is allocated/managed by
the core atomisp code. The most important parts of the struct
are filled by the atomisp core itself, like e.g. the port number.
-The sensor drivers on a set_fmt call do fill in camera_mipi_info.data
-which is a atomisp_sensor_mode_data struct. This gets filled from
-a function called <sensor_name>_get_intg_factor(). This struct is not
-used by the atomisp code at all. It is returned to userspace by
-a ATOMISP_IOC_G_SENSOR_MODE_DATA and the Android userspace does use this.
-
Other members of camera_mipi_info which are set by some drivers are:
-metadata_width, metadata_height, metadata_effective_width, set by
the ov5693 driver (and used by the atomisp core)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index d8c7e7367386..47f18ac5e40e 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -280,14 +280,14 @@ int atomisp_freq_scaling(struct atomisp_device *isp,
done:
dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq);
- if ((new_freq == isp->sw_contex.running_freq) && !force)
+ if ((new_freq == isp->running_freq) && !force)
return 0;
dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq);
ret = write_target_freq_to_hw(isp, new_freq);
if (!ret) {
- isp->sw_contex.running_freq = new_freq;
+ isp->running_freq = new_freq;
trace_ipu_pstate(new_freq, -1);
}
return ret;
@@ -679,7 +679,8 @@ void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state
vb2_buffer_done(&frame->vb.vb2_buf, state);
}
-void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames)
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state,
+ bool warn_on_css_frames)
{
struct ia_css_frame *frame, *_frame;
unsigned long irqflags;
@@ -689,15 +690,15 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_
list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) {
if (warn_on_css_frames)
dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n");
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
}
list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue)
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) {
pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0;
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
}
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
@@ -706,10 +707,10 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_
/* Returns queued buffers back to video-core */
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd)
{
- atomisp_flush_video_pipe(&asd->video_out_capture, false);
- atomisp_flush_video_pipe(&asd->video_out_vf, false);
- atomisp_flush_video_pipe(&asd->video_out_preview, false);
- atomisp_flush_video_pipe(&asd->video_out_video_capture, false);
+ atomisp_flush_video_pipe(&asd->video_out_capture, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_vf, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_preview, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_video_capture, VB2_BUF_STATE_ERROR, false);
}
/* clean out the parameters that did not apply */
@@ -4211,25 +4212,6 @@ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
return 0;
}
-/*
- * Function to get sensor specific info for current resolution,
- * which will be used for auto exposure conversion.
- */
-int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
- struct atomisp_sensor_mode_data *config)
-{
- struct camera_mipi_info *mipi_info;
- struct atomisp_device *isp = asd->isp;
-
- mipi_info = atomisp_to_sensor_mipi_info(
- isp->inputs[asd->input_curr].camera);
- if (!mipi_info)
- return -EINVAL;
-
- memcpy(config, &mipi_info->data, sizeof(*config));
- return 0;
-}
-
static void __atomisp_update_stream_env(struct atomisp_sub_device *asd,
u16 stream_index, struct atomisp_input_stream_info *stream_info)
{
@@ -5010,7 +4992,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
struct v4l2_subdev_format vformat = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
- struct v4l2_mbus_framefmt *ffmt = &vformat.format;
struct v4l2_rect isp_sink_crop;
u16 source_pad = atomisp_subdev_source_pad(vdev);
struct v4l2_subdev_fh fh;
@@ -5049,17 +5030,17 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
/* Ensure that the resolution is equal or below the maximum supported */
vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code);
- ffmt->height += padding_h;
- ffmt->width += padding_w;
+ v4l2_fill_mbus_format(&vformat.format, &f->fmt.pix, format_bridge->mbus_code);
+ vformat.format.height += padding_h;
+ vformat.format.width += padding_w;
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad,
set_fmt, NULL, &vformat);
if (ret)
return ret;
- f->fmt.pix.width = ffmt->width - padding_w;
- f->fmt.pix.height = ffmt->height - padding_h;
+ f->fmt.pix.width = vformat.format.width - padding_w;
+ f->fmt.pix.height = vformat.format.height - padding_h;
snr_fmt = f->fmt.pix;
backup_fmt = snr_fmt;
@@ -5182,9 +5163,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
if (!atomisp_subdev_format_conversion(asd, source_pad)) {
padding_w = 0;
padding_h = 0;
- } else if (IS_BYT) {
- padding_w = 12;
- padding_h = 12;
}
/* construct resolution supported by isp */
@@ -5492,42 +5470,6 @@ out:
return ret;
}
-int atomisp_exif_makernote(struct atomisp_sub_device *asd,
- struct atomisp_makernote_info *config)
-{
- struct v4l2_control ctrl;
- struct atomisp_device *isp = asd->isp;
-
- ctrl.id = V4L2_CID_FOCAL_ABSOLUTE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for focal length\n");
- return -EINVAL;
- } else {
- config->focal_length = ctrl.value;
- }
-
- ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for f-number\n");
- return -EINVAL;
- } else {
- config->f_number_curr = ctrl.value;
- }
-
- ctrl.id = V4L2_CID_FNUMBER_RANGE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for f number range\n");
- return -EINVAL;
- } else {
- config->f_number_range = ctrl.value;
- }
-
- return 0;
-}
-
int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
struct atomisp_cont_capture_conf *cvf_config)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
index b8911491581a..733b9f8cd06f 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
@@ -57,7 +57,8 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev);
int atomisp_reset(struct atomisp_device *isp);
int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe);
void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state);
-void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames);
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state,
+ bool warn_on_css_frames);
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd);
void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd);
@@ -258,9 +259,6 @@ int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd,
int atomisp_compare_grid(struct atomisp_sub_device *asd,
struct atomisp_grid_info *atomgrid);
-int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
- struct atomisp_sensor_mode_data *config);
-
/* This function looks up the closest available resolution. */
int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
bool *res_overflow);
@@ -273,9 +271,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd,
int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
struct atomisp_cont_capture_conf *cvf_config);
-int atomisp_exif_makernote(struct atomisp_sub_device *asd,
- struct atomisp_makernote_info *config);
-
void atomisp_free_internal_buffers(struct atomisp_sub_device *asd);
int atomisp_s_ae_window(struct atomisp_sub_device *asd,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
index 4a9268bac8a9..b00bc0b7aaad 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
@@ -175,47 +175,8 @@ static const struct v4l2_subdev_ops csi2_ops = {
.pad = &csi2_pad_ops,
};
-/*
- * csi2_link_setup - Setup CSI2 connections.
- * @entity : Pointer to media entity structure
- * @local : Pointer to local pad array
- * @remote : Pointer to remote pad array
- * @flags : Link flags
- * return -EINVAL or zero on success
- */
-static int csi2_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity);
-
- switch (result) {
- case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE:
- /* not supported yet */
- return -EINVAL;
-
- case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV)
- return -EBUSY;
- csi2->output |= CSI2_OUTPUT_ISP_SUBDEV;
- } else {
- csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV;
- }
- break;
-
- default:
- /* Link from camera to CSI2 is fixed... */
- return -EINVAL;
- }
- return 0;
-}
-
/* media operations */
static const struct media_entity_operations csi2_media_ops = {
- .link_setup = csi2_link_setup,
.link_validate = v4l2_subdev_link_validate,
};
@@ -242,7 +203,7 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2,
pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
me->ops = &csi2_media_ops;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_VID_IF_BRIDGE;
ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
if (ret < 0)
return ret;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
index e35711be8a37..b245b2f5ce99 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
@@ -25,9 +25,6 @@
#define CSI2_PAD_SOURCE 1
#define CSI2_PADS_NUM 2
-#define CSI2_OUTPUT_ISP_SUBDEV BIT(0)
-#define CSI2_OUTPUT_MEMORY BIT(1)
-
struct atomisp_device;
struct v4l2_device;
struct atomisp_sub_device;
@@ -39,8 +36,6 @@ struct atomisp_mipi_csi2_device {
struct v4l2_ctrl_handler ctrls;
struct atomisp_device *isp;
-
- u32 output; /* output direction */
};
int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c
index acea7492847d..ce01479bdd68 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c
@@ -80,7 +80,7 @@ static int atomisp_queue_setup(struct vb2_queue *vq,
out:
mutex_unlock(&pipe->asd->isp->mutex);
- return 0;
+ return ret;
}
static int atomisp_buf_init(struct vb2_buffer *vb)
@@ -624,7 +624,7 @@ static void atomisp_buf_cleanup(struct vb2_buffer *vb)
hmm_free(frame->data);
}
-static const struct vb2_ops atomisp_vb2_ops = {
+const struct vb2_ops atomisp_vb2_ops = {
.queue_setup = atomisp_queue_setup,
.buf_init = atomisp_buf_init,
.buf_cleanup = atomisp_buf_cleanup,
@@ -633,40 +633,6 @@ static const struct vb2_ops atomisp_vb2_ops = {
.stop_streaming = atomisp_stop_streaming,
};
-static int atomisp_init_pipe(struct atomisp_video_pipe *pipe)
-{
- int ret;
-
- /* init locks */
- spin_lock_init(&pipe->irq_lock);
- mutex_init(&pipe->vb_queue_mutex);
-
- /* Init videobuf2 queue structure */
- pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
- pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
- pipe->vb_queue.ops = &atomisp_vb2_ops;
- pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
- pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- ret = vb2_queue_init(&pipe->vb_queue);
- if (ret)
- return ret;
-
- pipe->vdev.queue = &pipe->vb_queue;
- pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
-
- INIT_LIST_HEAD(&pipe->activeq);
- INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
- INIT_LIST_HEAD(&pipe->per_frame_params);
- memset(pipe->frame_request_config_id, 0,
- VIDEO_MAX_FRAME * sizeof(unsigned int));
- memset(pipe->frame_params, 0,
- VIDEO_MAX_FRAME *
- sizeof(struct atomisp_css_params_with_list *));
-
- return 0;
-}
-
static void atomisp_dev_init_struct(struct atomisp_device *isp)
{
unsigned int i;
@@ -681,7 +647,7 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp)
* For Merrifield, frequency is scalable.
* After boot-up, the default frequency is 200MHz.
*/
- isp->sw_contex.running_freq = ISP_FREQ_200MHZ;
+ isp->running_freq = ISP_FREQ_200MHZ;
}
static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd)
@@ -757,25 +723,6 @@ static int atomisp_open(struct file *file)
mutex_lock(&isp->mutex);
asd->subdev.devnode = vdev;
- /* Deferred firmware loading case. */
- if (isp->css_env.isp_css_fw.bytes == 0) {
- dev_err(isp->dev, "Deferred firmware load.\n");
- isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- dev_err(isp->dev, "Failed to load ISP firmware.\n");
- ret = -ENOENT;
- goto error;
- }
- ret = atomisp_css_load_firmware(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to init css.\n");
- goto error;
- }
- /* No need to keep FW in memory anymore. */
- release_firmware(isp->firmware);
- isp->firmware = NULL;
- isp->css_env.isp_css_fw.data = NULL;
- }
if (!isp->input_cnt) {
dev_err(isp->dev, "no camera attached\n");
@@ -792,10 +739,6 @@ static int atomisp_open(struct file *file)
return -EBUSY;
}
- ret = atomisp_init_pipe(pipe);
- if (ret)
- goto error;
-
if (atomisp_dev_users(isp)) {
dev_dbg(isp->dev, "skip init isp in open\n");
goto init_subdev;
@@ -821,13 +764,13 @@ init_subdev:
goto done;
atomisp_subdev_init_struct(asd);
+ /* Ensure that a mode is set */
+ v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode);
done:
pipe->users++;
mutex_unlock(&isp->mutex);
- /* Ensure that a mode is set */
- v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode);
return 0;
@@ -885,13 +828,17 @@ static int atomisp_release(struct file *file)
atomisp_css_free_stat_buffers(asd);
atomisp_free_internal_buffers(asd);
- ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- core, s_power, 0);
- if (ret)
- dev_warn(isp->dev, "Failed to power-off sensor\n");
- /* clear the asd field to show this camera is not used */
- isp->inputs[asd->input_curr].asd = NULL;
+ if (isp->inputs[asd->input_curr].asd == asd) {
+ ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
+ core, s_power, 0);
+ if (ret && ret != -ENOIOCTLCMD)
+ dev_warn(isp->dev, "Failed to power-off sensor\n");
+
+ /* clear the asd field to show this camera is not used */
+ isp->inputs[asd->input_curr].asd = NULL;
+ }
+
spin_lock_irqsave(&isp->lock, flags);
asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
spin_unlock_irqrestore(&isp->lock, flags);
@@ -901,12 +848,6 @@ static int atomisp_release(struct file *file)
atomisp_destroy_pipes_stream_force(asd);
- if (defer_fw_load) {
- ia_css_unload_firmware();
- isp->css_env.isp_css_fw.data = NULL;
- isp->css_env.isp_css_fw.bytes = 0;
- }
-
ret = v4l2_subdev_call(isp->flash, core, s_power, 0);
if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD)
dev_warn(isp->dev, "Failed to power-off flash\n");
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h
index 10e43126b693..883c1851c1c9 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h
@@ -31,8 +31,7 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd);
int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd);
+extern const struct vb2_ops atomisp_vb2_ops;
extern const struct v4l2_file_operations atomisp_fops;
-extern bool defer_fw_load;
-
#endif /* __ATOMISP_FOPS_H__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
index 3d41fab661cf..7fc7dfa56172 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
@@ -57,8 +57,12 @@ enum clock_rate {
#define LDO_1P8V_OFF 0x58 /* ... bottom bit is "enabled" */
/* CRYSTAL COVE PMIC register set */
-#define CRYSTAL_1P8V_REG 0x57
-#define CRYSTAL_2P8V_REG 0x5d
+#define CRYSTAL_BYT_1P8V_REG 0x5d
+#define CRYSTAL_BYT_2P8V_REG 0x66
+
+#define CRYSTAL_CHT_1P8V_REG 0x57
+#define CRYSTAL_CHT_2P8V_REG 0x5d
+
#define CRYSTAL_ON 0x63
#define CRYSTAL_OFF 0x62
@@ -145,7 +149,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
enum intel_v4l2_subdev_type type)
{
int i;
- struct i2c_board_info *bi;
struct gmin_subdev *gs;
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
@@ -158,6 +161,14 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
* tickled during suspend/resume. This has caused power and
* performance issues on multiple devices.
*/
+
+ /*
+ * Turn off the device before disabling ACPI power resources
+ * (the sensor driver has already probed it at this point).
+ * This avoids leaking the reference count of the (possibly shared)
+ * ACPI power resources which were enabled/referenced before probe().
+ */
+ acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
adev->power.flags.power_resources = 0;
for (i = 0; i < MAX_SUBDEVS; i++)
@@ -179,36 +190,10 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
pdata.subdevs[i].type = type;
pdata.subdevs[i].port = gs->csi_port;
pdata.subdevs[i].subdev = subdev;
- pdata.subdevs[i].v4l2_subdev.i2c_adapter_id = client->adapter->nr;
-
- /* Convert i2c_client to i2c_board_info */
- bi = &pdata.subdevs[i].v4l2_subdev.board_info;
- memcpy(bi->type, client->name, I2C_NAME_SIZE);
- bi->flags = client->flags;
- bi->addr = client->addr;
- bi->irq = client->irq;
- bi->platform_data = plat_data;
-
return 0;
}
EXPORT_SYMBOL_GPL(atomisp_register_i2c_module);
-struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter,
- struct i2c_board_info *board_info)
-{
- int i;
-
- for (i = 0; i < MAX_SUBDEVS && pdata.subdevs[i].type; i++) {
- struct intel_v4l2_subdev_table *sd = &pdata.subdevs[i];
-
- if (sd->v4l2_subdev.i2c_adapter_id == adapter->nr &&
- sd->v4l2_subdev.board_info.addr == board_info->addr)
- return sd->subdev;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(atomisp_gmin_find_subdev);
-
int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd)
{
int i, j;
@@ -843,6 +828,7 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on)
struct gmin_subdev *gs = find_gmin_subdev(subdev);
int ret;
int value;
+ int reg;
if (!gs || gs->v1p8_on == on)
return 0;
@@ -898,10 +884,15 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on)
LDO10_REG, value, 0xff);
break;
case PMIC_CRYSTALCOVE:
+ if (IS_ISP2401)
+ reg = CRYSTAL_CHT_1P8V_REG;
+ else
+ reg = CRYSTAL_BYT_1P8V_REG;
+
value = on ? CRYSTAL_ON : CRYSTAL_OFF;
ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr,
- CRYSTAL_1P8V_REG, value, 0xff);
+ reg, value, 0xff);
break;
default:
dev_err(subdev->dev, "Couldn't set power mode for v1p8\n");
@@ -918,6 +909,7 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on)
struct gmin_subdev *gs = find_gmin_subdev(subdev);
int ret;
int value;
+ int reg;
if (WARN_ON(!gs))
return -ENODEV;
@@ -974,10 +966,15 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on)
LDO9_REG, value, 0xff);
break;
case PMIC_CRYSTALCOVE:
+ if (IS_ISP2401)
+ reg = CRYSTAL_CHT_2P8V_REG;
+ else
+ reg = CRYSTAL_BYT_2P8V_REG;
+
value = on ? CRYSTAL_ON : CRYSTAL_OFF;
ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr,
- CRYSTAL_2P8V_REG, value, 0xff);
+ reg, value, 0xff);
break;
default:
dev_err(subdev->dev, "Couldn't set power mode for v2p8\n");
@@ -1095,6 +1092,67 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag)
return 0;
}
+int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes,
+ enum atomisp_input_format format,
+ enum atomisp_bayer_order bayer_order)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ int i, ret, clock_num, port = 0;
+
+ if (adev) {
+ /* Get ACPI _PR0 derived clock to determine the csi_port default */
+ if (acpi_device_power_manageable(adev)) {
+ clock_num = atomisp_get_acpi_power(&client->dev);
+
+ /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */
+ if (IS_ISP2401)
+ port = clock_num == 4 ? 1 : 0;
+ else
+ port = clock_num == 0 ? 1 : 0;
+ }
+
+ port = gmin_get_var_int(&client->dev, false, "CsiPort", port);
+ lanes = gmin_get_var_int(&client->dev, false, "CsiLanes", lanes);
+ }
+
+ for (i = 0; i < MAX_SUBDEVS; i++)
+ if (!pdata.subdevs[i].type)
+ break;
+
+ if (i >= MAX_SUBDEVS) {
+ dev_err(&client->dev, "Error too many subdevs already registered\n");
+ return -ENOMEM;
+ }
+
+ ret = camera_sensor_csi_alloc(subdev, port, lanes, format, bayer_order);
+ if (ret)
+ return ret;
+
+ pdata.subdevs[i].type = RAW_CAMERA;
+ pdata.subdevs[i].port = port;
+ pdata.subdevs[i].subdev = subdev;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(atomisp_register_sensor_no_gmin);
+
+void atomisp_unregister_subdev(struct v4l2_subdev *subdev)
+{
+ int i;
+
+ for (i = 0; i < MAX_SUBDEVS; i++) {
+ if (pdata.subdevs[i].subdev != subdev)
+ continue;
+
+ camera_sensor_csi_free(subdev);
+ pdata.subdevs[i].subdev = NULL;
+ pdata.subdevs[i].type = 0;
+ pdata.subdevs[i].port = 0;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(atomisp_unregister_subdev);
+
static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev,
char *camera_module)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h
index 653e6d74a966..fa38d91420cf 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_internal.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h
@@ -194,10 +194,6 @@ struct atomisp_regs {
u32 csi_access_viol;
};
-struct atomisp_sw_contex {
- int running_freq;
-};
-
#define ATOMISP_DEVICE_STREAMING_DISABLED 0
#define ATOMISP_DEVICE_STREAMING_ENABLED 1
#define ATOMISP_DEVICE_STREAMING_STOPPING 2
@@ -214,6 +210,7 @@ struct atomisp_device {
void __iomem *base;
const struct firmware *firmware;
+ struct dev_pm_domain pm_domain;
struct pm_qos_request pm_qos;
s32 max_isr_latency;
@@ -242,7 +239,6 @@ struct atomisp_device {
struct v4l2_subdev *motor;
struct atomisp_regs saved_regs;
- struct atomisp_sw_contex sw_contex;
struct atomisp_css_env css_env;
/* isp timeout status flag */
@@ -257,6 +253,7 @@ struct atomisp_device {
unsigned int mipi_frame_size;
const struct atomisp_dfs_config *dfs;
unsigned int hpll_freq;
+ unsigned int running_freq;
bool css_initialized;
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index cb01ba65c88f..d1314bdbf7d5 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -173,24 +173,6 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = {
.default_value = 1,
},
{
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Horizontal binning factor",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical binning factor",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
.id = V4L2_CID_2A_STATUS,
.type = V4L2_CTRL_TYPE_BITMASK,
.name = "AE and AWB status",
@@ -636,10 +618,10 @@ static int atomisp_enum_input(struct file *file, void *fh,
static unsigned int
atomisp_subdev_streaming_count(struct atomisp_sub_device *asd)
{
- return asd->video_out_preview.vb_queue.start_streaming_called
- + asd->video_out_capture.vb_queue.start_streaming_called
- + asd->video_out_video_capture.vb_queue.start_streaming_called
- + asd->video_out_vf.vb_queue.start_streaming_called;
+ return vb2_start_streaming_called(&asd->video_out_preview.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_capture.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_video_capture.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_vf.vb_queue);
}
unsigned int atomisp_streaming_count(struct atomisp_device *isp)
@@ -718,7 +700,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input)
asd->input_curr != input) {
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
core, s_power, 0);
- if (ret)
+ if (ret && ret != -ENOIOCTLCMD)
dev_warn(isp->dev,
"Failed to power-off sensor\n");
/* clear the asd field to show this camera is not used */
@@ -727,7 +709,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input)
/* powe on the new sensor */
ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1);
- if (ret) {
+ if (ret && ret != -ENOIOCTLCMD) {
dev_err(isp->dev, "Failed to power-on sensor\n");
return ret;
}
@@ -1067,13 +1049,23 @@ error:
return -ENOMEM;
}
+/*
+ * FIXME the abuse of buf->reserved2 in the qbuf and dqbuf wrappers comes from
+ * the original atomisp buffer handling and should be replaced with proper V4L2
+ * per frame parameters use.
+ *
+ * Once this is fixed these wrappers can be removed, replacing them with direct
+ * calls to vb2_ioctl_[d]qbuf().
+ */
static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */
+ if (buf->index >= vdev->queue->num_buffers)
+ return -EINVAL;
+
if (!atomisp_is_vf_pipe(pipe) &&
(buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) {
/* this buffer will have a per-frame parameter */
@@ -1106,7 +1098,6 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
vb = pipe->vb_queue.bufs[buf->index];
frame = vb_to_frame(vb);
- /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */
buf->reserved = asd->frame_status[buf->index];
/*
@@ -1354,7 +1345,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count)
ret = atomisp_css_start(asd, css_pipe_id, false);
if (ret) {
- atomisp_flush_video_pipe(pipe, true);
+ atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true);
goto out_unlock;
}
@@ -1530,7 +1521,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq)
css_pipe_id = atomisp_get_css_pipe_id(asd);
atomisp_css_stop(asd, css_pipe_id, false);
- atomisp_flush_video_pipe(pipe, true);
+ atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true);
atomisp_subdev_cleanup_pending_events(asd);
stopsensor:
@@ -1631,7 +1622,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh,
switch (control->id) {
case V4L2_CID_IRIS_ABSOLUTE:
case V4L2_CID_EXPOSURE_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
case V4L2_CID_2A_STATUS:
case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
case V4L2_CID_EXPOSURE:
@@ -1828,9 +1818,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh,
case V4L2_CID_EXPOSURE_ABSOLUTE:
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_IRIS_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
- case V4L2_CID_BIN_FACTOR_HORZ:
- case V4L2_CID_BIN_FACTOR_VERT:
case V4L2_CID_3A_LOCK:
case V4L2_CID_TEST_PATTERN:
case V4L2_CID_TEST_PATTERN_COLOR_R:
@@ -1940,7 +1927,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh,
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_EXPOSURE_METERING:
case V4L2_CID_IRIS_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
case V4L2_CID_VCM_TIMING:
case V4L2_CID_VCM_SLEW:
case V4L2_CID_3A_LOCK:
@@ -2276,14 +2262,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
err = atomisp_fixed_pattern_table(asd, arg);
break;
- case ATOMISP_IOC_ISP_MAKERNOTE:
- err = atomisp_exif_makernote(asd, arg);
- break;
-
- case ATOMISP_IOC_G_SENSOR_MODE_DATA:
- err = atomisp_get_sensor_mode_data(asd, arg);
- break;
-
case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
if (motor)
err = v4l2_subdev_call(motor, core, ioctl, cmd, arg);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index cadc468b4c2f..9cfb85c61db6 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -25,9 +25,11 @@
#include <media/v4l2-event.h>
#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-vmalloc.h>
#include "atomisp_cmd.h"
#include "atomisp_common.h"
#include "atomisp_compat.h"
+#include "atomisp_fops.h"
#include "atomisp_internal.h"
const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
@@ -574,40 +576,6 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd,
sel->target, sel->flags, &sel->r);
}
-static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
-{
- struct v4l2_control ctrl = {0};
- struct atomisp_device *isp = asd->isp;
- int hbin, vbin;
- int ret;
-
- if (isp->inputs[asd->input_curr].type == FILE_INPUT ||
- isp->inputs[asd->input_curr].type == TEST_PATTERN)
- return 0;
-
- ctrl.id = V4L2_CID_BIN_FACTOR_HORZ;
- ret =
- v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
- &ctrl);
- hbin = ctrl.value;
- ctrl.id = V4L2_CID_BIN_FACTOR_VERT;
- ret |=
- v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
- &ctrl);
- vbin = ctrl.value;
-
- /*
- * ISP needs to know binning factor from sensor.
- * In case horizontal and vertical sensor's binning factors
- * are different or sensor does not support binning factor CID,
- * ISP will apply default 0 value.
- */
- if (ret || hbin != vbin)
- hbin = 0;
-
- return hbin;
-}
-
void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
uint32_t which,
@@ -645,7 +613,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
ATOMISP_INPUT_STREAM_GENERAL, ffmt);
atomisp_css_input_set_binning_factor(isp_sd,
ATOMISP_INPUT_STREAM_GENERAL,
- atomisp_get_sensor_bin_factor(isp_sd));
+ 0);
atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
fc->bayer_order);
atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
@@ -746,85 +714,8 @@ static void isp_subdev_init_params(struct atomisp_sub_device *asd)
}
}
-/*
-* isp_subdev_link_setup - Setup isp subdev connections
-* @entity: ispsubdev media entity
-* @local: Pad at the local end of the link
-* @remote: Pad at the remote end of the link
-* @flags: Link flags
-*
-* return -EINVAL or zero on success
-*/
-static int isp_subdev_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
- struct atomisp_device *isp = isp_sd->isp;
- unsigned int i;
-
- switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) {
- case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
- /* Read from the sensor CSI2-ports. */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
- break;
- }
-
- if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
- return -EBUSY;
-
- for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
- if (remote->entity != &isp->csi2_port[i].subdev.entity)
- continue;
-
- isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i;
- return 0;
- }
-
- return -EINVAL;
-
- case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE:
- /* read from memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 &&
- isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1
- + ATOMISP_CAMERA_NR_PORTS))
- return -EBUSY;
- isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
- } else {
- if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
- isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
- }
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
/* media operations */
static const struct media_entity_operations isp_subdev_media_ops = {
- .link_setup = isp_subdev_link_setup,
.link_validate = v4l2_subdev_link_validate,
/* .set_power = v4l2_subdev_set_power, */
};
@@ -1057,23 +948,37 @@ static const struct v4l2_ctrl_config ctrl_depth_mode = {
.def = 0,
};
-static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
- struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
+static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
+ struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
{
+ int ret;
+
pipe->type = buf_type;
pipe->asd = asd;
pipe->isp = asd->isp;
spin_lock_init(&pipe->irq_lock);
mutex_init(&pipe->vb_queue_mutex);
+
+ /* Init videobuf2 queue structure */
+ pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
+ pipe->vb_queue.ops = &atomisp_vb2_ops;
+ pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&pipe->vb_queue);
+ if (ret)
+ return ret;
+
+ pipe->vdev.queue = &pipe->vb_queue;
+ pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
+
INIT_LIST_HEAD(&pipe->buffers_in_css);
INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
INIT_LIST_HEAD(&pipe->per_frame_params);
- memset(pipe->frame_request_config_id,
- 0, VIDEO_MAX_FRAME * sizeof(unsigned int));
- memset(pipe->frame_params,
- 0, VIDEO_MAX_FRAME *
- sizeof(struct atomisp_css_params_with_list *));
+
+ return 0;
}
/*
@@ -1089,8 +994,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
struct media_entity *me = &sd->entity;
int ret;
- asd->input = ATOMISP_SUBDEV_INPUT_NONE;
-
v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
v4l2_set_subdevdata(sd, asd);
@@ -1114,22 +1017,30 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
MEDIA_BUS_FMT_SBGGR10_1X10;
me->ops = &isp_subdev_media_ops;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
if (ret < 0)
return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE",
ATOMISP_RUN_MODE_STILL_CAPTURE);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
index bd2872cbb50c..daa6077a83bd 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
@@ -30,18 +30,6 @@
/* EXP_ID's ranger is 1 ~ 250 */
#define ATOMISP_MAX_EXP_ID (250)
-enum atomisp_subdev_input_entity {
- ATOMISP_SUBDEV_INPUT_NONE,
- ATOMISP_SUBDEV_INPUT_MEMORY,
- ATOMISP_SUBDEV_INPUT_CSI2,
- /*
- * The following enum for CSI2 port must go together in one row.
- * Otherwise it breaks the code logic.
- */
- ATOMISP_SUBDEV_INPUT_CSI2_PORT1,
- ATOMISP_SUBDEV_INPUT_CSI2_PORT2,
- ATOMISP_SUBDEV_INPUT_CSI2_PORT3,
-};
#define ATOMISP_SUBDEV_PAD_SINK 0
/* capture output for still frames */
@@ -267,7 +255,6 @@ struct atomisp_sub_device {
struct atomisp_pad_format fmt[ATOMISP_SUBDEV_PADS_NUM];
u16 capture_pad; /* main capture pad; defines much of isp config */
- enum atomisp_subdev_input_entity input;
unsigned int output;
struct atomisp_video_pipe video_out_capture; /* capture output */
struct atomisp_video_pipe video_out_vf; /* viewfinder output */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
index e29a96da5f98..074826a5b706 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
@@ -152,7 +152,7 @@ int atomisp_tpg_init(struct atomisp_device *isp)
v4l2_set_subdevdata(sd, tpg);
pads[0].flags = MEDIA_PAD_FL_SINK;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
ret = media_entity_pads_init(me, 1, pads);
if (ret < 0)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index e786b81921da..ba628f7cf385 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -19,6 +19,7 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/timer.h>
@@ -57,12 +58,6 @@ static uint skip_fwload;
module_param(skip_fwload, uint, 0644);
MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load");
-/* memory optimization: deferred firmware loading */
-bool defer_fw_load;
-module_param(defer_fw_load, bool, 0644);
-MODULE_PARM_DESC(defer_fw_load,
- "Defer FW loading until device is opened (default:disable)");
-
/* cross componnet debug message flag */
int dbg_level;
module_param(dbg_level, int, 0644);
@@ -524,7 +519,7 @@ static int atomisp_save_iunit_reg(struct atomisp_device *isp)
return 0;
}
-static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp)
+static int atomisp_restore_iunit_reg(struct atomisp_device *isp)
{
struct pci_dev *pdev = to_pci_dev(isp->dev);
@@ -637,31 +632,21 @@ done:
*/
static void punit_ddr_dvfs_enable(bool enable)
{
- int door_bell = 1 << 8;
- int max_wait = 30;
int reg;
iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
if (enable) {
reg &= ~(MRFLD_BIT0 | MRFLD_BIT1);
} else {
- reg |= (MRFLD_BIT1 | door_bell);
+ reg |= MRFLD_BIT1;
reg &= ~(MRFLD_BIT0);
}
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg);
-
- /* Check Req_ACK to see freq status, wait until door_bell is cleared */
- while ((reg & door_bell) && max_wait--) {
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
- usleep_range(100, 500);
- }
-
- if (max_wait == -1)
- pr_info("DDR DVFS, door bell is not cleared within 3ms\n");
}
static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
{
+ struct pci_dev *pdev = to_pci_dev(isp->dev);
unsigned long timeout;
u32 val = enable ? MRFLD_ISPSSPM0_IUNIT_POWER_ON :
MRFLD_ISPSSPM0_IUNIT_POWER_OFF;
@@ -669,16 +654,10 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off");
/* WA for P-Unit, if DVFS enabled, ISP timeout observed */
- if (IS_CHT && enable)
+ if (IS_CHT && enable) {
punit_ddr_dvfs_enable(false);
-
- /*
- * FIXME:WA for ECS28A, with this sleep, CTS
- * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort
- * PASS, no impact on other platforms
- */
- if (IS_BYT && enable)
- msleep(10);
+ msleep(20);
+ }
/* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */
iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0,
@@ -703,6 +682,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
tmp = (tmp >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) & MRFLD_ISPSSPM0_ISPSSC_MASK;
if (tmp == val) {
trace_ipu_cstate(enable);
+ pdev->current_state = enable ? PCI_D0 : PCI_D3cold;
return 0;
}
@@ -743,6 +723,7 @@ int atomisp_power_off(struct device *dev)
pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg);
cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
+ pci_save_state(pdev);
return atomisp_mrfld_power(isp, false);
}
@@ -756,6 +737,7 @@ int atomisp_power_on(struct device *dev)
if (ret)
return ret;
+ pci_restore_state(to_pci_dev(dev));
cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
/*restore register values for iUnit and iUnitPHY registers*/
@@ -767,7 +749,7 @@ int atomisp_power_on(struct device *dev)
return atomisp_css_init(isp);
}
-static int __maybe_unused atomisp_suspend(struct device *dev)
+static int atomisp_suspend(struct device *dev)
{
struct atomisp_device *isp = (struct atomisp_device *)
dev_get_drvdata(dev);
@@ -790,10 +772,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev)
}
spin_unlock_irqrestore(&isp->lock, flags);
+ pm_runtime_resume(dev);
+
return atomisp_power_off(dev);
}
-static int __maybe_unused atomisp_resume(struct device *dev)
+static int atomisp_resume(struct device *dev)
{
return atomisp_power_on(dev);
}
@@ -953,45 +937,9 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
/* FIXME: should, instead, use I2C probe */
for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) {
- struct v4l2_subdev *subdev;
- struct i2c_board_info *board_info =
- &subdevs->v4l2_subdev.board_info;
- struct i2c_adapter *adapter =
- i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id);
-
- dev_info(isp->dev, "Probing Subdev %s\n", board_info->type);
-
- if (!adapter) {
- dev_err(isp->dev,
- "Failed to find i2c adapter for subdev %s\n",
- board_info->type);
- break;
- }
-
- /* In G-Min, the sensor devices will already be probed
- * (via ACPI) and registered, do not create new
- * ones */
- subdev = atomisp_gmin_find_subdev(adapter, board_info);
- if (!subdev) {
- dev_warn(isp->dev, "Subdev %s not found\n",
- board_info->type);
+ ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev);
+ if (ret)
continue;
- }
- ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev);
- if (ret) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- if (!subdev) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- dev_info(isp->dev, "Subdev %s successfully register\n",
- board_info->type);
switch (subdevs->type) {
case RAW_CAMERA:
@@ -1008,7 +956,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
isp->inputs[isp->input_cnt].type = subdevs->type;
isp->inputs[isp->input_cnt].port = subdevs->port;
- isp->inputs[isp->input_cnt].camera = subdev;
+ isp->inputs[isp->input_cnt].camera = subdevs->subdev;
isp->inputs[isp->input_cnt].sensor_index = 0;
/*
* initialize the subdev frame size, then next we can
@@ -1020,22 +968,18 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
break;
case CAMERA_MOTOR:
if (isp->motor) {
- dev_warn(isp->dev,
- "too many atomisp motors, ignored %s\n",
- board_info->type);
+ dev_warn(isp->dev, "too many atomisp motors\n");
continue;
}
- isp->motor = subdev;
+ isp->motor = subdevs->subdev;
break;
case LED_FLASH:
case XENON_FLASH:
if (isp->flash) {
- dev_warn(isp->dev,
- "too many atomisp flash devices, ignored %s\n",
- board_info->type);
+ dev_warn(isp->dev, "too many atomisp flash devices\n");
continue;
}
- isp->flash = subdev;
+ isp->flash = subdevs->subdev;
break;
default:
dev_dbg(isp->dev, "unknown subdev probed\n");
@@ -1524,21 +1468,17 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY;
/* Load isp firmware from user space */
- if (!defer_fw_load) {
- isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- err = -ENOENT;
- dev_dbg(&pdev->dev, "Firmware load failed\n");
- goto load_fw_fail;
- }
+ isp->firmware = atomisp_load_firmware(isp);
+ if (!isp->firmware) {
+ err = -ENOENT;
+ dev_dbg(&pdev->dev, "Firmware load failed\n");
+ goto load_fw_fail;
+ }
- err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
- if (err) {
- dev_dbg(&pdev->dev, "Firmware version check failed\n");
- goto fw_validation_fail;
- }
- } else {
- dev_info(&pdev->dev, "Firmware load will be deferred\n");
+ err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
+ if (err) {
+ dev_dbg(&pdev->dev, "Firmware version check failed\n");
+ goto fw_validation_fail;
}
pci_set_master(pdev);
@@ -1603,6 +1543,26 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
/* save the iunit context only once after all the values are init'ed. */
atomisp_save_iunit_reg(isp);
+ /*
+ * The atomisp does not use standard PCI power-management through the
+ * PCI config space. Instead this driver directly tells the P-Unit to
+ * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will
+ * try to access the config space before (resume) / after (suspend) this
+ * driver has turned the ISP on / off, resulting in the following errors:
+ *
+ * "Unable to change power state from D0 to D3hot, device inaccessible"
+ * "Unable to change power state from D3cold to D0, device inaccessible"
+ *
+ * To avoid these errors override the pm_domain so that all the PCI
+ * subsys suspend / resume handling is skipped.
+ */
+ isp->pm_domain.ops.runtime_suspend = atomisp_power_off;
+ isp->pm_domain.ops.runtime_resume = atomisp_power_on;
+ isp->pm_domain.ops.suspend = atomisp_suspend;
+ isp->pm_domain.ops.resume = atomisp_resume;
+
+ dev_pm_domain_set(&pdev->dev, &isp->pm_domain);
+
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
@@ -1618,14 +1578,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
}
/* Load firmware into ISP memory */
- if (!defer_fw_load) {
- err = atomisp_css_load_firmware(isp);
- if (err) {
- dev_err(&pdev->dev, "Failed to init css.\n");
- goto css_init_fail;
- }
- } else {
- dev_dbg(&pdev->dev, "Skip css init.\n");
+ err = atomisp_css_load_firmware(isp);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init css.\n");
+ goto css_init_fail;
}
/* Clear FW image from memory */
release_firmware(isp->firmware);
@@ -1645,6 +1601,7 @@ css_init_fail:
request_irq_fail:
hmm_cleanup();
pm_runtime_get_noresume(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
atomisp_unregister_entities(isp);
register_entities_fail:
atomisp_uninitialize_modules(isp);
@@ -1697,6 +1654,7 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
cpu_latency_qos_remove_request(&isp->pm_qos);
atomisp_msi_irq_uninit(isp);
@@ -1721,17 +1679,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl);
-static const struct dev_pm_ops atomisp_pm_ops = {
- .runtime_suspend = atomisp_power_off,
- .runtime_resume = atomisp_power_on,
- .suspend = atomisp_suspend,
- .resume = atomisp_resume,
-};
static struct pci_driver atomisp_pci_driver = {
- .driver = {
- .pm = &atomisp_pm_ops,
- },
.name = "atomisp-isp2",
.id_table = atomisp_pci_tbl,
.probe = atomisp_pci_probe,
diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
index a313e1dc7c71..d65fe9ec9049 100644
--- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
+++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
@@ -34,8 +34,6 @@ void isys2401_dma_reg_store(const isys2401_dma_ID_t dma_id,
reg_loc = ISYS2401_DMA_BASE[dma_id] + (reg * sizeof(hrt_data));
- ia_css_print("isys dma store at addr(0x%x) val(%u)\n", reg_loc,
- (unsigned int)value);
ia_css_device_store_uint32(reg_loc, value);
}
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
index 6620f091442f..d9cdfbc50197 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
@@ -28,10 +28,18 @@ typedef hive_uedge *hive_wide;
/* Copied from SDK: sim_semantics.c */
/* subword bits move like this: MSB[____xxxx____]LSB -> MSB[00000000xxxx]LSB */
-#define SUBWORD(w, start, end) (((w) & (((1ULL << ((end) - 1)) - 1) << 1 | 1)) >> (start))
+static inline hive_uedge
+subword(hive_uedge w, unsigned int start, unsigned int end)
+{
+ return (w & (((1ULL << (end - 1)) - 1) << 1 | 1)) >> start;
+}
/* inverse subword bits move like this: MSB[xxxx____xxxx]LSB -> MSB[xxxx0000xxxx]LSB */
-#define INV_SUBWORD(w, start, end) ((w) & (~(((1ULL << ((end) - 1)) - 1) << 1 | 1) | ((1ULL << (start)) - 1)))
+static inline hive_uedge
+inv_subword(hive_uedge w, unsigned int start, unsigned int end)
+{
+ return w & (~(((1ULL << (end - 1)) - 1) << 1 | 1) | ((1ULL << start) - 1));
+}
#define uedge_bits (8 * sizeof(hive_uedge))
#define move_lower_bits(target, target_bit, src, src_bit) move_subword(target, target_bit, src, 0, src_bit)
@@ -50,18 +58,18 @@ move_subword(
unsigned int start_bit = target_bit % uedge_bits;
unsigned int subword_width = src_end - src_start;
- hive_uedge src_subword = SUBWORD(src, src_start, src_end);
+ hive_uedge src_subword = subword(src, src_start, src_end);
if (subword_width + start_bit > uedge_bits) { /* overlap */
hive_uedge old_val1;
- hive_uedge old_val0 = INV_SUBWORD(target[start_elem], start_bit, uedge_bits);
+ hive_uedge old_val0 = inv_subword(target[start_elem], start_bit, uedge_bits);
target[start_elem] = old_val0 | (src_subword << start_bit);
- old_val1 = INV_SUBWORD(target[start_elem + 1], 0,
+ old_val1 = inv_subword(target[start_elem + 1], 0,
subword_width + start_bit - uedge_bits);
target[start_elem + 1] = old_val1 | (src_subword >> (uedge_bits - start_bit));
} else {
- hive_uedge old_val = INV_SUBWORD(target[start_elem], start_bit,
+ hive_uedge old_val = inv_subword(target[start_elem], start_bit,
start_bit + subword_width);
target[start_elem] = old_val | (src_subword << start_bit);
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index 726cb7aa4ecd..93789500416f 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -97,9 +97,6 @@
*/
#define JPEG_BYTES (16 * 1024 * 1024)
-#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
- (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
-
struct sh_css my_css;
int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL;
@@ -3743,7 +3740,9 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
* The SP will read the params after it got
* empty 3a and dis
*/
- if (STATS_ENABLED(stage)) {
+ if (stage->binary && stage->binary->info &&
+ (stage->binary->info->sp.enable.s3a ||
+ stage->binary->info->sp.enable.dis)) {
/* there is a stage that needs it */
return_err = ia_css_bufq_enqueue_buffer(thread_id,
queue_id,
diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c
index f08564f58242..588f2adab058 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_params.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_params.c
@@ -98,17 +98,27 @@
#include "sh_css_frac.h"
#include "ia_css_bufq.h"
-#define FPNTBL_BYTES(binary) \
- (sizeof(char) * (binary)->in_frame_info.res.height * \
- (binary)->in_frame_info.padded_width)
+static size_t fpntbl_bytes(const struct ia_css_binary *binary)
+{
+ return array3_size(sizeof(char),
+ binary->in_frame_info.res.height,
+ binary->in_frame_info.padded_width);
+}
-#define SCTBL_BYTES(binary) \
- (sizeof(unsigned short) * (binary)->sctbl_height * \
- (binary)->sctbl_aligned_width_per_color * IA_CSS_SC_NUM_COLORS)
+static size_t sctbl_bytes(const struct ia_css_binary *binary)
+{
+ return size_mul(sizeof(unsigned short),
+ array3_size(binary->sctbl_height,
+ binary->sctbl_aligned_width_per_color,
+ IA_CSS_SC_NUM_COLORS));
+}
-#define MORPH_PLANE_BYTES(binary) \
- (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \
- (binary)->morph_tbl_height)
+static size_t morph_plane_bytes(const struct ia_css_binary *binary)
+{
+ return array3_size(SH_CSS_MORPH_TABLE_ELEM_BYTES,
+ binary->morph_tbl_aligned_width,
+ binary->morph_tbl_height);
+}
/* We keep a second copy of the ptr struct for the SP to access.
Again, this would not be necessary on the chip. */
@@ -3279,7 +3289,7 @@ sh_css_params_write_to_ddr_internal(
if (binary->info->sp.enable.fpnr) {
buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl,
&ddr_map_size->fpn_tbl,
- (size_t)(FPNTBL_BYTES(binary)),
+ fpntbl_bytes(binary),
params->config_changed[IA_CSS_FPN_ID],
&err);
if (err) {
@@ -3304,7 +3314,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced = reallocate_buffer(&ddr_map->sc_tbl,
&ddr_map_size->sc_tbl,
- SCTBL_BYTES(binary),
+ sctbl_bytes(binary),
params->sc_table_changed,
&err);
if (err) {
@@ -3538,8 +3548,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced |=
reallocate_buffer(virt_addr_tetra_x[i],
virt_size_tetra_x[i],
- (size_t)
- (MORPH_PLANE_BYTES(binary)),
+ morph_plane_bytes(binary),
params->morph_table_changed,
&err);
if (err) {
@@ -3549,8 +3558,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced |=
reallocate_buffer(virt_addr_tetra_y[i],
virt_size_tetra_y[i],
- (size_t)
- (MORPH_PLANE_BYTES(binary)),
+ morph_plane_bytes(binary),
params->morph_table_changed,
&err);
if (err) {
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig
index 1571eab31926..9faf9d2d4001 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig
+++ b/drivers/staging/media/av7110/Kconfig
@@ -5,7 +5,7 @@ config DVB_AV7110_IR
default DVB_AV7110
config DVB_AV7110
- tristate "AV7110 cards (DEPRECATED)"
+ tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
@@ -35,13 +35,10 @@ config DVB_AV7110
kernel image by adding the filename to the EXTRA_FIRMWARE
configuration option string.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
config DVB_AV7110_OSD
- bool "AV7110 OSD support (DEPRECATED)"
+ bool "AV7110 OSD support"
depends on DVB_AV7110
default y if DVB_AV7110=y || DVB_AV7110=m
help
@@ -52,13 +49,10 @@ config DVB_AV7110_OSD
Anyway, some popular DVB software like VDR uses this OSD to render
its menus, so say Y if you want to use this software.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
All other people say N.
config DVB_BUDGET_PATCH
- tristate "AV7110 cards with Budget Patch (DEPRECATED)"
+ tristate "AV7110 cards with Budget Patch"
depends on DVB_BUDGET_CORE && I2C
depends on DVB_AV7110
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
@@ -74,9 +68,6 @@ config DVB_BUDGET_PATCH
standard AV7110 driver prior to loading this
driver.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
@@ -89,7 +80,7 @@ if DVB_AV7110
# it if we drop support for AV7110, as no other driver will use it.
config DVB_SP8870
- tristate "Spase sp8870 based (DEPRECATED)"
+ tristate "Spase sp8870 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
@@ -100,7 +91,4 @@ config DVB_SP8870
download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
endif
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Makefile b/drivers/staging/media/av7110/Makefile
index c04cd0a59109..307b267598ea 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/Makefile
+++ b/drivers/staging/media/av7110/Makefile
@@ -18,6 +18,5 @@ obj-$(CONFIG_DVB_SP8870) += sp8870.o
ccflags-y += -I $(srctree)/drivers/media/dvb-frontends
ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/pci/ttpci
ccflags-y += -I $(srctree)/drivers/media/common
-ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/ttpci
-ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/common
diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO
new file mode 100644
index 000000000000..60062d8441b3
--- /dev/null
+++ b/drivers/staging/media/av7110/TODO
@@ -0,0 +1,3 @@
+- This driver is too old and relies on a different API.
+ Drop it from Kernel on a couple of versions.
+- Cleanup patches for the drivers here won't be accepted.
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
index 33b5363317f1..33b5363317f1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst
+++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst
index 74093df92a68..74093df92a68 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst
+++ b/drivers/staging/media/av7110/audio-channel-select.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst
index a0ebb0278260..a0ebb0278260 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst
+++ b/drivers/staging/media/av7110/audio-clear-buffer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst
index a2e9850f37f2..a2e9850f37f2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst
+++ b/drivers/staging/media/av7110/audio-continue.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst
index 77857d578e83..77857d578e83 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst
+++ b/drivers/staging/media/av7110/audio-fclose.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst
index 774daaab3bad..774daaab3bad 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst
+++ b/drivers/staging/media/av7110/audio-fopen.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst
index 7b096ac2b6c4..7b096ac2b6c4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst
+++ b/drivers/staging/media/av7110/audio-fwrite.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst
index 6d9eb71dad17..6d9eb71dad17 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst
+++ b/drivers/staging/media/av7110/audio-get-capabilities.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst
index 7ae8db2e65e9..7ae8db2e65e9 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst
+++ b/drivers/staging/media/av7110/audio-get-status.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst
index d37d1ddce4df..d37d1ddce4df 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst
+++ b/drivers/staging/media/av7110/audio-pause.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst
index e591930b6ca7..e591930b6ca7 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst
+++ b/drivers/staging/media/av7110/audio-play.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst
index 6a0c0f365eb1..6a0c0f365eb1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst
+++ b/drivers/staging/media/av7110/audio-select-source.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst
index 85a8016bf025..85a8016bf025 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst
+++ b/drivers/staging/media/av7110/audio-set-av-sync.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
index 80d551a2053a..80d551a2053a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst
+++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst
index 39ad846d412d..39ad846d412d 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst
+++ b/drivers/staging/media/av7110/audio-set-id.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst
index 45dbdf4801e0..45dbdf4801e0 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst
+++ b/drivers/staging/media/av7110/audio-set-mixer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst
index 987751f92967..987751f92967 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst
+++ b/drivers/staging/media/av7110/audio-set-mute.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst
index 77d73c74882f..77d73c74882f 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst
+++ b/drivers/staging/media/av7110/audio-set-streamtype.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst
index d77f786fd797..d77f786fd797 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst
+++ b/drivers/staging/media/av7110/audio-stop.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst
index aa753336b31f..aa753336b31f 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst
+++ b/drivers/staging/media/av7110/audio.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst
index 4744529136a8..4744529136a8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst
+++ b/drivers/staging/media/av7110/audio_data_types.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst
index fa5ba9539caf..fa5ba9539caf 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst
+++ b/drivers/staging/media/av7110/audio_function_calls.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c
index df81a9b744c2..df81a9b744c2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c
+++ b/drivers/staging/media/av7110/av7110.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h
index 9fde69b38f1c..809d938ae166 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h
+++ b/drivers/staging/media/av7110/av7110.h
@@ -33,7 +33,7 @@
#include "stv0297.h"
#include "l64781.h"
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
#define ANALOG_TUNER_VES1820 1
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c
index 0bf513c26b6b..0bf513c26b6b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c
+++ b/drivers/staging/media/av7110/av7110_av.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h
index 71bbd4391f57..71bbd4391f57 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h
+++ b/drivers/staging/media/av7110/av7110_av.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c
index c1338e074a3d..c1338e074a3d 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c
+++ b/drivers/staging/media/av7110/av7110_ca.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h
index a6e3f2955730..a6e3f2955730 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h
+++ b/drivers/staging/media/av7110/av7110_ca.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c
index 93ca31e38ddd..93ca31e38ddd 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c
+++ b/drivers/staging/media/av7110/av7110_hw.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h
index 6380d8950c69..6380d8950c69 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h
+++ b/drivers/staging/media/av7110/av7110_hw.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c
index 30330ed01ce8..30330ed01ce8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c
+++ b/drivers/staging/media/av7110/av7110_ipack.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h
index 943ec899bb93..943ec899bb93 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h
+++ b/drivers/staging/media/av7110/av7110_ipack.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c
index a851ba328e4a..a851ba328e4a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c
+++ b/drivers/staging/media/av7110/av7110_ir.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c
index c89f536f699c..c89f536f699c 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c
+++ b/drivers/staging/media/av7110/av7110_v4l.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c
index d173c8ade6a7..d173c8ade6a7 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c
+++ b/drivers/staging/media/av7110/budget-patch.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c
index 8c2eca5dcdc9..8c2eca5dcdc9 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c
+++ b/drivers/staging/media/av7110/dvb_filter.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h
index 67a3c6333bca..67a3c6333bca 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h
+++ b/drivers/staging/media/av7110/dvb_filter.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c
index 9767159aeb9b..9767159aeb9b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c
+++ b/drivers/staging/media/av7110/sp8870.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h
index 5eacf39f425e..5eacf39f425e 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h
+++ b/drivers/staging/media/av7110/sp8870.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst
index a7730559bbb2..a7730559bbb2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst
+++ b/drivers/staging/media/av7110/video-clear-buffer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst
index cae9445eb3af..cae9445eb3af 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst
+++ b/drivers/staging/media/av7110/video-command.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst
index bc34bf3989e4..bc34bf3989e4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst
+++ b/drivers/staging/media/av7110/video-continue.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst
index e71fa8d6965b..e71fa8d6965b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst
+++ b/drivers/staging/media/av7110/video-fast-forward.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst
index 01d24d548439..01d24d548439 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst
+++ b/drivers/staging/media/av7110/video-fclose.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst
index 1371b083e4e8..1371b083e4e8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst
+++ b/drivers/staging/media/av7110/video-fopen.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst
index 4321f257cb70..4321f257cb70 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst
+++ b/drivers/staging/media/av7110/video-freeze.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst
index a07fd7d7a40e..a07fd7d7a40e 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst
+++ b/drivers/staging/media/av7110/video-fwrite.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst
index 01e09f56656c..01e09f56656c 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst
+++ b/drivers/staging/media/av7110/video-get-capabilities.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst
index 90382bc36cfe..90382bc36cfe 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst
+++ b/drivers/staging/media/av7110/video-get-event.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst
index b48ac8c58a41..b48ac8c58a41 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst
+++ b/drivers/staging/media/av7110/video-get-frame-count.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst
index fedaff41be0b..fedaff41be0b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst
+++ b/drivers/staging/media/av7110/video-get-pts.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst
index de34331c5bd1..de34331c5bd1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst
+++ b/drivers/staging/media/av7110/video-get-size.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst
index 9b86fbf411d4..9b86fbf411d4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst
+++ b/drivers/staging/media/av7110/video-get-status.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst
index 35ac8b98fdbf..35ac8b98fdbf 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst
+++ b/drivers/staging/media/av7110/video-play.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst
index 929a20985d53..929a20985d53 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst
+++ b/drivers/staging/media/av7110/video-select-source.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst
index 70249a6ba125..70249a6ba125 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst
+++ b/drivers/staging/media/av7110/video-set-blank.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst
index 1de4f40ae732..1de4f40ae732 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst
+++ b/drivers/staging/media/av7110/video-set-display-format.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst
index bb64e37ae081..bb64e37ae081 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst
+++ b/drivers/staging/media/av7110/video-set-format.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst
index 1f31c048bdbc..1f31c048bdbc 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst
+++ b/drivers/staging/media/av7110/video-set-streamtype.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst
index 1478fcc30cb8..1478fcc30cb8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst
+++ b/drivers/staging/media/av7110/video-slowmotion.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst
index d25384222a20..d25384222a20 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst
+++ b/drivers/staging/media/av7110/video-stillpicture.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst
index 96f61c5b48a2..96f61c5b48a2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst
+++ b/drivers/staging/media/av7110/video-stop.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst
index 79bf3dfb8a32..79bf3dfb8a32 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst
+++ b/drivers/staging/media/av7110/video-try-command.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video.rst b/drivers/staging/media/av7110/video.rst
index 808705b769a1..808705b769a1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video.rst
+++ b/drivers/staging/media/av7110/video.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst
index 20a897be5dca..20a897be5dca 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst
+++ b/drivers/staging/media/av7110/video_function_calls.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst
index c4557d328b7a..c4557d328b7a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst
+++ b/drivers/staging/media/av7110/video_types.rst
diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig
deleted file mode 100644
index 54154da79f59..000000000000
--- a/drivers/staging/media/deprecated/saa7146/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-source "drivers/staging/media/deprecated/saa7146/common/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/av7110/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig"
diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile
deleted file mode 100644
index 68e7aa10c639..000000000000
--- a/drivers/staging/media/deprecated/saa7146/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
- # SPDX-License-Identifier: GPL-2.0-only
-obj-y += common/ av7110/ saa7146/ ttpci/
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/TODO b/drivers/staging/media/deprecated/saa7146/av7110/TODO
deleted file mode 100644
index 38817e04bb67..000000000000
--- a/drivers/staging/media/deprecated/saa7146/av7110/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-- This driver is too old and relies on a different API.
- Drop it from Kernel on a couple of versions.
-- Cleanup patches for the drivers here won't be accepted.
-
-These drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/TODO b/drivers/staging/media/deprecated/saa7146/saa7146/TODO
deleted file mode 100644
index c9ae2ec79cea..000000000000
--- a/drivers/staging/media/deprecated/saa7146/saa7146/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-The saa7146-based drivers are one of the few drivers still not using
-the vb2 framework, so these drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-In order to keep these drivers they have to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/TODO b/drivers/staging/media/deprecated/saa7146/ttpci/TODO
deleted file mode 100644
index c9ae2ec79cea..000000000000
--- a/drivers/staging/media/deprecated/saa7146/ttpci/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-The saa7146-based drivers are one of the few drivers still not using
-the vb2 framework, so these drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-In order to keep these drivers they have to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 5c3cc7de209d..44d87fe30d52 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -779,11 +779,8 @@ static int csi_start(struct csi_priv *priv)
goto idmac_stop;
/* start the frame interval monitor */
- if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) {
- ret = imx_media_fim_set_stream(priv->fim, output_fi, true);
- if (ret)
- goto idmac_stop;
- }
+ if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC)
+ imx_media_fim_set_stream(priv->fim, output_fi, true);
ret = ipu_csi_enable(priv->csi);
if (ret) {
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index fb6590dcfc36..e28a33d9dec7 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -68,7 +68,10 @@ struct imx_media_fim {
bool stream_on;
};
-#define icap_enabled(fim) ((fim)->icap_flags != IRQ_TYPE_NONE)
+static bool icap_enabled(struct imx_media_fim *fim)
+{
+ return fim->icap_flags != IRQ_TYPE_NONE;
+}
static void update_fim_nominal(struct imx_media_fim *fim,
const struct v4l2_fract *fi)
@@ -368,12 +371,11 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp)
}
/* Called by the subdev in its s_stream callback */
-int imx_media_fim_set_stream(struct imx_media_fim *fim,
- const struct v4l2_fract *fi,
- bool on)
+void imx_media_fim_set_stream(struct imx_media_fim *fim,
+ const struct v4l2_fract *fi,
+ bool on)
{
unsigned long flags;
- int ret = 0;
v4l2_ctrl_lock(fim->ctrl[FIM_CL_ENABLE]);
@@ -393,7 +395,6 @@ int imx_media_fim_set_stream(struct imx_media_fim *fim,
fim->stream_on = on;
out:
v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]);
- return ret;
}
int imx_media_fim_add_controls(struct imx_media_fim *fim)
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index f679249d82e4..6f9a46573edd 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -246,9 +246,9 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
/* imx-media-fim.c */
struct imx_media_fim;
void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp);
-int imx_media_fim_set_stream(struct imx_media_fim *fim,
- const struct v4l2_fract *frame_interval,
- bool on);
+void imx_media_fim_set_stream(struct imx_media_fim *fim,
+ const struct v4l2_fract *frame_interval,
+ bool on);
int imx_media_fim_add_controls(struct imx_media_fim *fim);
struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim);
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index 86ccc8937afc..7b15fc54efe4 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -314,8 +314,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
num_dst_bufs = codec_ops->num_pending_bufs(sess);
num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
- if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9)
- num_dst_bufs -= 3;
+ num_dst_bufs -= 3;
if (esparser_vififo_get_free_space(sess) < payload_size ||
atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 0ad70faa9ba0..05548eab7daa 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -201,39 +201,34 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad)
/* Return a pointer to the ISS video instance at the far end of the pipeline. */
static struct iss_video *
-iss_video_far_end(struct iss_video *video)
+iss_video_far_end(struct iss_video *video, struct iss_pipeline *pipe)
{
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_entity_iter iter;
+ struct media_entity *entity;
struct iss_video *far_end = NULL;
+ int ret;
- mutex_lock(&mdev->graph_mutex);
-
- if (media_graph_walk_init(&graph, mdev)) {
- mutex_unlock(&mdev->graph_mutex);
- return NULL;
- }
+ ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
- media_graph_walk_start(&graph, entity);
+ media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) {
+ struct iss_video *other;
- while ((entity = media_graph_walk_next(&graph))) {
if (entity == &video->video.entity)
continue;
if (!is_media_entity_v4l2_video_device(entity))
continue;
- far_end = to_iss_video(media_entity_to_video_device(entity));
- if (far_end->type != video->type)
+ other = to_iss_video(media_entity_to_video_device(entity));
+ if (other->type != video->type) {
+ far_end = other;
break;
-
- far_end = NULL;
+ }
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
+ media_pipeline_entity_iter_cleanup(&iter);
return far_end;
}
@@ -850,12 +845,12 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct iss_video_fh *vfh = to_iss_video_fh(fh);
struct iss_video *video = video_drvdata(file);
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_device *mdev = video->video.entity.graph_obj.mdev;
+ struct media_pipeline_pad_iter iter;
enum iss_pipeline_state state;
struct iss_pipeline *pipe;
struct iss_video *far_end;
+ struct media_pad *pad;
unsigned long flags;
int ret;
@@ -873,13 +868,9 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe->external_rate = 0;
pipe->external_bpp = 0;
- ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
- if (ret)
- goto err_graph_walk_init;
-
- ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
+ ret = media_entity_enum_init(&pipe->ent_enum, mdev);
if (ret)
- goto err_graph_walk_init;
+ goto err_entity_enum_init;
if (video->iss->pdata->set_constraints)
video->iss->pdata->set_constraints(video->iss, true);
@@ -888,11 +879,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_media_pipeline_start;
- mutex_lock(&mdev->graph_mutex);
- media_graph_walk_start(&graph, entity);
- while ((entity = media_graph_walk_next(&graph)))
- media_entity_enum_set(&pipe->ent_enum, entity);
- mutex_unlock(&mdev->graph_mutex);
+ media_pipeline_for_each_pad(&pipe->pipe, &iter, pad)
+ media_entity_enum_set(&pipe->ent_enum, pad->entity);
/*
* Verify that the currently configured format matches the output of
@@ -909,7 +897,11 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
* Find the ISS video node connected at the far end of the pipeline and
* update the pipeline.
*/
- far_end = iss_video_far_end(video);
+ far_end = iss_video_far_end(video, pipe);
+ if (IS_ERR(far_end)) {
+ ret = PTR_ERR(far_end);
+ goto err_iss_video_check_format;
+ }
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT;
@@ -966,8 +958,6 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
spin_unlock_irqrestore(&video->qlock, flags);
}
- media_graph_walk_cleanup(&graph);
-
mutex_unlock(&video->stream_lock);
return 0;
@@ -981,9 +971,7 @@ err_media_pipeline_start:
video->iss->pdata->set_constraints(video->iss, false);
video->queue = NULL;
- media_graph_walk_cleanup(&graph);
-
-err_graph_walk_init:
+err_entity_enum_init:
media_entity_enum_cleanup(&pipe->ent_enum);
mutex_unlock(&video->stream_lock);
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146.h b/include/media/drv-intf/saa7146.h
index 71ce63c99cb4..71ce63c99cb4 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146.h
+++ b/include/media/drv-intf/saa7146.h
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h
index d7bd916fe3ad..635805fb35e8 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h
+++ b/include/media/drv-intf/saa7146_vv.h
@@ -5,8 +5,8 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fh.h>
+#include <media/drv-intf/saa7146.h>
#include <media/videobuf-dma-sg.h>
-#include "saa7146.h"
#define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */
#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
diff --git a/include/media/i2c/s5c73m3.h b/include/media/i2c/s5c73m3.h
deleted file mode 100644
index df0769d64523..000000000000
--- a/include/media/i2c/s5c73m3.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Samsung LSI S5C73M3 8M pixel camera driver
- *
- * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
- * Andrzej Hajda <a.hajda@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#ifndef MEDIA_S5C73M3__
-#define MEDIA_S5C73M3__
-
-#include <linux/videodev2.h>
-#include <media/v4l2-mediabus.h>
-
-/**
- * struct s5c73m3_platform_data - s5c73m3 driver platform data
- * @mclk_frequency: sensor's master clock frequency in Hz
- * @bus_type: bus type
- * @nlanes: maximum number of MIPI-CSI lanes used
- * @horiz_flip: default horizontal image flip value, non zero to enable
- * @vert_flip: default vertical image flip value, non zero to enable
- */
-
-struct s5c73m3_platform_data {
- unsigned long mclk_frequency;
-
- enum v4l2_mbus_type bus_type;
- u8 nlanes;
- u8 horiz_flip;
- u8 vert_flip;
-};
-
-#endif /* MEDIA_S5C73M3__ */
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 47863e8fde7b..741f9c629c6f 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -131,6 +131,26 @@ struct media_pipeline_pad {
};
/**
+ * struct media_pipeline_pad_iter - Iterator for media_pipeline_for_each_pad
+ *
+ * @cursor: The current element
+ */
+struct media_pipeline_pad_iter {
+ struct list_head *cursor;
+};
+
+/**
+ * struct media_pipeline_entity_iter - Iterator for media_pipeline_for_each_entity
+ *
+ * @ent_enum: The entity enumeration tracker
+ * @cursor: The current element
+ */
+struct media_pipeline_entity_iter {
+ struct media_entity_enum ent_enum;
+ struct list_head *cursor;
+};
+
+/**
* struct media_link - A link object part of a media graph.
*
* @graph_obj: Embedded structure containing the media object common data
@@ -1068,6 +1088,8 @@ int media_entity_get_fwnode_pad(struct media_entity *entity,
* @graph: Media graph structure that will be used to walk the graph
* @mdev: Pointer to the &media_device that contains the object
*
+ * This function is deprecated, use media_pipeline_for_each_pad() instead.
+ *
* The caller is required to hold the media_device graph_mutex during the graph
* walk until the graph state is released.
*
@@ -1080,6 +1102,8 @@ __must_check int media_graph_walk_init(
* media_graph_walk_cleanup - Release resources used by graph walk.
*
* @graph: Media graph structure that will be used to walk the graph
+ *
+ * This function is deprecated, use media_pipeline_for_each_pad() instead.
*/
void media_graph_walk_cleanup(struct media_graph *graph);
@@ -1090,6 +1114,8 @@ void media_graph_walk_cleanup(struct media_graph *graph);
* @graph: Media graph structure that will be used to walk the graph
* @entity: Starting entity
*
+ * This function is deprecated, use media_pipeline_for_each_pad() instead.
+ *
* Before using this function, media_graph_walk_init() must be
* used to allocate resources used for walking the graph. This
* function initializes the graph traversal structure to walk the
@@ -1105,6 +1131,8 @@ void media_graph_walk_start(struct media_graph *graph,
* media_graph_walk_next - Get the next entity in the graph
* @graph: Media graph structure
*
+ * This function is deprecated, use media_pipeline_for_each_pad() instead.
+ *
* Perform a depth-first traversal of the given media entities graph.
*
* The graph structure must have been previously initialized with a call to
@@ -1165,6 +1193,76 @@ void media_pipeline_stop(struct media_pad *pad);
*/
void __media_pipeline_stop(struct media_pad *pad);
+struct media_pad *
+__media_pipeline_pad_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_pad_iter *iter,
+ struct media_pad *pad);
+
+/**
+ * media_pipeline_for_each_pad - Iterate on all pads in a media pipeline
+ * @pipe: The pipeline
+ * @iter: The iterator (struct media_pipeline_pad_iter)
+ * @pad: The iterator pad
+ *
+ * Iterate on all pads in a media pipeline. This is only valid after the
+ * pipeline has been built with media_pipeline_start() and before it gets
+ * destroyed with media_pipeline_stop().
+ */
+#define media_pipeline_for_each_pad(pipe, iter, pad) \
+ for (pad = __media_pipeline_pad_iter_next((pipe), iter, NULL); \
+ pad != NULL; \
+ pad = __media_pipeline_pad_iter_next((pipe), iter, pad))
+
+/**
+ * media_pipeline_entity_iter_init - Initialize a pipeline entity iterator
+ * @pipe: The pipeline
+ * @iter: The iterator
+ *
+ * This function must be called to initialize the iterator before using it in a
+ * media_pipeline_for_each_entity() loop. The iterator must be destroyed by a
+ * call to media_pipeline_entity_iter_cleanup after the loop (including in code
+ * paths that break from the loop).
+ *
+ * The same iterator can be used in multiple consecutive loops without being
+ * destroyed and reinitialized.
+ *
+ * Return: 0 on success or a negative error code otherwise.
+ */
+int media_pipeline_entity_iter_init(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter);
+
+/**
+ * media_pipeline_entity_iter_cleanup - Destroy a pipeline entity iterator
+ * @iter: The iterator
+ *
+ * This function must be called to destroy iterators initialized with
+ * media_pipeline_entity_iter_init().
+ */
+void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter);
+
+struct media_entity *
+__media_pipeline_entity_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter,
+ struct media_entity *entity);
+
+/**
+ * media_pipeline_for_each_entity - Iterate on all entities in a media pipeline
+ * @pipe: The pipeline
+ * @iter: The iterator (struct media_pipeline_entity_iter)
+ * @entity: The iterator entity
+ *
+ * Iterate on all entities in a media pipeline. This is only valid after the
+ * pipeline has been built with media_pipeline_start() and before it gets
+ * destroyed with media_pipeline_stop(). The iterator must be initialized with
+ * media_pipeline_entity_iter_init() before iteration, and destroyed with
+ * media_pipeline_entity_iter_cleanup() after (including in code paths that
+ * break from the loop).
+ */
+#define media_pipeline_for_each_entity(pipe, iter, entity) \
+ for (entity = __media_pipeline_entity_iter_next((pipe), iter, NULL); \
+ entity != NULL; \
+ entity = __media_pipeline_entity_iter_next((pipe), iter, entity))
+
/**
* media_pipeline_alloc_start - Mark a pipeline as streaming
* @pad: Starting pad
diff --git a/include/media/ov_16bit_addr_reg_helpers.h b/include/media/ov_16bit_addr_reg_helpers.h
new file mode 100644
index 000000000000..1c60a50bd795
--- /dev/null
+++ b/include/media/ov_16bit_addr_reg_helpers.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * I2C register access helpers for Omnivision OVxxxx image sensors which expect
+ * a 16 bit register address in big-endian format and which have 1-3 byte
+ * wide registers, in big-endian format (for the higher width registers).
+ *
+ * Based on the register helpers from drivers/media/i2c/ov2680.c which is:
+ * Copyright (C) 2018 Linaro Ltd
+ */
+#ifndef __OV_16BIT_ADDR_REG_HELPERS_H
+#define __OV_16BIT_ADDR_REG_HELPERS_H
+
+#include <asm/unaligned.h>
+#include <linux/dev_printk.h>
+#include <linux/i2c.h>
+
+static inline int ov_read_reg(struct i2c_client *client, u16 reg,
+ unsigned int len, u32 *val)
+{
+ u8 addr_buf[2], data_buf[4] = { };
+ struct i2c_msg msgs[2];
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, addr_buf);
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = ARRAY_SIZE(addr_buf);
+ msgs[0].buf = addr_buf;
+
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_buf[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret);
+ return -EIO;
+ }
+
+ *val = get_unaligned_be32(data_buf);
+
+ return 0;
+}
+
+#define ov_read_reg8(s, r, v) ov_read_reg(s, r, 1, v)
+#define ov_read_reg16(s, r, v) ov_read_reg(s, r, 2, v)
+#define ov_read_reg24(s, r, v) ov_read_reg(s, r, 3, v)
+
+static inline int ov_write_reg(struct i2c_client *client, u16 reg,
+ unsigned int len, u32 val)
+{
+ u8 buf[6];
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+ ret = i2c_master_send(client, buf, len + 2);
+ if (ret != len + 2) {
+ dev_err(&client->dev, "write error: reg=0x%4x: %d\n", reg, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#define ov_write_reg8(s, r, v) ov_write_reg(s, r, 1, v)
+#define ov_write_reg16(s, r, v) ov_write_reg(s, r, 2, v)
+#define ov_write_reg24(s, r, v) ov_write_reg(s, r, 3, v)
+
+static inline int ov_update_reg(struct i2c_client *client, u16 reg, u8 mask, u8 val)
+{
+ u32 readval;
+ int ret;
+
+ ret = ov_read_reg8(client, reg, &readval);
+ if (ret < 0)
+ return ret;
+
+ val = (readval & ~mask) | (val & mask);
+
+ return ov_write_reg8(client, reg, val);
+}
+
+#endif