whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 134bf98c5596605af90f104716ef912e8f7eb56b
parent 044ee890286153a1aefb40cb8b6659921aecb38b
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Mon, 29 Oct 2018 14:29:58 -0700

Merge tag 'media/v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - new dvb frontend driver: lnbh29

 - new sensor drivers: imx319 and imx 355

 - some old soc_camera driver renames to avoid conflict with new
   drivers

 - new i.MX Pixel Pipeline (PXP) mem-to-mem platform driver

 - a new V4L2 frontend for the FWHT codec

 - several other improvements, bug fixes, code cleanups, etc

* tag 'media/v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (289 commits)
  media: rename soc_camera I2C drivers
  media: cec: forgot to cancel delayed work
  media: vivid: Support 480p for webcam capture
  media: v4l2-tpg: fix kernel oops when enabling HFLIP and OSD
  media: vivid: Add 16-bit bayer to format list
  media: v4l2-tpg-core: Add 16-bit bayer
  media: pvrusb2: replace `printk` with `pr_*`
  media: venus: vdec: fix decoded data size
  media: cx231xx: fix potential sign-extension overflow on large shift
  media: dt-bindings: media: rcar_vin: add device tree support for r8a7744
  media: isif: fix a NULL pointer dereference bug
  media: exynos4-is: make const array config_ids static
  media: cx23885: make const array addr_list static
  media: ivtv: make const array addr_list static
  media: bttv-input: make const array addr_list static
  media: cx18: Don't check for address of video_dev
  media: dw9807-vcm: Fix probe error handling
  media: dw9714: Remove useless error message
  media: dw9714: Fix error handling in probe function
  media: cec: name for RC passthrough device does not need 'RC for'
  ...

Diffstat:
ADocumentation/devicetree/bindings/media/fsl-pxp.txt | 26++++++++++++++++++++++++++
MDocumentation/devicetree/bindings/media/i2c/adv748x.txt | 20++++++++++++++++----
MDocumentation/devicetree/bindings/media/i2c/adv7604.txt | 2+-
RDocumentation/devicetree/bindings/media/i2c/dongwoon,dw9807.txt -> Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.txt | 0
MDocumentation/devicetree/bindings/media/rcar_vin.txt | 1+
MDocumentation/devicetree/bindings/media/renesas,ceu.txt | 14+++++++++-----
MDocumentation/devicetree/bindings/media/video-interfaces.txt | 4+++-
MDocumentation/media/kapi/cec-core.rst | 4++++
MDocumentation/media/kapi/v4l2-subdev.rst | 30+++++++++++++++++++-----------
MDocumentation/media/uapi/cec/cec-func-poll.rst | 3++-
MDocumentation/media/uapi/cec/cec-ioc-receive.rst | 25+++++++++++++++++++++++--
MDocumentation/media/uapi/mediactl/media-ioc-device-info.rst | 1+
MDocumentation/media/uapi/mediactl/media-ioc-enum-entities.rst | 1+
MDocumentation/media/uapi/mediactl/media-ioc-enum-links.rst | 1+
MDocumentation/media/uapi/mediactl/media-ioc-g-topology.rst | 1+
MDocumentation/media/uapi/mediactl/media-ioc-setup-link.rst | 1+
MDocumentation/media/uapi/v4l/biblio.rst | 10----------
MDocumentation/media/uapi/v4l/colorspaces-defs.rst | 8++++----
MDocumentation/media/uapi/v4l/colorspaces-details.rst | 13++++++-------
MDocumentation/media/uapi/v4l/func-poll.rst | 3++-
MDocumentation/media/uapi/v4l/meta-formats.rst | 1+
MDocumentation/media/uapi/v4l/pixfmt-compressed.rst | 2+-
ADocumentation/media/uapi/v4l/pixfmt-meta-d4xx.rst | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MDocumentation/media/uapi/v4l/vidioc-cropcap.rst | 2+-
MDocumentation/media/uapi/v4l/vidioc-dqevent.rst | 12+++++++++++-
MDocumentation/media/uapi/v4l/vidioc-g-crop.rst | 2+-
MDocumentation/media/uapi/v4l/vidioc-g-dv-timings.rst | 27+++++++++++++++++++--------
MDocumentation/media/videodev2.h.rst.exceptions | 7+++++--
MMAINTAINERS | 44++++++++++++++++++++++++++++++++------------
March/arm/boot/dts/gr-peach-audiocamerashield.dtsi | 4----
Mdrivers/gpu/ipu-v3/ipu-csi.c | 6+++---
Mdrivers/hid/hid-picolcd_cir.c | 3+--
Mdrivers/media/cec/Makefile | 2+-
Mdrivers/media/cec/cec-adap.c | 107++++++++++++++++++++++++++++++-------------------------------------------------
Mdrivers/media/cec/cec-api.c | 24+++++++++++++++++++++---
Mdrivers/media/cec/cec-core.c | 8+++-----
Ddrivers/media/cec/cec-edid.c | 155-------------------------------------------------------------------------------
Mdrivers/media/cec/cec-pin.c | 20++++++++++++++++++++
Mdrivers/media/common/b2c2/flexcop-i2c.c | 12++++++------
Mdrivers/media/common/cx2341x.c | 2+-
Mdrivers/media/common/saa7146/saa7146_fops.c | 2+-
Mdrivers/media/common/saa7146/saa7146_video.c | 8++++----
Mdrivers/media/common/siano/smscoreapi.c | 4++--
Mdrivers/media/common/siano/smsir.c | 10+++++-----
Mdrivers/media/common/v4l2-tpg/v4l2-tpg-colors.c | 262++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdrivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 41++++++++++++++++++++++++++++++++++++++---
Mdrivers/media/common/videobuf2/videobuf2-core.c | 9+++++++++
Mdrivers/media/dvb-core/dmxdev.c | 1+
Mdrivers/media/dvb-core/dvb_frontend.c | 2+-
Mdrivers/media/dvb-core/dvb_vb2.c | 2+-
Mdrivers/media/dvb-core/dvbdev.c | 23++++++++++++++++-------
Mdrivers/media/dvb-frontends/Kconfig | 10++++++++++
Mdrivers/media/dvb-frontends/Makefile | 1+
Mdrivers/media/dvb-frontends/au8522_decoder.c | 10++++++----
Mdrivers/media/dvb-frontends/au8522_priv.h | 9++++++++-
Mdrivers/media/dvb-frontends/cx24123.c | 2+-
Mdrivers/media/dvb-frontends/cxd2099.c | 3++-
Mdrivers/media/dvb-frontends/cxd2099.h | 1+
Mdrivers/media/dvb-frontends/cxd2820r_core.c | 2+-
Mdrivers/media/dvb-frontends/dibx000_common.c | 2+-
Mdrivers/media/dvb-frontends/drx39xyj/drxj.c | 10+++++-----
Mdrivers/media/dvb-frontends/lgdt330x.c | 2+-
Adrivers/media/dvb-frontends/lnbh29.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/dvb-frontends/lnbh29.h | 36++++++++++++++++++++++++++++++++++++
Mdrivers/media/dvb-frontends/m88ds3103.c | 2+-
Mdrivers/media/dvb-frontends/mt312.c | 9++++++---
Mdrivers/media/dvb-frontends/mxl5xx.c | 5+++--
Mdrivers/media/dvb-frontends/mxl5xx.h | 22++++++++++++++++++++++
Mdrivers/media/dvb-frontends/mxl5xx_defs.h | 1+
Mdrivers/media/dvb-frontends/mxl5xx_regs.h | 1+
Mdrivers/media/dvb-frontends/rtl2832_sdr.c | 10+++++-----
Mdrivers/media/dvb-frontends/s5h1420.c | 2+-
Mdrivers/media/dvb-frontends/stv0910.c | 3++-
Mdrivers/media/dvb-frontends/stv0910.h | 18++++++++++++++++++
Mdrivers/media/dvb-frontends/stv0910_regs.h | 1+
Mdrivers/media/dvb-frontends/stv6111.c | 4++--
Mdrivers/media/dvb-frontends/stv6111.h | 16++++++++++++++++
Mdrivers/media/dvb-frontends/tc90522.c | 2+-
Mdrivers/media/dvb-frontends/ts2020.c | 2+-
Mdrivers/media/dvb-frontends/zd1301_demod.c | 3++-
Mdrivers/media/dvb-frontends/zl10039.c | 5+++--
Mdrivers/media/firewire/firedtv-fe.c | 2+-
Mdrivers/media/i2c/Kconfig | 24++++++++++++++++++++++++
Mdrivers/media/i2c/Makefile | 2++
Mdrivers/media/i2c/ad5820.c | 2+-
Mdrivers/media/i2c/adv7180.c | 13++-----------
Mdrivers/media/i2c/adv748x/adv748x-afe.c | 8++------
Mdrivers/media/i2c/adv748x/adv748x-core.c | 93+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdrivers/media/i2c/adv748x/adv748x-csi2.c | 35++++++++++-------------------------
Mdrivers/media/i2c/adv748x/adv748x-hdmi.c | 8++------
Mdrivers/media/i2c/adv748x/adv748x.h | 25+++++++++++++++----------
Mdrivers/media/i2c/adv7511.c | 6+++---
Mdrivers/media/i2c/adv7604.c | 12+++++++-----
Mdrivers/media/i2c/adv7842.c | 17++++++++++++++---
Mdrivers/media/i2c/ak881x.c | 1-
Mdrivers/media/i2c/cs53l32a.c | 2+-
Mdrivers/media/i2c/cx25840/cx25840-ir.c | 6++----
Mdrivers/media/i2c/dw9714.c | 5+++--
Mdrivers/media/i2c/dw9807-vcm.c | 4++--
Mdrivers/media/i2c/imx274.c | 165+++++++++++++++++++++++++++++++++++--------------------------------------------
Adrivers/media/i2c/imx319.c | 2560+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/imx355.c | 1860+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/media/i2c/lm3560.c | 3++-
Mdrivers/media/i2c/lm3646.c | 3++-
Mdrivers/media/i2c/m5mols/m5mols_core.c | 3++-
Mdrivers/media/i2c/max2175.c | 12++----------
Mdrivers/media/i2c/max2175.h | 12++----------
Mdrivers/media/i2c/msp3400-driver.c | 8+++++---
Mdrivers/media/i2c/msp3400-driver.h | 8+++++++-
Mdrivers/media/i2c/mt9m111.c | 1-
Mdrivers/media/i2c/mt9t112.c | 6------
Mdrivers/media/i2c/mt9v032.c | 2+-
Mdrivers/media/i2c/noon010pc30.c | 3++-
Mdrivers/media/i2c/ov13858.c | 12++----------
Mdrivers/media/i2c/ov2640.c | 1-
Mdrivers/media/i2c/ov2659.c | 14++++++++------
Mdrivers/media/i2c/ov2680.c | 16+++++-----------
Mdrivers/media/i2c/ov2685.c | 2+-
Mdrivers/media/i2c/ov5640.c | 309++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mdrivers/media/i2c/ov5645.c | 2+-
Mdrivers/media/i2c/ov5647.c | 2+-
Mdrivers/media/i2c/ov5670.c | 12++----------
Mdrivers/media/i2c/ov5695.c | 2+-
Mdrivers/media/i2c/ov6650.c | 1-
Mdrivers/media/i2c/ov7251.c | 4++--
Mdrivers/media/i2c/ov7670.c | 29++++++++++++++++++-----------
Mdrivers/media/i2c/ov772x.c | 194+++++++++++++++++++++++++++++++++----------------------------------------------
Mdrivers/media/i2c/ov7740.c | 2+-
Mdrivers/media/i2c/ov9650.c | 161++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mdrivers/media/i2c/rj54n1cb0c.c | 1-
Mdrivers/media/i2c/s5c73m3/s5c73m3-core.c | 9+++++----
Mdrivers/media/i2c/s5k4ecgx.c | 3++-
Mdrivers/media/i2c/s5k5baf.c | 6+++---
Mdrivers/media/i2c/s5k6aa.c | 5+++--
Mdrivers/media/i2c/saa7115.c | 24++++++++++++++++--------
Mdrivers/media/i2c/saa7127.c | 4++--
Mdrivers/media/i2c/smiapp/smiapp-core.c | 48+++++++++++++++++++++++++-----------------------
Mdrivers/media/i2c/soc_camera/Makefile | 18+++++++++---------
Ddrivers/media/i2c/soc_camera/mt9m001.c | 758-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/mt9t112.c | 1163-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/mt9v022.c | 1013-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/ov5642.c | 1088-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/ov772x.c | 1124-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/ov9640.c | 739-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/ov9740.c | 997-------------------------------------------------------------------------------
Ddrivers/media/i2c/soc_camera/rj54n1cb0c.c | 1416-------------------------------------------------------------------------------
Adrivers/media/i2c/soc_camera/soc_mt9m001.c | 757+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_mt9t112.c | 1157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_mt9v022.c | 1012+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_ov5642.c | 1087+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_ov772x.c | 1123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_ov9640.c | 738+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_ov9740.c | 996+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/i2c/soc_camera/soc_rj54n1cb0c.c | 1415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rdrivers/media/i2c/soc_camera/tw9910.c -> drivers/media/i2c/soc_camera/soc_tw9910.c | 0
Mdrivers/media/i2c/sr030pc30.c | 3+--
Mdrivers/media/i2c/tc358743.c | 34++++++++++++++++++----------------
Mdrivers/media/i2c/tda1997x.c | 2+-
Mdrivers/media/i2c/tvaudio.c | 2+-
Mdrivers/media/i2c/tvp514x.c | 2+-
Mdrivers/media/i2c/tvp5150.c | 560++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mdrivers/media/i2c/tvp5150_reg.h | 3+++
Mdrivers/media/i2c/tvp7002.c | 2+-
Mdrivers/media/i2c/video-i2c.c | 8++++----
Mdrivers/media/media-device.c | 28++++++++++++++--------------
Mdrivers/media/media-entity.c | 26++++++++++++++++++++++++++
Mdrivers/media/pci/bt8xx/bttv-driver.c | 11+++++------
Mdrivers/media/pci/bt8xx/bttv-i2c.c | 6+++---
Mdrivers/media/pci/bt8xx/bttv-input.c | 4++--
Mdrivers/media/pci/bt8xx/dvb-bt8xx.c | 3++-
Mdrivers/media/pci/cobalt/cobalt-alsa-main.c | 2+-
Mdrivers/media/pci/cobalt/cobalt-alsa-pcm.c | 4++--
Mdrivers/media/pci/cobalt/cobalt-v4l2.c | 23++++++++++++++---------
Mdrivers/media/pci/cx18/cx18-alsa-main.c | 2+-
Mdrivers/media/pci/cx18/cx18-alsa-pcm.c | 2+-
Mdrivers/media/pci/cx18/cx18-cards.c | 8++++----
Mdrivers/media/pci/cx18/cx18-driver.c | 4++--
Mdrivers/media/pci/cx18/cx18-i2c.c | 2+-
Mdrivers/media/pci/cx18/cx18-ioctl.c | 8++++----
Mdrivers/media/pci/cx23885/altera-ci.c | 10++++++++++
Mdrivers/media/pci/cx23885/cx23885-417.c | 8++++----
Mdrivers/media/pci/cx23885/cx23885-alsa.c | 4++--
Mdrivers/media/pci/cx23885/cx23885-dvb.c | 54+++++++++++++++++++++++++++---------------------------
Mdrivers/media/pci/cx23885/cx23885-i2c.c | 6+++---
Mdrivers/media/pci/cx23885/cx23885-ioctl.c | 4++--
Mdrivers/media/pci/cx23885/cx23885-video.c | 15++++++++-------
Mdrivers/media/pci/cx23885/cx23888-ir.c | 6++----
Mdrivers/media/pci/cx25821/cx25821-alsa.c | 8++++----
Mdrivers/media/pci/cx25821/cx25821-i2c.c | 2+-
Mdrivers/media/pci/cx25821/cx25821-video.c | 10+++++-----
Mdrivers/media/pci/cx88/cx88-alsa.c | 6+++---
Mdrivers/media/pci/cx88/cx88-blackbird.c | 6+++---
Mdrivers/media/pci/cx88/cx88-cards.c | 2+-
Mdrivers/media/pci/cx88/cx88-i2c.c | 4++--
Mdrivers/media/pci/cx88/cx88-input.c | 7+++----
Mdrivers/media/pci/cx88/cx88-video.c | 12++++++------
Mdrivers/media/pci/cx88/cx88-vp3054-i2c.c | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-ci.c | 4+---
Mdrivers/media/pci/ddbridge/ddbridge-ci.h | 4+---
Mdrivers/media/pci/ddbridge/ddbridge-core.c | 6+-----
Mdrivers/media/pci/ddbridge/ddbridge-hw.c | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-hw.h | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-i2c.c | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-i2c.h | 4++--
Mdrivers/media/pci/ddbridge/ddbridge-io.h | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-main.c | 4++--
Mdrivers/media/pci/ddbridge/ddbridge-max.c | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-max.h | 2+-
Mdrivers/media/pci/ddbridge/ddbridge-regs.h | 5+----
Mdrivers/media/pci/ddbridge/ddbridge-sx8.c | 4+---
Mdrivers/media/pci/ddbridge/ddbridge.h | 5+----
Mdrivers/media/pci/dm1105/dm1105.c | 5+++--
Mdrivers/media/pci/dt3155/dt3155.c | 8++++----
Mdrivers/media/pci/intel/ipu3/ipu3-cio2.c | 30+++++++++++++++---------------
Mdrivers/media/pci/ivtv/ivtv-alsa-main.c | 2+-
Mdrivers/media/pci/ivtv/ivtv-alsa-pcm.c | 2+-
Mdrivers/media/pci/ivtv/ivtv-cards.c | 12++++++------
Mdrivers/media/pci/ivtv/ivtv-i2c.c | 6+++---
Mdrivers/media/pci/ivtv/ivtv-ioctl.c | 42++++++++++++++++++++++++++++++++++++------
Mdrivers/media/pci/ivtv/ivtv-streams.c | 9+++++++++
Mdrivers/media/pci/ivtv/ivtv-yuv.c | 2+-
Mdrivers/media/pci/ivtv/ivtvfb.c | 2+-
Mdrivers/media/pci/meye/meye.c | 12++++++------
Mdrivers/media/pci/ngene/ngene-i2c.c | 2+-
Mdrivers/media/pci/pluto2/pluto2.c | 2+-
Mdrivers/media/pci/pt1/pt1.c | 2+-
Mdrivers/media/pci/pt3/pt3.c | 2+-
Mdrivers/media/pci/saa7134/saa7134-alsa.c | 8++++----
Mdrivers/media/pci/saa7134/saa7134-cards.c | 15+++++++++++++++
Mdrivers/media/pci/saa7134/saa7134-core.c | 9+++++----
Mdrivers/media/pci/saa7134/saa7134-empress.c | 2+-
Mdrivers/media/pci/saa7134/saa7134-go7007.c | 2+-
Mdrivers/media/pci/saa7134/saa7134-i2c.c | 2+-
Mdrivers/media/pci/saa7134/saa7134-input.c | 2+-
Mdrivers/media/pci/saa7134/saa7134-video.c | 15++++++++-------
Mdrivers/media/pci/saa7134/saa7134.h | 8+++++++-
Mdrivers/media/pci/saa7146/mxb.c | 2+-
Mdrivers/media/pci/saa7164/saa7164-core.c | 2+-
Mdrivers/media/pci/saa7164/saa7164-dvb.c | 10+++++-----
Mdrivers/media/pci/saa7164/saa7164-encoder.c | 10+++++-----
Mdrivers/media/pci/saa7164/saa7164-i2c.c | 2+-
Mdrivers/media/pci/saa7164/saa7164-vbi.c | 4++--
Mdrivers/media/pci/smipcie/smipcie-main.c | 12++++++------
Mdrivers/media/pci/solo6x10/solo6x10-g723.c | 8++++----
Mdrivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | 12+++++++-----
Mdrivers/media/pci/solo6x10/solo6x10-v4l2.c | 6+++---
Mdrivers/media/pci/sta2x11/sta2x11_vip.c | 6+++---
Mdrivers/media/pci/ttpci/av7110.c | 3++-
Mdrivers/media/pci/ttpci/av7110_av.c | 58+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mdrivers/media/pci/ttpci/av7110_v4l.c | 2+-
Mdrivers/media/pci/ttpci/budget-core.c | 6++++--
Mdrivers/media/pci/tw5864/tw5864-video.c | 2+-
Mdrivers/media/pci/tw68/tw68-video.c | 6+++---
Mdrivers/media/pci/tw686x/tw686x-audio.c | 8++++----
Mdrivers/media/pci/tw686x/tw686x-video.c | 4++--
Mdrivers/media/platform/Kconfig | 10++++++++++
Mdrivers/media/platform/Makefile | 2++
Mdrivers/media/platform/am437x/am437x-vpfe.c | 93++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mdrivers/media/platform/atmel/atmel-isc.c | 26++++++++++++++++++--------
Mdrivers/media/platform/atmel/atmel-isi.c | 29+++++++++++++----------------
Mdrivers/media/platform/cadence/cdns-csi2rx.c | 32+++++++++++++++++++-------------
Mdrivers/media/platform/cadence/cdns-csi2tx.c | 4++--
Mdrivers/media/platform/coda/coda-common.c | 14+++++++-------
Mdrivers/media/platform/davinci/isif.c | 3++-
Mdrivers/media/platform/davinci/vpbe_display.c | 10++++++----
Mdrivers/media/platform/davinci/vpbe_venc.c | 2+-
Mdrivers/media/platform/davinci/vpfe_capture.c | 6+++---
Mdrivers/media/platform/davinci/vpif_capture.c | 88++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mdrivers/media/platform/davinci/vpif_display.c | 29++++++++++++++++++++++-------
Mdrivers/media/platform/exynos-gsc/gsc-core.c | 2+-
Mdrivers/media/platform/exynos-gsc/gsc-m2m.c | 4++--
Mdrivers/media/platform/exynos4-is/common.c | 4++--
Mdrivers/media/platform/exynos4-is/fimc-capture.c | 2+-
Mdrivers/media/platform/exynos4-is/fimc-is-i2c.c | 2+-
Mdrivers/media/platform/exynos4-is/fimc-is.c | 2+-
Mdrivers/media/platform/exynos4-is/fimc-isp-video.c | 2+-
Mdrivers/media/platform/exynos4-is/fimc-lite.c | 6+++---
Mdrivers/media/platform/exynos4-is/media-dev.c | 42++++++++++++++++++++++++++++--------------
Mdrivers/media/platform/exynos4-is/media-dev.h | 1-
Mdrivers/media/platform/exynos4-is/mipi-csis.c | 2+-
Mdrivers/media/platform/fsl-viu.c | 8++++----
Adrivers/media/platform/imx-pxp.c | 1754+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/platform/imx-pxp.h | 1685+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/media/platform/m2m-deinterlace.c | 8++++----
Mdrivers/media/platform/marvell-ccic/cafe-driver.c | 2+-
Mdrivers/media/platform/marvell-ccic/mcam-core.c | 16++++++++--------
Mdrivers/media/platform/marvell-ccic/mmp-driver.c | 4++--
Mdrivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 4++--
Mdrivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 6+++---
Mdrivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 6+++---
Mdrivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 6+++---
Mdrivers/media/platform/mtk-vcodec/mtk_vcodec_util.c | 5+----
Mdrivers/media/platform/mtk-vpu/mtk_vpu.c | 7+++----
Mdrivers/media/platform/mx2_emmaprp.c | 2+-
Mdrivers/media/platform/omap/omap_vout.c | 10+++++-----
Mdrivers/media/platform/omap3isp/isp.c | 5+++--
Mdrivers/media/platform/omap3isp/ispccdc.c | 2+-
Mdrivers/media/platform/omap3isp/ispccp2.c | 2+-
Mdrivers/media/platform/omap3isp/ispcsi2.c | 2+-
Mdrivers/media/platform/omap3isp/isppreview.c | 2+-
Mdrivers/media/platform/omap3isp/ispresizer.c | 2+-
Mdrivers/media/platform/omap3isp/ispvideo.c | 8++++----
Mdrivers/media/platform/pxa_camera.c | 39++++++++++++++++++++++-----------------
Mdrivers/media/platform/qcom/camss/camss-video.c | 8++++----
Mdrivers/media/platform/qcom/camss/camss.c | 91+++++++++++++++++++++++++++++++++++++------------------------------------------
Mdrivers/media/platform/qcom/camss/camss.h | 3+--
Mdrivers/media/platform/qcom/venus/helpers.c | 2+-
Mdrivers/media/platform/qcom/venus/vdec.c | 11+++++------
Mdrivers/media/platform/qcom/venus/venc.c | 8++++----
Mdrivers/media/platform/rcar-vin/rcar-core.c | 11+++++++----
Mdrivers/media/platform/rcar-vin/rcar-csi2.c | 26+++++++++++++++-----------
Mdrivers/media/platform/rcar-vin/rcar-v4l2.c | 8++++----
Mdrivers/media/platform/rcar_drif.c | 22+++++++++++++---------
Mdrivers/media/platform/rcar_fdp1.c | 6+++---
Mdrivers/media/platform/rcar_jpu.c | 10+++++-----
Mdrivers/media/platform/renesas-ceu.c | 78+++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mdrivers/media/platform/rockchip/rga/rga.c | 6+++---
Mdrivers/media/platform/s3c-camif/camif-capture.c | 10+++++-----
Mdrivers/media/platform/s3c-camif/camif-core.c | 4++--
Mdrivers/media/platform/s5p-jpeg/jpeg-core.c | 10+++++-----
Mdrivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 6+++---
Mdrivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 6+++---
Mdrivers/media/platform/sh_veu.c | 9+++++----
Mdrivers/media/platform/sh_vou.c | 10+++++-----
Mdrivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 6+++---
Mdrivers/media/platform/soc_camera/soc_camera.c | 43+++++++++++++++++++++++++++++--------------
Mdrivers/media/platform/soc_camera/soc_camera_platform.c | 2+-
Mdrivers/media/platform/soc_camera/soc_mediabus.c | 2+-
Mdrivers/media/platform/soc_camera/soc_scale_crop.c | 2+-
Mdrivers/media/platform/sti/bdisp/bdisp-v4l2.c | 4++--
Mdrivers/media/platform/sti/delta/delta-v4l2.c | 4++--
Mdrivers/media/platform/sti/hva/hva-v4l2.c | 4++--
Mdrivers/media/platform/stm32/stm32-dcmi.c | 43+++++++++++++++++++++++--------------------
Mdrivers/media/platform/ti-vpe/cal.c | 61+++++++++++++++++++++++++++++++++++++++++--------------------
Mdrivers/media/platform/via-camera.c | 10+++++-----
Mdrivers/media/platform/vicodec/Kconfig | 2+-
Mdrivers/media/platform/vicodec/Makefile | 2+-
Adrivers/media/platform/vicodec/codec-fwht.c | 855+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/platform/vicodec/codec-fwht.h | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/platform/vicodec/codec-v4l2-fwht.c | 332+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/media/platform/vicodec/codec-v4l2-fwht.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Ddrivers/media/platform/vicodec/vicodec-codec.c | 797-------------------------------------------------------------------------------
Ddrivers/media/platform/vicodec/vicodec-codec.h | 129-------------------------------------------------------------------------------
Mdrivers/media/platform/vicodec/vicodec-core.c | 520++++++++++++++++++++++++++++++++++---------------------------------------------
Mdrivers/media/platform/video-mux.c | 38++++++++++++++++++++++++++++++++++++--
Mdrivers/media/platform/vim2m.c | 2+-
Mdrivers/media/platform/vimc/vimc-capture.c | 6+++---
Mdrivers/media/platform/vimc/vimc-common.c | 2+-
Mdrivers/media/platform/vimc/vimc-core.c | 4++--
Mdrivers/media/platform/vimc/vimc-sensor.c | 20++++++++++++++++++++
Mdrivers/media/platform/vivid/vivid-cec.c | 4++--
Mdrivers/media/platform/vivid/vivid-core.c | 4++--
Mdrivers/media/platform/vivid/vivid-core.h | 2+-
Mdrivers/media/platform/vivid/vivid-ctrls.c | 6+++---
Mdrivers/media/platform/vivid/vivid-osd.c | 2+-
Mdrivers/media/platform/vivid/vivid-radio-common.c | 4++--
Mdrivers/media/platform/vivid/vivid-radio-rx.c | 2+-
Mdrivers/media/platform/vivid/vivid-radio-tx.c | 2+-
Mdrivers/media/platform/vivid/vivid-rds-gen.c | 4++--
Mdrivers/media/platform/vivid/vivid-sdr-cap.c | 4++--
Mdrivers/media/platform/vivid/vivid-vid-cap.c | 11+++++++----
Mdrivers/media/platform/vivid/vivid-vid-common.c | 30+++++++++++++++++++++++++++++-
Mdrivers/media/platform/vivid/vivid-vid-out.c | 2+-
Mdrivers/media/platform/vsp1/vsp1_brx.c | 4++--
Mdrivers/media/platform/vsp1/vsp1_drm.c | 11++++++++++-
Mdrivers/media/platform/vsp1/vsp1_drv.c | 8++++----
Mdrivers/media/platform/vsp1/vsp1_entity.c | 2+-
Mdrivers/media/platform/vsp1/vsp1_histo.c | 4++--
Mdrivers/media/platform/vsp1/vsp1_lif.c | 29+++++++++++++++++++++++++----
Mdrivers/media/platform/vsp1/vsp1_regs.h | 2+-
Mdrivers/media/platform/vsp1/vsp1_rpf.c | 4++--
Mdrivers/media/platform/vsp1/vsp1_sru.c | 7++++++-
Mdrivers/media/platform/vsp1/vsp1_uds.c | 14+++++++++++---
Mdrivers/media/platform/vsp1/vsp1_video.c | 13+++++--------
Mdrivers/media/platform/vsp1/vsp1_wpf.c | 2+-
Mdrivers/media/platform/xilinx/xilinx-dma.c | 14+++++++-------
Mdrivers/media/platform/xilinx/xilinx-tpg.c | 2+-
Mdrivers/media/platform/xilinx/xilinx-vipp.c | 175+++++++++++++++++++++++++++++++++++++------------------------------------------
Mdrivers/media/platform/xilinx/xilinx-vipp.h | 4----
Mdrivers/media/radio/dsbr100.c | 9+++++----
Mdrivers/media/radio/radio-cadet.c | 12++++++------
Mdrivers/media/radio/radio-isa.c | 10+++++-----
Mdrivers/media/radio/radio-keene.c | 8++++----
Mdrivers/media/radio/radio-ma901.c | 8++++----
Mdrivers/media/radio/radio-maxiradio.c | 2+-
Mdrivers/media/radio/radio-miropcm20.c | 10+++++-----
Mdrivers/media/radio/radio-mr800.c | 8++++----
Mdrivers/media/radio/radio-raremono.c | 8++++----
Mdrivers/media/radio/radio-sf16fmi.c | 12++++++------
Mdrivers/media/radio/radio-sf16fmr2.c | 6+++---
Mdrivers/media/radio/radio-shark.c | 2+-
Mdrivers/media/radio/radio-shark2.c | 2+-
Mdrivers/media/radio/radio-si476x.c | 12++++++------
Mdrivers/media/radio/radio-tea5764.c | 6+++---
Mdrivers/media/radio/radio-tea5777.c | 12++++++------
Mdrivers/media/radio/radio-timb.c | 8++++----
Mdrivers/media/radio/radio-wl1273.c | 12++++++------
Mdrivers/media/radio/si470x/radio-si470x-common.c | 2+-
Mdrivers/media/radio/si470x/radio-si470x-i2c.c | 4++--
Mdrivers/media/radio/si470x/radio-si470x-usb.c | 4++--
Mdrivers/media/radio/si4713/radio-platform-si4713.c | 6+++---
Mdrivers/media/radio/si4713/radio-usb-si4713.c | 6+++---
Mdrivers/media/radio/tea575x.c | 10+++++-----
Mdrivers/media/radio/tef6862.c | 2+-
Mdrivers/media/radio/wl128x/fmdrv_v4l2.c | 13+++++++------
Mdrivers/media/rc/ati_remote.c | 2+-
Mdrivers/media/rc/ene_ir.c | 12++++++------
Mdrivers/media/rc/fintek-cir.c | 3+--
Mdrivers/media/rc/igorplugusb.c | 2+-
Mdrivers/media/rc/iguanair.c | 4+---
Mdrivers/media/rc/imon_raw.c | 2+-
Mdrivers/media/rc/ir-hix5hd2.c | 2+-
Mdrivers/media/rc/ir-imon-decoder.c | 62++++----------------------------------------------------------
Mdrivers/media/rc/ir-mce_kbd-decoder.c | 77++++++++++++++---------------------------------------------------------------
Mdrivers/media/rc/ir-rc6-decoder.c | 9+++++++--
Mdrivers/media/rc/ite-cir.c | 5+----
Mdrivers/media/rc/keymaps/rc-behold.c | 2+-
Mdrivers/media/rc/keymaps/rc-delock-61959.c | 2+-
Mdrivers/media/rc/keymaps/rc-imon-rsc.c | 2+-
Mdrivers/media/rc/keymaps/rc-it913x-v1.c | 2+-
Mdrivers/media/rc/keymaps/rc-it913x-v2.c | 2+-
Mdrivers/media/rc/keymaps/rc-msi-digivox-iii.c | 2+-
Mdrivers/media/rc/keymaps/rc-pixelview-002t.c | 2+-
Mdrivers/media/rc/keymaps/rc-pixelview-mk12.c | 2+-
Mdrivers/media/rc/keymaps/rc-reddo.c | 2+-
Mdrivers/media/rc/keymaps/rc-terratec-slim.c | 2+-
Mdrivers/media/rc/keymaps/rc-tivo.c | 2+-
Mdrivers/media/rc/keymaps/rc-total-media-in-hand.c | 2+-
Mdrivers/media/rc/mceusb.c | 17+++++++++--------
Mdrivers/media/rc/meson-ir.c | 2+-
Mdrivers/media/rc/mtk-cir.c | 2+-
Mdrivers/media/rc/nuvoton-cir.c | 2+-
Mdrivers/media/rc/rc-core-priv.h | 12++++--------
Mdrivers/media/rc/rc-ir-raw.c | 12++++++------
Mdrivers/media/rc/rc-loopback.c | 2+-
Mdrivers/media/rc/rc-main.c | 20++++++++------------
Mdrivers/media/rc/redrat3.c | 10+++++-----
Mdrivers/media/rc/serial_ir.c | 10+++++-----
Mdrivers/media/rc/sir_ir.c | 2+-
Mdrivers/media/rc/st_rc.c | 5++---
Mdrivers/media/rc/streamzap.c | 14+++++++-------
Mdrivers/media/rc/sunxi-cir.c | 2+-
Mdrivers/media/rc/ttusbir.c | 4+---
Mdrivers/media/rc/winbond-cir.c | 12++++++------
Mdrivers/media/tuners/e4000.c | 2+-
Mdrivers/media/tuners/fc2580.c | 2+-
Mdrivers/media/tuners/msi001.c | 2+-
Mdrivers/media/tuners/mt20xx.c | 2+-
Mdrivers/media/tuners/si2157.c | 13++++++++-----
Mdrivers/media/tuners/si2157_priv.h | 9++++++++-
Mdrivers/media/tuners/tuner-simple.c | 2+-
Mdrivers/media/usb/airspy/airspy.c | 10+++++-----
Mdrivers/media/usb/au0828/au0828-core.c | 17+++++++++--------
Mdrivers/media/usb/au0828/au0828-i2c.c | 2+-
Mdrivers/media/usb/au0828/au0828-input.c | 5+----
Mdrivers/media/usb/au0828/au0828-video.c | 22+++++++++++-----------
Mdrivers/media/usb/cpia2/cpia2_v4l.c | 12++++++------
Mdrivers/media/usb/cx231xx/cx231xx-417.c | 2+-
Mdrivers/media/usb/cx231xx/cx231xx-audio.c | 8++++----
Mdrivers/media/usb/cx231xx/cx231xx-input.c | 2+-
Mdrivers/media/usb/cx231xx/cx231xx-video.c | 29+++++++++++++++--------------
Mdrivers/media/usb/dvb-usb-v2/af9035.c | 2+-
Mdrivers/media/usb/dvb-usb-v2/anysee.c | 2+-
Mdrivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2+-
Mdrivers/media/usb/dvb-usb-v2/dvbsky.c | 16++++++++++------
Mdrivers/media/usb/dvb-usb-v2/gl861.c | 2+-
Mdrivers/media/usb/dvb-usb-v2/lmedm04.c | 2+-
Mdrivers/media/usb/dvb-usb-v2/mxl111sf.c | 8+++++---
Mdrivers/media/usb/dvb-usb-v2/mxl111sf.h | 8+++++++-
Mdrivers/media/usb/dvb-usb-v2/rtl28xxu.c | 22++++++++++------------
Mdrivers/media/usb/dvb-usb-v2/zd1301.c | 2+-
Mdrivers/media/usb/dvb-usb/cxusb.c | 4++--
Mdrivers/media/usb/dvb-usb/dib0700_devices.c | 4++--
Mdrivers/media/usb/dvb-usb/dvb-usb-i2c.c | 2+-
Mdrivers/media/usb/dvb-usb/dw2102.c | 4++--
Mdrivers/media/usb/dvb-usb/technisat-usb2.c | 5+++--
Mdrivers/media/usb/em28xx/em28xx-audio.c | 16++++++++--------
Mdrivers/media/usb/em28xx/em28xx-cards.c | 33+++++++++++++++++++++++++++++++--
Mdrivers/media/usb/em28xx/em28xx-i2c.c | 3++-
Mdrivers/media/usb/em28xx/em28xx-video.c | 124++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mdrivers/media/usb/em28xx/em28xx.h | 8+++++++-
Mdrivers/media/usb/go7007/go7007-driver.c | 2+-
Mdrivers/media/usb/go7007/go7007-v4l2.c | 16++++++++--------
Mdrivers/media/usb/go7007/snd-go7007.c | 8++++----
Mdrivers/media/usb/gspca/gspca.c | 10+++++-----
Mdrivers/media/usb/gspca/sn9c20x.c | 2+-
Mdrivers/media/usb/gspca/sq930x.c | 2+-
Mdrivers/media/usb/hackrf/hackrf.c | 12++++++------
Mdrivers/media/usb/hdpvr/hdpvr-video.c | 9+++++----
Mdrivers/media/usb/msi2500/msi2500.c | 8++++----
Mdrivers/media/usb/pulse8-cec/pulse8-cec.c | 3++-
Mdrivers/media/usb/pvrusb2/pvrusb2-debug.h | 2+-
Mdrivers/media/usb/pvrusb2/pvrusb2-hdw.c | 8++++----
Mdrivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 34++++++++++++++++------------------
Mdrivers/media/usb/pvrusb2/pvrusb2-main.c | 4++--
Mdrivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 14+++++++-------
Mdrivers/media/usb/pwc/pwc-if.c | 2+-
Mdrivers/media/usb/pwc/pwc-v4l.c | 12+++++++-----
Mdrivers/media/usb/rainshadow-cec/rainshadow-cec.c | 3++-
Mdrivers/media/usb/s2255/s2255drv.c | 10+++++-----
Mdrivers/media/usb/stk1160/stk1160-i2c.c | 2+-
Mdrivers/media/usb/stk1160/stk1160-v4l.c | 6+++---
Mdrivers/media/usb/stkwebcam/stk-webcam.c | 16++++++++--------
Mdrivers/media/usb/tm6000/tm6000-alsa.c | 6+++---
Mdrivers/media/usb/tm6000/tm6000-i2c.c | 4++--
Mdrivers/media/usb/tm6000/tm6000-video.c | 13+++++++------
Mdrivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 2+-
Mdrivers/media/usb/usbtv/usbtv-audio.c | 6+++---
Mdrivers/media/usb/usbtv/usbtv-video.c | 14+++++++-------
Mdrivers/media/usb/usbvision/usbvision-core.c | 3---
Mdrivers/media/usb/usbvision/usbvision-video.c | 26++++++++++++++------------
Mdrivers/media/usb/usbvision/usbvision.h | 1-
Mdrivers/media/usb/uvc/uvc_ctrl.c | 18+++++++++---------
Mdrivers/media/usb/uvc/uvc_debugfs.c | 6+-----
Mdrivers/media/usb/uvc/uvc_driver.c | 75++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mdrivers/media/usb/uvc/uvc_entity.c | 2+-
Mdrivers/media/usb/uvc/uvc_metadata.c | 11++++++-----
Mdrivers/media/usb/uvc/uvc_v4l2.c | 10+++++-----
Mdrivers/media/usb/uvc/uvcvideo.h | 10++++++++--
Mdrivers/media/usb/zr364xx/zr364xx.c | 10+++++-----
Mdrivers/media/v4l2-core/tuner-core.c | 54+++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mdrivers/media/v4l2-core/v4l2-async.c | 313++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mdrivers/media/v4l2-core/v4l2-common.c | 25++++++++++++++++++-------
Mdrivers/media/v4l2-core/v4l2-ctrls.c | 22++++++++--------------
Mdrivers/media/v4l2-core/v4l2-device.c | 2+-
Mdrivers/media/v4l2-core/v4l2-dv-timings.c | 202++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdrivers/media/v4l2-core/v4l2-flash-led-class.c | 2+-
Mdrivers/media/v4l2-core/v4l2-fwnode.c | 845++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mdrivers/media/v4l2-core/v4l2-ioctl.c | 8++++----
Mdrivers/media/v4l2-core/v4l2-mc.c | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mdrivers/media/v4l2-core/v4l2-subdev.c | 2+-
Mdrivers/staging/media/bcm2048/radio-bcm2048.c | 4++--
Mdrivers/staging/media/davinci_vpfe/dm365_ipipe.c | 2+-
Mdrivers/staging/media/davinci_vpfe/dm365_ipipeif.c | 2+-
Mdrivers/staging/media/davinci_vpfe/dm365_isif.c | 2+-
Mdrivers/staging/media/davinci_vpfe/dm365_resizer.c | 6+++---
Mdrivers/staging/media/davinci_vpfe/vpfe_mc_capture.c | 3++-
Mdrivers/staging/media/davinci_vpfe/vpfe_video.c | 6+++---
Mdrivers/staging/media/imx/TODO | 29+++++++----------------------
Mdrivers/staging/media/imx/imx-media-capture.c | 4++--
Mdrivers/staging/media/imx/imx-media-csi.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mdrivers/staging/media/imx/imx-media-dev.c | 163+++++++++++++++++++++++++------------------------------------------------------
Mdrivers/staging/media/imx/imx-media-internal-sd.c | 5++++-
Mdrivers/staging/media/imx/imx-media-of.c | 106++++++-------------------------------------------------------------------------
Mdrivers/staging/media/imx/imx-media-utils.c | 4++--
Mdrivers/staging/media/imx/imx-media.h | 6++----
Mdrivers/staging/media/imx/imx6-mipi-csi2.c | 33+++++++++++++++------------------
Mdrivers/staging/media/imx074/imx074.c | 3+--
Mdrivers/staging/media/mt9t031/mt9t031.c | 1-
Mdrivers/staging/media/omap4iss/Kconfig | 2++
Mdrivers/staging/media/omap4iss/Makefile | 3+++
Mdrivers/staging/media/omap4iss/iss.c | 8++------
Mdrivers/staging/media/omap4iss/iss.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_csi2.c | 6+-----
Mdrivers/staging/media/omap4iss/iss_csi2.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_csiphy.c | 6+-----
Mdrivers/staging/media/omap4iss/iss_csiphy.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_ipipe.c | 8++------
Mdrivers/staging/media/omap4iss/iss_ipipe.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_ipipeif.c | 8++------
Mdrivers/staging/media/omap4iss/iss_ipipeif.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_regs.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_resizer.c | 8++------
Mdrivers/staging/media/omap4iss/iss_resizer.h | 6+-----
Mdrivers/staging/media/omap4iss/iss_video.c | 16++++++----------
Mdrivers/staging/media/omap4iss/iss_video.h | 6+-----
Mdrivers/staging/media/zoran/zoran_card.c | 6+++---
Mdrivers/staging/media/zoran/zoran_driver.c | 6+++---
Mdrivers/video/backlight/as3711_bl.c | 7++-----
Mdrivers/video/fbdev/sh7760fb.c | 7++-----
Mdrivers/video/hdmi.c | 8++++----
Mfs/compat_ioctl.c | 131-------------------------------------------------------------------------------
Minclude/linux/hdmi.h | 4++--
Minclude/media/cec.h | 154++++++++++++++++++++++++++++++++++++-------------------------------------------
Minclude/media/media-entity.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/media/rc-core.h | 11+----------
Minclude/media/rcar-fcp.h | 6+-----
Minclude/media/v4l2-async.h | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Minclude/media/v4l2-common.h | 14+++++++++++++-
Minclude/media/v4l2-ctrls.h | 26+++++++++++++++++++++++++-
Minclude/media/v4l2-dv-timings.h | 17+++++++++++++++++
Minclude/media/v4l2-fwnode.h | 141++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Minclude/media/v4l2-mc.h | 78------------------------------------------------------------------------------
Minclude/media/v4l2-mediabus.h | 40++++++++++++++++++++++++----------------
Minclude/media/v4l2-rect.h | 26++++++++++++++++++++++++++
Minclude/media/vsp1.h | 8++------
Minclude/uapi/linux/cec.h | 3+++
Minclude/uapi/linux/videodev2.h | 31+++++++++++++++++++++++++------
588 files changed, 23728 insertions(+), 13706 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/fsl-pxp.txt b/Documentation/devicetree/bindings/media/fsl-pxp.txt @@ -0,0 +1,26 @@ +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, 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/adv748x.txt b/Documentation/devicetree/bindings/media/i2c/adv748x.txt @@ -10,7 +10,11 @@ Required Properties: - "adi,adv7481" for the ADV7481 - "adi,adv7482" for the ADV7482 - - reg: I2C slave address + - reg: I2C slave addresses + The ADV748x has up to twelve 256-byte maps that can be accessed via the + main I2C ports. Each map has it own I2C address and acts as a standard + slave device on the I2C bus. The main address is mandatory, others are + optional and remain at default values if not specified. Optional Properties: @@ -18,6 +22,11 @@ Optional Properties: "intrq3". All interrupts are optional. The "intrq3" interrupt is only available on the adv7481 - interrupts: Specify the interrupt lines for the ADV748x + - reg-names : Names of maps with programmable addresses. + It shall contain all maps needing a non-default address. + Possible map names are: + "main", "dpll", "cp", "hdmi", "edid", "repeater", + "infoframe", "cbus", "cec", "sdp", "txa", "txb" The device node must contain one 'port' child node per device input and output port, in accordance with the video interface bindings defined in @@ -47,7 +56,10 @@ Example: video-receiver@70 { compatible = "adi,adv7482"; - reg = <0x70>; + reg = <0x70 0x71 0x72 0x73 0x74 0x75 + 0x60 0x61 0x62 0x63 0x64 0x65>; + reg-names = "main", "dpll", "cp", "hdmi", "edid", "repeater", + "infoframe", "cbus", "cec", "sdp", "txa", "txb"; #address-cells = <1>; #size-cells = <0>; @@ -73,7 +85,7 @@ Example: }; }; - port@10 { + port@a { reg = <10>; adv7482_txa: endpoint { @@ -83,7 +95,7 @@ Example: }; }; - port@11 { + port@b { reg = <11>; adv7482_txb: endpoint { diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -66,7 +66,7 @@ Example: * other maps will retain their default addresses. */ reg = <0x4c>, <0x66>; - reg-names "main", "edid"; + reg-names = "main", "edid"; reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; diff --git a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807.txt b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.txt diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt @@ -11,6 +11,7 @@ on Gen3 platforms to a CSI-2 receiver. - compatible: Must be one or more of the following - "renesas,vin-r8a7743" for the R8A7743 device + - "renesas,vin-r8a7744" for the R8A7744 device - "renesas,vin-r8a7745" for the R8A7745 device - "renesas,vin-r8a7778" for the R8A7778 device - "renesas,vin-r8a7779" for the R8A7779 device diff --git a/Documentation/devicetree/bindings/media/renesas,ceu.txt b/Documentation/devicetree/bindings/media/renesas,ceu.txt @@ -17,15 +17,19 @@ Required properties: The CEU supports a single parallel input and should contain a single 'port' subnode with a single 'endpoint'. Connection to input devices are modeled according to the video interfaces OF bindings specified in: -Documentation/devicetree/bindings/media/video-interfaces.txt +[1] Documentation/devicetree/bindings/media/video-interfaces.txt Optional endpoint properties applicable to parallel input bus described in the above mentioned "video-interfaces.txt" file are supported. -- hsync-active: Active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. - If property is not present, default is active high. -- vsync-active: Active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. - If property is not present, default is active high. +- hsync-active: See [1] for description. If property is not present, + default is active high. +- vsync-active: See [1] for description. If property is not present, + default is active high. +- bus-width: See [1] for description. Accepted values are '8' and '16'. + If property is not present, default is '8'. +- field-even-active: See [1] for description. If property is not present, + an even field is identified by a logic 0 (active-low signal). Example: diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -100,10 +100,12 @@ Optional endpoint properties slave device (data source) by the master device (data sink). In the master mode the data source device is also the source of the synchronization signals. - bus-type: data bus type. Possible values are: - 0 - autodetect based on other properties (MIPI CSI-2 D-PHY, parallel or Bt656) 1 - MIPI CSI-2 C-PHY 2 - MIPI CSI1 3 - CCP2 + 4 - MIPI CSI-2 D-PHY + 5 - Parallel + 6 - Bt.656 - bus-width: number of data lines actively used, valid for the parallel busses. - data-shift: on the parallel data busses, if bus-width is used to specify the number of data lines, data-shift can be used to specify which data lines are diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst @@ -268,6 +268,10 @@ to 1, if the hardware does support retry then either set these counters to 0 if the hardware provides no feedback of which errors occurred and how many times, or fill in the correct values as reported by the hardware. +Be aware that calling these functions can immediately start a new transmit +if there is one pending in the queue. So make sure that the hardware is in +a state where new transmits can be started *before* calling these functions. + The cec_transmit_attempt_done() function is a helper for cases where the hardware never retries, so the transmit is always for just a single attempt. It will call cec_transmit_done() in turn, filling in 1 for the diff --git a/Documentation/media/kapi/v4l2-subdev.rst b/Documentation/media/kapi/v4l2-subdev.rst @@ -247,20 +247,28 @@ performed using the :c:func:`v4l2_async_unregister_subdev` call. Subdevices registered this way are stored in a global list of subdevices, ready to be picked up by bridge drivers. -Bridge drivers in turn have to register a notifier object with an array of -subdevice descriptors that the bridge device needs for its operation. This is +Bridge drivers in turn have to register a notifier object. This is performed using the :c:func:`v4l2_async_notifier_register` call. To unregister the notifier the driver has to call :c:func:`v4l2_async_notifier_unregister`. The former of the two functions -takes two arguments: a pointer to struct :c:type:`v4l2_device` and a pointer to -struct :c:type:`v4l2_async_notifier`. The latter contains a pointer to an array -of pointers to subdevice descriptors of type struct :c:type:`v4l2_async_subdev` -type. The V4L2 core will then use these descriptors to match asynchronously -registered -subdevices to them. If a match is detected the ``.bound()`` notifier callback -is called. After all subdevices have been located the .complete() callback is -called. When a subdevice is removed from the system the .unbind() method is -called. All three callbacks are optional. +takes two arguments: a pointer to struct :c:type:`v4l2_device` and a +pointer to struct :c:type:`v4l2_async_notifier`. + +Before registering the notifier, bridge drivers must do two things: +first, the notifier must be initialized using the +:c:func:`v4l2_async_notifier_init`. Second, bridge drivers can then +begin to form a list of subdevice descriptors that the bridge device +needs for its operation. Subdevice descriptors are added to the notifier +using the :c:func:`v4l2_async_notifier_add_subdev` call. This function +takes two arguments: a pointer to struct :c:type:`v4l2_async_notifier`, +and a pointer to the subdevice descripter, which is of type struct +:c:type:`v4l2_async_subdev`. + +The V4L2 core will then use these descriptors to match asynchronously +registered subdevices to them. If a match is detected the ``.bound()`` +notifier callback is called. After all subdevices have been located the +.complete() callback is called. When a subdevice is removed from the +system the .unbind() method is called. All three callbacks are optional. V4L2 sub-device userspace API ----------------------------- diff --git a/Documentation/media/uapi/cec/cec-func-poll.rst b/Documentation/media/uapi/cec/cec-func-poll.rst @@ -74,4 +74,5 @@ is returned, and the ``errno`` variable is set appropriately: The call was interrupted by a signal. ``EINVAL`` - The ``nfds`` argument is greater than ``OPEN_MAX``. + The ``nfds`` value exceeds the ``RLIMIT_NOFILE`` value. Use + ``getrlimit()`` to obtain this value. diff --git a/Documentation/media/uapi/cec/cec-ioc-receive.rst b/Documentation/media/uapi/cec/cec-ioc-receive.rst @@ -16,10 +16,10 @@ CEC_RECEIVE, CEC_TRANSMIT - Receive or transmit a CEC message Synopsis ======== -.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg *argp ) +.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg \*argp ) :name: CEC_RECEIVE -.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg *argp ) +.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg \*argp ) :name: CEC_TRANSMIT Arguments @@ -272,6 +272,19 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - The transmit failed after one or more retries. This status bit is mutually exclusive with :ref:`CEC_TX_STATUS_OK <CEC-TX-STATUS-OK>`. Other bits can still be set to explain which failures were seen. + * .. _`CEC-TX-STATUS-ABORTED`: + + - ``CEC_TX_STATUS_ABORTED`` + - 0x40 + - The transmit was aborted due to an HDMI disconnect, or the adapter + was unconfigured, or a transmit was interrupted, or the driver + returned an error when attempting to start a transmit. + * .. _`CEC-TX-STATUS-TIMEOUT`: + + - ``CEC_TX_STATUS_TIMEOUT`` + - 0x80 + - The transmit timed out. This should not normally happen and this + indicates a driver problem. .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| @@ -300,6 +313,14 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - The message was received successfully but the reply was ``CEC_MSG_FEATURE_ABORT``. This status is only set if this message was the reply to an earlier transmitted message. + * .. _`CEC-RX-STATUS-ABORTED`: + + - ``CEC_RX_STATUS_ABORTED`` + - 0x08 + - The wait for a reply to an earlier transmitted message was aborted + because the HDMI cable was disconnected, the adapter was unconfigured + or the :ref:`CEC_TRANSMIT <CEC_RECEIVE>` that waited for a + reply was interrupted. diff --git a/Documentation/media/uapi/mediactl/media-ioc-device-info.rst b/Documentation/media/uapi/mediactl/media-ioc-device-info.rst @@ -26,6 +26,7 @@ Arguments File descriptor returned by :ref:`open() <media-func-open>`. ``argp`` + Pointer to struct :c:type:`media_device_info`. Description diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst @@ -26,6 +26,7 @@ Arguments File descriptor returned by :ref:`open() <media-func-open>`. ``argp`` + Pointer to struct :c:type:`media_entity_desc`. Description diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst @@ -26,6 +26,7 @@ Arguments File descriptor returned by :ref:`open() <media-func-open>`. ``argp`` + Pointer to struct :c:type:`media_links_enum`. Description diff --git a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst @@ -26,6 +26,7 @@ Arguments File descriptor returned by :ref:`open() <media-func-open>`. ``argp`` + Pointer to struct :c:type:`media_v2_topology`. Description diff --git a/Documentation/media/uapi/mediactl/media-ioc-setup-link.rst b/Documentation/media/uapi/mediactl/media-ioc-setup-link.rst @@ -26,6 +26,7 @@ Arguments File descriptor returned by :ref:`open() <media-func-open>`. ``argp`` + Pointer to struct :c:type:`media_link_desc`. Description diff --git a/Documentation/media/uapi/v4l/biblio.rst b/Documentation/media/uapi/v4l/biblio.rst @@ -226,16 +226,6 @@ xvYCC :author: International Electrotechnical Commission (http://www.iec.ch) -.. _adobergb: - -AdobeRGB -======== - - -:title: Adobe© RGB (1998) Color Image Encoding Version 2005-05 - -:author: Adobe Systems Incorporated (http://www.adobe.com) - .. _oprgb: opRGB diff --git a/Documentation/media/uapi/v4l/colorspaces-defs.rst b/Documentation/media/uapi/v4l/colorspaces-defs.rst @@ -51,8 +51,8 @@ whole range, 0-255, dividing the angular value by 1.41. The enum - See :ref:`col-rec709`. * - ``V4L2_COLORSPACE_SRGB`` - See :ref:`col-srgb`. - * - ``V4L2_COLORSPACE_ADOBERGB`` - - See :ref:`col-adobergb`. + * - ``V4L2_COLORSPACE_OPRGB`` + - See :ref:`col-oprgb`. * - ``V4L2_COLORSPACE_BT2020`` - See :ref:`col-bt2020`. * - ``V4L2_COLORSPACE_DCI_P3`` @@ -90,8 +90,8 @@ whole range, 0-255, dividing the angular value by 1.41. The enum - Use the Rec. 709 transfer function. * - ``V4L2_XFER_FUNC_SRGB`` - Use the sRGB transfer function. - * - ``V4L2_XFER_FUNC_ADOBERGB`` - - Use the AdobeRGB transfer function. + * - ``V4L2_XFER_FUNC_OPRGB`` + - Use the opRGB transfer function. * - ``V4L2_XFER_FUNC_SMPTE240M`` - Use the SMPTE 240M transfer function. * - ``V4L2_XFER_FUNC_NONE`` diff --git a/Documentation/media/uapi/v4l/colorspaces-details.rst b/Documentation/media/uapi/v4l/colorspaces-details.rst @@ -290,15 +290,14 @@ Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range 170M/BT.601. The Y'CbCr quantization is limited range. -.. _col-adobergb: +.. _col-oprgb: -Colorspace Adobe RGB (V4L2_COLORSPACE_ADOBERGB) +Colorspace opRGB (V4L2_COLORSPACE_OPRGB) =============================================== -The :ref:`adobergb` standard defines the colorspace used by computer -graphics that use the AdobeRGB colorspace. This is also known as the -:ref:`oprgb` standard. The default transfer function is -``V4L2_XFER_FUNC_ADOBERGB``. The default Y'CbCr encoding is +The :ref:`oprgb` standard defines the colorspace used by computer +graphics that use the opRGB colorspace. The default transfer function is +``V4L2_XFER_FUNC_OPRGB``. The default Y'CbCr encoding is ``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited range. @@ -312,7 +311,7 @@ The chromaticities of the primary colors and the white reference are: .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| -.. flat-table:: Adobe RGB Chromaticities +.. flat-table:: opRGB Chromaticities :header-rows: 1 :stub-columns: 0 :widths: 1 1 2 diff --git a/Documentation/media/uapi/v4l/func-poll.rst b/Documentation/media/uapi/v4l/func-poll.rst @@ -113,4 +113,5 @@ EINTR The call was interrupted by a signal. EINVAL - The ``nfds`` argument is greater than ``OPEN_MAX``. + The ``nfds`` value exceeds the ``RLIMIT_NOFILE`` value. Use + ``getrlimit()`` to obtain this value. diff --git a/Documentation/media/uapi/v4l/meta-formats.rst b/Documentation/media/uapi/v4l/meta-formats.rst @@ -12,6 +12,7 @@ These formats are used for the :ref:`metadata` interface only. .. toctree:: :maxdepth: 1 + pixfmt-meta-d4xx pixfmt-meta-uvc pixfmt-meta-vsp1-hgo pixfmt-meta-vsp1-hgt diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -101,4 +101,4 @@ Compressed Formats - 'FWHT' - Video elementary stream using a codec based on the Fast Walsh Hadamard Transform. This codec is implemented by the vicodec ('Virtual Codec') - driver. See the vicodec-codec.h header for more details. + driver. See the codec-fwht.h header for more details. diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst b/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst @@ -0,0 +1,210 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _v4l2-meta-fmt-d4xx: + +******************************* +V4L2_META_FMT_D4XX ('D4XX') +******************************* + +Intel D4xx UVC Cameras Metadata + + +Description +=========== + +Intel D4xx (D435 and other) cameras include per-frame metadata in their UVC +payload headers, following the Microsoft(R) UVC extension proposal [1_]. That +means, that the private D4XX metadata, following the standard UVC header, is +organised in blocks. D4XX cameras implement several standard block types, +proposed by Microsoft, and several proprietary ones. Supported standard metadata +types are MetadataId_CaptureStats (ID 3), MetadataId_CameraExtrinsics (ID 4), +and MetadataId_CameraIntrinsics (ID 5). For their description see [1_]. This +document describes proprietary metadata types, used by D4xx cameras. + +V4L2_META_FMT_D4XX buffers follow the metadata buffer layout of +V4L2_META_FMT_UVC with the only difference, that it also includes proprietary +payload header data. D4xx cameras use bulk transfers and only send one payload +per frame, therefore their headers cannot be larger than 255 bytes. + +Below are proprietary Microsoft style metadata types, used by D4xx cameras, +where all fields are in little endian order: + +.. flat-table:: D4xx metadata + :widths: 1 4 + :header-rows: 1 + :stub-columns: 0 + + * - Field + - Description + * - :cspan:`1` *Depth Control* + * - __u32 ID + - 0x80000000 + * - __u32 Size + - Size in bytes (currently 56) + * - __u32 Version + - Version of this structure. The documentation herein corresponds to + version xxx. The version number will be incremented when new fields are + added. + * - __u32 Flags + - A bitmask of flags: see [2_] below + * - __u32 Gain + - Gain value in internal units, same as the V4L2_CID_GAIN control, used to + capture the frame + * - __u32 Exposure + - Exposure time (in microseconds) used to capture the frame + * - __u32 Laser power + - Power of the laser LED 0-360, used for depth measurement + * - __u32 AE mode + - 0: manual; 1: automatic exposure + * - __u32 Exposure priority + - Exposure priority value: 0 - constant frame rate + * - __u32 AE ROI left + - Left border of the AE Region of Interest (all ROI values are in pixels + and lie between 0 and maximum width or height respectively) + * - __u32 AE ROI right + - Right border of the AE Region of Interest + * - __u32 AE ROI top + - Top border of the AE Region of Interest + * - __u32 AE ROI bottom + - Bottom border of the AE Region of Interest + * - __u32 Preset + - Preset selector value, default: 0, unless changed by the user + * - __u32 Laser mode + - 0: off, 1: on + * - :cspan:`1` *Capture Timing* + * - __u32 ID + - 0x80000001 + * - __u32 Size + - Size in bytes (currently 40) + * - __u32 Version + - Version of this structure. The documentation herein corresponds to + version xxx. The version number will be incremented when new fields are + added. + * - __u32 Flags + - A bitmask of flags: see [3_] below + * - __u32 Frame counter + - Monotonically increasing counter + * - __u32 Optical time + - Time in microseconds from the beginning of a frame till its middle + * - __u32 Readout time + - Time, used to read out a frame in microseconds + * - __u32 Exposure time + - Frame exposure time in microseconds + * - __u32 Frame interval + - In microseconds = 1000000 / framerate + * - __u32 Pipe latency + - Time in microseconds from start of frame to data in USB buffer + * - :cspan:`1` *Configuration* + * - __u32 ID + - 0x80000002 + * - __u32 Size + - Size in bytes (currently 40) + * - __u32 Version + - Version of this structure. The documentation herein corresponds to + version xxx. The version number will be incremented when new fields are + added. + * - __u32 Flags + - A bitmask of flags: see [4_] below + * - __u8 Hardware type + - Camera hardware version [5_] + * - __u8 SKU ID + - Camera hardware configuration [6_] + * - __u32 Cookie + - Internal synchronisation + * - __u16 Format + - Image format code [7_] + * - __u16 Width + - Width in pixels + * - __u16 Height + - Height in pixels + * - __u16 Framerate + - Requested frame rate per second + * - __u16 Trigger + - Byte 0: bit 0: depth and RGB are synchronised, bit 1: external trigger + +.. _1: + +[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5 + +.. _2: + +[2] Depth Control flags specify which fields are valid: :: + + 0x00000001 Gain + 0x00000002 Exposure + 0x00000004 Laser power + 0x00000008 AE mode + 0x00000010 Exposure priority + 0x00000020 AE ROI + 0x00000040 Preset + +.. _3: + +[3] Capture Timing flags specify which fields are valid: :: + + 0x00000001 Frame counter + 0x00000002 Optical time + 0x00000004 Readout time + 0x00000008 Exposure time + 0x00000010 Frame interval + 0x00000020 Pipe latency + +.. _4: + +[4] Configuration flags specify which fields are valid: :: + + 0x00000001 Hardware type + 0x00000002 SKU ID + 0x00000004 Cookie + 0x00000008 Format + 0x00000010 Width + 0x00000020 Height + 0x00000040 Framerate + 0x00000080 Trigger + 0x00000100 Cal count + +.. _5: + +[5] Camera model: :: + + 0 DS5 + 1 IVCAM2 + +.. _6: + +[6] 8-bit camera hardware configuration bitfield: :: + + [1:0] depthCamera + 00: no depth + 01: standard depth + 10: wide depth + 11: reserved + [2] depthIsActive - has a laser projector + [3] RGB presence + [4] Inertial Measurement Unit (IMU) presence + [5] projectorType + 0: HPTG + 1: Princeton + [6] 0: a projector, 1: an LED + [7] reserved + +.. _7: + +[7] Image format codes per video streaming interface: + +Depth: :: + + 1 Z16 + 2 Z + +Left sensor: :: + + 1 Y8 + 2 UYVY + 3 R8L8 + 4 Calibration + 5 W10 + +Fish Eye sensor: :: + + 1 RAW8 diff --git a/Documentation/media/uapi/v4l/vidioc-cropcap.rst b/Documentation/media/uapi/v4l/vidioc-cropcap.rst @@ -58,7 +58,7 @@ overlay devices. - Type of the data stream, set by the application. Only these types are valid here: ``V4L2_BUF_TYPE_VIDEO_CAPTURE``, ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``, ``V4L2_BUF_TYPE_VIDEO_OUTPUT``, ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE`` and - ``V4L2_BUF_TYPE_VIDEO_OVERLAY``. See :c:type:`v4l2_buf_type` and the note above. + ``V4L2_BUF_TYPE_VIDEO_OVERLAY``. See :c:type:`v4l2_buf_type` and the note below. * - struct :ref:`v4l2_rect <v4l2-rect-crop>` - ``bounds`` - Defines the window within capturing or output is possible, this diff --git a/Documentation/media/uapi/v4l/vidioc-dqevent.rst b/Documentation/media/uapi/v4l/vidioc-dqevent.rst @@ -379,7 +379,17 @@ call. - 0x0001 - This event gets triggered when a resolution change is detected at an input. This can come from an input connector or from a video - decoder. + decoder. Applications will have to query the new resolution (if + any, the signal may also have been lost). + + *Important*: even if the new video timings appear identical to the old + ones, receiving this event indicates that there was an issue with the + video signal and you must stop and restart streaming + (:ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` + followed by :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`). The reason is + that many devices are not able to recover from a temporary loss of + signal and so restarting streaming I/O is required in order for the + hardware to synchronize to the video signal. Return Value diff --git a/Documentation/media/uapi/v4l/vidioc-g-crop.rst b/Documentation/media/uapi/v4l/vidioc-g-crop.rst @@ -84,7 +84,7 @@ When cropping is not supported then no parameters are changed and - Type of the data stream, set by the application. Only these types are valid here: ``V4L2_BUF_TYPE_VIDEO_CAPTURE``, ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``, ``V4L2_BUF_TYPE_VIDEO_OUTPUT``, ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE`` and - ``V4L2_BUF_TYPE_VIDEO_OVERLAY``. See :c:type:`v4l2_buf_type` and the note above. + ``V4L2_BUF_TYPE_VIDEO_OVERLAY``. See :c:type:`v4l2_buf_type` and the note below. * - struct :c:type:`v4l2_rect` - ``c`` - Cropping rectangle. The same co-ordinate system as for struct diff --git a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst @@ -257,14 +257,19 @@ EBUSY will also be cleared. This is a read-only flag, applications must not set this. * - ``V4L2_DV_FL_REDUCED_FPS`` - - CEA-861 specific: only valid for video transmitters, the flag is - cleared by receivers. It is also only valid for formats with the - ``V4L2_DV_FL_CAN_REDUCE_FPS`` flag set, for other formats the - flag will be cleared by the driver. If the application sets this - flag, then the pixelclock used to set up the transmitter is - divided by 1.001 to make it compatible with NTSC framerates. If - the transmitter can't generate such frequencies, then the flag - will also be cleared. + - CEA-861 specific: only valid for video transmitters or video + receivers that have the ``V4L2_DV_FL_CAN_DETECT_REDUCED_FPS`` + set. This flag is cleared otherwise. It is also only valid for + formats with the ``V4L2_DV_FL_CAN_REDUCE_FPS`` flag set, for other + formats the flag will be cleared by the driver. + + If the application sets this flag for a transmitter, then the + pixelclock used to set up the transmitter is divided by 1.001 to + make it compatible with NTSC framerates. If the transmitter can't + generate such frequencies, then the flag will be cleared. + + If a video receiver detects that the format uses a reduced framerate, + then it will set this flag to signal this to the application. * - ``V4L2_DV_FL_HALF_LINE`` - Specific to interlaced formats: if set, then the vertical backporch of field 1 (aka the odd field) is really one half-line @@ -294,3 +299,9 @@ EBUSY - If set, then the hdmi_vic field is valid and contains the Video Identification Code as per the HDMI standard (HDMI Vendor Specific InfoFrame). + * - ``V4L2_DV_FL_CAN_DETECT_REDUCED_FPS`` + - CEA-861 specific: only valid for video receivers, the flag is + cleared by transmitters. + If set, then the hardware can detect the difference between + regular framerates and framerates reduced by 1000/1001. E.g.: + 60 vs 59.94 Hz, 30 vs 29.97 Hz or 24 vs 23.976 Hz. diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions @@ -56,7 +56,8 @@ replace symbol V4L2_MEMORY_USERPTR :c:type:`v4l2_memory` # Documented enum v4l2_colorspace replace symbol V4L2_COLORSPACE_470_SYSTEM_BG :c:type:`v4l2_colorspace` replace symbol V4L2_COLORSPACE_470_SYSTEM_M :c:type:`v4l2_colorspace` -replace symbol V4L2_COLORSPACE_ADOBERGB :c:type:`v4l2_colorspace` +replace symbol V4L2_COLORSPACE_OPRGB :c:type:`v4l2_colorspace` +replace define V4L2_COLORSPACE_ADOBERGB :c:type:`v4l2_colorspace` replace symbol V4L2_COLORSPACE_BT2020 :c:type:`v4l2_colorspace` replace symbol V4L2_COLORSPACE_DCI_P3 :c:type:`v4l2_colorspace` replace symbol V4L2_COLORSPACE_DEFAULT :c:type:`v4l2_colorspace` @@ -69,7 +70,8 @@ replace symbol V4L2_COLORSPACE_SRGB :c:type:`v4l2_colorspace` # Documented enum v4l2_xfer_func replace symbol V4L2_XFER_FUNC_709 :c:type:`v4l2_xfer_func` -replace symbol V4L2_XFER_FUNC_ADOBERGB :c:type:`v4l2_xfer_func` +replace symbol V4L2_XFER_FUNC_OPRGB :c:type:`v4l2_xfer_func` +replace define V4L2_XFER_FUNC_ADOBERGB :c:type:`v4l2_xfer_func` replace symbol V4L2_XFER_FUNC_DCI_P3 :c:type:`v4l2_xfer_func` replace symbol V4L2_XFER_FUNC_DEFAULT :c:type:`v4l2_xfer_func` replace symbol V4L2_XFER_FUNC_NONE :c:type:`v4l2_xfer_func` @@ -278,6 +280,7 @@ replace define V4L2_DV_BT_STD_SDI dv-bt-standards replace define V4L2_DV_FL_REDUCED_BLANKING dv-bt-standards replace define V4L2_DV_FL_CAN_REDUCE_FPS dv-bt-standards +replace define V4L2_DV_FL_CAN_DETECT_REDUCED_FPS dv-bt-standards replace define V4L2_DV_FL_REDUCED_FPS dv-bt-standards replace define V4L2_DV_FL_HALF_LINE dv-bt-standards replace define V4L2_DV_FL_IS_CE_VIDEO dv-bt-standards diff --git a/MAINTAINERS b/MAINTAINERS @@ -4546,13 +4546,15 @@ L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/i2c/dw9714.c +F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt DONGWOON DW9807 LENS VOICE COIL DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Maintained -F: drivers/media/i2c/dw9807.c +F: drivers/media/i2c/dw9807-vcm.c +F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.txt DOUBLETALK DRIVER M: "James R. Van Zandt" <jrv@vanzandt.mv.com> @@ -9086,11 +9088,10 @@ F: drivers/media/dvb-frontends/cxd2880/* F: drivers/media/spi/cxd2880* MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES -M: Daniel Scheller <d.scheller.oss@gmail.com> L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: drivers/media/pci/ddbridge/* MEDIA DRIVERS FOR FREESCALE IMX @@ -9105,6 +9106,13 @@ F: drivers/staging/media/imx/ F: include/linux/imx-media.h F: include/media/imx.h +MEDIA DRIVER FOR FREESCALE IMX PXP +M: Philipp Zabel <p.zabel@pengutronix.de> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/platform/imx-pxp.[ch] + MEDIA DRIVERS FOR HELENE M: Abylay Ospan <aospan@netup.ru> L: linux-media@vger.kernel.org @@ -9135,11 +9143,10 @@ S: Supported F: drivers/media/dvb-frontends/lnbh25* MEDIA DRIVERS FOR MXL5XX TUNER DEMODULATORS -M: Daniel Scheller <d.scheller.oss@gmail.com> L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: drivers/media/dvb-frontends/mxl5xx* MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices @@ -9182,7 +9189,7 @@ F: drivers/media/platform/rcar-fcp.c F: include/media/rcar-fcp.h MEDIA DRIVERS FOR RENESAS - FDP1 -M: Kieran Bingham <kieran@bingham.xyz> +M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org T: git git://linuxtv.org/media_tree.git @@ -9202,6 +9209,7 @@ F: drivers/media/platform/rcar-vin/ MEDIA DRIVERS FOR RENESAS - VSP1 M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org T: git git://linuxtv.org/media_tree.git @@ -9210,19 +9218,17 @@ F: Documentation/devicetree/bindings/media/renesas,vsp1.txt F: drivers/media/platform/vsp1/ MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs -M: Daniel Scheller <d.scheller.oss@gmail.com> L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: drivers/media/dvb-frontends/stv0910* MEDIA DRIVERS FOR ST STV6111 TUNER ICs -M: Daniel Scheller <d.scheller.oss@gmail.com> L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: drivers/media/dvb-frontends/stv6111* MEDIA DRIVERS FOR STM32 - DCMI @@ -13719,6 +13725,20 @@ S: Maintained F: drivers/media/i2c/imx274.c F: Documentation/devicetree/bindings/media/i2c/imx274.txt +SONY IMX319 SENSOR DRIVER +M: Bingbu Cao <bingbu.cao@intel.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/imx319.c + +SONY IMX355 SENSOR DRIVER +M: Tianshu Qiu <tian.shu.qiu@intel.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/imx355.c + SONY MEMORYSTICK CARD SUPPORT M: Alex Dubov <oakad@yahoo.com> W: http://tifmxx.berlios.de/ @@ -14038,7 +14058,7 @@ F: sound/soc/sti/ STI CEC DRIVER M: Benjamin Gaignard <benjamin.gaignard@linaro.org> S: Maintained -F: drivers/staging/media/st-cec/ +F: drivers/media/platform/sti/cec/ F: Documentation/devicetree/bindings/media/stih-cec.txt STK1160 USB VIDEO CAPTURE DRIVER @@ -15697,7 +15717,7 @@ M: Marek Szyprowski <m.szyprowski@samsung.com> M: Kyungmin Park <kyungmin.park@samsung.com> L: linux-media@vger.kernel.org S: Maintained -F: drivers/media/v4l2-core/videobuf2-* +F: drivers/media/common/videobuf2/* F: include/media/videobuf2-* VIMC VIRTUAL MEDIA CONTROLLER DRIVER diff --git a/arch/arm/boot/dts/gr-peach-audiocamerashield.dtsi b/arch/arm/boot/dts/gr-peach-audiocamerashield.dtsi @@ -69,10 +69,6 @@ port { ceu_in: endpoint { - hsync-active = <1>; - vsync-active = <1>; - bus-width = <8>; - pclk-sample = <1>; remote-endpoint = <&mt9v111_out>; }; }; diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c @@ -232,7 +232,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code, case MEDIA_BUS_FMT_BGR565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: - if (mbus_type == V4L2_MBUS_CSI2) + if (mbus_type == V4L2_MBUS_CSI2_DPHY) cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; else cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; @@ -359,7 +359,7 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, else csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; break; - case V4L2_MBUS_CSI2: + case V4L2_MBUS_CSI2_DPHY: /* * MIPI CSI-2 requires non gated clock mode, all other * parameters are not applicable for MIPI CSI-2 bus. @@ -611,7 +611,7 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, if (vc > 3) return -EINVAL; - ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2); + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY); if (ret < 0) return ret; diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c @@ -45,7 +45,7 @@ int picolcd_raw_cir(struct picolcd_data *data, { unsigned long flags; int i, w, sz; - DEFINE_IR_RAW_EVENT(rawir); + struct ir_raw_event rawir = {}; /* ignore if rc_dev is NULL or status is shunned */ spin_lock_irqsave(&data->lock, flags); @@ -67,7 +67,6 @@ int picolcd_raw_cir(struct picolcd_data *data, */ sz = size > 0 ? min((int)raw_data[0], size-1) : 0; for (i = 0; i+1 < sz; i += 2) { - init_ir_raw_event(&rawir); w = (raw_data[i] << 8) | (raw_data[i+1]); rawir.pulse = !!(w & 0x8000); rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w); diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o +cec-objs := cec-core.o cec-adap.o cec-api.o ifeq ($(CONFIG_CEC_NOTIFIER),y) cec-objs += cec-notifier.o diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c @@ -62,6 +62,19 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr return adap->log_addrs.primary_device_type[i < 0 ? 0 : i]; } +u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, + unsigned int *offset) +{ + unsigned int loc = cec_get_edid_spa_location(edid, size); + + if (offset) + *offset = loc; + if (loc == 0) + return CEC_PHYS_ADDR_INVALID; + return (edid[loc] << 8) | edid[loc + 1]; +} +EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); + /* * Queue a new event for this filehandle. If ts == 0, then set it * to the current time. @@ -341,7 +354,7 @@ static void cec_data_completed(struct cec_data *data) * * This function is called with adap->lock held. */ -static void cec_data_cancel(struct cec_data *data) +static void cec_data_cancel(struct cec_data *data, u8 tx_status) { /* * It's either the current transmit, or it is a pending @@ -356,13 +369,11 @@ static void cec_data_cancel(struct cec_data *data) } if (data->msg.tx_status & CEC_TX_STATUS_OK) { - /* Mark the canceled RX as a timeout */ data->msg.rx_ts = ktime_get_ns(); - data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; + data->msg.rx_status = CEC_RX_STATUS_ABORTED; } else { - /* Mark the canceled TX as an error */ data->msg.tx_ts = ktime_get_ns(); - data->msg.tx_status |= CEC_TX_STATUS_ERROR | + data->msg.tx_status |= tx_status | CEC_TX_STATUS_MAX_RETRIES; data->msg.tx_error_cnt++; data->attempts = 0; @@ -390,15 +401,15 @@ static void cec_flush(struct cec_adapter *adap) while (!list_empty(&adap->transmit_queue)) { data = list_first_entry(&adap->transmit_queue, struct cec_data, list); - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); } if (adap->transmitting) - cec_data_cancel(adap->transmitting); + cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED); /* Cancel the pending timeout work. */ list_for_each_entry_safe(data, n, &adap->wait_queue, list) { if (cancel_delayed_work(&data->work)) - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_OK); /* * If cancel_delayed_work returned false, then * the cec_wait_timeout function is running, @@ -474,12 +485,13 @@ int cec_thread_func(void *_adap) * so much traffic on the bus that the adapter was * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). */ - dprintk(1, "%s: message %*ph timed out\n", __func__, + pr_warn("cec-%s: message %*ph timed out\n", adap->name, adap->transmitting->msg.len, adap->transmitting->msg.msg); adap->tx_timeouts++; /* Just give up on this. */ - cec_data_cancel(adap->transmitting); + cec_data_cancel(adap->transmitting, + CEC_TX_STATUS_TIMEOUT); goto unlock; } @@ -514,9 +526,11 @@ int cec_thread_func(void *_adap) if (data->attempts) { /* should be >= 3 data bit periods for a retry */ signal_free_time = CEC_SIGNAL_FREE_TIME_RETRY; - } else if (data->new_initiator) { + } else if (adap->last_initiator != + cec_msg_initiator(&data->msg)) { /* should be >= 5 data bit periods for new initiator */ signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; + adap->last_initiator = cec_msg_initiator(&data->msg); } else { /* * should be >= 7 data bit periods for sending another @@ -530,7 +544,7 @@ int cec_thread_func(void *_adap) /* Tell the adapter to transmit, cancel on error */ if (adap->ops->adap_transmit(adap, data->attempts, signal_free_time, &data->msg)) - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); unlock: mutex_unlock(&adap->lock); @@ -701,9 +715,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, struct cec_fh *fh, bool block) { struct cec_data *data; - u8 last_initiator = 0xff; - unsigned int timeout; - int res = 0; msg->rx_ts = 0; msg->tx_ts = 0; @@ -813,23 +824,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, data->adap = adap; data->blocking = block; - /* - * Determine if this message follows a message from the same - * initiator. Needed to determine the free signal time later on. - */ - if (msg->len > 1) { - if (!(list_empty(&adap->transmit_queue))) { - const struct cec_data *last; - - last = list_last_entry(&adap->transmit_queue, - const struct cec_data, list); - last_initiator = cec_msg_initiator(&last->msg); - } else if (adap->transmitting) { - last_initiator = - cec_msg_initiator(&adap->transmitting->msg); - } - } - data->new_initiator = last_initiator != cec_msg_initiator(msg); init_completion(&data->c); INIT_DELAYED_WORK(&data->work, cec_wait_timeout); @@ -846,47 +840,22 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, return 0; /* - * If we don't get a completion before this time something is really - * wrong and we time out. - */ - timeout = CEC_XFER_TIMEOUT_MS; - /* Add the requested timeout if we have to wait for a reply as well */ - if (msg->timeout) - timeout += msg->timeout; - - /* * Release the lock and wait, retake the lock afterwards. */ mutex_unlock(&adap->lock); - res = wait_for_completion_killable_timeout(&data->c, - msecs_to_jiffies(timeout)); + wait_for_completion_killable(&data->c); + if (!data->completed) + cancel_delayed_work_sync(&data->work); mutex_lock(&adap->lock); - if (data->completed) { - /* The transmit completed (possibly with an error) */ - *msg = data->msg; - kfree(data); - return 0; - } - /* - * The wait for completion timed out or was interrupted, so mark this - * as non-blocking and disconnect from the filehandle since it is - * still 'in flight'. When it finally completes it will just drop the - * result silently. - */ - data->blocking = false; - if (data->fh) - list_del(&data->xfer_list); - data->fh = NULL; + /* Cancel the transmit if it was interrupted */ + if (!data->completed) + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); - if (res == 0) { /* timed out */ - /* Check if the reply or the transmit failed */ - if (msg->timeout && (msg->tx_status & CEC_TX_STATUS_OK)) - msg->rx_status = CEC_RX_STATUS_TIMEOUT; - else - msg->tx_status = CEC_TX_STATUS_MAX_RETRIES; - } - return res > 0 ? 0 : res; + /* The transmit completed (possibly with an error) */ + *msg = data->msg; + kfree(data); + return 0; } /* Helper function to be used by drivers and this framework. */ @@ -1044,6 +1013,8 @@ void cec_received_msg_ts(struct cec_adapter *adap, mutex_lock(&adap->lock); dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); + adap->last_initiator = 0xff; + /* Check if this message was for us (directed or broadcast). */ if (!cec_msg_is_broadcast(msg)) valid_la = cec_has_log_addr(adap, msg_dest); @@ -1506,6 +1477,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) } mutex_lock(&adap->devnode.lock); + adap->last_initiator = 0xff; + if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) && adap->ops->adap_enable(adap, true)) { mutex_unlock(&adap->devnode.lock); diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c @@ -77,9 +77,9 @@ static long cec_adap_g_caps(struct cec_adapter *adap, { struct cec_caps caps = {}; - strlcpy(caps.driver, adap->devnode.dev.parent->driver->name, + strscpy(caps.driver, adap->devnode.dev.parent->driver->name, sizeof(caps.driver)); - strlcpy(caps.name, adap->name, sizeof(caps.name)); + strscpy(caps.name, adap->name, sizeof(caps.name)); caps.available_log_addrs = adap->available_log_addrs; caps.capabilities = adap->capabilities; caps.version = LINUX_VERSION_CODE; @@ -101,6 +101,23 @@ static long cec_adap_g_phys_addr(struct cec_adapter *adap, return 0; } +static int cec_validate_phys_addr(u16 phys_addr) +{ + int i; + + if (phys_addr == CEC_PHYS_ADDR_INVALID) + return 0; + for (i = 0; i < 16; i += 4) + if (phys_addr & (0xf << i)) + break; + if (i == 16) + return 0; + for (i += 4; i < 16; i += 4) + if ((phys_addr & (0xf << i)) == 0) + return -EINVAL; + return 0; +} + static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh, bool block, __u16 __user *parg) { @@ -112,7 +129,7 @@ static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh, if (copy_from_user(&phys_addr, parg, sizeof(phys_addr))) return -EFAULT; - err = cec_phys_addr_validate(phys_addr, NULL, NULL); + err = cec_validate_phys_addr(phys_addr); if (err) return err; mutex_lock(&adap->lock); @@ -665,6 +682,7 @@ const struct file_operations cec_devnode_fops = { .owner = THIS_MODULE, .open = cec_open, .unlocked_ioctl = cec_ioctl, + .compat_ioctl = cec_ioctl, .release = cec_release, .poll = cec_poll, .llseek = no_llseek, diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c @@ -264,7 +264,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap = kzalloc(sizeof(*adap), GFP_KERNEL); if (!adap) return ERR_PTR(-ENOMEM); - strlcpy(adap->name, name, sizeof(adap->name)); + strscpy(adap->name, name, sizeof(adap->name)); adap->phys_addr = CEC_PHYS_ADDR_INVALID; adap->cec_pin_is_high = true; adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; @@ -307,12 +307,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, return ERR_PTR(-ENOMEM); } - snprintf(adap->device_name, sizeof(adap->device_name), - "RC for %s", name); snprintf(adap->input_phys, sizeof(adap->input_phys), - "%s/input0", name); + "%s/input0", adap->name); - adap->rc->device_name = adap->device_name; + adap->rc->device_name = adap->name; adap->rc->input_phys = adap->input_phys; adap->rc->input_id.bustype = BUS_CEC; adap->rc->input_id.vendor = 0; diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <media/cec.h> - -/* - * This EDID is expected to be a CEA-861 compliant, which means that there are - * at least two blocks and one or more of the extensions blocks are CEA-861 - * blocks. - * - * The returned location is guaranteed to be < size - 1. - */ -static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size) -{ - unsigned int blocks = size / 128; - unsigned int block; - u8 d; - - /* Sanity check: at least 2 blocks and a multiple of the block size */ - if (blocks < 2 || size % 128) - return 0; - - /* - * If there are fewer extension blocks than the size, then update - * 'blocks'. It is allowed to have more extension blocks than the size, - * since some hardware can only read e.g. 256 bytes of the EDID, even - * though more blocks are present. The first CEA-861 extension block - * should normally be in block 1 anyway. - */ - if (edid[0x7e] + 1 < blocks) - blocks = edid[0x7e] + 1; - - for (block = 1; block < blocks; block++) { - unsigned int offset = block * 128; - - /* Skip any non-CEA-861 extension blocks */ - if (edid[offset] != 0x02 || edid[offset + 1] != 0x03) - continue; - - /* search Vendor Specific Data Block (tag 3) */ - d = edid[offset + 2] & 0x7f; - /* Check if there are Data Blocks */ - if (d <= 4) - continue; - if (d > 4) { - unsigned int i = offset + 4; - unsigned int end = offset + d; - - /* Note: 'end' is always < 'size' */ - do { - u8 tag = edid[i] >> 5; - u8 len = edid[i] & 0x1f; - - if (tag == 3 && len >= 5 && i + len <= end && - edid[i + 1] == 0x03 && - edid[i + 2] == 0x0c && - edid[i + 3] == 0x00) - return i + 4; - i += len + 1; - } while (i < end); - } - } - return 0; -} - -u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, - unsigned int *offset) -{ - unsigned int loc = cec_get_edid_spa_location(edid, size); - - if (offset) - *offset = loc; - if (loc == 0) - return CEC_PHYS_ADDR_INVALID; - return (edid[loc] << 8) | edid[loc + 1]; -} -EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); - -void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr) -{ - unsigned int loc = cec_get_edid_spa_location(edid, size); - u8 sum = 0; - unsigned int i; - - if (loc == 0) - return; - edid[loc] = phys_addr >> 8; - edid[loc + 1] = phys_addr & 0xff; - loc &= ~0x7f; - - /* update the checksum */ - for (i = loc; i < loc + 127; i++) - sum += edid[i]; - edid[i] = 256 - sum; -} -EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr); - -u16 cec_phys_addr_for_input(u16 phys_addr, u8 input) -{ - /* Check if input is sane */ - if (WARN_ON(input == 0 || input > 0xf)) - return CEC_PHYS_ADDR_INVALID; - - if (phys_addr == 0) - return input << 12; - - if ((phys_addr & 0x0fff) == 0) - return phys_addr | (input << 8); - - if ((phys_addr & 0x00ff) == 0) - return phys_addr | (input << 4); - - if ((phys_addr & 0x000f) == 0) - return phys_addr | input; - - /* - * All nibbles are used so no valid physical addresses can be assigned - * to the input. - */ - return CEC_PHYS_ADDR_INVALID; -} -EXPORT_SYMBOL_GPL(cec_phys_addr_for_input); - -int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) -{ - int i; - - if (parent) - *parent = phys_addr; - if (port) - *port = 0; - if (phys_addr == CEC_PHYS_ADDR_INVALID) - return 0; - for (i = 0; i < 16; i += 4) - if (phys_addr & (0xf << i)) - break; - if (i == 16) - return 0; - if (parent) - *parent = phys_addr & (0xfff0 << i); - if (port) - *port = (phys_addr >> i) & 0xf; - for (i += 4; i < 16; i += 4) - if ((phys_addr & (0xf << i)) == 0) - return -EINVAL; - return 0; -} -EXPORT_SYMBOL_GPL(cec_phys_addr_validate); diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c @@ -935,6 +935,17 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) /* Start bit, switch to receive state */ pin->ts = ts; pin->state = CEC_ST_RX_START_BIT_LOW; + /* + * If a transmit is pending, then that transmit should + * use a signal free time of no more than + * CEC_SIGNAL_FREE_TIME_NEW_INITIATOR since it will + * have a new initiator due to the receive that is now + * starting. + */ + if (pin->tx_msg.len && pin->tx_signal_free_time > + CEC_SIGNAL_FREE_TIME_NEW_INITIATOR) + pin->tx_signal_free_time = + CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; break; } if (ktime_to_ns(pin->ts) == 0) @@ -1157,6 +1168,15 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, { struct cec_pin *pin = adap->pin; + /* + * If a receive is in progress, then this transmit should use + * a signal free time of max CEC_SIGNAL_FREE_TIME_NEW_INITIATOR + * since when it starts transmitting it will have a new initiator. + */ + if (pin->state != CEC_ST_IDLE && + signal_free_time > CEC_SIGNAL_FREE_TIME_NEW_INITIATOR) + signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; + pin->tx_signal_free_time = signal_free_time; pin->tx_extra_bytes = 0; pin->tx_msg = *msg; diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c @@ -226,12 +226,12 @@ int flexcop_i2c_init(struct flexcop_device *fc) fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; - strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", - sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", - sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", - sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); + strscpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", + sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); + strscpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", + sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); + strscpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", + sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c @@ -569,7 +569,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, qctrl->step = step; qctrl->default_value = def; qctrl->reserved[0] = qctrl->reserved[1] = 0; - strlcpy(qctrl->name, name, sizeof(qctrl->name)); + strscpy(qctrl->name, name, sizeof(qctrl->name)); return 0; default: diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c @@ -606,7 +606,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, vfd->tvnorms = 0; for (i = 0; i < dev->ext_vv_data->num_stds; i++) vfd->tvnorms |= dev->ext_vv_data->stds[i].id; - strlcpy(vfd->name, name, sizeof(vfd->name)); + strscpy(vfd->name, name, sizeof(vfd->name)); video_set_drvdata(vfd, dev); err = video_register_device(vfd, type, -1); diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c @@ -451,8 +451,8 @@ static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability * struct video_device *vdev = video_devdata(file); struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - strcpy((char *)cap->driver, "saa7146 v4l2"); - strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); + strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver)); + strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | @@ -525,8 +525,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtd { if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; - strlcpy((char *)f->description, formats[f->index].name, - sizeof(f->description)); + strscpy((char *)f->description, formats[f->index].name, + sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; } diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c @@ -450,7 +450,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (entry) { entry->mode = default_mode; - strlcpy(entry->devpath, devpath, sizeof(entry->devpath)); + strscpy(entry->devpath, devpath, sizeof(entry->devpath)); list_add(&entry->entry, &g_smscore_registry); } else pr_err("failed to create smscore_registry.\n"); @@ -735,7 +735,7 @@ int smscore_register_device(struct smsdevice_params_t *params, dev->postload_handler = params->postload_handler; dev->device_flags = params->flags; - strlcpy(dev->devpath, params->devpath, sizeof(dev->devpath)); + strscpy(dev->devpath, params->devpath, sizeof(dev->devpath)); smscore_registry_settype(dev->devpath, params->device_type); diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c @@ -26,10 +26,10 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) const s32 *samples = (const void *)buf; for (i = 0; i < len >> 2; i++) { - DEFINE_IR_RAW_EVENT(ev); - - ev.duration = abs(samples[i]) * 1000; /* Convert to ns */ - ev.pulse = (samples[i] > 0) ? false : true; + struct ir_raw_event ev = { + .duration = abs(samples[i]) * 1000, /* Convert to ns */ + .pulse = (samples[i] > 0) ? false : true + }; ir_raw_event_store(coredev->ir.dev, &ev); } @@ -55,7 +55,7 @@ int sms_ir_init(struct smscore_device_t *coredev) snprintf(coredev->ir.name, sizeof(coredev->ir.name), "SMS IR (%s)", sms_get_board(board_id)->name); - strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); + strscpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); dev->device_name = coredev->ir.name; diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c @@ -602,14 +602,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][1] = { 3046, 3054, 886 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][2] = { 0, 3058, 3031 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][3] = { 360, 3079, 877 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][4] = { 3103, 587, 3027 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][5] = { 3116, 723, 861 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][6] = { 789, 744, 3025 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 }, @@ -658,14 +658,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][1] = { 3046, 3054, 886 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][2] = { 0, 3058, 3031 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][3] = { 360, 3079, 877 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][4] = { 3103, 587, 3027 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][5] = { 3116, 723, 861 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][6] = { 789, 744, 3025 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 }, @@ -714,14 +714,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][2] = { 851, 3033, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][3] = { 851, 3033, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][4] = { 3033, 851, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][5] = { 3033, 851, 851 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3033 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 }, @@ -770,14 +770,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][5] = { 2599, 901, 909 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][6] = { 991, 0, 2966 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][1] = { 2989, 3120, 1180 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][2] = { 1913, 3011, 3009 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][3] = { 1836, 3099, 1105 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][4] = { 2627, 413, 2966 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][5] = { 2576, 943, 951 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][6] = { 1026, 0, 2942 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][1] = { 2989, 3120, 1180 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][2] = { 1913, 3011, 3009 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][3] = { 1836, 3099, 1105 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][4] = { 2627, 413, 2966 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][5] = { 2576, 943, 951 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][6] = { 1026, 0, 2942 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2879, 3022, 874 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][2] = { 1688, 2903, 2901 }, @@ -826,14 +826,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][5] = { 3001, 800, 799 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3071 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 776 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][2] = { 1068, 3033, 3033 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][3] = { 1068, 3033, 776 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][4] = { 2977, 851, 3048 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][5] = { 2977, 851, 851 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3048 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 776 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][2] = { 1068, 3033, 3033 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][3] = { 1068, 3033, 776 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][4] = { 2977, 851, 3048 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][5] = { 2977, 851, 851 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3048 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 423 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][2] = { 749, 2926, 2926 }, @@ -882,14 +882,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][2] = { 851, 3033, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][3] = { 851, 3033, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][4] = { 3033, 851, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][5] = { 3033, 851, 851 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3033 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 }, @@ -922,62 +922,62 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1812, 886, 886 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1812 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 1063 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 1828, 3033, 3033 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 1828, 3033, 1063 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 2633, 851, 2979 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 2633, 851, 851 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 2979 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 1022 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 1402, 1812, 1812 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 1402, 1812, 1022 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1692, 886, 1797 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1692, 886, 886 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1797 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 1063 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][2] = { 1828, 3033, 3033 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][3] = { 1828, 3033, 1063 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][4] = { 2633, 851, 2979 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][5] = { 2633, 851, 851 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 2979 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 1022 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 1402, 1812, 1812 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 1402, 1812, 1022 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1692, 886, 1797 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1692, 886, 886 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1797 }, + [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 }, @@ -994,14 +994,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][5] = { 2517, 1159, 900 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][6] = { 1042, 870, 2917 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][1] = { 2976, 3018, 1315 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][2] = { 2024, 2942, 3011 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][3] = { 1930, 2926, 1256 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][4] = { 2563, 1227, 2916 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][5] = { 2494, 1183, 943 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][6] = { 1073, 916, 2894 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][1] = { 2976, 3018, 1315 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][2] = { 2024, 2942, 3011 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][3] = { 1930, 2926, 1256 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][4] = { 2563, 1227, 2916 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][5] = { 2494, 1183, 943 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][6] = { 1073, 916, 2894 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][1] = { 2864, 2910, 1024 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][2] = { 1811, 2826, 2903 }, @@ -1050,14 +1050,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][5] = { 2880, 998, 902 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][6] = { 816, 823, 2940 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][1] = { 3029, 3028, 1255 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][2] = { 1406, 2988, 3011 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][3] = { 1398, 2983, 1190 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][4] = { 2860, 1050, 2939 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][5] = { 2857, 1033, 945 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][6] = { 866, 873, 2916 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][1] = { 3029, 3028, 1255 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][2] = { 1406, 2988, 3011 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][3] = { 1398, 2983, 1190 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][4] = { 2860, 1050, 2939 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][5] = { 2857, 1033, 945 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][6] = { 866, 873, 2916 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][1] = { 2923, 2921, 957 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][2] = { 1125, 2877, 2902 }, @@ -1128,7 +1128,7 @@ static const double rec709_to_240m[3][3] = { { 0.0016327, 0.0044133, 0.9939540 }, }; -static const double rec709_to_adobergb[3][3] = { +static const double rec709_to_oprgb[3][3] = { { 0.7151627, 0.2848373, -0.0000000 }, { 0.0000000, 1.0000000, 0.0000000 }, { -0.0000000, 0.0411705, 0.9588295 }, @@ -1195,7 +1195,7 @@ static double transfer_rec709_to_rgb(double v) return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45); } -static double transfer_rgb_to_adobergb(double v) +static double transfer_rgb_to_oprgb(double v) { return pow(v, 1.0 / 2.19921875); } @@ -1251,8 +1251,8 @@ static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func, case V4L2_COLORSPACE_470_SYSTEM_M: mult_matrix(r, g, b, rec709_to_ntsc1953); break; - case V4L2_COLORSPACE_ADOBERGB: - mult_matrix(r, g, b, rec709_to_adobergb); + case V4L2_COLORSPACE_OPRGB: + mult_matrix(r, g, b, rec709_to_oprgb); break; case V4L2_COLORSPACE_BT2020: mult_matrix(r, g, b, rec709_to_bt2020); @@ -1284,10 +1284,10 @@ static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func, *g = transfer_rgb_to_srgb(*g); *b = transfer_rgb_to_srgb(*b); break; - case V4L2_XFER_FUNC_ADOBERGB: - *r = transfer_rgb_to_adobergb(*r); - *g = transfer_rgb_to_adobergb(*g); - *b = transfer_rgb_to_adobergb(*b); + case V4L2_XFER_FUNC_OPRGB: + *r = transfer_rgb_to_oprgb(*r); + *g = transfer_rgb_to_oprgb(*g); + *b = transfer_rgb_to_oprgb(*b); break; case V4L2_XFER_FUNC_DCI_P3: *r = transfer_rgb_to_dcip3(*r); @@ -1321,7 +1321,7 @@ int main(int argc, char **argv) V4L2_COLORSPACE_470_SYSTEM_BG, 0, V4L2_COLORSPACE_SRGB, - V4L2_COLORSPACE_ADOBERGB, + V4L2_COLORSPACE_OPRGB, V4L2_COLORSPACE_BT2020, 0, V4L2_COLORSPACE_DCI_P3, @@ -1336,7 +1336,7 @@ int main(int argc, char **argv) "V4L2_COLORSPACE_470_SYSTEM_BG", "", "V4L2_COLORSPACE_SRGB", - "V4L2_COLORSPACE_ADOBERGB", + "V4L2_COLORSPACE_OPRGB", "V4L2_COLORSPACE_BT2020", "", "V4L2_COLORSPACE_DCI_P3", @@ -1345,7 +1345,7 @@ int main(int argc, char **argv) "", "V4L2_XFER_FUNC_709", "V4L2_XFER_FUNC_SRGB", - "V4L2_XFER_FUNC_ADOBERGB", + "V4L2_XFER_FUNC_OPRGB", "V4L2_XFER_FUNC_SMPTE240M", "V4L2_XFER_FUNC_NONE", "V4L2_XFER_FUNC_DCI_P3", diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -202,6 +202,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: tpg->interleaved = true; tpg->vdownsampling[1] = 1; tpg->hdownsampling[1] = 1; @@ -235,6 +239,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: + case V4L2_PIX_FMT_Z16: tpg->color_enc = TGP_COLOR_ENC_LUMA; break; case V4L2_PIX_FMT_YUV444: @@ -351,6 +356,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: + case V4L2_PIX_FMT_Z16: tpg->twopixelsize[0] = 2 * 2; break; case V4L2_PIX_FMT_RGB24: @@ -392,6 +398,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SRGGB16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SBGGR16: tpg->twopixelsize[0] = 4; tpg->twopixelsize[1] = 4; break; @@ -1062,6 +1072,7 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset+1] = r_y_h >> 4; break; case V4L2_PIX_FMT_Y16: + case V4L2_PIX_FMT_Z16: /* * Ideally both bytes should be set to r_y_h, but then you won't * be able to detect endian problems. So keep it 0 except for @@ -1355,6 +1366,22 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset] |= (buf[0][offset] >> 4) & 0xf; buf[1][offset] |= (buf[1][offset] >> 4) & 0xf; break; + case V4L2_PIX_FMT_SBGGR16: + buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v; + buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s; + break; + case V4L2_PIX_FMT_SGBRG16: + buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s; + buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h; + break; + case V4L2_PIX_FMT_SGRBG16: + buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s; + buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v; + break; + case V4L2_PIX_FMT_SRGGB16: + buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h; + buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s; + break; } } @@ -1373,6 +1400,10 @@ unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line) case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: return buf_line & 1; default: return 0; @@ -1770,7 +1801,7 @@ typedef struct { u16 __; u8 _; } __packed x24; pos[7] = (chr & (0x01 << 0) ? fg : bg); \ } \ \ - pos += (tpg->hflip ? -8 : 8) / hdiv; \ + pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \ } \ } \ } while (0) @@ -2038,8 +2069,12 @@ void tpg_log_status(struct tpg_data *tpg) tpg->compose.left, tpg->compose.top); pr_info("tpg colorspace: %d\n", tpg->colorspace); pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func); - pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc); - pr_info("tpg HSV encoding: %d/%d\n", tpg->hsv_enc, tpg->real_hsv_enc); + if (tpg->color_enc == TGP_COLOR_ENC_HSV) + pr_info("tpg HSV encoding: %d/%d\n", + tpg->hsv_enc, tpg->real_hsv_enc); + else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) + pr_info("tpg Y'CbCr encoding: %d/%d\n", + tpg->ycbcr_enc, tpg->real_ycbcr_enc); pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); } diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c @@ -661,6 +661,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, { unsigned int num_buffers, allocated_buffers, num_planes = 0; unsigned plane_sizes[VB2_MAX_PLANES] = { }; + unsigned int i; int ret; if (q->streaming) { @@ -718,6 +719,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, if (ret) return ret; + /* Check that driver has set sane values */ + if (WARN_ON(!num_planes)) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + if (WARN_ON(!plane_sizes[i])) + return -EINVAL; + /* Finally, allocate buffers and video memory */ allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c @@ -1265,6 +1265,7 @@ static const struct file_operations dvb_demux_fops = { .owner = THIS_MODULE, .read = dvb_demux_read, .unlocked_ioctl = dvb_demux_ioctl, + .compat_ioctl = dvb_demux_ioctl, .open = dvb_demux_open, .release = dvb_demux_release, .poll = dvb_demux_poll, diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c @@ -2422,7 +2422,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, struct dvb_frontend_info *info = parg; memset(info, 0, sizeof(*info)); - strcpy(info->name, fe->ops.info.name); + strscpy(info->name, fe->ops.info.name, sizeof(info->name)); info->symbol_rate_min = fe->ops.info.symbol_rate_min; info->symbol_rate_max = fe->ops.info.symbol_rate_max; info->symbol_rate_tolerance = fe->ops.info.symbol_rate_tolerance; diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c @@ -194,7 +194,7 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking) spin_lock_init(&ctx->slock); INIT_LIST_HEAD(&ctx->dvb_q); - strlcpy(ctx->name, name, DVB_VB2_NAME_MAX); + strscpy(ctx->name, name, DVB_VB2_NAME_MAX); ctx->nonblocking = nonblocking; ctx->state = DVB_VB2_STATE_INIT; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c @@ -621,7 +621,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, unsigned demux_pad = 0; unsigned dvr_pad = 0; unsigned ntuner = 0, ndemod = 0; - int ret; + int ret, pad_source, pad_sink; static const char *connector_name = "Television"; if (!mdev) @@ -681,7 +681,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, if (ret) return ret; - if (!ntuner) + if (!ntuner) { ret = media_create_pad_links(mdev, MEDIA_ENT_F_CONN_RF, conn, 0, @@ -689,22 +689,31 @@ int dvb_create_media_graph(struct dvb_adapter *adap, demod, 0, MEDIA_LNK_FL_ENABLED, false); - else + } else { + pad_sink = media_get_pad_index(tuner, true, + PAD_SIGNAL_ANALOG); + if (pad_sink < 0) + return -EINVAL; ret = media_create_pad_links(mdev, MEDIA_ENT_F_CONN_RF, conn, 0, MEDIA_ENT_F_TUNER, - tuner, TUNER_PAD_RF_INPUT, + tuner, pad_sink, MEDIA_LNK_FL_ENABLED, false); + } if (ret) return ret; } if (ntuner && ndemod) { + pad_source = media_get_pad_index(tuner, true, + PAD_SIGNAL_ANALOG); + if (pad_source) + return -EINVAL; ret = media_create_pad_links(mdev, MEDIA_ENT_F_TUNER, - tuner, TUNER_PAD_OUTPUT, + tuner, pad_source, MEDIA_ENT_F_DTV_DEMOD, demod, 0, MEDIA_LNK_FL_ENABLED, false); @@ -967,9 +976,9 @@ struct i2c_client *dvb_module_probe(const char *module_name, return NULL; if (name) - strlcpy(board_info->type, name, I2C_NAME_SIZE); + strscpy(board_info->type, name, I2C_NAME_SIZE); else - strlcpy(board_info->type, module_name, I2C_NAME_SIZE); + strscpy(board_info->type, module_name, I2C_NAME_SIZE); board_info->addr = addr; board_info->platform_data = platform_data; diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig @@ -791,6 +791,16 @@ config DVB_LNBH25 An SEC control chip. Say Y when you want to support this chip. +config DVB_LNBH29 + tristate "LNBH29 SEC controller" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + LNB power supply and control voltage + regulator chip with step-up converter + and I2C interface for STMicroelectronics LNBH29. + Say Y when you want to support this chip. + config DVB_LNBP21 tristate "LNBP21/LNBH24 SEC controllers" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o obj-$(CONFIG_DVB_LG2160) += lg2160.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBH25) += lnbh25.o +obj-$(CONFIG_DVB_LNBH29) += lnbh29.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_LNBP22) += lnbp22.o obj-$(CONFIG_DVB_ISL6405) += isl6405.o diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c @@ -718,10 +718,12 @@ static int au8522_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &au8522_ops); #if defined(CONFIG_MEDIA_CONTROLLER) - state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; - state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; - state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; - state->pads[DEMOD_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[AU8522_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[AU8522_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; + state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[AU8522_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; + state->pads[AU8522_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[AU8522_PAD_AUDIO_OUT].sig_type = PAD_SIGNAL_AUDIO; sd->entity.function = MEDIA_ENT_F_ATV_DECODER; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h @@ -40,6 +40,13 @@ #define AU8522_DIGITAL_MODE 1 #define AU8522_SUSPEND_MODE 2 +enum au8522_pads { + AU8522_PAD_IF_INPUT, + AU8522_PAD_VID_OUT, + AU8522_PAD_AUDIO_OUT, + AU8522_NUM_PADS +}; + struct au8522_state { struct i2c_client *c; struct i2c_adapter *i2c; @@ -71,7 +78,7 @@ struct au8522_state { struct v4l2_ctrl_handler hdl; #ifdef CONFIG_MEDIA_CONTROLLER - struct media_pad pads[DEMOD_NUM_PADS]; + struct media_pad pads[AU8522_NUM_PADS]; #endif }; diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c @@ -1087,7 +1087,7 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, if (config->dont_use_pll) cx24123_repeater_mode(state, 1, 0); - strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", + strscpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller * @@ -701,4 +702,4 @@ module_i2c_driver(cxd2099_driver); MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver"); MODULE_AUTHOR("Ralph Metzler"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2099.h: Driver for the Sony CXD2099AR Common Interface Controller * diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -540,7 +540,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *config, pdata.attach_in_use = true; memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "cxd2820r", I2C_NAME_SIZE); + strscpy(board_info.type, "cxd2820r", I2C_NAME_SIZE); board_info.addr = config->i2c_address; board_info.platform_data = &pdata; client = i2c_new_device(adapter, &board_info); diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c @@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) { - strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name)); + strscpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->algo = algo; i2c_adap->algo_data = NULL; i2c_set_adapdata(i2c_adap, mst); diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -3555,8 +3555,8 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg if (!ext_attr->has_smatx) return -EIO; switch (uio_cfg->mode) { - case DRX_UIO_MODE_FIRMWARE_SMA: /* falltrough */ - case DRX_UIO_MODE_FIRMWARE_SAW: /* falltrough */ + case DRX_UIO_MODE_FIRMWARE_SMA: /* fall through */ + case DRX_UIO_MODE_FIRMWARE_SAW: /* fall through */ case DRX_UIO_MODE_READWRITE: ext_attr->uio_sma_tx_mode = uio_cfg->mode; break; @@ -3579,7 +3579,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg if (!ext_attr->has_smarx) return -EIO; switch (uio_cfg->mode) { - case DRX_UIO_MODE_FIRMWARE0: /* falltrough */ + case DRX_UIO_MODE_FIRMWARE0: /* fall through */ case DRX_UIO_MODE_READWRITE: ext_attr->uio_sma_rx_mode = uio_cfg->mode; break; @@ -3603,7 +3603,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg if (!ext_attr->has_gpio) return -EIO; switch (uio_cfg->mode) { - case DRX_UIO_MODE_FIRMWARE0: /* falltrough */ + case DRX_UIO_MODE_FIRMWARE0: /* fall through */ case DRX_UIO_MODE_READWRITE: ext_attr->uio_gpio_mode = uio_cfg->mode; break; @@ -3639,7 +3639,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg } ext_attr->uio_irqn_mode = uio_cfg->mode; break; - case DRX_UIO_MODE_FIRMWARE0: /* falltrough */ + case DRX_UIO_MODE_FIRMWARE0: /* fall through */ default: return -EINVAL; break; diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c @@ -929,7 +929,7 @@ struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config, struct i2c_board_info board_info = {}; struct lgdt330x_config config = *_config; - strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type)); + strscpy(board_info.type, "lgdt330x", sizeof(board_info.type)); board_info.addr = demod_address; board_info.platform_data = &config; client = i2c_new_device(i2c, &board_info); diff --git a/drivers/media/dvb-frontends/lnbh29.c b/drivers/media/dvb-frontends/lnbh29.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for LNB supply and control IC STMicroelectronics LNBH29 +// +// Copyright (c) 2018 Socionext Inc. + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> + +#include <media/dvb_frontend.h> +#include "lnbh29.h" + +/** + * struct lnbh29_priv - LNBH29 driver private data + * @i2c: Pointer to the I2C adapter structure + * @i2c_address: I2C address of LNBH29 chip + * @config: Registers configuration + * offset 0: 1st register address, always 0x01 (DATA) + * offset 1: DATA register value + */ +struct lnbh29_priv { + struct i2c_adapter *i2c; + u8 i2c_address; + u8 config[2]; +}; + +#define LNBH29_STATUS_OLF BIT(0) +#define LNBH29_STATUS_OTF BIT(1) +#define LNBH29_STATUS_VMON BIT(2) +#define LNBH29_STATUS_PNG BIT(3) +#define LNBH29_STATUS_PDO BIT(4) +#define LNBH29_VSEL_MASK GENMASK(2, 0) +#define LNBH29_VSEL_0 0x00 +/* Min: 13.188V, Typ: 13.667V, Max:14V */ +#define LNBH29_VSEL_13 0x03 +/* Min: 18.158V, Typ: 18.817V, Max:19.475V */ +#define LNBH29_VSEL_18 0x07 + +static int lnbh29_read_vmon(struct lnbh29_priv *priv) +{ + u8 addr = 0x00; + u8 status[2]; + int ret; + struct i2c_msg msg[2] = { + { + .addr = priv->i2c_address, + .flags = 0, + .len = 1, + .buf = &addr + }, { + .addr = priv->i2c_address, + .flags = I2C_M_RD, + .len = sizeof(status), + .buf = status + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret >= 0 && ret != 2) + ret = -EIO; + if (ret < 0) { + dev_dbg(&priv->i2c->dev, "LNBH29 I2C transfer failed (%d)\n", + ret); + return ret; + } + + if (status[0] & (LNBH29_STATUS_OLF | LNBH29_STATUS_VMON)) { + dev_err(&priv->i2c->dev, + "LNBH29 voltage in failure state, status reg 0x%x\n", + status[0]); + return -EIO; + } + + return 0; +} + +static int lnbh29_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + struct lnbh29_priv *priv = fe->sec_priv; + u8 data_reg; + int ret; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .len = sizeof(priv->config), + .buf = priv->config + }; + + switch (voltage) { + case SEC_VOLTAGE_OFF: + data_reg = LNBH29_VSEL_0; + break; + case SEC_VOLTAGE_13: + data_reg = LNBH29_VSEL_13; + break; + case SEC_VOLTAGE_18: + data_reg = LNBH29_VSEL_18; + break; + default: + return -EINVAL; + } + priv->config[1] &= ~LNBH29_VSEL_MASK; + priv->config[1] |= data_reg; + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret >= 0 && ret != 1) + ret = -EIO; + if (ret < 0) { + dev_err(&priv->i2c->dev, "LNBH29 I2C transfer error (%d)\n", + ret); + return ret; + } + + /* Soft-start time (Vout 0V to 18V) is Typ. 6ms. */ + usleep_range(6000, 20000); + + if (voltage == SEC_VOLTAGE_OFF) + return 0; + + return lnbh29_read_vmon(priv); +} + +static void lnbh29_release(struct dvb_frontend *fe) +{ + lnbh29_set_voltage(fe, SEC_VOLTAGE_OFF); + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe, + struct lnbh29_config *cfg, + struct i2c_adapter *i2c) +{ + struct lnbh29_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return NULL; + + priv->i2c_address = (cfg->i2c_address >> 1); + priv->i2c = i2c; + priv->config[0] = 0x01; + priv->config[1] = cfg->data_config; + fe->sec_priv = priv; + + if (lnbh29_set_voltage(fe, SEC_VOLTAGE_OFF)) { + dev_err(&i2c->dev, "no LNBH29 found at I2C addr 0x%02x\n", + priv->i2c_address); + kfree(priv); + fe->sec_priv = NULL; + return NULL; + } + + fe->ops.release_sec = lnbh29_release; + fe->ops.set_voltage = lnbh29_set_voltage; + + dev_info(&i2c->dev, "LNBH29 attached at I2C addr 0x%02x\n", + priv->i2c_address); + + return fe; +} +EXPORT_SYMBOL(lnbh29_attach); + +MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>"); +MODULE_DESCRIPTION("STMicroelectronics LNBH29 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/lnbh29.h b/drivers/media/dvb-frontends/lnbh29.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for LNB supply and control IC STMicroelectronics LNBH29 + * + * Copyright (c) 2018 Socionext Inc. + */ + +#ifndef LNBH29_H +#define LNBH29_H + +#include <linux/i2c.h> +#include <linux/dvb/frontend.h> + +/* Using very low E.S.R. capacitors or ceramic caps */ +#define LNBH29_DATA_COMP BIT(3) + +struct lnbh29_config { + u8 i2c_address; + u8 data_config; +}; + +#if IS_REACHABLE(CONFIG_DVB_LNBH29) +struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe, + struct lnbh29_config *cfg, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe, + struct lnbh29_config *cfg, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c @@ -1284,7 +1284,7 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, pdata.attach_in_use = true; memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); + strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); board_info.addr = cfg->i2c_addr; board_info.platform_data = &pdata; client = i2c_new_device(i2c, &board_info); diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c @@ -815,17 +815,20 @@ struct dvb_frontend *mt312_attach(const struct mt312_config *config, switch (state->id) { case ID_VP310: - strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S"); + strscpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S", + sizeof(state->frontend.ops.info.name)); state->xtal = MT312_PLL_CLK; state->freq_mult = 9; break; case ID_MT312: - strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S"); + strscpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S", + sizeof(state->frontend.ops.info.name)); state->xtal = MT312_PLL_CLK; state->freq_mult = 6; break; case ID_ZL10313: - strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S"); + strscpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S", + sizeof(state->frontend.ops.info.name)); state->xtal = MT312_PLL_CLK_10_111; state->freq_mult = 9; break; diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the MaxLinear MxL5xx family of tuners/demods * @@ -17,7 +18,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * */ #include <linux/kernel.h> @@ -739,6 +739,7 @@ static int get_frontend(struct dvb_frontend *fe, default: break; } + /* Fall through */ case SYS_DVBS: switch ((enum MXL_HYDRA_MODULATION_E) reg_data[DMD_MODULATION_SCHEME_ADDR]) { @@ -1893,4 +1894,4 @@ EXPORT_SYMBOL_GPL(mxl5xx_attach); MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver"); MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/mxl5xx.h b/drivers/media/dvb-frontends/mxl5xx.h @@ -1,3 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for the MaxLinear MxL5xx family of tuners/demods + * + * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * developed for Digital Devices GmbH + * + * based on code: + * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved + * which was released under GPL V2 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef _MXL5XX_H_ #define _MXL5XX_H_ diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Defines for the Maxlinear MX58x family of tuners/demods * diff --git a/drivers/media/dvb-frontends/mxl5xx_regs.h b/drivers/media/dvb-frontends/mxl5xx_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved * diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -439,8 +439,8 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, dev_dbg(&pdev->dev, "\n"); - strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); - strlcpy(cap->card, dev->vdev.name, sizeof(cap->card)); + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, dev->vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | V4L2_CAP_TUNER; @@ -976,7 +976,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type); if (v->index == 0) { - strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); + strscpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); v->type = V4L2_TUNER_ADC; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->rangelow = 300000; @@ -986,7 +986,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_tuner)) { ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_tuner, v); } else if (v->index == 1) { - strlcpy(v->name, "RF: <unknown>", sizeof(v->name)); + strscpy(v->name, "RF: <unknown>", sizeof(v->name)); v->type = V4L2_TUNER_RF; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->rangelow = 50000000; @@ -1133,7 +1133,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, if (f->index >= dev->num_formats) return -EINVAL; - strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c @@ -912,7 +912,7 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, state->frontend.demodulator_priv = state; /* create tuner i2c adapter */ - strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", + strscpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the ST STV0910 DVB-S/S2 demodulator. * @@ -1839,4 +1840,4 @@ EXPORT_SYMBOL_GPL(stv0910_attach); MODULE_DESCRIPTION("ST STV0910 multistandard frontend driver"); MODULE_AUTHOR("Ralph and Marcus Metzler, Manfred Voelkel"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/stv0910.h b/drivers/media/dvb-frontends/stv0910.h @@ -1,3 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for the ST STV0910 DVB-S/S2 demodulator. + * + * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * developed for Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef _STV0910_H_ #define _STV0910_H_ diff --git a/drivers/media/dvb-frontends/stv0910_regs.h b/drivers/media/dvb-frontends/stv0910_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * @DVB-S/DVB-S2 STMicroelectronics STV0900 register definitions * Author Manfred Voelkel, August 2013 diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the ST STV6111 tuner * @@ -11,7 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * */ #include <linux/kernel.h> @@ -687,4 +687,4 @@ EXPORT_SYMBOL_GPL(stv6111_attach); MODULE_DESCRIPTION("ST STV6111 satellite tuner driver"); MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/stv6111.h b/drivers/media/dvb-frontends/stv6111.h @@ -1,3 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for the ST STV6111 tuner + * + * Copyright (C) 2014 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef _STV6111_H_ #define _STV6111_H_ diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c @@ -781,7 +781,7 @@ static int tc90522_probe(struct i2c_client *client, adap->owner = THIS_MODULE; adap->algo = &tc90522_tuner_i2c_algo; adap->dev.parent = &client->dev; - strlcpy(adap->name, "tc90522_sub", sizeof(adap->name)); + strscpy(adap->name, "tc90522_sub", sizeof(adap->name)); i2c_set_adapdata(adap, state); ret = i2c_add_adapter(adap); if (ret < 0) diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c @@ -525,7 +525,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, pdata.attach_in_use = true; memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "ts2020", I2C_NAME_SIZE); + strscpy(board_info.type, "ts2020", I2C_NAME_SIZE); board_info.addr = config->tuner_address; board_info.platform_data = &pdata; client = i2c_new_device(i2c, &board_info); diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c @@ -499,7 +499,8 @@ static int zd1301_demod_probe(struct platform_device *pdev) goto err_kfree; /* Create I2C adapter */ - strlcpy(dev->adapter.name, "ZyDAS ZD1301 demod", sizeof(dev->adapter.name)); + strscpy(dev->adapter.name, "ZyDAS ZD1301 demod", + sizeof(dev->adapter.name)); dev->adapter.algo = &zd1301_demod_i2c_algorithm; dev->adapter.algo_data = NULL; dev->adapter.dev.parent = pdev->dev.parent; diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c @@ -288,8 +288,9 @@ struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, state->id = state->id & 0x0f; switch (state->id) { case ID_ZL10039: - strcpy(fe->ops.tuner_ops.info.name, - "Zarlink ZL10039 DVB-S tuner"); + strscpy(fe->ops.tuner_ops.info.name, + "Zarlink ZL10039 DVB-S tuner", + sizeof(fe->ops.tuner_ops.info.name)); break; default: dprintk("Chip ID=%x does not match a known type\n", state->id); diff --git a/drivers/media/firewire/firedtv-fe.c b/drivers/media/firewire/firedtv-fe.c @@ -247,7 +247,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) dev_err(fdtv->device, "no frontend for model type %d\n", fdtv->type); } - strcpy(fi->name, name); + strscpy(fi->name, name, sizeof(fi->name)); fdtv->fe.dvb = &fdtv->adapter; fdtv->fe.sec_priv = fdtv; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig @@ -614,6 +614,28 @@ config VIDEO_IMX274 This is a V4L2 sensor driver for the Sony IMX274 CMOS image sensor. +config VIDEO_IMX319 + tristate "Sony IMX319 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + help + This is a Video4Linux2 sensor driver for the Sony + IMX319 camera. + + To compile this driver as a module, choose M here: the + module will be called imx319. + +config VIDEO_IMX355 + tristate "Sony IMX355 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + help + This is a Video4Linux2 sensor driver for the Sony + IMX355 camera. + + To compile this driver as a module, choose M here: the + module will be called imx355. + config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" depends on VIDEO_V4L2 && I2C @@ -747,6 +769,7 @@ config VIDEO_OV772X tristate "OmniVision OV772x sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT + select REGMAP_SCCB ---help--- This is a Video4Linux2 sensor driver for the OmniVision OV772x camera. @@ -786,6 +809,7 @@ config VIDEO_OV7740 config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select REGMAP_SCCB ---help--- This is a V4L2 sensor driver for the Omnivision OV9650 and OV9652 camera sensors. diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile @@ -108,5 +108,7 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o +obj-$(CONFIG_VIDEO_IMX319) += imx319.o +obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c @@ -317,7 +317,7 @@ static int ad5820_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops); coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; coil->subdev.internal_ops = &ad5820_internal_ops; - strcpy(coil->subdev.name, "ad5820 focus"); + strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name)); ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL); if (ret < 0) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * adv7180.c Analog Devices ADV7180 video decoder driver * Copyright (c) 2009 Intel Corporation * Copyright (C) 2013 Cogent Embedded, Inc. * Copyright (C) 2013 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ - #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> @@ -761,7 +752,7 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd, struct adv7180_state *state = to_state(sd); if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { - cfg->type = V4L2_MBUS_CSI2; + cfg->type = V4L2_MBUS_CSI2_DPHY; cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver * with standard definition processor (SDP) * * Copyright (C) 2017 Renesas Electronics Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/delay.h> @@ -286,7 +282,7 @@ static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable) goto unlock; } - ret = adv748x_txb_power(state, enable); + ret = adv748x_tx_power(&state->txb, enable); if (ret) goto unlock; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Analog Devices ADV748X HDMI receiver with AFE * * Copyright (C) 2017 Renesas Electronics Corp. * - * 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. - * * Authors: * Koji Matsuoka <koji.matsuoka.xm@renesas.com> * Niklas Söderlund <niklas.soderlund@ragnatech.se> @@ -285,40 +281,23 @@ static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = { {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ {ADV748X_PAGE_TXB, 0x1e, 0x00}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 4-lane MIPI */ + {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ {ADV748X_PAGE_TXB, 0xc1, 0x3b}, /* ADI Required Write */ {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; -int adv748x_txa_power(struct adv748x_state *state, bool on) +int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) { + struct adv748x_state *state = tx->state; + const struct adv748x_reg_value *reglist; int val; - val = txa_read(state, ADV748X_CSI_FS_AS_LS); - if (val < 0) - return val; - - /* - * This test against BIT(6) is not documented by the datasheet, but was - * specified in the downstream driver. - * Track with a WARN_ONCE to determine if it is ever set by HW. - */ - WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), - "Enabling with unknown bit set"); + if (!is_tx_enabled(tx)) + return 0; - if (on) - return adv748x_write_regs(state, adv748x_power_up_txa_4lane); - - return adv748x_write_regs(state, adv748x_power_down_txa_4lane); -} - -int adv748x_txb_power(struct adv748x_state *state, bool on) -{ - int val; - - val = txb_read(state, ADV748X_CSI_FS_AS_LS); + val = tx_read(tx, ADV748X_CSI_FS_AS_LS); if (val < 0) return val; @@ -331,9 +310,13 @@ int adv748x_txb_power(struct adv748x_state *state, bool on) "Enabling with unknown bit set"); if (on) - return adv748x_write_regs(state, adv748x_power_up_txb_1lane); + reglist = is_txa(tx) ? adv748x_power_up_txa_4lane : + adv748x_power_up_txb_1lane; + else + reglist = is_txa(tx) ? adv748x_power_down_txa_4lane : + adv748x_power_down_txb_1lane; - return adv748x_write_regs(state, adv748x_power_down_txb_1lane); + return adv748x_write_regs(state, reglist); } /* ----------------------------------------------------------------------------- @@ -399,8 +382,6 @@ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { {ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */ {ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */ - /* Outputs Enabled */ - {ADV748X_PAGE_IO, 0x10, 0xa0}, /* Enable 4-lane CSI Tx & Pixel Port */ {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ @@ -454,10 +435,6 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { {ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */ {ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */ - /* Enable 1-Lane MIPI Tx, */ - /* enable pixel output and route SD through Pixel port */ - {ADV748X_PAGE_IO, 0x10, 0x70}, - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ @@ -482,6 +459,7 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { static int adv748x_reset(struct adv748x_state *state) { int ret; + u8 regval = 0; ret = adv748x_write_regs(state, adv748x_sw_reset); if (ret < 0) @@ -496,22 +474,24 @@ static int adv748x_reset(struct adv748x_state *state) if (ret) return ret; - adv748x_txa_power(state, 0); + adv748x_tx_power(&state->txa, 0); /* Init and power down TXB */ ret = adv748x_write_regs(state, adv748x_init_txb_1lane); if (ret) return ret; - adv748x_txb_power(state, 0); + adv748x_tx_power(&state->txb, 0); /* Disable chip powerdown & Enable HDMI Rx block */ io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN); - /* Enable 4-lane CSI Tx & Pixel Port */ - io_write(state, ADV748X_IO_10, ADV748X_IO_10_CSI4_EN | - ADV748X_IO_10_CSI1_EN | - ADV748X_IO_10_PIX_OUT_EN); + /* Conditionally enable TXa and TXb. */ + if (is_tx_enabled(&state->txa)) + regval |= ADV748X_IO_10_CSI4_EN; + if (is_tx_enabled(&state->txb)) + regval |= ADV748X_IO_10_CSI1_EN; + io_write(state, ADV748X_IO_10, regval); /* Use vid_std and v_freq as freerun resolution for CP */ cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO, @@ -569,7 +549,8 @@ static int adv748x_parse_dt(struct adv748x_state *state) { struct device_node *ep_np = NULL; struct of_endpoint ep; - bool found = false; + bool out_found = false; + bool in_found = false; for_each_endpoint_of_node(state->dev->of_node, ep_np) { of_graph_parse_endpoint(ep_np, &ep); @@ -592,10 +573,17 @@ static int adv748x_parse_dt(struct adv748x_state *state) of_node_get(ep_np); state->endpoints[ep.port] = ep_np; - found = true; + /* + * At least one input endpoint and one output endpoint shall + * be defined. + */ + if (ep.port < ADV748X_PORT_TXA) + in_found = true; + else + out_found = true; } - return found ? 0 : -ENODEV; + return in_found && out_found ? 0 : -ENODEV; } static void adv748x_dt_cleanup(struct adv748x_state *state) @@ -627,6 +615,17 @@ static int adv748x_probe(struct i2c_client *client, state->i2c_clients[ADV748X_PAGE_IO] = client; i2c_set_clientdata(client, state); + /* + * We can not use container_of to get back to the state with two TXs; + * Initialize the TXs's fields unconditionally on the endpoint + * presence to access them later. + */ + state->txa.state = state->txb.state = state; + state->txa.page = ADV748X_PAGE_TXA; + state->txb.page = ADV748X_PAGE_TXB; + state->txa.port = ADV748X_PORT_TXA; + state->txb.port = ADV748X_PORT_TXB; + /* Discover and process ports declared by the Device tree endpoints */ ret = adv748x_parse_dt(state); if (ret) { @@ -755,4 +754,4 @@ module_i2c_driver(adv748x_driver); MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>"); MODULE_DESCRIPTION("ADV748X video decoder"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Analog Devices ADV748X CSI-2 Transmitter * * Copyright (C) 2017 Renesas Electronics Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/module.h> @@ -18,11 +14,6 @@ #include "adv748x.h" -static bool is_txa(struct adv748x_csi2 *tx) -{ - return tx == &tx->state->txa; -} - static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) { @@ -87,15 +78,15 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd) * * Link HDMI->TXA, and AFE->TXB directly. */ - if (is_txa(tx)) { + if (is_txa(tx) && is_hdmi_enabled(state)) return adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd, ADV748X_HDMI_SOURCE); - } else { + if (!is_txa(tx) && is_afe_enabled(state)) return adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->afe.sd, ADV748X_AFE_SOURCE); - } + return 0; } static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { @@ -266,19 +257,10 @@ static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx) int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) { - struct device_node *ep; int ret; - /* We can not use container_of to get back to the state with two TXs */ - tx->state = state; - tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; - - ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB]; - if (!ep) { - adv_err(state, "No endpoint found for %s\n", - is_txa(tx) ? "txa" : "txb"); - return -ENODEV; - } + if (!is_tx_enabled(tx)) + return 0; /* Initialise the virtual channel */ adv748x_csi2_set_virtual_channel(tx, 0); @@ -288,7 +270,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) is_txa(tx) ? "txa" : "txb"); /* Ensure that matching is based upon the endpoint fwnodes */ - tx->sd.fwnode = of_fwnode_handle(ep); + tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]); /* Register internal ops for incremental subdev registration */ tx->sd.internal_ops = &adv748x_csi2_internal_ops; @@ -321,6 +303,9 @@ err_free_media: void adv748x_csi2_cleanup(struct adv748x_csi2 *tx) { + if (!is_tx_enabled(tx)) + return; + v4l2_async_unregister_subdev(&tx->sd); media_entity_cleanup(&tx->sd.entity); v4l2_ctrl_handler_free(&tx->ctrl_hdl); diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Analog Devices ADV748X HDMI receiver and Component Processor (CP) * * Copyright (C) 2017 Renesas Electronics Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/module.h> @@ -362,7 +358,7 @@ static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&state->mutex); - ret = adv748x_txa_power(state, enable); + ret = adv748x_tx_power(&state->txa, enable); if (ret) goto done; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for Analog Devices ADV748X video decoder and HDMI receiver * * Copyright (C) 2017 Renesas Electronics Corp. * - * 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. - * * Authors: * Koji Matsuoka <koji.matsuoka.xm@renesas.com> * Niklas Söderlund <niklas.soderlund@ragnatech.se> @@ -82,6 +78,7 @@ struct adv748x_csi2 { struct adv748x_state *state; struct v4l2_mbus_framefmt format; unsigned int page; + unsigned int port; struct media_pad pads[ADV748X_CSI2_NR_PADS]; struct v4l2_ctrl_handler ctrl_hdl; @@ -91,6 +88,18 @@ struct adv748x_csi2 { #define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier) #define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd) +#define is_tx_enabled(_tx) ((_tx)->state->endpoints[(_tx)->port] != NULL) +#define is_txa(_tx) ((_tx) == &(_tx)->state->txa) +#define is_afe_enabled(_state) \ + ((_state)->endpoints[ADV748X_PORT_AIN0] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN1] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN2] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN3] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN4] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN5] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN6] != NULL || \ + (_state)->endpoints[ADV748X_PORT_AIN7] != NULL) +#define is_hdmi_enabled(_state) ((_state)->endpoints[ADV748X_PORT_HDMI] != NULL) enum adv748x_hdmi_pads { ADV748X_HDMI_SINK, @@ -376,9 +385,6 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, #define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v) #define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v) -#define txa_read(s, r) adv748x_read(s, ADV748X_PAGE_TXA, r) -#define txb_read(s, r) adv748x_read(s, ADV748X_PAGE_TXB, r) - #define tx_read(t, r) adv748x_read(t->state, t->page, r) #define tx_write(t, r, v) adv748x_write(t->state, t->page, r, v) @@ -398,8 +404,7 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, int adv748x_register_subdevs(struct adv748x_state *state, struct v4l2_device *v4l2_dev); -int adv748x_txa_power(struct adv748x_state *state, bool on); -int adv748x_txb_power(struct adv748x_state *state, bool on); +int adv748x_tx_power(struct adv748x_csi2 *tx, bool on); int adv748x_afe_init(struct adv748x_afe *afe); void adv748x_afe_cleanup(struct adv748x_afe *afe); diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c @@ -1355,10 +1355,10 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, state->xfer_func = format->format.xfer_func; switch (format->format.colorspace) { - case V4L2_COLORSPACE_ADOBERGB: + case V4L2_COLORSPACE_OPRGB: c = HDMI_COLORIMETRY_EXTENDED; - ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 : - HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB; + ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 : + HDMI_EXTENDED_COLORIMETRY_OPRGB; break; case V4L2_COLORSPACE_SMPTE170M: c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c @@ -2284,8 +2284,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) state->aspect_ratio.numerator = 16; state->aspect_ratio.denominator = 9; - if (!state->edid.present) + if (!state->edid.present) { state->edid.blocks = 0; + cec_phys_addr_invalidate(state->cec_adap); + } v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n", __func__, edid->pad, state->edid.present); @@ -2295,8 +2297,8 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) edid->blocks = 2; return -E2BIG; } - pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc); - err = cec_phys_addr_validate(pa, &pa, NULL); + pa = v4l2_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc); + err = v4l2_phys_addr_validate(pa, &pa, NULL); if (err) return err; @@ -2474,7 +2476,7 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", "xvYCC Bt.601", "xvYCC Bt.709", "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", - "sYCC", "Adobe YCC 601", "AdobeRGB", "invalid", "invalid", + "sYCC", "opYCC 601", "opRGB", "invalid", "invalid", "invalid", "invalid", "invalid" }; static const char * const rgb_quantization_range_txt[] = { @@ -3093,7 +3095,7 @@ MODULE_DEVICE_TABLE(of, adv76xx_of_id); static int adv76xx_parse_dt(struct adv76xx_state *state) { - struct v4l2_fwnode_endpoint bus_cfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct device_node *endpoint; struct device_node *np; unsigned int flags; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c @@ -786,11 +786,13 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) /* Disable I2C access to internal EDID ram from HDMI DDC ports */ rep_write_and_or(sd, 0x77, 0xf3, 0x00); - if (!state->hdmi_edid.present) + if (!state->hdmi_edid.present) { + cec_phys_addr_invalidate(state->cec_adap); return 0; + } - pa = cec_get_edid_phys_addr(edid, 256, &spa_loc); - err = cec_phys_addr_validate(pa, &pa, NULL); + pa = v4l2_get_edid_phys_addr(edid, 256, &spa_loc); + err = v4l2_phys_addr_validate(pa, &pa, NULL); if (err) return err; @@ -1525,6 +1527,7 @@ static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, v4l2_find_dv_timings_cap(timings, adv7842_get_dv_timings_cap(sd), is_digital_input(sd) ? 250000 : 1000000, adv7842_check_dv_timings, NULL); + timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS; } static int adv7842_query_dv_timings(struct v4l2_subdev *sd, @@ -1596,6 +1599,14 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, bt->il_vbackporch = 0; } adv7842_fill_optional_dv_timings_fields(sd, timings); + if ((timings->bt.flags & V4L2_DV_FL_CAN_REDUCE_FPS) && + freq < bt->pixelclock) { + u32 reduced_freq = ((u32)bt->pixelclock / 1001) * 1000; + u32 delta_freq = abs(freq - reduced_freq); + + if (delta_freq < ((u32)bt->pixelclock - reduced_freq) / 2) + timings->bt.flags |= V4L2_DV_FL_REDUCED_FPS; + } } else { /* find format * Since LCVS values are inaccurate [REF_03, p. 339-340], diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c @@ -136,7 +136,6 @@ static int ak881x_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: sel->r.left = 0; sel->r.top = 0; sel->r.width = 720; diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c @@ -149,7 +149,7 @@ static int cs53l32a_probe(struct i2c_client *client, return -EIO; if (!id) - strlcpy(client->name, "cs53l32a", sizeof(client->name)); + strscpy(client->name, "cs53l32a", sizeof(client->name)); v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -701,10 +701,8 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, if (v > IR_MAX_DURATION) v = IR_MAX_DURATION; - init_ir_raw_event(&p->ir_core_data); - p->ir_core_data.pulse = u; - p->ir_core_data.duration = v; - p->ir_core_data.timeout = w; + p->ir_core_data = (struct ir_raw_event) + { .pulse = u, .duration = v, .timeout = w }; v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n", v, u ? "mark" : "space", w ? "(timed out)" : ""); diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c @@ -169,8 +169,9 @@ static int dw9714_probe(struct i2c_client *client) return 0; err_cleanup: - dw9714_subdev_cleanup(dw9714_dev); - dev_err(&client->dev, "Probe failed: %d\n", rval); + v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm); + media_entity_cleanup(&dw9714_dev->sd.entity); + return rval; } diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c @@ -218,7 +218,8 @@ static int dw9807_probe(struct i2c_client *client) return 0; err_cleanup: - dw9807_subdev_cleanup(dw9807_dev); + v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm); + media_entity_cleanup(&dw9807_dev->sd.entity); return rval; } @@ -229,7 +230,6 @@ static int dw9807_remove(struct i2c_client *client) struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd); pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); dw9807_subdev_cleanup(dw9807_dev); diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * imx274.c - IMX274 CMOS Image Sensor driver * @@ -6,18 +7,6 @@ * Leon Luo <leonl@leopardimaging.com> * Edwin Zou <edwinz@leopardimaging.com> * Luca Ceresoli <luca@lucaceresoli.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> @@ -76,7 +65,7 @@ */ #define IMX274_MIN_EXPOSURE_TIME (4 * 260 / 72) -#define IMX274_DEFAULT_MODE IMX274_BINNING_OFF +#define IMX274_DEFAULT_BINNING IMX274_BINNING_OFF #define IMX274_MAX_WIDTH (3840) #define IMX274_MAX_HEIGHT (2160) #define IMX274_MAX_FRAME_RATE (120) @@ -178,7 +167,7 @@ enum imx274_binning { * @nocpiop: Number of clocks per internal offset period (see "Integration Time * in Each Readout Drive Mode (CSI-2)" in the datasheet) */ -struct imx274_frmfmt { +struct imx274_mode { const struct reg_8 *init_regs; unsigned int bin_ratio; int min_frame_len; @@ -349,20 +338,14 @@ static const struct reg_8 imx274_mode5_1280x720_raw10[] = { */ static const struct reg_8 imx274_start_1[] = { {IMX274_STANDBY_REG, 0x12}, - {IMX274_TABLE_END, 0x00} -}; -/* - * imx274 second step register configuration for - * starting stream - */ -static const struct reg_8 imx274_start_2[] = { - {0x3120, 0xF0}, /* clock settings */ - {0x3121, 0x00}, /* clock settings */ - {0x3122, 0x02}, /* clock settings */ - {0x3129, 0x9C}, /* clock settings */ - {0x312A, 0x02}, /* clock settings */ - {0x312D, 0x02}, /* clock settings */ + /* PLRD: clock settings */ + {0x3120, 0xF0}, + {0x3121, 0x00}, + {0x3122, 0x02}, + {0x3129, 0x9C}, + {0x312A, 0x02}, + {0x312D, 0x02}, {0x310B, 0x00}, @@ -407,20 +390,20 @@ static const struct reg_8 imx274_start_2[] = { }; /* - * imx274 third step register configuration for + * imx274 second step register configuration for * starting stream */ -static const struct reg_8 imx274_start_3[] = { +static const struct reg_8 imx274_start_2[] = { {IMX274_STANDBY_REG, 0x00}, {0x303E, 0x02}, /* SYS_MODE = 2 */ {IMX274_TABLE_END, 0x00} }; /* - * imx274 forth step register configuration for + * imx274 third step register configuration for * starting stream */ -static const struct reg_8 imx274_start_4[] = { +static const struct reg_8 imx274_start_3[] = { {0x30F4, 0x00}, {0x3018, 0xA2}, /* XHS VHS OUTUPT */ {IMX274_TABLE_END, 0x00} @@ -459,7 +442,7 @@ static const struct reg_8 imx274_tp_regs[] = { }; /* nocpiop happens to be the same number for the implemented modes */ -static const struct imx274_frmfmt imx274_formats[] = { +static const struct imx274_mode imx274_modes[] = { { /* mode 1, 4K */ .bin_ratio = 1, @@ -532,7 +515,7 @@ struct stimx274 { struct regmap *regmap; struct gpio_desc *reset_gpio; struct mutex lock; /* mutex lock for operations */ - const struct imx274_frmfmt *mode; + const struct imx274_mode *mode; }; #define IMX274_ROUND(dim, step, flags) \ @@ -666,6 +649,41 @@ static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) } /** + * Read a multibyte register. + * + * Uses a bulk read where possible. + * + * @priv: Pointer to device structure + * @addr: Address of the LSB register. Other registers must be + * consecutive, least-to-most significant. + * @val: Pointer to store the register value (cpu endianness) + * @nbytes: Number of bytes to read (range: [1..3]). + * Other bytes are zet to 0. + * + * Return: 0 on success, errors otherwise + */ +static int imx274_read_mbreg(struct stimx274 *priv, u16 addr, u32 *val, + size_t nbytes) +{ + __le32 val_le = 0; + int err; + + err = regmap_bulk_read(priv->regmap, addr, &val_le, nbytes); + if (err) { + dev_err(&priv->client->dev, + "%s : i2c bulk read failed, %x (%zu bytes)\n", + __func__, addr, nbytes); + } else { + *val = le32_to_cpu(val_le); + dev_dbg(&priv->client->dev, + "%s : addr 0x%x, val=0x%x (%zu bytes)\n", + __func__, addr, *val, nbytes); + } + + return err; +} + +/** * Write a multibyte register. * * Uses a bulk write where possible. @@ -674,7 +692,7 @@ static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) * @addr: Address of the LSB register. Other registers must be * consecutive, least-to-most significant. * @val: Value to be written to the register (cpu endianness) - * @nbytes: Number of bits to write (range: [1..3]) + * @nbytes: Number of bytes to write (range: [1..3]) */ static int imx274_write_mbreg(struct stimx274 *priv, u16 addr, u32 val, size_t nbytes) @@ -708,10 +726,6 @@ static int imx274_mode_regs(struct stimx274 *priv) if (err) return err; - err = imx274_write_table(priv, imx274_start_2); - if (err) - return err; - err = imx274_write_table(priv, priv->mode->init_regs); return err; @@ -733,7 +747,7 @@ static int imx274_start_stream(struct stimx274 *priv) * give it 1 extra ms for margin */ msleep_range(11); - err = imx274_write_table(priv, imx274_start_3); + err = imx274_write_table(priv, imx274_start_2); if (err) return err; @@ -743,7 +757,7 @@ static int imx274_start_stream(struct stimx274 *priv) * give it 1 extra ms for margin */ msleep_range(8); - err = imx274_write_table(priv, imx274_start_4); + err = imx274_write_table(priv, imx274_start_3); if (err) return err; @@ -881,7 +895,7 @@ static int __imx274_change_compose(struct stimx274 *imx274, const struct v4l2_rect *cur_crop; struct v4l2_mbus_framefmt *tgt_fmt; unsigned int i; - const struct imx274_frmfmt *best_mode = &imx274_formats[0]; + const struct imx274_mode *best_mode = &imx274_modes[0]; int best_goodness = INT_MIN; if (which == V4L2_SUBDEV_FORMAT_TRY) { @@ -892,8 +906,8 @@ static int __imx274_change_compose(struct stimx274 *imx274, tgt_fmt = &imx274->format; } - for (i = 0; i < ARRAY_SIZE(imx274_formats); i++) { - unsigned int ratio = imx274_formats[i].bin_ratio; + for (i = 0; i < ARRAY_SIZE(imx274_modes); i++) { + unsigned int ratio = imx274_modes[i].bin_ratio; int goodness = imx274_binning_goodness( imx274, @@ -903,7 +917,7 @@ static int __imx274_change_compose(struct stimx274 *imx274, if (goodness >= best_goodness) { best_goodness = goodness; - best_mode = &imx274_formats[i]; + best_mode = &imx274_modes[i]; } } @@ -1323,7 +1337,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) dev_dbg(&imx274->client->dev, "%s : %s, mode index = %td\n", __func__, on ? "Stream Start" : "Stream Stop", - imx274->mode - &imx274_formats[0]); + imx274->mode - &imx274_modes[0]); mutex_lock(&imx274->lock); @@ -1387,37 +1401,17 @@ fail: static int imx274_get_frame_length(struct stimx274 *priv, u32 *val) { int err; - u16 svr; + u32 svr; u32 vmax; - u8 reg_val[3]; - - /* svr */ - err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, &reg_val[0]); - if (err) - goto fail; - err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, &reg_val[1]); + err = imx274_read_mbreg(priv, IMX274_SVR_REG_LSB, &svr, 2); if (err) goto fail; - svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; - - /* vmax */ - err = imx274_read_reg(priv, IMX274_VMAX_REG_3, &reg_val[0]); + err = imx274_read_mbreg(priv, IMX274_VMAX_REG_3, &vmax, 3); if (err) goto fail; - err = imx274_read_reg(priv, IMX274_VMAX_REG_2, &reg_val[1]); - if (err) - goto fail; - - err = imx274_read_reg(priv, IMX274_VMAX_REG_1, &reg_val[2]); - if (err) - goto fail; - - vmax = ((reg_val[2] & IMX274_MASK_LSB_3_BITS) << IMX274_SHIFT_16_BITS) - + (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; - *val = vmax * (svr + 1); return 0; @@ -1598,8 +1592,7 @@ fail: static int imx274_set_exposure(struct stimx274 *priv, int val) { int err; - u16 hmax; - u8 reg_val[2]; + u32 hmax; u32 coarse_time; /* exposure time in unit of line (HMAX)*/ dev_dbg(&priv->client->dev, @@ -1607,14 +1600,10 @@ static int imx274_set_exposure(struct stimx274 *priv, int val) /* step 1: convert input exposure_time (val) into number of 1[HMAX] */ - /* obtain HMAX value */ - err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, &reg_val[0]); - if (err) - goto fail; - err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, &reg_val[1]); + err = imx274_read_mbreg(priv, IMX274_HMAX_REG_LSB, &hmax, 2); if (err) goto fail; - hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + if (hmax == 0) { err = -EINVAL; goto fail; @@ -1749,9 +1738,8 @@ static int imx274_set_frame_interval(struct stimx274 *priv, { int err; u32 frame_length, req_frame_rate; - u16 svr; - u16 hmax; - u8 reg_val[2]; + u32 svr; + u32 hmax; dev_dbg(&priv->client->dev, "%s: input frame interval = %d / %d", __func__, frame_interval.numerator, @@ -1779,25 +1767,17 @@ static int imx274_set_frame_interval(struct stimx274 *priv, * frame_length (i.e. VMAX) = (frame_interval) x 72M /(SVR+1) / HMAX */ - /* SVR */ - err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, &reg_val[0]); - if (err) - goto fail; - err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, &reg_val[1]); + err = imx274_read_mbreg(priv, IMX274_SVR_REG_LSB, &svr, 2); if (err) goto fail; - svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + dev_dbg(&priv->client->dev, "%s : register SVR = %d\n", __func__, svr); - /* HMAX */ - err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, &reg_val[0]); - if (err) - goto fail; - err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, &reg_val[1]); + err = imx274_read_mbreg(priv, IMX274_HMAX_REG_LSB, &hmax, 2); if (err) goto fail; - hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + dev_dbg(&priv->client->dev, "%s : register HMAX = %d\n", __func__, hmax); @@ -1871,7 +1851,7 @@ static int imx274_probe(struct i2c_client *client, mutex_init(&imx274->lock); /* initialize format */ - imx274->mode = &imx274_formats[IMX274_DEFAULT_MODE]; + imx274->mode = &imx274_modes[IMX274_DEFAULT_BINNING]; imx274->crop.width = IMX274_MAX_WIDTH; imx274->crop.height = IMX274_MAX_HEIGHT; imx274->format.width = imx274->crop.width / imx274->mode->bin_ratio; @@ -1895,7 +1875,6 @@ static int imx274_probe(struct i2c_client *client, imx274->client = client; sd = &imx274->sd; v4l2_i2c_subdev_init(sd, client, &imx274_subdev_ops); - strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* initialize subdev media pad */ diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c @@ -0,0 +1,2560 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Intel Corporation + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> + +#define IMX319_REG_MODE_SELECT 0x0100 +#define IMX319_MODE_STANDBY 0x00 +#define IMX319_MODE_STREAMING 0x01 + +/* Chip ID */ +#define IMX319_REG_CHIP_ID 0x0016 +#define IMX319_CHIP_ID 0x0319 + +/* V_TIMING internal */ +#define IMX319_REG_FLL 0x0340 +#define IMX319_FLL_MAX 0xffff + +/* Exposure control */ +#define IMX319_REG_EXPOSURE 0x0202 +#define IMX319_EXPOSURE_MIN 1 +#define IMX319_EXPOSURE_STEP 1 +#define IMX319_EXPOSURE_DEFAULT 0x04f6 + +/* + * the digital control register for all color control looks like: + * +-----------------+------------------+ + * | [7:0] | [15:8] | + * +-----------------+------------------+ + * | 0x020f | 0x020e | + * -------------------------------------- + * it is used to calculate the digital gain times value(integral + fractional) + * the [15:8] bits is the fractional part and [7:0] bits is the integral + * calculation equation is: + * gain value (unit: times) = REG[15:8] + REG[7:0]/0x100 + * Only value in 0x0100 ~ 0x0FFF range is allowed. + * Analog gain use 10 bits in the registers and allowed range is 0 ~ 960 + */ +/* Analog gain control */ +#define IMX319_REG_ANALOG_GAIN 0x0204 +#define IMX319_ANA_GAIN_MIN 0 +#define IMX319_ANA_GAIN_MAX 960 +#define IMX319_ANA_GAIN_STEP 1 +#define IMX319_ANA_GAIN_DEFAULT 0 + +/* Digital gain control */ +#define IMX319_REG_DPGA_USE_GLOBAL_GAIN 0x3ff9 +#define IMX319_REG_DIG_GAIN_GLOBAL 0x020e +#define IMX319_DGTL_GAIN_MIN 256 +#define IMX319_DGTL_GAIN_MAX 4095 +#define IMX319_DGTL_GAIN_STEP 1 +#define IMX319_DGTL_GAIN_DEFAULT 256 + +/* Test Pattern Control */ +#define IMX319_REG_TEST_PATTERN 0x0600 +#define IMX319_TEST_PATTERN_DISABLED 0 +#define IMX319_TEST_PATTERN_SOLID_COLOR 1 +#define IMX319_TEST_PATTERN_COLOR_BARS 2 +#define IMX319_TEST_PATTERN_GRAY_COLOR_BARS 3 +#define IMX319_TEST_PATTERN_PN9 4 + +/* Flip Control */ +#define IMX319_REG_ORIENTATION 0x0101 + +/* default link frequency and external clock */ +#define IMX319_LINK_FREQ_DEFAULT 482400000 +#define IMX319_EXT_CLK 19200000 +#define IMX319_LINK_FREQ_INDEX 0 + +struct imx319_reg { + u16 address; + u8 val; +}; + +struct imx319_reg_list { + u32 num_of_regs; + const struct imx319_reg *regs; +}; + +/* Mode : resolution and related config&values */ +struct imx319_mode { + /* Frame width */ + u32 width; + /* Frame height */ + u32 height; + + /* V-timing */ + u32 fll_def; + u32 fll_min; + + /* H-timing */ + u32 llp; + + /* index of link frequency */ + u32 link_freq_index; + + /* Default register values */ + struct imx319_reg_list reg_list; +}; + +struct imx319_hwcfg { + u32 ext_clk; /* sensor external clk */ + s64 *link_freqs; /* CSI-2 link frequencies */ + unsigned int nr_of_link_freqs; +}; + +struct imx319 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; + + /* Current mode */ + const struct imx319_mode *cur_mode; + + struct imx319_hwcfg *hwcfg; + s64 link_def_freq; /* CSI-2 link default frequency */ + + /* + * Mutex for serialized access: + * Protect sensor set pad format and start/stop streaming safely. + * Protect access to sensor v4l2 controls. + */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static const struct imx319_reg imx319_global_regs[] = { + { 0x0136, 0x13 }, + { 0x0137, 0x33 }, + { 0x3c7e, 0x05 }, + { 0x3c7f, 0x07 }, + { 0x4d39, 0x0b }, + { 0x4d41, 0x33 }, + { 0x4d43, 0x0c }, + { 0x4d49, 0x89 }, + { 0x4e05, 0x0b }, + { 0x4e0d, 0x33 }, + { 0x4e0f, 0x0c }, + { 0x4e15, 0x89 }, + { 0x4e49, 0x2a }, + { 0x4e51, 0x33 }, + { 0x4e53, 0x0c }, + { 0x4e59, 0x89 }, + { 0x5601, 0x4f }, + { 0x560b, 0x45 }, + { 0x562f, 0x0a }, + { 0x5643, 0x0a }, + { 0x5645, 0x0c }, + { 0x56ef, 0x51 }, + { 0x586f, 0x33 }, + { 0x5873, 0x89 }, + { 0x5905, 0x33 }, + { 0x5907, 0x89 }, + { 0x590d, 0x33 }, + { 0x590f, 0x89 }, + { 0x5915, 0x33 }, + { 0x5917, 0x89 }, + { 0x5969, 0x1c }, + { 0x596b, 0x72 }, + { 0x5971, 0x33 }, + { 0x5973, 0x89 }, + { 0x5975, 0x33 }, + { 0x5977, 0x89 }, + { 0x5979, 0x1c }, + { 0x597b, 0x72 }, + { 0x5985, 0x33 }, + { 0x5987, 0x89 }, + { 0x5999, 0x1c }, + { 0x599b, 0x72 }, + { 0x59a5, 0x33 }, + { 0x59a7, 0x89 }, + { 0x7485, 0x08 }, + { 0x7487, 0x0c }, + { 0x7489, 0xc7 }, + { 0x748b, 0x8b }, + { 0x9004, 0x09 }, + { 0x9200, 0x6a }, + { 0x9201, 0x22 }, + { 0x9202, 0x6a }, + { 0x9203, 0x23 }, + { 0x9204, 0x5f }, + { 0x9205, 0x23 }, + { 0x9206, 0x5f }, + { 0x9207, 0x24 }, + { 0x9208, 0x5f }, + { 0x9209, 0x26 }, + { 0x920a, 0x5f }, + { 0x920b, 0x27 }, + { 0x920c, 0x5f }, + { 0x920d, 0x29 }, + { 0x920e, 0x5f }, + { 0x920f, 0x2a }, + { 0x9210, 0x5f }, + { 0x9211, 0x2c }, + { 0xbc22, 0x1a }, + { 0xf01f, 0x04 }, + { 0xf021, 0x03 }, + { 0xf023, 0x02 }, + { 0xf03d, 0x05 }, + { 0xf03f, 0x03 }, + { 0xf041, 0x02 }, + { 0xf0af, 0x04 }, + { 0xf0b1, 0x03 }, + { 0xf0b3, 0x02 }, + { 0xf0cd, 0x05 }, + { 0xf0cf, 0x03 }, + { 0xf0d1, 0x02 }, + { 0xf13f, 0x04 }, + { 0xf141, 0x03 }, + { 0xf143, 0x02 }, + { 0xf15d, 0x05 }, + { 0xf15f, 0x03 }, + { 0xf161, 0x02 }, + { 0xf1cf, 0x04 }, + { 0xf1d1, 0x03 }, + { 0xf1d3, 0x02 }, + { 0xf1ed, 0x05 }, + { 0xf1ef, 0x03 }, + { 0xf1f1, 0x02 }, + { 0xf287, 0x04 }, + { 0xf289, 0x03 }, + { 0xf28b, 0x02 }, + { 0xf2a5, 0x05 }, + { 0xf2a7, 0x03 }, + { 0xf2a9, 0x02 }, + { 0xf2b7, 0x04 }, + { 0xf2b9, 0x03 }, + { 0xf2bb, 0x02 }, + { 0xf2d5, 0x05 }, + { 0xf2d7, 0x03 }, + { 0xf2d9, 0x02 }, +}; + +static const struct imx319_reg_list imx319_global_setting = { + .num_of_regs = ARRAY_SIZE(imx319_global_regs), + .regs = imx319_global_regs, +}; + +static const struct imx319_reg mode_3264x2448_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0f }, + { 0x0343, 0x80 }, + { 0x0340, 0x0c }, + { 0x0341, 0xaa }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x01 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0x08 }, + { 0x040a, 0x00 }, + { 0x040b, 0x08 }, + { 0x040c, 0x0c }, + { 0x040d, 0xc0 }, + { 0x040e, 0x09 }, + { 0x040f, 0x90 }, + { 0x034c, 0x0c }, + { 0x034d, 0xc0 }, + { 0x034e, 0x09 }, + { 0x034f, 0x90 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0x48 }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x01 }, + { 0x3f79, 0x18 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x00 }, + { 0xe014, 0x00 }, + { 0x0202, 0x0a }, + { 0x0203, 0x7a }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_3280x2464_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0f }, + { 0x0343, 0x80 }, + { 0x0340, 0x0c }, + { 0x0341, 0xaa }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x01 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0x00 }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x0c }, + { 0x040d, 0xd0 }, + { 0x040e, 0x09 }, + { 0x040f, 0xa0 }, + { 0x034c, 0x0c }, + { 0x034d, 0xd0 }, + { 0x034e, 0x09 }, + { 0x034f, 0xa0 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0x48 }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x01 }, + { 0x3f79, 0x18 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x00 }, + { 0xe014, 0x00 }, + { 0x0202, 0x0a }, + { 0x0203, 0x7a }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1936x1096_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0f }, + { 0x0343, 0x80 }, + { 0x0340, 0x0c }, + { 0x0341, 0xaa }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x02 }, + { 0x0347, 0xac }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x06 }, + { 0x034b, 0xf3 }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x01 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x02 }, + { 0x0409, 0xa0 }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x07 }, + { 0x040d, 0x90 }, + { 0x040e, 0x04 }, + { 0x040f, 0x48 }, + { 0x034c, 0x07 }, + { 0x034d, 0x90 }, + { 0x034e, 0x04 }, + { 0x034f, 0x48 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0x48 }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x01 }, + { 0x3f79, 0x18 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x00 }, + { 0xe014, 0x00 }, + { 0x0202, 0x05 }, + { 0x0203, 0x34 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1920x1080_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0f }, + { 0x0343, 0x80 }, + { 0x0340, 0x0c }, + { 0x0341, 0xaa }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x02 }, + { 0x0347, 0xb4 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x06 }, + { 0x034b, 0xeb }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x01 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x02 }, + { 0x0409, 0xa8 }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x07 }, + { 0x040d, 0x80 }, + { 0x040e, 0x04 }, + { 0x040f, 0x38 }, + { 0x034c, 0x07 }, + { 0x034d, 0x80 }, + { 0x034e, 0x04 }, + { 0x034f, 0x38 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0x48 }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x01 }, + { 0x3f79, 0x18 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x00 }, + { 0xe014, 0x00 }, + { 0x0202, 0x05 }, + { 0x0203, 0x34 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1640x1232_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x08 }, + { 0x0343, 0x20 }, + { 0x0340, 0x18 }, + { 0x0341, 0x2a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x02 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0x00 }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x06 }, + { 0x040d, 0x68 }, + { 0x040e, 0x04 }, + { 0x040f, 0xd0 }, + { 0x034c, 0x06 }, + { 0x034d, 0x68 }, + { 0x034e, 0x04 }, + { 0x034f, 0xd0 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0xba }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x00 }, + { 0x3f79, 0x34 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x04 }, + { 0xe014, 0x00 }, + { 0x0202, 0x04 }, + { 0x0203, 0xf6 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1640x922_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x08 }, + { 0x0343, 0x20 }, + { 0x0340, 0x18 }, + { 0x0341, 0x2a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x01 }, + { 0x0347, 0x30 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x08 }, + { 0x034b, 0x6f }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x02 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0x00 }, + { 0x040a, 0x00 }, + { 0x040b, 0x02 }, + { 0x040c, 0x06 }, + { 0x040d, 0x68 }, + { 0x040e, 0x03 }, + { 0x040f, 0x9a }, + { 0x034c, 0x06 }, + { 0x034d, 0x68 }, + { 0x034e, 0x03 }, + { 0x034f, 0x9a }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0xba }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x00 }, + { 0x3f79, 0x34 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x04 }, + { 0xe014, 0x00 }, + { 0x0202, 0x04 }, + { 0x0203, 0xf6 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1296x736_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x08 }, + { 0x0343, 0x20 }, + { 0x0340, 0x18 }, + { 0x0341, 0x2a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x01 }, + { 0x0347, 0xf0 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x07 }, + { 0x034b, 0xaf }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x02 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0xac }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x05 }, + { 0x040d, 0x10 }, + { 0x040e, 0x02 }, + { 0x040f, 0xe0 }, + { 0x034c, 0x05 }, + { 0x034d, 0x10 }, + { 0x034e, 0x02 }, + { 0x034f, 0xe0 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0xba }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x00 }, + { 0x3f79, 0x34 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x04 }, + { 0xe014, 0x00 }, + { 0x0202, 0x04 }, + { 0x0203, 0xf6 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const struct imx319_reg mode_1280x720_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x08 }, + { 0x0343, 0x20 }, + { 0x0340, 0x18 }, + { 0x0341, 0x2a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x02 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x07 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0221, 0x11 }, + { 0x0381, 0x01 }, + { 0x0383, 0x01 }, + { 0x0385, 0x01 }, + { 0x0387, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x0a }, + { 0x3140, 0x02 }, + { 0x3141, 0x00 }, + { 0x3f0d, 0x0a }, + { 0x3f14, 0x01 }, + { 0x3f3c, 0x02 }, + { 0x3f4d, 0x01 }, + { 0x3f4c, 0x01 }, + { 0x4254, 0x7f }, + { 0x0401, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x10 }, + { 0x0408, 0x00 }, + { 0x0409, 0xb4 }, + { 0x040a, 0x00 }, + { 0x040b, 0x00 }, + { 0x040c, 0x05 }, + { 0x040d, 0x00 }, + { 0x040e, 0x02 }, + { 0x040f, 0xd0 }, + { 0x034c, 0x05 }, + { 0x034d, 0x00 }, + { 0x034e, 0x02 }, + { 0x034f, 0xd0 }, + { 0x3261, 0x00 }, + { 0x3264, 0x00 }, + { 0x3265, 0x10 }, + { 0x0301, 0x05 }, + { 0x0303, 0x04 }, + { 0x0305, 0x04 }, + { 0x0306, 0x01 }, + { 0x0307, 0x92 }, + { 0x0309, 0x0a }, + { 0x030b, 0x02 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0xfa }, + { 0x0310, 0x00 }, + { 0x0820, 0x0f }, + { 0x0821, 0x13 }, + { 0x0822, 0x33 }, + { 0x0823, 0x33 }, + { 0x3e20, 0x01 }, + { 0x3e37, 0x00 }, + { 0x3e3b, 0x01 }, + { 0x38a3, 0x01 }, + { 0x38a8, 0x00 }, + { 0x38a9, 0x00 }, + { 0x38aa, 0x00 }, + { 0x38ab, 0x00 }, + { 0x3234, 0x00 }, + { 0x3fc1, 0x00 }, + { 0x3235, 0x00 }, + { 0x3802, 0x00 }, + { 0x3143, 0x04 }, + { 0x360a, 0x00 }, + { 0x0b00, 0x00 }, + { 0x0106, 0x00 }, + { 0x0b05, 0x01 }, + { 0x0b06, 0x01 }, + { 0x3230, 0x00 }, + { 0x3602, 0x01 }, + { 0x3607, 0x01 }, + { 0x3c00, 0x00 }, + { 0x3c01, 0xba }, + { 0x3c02, 0xc8 }, + { 0x3c03, 0xaa }, + { 0x3c04, 0x91 }, + { 0x3c05, 0x54 }, + { 0x3c06, 0x26 }, + { 0x3c07, 0x20 }, + { 0x3c08, 0x51 }, + { 0x3d80, 0x00 }, + { 0x3f50, 0x00 }, + { 0x3f56, 0x00 }, + { 0x3f57, 0x30 }, + { 0x3f78, 0x00 }, + { 0x3f79, 0x34 }, + { 0x3f7c, 0x00 }, + { 0x3f7d, 0x00 }, + { 0x3fba, 0x00 }, + { 0x3fbb, 0x00 }, + { 0xa081, 0x04 }, + { 0xe014, 0x00 }, + { 0x0202, 0x04 }, + { 0x0203, 0xf6 }, + { 0x0224, 0x01 }, + { 0x0225, 0xf4 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0216, 0x00 }, + { 0x0217, 0x00 }, + { 0x020e, 0x01 }, + { 0x020f, 0x00 }, + { 0x0210, 0x01 }, + { 0x0211, 0x00 }, + { 0x0212, 0x01 }, + { 0x0213, 0x00 }, + { 0x0214, 0x01 }, + { 0x0215, 0x00 }, + { 0x0218, 0x01 }, + { 0x0219, 0x00 }, + { 0x3614, 0x00 }, + { 0x3616, 0x0d }, + { 0x3617, 0x56 }, + { 0xb612, 0x20 }, + { 0xb613, 0x20 }, + { 0xb614, 0x20 }, + { 0xb615, 0x20 }, + { 0xb616, 0x0a }, + { 0xb617, 0x0a }, + { 0xb618, 0x20 }, + { 0xb619, 0x20 }, + { 0xb61a, 0x20 }, + { 0xb61b, 0x20 }, + { 0xb61c, 0x0a }, + { 0xb61d, 0x0a }, + { 0xb666, 0x30 }, + { 0xb667, 0x30 }, + { 0xb668, 0x30 }, + { 0xb669, 0x30 }, + { 0xb66a, 0x14 }, + { 0xb66b, 0x14 }, + { 0xb66c, 0x20 }, + { 0xb66d, 0x20 }, + { 0xb66e, 0x20 }, + { 0xb66f, 0x20 }, + { 0xb670, 0x10 }, + { 0xb671, 0x10 }, + { 0x3237, 0x00 }, + { 0x3900, 0x00 }, + { 0x3901, 0x00 }, + { 0x3902, 0x00 }, + { 0x3904, 0x00 }, + { 0x3905, 0x00 }, + { 0x3906, 0x00 }, + { 0x3907, 0x00 }, + { 0x3908, 0x00 }, + { 0x3909, 0x00 }, + { 0x3912, 0x00 }, + { 0x3930, 0x00 }, + { 0x3931, 0x00 }, + { 0x3933, 0x00 }, + { 0x3934, 0x00 }, + { 0x3935, 0x00 }, + { 0x3936, 0x00 }, + { 0x3937, 0x00 }, + { 0x30ac, 0x00 }, +}; + +static const char * const imx319_test_pattern_menu[] = { + "Disabled", + "100% color bars", + "Solid color", + "Fade to gray color bars", + "PN9" +}; + +/* supported link frequencies */ +static const s64 link_freq_menu_items[] = { + IMX319_LINK_FREQ_DEFAULT, +}; + +/* Mode configs */ +static const struct imx319_mode supported_modes[] = { + { + .width = 3280, + .height = 2464, + .fll_def = 3242, + .fll_min = 3242, + .llp = 3968, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), + .regs = mode_3280x2464_regs, + }, + }, + { + .width = 3264, + .height = 2448, + .fll_def = 3242, + .fll_min = 3242, + .llp = 3968, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), + .regs = mode_3264x2448_regs, + }, + }, + { + .width = 1936, + .height = 1096, + .fll_def = 3242, + .fll_min = 3242, + .llp = 3968, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), + .regs = mode_1936x1096_regs, + }, + }, + { + .width = 1920, + .height = 1080, + .fll_def = 3242, + .fll_min = 3242, + .llp = 3968, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), + .regs = mode_1920x1080_regs, + }, + }, + { + .width = 1640, + .height = 1232, + .fll_def = 5146, + .fll_min = 5146, + .llp = 2500, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), + .regs = mode_1640x1232_regs, + }, + }, + { + .width = 1640, + .height = 922, + .fll_def = 5146, + .fll_min = 5146, + .llp = 2500, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), + .regs = mode_1640x922_regs, + }, + }, + { + .width = 1296, + .height = 736, + .fll_def = 5146, + .fll_min = 5146, + .llp = 2500, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), + .regs = mode_1296x736_regs, + }, + }, + { + .width = 1280, + .height = 720, + .fll_def = 5146, + .fll_min = 5146, + .llp = 2500, + .link_freq_index = IMX319_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), + .regs = mode_1280x720_regs, + }, + }, +}; + +static inline struct imx319 *to_imx319(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx319, sd); +} + +/* Get bayer order based on flip setting. */ +static u32 imx319_get_format_code(struct imx319 *imx319) +{ + /* + * Only one bayer order is supported. + * It depends on the flip settings. + */ + u32 code; + static const u32 codes[2][2] = { + { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, }, + { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, + }; + + lockdep_assert_held(&imx319->mutex); + code = codes[imx319->vflip->val][imx319->hflip->val]; + + return code; +} + +/* Read registers up to 4 at a time */ +static int imx319_read_reg(struct imx319 *imx319, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = { 0 }; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + 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)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/* Write registers up to 4 at a time */ +static int imx319_write_reg(struct imx319 *imx319, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/* Write a list of registers */ +static int imx319_write_regs(struct imx319 *imx319, + const struct imx319_reg *regs, u32 len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + int ret; + u32 i; + + for (i = 0; i < len; i++) { + ret = imx319_write_reg(imx319, regs[i].address, 1, regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "write reg 0x%4.4x return err %d", + regs[i].address, ret); + return ret; + } + } + + return 0; +} + +/* Open sub-device */ +static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct imx319 *imx319 = to_imx319(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + mutex_lock(&imx319->mutex); + + /* Initialize try_fmt */ + try_fmt->width = imx319->cur_mode->width; + try_fmt->height = imx319->cur_mode->height; + try_fmt->code = imx319_get_format_code(imx319); + try_fmt->field = V4L2_FIELD_NONE; + + mutex_unlock(&imx319->mutex); + + return 0; +} + +static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx319 *imx319 = container_of(ctrl->handler, + struct imx319, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + s64 max; + int ret; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = imx319->cur_mode->height + ctrl->val - 18; + __v4l2_ctrl_modify_range(imx319->exposure, + imx319->exposure->minimum, + max, imx319->exposure->step, max); + break; + } + + /* + * Applying V4L2 control value only happens + * when power is up for streaming + */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + /* Analog gain = 1024/(1024 - ctrl->val) times */ + ret = imx319_write_reg(imx319, IMX319_REG_ANALOG_GAIN, 2, + ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx319_write_reg(imx319, IMX319_REG_DIG_GAIN_GLOBAL, 2, + ctrl->val); + break; + case V4L2_CID_EXPOSURE: + ret = imx319_write_reg(imx319, IMX319_REG_EXPOSURE, 2, + ctrl->val); + break; + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + ret = imx319_write_reg(imx319, IMX319_REG_FLL, 2, + imx319->cur_mode->height + ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = imx319_write_reg(imx319, IMX319_REG_TEST_PATTERN, + 2, ctrl->val); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = imx319_write_reg(imx319, IMX319_REG_ORIENTATION, 1, + imx319->hflip->val | + imx319->vflip->val << 1); + break; + default: + ret = -EINVAL; + dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx319_ctrl_ops = { + .s_ctrl = imx319_set_ctrl, +}; + +static int imx319_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx319 *imx319 = to_imx319(sd); + + if (code->index > 0) + return -EINVAL; + + mutex_lock(&imx319->mutex); + code->code = imx319_get_format_code(imx319); + mutex_unlock(&imx319->mutex); + + return 0; +} + +static int imx319_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx319 *imx319 = to_imx319(sd); + + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + mutex_lock(&imx319->mutex); + if (fse->code != imx319_get_format_code(imx319)) { + mutex_unlock(&imx319->mutex); + return -EINVAL; + } + mutex_unlock(&imx319->mutex); + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static void imx319_update_pad_format(struct imx319 *imx319, + const struct imx319_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = imx319_get_format_code(imx319); + fmt->format.field = V4L2_FIELD_NONE; +} + +static int imx319_do_get_pad_format(struct imx319 *imx319, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt; + struct v4l2_subdev *sd = &imx319->sd; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + fmt->format = *framefmt; + } else { + imx319_update_pad_format(imx319, imx319->cur_mode, fmt); + } + + return 0; +} + +static int imx319_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx319 *imx319 = to_imx319(sd); + int ret; + + mutex_lock(&imx319->mutex); + ret = imx319_do_get_pad_format(imx319, cfg, fmt); + mutex_unlock(&imx319->mutex); + + return ret; +} + +static int +imx319_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx319 *imx319 = to_imx319(sd); + const struct imx319_mode *mode; + struct v4l2_mbus_framefmt *framefmt; + s32 vblank_def; + s32 vblank_min; + s64 h_blank; + u64 pixel_rate; + u32 height; + + mutex_lock(&imx319->mutex); + + /* + * Only one bayer order is supported. + * It depends on the flip settings. + */ + fmt->format.code = imx319_get_format_code(imx319); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + imx319_update_pad_format(imx319, mode, fmt); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + *framefmt = fmt->format; + } else { + imx319->cur_mode = mode; + pixel_rate = imx319->link_def_freq * 2 * 4; + do_div(pixel_rate, 10); + __v4l2_ctrl_s_ctrl_int64(imx319->pixel_rate, pixel_rate); + /* Update limits and set FPS to default */ + height = imx319->cur_mode->height; + vblank_def = imx319->cur_mode->fll_def - height; + vblank_min = imx319->cur_mode->fll_min - height; + height = IMX319_FLL_MAX - height; + __v4l2_ctrl_modify_range(imx319->vblank, vblank_min, height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(imx319->vblank, vblank_def); + h_blank = mode->llp - imx319->cur_mode->width; + /* + * Currently hblank is not changeable. + * So FPS control is done only by vblank. + */ + __v4l2_ctrl_modify_range(imx319->hblank, h_blank, + h_blank, 1, h_blank); + } + + mutex_unlock(&imx319->mutex); + + return 0; +} + +/* Start streaming */ +static int imx319_start_streaming(struct imx319 *imx319) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + const struct imx319_reg_list *reg_list; + int ret; + + /* Global Setting */ + reg_list = &imx319_global_setting; + ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(&client->dev, "failed to set global settings"); + return ret; + } + + /* Apply default values of current mode */ + reg_list = &imx319->cur_mode->reg_list; + ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + /* set digital gain control to all color mode */ + ret = imx319_write_reg(imx319, IMX319_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); + if (ret) + return ret; + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx319->sd.ctrl_handler); + if (ret) + return ret; + + return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT, + 1, IMX319_MODE_STREAMING); +} + +/* Stop streaming */ +static int imx319_stop_streaming(struct imx319 *imx319) +{ + return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT, + 1, IMX319_MODE_STANDBY); +} + +static int imx319_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx319 *imx319 = to_imx319(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&imx319->mutex); + if (imx319->streaming == enable) { + mutex_unlock(&imx319->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto err_unlock; + } + + /* + * Apply default & customized values + * and then start streaming. + */ + ret = imx319_start_streaming(imx319); + if (ret) + goto err_rpm_put; + } else { + imx319_stop_streaming(imx319); + pm_runtime_put(&client->dev); + } + + imx319->streaming = enable; + + /* vflip and hflip cannot change during streaming */ + __v4l2_ctrl_grab(imx319->vflip, enable); + __v4l2_ctrl_grab(imx319->hflip, enable); + + mutex_unlock(&imx319->mutex); + + return ret; + +err_rpm_put: + pm_runtime_put(&client->dev); +err_unlock: + mutex_unlock(&imx319->mutex); + + return ret; +} + +static int __maybe_unused imx319_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx319 *imx319 = to_imx319(sd); + + if (imx319->streaming) + imx319_stop_streaming(imx319); + + return 0; +} + +static int __maybe_unused imx319_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx319 *imx319 = to_imx319(sd); + int ret; + + if (imx319->streaming) { + ret = imx319_start_streaming(imx319); + if (ret) + goto error; + } + + return 0; + +error: + imx319_stop_streaming(imx319); + imx319->streaming = 0; + return ret; +} + +/* Verify chip ID */ +static int imx319_identify_module(struct imx319 *imx319) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + int ret; + u32 val; + + ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX319_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + IMX319_CHIP_ID, val); + return -EIO; + } + + return 0; +} + +static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops imx319_video_ops = { + .s_stream = imx319_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx319_pad_ops = { + .enum_mbus_code = imx319_enum_mbus_code, + .get_fmt = imx319_get_pad_format, + .set_fmt = imx319_set_pad_format, + .enum_frame_size = imx319_enum_frame_size, +}; + +static const struct v4l2_subdev_ops imx319_subdev_ops = { + .core = &imx319_subdev_core_ops, + .video = &imx319_video_ops, + .pad = &imx319_pad_ops, +}; + +static const struct media_entity_operations imx319_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops imx319_internal_ops = { + .open = imx319_open, +}; + +/* Initialize control handlers */ +static int imx319_init_controls(struct imx319 *imx319) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max; + s64 vblank_def; + s64 vblank_min; + s64 hblank; + u64 pixel_rate; + const struct imx319_mode *mode; + u32 max; + int ret; + + ctrl_hdlr = &imx319->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); + if (ret) + return ret; + + ctrl_hdlr->lock = &imx319->mutex; + max = ARRAY_SIZE(link_freq_menu_items) - 1; + imx319->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_LINK_FREQ, max, 0, + link_freq_menu_items); + if (imx319->link_freq) + imx319->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = imx319->link_def_freq * 2 * 4; + do_div(pixel_rate, 10); + /* By default, PIXEL_RATE is read only */ + imx319->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + /* Initial vblank/hblank/exposure parameters based on current mode */ + mode = imx319->cur_mode; + vblank_def = mode->fll_def - mode->height; + vblank_min = mode->fll_min - mode->height; + imx319->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_VBLANK, vblank_min, + IMX319_FLL_MAX - mode->height, + 1, vblank_def); + + hblank = mode->llp - mode->width; + imx319->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + if (imx319->hblank) + imx319->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* fll >= exposure time + adjust parameter (default value is 18) */ + exposure_max = mode->fll_def - 18; + imx319->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX319_EXPOSURE_MIN, exposure_max, + IMX319_EXPOSURE_STEP, + IMX319_EXPOSURE_DEFAULT); + + imx319->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + imx319->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX319_ANA_GAIN_MIN, IMX319_ANA_GAIN_MAX, + IMX319_ANA_GAIN_STEP, IMX319_ANA_GAIN_DEFAULT); + + /* Digital gain */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX319_DGTL_GAIN_MIN, IMX319_DGTL_GAIN_MAX, + IMX319_DGTL_GAIN_STEP, IMX319_DGTL_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx319_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx319_test_pattern_menu) - 1, + 0, 0, imx319_test_pattern_menu); + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "control init failed: %d", ret); + goto error; + } + + imx319->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) +{ + struct imx319_hwcfg *cfg; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + unsigned int i; + int ret; + + if (!fwnode) + return NULL; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return NULL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (ret) + goto out_err; + + cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + goto out_err; + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &cfg->ext_clk); + if (ret) { + dev_err(dev, "can't get clock frequency"); + goto out_err; + } + + dev_dbg(dev, "ext clk: %d", cfg->ext_clk); + if (cfg->ext_clk != IMX319_EXT_CLK) { + dev_err(dev, "external clock %d is not supported", + cfg->ext_clk); + goto out_err; + } + + dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); + if (!bus_cfg.nr_of_link_frequencies) { + dev_warn(dev, "no link frequencies defined"); + goto out_err; + } + + cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; + cfg->link_freqs = devm_kcalloc(dev, + bus_cfg.nr_of_link_frequencies + 1, + sizeof(*cfg->link_freqs), GFP_KERNEL); + if (!cfg->link_freqs) + goto out_err; + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; + dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return cfg; + +out_err: + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return NULL; +} + +static int imx319_probe(struct i2c_client *client) +{ + struct imx319 *imx319; + int ret; + u32 i; + + imx319 = devm_kzalloc(&client->dev, sizeof(*imx319), GFP_KERNEL); + if (!imx319) + return -ENOMEM; + + mutex_init(&imx319->mutex); + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops); + + /* Check module identity */ + ret = imx319_identify_module(imx319); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + goto error_probe; + } + + imx319->hwcfg = imx319_get_hwcfg(&client->dev); + if (!imx319->hwcfg) { + dev_err(&client->dev, "failed to get hwcfg"); + ret = -ENODEV; + goto error_probe; + } + + imx319->link_def_freq = link_freq_menu_items[IMX319_LINK_FREQ_INDEX]; + for (i = 0; i < imx319->hwcfg->nr_of_link_freqs; i++) { + if (imx319->hwcfg->link_freqs[i] == imx319->link_def_freq) { + dev_dbg(&client->dev, "link freq index %d matched", i); + break; + } + } + + if (i == imx319->hwcfg->nr_of_link_freqs) { + dev_err(&client->dev, "no link frequency supported"); + ret = -EINVAL; + goto error_probe; + } + + /* Set default mode to max resolution */ + imx319->cur_mode = &supported_modes[0]; + + ret = imx319_init_controls(imx319); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto error_probe; + } + + /* Initialize subdev */ + imx319->sd.internal_ops = &imx319_internal_ops; + imx319->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + imx319->sd.entity.ops = &imx319_subdev_entity_ops; + imx319->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx319->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx319->sd.entity, 1, &imx319->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&imx319->sd); + if (ret < 0) + goto error_media_entity; + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx319->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(imx319->sd.ctrl_handler); + +error_probe: + mutex_destroy(&imx319->mutex); + + return ret; +} + +static int imx319_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx319 *imx319 = to_imx319(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx319->mutex); + + return 0; +} + +static const struct dev_pm_ops imx319_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume) +}; + +static const struct acpi_device_id imx319_acpi_ids[] = { + { "SONY319A" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, imx319_acpi_ids); + +static struct i2c_driver imx319_i2c_driver = { + .driver = { + .name = "imx319", + .pm = &imx319_pm_ops, + .acpi_match_table = ACPI_PTR(imx319_acpi_ids), + }, + .probe_new = imx319_probe, + .remove = imx319_remove, +}; +module_i2c_driver(imx319_i2c_driver); + +MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); +MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); +MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_DESCRIPTION("Sony imx319 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c @@ -0,0 +1,1860 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Intel Corporation + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> + +#define IMX355_REG_MODE_SELECT 0x0100 +#define IMX355_MODE_STANDBY 0x00 +#define IMX355_MODE_STREAMING 0x01 + +/* Chip ID */ +#define IMX355_REG_CHIP_ID 0x0016 +#define IMX355_CHIP_ID 0x0355 + +/* V_TIMING internal */ +#define IMX355_REG_FLL 0x0340 +#define IMX355_FLL_MAX 0xffff + +/* Exposure control */ +#define IMX355_REG_EXPOSURE 0x0202 +#define IMX355_EXPOSURE_MIN 1 +#define IMX355_EXPOSURE_STEP 1 +#define IMX355_EXPOSURE_DEFAULT 0x0282 + +/* Analog gain control */ +#define IMX355_REG_ANALOG_GAIN 0x0204 +#define IMX355_ANA_GAIN_MIN 0 +#define IMX355_ANA_GAIN_MAX 960 +#define IMX355_ANA_GAIN_STEP 1 +#define IMX355_ANA_GAIN_DEFAULT 0 + +/* Digital gain control */ +#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070 +#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e +#define IMX355_DGTL_GAIN_MIN 256 +#define IMX355_DGTL_GAIN_MAX 4095 +#define IMX355_DGTL_GAIN_STEP 1 +#define IMX355_DGTL_GAIN_DEFAULT 256 + +/* Test Pattern Control */ +#define IMX355_REG_TEST_PATTERN 0x0600 +#define IMX355_TEST_PATTERN_DISABLED 0 +#define IMX355_TEST_PATTERN_SOLID_COLOR 1 +#define IMX355_TEST_PATTERN_COLOR_BARS 2 +#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3 +#define IMX355_TEST_PATTERN_PN9 4 + +/* Flip Control */ +#define IMX355_REG_ORIENTATION 0x0101 + +/* default link frequency and external clock */ +#define IMX355_LINK_FREQ_DEFAULT 360000000 +#define IMX355_EXT_CLK 19200000 +#define IMX355_LINK_FREQ_INDEX 0 + +struct imx355_reg { + u16 address; + u8 val; +}; + +struct imx355_reg_list { + u32 num_of_regs; + const struct imx355_reg *regs; +}; + +/* Mode : resolution and related config&values */ +struct imx355_mode { + /* Frame width */ + u32 width; + /* Frame height */ + u32 height; + + /* V-timing */ + u32 fll_def; + u32 fll_min; + + /* H-timing */ + u32 llp; + + /* index of link frequency */ + u32 link_freq_index; + + /* Default register values */ + struct imx355_reg_list reg_list; +}; + +struct imx355_hwcfg { + u32 ext_clk; /* sensor external clk */ + s64 *link_freqs; /* CSI-2 link frequencies */ + unsigned int nr_of_link_freqs; +}; + +struct imx355 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; + + /* Current mode */ + const struct imx355_mode *cur_mode; + + struct imx355_hwcfg *hwcfg; + s64 link_def_freq; /* CSI-2 link default frequency */ + + /* + * Mutex for serialized access: + * Protect sensor set pad format and start/stop streaming safely. + * Protect access to sensor v4l2 controls. + */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static const struct imx355_reg imx355_global_regs[] = { + { 0x0136, 0x13 }, + { 0x0137, 0x33 }, + { 0x304e, 0x03 }, + { 0x4348, 0x16 }, + { 0x4350, 0x19 }, + { 0x4408, 0x0a }, + { 0x440c, 0x0b }, + { 0x4411, 0x5f }, + { 0x4412, 0x2c }, + { 0x4623, 0x00 }, + { 0x462c, 0x0f }, + { 0x462d, 0x00 }, + { 0x462e, 0x00 }, + { 0x4684, 0x54 }, + { 0x480a, 0x07 }, + { 0x4908, 0x07 }, + { 0x4909, 0x07 }, + { 0x490d, 0x0a }, + { 0x491e, 0x0f }, + { 0x4921, 0x06 }, + { 0x4923, 0x28 }, + { 0x4924, 0x28 }, + { 0x4925, 0x29 }, + { 0x4926, 0x29 }, + { 0x4927, 0x1f }, + { 0x4928, 0x20 }, + { 0x4929, 0x20 }, + { 0x492a, 0x20 }, + { 0x492c, 0x05 }, + { 0x492d, 0x06 }, + { 0x492e, 0x06 }, + { 0x492f, 0x06 }, + { 0x4930, 0x03 }, + { 0x4931, 0x04 }, + { 0x4932, 0x04 }, + { 0x4933, 0x05 }, + { 0x595e, 0x01 }, + { 0x5963, 0x01 }, + { 0x3030, 0x01 }, + { 0x3031, 0x01 }, + { 0x3045, 0x01 }, + { 0x4010, 0x00 }, + { 0x4011, 0x00 }, + { 0x4012, 0x00 }, + { 0x4013, 0x01 }, + { 0x68a8, 0xfe }, + { 0x68a9, 0xff }, + { 0x6888, 0x00 }, + { 0x6889, 0x00 }, + { 0x68b0, 0x00 }, + { 0x3058, 0x00 }, + { 0x305a, 0x00 }, +}; + +static const struct imx355_reg_list imx355_global_setting = { + .num_of_regs = ARRAY_SIZE(imx355_global_regs), + .regs = imx355_global_regs, +}; + +static const struct imx355_reg mode_3268x2448_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x0a }, + { 0x0341, 0x37 }, + { 0x0344, 0x00 }, + { 0x0345, 0x08 }, + { 0x0346, 0x00 }, + { 0x0347, 0x08 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcb }, + { 0x034a, 0x09 }, + { 0x034b, 0x97 }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x0c }, + { 0x034d, 0xc4 }, + { 0x034e, 0x09 }, + { 0x034f, 0x90 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_3264x2448_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x0a }, + { 0x0341, 0x37 }, + { 0x0344, 0x00 }, + { 0x0345, 0x08 }, + { 0x0346, 0x00 }, + { 0x0347, 0x08 }, + { 0x0348, 0x0c }, + { 0x0349, 0xc7 }, + { 0x034a, 0x09 }, + { 0x034b, 0x97 }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x0c }, + { 0x034d, 0xc0 }, + { 0x034e, 0x09 }, + { 0x034f, 0x90 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_3280x2464_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x0a }, + { 0x0341, 0x37 }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x0c }, + { 0x034d, 0xd0 }, + { 0x034e, 0x09 }, + { 0x034f, 0xa0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1940x1096_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x02 }, + { 0x0345, 0xa0 }, + { 0x0346, 0x02 }, + { 0x0347, 0xac }, + { 0x0348, 0x0a }, + { 0x0349, 0x33 }, + { 0x034a, 0x06 }, + { 0x034b, 0xf3 }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x07 }, + { 0x034d, 0x94 }, + { 0x034e, 0x04 }, + { 0x034f, 0x48 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1936x1096_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x02 }, + { 0x0345, 0xa0 }, + { 0x0346, 0x02 }, + { 0x0347, 0xac }, + { 0x0348, 0x0a }, + { 0x0349, 0x2f }, + { 0x034a, 0x06 }, + { 0x034b, 0xf3 }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x07 }, + { 0x034d, 0x90 }, + { 0x034e, 0x04 }, + { 0x034f, 0x48 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1924x1080_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x02 }, + { 0x0345, 0xa8 }, + { 0x0346, 0x02 }, + { 0x0347, 0xb4 }, + { 0x0348, 0x0a }, + { 0x0349, 0x2b }, + { 0x034a, 0x06 }, + { 0x034b, 0xeb }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x07 }, + { 0x034d, 0x84 }, + { 0x034e, 0x04 }, + { 0x034f, 0x38 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1920x1080_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x02 }, + { 0x0345, 0xa8 }, + { 0x0346, 0x02 }, + { 0x0347, 0xb4 }, + { 0x0348, 0x0a }, + { 0x0349, 0x27 }, + { 0x034a, 0x06 }, + { 0x034b, 0xeb }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x00 }, + { 0x0901, 0x11 }, + { 0x0902, 0x00 }, + { 0x034c, 0x07 }, + { 0x034d, 0x80 }, + { 0x034e, 0x04 }, + { 0x034f, 0x38 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1640x1232_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x06 }, + { 0x034d, 0x68 }, + { 0x034e, 0x04 }, + { 0x034f, 0xd0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1640x922_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x01 }, + { 0x0347, 0x30 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x08 }, + { 0x034b, 0x63 }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x06 }, + { 0x034d, 0x68 }, + { 0x034e, 0x03 }, + { 0x034f, 0x9a }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1300x736_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x01 }, + { 0x0345, 0x58 }, + { 0x0346, 0x01 }, + { 0x0347, 0xf0 }, + { 0x0348, 0x0b }, + { 0x0349, 0x7f }, + { 0x034a, 0x07 }, + { 0x034b, 0xaf }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x05 }, + { 0x034d, 0x14 }, + { 0x034e, 0x02 }, + { 0x034f, 0xe0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1296x736_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x01 }, + { 0x0345, 0x58 }, + { 0x0346, 0x01 }, + { 0x0347, 0xf0 }, + { 0x0348, 0x0b }, + { 0x0349, 0x77 }, + { 0x034a, 0x07 }, + { 0x034b, 0xaf }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x05 }, + { 0x034d, 0x10 }, + { 0x034e, 0x02 }, + { 0x034f, 0xe0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1284x720_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x01 }, + { 0x0345, 0x68 }, + { 0x0346, 0x02 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0b }, + { 0x0349, 0x6f }, + { 0x034a, 0x07 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x05 }, + { 0x034d, 0x04 }, + { 0x034e, 0x02 }, + { 0x034f, 0xd0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_1280x720_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x07 }, + { 0x0343, 0x2c }, + { 0x0340, 0x05 }, + { 0x0341, 0x1a }, + { 0x0344, 0x01 }, + { 0x0345, 0x68 }, + { 0x0346, 0x02 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0b }, + { 0x0349, 0x67 }, + { 0x034a, 0x07 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x22 }, + { 0x0902, 0x00 }, + { 0x034c, 0x05 }, + { 0x034d, 0x00 }, + { 0x034e, 0x02 }, + { 0x034f, 0xd0 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x00 }, + { 0x0701, 0x10 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const struct imx355_reg mode_820x616_regs[] = { + { 0x0112, 0x0a }, + { 0x0113, 0x0a }, + { 0x0114, 0x03 }, + { 0x0342, 0x0e }, + { 0x0343, 0x58 }, + { 0x0340, 0x02 }, + { 0x0341, 0x8c }, + { 0x0344, 0x00 }, + { 0x0345, 0x00 }, + { 0x0346, 0x00 }, + { 0x0347, 0x00 }, + { 0x0348, 0x0c }, + { 0x0349, 0xcf }, + { 0x034a, 0x09 }, + { 0x034b, 0x9f }, + { 0x0220, 0x00 }, + { 0x0222, 0x01 }, + { 0x0900, 0x01 }, + { 0x0901, 0x44 }, + { 0x0902, 0x00 }, + { 0x034c, 0x03 }, + { 0x034d, 0x34 }, + { 0x034e, 0x02 }, + { 0x034f, 0x68 }, + { 0x0301, 0x05 }, + { 0x0303, 0x01 }, + { 0x0305, 0x02 }, + { 0x0306, 0x00 }, + { 0x0307, 0x78 }, + { 0x030b, 0x01 }, + { 0x030d, 0x02 }, + { 0x030e, 0x00 }, + { 0x030f, 0x4b }, + { 0x0310, 0x00 }, + { 0x0700, 0x02 }, + { 0x0701, 0x78 }, + { 0x0820, 0x0b }, + { 0x0821, 0x40 }, + { 0x3088, 0x04 }, + { 0x6813, 0x02 }, + { 0x6835, 0x07 }, + { 0x6836, 0x01 }, + { 0x6837, 0x04 }, + { 0x684d, 0x07 }, + { 0x684e, 0x01 }, + { 0x684f, 0x04 }, +}; + +static const char * const imx355_test_pattern_menu[] = { + "Disabled", + "100% color bars", + "Solid color", + "Fade to gray color bars", + "PN9" +}; + +/* supported link frequencies */ +static const s64 link_freq_menu_items[] = { + IMX355_LINK_FREQ_DEFAULT, +}; + +/* Mode configs */ +static const struct imx355_mode supported_modes[] = { + { + .width = 3280, + .height = 2464, + .fll_def = 2615, + .fll_min = 2615, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), + .regs = mode_3280x2464_regs, + }, + }, + { + .width = 3268, + .height = 2448, + .fll_def = 2615, + .fll_min = 2615, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs), + .regs = mode_3268x2448_regs, + }, + }, + { + .width = 3264, + .height = 2448, + .fll_def = 2615, + .fll_min = 2615, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), + .regs = mode_3264x2448_regs, + }, + }, + { + .width = 1940, + .height = 1096, + .fll_def = 1306, + .fll_min = 1306, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs), + .regs = mode_1940x1096_regs, + }, + }, + { + .width = 1936, + .height = 1096, + .fll_def = 1306, + .fll_min = 1306, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), + .regs = mode_1936x1096_regs, + }, + }, + { + .width = 1924, + .height = 1080, + .fll_def = 1306, + .fll_min = 1306, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs), + .regs = mode_1924x1080_regs, + }, + }, + { + .width = 1920, + .height = 1080, + .fll_def = 1306, + .fll_min = 1306, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), + .regs = mode_1920x1080_regs, + }, + }, + { + .width = 1640, + .height = 1232, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), + .regs = mode_1640x1232_regs, + }, + }, + { + .width = 1640, + .height = 922, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), + .regs = mode_1640x922_regs, + }, + }, + { + .width = 1300, + .height = 736, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1300x736_regs), + .regs = mode_1300x736_regs, + }, + }, + { + .width = 1296, + .height = 736, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), + .regs = mode_1296x736_regs, + }, + }, + { + .width = 1284, + .height = 720, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1284x720_regs), + .regs = mode_1284x720_regs, + }, + }, + { + .width = 1280, + .height = 720, + .fll_def = 1306, + .fll_min = 1306, + .llp = 1836, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), + .regs = mode_1280x720_regs, + }, + }, + { + .width = 820, + .height = 616, + .fll_def = 652, + .fll_min = 652, + .llp = 3672, + .link_freq_index = IMX355_LINK_FREQ_INDEX, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_820x616_regs), + .regs = mode_820x616_regs, + }, + }, +}; + +static inline struct imx355 *to_imx355(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx355, sd); +} + +/* Get bayer order based on flip setting. */ +static u32 imx355_get_format_code(struct imx355 *imx355) +{ + /* + * Only one bayer order is supported. + * It depends on the flip settings. + */ + u32 code; + static const u32 codes[2][2] = { + { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, }, + { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, + }; + + lockdep_assert_held(&imx355->mutex); + code = codes[imx355->vflip->val][imx355->hflip->val]; + + return code; +} + +/* Read registers up to 4 at a time */ +static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = { 0 }; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + 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)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/* Write registers up to 4 at a time */ +static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/* Write a list of registers */ +static int imx355_write_regs(struct imx355 *imx355, + const struct imx355_reg *regs, u32 len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + int ret; + u32 i; + + for (i = 0; i < len; i++) { + ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "write reg 0x%4.4x return err %d", + regs[i].address, ret); + + return ret; + } + } + + return 0; +} + +/* Open sub-device */ +static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct imx355 *imx355 = to_imx355(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + mutex_lock(&imx355->mutex); + + /* Initialize try_fmt */ + try_fmt->width = imx355->cur_mode->width; + try_fmt->height = imx355->cur_mode->height; + try_fmt->code = imx355_get_format_code(imx355); + try_fmt->field = V4L2_FIELD_NONE; + + mutex_unlock(&imx355->mutex); + + return 0; +} + +static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx355 *imx355 = container_of(ctrl->handler, + struct imx355, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + s64 max; + int ret; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = imx355->cur_mode->height + ctrl->val - 10; + __v4l2_ctrl_modify_range(imx355->exposure, + imx355->exposure->minimum, + max, imx355->exposure->step, max); + break; + } + + /* + * Applying V4L2 control value only happens + * when power is up for streaming + */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + /* Analog gain = 1024/(1024 - ctrl->val) times */ + ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2, + ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2, + ctrl->val); + break; + case V4L2_CID_EXPOSURE: + ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2, + ctrl->val); + break; + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2, + imx355->cur_mode->height + ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN, + 2, ctrl->val); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1, + imx355->hflip->val | + imx355->vflip->val << 1); + break; + default: + ret = -EINVAL; + dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx355_ctrl_ops = { + .s_ctrl = imx355_set_ctrl, +}; + +static int imx355_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx355 *imx355 = to_imx355(sd); + + if (code->index > 0) + return -EINVAL; + + mutex_lock(&imx355->mutex); + code->code = imx355_get_format_code(imx355); + mutex_unlock(&imx355->mutex); + + return 0; +} + +static int imx355_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx355 *imx355 = to_imx355(sd); + + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + mutex_lock(&imx355->mutex); + if (fse->code != imx355_get_format_code(imx355)) { + mutex_unlock(&imx355->mutex); + return -EINVAL; + } + mutex_unlock(&imx355->mutex); + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static void imx355_update_pad_format(struct imx355 *imx355, + const struct imx355_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = imx355_get_format_code(imx355); + fmt->format.field = V4L2_FIELD_NONE; +} + +static int imx355_do_get_pad_format(struct imx355 *imx355, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt; + struct v4l2_subdev *sd = &imx355->sd; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + fmt->format = *framefmt; + } else { + imx355_update_pad_format(imx355, imx355->cur_mode, fmt); + } + + return 0; +} + +static int imx355_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx355 *imx355 = to_imx355(sd); + int ret; + + mutex_lock(&imx355->mutex); + ret = imx355_do_get_pad_format(imx355, cfg, fmt); + mutex_unlock(&imx355->mutex); + + return ret; +} + +static int +imx355_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx355 *imx355 = to_imx355(sd); + const struct imx355_mode *mode; + struct v4l2_mbus_framefmt *framefmt; + s32 vblank_def; + s32 vblank_min; + s64 h_blank; + u64 pixel_rate; + u32 height; + + mutex_lock(&imx355->mutex); + + /* + * Only one bayer order is supported. + * It depends on the flip settings. + */ + fmt->format.code = imx355_get_format_code(imx355); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + imx355_update_pad_format(imx355, mode, fmt); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + *framefmt = fmt->format; + } else { + imx355->cur_mode = mode; + pixel_rate = imx355->link_def_freq * 2 * 4; + do_div(pixel_rate, 10); + __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); + /* Update limits and set FPS to default */ + height = imx355->cur_mode->height; + vblank_def = imx355->cur_mode->fll_def - height; + vblank_min = imx355->cur_mode->fll_min - height; + height = IMX355_FLL_MAX - height; + __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def); + h_blank = mode->llp - imx355->cur_mode->width; + /* + * Currently hblank is not changeable. + * So FPS control is done only by vblank. + */ + __v4l2_ctrl_modify_range(imx355->hblank, h_blank, + h_blank, 1, h_blank); + } + + mutex_unlock(&imx355->mutex); + + return 0; +} + +/* Start streaming */ +static int imx355_start_streaming(struct imx355 *imx355) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + const struct imx355_reg_list *reg_list; + int ret; + + /* Global Setting */ + reg_list = &imx355_global_setting; + ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(&client->dev, "failed to set global settings"); + return ret; + } + + /* Apply default values of current mode */ + reg_list = &imx355->cur_mode->reg_list; + ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + /* set digital gain control to all color mode */ + ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); + if (ret) + return ret; + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); + if (ret) + return ret; + + return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, + 1, IMX355_MODE_STREAMING); +} + +/* Stop streaming */ +static int imx355_stop_streaming(struct imx355 *imx355) +{ + return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, + 1, IMX355_MODE_STANDBY); +} + +static int imx355_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx355 *imx355 = to_imx355(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&imx355->mutex); + if (imx355->streaming == enable) { + mutex_unlock(&imx355->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto err_unlock; + } + + /* + * Apply default & customized values + * and then start streaming. + */ + ret = imx355_start_streaming(imx355); + if (ret) + goto err_rpm_put; + } else { + imx355_stop_streaming(imx355); + pm_runtime_put(&client->dev); + } + + imx355->streaming = enable; + + /* vflip and hflip cannot change during streaming */ + __v4l2_ctrl_grab(imx355->vflip, enable); + __v4l2_ctrl_grab(imx355->hflip, enable); + + mutex_unlock(&imx355->mutex); + + return ret; + +err_rpm_put: + pm_runtime_put(&client->dev); +err_unlock: + mutex_unlock(&imx355->mutex); + + return ret; +} + +static int __maybe_unused imx355_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx355 *imx355 = to_imx355(sd); + + if (imx355->streaming) + imx355_stop_streaming(imx355); + + return 0; +} + +static int __maybe_unused imx355_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx355 *imx355 = to_imx355(sd); + int ret; + + if (imx355->streaming) { + ret = imx355_start_streaming(imx355); + if (ret) + goto error; + } + + return 0; + +error: + imx355_stop_streaming(imx355); + imx355->streaming = 0; + return ret; +} + +/* Verify chip ID */ +static int imx355_identify_module(struct imx355 *imx355) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + int ret; + u32 val; + + ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX355_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + IMX355_CHIP_ID, val); + return -EIO; + } + return 0; +} + +static const struct v4l2_subdev_core_ops imx355_subdev_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops imx355_video_ops = { + .s_stream = imx355_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx355_pad_ops = { + .enum_mbus_code = imx355_enum_mbus_code, + .get_fmt = imx355_get_pad_format, + .set_fmt = imx355_set_pad_format, + .enum_frame_size = imx355_enum_frame_size, +}; + +static const struct v4l2_subdev_ops imx355_subdev_ops = { + .core = &imx355_subdev_core_ops, + .video = &imx355_video_ops, + .pad = &imx355_pad_ops, +}; + +static const struct media_entity_operations imx355_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops imx355_internal_ops = { + .open = imx355_open, +}; + +/* Initialize control handlers */ +static int imx355_init_controls(struct imx355 *imx355) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max; + s64 vblank_def; + s64 vblank_min; + s64 hblank; + u64 pixel_rate; + const struct imx355_mode *mode; + u32 max; + int ret; + + ctrl_hdlr = &imx355->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); + if (ret) + return ret; + + ctrl_hdlr->lock = &imx355->mutex; + max = ARRAY_SIZE(link_freq_menu_items) - 1; + imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_LINK_FREQ, max, 0, + link_freq_menu_items); + if (imx355->link_freq) + imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = imx355->link_def_freq * 2 * 4; + do_div(pixel_rate, 10); + /* By default, PIXEL_RATE is read only */ + imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + /* Initialize vblank/hblank/exposure parameters based on current mode */ + mode = imx355->cur_mode; + vblank_def = mode->fll_def - mode->height; + vblank_min = mode->fll_min - mode->height; + imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_VBLANK, vblank_min, + IMX355_FLL_MAX - mode->height, + 1, vblank_def); + + hblank = mode->llp - mode->width; + imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + if (imx355->hblank) + imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* fll >= exposure time + adjust parameter (default value is 10) */ + exposure_max = mode->fll_def - 10; + imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX355_EXPOSURE_MIN, exposure_max, + IMX355_EXPOSURE_STEP, + IMX355_EXPOSURE_DEFAULT); + + imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX, + IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT); + + /* Digital gain */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX, + IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx355_test_pattern_menu) - 1, + 0, 0, imx355_test_pattern_menu); + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "control init failed: %d", ret); + goto error; + } + + imx355->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) +{ + struct imx355_hwcfg *cfg; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + unsigned int i; + int ret; + + if (!fwnode) + return NULL; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return NULL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (ret) + goto out_err; + + cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + goto out_err; + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &cfg->ext_clk); + if (ret) { + dev_err(dev, "can't get clock frequency"); + goto out_err; + } + + dev_dbg(dev, "ext clk: %d", cfg->ext_clk); + if (cfg->ext_clk != IMX355_EXT_CLK) { + dev_err(dev, "external clock %d is not supported", + cfg->ext_clk); + goto out_err; + } + + dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); + if (!bus_cfg.nr_of_link_frequencies) { + dev_warn(dev, "no link frequencies defined"); + goto out_err; + } + + cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; + cfg->link_freqs = devm_kcalloc(dev, + bus_cfg.nr_of_link_frequencies + 1, + sizeof(*cfg->link_freqs), GFP_KERNEL); + if (!cfg->link_freqs) + goto out_err; + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; + dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return cfg; + +out_err: + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return NULL; +} + +static int imx355_probe(struct i2c_client *client) +{ + struct imx355 *imx355; + int ret; + u32 i; + + imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); + if (!imx355) + return -ENOMEM; + + mutex_init(&imx355->mutex); + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); + + /* Check module identity */ + ret = imx355_identify_module(imx355); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + goto error_probe; + } + + imx355->hwcfg = imx355_get_hwcfg(&client->dev); + if (!imx355->hwcfg) { + dev_err(&client->dev, "failed to get hwcfg"); + ret = -ENODEV; + goto error_probe; + } + + imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX]; + for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) { + if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) { + dev_dbg(&client->dev, "link freq index %d matched", i); + break; + } + } + + if (i == imx355->hwcfg->nr_of_link_freqs) { + dev_err(&client->dev, "no link frequency supported"); + ret = -EINVAL; + goto error_probe; + } + + /* Set default mode to max resolution */ + imx355->cur_mode = &supported_modes[0]; + + ret = imx355_init_controls(imx355); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto error_probe; + } + + /* Initialize subdev */ + imx355->sd.internal_ops = &imx355_internal_ops; + imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + imx355->sd.entity.ops = &imx355_subdev_entity_ops; + imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx355->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&imx355->sd); + if (ret < 0) + goto error_media_entity; + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx355->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(imx355->sd.ctrl_handler); + +error_probe: + mutex_destroy(&imx355->mutex); + + return ret; +} + +static int imx355_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx355 *imx355 = to_imx355(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx355->mutex); + + return 0; +} + +static const struct dev_pm_ops imx355_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) +}; + +static const struct acpi_device_id imx355_acpi_ids[] = { + { "SONY355A" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); + +static struct i2c_driver imx355_i2c_driver = { + .driver = { + .name = "imx355", + .pm = &imx355_pm_ops, + .acpi_match_table = ACPI_PTR(imx355_acpi_ids), + }, + .probe_new = imx355_probe, + .remove = imx355_remove, +}; +module_i2c_driver(imx355_i2c_driver); + +MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); +MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); +MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_DESCRIPTION("Sony imx355 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c @@ -362,7 +362,8 @@ static int lm3560_subdev_init(struct lm3560_flash *flash, v4l2_i2c_subdev_init(&flash->subdev_led[led_no], client, &lm3560_ops); flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - strcpy(flash->subdev_led[led_no].name, led_name); + strscpy(flash->subdev_led[led_no].name, led_name, + sizeof(flash->subdev_led[led_no].name)); rval = lm3560_init_controls(flash, led_no); if (rval) goto err_out; diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c @@ -278,7 +278,8 @@ static int lm3646_subdev_init(struct lm3646_flash *flash) v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops); flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - strcpy(flash->subdev_led.name, LM3646_NAME); + strscpy(flash->subdev_led.name, LM3646_NAME, + sizeof(flash->subdev_led.name)); rval = lm3646_init_controls(flash); if (rval) goto err_out; diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c @@ -987,7 +987,8 @@ static int m5mols_probe(struct i2c_client *client, sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &m5mols_ops); - strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + /* Static name; NEVER use in new drivers! */ + strscpy(sd->name, MODULE_NAME, sizeof(sd->name)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->internal_ops = &m5mols_subdev_internal_ops; diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Maxim Integrated MAX2175 RF to Bits tuner driver * @@ -6,15 +7,6 @@ * * Copyright (C) 2016 Maxim Integrated Products * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> @@ -1165,7 +1157,7 @@ static int max2175_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (vt->index > 0) return -EINVAL; - strlcpy(vt->name, "RF", sizeof(vt->name)); + strscpy(vt->name, "RF", sizeof(vt->name)); vt->type = V4L2_TUNER_RF; vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; vt->rangelow = ctx->bands_rf->rangelow; diff --git a/drivers/media/i2c/max2175.h b/drivers/media/i2c/max2175.h @@ -1,4 +1,5 @@ -/* +/* SPDX-License-Identifier: GPL-2.0 + * * Maxim Integrated MAX2175 RF to Bits tuner driver * * This driver & most of the hard coded values are based on the reference @@ -6,15 +7,6 @@ * * Copyright (C) 2016 Maxim Integrated Products * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __MAX2175_H__ diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c @@ -688,7 +688,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) #endif if (!id) - strlcpy(client->name, "msp3400", sizeof(client->name)); + strscpy(client->name, "msp3400", sizeof(client->name)); if (msp_reset(client) == -1) { dev_dbg_lvl(&client->dev, 1, msp_debug, "msp3400 not found\n"); @@ -703,8 +703,10 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) v4l2_i2c_subdev_init(sd, client, &msp_ops); #if defined(CONFIG_MEDIA_CONTROLLER) - state->pads[IF_AUD_DEC_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; - state->pads[IF_AUD_DEC_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[MSP3400_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[MSP3400_PAD_IF_INPUT].sig_type = PAD_SIGNAL_AUDIO; + state->pads[MSP3400_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[MSP3400_PAD_OUT].sig_type = PAD_SIGNAL_AUDIO; sd->entity.function = MEDIA_ENT_F_IF_AUD_DECODER; diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h @@ -52,6 +52,12 @@ extern int msp_standard; extern bool msp_dolby; extern int msp_stereo_thresh; +enum msp3400_pads { + MSP3400_PAD_IF_INPUT, + MSP3400_PAD_OUT, + MSP3400_NUM_PADS +}; + struct msp_state { struct v4l2_subdev sd; struct v4l2_ctrl_handler hdl; @@ -106,7 +112,7 @@ struct msp_state { unsigned int watch_stereo:1; #if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) - struct media_pad pads[IF_AUD_DEC_PAD_NUM_PADS]; + struct media_pad pads[MSP3400_NUM_PADS]; #endif }; diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c @@ -445,7 +445,6 @@ static int mt9m111_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: sel->r.left = MT9M111_MIN_DARK_COLS; sel->r.top = MT9M111_MIN_DARK_ROWS; sel->r.width = MT9M111_MAX_WIDTH; diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c @@ -888,12 +888,6 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd, sel->r.width = MAX_WIDTH; sel->r.height = MAX_HEIGHT; return 0; - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = VGA_WIDTH; - sel->r.height = VGA_HEIGHT; - return 0; case V4L2_SEL_TGT_CROP: sel->r = priv->frame; return 0; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c @@ -989,7 +989,7 @@ static struct mt9v032_platform_data * mt9v032_get_pdata(struct i2c_client *client) { struct mt9v032_platform_data *pdata = NULL; - struct v4l2_fwnode_endpoint endpoint; + struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 }; struct device_node *np; struct property *prop; diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c @@ -720,7 +720,8 @@ static int noon010_probe(struct i2c_client *client, mutex_init(&info->lock); sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &noon010_ops); - strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + /* Static name; NEVER use in new drivers! */ + strscpy(sd->name, MODULE_NAME, sizeof(sd->name)); sd->internal_ops = &noon010_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c @@ -1230,7 +1230,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (pm_runtime_get_if_in_use(&client->dev) <= 0) + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; ret = 0; @@ -1735,10 +1735,9 @@ static int ov13858_probe(struct i2c_client *client, * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_get_noresume(&client->dev); pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); - pm_runtime_put(&client->dev); + pm_runtime_idle(&client->dev); return 0; @@ -1761,14 +1760,7 @@ static int ov13858_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov13858_free_controls(ov13858); - /* - * Disable runtime PM but keep the device turned on. - * i2c-core with ACPI domain PM will turn off the device. - */ - pm_runtime_get_sync(&client->dev); pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); return 0; } diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c @@ -1010,7 +1010,6 @@ static int ov2640_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP: sel->r.left = 0; sel->r.top = 0; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c @@ -1347,8 +1347,9 @@ static struct ov2659_platform_data * ov2659_get_pdata(struct i2c_client *client) { struct ov2659_platform_data *pdata; - struct v4l2_fwnode_endpoint *bus_cfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct device_node *endpoint; + int ret; if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; @@ -1357,8 +1358,9 @@ ov2659_get_pdata(struct i2c_client *client) if (!endpoint) return NULL; - bus_cfg = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint)); - if (IS_ERR(bus_cfg)) { + ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint), + &bus_cfg); + if (ret) { pdata = NULL; goto done; } @@ -1367,17 +1369,17 @@ ov2659_get_pdata(struct i2c_client *client) if (!pdata) goto done; - if (!bus_cfg->nr_of_link_frequencies) { + if (!bus_cfg.nr_of_link_frequencies) { dev_err(&client->dev, "link-frequencies property not found or too many\n"); pdata = NULL; goto done; } - pdata->link_frequency = bus_cfg->link_frequencies[0]; + pdata->link_frequency = bus_cfg.link_frequencies[0]; done: - v4l2_fwnode_endpoint_free(bus_cfg); + v4l2_fwnode_endpoint_free(&bus_cfg); of_node_put(endpoint); return pdata; } diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c @@ -926,7 +926,7 @@ static int ov2680_mode_init(struct ov2680_dev *sensor) return 0; } -static int ov2680_v4l2_init(struct ov2680_dev *sensor) +static int ov2680_v4l2_register(struct ov2680_dev *sensor) { const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; struct ov2680_ctrls *ctrls = &sensor->ctrls; @@ -1088,26 +1088,20 @@ static int ov2680_probe(struct i2c_client *client) mutex_init(&sensor->lock); - ret = ov2680_v4l2_init(sensor); + ret = ov2680_check_id(sensor); if (ret < 0) goto lock_destroy; - ret = ov2680_check_id(sensor); + ret = ov2680_v4l2_register(sensor); if (ret < 0) - goto error_cleanup; + goto lock_destroy; dev_info(dev, "ov2680 init correctly\n"); return 0; -error_cleanup: - dev_err(dev, "ov2680 init fail: %d\n", ret); - - media_entity_cleanup(&sensor->sd.entity); - v4l2_async_unregister_subdev(&sensor->sd); - v4l2_ctrl_handler_free(&sensor->ctrls.handler); - lock_destroy: + dev_err(dev, "ov2680 init fail: %d\n", ret); mutex_destroy(&sensor->lock); return ret; diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c @@ -549,7 +549,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (pm_runtime_get_if_in_use(&client->dev) <= 0) + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; switch (ctrl->id) { diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c @@ -223,8 +223,10 @@ struct ov5640_dev { int power_count; struct v4l2_mbus_framefmt fmt; + bool pending_fmt_change; const struct ov5640_mode_info *current_mode; + const struct ov5640_mode_info *last_mode; enum ov5640_frame_rate current_fr; struct v4l2_fract frame_interval; @@ -255,7 +257,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) * should be identified and removed to speed register load time * over i2c. */ - +/* YUV422 UYVY VGA@30fps */ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, @@ -286,10 +288,10 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, - {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, + {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, @@ -606,7 +608,7 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = { {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, }; @@ -908,6 +910,26 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, } /* download ov5640 settings to sensor through i2c */ +static int ov5640_set_timings(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) +{ + int ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); + if (ret < 0) + return ret; + + return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); +} + static int ov5640_load_regs(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) { @@ -935,7 +957,13 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } - return ret; + return ov5640_set_timings(sensor, mode); +} + +static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) +{ + return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, + BIT(0), on ? 0 : BIT(0)); } /* read exposure, in number of line periods */ @@ -994,6 +1022,18 @@ static int ov5640_get_gain(struct ov5640_dev *sensor) return gain & 0x3ff; } +static int ov5640_set_gain(struct ov5640_dev *sensor, int gain) +{ + return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, + (u16)gain & 0x3ff); +} + +static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) +{ + return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, + BIT(1), on ? 0 : BIT(1)); +} + static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) { int ret; @@ -1102,12 +1142,25 @@ static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) { int ret; - ret = ov5640_mod_reg(sensor, OV5640_REG_MIPI_CTRL00, BIT(5), - on ? 0 : BIT(5)); - if (ret) - return ret; - ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, - on ? 0x00 : 0x70); + /* + * Enable/disable the MIPI interface + * + * 0x300e = on ? 0x45 : 0x40 + * + * FIXME: the sensor manual (version 2.03) reports + * [7:5] = 000 : 1 data lane mode + * [7:5] = 001 : 2 data lanes mode + * But this settings do not work, while the following ones + * have been validated for 2 data lanes mode. + * + * [7:5] = 010 : 2 data lanes mode + * [4] = 0 : Power up MIPI HS Tx + * [3] = 0 : Power up MIPI LS Rx + * [2] = 1/0 : MIPI interface enable/disable + * [1:0] = 01/00: FIXME: 'debug' + */ + ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, + on ? 0x45 : 0x40); if (ret) return ret; @@ -1331,7 +1384,7 @@ static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); } -static int ov5640_binning_on(struct ov5640_dev *sensor) +static int ov5640_get_binning(struct ov5640_dev *sensor) { u8 temp; int ret; @@ -1339,8 +1392,8 @@ static int ov5640_binning_on(struct ov5640_dev *sensor) ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); if (ret) return ret; - temp &= 0xfe; - return temp ? 1 : 0; + + return temp & BIT(0); } static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) @@ -1385,30 +1438,6 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); } -static int ov5640_set_timings(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) -{ - int ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); - if (ret < 0) - return ret; - - return 0; -} - static const struct ov5640_mode_info * ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, int width, int height, bool nearest) @@ -1450,7 +1479,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, if (ret < 0) return ret; prev_shutter = ret; - ret = ov5640_binning_on(sensor); + ret = ov5640_get_binning(sensor); if (ret < 0) return ret; if (ret && mode->id != OV5640_MODE_720P_1280_720 && @@ -1571,7 +1600,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, } /* set capture gain */ - ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.gain, cap_gain16); + ret = ov5640_set_gain(sensor, cap_gain16); if (ret) return ret; @@ -1584,7 +1613,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, } /* set exposure */ - return __v4l2_ctrl_s_ctrl(sensor->ctrls.exposure, cap_shutter); + return ov5640_set_exposure(sensor, cap_shutter); } /* @@ -1592,53 +1621,45 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, * change mode directly */ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode, - s32 exposure) + const struct ov5640_mode_info *mode) { - int ret; - if (!mode->reg_data) return -EINVAL; /* Write capture setting */ - ret = ov5640_load_regs(sensor, mode); - if (ret < 0) - return ret; - - /* turn auto gain/exposure back on for direct mode */ - ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 1); - if (ret) - return ret; - - return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, exposure); + return ov5640_load_regs(sensor, mode); } -static int ov5640_set_mode(struct ov5640_dev *sensor, - const struct ov5640_mode_info *orig_mode) +static int ov5640_set_mode(struct ov5640_dev *sensor) { const struct ov5640_mode_info *mode = sensor->current_mode; + const struct ov5640_mode_info *orig_mode = sensor->last_mode; enum ov5640_downsize_mode dn_mode, orig_dn_mode; - s32 exposure; + bool auto_gain = sensor->ctrls.auto_gain->val == 1; + bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; int ret; dn_mode = mode->dn_mode; orig_dn_mode = orig_mode->dn_mode; /* auto gain and exposure must be turned off when changing modes */ - ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 0); - if (ret) - return ret; + if (auto_gain) { + ret = ov5640_set_autogain(sensor, false); + if (ret) + return ret; + } - exposure = sensor->ctrls.auto_exp->val; - ret = ov5640_set_exposure(sensor, V4L2_EXPOSURE_MANUAL); - if (ret) - return ret; + if (auto_exp) { + ret = ov5640_set_autoexposure(sensor, false); + if (ret) + goto restore_auto_gain; + } if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { /* * change between subsampling and scaling - * go through exposure calucation + * go through exposure calculation */ ret = ov5640_set_mode_exposure_calc(sensor, mode); } else { @@ -1646,15 +1667,16 @@ static int ov5640_set_mode(struct ov5640_dev *sensor, * change inside subsampling or scaling * download firmware directly */ - ret = ov5640_set_mode_direct(sensor, mode, exposure); + ret = ov5640_set_mode_direct(sensor, mode); } - if (ret < 0) - return ret; + goto restore_auto_exp_gain; - ret = ov5640_set_timings(sensor, mode); - if (ret < 0) - return ret; + /* restore auto gain and exposure */ + if (auto_gain) + ov5640_set_autogain(sensor, true); + if (auto_exp) + ov5640_set_autoexposure(sensor, true); ret = ov5640_set_binning(sensor, dn_mode != SCALING); if (ret < 0) @@ -1673,8 +1695,18 @@ static int ov5640_set_mode(struct ov5640_dev *sensor, return ret; sensor->pending_mode_change = false; + sensor->last_mode = mode; return 0; + +restore_auto_exp_gain: + if (auto_exp) + ov5640_set_autoexposure(sensor, true); +restore_auto_gain: + if (auto_gain) + ov5640_set_autogain(sensor, true); + + return ret; } static int ov5640_set_framefmt(struct ov5640_dev *sensor, @@ -1689,6 +1721,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) ret = ov5640_load_regs(sensor, &ov5640_mode_init_data); if (ret < 0) return ret; + sensor->last_mode = &ov5640_mode_init_data; ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, (ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) | @@ -1697,7 +1730,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) return ret; /* now restore the last capture mode */ - ret = ov5640_set_mode(sensor, &ov5640_mode_init_data); + ret = ov5640_set_mode(sensor); if (ret < 0) return ret; @@ -1786,23 +1819,69 @@ static int ov5640_set_power(struct ov5640_dev *sensor, bool on) if (ret) goto power_off; - if (sensor->ep.bus_type == V4L2_MBUS_CSI2) { - /* - * start streaming briefly followed by stream off in - * order to coax the clock lane into LP-11 state. - */ - ret = ov5640_set_stream_mipi(sensor, true); - if (ret) - goto power_off; - usleep_range(1000, 2000); - ret = ov5640_set_stream_mipi(sensor, false); - if (ret) - goto power_off; + /* We're done here for DVP bus, while CSI-2 needs setup. */ + if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) + return 0; + + /* + * Power up MIPI HS Tx and LS Rx; 2 data lanes mode + * + * 0x300e = 0x40 + * [7:5] = 010 : 2 data lanes mode (see FIXME note in + * "ov5640_set_stream_mipi()") + * [4] = 0 : Power up MIPI HS Tx + * [3] = 0 : Power up MIPI LS Rx + * [2] = 0 : MIPI interface disabled + */ + ret = ov5640_write_reg(sensor, + OV5640_REG_IO_MIPI_CTRL00, 0x40); + if (ret) + goto power_off; + + /* + * Gate clock and set LP11 in 'no packets mode' (idle) + * + * 0x4800 = 0x24 + * [5] = 1 : Gate clock when 'no packets' + * [2] = 1 : MIPI bus in LP11 when 'no packets' + */ + ret = ov5640_write_reg(sensor, + OV5640_REG_MIPI_CTRL00, 0x24); + if (ret) + goto power_off; + + /* + * Set data lanes and clock in LP11 when 'sleeping' + * + * 0x3019 = 0x70 + * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' + * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' + * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' + */ + ret = ov5640_write_reg(sensor, + OV5640_REG_PAD_OUTPUT00, 0x70); + if (ret) + goto power_off; + + /* Give lanes some time to coax into LP11 state. */ + usleep_range(500, 1000); + + } else { + if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { + /* Reset MIPI bus settings to their default values. */ + ov5640_write_reg(sensor, + OV5640_REG_IO_MIPI_CTRL00, 0x58); + ov5640_write_reg(sensor, + OV5640_REG_MIPI_CTRL00, 0x04); + ov5640_write_reg(sensor, + OV5640_REG_PAD_OUTPUT00, 0x00); } - return 0; + ov5640_set_power_off(sensor); } + return 0; + power_off: ov5640_set_power_off(sensor); return ret; @@ -1968,9 +2047,12 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, if (new_mode != sensor->current_mode) { sensor->current_mode = new_mode; - sensor->fmt = *mbus_fmt; sensor->pending_mode_change = true; } + if (mbus_fmt->code != sensor->fmt.code) { + sensor->fmt = *mbus_fmt; + sensor->pending_fmt_change = true; + } out: mutex_unlock(&sensor->lock); return ret; @@ -2137,20 +2219,20 @@ static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) return ret; } -static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, int exp) +static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, + enum v4l2_exposure_auto_type auto_exposure) { struct ov5640_ctrls *ctrls = &sensor->ctrls; - bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO); + bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); int ret = 0; if (ctrls->auto_exp->is_new) { - ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, - BIT(0), auto_exposure ? 0 : BIT(0)); + ret = ov5640_set_autoexposure(sensor, auto_exp); if (ret) return ret; } - if (!auto_exposure && ctrls->exposure->is_new) { + if (!auto_exp && ctrls->exposure->is_new) { u16 max_exp; ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, @@ -2170,25 +2252,19 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, int exp) return ret; } -static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, int auto_gain) +static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) { struct ov5640_ctrls *ctrls = &sensor->ctrls; int ret = 0; if (ctrls->auto_gain->is_new) { - ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, - BIT(1), - ctrls->auto_gain->val ? 0 : BIT(1)); + ret = ov5640_set_autogain(sensor, auto_gain); if (ret) return ret; } - if (!auto_gain && ctrls->gain->is_new) { - u16 gain = (u16)ctrls->gain->val; - - ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, - gain & 0x3ff); - } + if (!auto_gain && ctrls->gain->is_new) + ret = ov5640_set_gain(sensor, ctrls->gain->val); return ret; } @@ -2261,16 +2337,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_AUTOGAIN: - if (!ctrl->val) - return 0; val = ov5640_get_gain(sensor); if (val < 0) return val; sensor->ctrls.gain->val = val; break; case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_MANUAL) - return 0; val = ov5640_get_exposure(sensor); if (val < 0) return val; @@ -2501,8 +2573,6 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, if (frame_rate < 0) frame_rate = OV5640_15_FPS; - sensor->current_fr = frame_rate; - sensor->frame_interval = fi->interval; mode = ov5640_find_mode(sensor, frame_rate, mode->hact, mode->vact, true); if (!mode) { @@ -2510,7 +2580,10 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, goto out; } - if (mode != sensor->current_mode) { + if (mode != sensor->current_mode || + frame_rate != sensor->current_fr) { + sensor->current_fr = frame_rate; + sensor->frame_interval = fi->interval; sensor->current_mode = mode; sensor->pending_mode_change = true; } @@ -2541,16 +2614,19 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) if (sensor->streaming == !enable) { if (enable && sensor->pending_mode_change) { - ret = ov5640_set_mode(sensor, sensor->current_mode); + ret = ov5640_set_mode(sensor); if (ret) goto out; + } + if (enable && sensor->pending_fmt_change) { ret = ov5640_set_framefmt(sensor, &sensor->fmt); if (ret) goto out; + sensor->pending_fmt_change = false; } - if (sensor->ep.bus_type == V4L2_MBUS_CSI2) + if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) ret = ov5640_set_stream_mipi(sensor, enable); else ret = ov5640_set_stream_dvp(sensor, enable); @@ -2642,9 +2718,14 @@ static int ov5640_probe(struct i2c_client *client, return -ENOMEM; sensor->i2c_client = client; + + /* + * default init sequence initialize sensor to + * YUV422 UYVY VGA@30fps + */ fmt = &sensor->fmt; - fmt->code = ov5640_formats[0].code; - fmt->colorspace = ov5640_formats[0].colorspace; + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->colorspace = V4L2_COLORSPACE_SRGB; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); @@ -2656,7 +2737,7 @@ static int ov5640_probe(struct i2c_client *client, sensor->current_fr = OV5640_30_FPS; sensor->current_mode = &ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480]; - sensor->pending_mode_change = true; + sensor->last_mode = sensor->current_mode; sensor->ae_target = 52; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c @@ -1127,7 +1127,7 @@ static int ov5645_probe(struct i2c_client *client, return ret; } - if (ov5645->ep.bus_type != V4L2_MBUS_CSI2) { + if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { dev_err(dev, "invalid bus type, must be CSI2\n"); return -EINVAL; } diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c @@ -532,7 +532,7 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = { static int ov5647_parse_dt(struct device_node *np) { - struct v4l2_fwnode_endpoint bus_cfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct device_node *ep; int ret; diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c @@ -2016,7 +2016,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (pm_runtime_get_if_in_use(&client->dev) <= 0) + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; switch (ctrl->id) { @@ -2504,10 +2504,9 @@ static int ov5670_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_get_noresume(&client->dev); pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); - pm_runtime_put(&client->dev); + pm_runtime_idle(&client->dev); return 0; @@ -2536,14 +2535,7 @@ static int ov5670_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); mutex_destroy(&ov5670->mutex); - /* - * Disable runtime PM but keep the device turned on. - * i2c-core with ACPI domain PM will turn off the device. - */ - pm_runtime_get_sync(&client->dev); pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); return 0; } diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c @@ -1110,7 +1110,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (pm_runtime_get_if_in_use(&client->dev) <= 0) + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; switch (ctrl->id) { diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c @@ -449,7 +449,6 @@ static int ov6650_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: sel->r.left = DEF_HSTRT << 1; sel->r.top = DEF_VSTRT << 1; sel->r.width = W_CIF; diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c @@ -1279,9 +1279,9 @@ static int ov7251_probe(struct i2c_client *client) return ret; } - if (ov7251->ep.bus_type != V4L2_MBUS_CSI2) { + if (ov7251->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { dev_err(dev, "invalid bus type (%u), must be CSI2 (%u)\n", - ov7251->ep.bus_type, V4L2_MBUS_CSI2); + ov7251->ep.bus_type, V4L2_MBUS_CSI2_DPHY); return -EINVAL; } diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c @@ -1728,7 +1728,7 @@ static int ov7670_parse_dt(struct device *dev, struct ov7670_info *info) { struct fwnode_handle *fwnode = dev_fwnode(dev); - struct v4l2_fwnode_endpoint bus_cfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct fwnode_handle *ep; int ret; @@ -1808,17 +1808,24 @@ static int ov7670_probe(struct i2c_client *client, info->pclk_hb_disable = true; } - info->clk = devm_clk_get(&client->dev, "xclk"); - if (IS_ERR(info->clk)) - return PTR_ERR(info->clk); - ret = clk_prepare_enable(info->clk); - if (ret) - return ret; + info->clk = devm_clk_get(&client->dev, "xclk"); /* optional */ + if (IS_ERR(info->clk)) { + ret = PTR_ERR(info->clk); + if (ret == -ENOENT) + info->clk = NULL; + else + return ret; + } + if (info->clk) { + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; - info->clock_speed = clk_get_rate(info->clk) / 1000000; - if (info->clock_speed < 10 || info->clock_speed > 48) { - ret = -EINVAL; - goto clk_disable; + info->clock_speed = clk_get_rate(info->clk) / 1000000; + if (info->clock_speed < 10 || info->clock_speed > 48) { + ret = -EINVAL; + goto clk_disable; + } } ret = ov7670_init_gpio(client, info); diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> @@ -414,6 +415,7 @@ struct ov772x_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; struct clk *clk; + struct regmap *regmap; struct ov772x_camera_info *info; struct gpio_desc *pwdn_gpio; struct gpio_desc *rstb_gpio; @@ -549,51 +551,18 @@ static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd) return container_of(sd, struct ov772x_priv, subdev); } -static int ov772x_read(struct i2c_client *client, u8 addr) -{ - int ret; - u8 val; - - ret = i2c_master_send(client, &addr, 1); - if (ret < 0) - return ret; - ret = i2c_master_recv(client, &val, 1); - if (ret < 0) - return ret; - - return val; -} - -static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value) -{ - return i2c_smbus_write_byte_data(client, addr, value); -} - -static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask, - u8 set) -{ - s32 val = ov772x_read(client, command); - - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return ov772x_write(client, command, val); -} - -static int ov772x_reset(struct i2c_client *client) +static int ov772x_reset(struct ov772x_priv *priv) { int ret; - ret = ov772x_write(client, COM7, SCCB_RESET); + ret = regmap_write(priv->regmap, COM7, SCCB_RESET); if (ret < 0) return ret; usleep_range(1000, 5000); - return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); + return regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE, + SOFT_SLEEP_MODE); } /* @@ -611,8 +580,8 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) if (priv->streaming == enable) goto done; - ret = ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, - enable ? 0 : SOFT_SLEEP_MODE); + ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE, + enable ? 0 : SOFT_SLEEP_MODE); if (ret) goto done; @@ -657,7 +626,6 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv, const struct ov772x_color_format *cfmt, const struct ov772x_win_size *win) { - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); unsigned long fin = clk_get_rate(priv->clk); unsigned int best_diff; unsigned int fsize; @@ -723,11 +691,11 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv, } } - ret = ov772x_write(client, COM4, com4 | COM4_RESERVED); + ret = regmap_write(priv->regmap, COM4, com4 | COM4_RESERVED); if (ret < 0) return ret; - ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED); + ret = regmap_write(priv->regmap, CLKRC, clkrc | CLKRC_RESERVED); if (ret < 0) return ret; @@ -788,8 +756,7 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov772x_priv *priv = container_of(ctrl->handler, struct ov772x_priv, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct regmap *regmap = priv->regmap; int ret = 0; u8 val; @@ -808,27 +775,27 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) val = ctrl->val ? VFLIP_IMG : 0x00; if (priv->info && (priv->info->flags & OV772X_FLAG_VFLIP)) val ^= VFLIP_IMG; - return ov772x_mask_set(client, COM3, VFLIP_IMG, val); + return regmap_update_bits(regmap, COM3, VFLIP_IMG, val); case V4L2_CID_HFLIP: val = ctrl->val ? HFLIP_IMG : 0x00; if (priv->info && (priv->info->flags & OV772X_FLAG_HFLIP)) val ^= HFLIP_IMG; - return ov772x_mask_set(client, COM3, HFLIP_IMG, val); + return regmap_update_bits(regmap, COM3, HFLIP_IMG, val); case V4L2_CID_BAND_STOP_FILTER: if (!ctrl->val) { /* Switch the filter off, it is on now */ - ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); + ret = regmap_update_bits(regmap, BDBASE, 0xff, 0xff); if (!ret) - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, 0); + ret = regmap_update_bits(regmap, COM8, + BNDF_ON_OFF, 0); } else { /* Switch the filter on, set AEC low limit */ val = 256 - ctrl->val; - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, BNDF_ON_OFF); + ret = regmap_update_bits(regmap, COM8, + BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, val); + ret = regmap_update_bits(regmap, BDBASE, + 0xff, val); } return ret; @@ -841,18 +808,19 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) static int ov772x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov772x_priv *priv = to_ov772x(sd); int ret; + unsigned int val; reg->size = 1; if (reg->reg > 0xff) return -EINVAL; - ret = ov772x_read(client, reg->reg); + ret = regmap_read(priv->regmap, reg->reg, &val); if (ret < 0) return ret; - reg->val = (__u64)ret; + reg->val = (__u64)val; return 0; } @@ -860,13 +828,13 @@ static int ov772x_g_register(struct v4l2_subdev *sd, static int ov772x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov772x_priv *priv = to_ov772x(sd); if (reg->reg > 0xff || reg->val > 0xff) return -EINVAL; - return ov772x_write(client, reg->reg, reg->val); + return regmap_write(priv->regmap, reg->reg, reg->val); } #endif @@ -896,6 +864,7 @@ static int ov772x_power_on(struct ov772x_priv *priv) GPIOD_OUT_LOW); if (IS_ERR(priv->rstb_gpio)) { dev_info(&client->dev, "Unable to get GPIO \"reset\""); + clk_disable_unprepare(priv->clk); return PTR_ERR(priv->rstb_gpio); } @@ -1004,7 +973,7 @@ static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf, static int ov772x_edgectrl(struct ov772x_priv *priv) { - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + struct regmap *regmap = priv->regmap; int ret; if (!priv->info) @@ -1018,19 +987,19 @@ static int ov772x_edgectrl(struct ov772x_priv *priv) * Remove it when manual mode. */ - ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); + ret = regmap_update_bits(regmap, DSPAUTO, EDGE_ACTRL, 0x00); if (ret < 0) return ret; - ret = ov772x_mask_set(client, - EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, - priv->info->edgectrl.threshold); + ret = regmap_update_bits(regmap, EDGE_TRSHLD, + OV772X_EDGE_THRESHOLD_MASK, + priv->info->edgectrl.threshold); if (ret < 0) return ret; - ret = ov772x_mask_set(client, - EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, - priv->info->edgectrl.strength); + ret = regmap_update_bits(regmap, EDGE_STRNGT, + OV772X_EDGE_STRENGTH_MASK, + priv->info->edgectrl.strength); if (ret < 0) return ret; @@ -1040,15 +1009,15 @@ static int ov772x_edgectrl(struct ov772x_priv *priv) * * Set upper and lower limit. */ - ret = ov772x_mask_set(client, - EDGE_UPPER, OV772X_EDGE_UPPER_MASK, - priv->info->edgectrl.upper); + ret = regmap_update_bits(regmap, EDGE_UPPER, + OV772X_EDGE_UPPER_MASK, + priv->info->edgectrl.upper); if (ret < 0) return ret; - ret = ov772x_mask_set(client, - EDGE_LOWER, OV772X_EDGE_LOWER_MASK, - priv->info->edgectrl.lower); + ret = regmap_update_bits(regmap, EDGE_LOWER, + OV772X_EDGE_LOWER_MASK, + priv->info->edgectrl.lower); if (ret < 0) return ret; } @@ -1060,12 +1029,11 @@ static int ov772x_set_params(struct ov772x_priv *priv, const struct ov772x_color_format *cfmt, const struct ov772x_win_size *win) { - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); int ret; u8 val; /* Reset hardware. */ - ov772x_reset(client); + ov772x_reset(priv); /* Edge Ctrl. */ ret = ov772x_edgectrl(priv); @@ -1073,32 +1041,32 @@ static int ov772x_set_params(struct ov772x_priv *priv, return ret; /* Format and window size. */ - ret = ov772x_write(client, HSTART, win->rect.left >> 2); + ret = regmap_write(priv->regmap, HSTART, win->rect.left >> 2); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, HSIZE, win->rect.width >> 2); + ret = regmap_write(priv->regmap, HSIZE, win->rect.width >> 2); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, VSTART, win->rect.top >> 1); + ret = regmap_write(priv->regmap, VSTART, win->rect.top >> 1); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, VSIZE, win->rect.height >> 1); + ret = regmap_write(priv->regmap, VSIZE, win->rect.height >> 1); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2); + ret = regmap_write(priv->regmap, HOUTSIZE, win->rect.width >> 2); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1); + ret = regmap_write(priv->regmap, VOUTSIZE, win->rect.height >> 1); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, HREF, + ret = regmap_write(priv->regmap, HREF, ((win->rect.top & 1) << HREF_VSTART_SHIFT) | ((win->rect.left & 3) << HREF_HSTART_SHIFT) | ((win->rect.height & 1) << HREF_VSIZE_SHIFT) | ((win->rect.width & 3) << HREF_HSIZE_SHIFT)); if (ret < 0) goto ov772x_set_fmt_error; - ret = ov772x_write(client, EXHCH, + ret = regmap_write(priv->regmap, EXHCH, ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) | ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT)); if (ret < 0) @@ -1107,15 +1075,14 @@ static int ov772x_set_params(struct ov772x_priv *priv, /* Set DSP_CTRL3. */ val = cfmt->dsp3; if (val) { - ret = ov772x_mask_set(client, - DSP_CTRL3, UV_MASK, val); + ret = regmap_update_bits(priv->regmap, DSP_CTRL3, UV_MASK, val); if (ret < 0) goto ov772x_set_fmt_error; } /* DSP_CTRL4: AEC reference point and DSP output format. */ if (cfmt->dsp4) { - ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4); + ret = regmap_write(priv->regmap, DSP_CTRL4, cfmt->dsp4); if (ret < 0) goto ov772x_set_fmt_error; } @@ -1131,13 +1098,12 @@ static int ov772x_set_params(struct ov772x_priv *priv, if (priv->hflip_ctrl->val) val ^= HFLIP_IMG; - ret = ov772x_mask_set(client, - COM3, SWAP_MASK | IMG_MASK, val); + ret = regmap_update_bits(priv->regmap, COM3, SWAP_MASK | IMG_MASK, val); if (ret < 0) goto ov772x_set_fmt_error; /* COM7: Sensor resolution and output format control. */ - ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7); + ret = regmap_write(priv->regmap, COM7, win->com7_bit | cfmt->com7); if (ret < 0) goto ov772x_set_fmt_error; @@ -1150,10 +1116,11 @@ static int ov772x_set_params(struct ov772x_priv *priv, if (priv->band_filter_ctrl->val) { unsigned short band_filter = priv->band_filter_ctrl->val; - ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); + ret = regmap_update_bits(priv->regmap, COM8, + BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, 256 - band_filter); + ret = regmap_update_bits(priv->regmap, BDBASE, + 0xff, 256 - band_filter); if (ret < 0) goto ov772x_set_fmt_error; } @@ -1162,7 +1129,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, ov772x_set_fmt_error: - ov772x_reset(client); + ov772x_reset(priv); return ret; } @@ -1180,7 +1147,6 @@ static int ov772x_get_selection(struct v4l2_subdev *sd, sel->r.top = 0; switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP: sel->r.width = priv->win->rect.width; sel->r.height = priv->win->rect.height; @@ -1276,12 +1242,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv) return ret; /* Check and show product ID and manufacturer ID. */ - pid = ov772x_read(client, PID); - if (pid < 0) - return pid; - ver = ov772x_read(client, VER); - if (ver < 0) - return ver; + ret = regmap_read(priv->regmap, PID, &pid); + if (ret < 0) + return ret; + ret = regmap_read(priv->regmap, VER, &ver); + if (ret < 0) + return ret; switch (VERSION(pid, ver)) { case OV7720: @@ -1297,12 +1263,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv) goto done; } - midh = ov772x_read(client, MIDH); - if (midh < 0) - return midh; - midl = ov772x_read(client, MIDL); - if (midl < 0) - return midl; + ret = regmap_read(priv->regmap, MIDH, &midh); + if (ret < 0) + return ret; + ret = regmap_read(priv->regmap, MIDL, &midl); + if (ret < 0) + return ret; dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", @@ -1386,8 +1352,12 @@ static int ov772x_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov772x_priv *priv; - struct i2c_adapter *adapter = client->adapter; int ret; + static const struct regmap_config ov772x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = DSPAUTO, + }; if (!client->dev.of_node && !client->dev.platform_data) { dev_err(&client->dev, @@ -1395,16 +1365,16 @@ static int ov772x_probe(struct i2c_client *client, return -EINVAL; } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&adapter->dev, - "I2C-Adapter doesn't support SMBUS_BYTE_DATA\n"); - return -EIO; - } - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->regmap = devm_regmap_init_sccb(client, &ov772x_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, "Failed to allocate register map\n"); + return PTR_ERR(priv->regmap); + } + priv->info = client->dev.platform_data; mutex_init(&priv->lock); diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c @@ -510,7 +510,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) int ret; u8 val = 0; - if (pm_runtime_get_if_in_use(&client->dev) <= 0) + if (!pm_runtime_get_if_in_use(&client->dev)) return 0; switch (ctrl->id) { diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c @@ -20,6 +20,7 @@ #include <linux/media.h> #include <linux/module.h> #include <linux/ratelimit.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/videodev2.h> @@ -259,7 +260,7 @@ struct ov965x { /* Protects the struct fields below */ struct mutex lock; - struct i2c_client *client; + struct regmap *regmap; /* Exposure row interval in us */ unsigned int exp_row_interval; @@ -424,51 +425,42 @@ static inline struct ov965x *to_ov965x(struct v4l2_subdev *sd) return container_of(sd, struct ov965x, sd); } -static int ov965x_read(struct i2c_client *client, u8 addr, u8 *val) +static int ov965x_read(struct ov965x *ov965x, u8 addr, u8 *val) { - u8 buf = addr; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &buf - }; int ret; + unsigned int buf; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret == 1) { - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - - if (ret == 1) - *val = buf; - } + ret = regmap_read(ov965x->regmap, addr, &buf); + if (!ret) + *val = buf; + else + *val = -1; - v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02x. (%d)\n", + v4l2_dbg(2, debug, &ov965x->sd, "%s: 0x%02x @ 0x%02x. (%d)\n", __func__, *val, addr, ret); - return ret == 1 ? 0 : ret; + return ret; } -static int ov965x_write(struct i2c_client *client, u8 addr, u8 val) +static int ov965x_write(struct ov965x *ov965x, u8 addr, u8 val) { - u8 buf[2] = { addr, val }; + int ret; - int ret = i2c_master_send(client, buf, 2); + ret = regmap_write(ov965x->regmap, addr, val); - v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02X (%d)\n", + v4l2_dbg(2, debug, &ov965x->sd, "%s: 0x%02x @ 0x%02X (%d)\n", __func__, val, addr, ret); - return ret == 2 ? 0 : ret; + return ret; } -static int ov965x_write_array(struct i2c_client *client, +static int ov965x_write_array(struct ov965x *ov965x, const struct i2c_rv *regs) { int i, ret = 0; for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) - ret = ov965x_write(client, regs[i].addr, regs[i].value); + ret = ov965x_write(ov965x, regs[i].addr, regs[i].value); return ret; } @@ -486,7 +478,7 @@ static int ov965x_set_default_gamma_curve(struct ov965x *ov965x) unsigned int i; for (i = 0; i < ARRAY_SIZE(gamma_curve); i++) { - int ret = ov965x_write(ov965x->client, addr, gamma_curve[i]); + int ret = ov965x_write(ov965x, addr, gamma_curve[i]); if (ret < 0) return ret; @@ -506,7 +498,7 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x) unsigned int i; for (i = 0; i < ARRAY_SIZE(mtx); i++) { - int ret = ov965x_write(ov965x->client, addr, mtx[i]); + int ret = ov965x_write(ov965x, addr, mtx[i]); if (ret < 0) return ret; @@ -542,16 +534,15 @@ static int __ov965x_set_power(struct ov965x *ov965x, int on) static int ov965x_s_power(struct v4l2_subdev *sd, int on) { struct ov965x *ov965x = to_ov965x(sd); - struct i2c_client *client = ov965x->client; int ret = 0; - v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on); + v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on); mutex_lock(&ov965x->lock); if (ov965x->power == !on) { ret = __ov965x_set_power(ov965x, on); if (!ret && on) { - ret = ov965x_write_array(client, + ret = ov965x_write_array(ov965x, ov965x_init_regs); ov965x->apply_frame_fmt = 1; ov965x->ctrls.update = 1; @@ -609,13 +600,13 @@ static int ov965x_set_banding_filter(struct ov965x *ov965x, int value) int ret; u8 reg; - ret = ov965x_read(ov965x->client, REG_COM8, &reg); + ret = ov965x_read(ov965x, REG_COM8, &reg); if (!ret) { if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED) reg &= ~COM8_BFILT; else reg |= COM8_BFILT; - ret = ov965x_write(ov965x->client, REG_COM8, reg); + ret = ov965x_write(ov965x, REG_COM8, reg); } if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED) return 0; @@ -631,7 +622,7 @@ static int ov965x_set_banding_filter(struct ov965x *ov965x, int value) ov965x->fiv->interval.numerator; mbd = ((mbd / (light_freq * 2)) + 500) / 1000UL; - return ov965x_write(ov965x->client, REG_MBD, mbd); + return ov965x_write(ov965x, REG_MBD, mbd); } static int ov965x_set_white_balance(struct ov965x *ov965x, int awb) @@ -639,17 +630,17 @@ static int ov965x_set_white_balance(struct ov965x *ov965x, int awb) int ret; u8 reg; - ret = ov965x_read(ov965x->client, REG_COM8, &reg); + ret = ov965x_read(ov965x, REG_COM8, &reg); if (!ret) { reg = awb ? reg | REG_COM8 : reg & ~REG_COM8; - ret = ov965x_write(ov965x->client, REG_COM8, reg); + ret = ov965x_write(ov965x, REG_COM8, reg); } if (!ret && !awb) { - ret = ov965x_write(ov965x->client, REG_BLUE, + ret = ov965x_write(ov965x, REG_BLUE, ov965x->ctrls.blue_balance->val); if (ret < 0) return ret; - ret = ov965x_write(ov965x->client, REG_RED, + ret = ov965x_write(ov965x, REG_RED, ov965x->ctrls.red_balance->val); } return ret; @@ -677,14 +668,13 @@ static int ov965x_set_brightness(struct ov965x *ov965x, int val) return -EINVAL; for (i = 0; i < NUM_BR_REGS && !ret; i++) - ret = ov965x_write(ov965x->client, regs[0][i], + ret = ov965x_write(ov965x, regs[0][i], regs[val][i]); return ret; } static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) { - struct i2c_client *client = ov965x->client; struct ov965x_ctrls *ctrls = &ov965x->ctrls; int ret = 0; u8 reg; @@ -693,14 +683,14 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) * gain value in REG_VREF, REG_GAIN is not overwritten. */ if (ctrls->auto_gain->is_new) { - ret = ov965x_read(client, REG_COM8, &reg); + ret = ov965x_read(ov965x, REG_COM8, &reg); if (ret < 0) return ret; if (ctrls->auto_gain->val) reg |= COM8_AGC; else reg &= ~COM8_AGC; - ret = ov965x_write(client, REG_COM8, reg); + ret = ov965x_write(ov965x, REG_COM8, reg); if (ret < 0) return ret; } @@ -719,15 +709,15 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) rgain = (gain - ((1 << m) * 16)) / (1 << m); rgain |= (((1 << m) - 1) << 4); - ret = ov965x_write(client, REG_GAIN, rgain & 0xff); + ret = ov965x_write(ov965x, REG_GAIN, rgain & 0xff); if (ret < 0) return ret; - ret = ov965x_read(client, REG_VREF, &reg); + ret = ov965x_read(ov965x, REG_VREF, &reg); if (ret < 0) return ret; reg &= ~VREF_GAIN_MASK; reg |= (((rgain >> 8) & 0x3) << 6); - ret = ov965x_write(client, REG_VREF, reg); + ret = ov965x_write(ov965x, REG_VREF, reg); if (ret < 0) return ret; /* Return updated control's value to userspace */ @@ -742,10 +732,10 @@ static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value) u8 com14, edge; int ret; - ret = ov965x_read(ov965x->client, REG_COM14, &com14); + ret = ov965x_read(ov965x, REG_COM14, &com14); if (ret < 0) return ret; - ret = ov965x_read(ov965x->client, REG_EDGE, &edge); + ret = ov965x_read(ov965x, REG_EDGE, &edge); if (ret < 0) return ret; com14 = value ? com14 | COM14_EDGE_EN : com14 & ~COM14_EDGE_EN; @@ -756,33 +746,32 @@ static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value) } else { com14 &= ~COM14_EEF_X2; } - ret = ov965x_write(ov965x->client, REG_COM14, com14); + ret = ov965x_write(ov965x, REG_COM14, com14); if (ret < 0) return ret; edge &= ~EDGE_FACTOR_MASK; edge |= ((u8)value & 0x0f); - return ov965x_write(ov965x->client, REG_EDGE, edge); + return ov965x_write(ov965x, REG_EDGE, edge); } static int ov965x_set_exposure(struct ov965x *ov965x, int exp) { - struct i2c_client *client = ov965x->client; struct ov965x_ctrls *ctrls = &ov965x->ctrls; bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO); int ret; u8 reg; if (ctrls->auto_exp->is_new) { - ret = ov965x_read(client, REG_COM8, &reg); + ret = ov965x_read(ov965x, REG_COM8, &reg); if (ret < 0) return ret; if (auto_exposure) reg |= (COM8_AEC | COM8_AGC); else reg &= ~(COM8_AEC | COM8_AGC); - ret = ov965x_write(client, REG_COM8, reg); + ret = ov965x_write(ov965x, REG_COM8, reg); if (ret < 0) return ret; } @@ -794,12 +783,12 @@ static int ov965x_set_exposure(struct ov965x *ov965x, int exp) * Manual exposure value * [b15:b0] - AECHM (b15:b10), AECH (b9:b2), COM1 (b1:b0) */ - ret = ov965x_write(client, REG_COM1, exposure & 0x3); + ret = ov965x_write(ov965x, REG_COM1, exposure & 0x3); if (!ret) - ret = ov965x_write(client, REG_AECH, + ret = ov965x_write(ov965x, REG_AECH, (exposure >> 2) & 0xff); if (!ret) - ret = ov965x_write(client, REG_AECHM, + ret = ov965x_write(ov965x, REG_AECHM, (exposure >> 10) & 0x3f); /* Update the value to minimize rounding errors */ ctrls->exposure->val = ((exposure * ov965x->exp_row_interval) @@ -822,7 +811,7 @@ static int ov965x_set_flip(struct ov965x *ov965x) if (ov965x->ctrls.vflip->val) mvfp |= MVFP_FLIP; - return ov965x_write(ov965x->client, REG_MVFP, mvfp); + return ov965x_write(ov965x, REG_MVFP, mvfp); } #define NUM_SAT_LEVELS 5 @@ -846,7 +835,7 @@ static int ov965x_set_saturation(struct ov965x *ov965x, int val) return -EINVAL; for (i = 0; i < NUM_SAT_REGS && !ret; i++) - ret = ov965x_write(ov965x->client, addr + i, regs[val][i]); + ret = ov965x_write(ov965x, addr + i, regs[val][i]); return ret; } @@ -856,16 +845,15 @@ static int ov965x_set_test_pattern(struct ov965x *ov965x, int value) int ret; u8 reg; - ret = ov965x_read(ov965x->client, REG_COM23, &reg); + ret = ov965x_read(ov965x, REG_COM23, &reg); if (ret < 0) return ret; reg = value ? reg | COM23_TEST_MODE : reg & ~COM23_TEST_MODE; - return ov965x_write(ov965x->client, REG_COM23, reg); + return ov965x_write(ov965x, REG_COM23, reg); } static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl) { - struct i2c_client *client = ov965x->client; unsigned int exposure, gain, m; u8 reg0, reg1, reg2; int ret; @@ -877,10 +865,10 @@ static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl) case V4L2_CID_AUTOGAIN: if (!ctrl->val) return 0; - ret = ov965x_read(client, REG_GAIN, &reg0); + ret = ov965x_read(ov965x, REG_GAIN, &reg0); if (ret < 0) return ret; - ret = ov965x_read(client, REG_VREF, &reg1); + ret = ov965x_read(ov965x, REG_VREF, &reg1); if (ret < 0) return ret; gain = ((reg1 >> 6) << 8) | reg0; @@ -891,13 +879,13 @@ static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_AUTO: if (ctrl->val == V4L2_EXPOSURE_MANUAL) return 0; - ret = ov965x_read(client, REG_COM1, &reg0); + ret = ov965x_read(ov965x, REG_COM1, &reg0); if (ret < 0) return ret; - ret = ov965x_read(client, REG_AECH, &reg1); + ret = ov965x_read(ov965x, REG_AECH, &reg1); if (ret < 0) return ret; - ret = ov965x_read(client, REG_AECHM, &reg2); + ret = ov965x_read(ov965x, REG_AECHM, &reg2); if (ret < 0) return ret; exposure = ((reg2 & 0x3f) << 10) | (reg1 << 2) | @@ -1279,32 +1267,31 @@ static int ov965x_set_frame_size(struct ov965x *ov965x) int i, ret = 0; for (i = 0; ret == 0 && i < NUM_FMT_REGS; i++) - ret = ov965x_write(ov965x->client, frame_size_reg_addr[i], + ret = ov965x_write(ov965x, frame_size_reg_addr[i], ov965x->frame_size->regs[i]); return ret; } static int __ov965x_set_params(struct ov965x *ov965x) { - struct i2c_client *client = ov965x->client; struct ov965x_ctrls *ctrls = &ov965x->ctrls; int ret = 0; u8 reg; if (ov965x->apply_frame_fmt) { reg = DEF_CLKRC + ov965x->fiv->clkrc_div; - ret = ov965x_write(client, REG_CLKRC, reg); + ret = ov965x_write(ov965x, REG_CLKRC, reg); if (ret < 0) return ret; ret = ov965x_set_frame_size(ov965x); if (ret < 0) return ret; - ret = ov965x_read(client, REG_TSLB, &reg); + ret = ov965x_read(ov965x, REG_TSLB, &reg); if (ret < 0) return ret; reg &= ~TSLB_YUYV_MASK; reg |= ov965x->tslb_reg; - ret = ov965x_write(client, REG_TSLB, reg); + ret = ov965x_write(ov965x, REG_TSLB, reg); if (ret < 0) return ret; } @@ -1318,10 +1305,10 @@ static int __ov965x_set_params(struct ov965x *ov965x) * Select manual banding filter, the filter will * be enabled further if required. */ - ret = ov965x_read(client, REG_COM11, &reg); + ret = ov965x_read(ov965x, REG_COM11, &reg); if (!ret) reg |= COM11_BANDING; - ret = ov965x_write(client, REG_COM11, reg); + ret = ov965x_write(ov965x, REG_COM11, reg); if (ret < 0) return ret; /* @@ -1333,12 +1320,11 @@ static int __ov965x_set_params(struct ov965x *ov965x) static int ov965x_s_stream(struct v4l2_subdev *sd, int on) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov965x *ov965x = to_ov965x(sd); struct ov965x_ctrls *ctrls = &ov965x->ctrls; int ret = 0; - v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on); + v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on); mutex_lock(&ov965x->lock); if (ov965x->streaming == !on) { @@ -1358,7 +1344,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on) ctrls->update = 0; } if (!ret) - ret = ov965x_write(client, REG_COM2, + ret = ov965x_write(ov965x, REG_COM2, on ? 0x01 : 0x11); } if (!ret) @@ -1421,6 +1407,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x, { int ret, i; int gpios[NUM_GPIOS]; + struct device *dev = regmap_get_device(ov965x->regmap); gpios[GPIO_PWDN] = pdata->gpio_pwdn; gpios[GPIO_RST] = pdata->gpio_reset; @@ -1430,7 +1417,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x, if (!gpio_is_valid(gpio)) continue; - ret = devm_gpio_request_one(&ov965x->client->dev, gpio, + ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, "OV965X"); if (ret < 0) return ret; @@ -1446,7 +1433,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x, static int ov965x_configure_gpios(struct ov965x *ov965x) { - struct device *dev = &ov965x->client->dev; + struct device *dev = regmap_get_device(ov965x->regmap); ov965x->gpios[GPIO_PWDN] = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); @@ -1467,7 +1454,6 @@ static int ov965x_configure_gpios(struct ov965x *ov965x) static int ov965x_detect_sensor(struct v4l2_subdev *sd) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov965x *ov965x = to_ov965x(sd); u8 pid, ver; int ret; @@ -1480,9 +1466,9 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) msleep(25); /* Check sensor revision */ - ret = ov965x_read(client, REG_PID, &pid); + ret = ov965x_read(ov965x, REG_PID, &pid); if (!ret) - ret = ov965x_read(client, REG_VER, &ver); + ret = ov965x_read(ov965x, REG_VER, &ver); __ov965x_set_power(ov965x, 0); @@ -1509,12 +1495,21 @@ static int ov965x_probe(struct i2c_client *client, struct v4l2_subdev *sd; struct ov965x *ov965x; int ret; + static const struct regmap_config ov965x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xab, + }; ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL); if (!ov965x) return -ENOMEM; - ov965x->client = client; + ov965x->regmap = devm_regmap_init_sccb(client, &ov965x_regmap_config); + if (IS_ERR(ov965x->regmap)) { + dev_err(&client->dev, "Failed to allocate register map\n"); + return PTR_ERR(ov965x->regmap); + } if (pdata) { if (pdata->mclk_frequency == 0) { @@ -1527,7 +1522,7 @@ static int ov965x_probe(struct i2c_client *client, if (ret < 0) return ret; } else if (dev_fwnode(&client->dev)) { - ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL); + ov965x->clk = devm_clk_get(&client->dev, NULL); if (IS_ERR(ov965x->clk)) return PTR_ERR(ov965x->clk); ov965x->mclk_frequency = clk_get_rate(ov965x->clk); @@ -1546,7 +1541,7 @@ static int ov965x_probe(struct i2c_client *client, sd = &ov965x->sd; v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops); - strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + strscpy(sd->name, DRIVER_NAME, sizeof(sd->name)); sd->internal_ops = &ov965x_sd_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c @@ -589,7 +589,6 @@ static int rj54n1_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: sel->r.left = RJ54N1_COLUMN_SKIP; sel->r.top = RJ54N1_ROW_SKIP; sel->r.width = RJ54N1_MAX_WIDTH; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1603,7 +1603,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) const struct s5c73m3_platform_data *pdata = dev->platform_data; struct device_node *node = dev->of_node; struct device_node *node_ep; - struct v4l2_fwnode_endpoint ep; + struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; int ret; if (!node) { @@ -1644,7 +1644,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) if (ret) return ret; - if (ep.bus_type != V4L2_MBUS_CSI2) { + if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) { dev_err(dev, "unsupported bus type\n"); return -EINVAL; } @@ -1683,7 +1683,7 @@ static int s5c73m3_probe(struct i2c_client *client, v4l2_subdev_init(sd, &s5c73m3_subdev_ops); sd->owner = client->dev.driver->owner; v4l2_set_subdevdata(sd, state); - strlcpy(sd->name, "S5C73M3", sizeof(sd->name)); + strscpy(sd->name, "S5C73M3", sizeof(sd->name)); sd->internal_ops = &s5c73m3_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -1698,7 +1698,8 @@ static int s5c73m3_probe(struct i2c_client *client, return ret; v4l2_i2c_subdev_init(oif_sd, client, &oif_subdev_ops); - strcpy(oif_sd->name, "S5C73M3-OIF"); + /* Static name; NEVER use in new drivers! */ + strscpy(oif_sd->name, "S5C73M3-OIF", sizeof(oif_sd->name)); oif_sd->internal_ops = &oif_internal_ops; oif_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c @@ -954,7 +954,8 @@ static int s5k4ecgx_probe(struct i2c_client *client, sd = &priv->sd; /* Registering subdev */ v4l2_i2c_subdev_init(sd, client, &s5k4ecgx_ops); - strlcpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name)); + /* Static name; NEVER use in new drivers! */ + strscpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name)); sd->internal_ops = &s5k4ecgx_subdev_internal_ops; /* Support v4l2 sub-device user space API */ diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c @@ -766,7 +766,7 @@ static int s5k5baf_hw_set_video_bus(struct s5k5baf *state) { u16 en_pkts; - if (state->bus_type == V4L2_MBUS_CSI2) + if (state->bus_type == V4L2_MBUS_CSI2_DPHY) en_pkts = EN_PACKETS_CSI2; else en_pkts = 0; @@ -1841,7 +1841,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) { struct device_node *node = dev->of_node; struct device_node *node_ep; - struct v4l2_fwnode_endpoint ep; + struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; int ret; if (!node) { @@ -1875,7 +1875,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) state->bus_type = ep.bus_type; switch (state->bus_type) { - case V4L2_MBUS_CSI2: + case V4L2_MBUS_CSI2_DPHY: state->nlanes = ep.bus.mipi_csi2.num_data_lanes; break; case V4L2_MBUS_PARALLEL: diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c @@ -688,7 +688,7 @@ static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, * but there is nothing indicating how to switch between both * in the datasheet. For now default BT.601 interface is assumed. */ - if (bus_type == V4L2_MBUS_CSI2) + if (bus_type == V4L2_MBUS_CSI2_DPHY) cfg = nlanes; else if (bus_type != V4L2_MBUS_PARALLEL) return -EINVAL; @@ -1576,7 +1576,8 @@ static int s5k6aa_probe(struct i2c_client *client, sd = &s5k6aa->sd; v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); - strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + /* Static name; NEVER use in new drivers! */ + strscpy(sd->name, DRIVER_NAME, sizeof(sd->name)); sd->internal_ops = &s5k6aa_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c @@ -59,10 +59,16 @@ enum saa711x_model { SAA7118, }; +enum saa711x_pads { + SAA711X_PAD_IF_INPUT, + SAA711X_PAD_VID_OUT, + SAA711X_NUM_PADS +}; + struct saa711x_state { struct v4l2_subdev sd; #ifdef CONFIG_MEDIA_CONTROLLER - struct media_pad pads[DEMOD_NUM_PADS]; + struct media_pad pads[SAA711X_NUM_PADS]; #endif struct v4l2_ctrl_handler hdl; @@ -1765,7 +1771,7 @@ static int saa711x_detect_chip(struct i2c_client *client, * the lower nibble is a gm7113c. */ - strlcpy(name, "gm7113c", CHIP_VER_SIZE); + strscpy(name, "gm7113c", CHIP_VER_SIZE); if (!autodetect && strcmp(name, id->name)) return -EINVAL; @@ -1779,7 +1785,7 @@ static int saa711x_detect_chip(struct i2c_client *client, /* Check if it is a CJC7113 */ if (!memcmp(name, "1111111111111111", CHIP_VER_SIZE)) { - strlcpy(name, "cjc7113", CHIP_VER_SIZE); + strscpy(name, "cjc7113", CHIP_VER_SIZE); if (!autodetect && strcmp(name, id->name)) return -EINVAL; @@ -1825,7 +1831,7 @@ static int saa711x_probe(struct i2c_client *client, if (ident < 0) return ident; - strlcpy(client->name, name, sizeof(client->name)); + strscpy(client->name, name, sizeof(client->name)); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (state == NULL) @@ -1834,13 +1840,15 @@ static int saa711x_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &saa711x_ops); #if defined(CONFIG_MEDIA_CONTROLLER) - state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; - state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; - state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[SAA711X_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[SAA711X_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; + state->pads[SAA711X_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[SAA711X_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; sd->entity.function = MEDIA_ENT_F_ATV_DECODER; - ret = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, state->pads); + ret = media_entity_pads_init(&sd->entity, SAA711X_NUM_PADS, + state->pads); if (ret < 0) return ret; #endif diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c @@ -761,10 +761,10 @@ static int saa7127_probe(struct i2c_client *client, saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, read_result); state->ident = SAA7129; - strlcpy(client->name, "saa7129", I2C_NAME_SIZE); + strscpy(client->name, "saa7129", I2C_NAME_SIZE); } else { state->ident = SAA7127; - strlcpy(client->name, "saa7127", I2C_NAME_SIZE); + strscpy(client->name, "saa7127", I2C_NAME_SIZE); } } diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c @@ -624,7 +624,7 @@ static int smiapp_init_late_controls(struct smiapp_sensor *sensor) { unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ sensor->csi_format->compressed - sensor->compressed_min_bpp]; - unsigned int max, i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { int max_value = (1 << sensor->csi_format->width) - 1; @@ -635,8 +635,6 @@ static int smiapp_init_late_controls(struct smiapp_sensor *sensor) 0, max_value, 1, max_value); } - for (max = 0; sensor->hwcfg->op_sys_clock[max + 1]; max++); - sensor->link_freq = v4l2_ctrl_new_int_menu( &sensor->src->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), @@ -2617,9 +2615,7 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, ssd->npads = num_pads; ssd->source_pad = num_pads - 1; - snprintf(ssd->sd.name, - sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name, - name, i2c_adapter_id(client->adapter), client->addr); + v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); smiapp_get_native_size(ssd, &ssd->sink_fmt); @@ -2761,7 +2757,7 @@ static int __maybe_unused smiapp_resume(struct device *dev) static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) { struct smiapp_hwconfig *hwcfg; - struct v4l2_fwnode_endpoint *bus_cfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); u32 rotation; @@ -2775,27 +2771,33 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) if (!ep) return NULL; - bus_cfg = v4l2_fwnode_endpoint_alloc_parse(ep); - if (IS_ERR(bus_cfg)) + bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (rval == -ENXIO) { + bus_cfg = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_CCP2 }; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + } + if (rval) goto out_err; hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); if (!hwcfg) goto out_err; - switch (bus_cfg->bus_type) { - case V4L2_MBUS_CSI2: + switch (bus_cfg.bus_type) { + case V4L2_MBUS_CSI2_DPHY: hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; - hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; + hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; break; case V4L2_MBUS_CCP2: - hwcfg->csi_signalling_mode = (bus_cfg->bus.mipi_csi1.strobe) ? + hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; hwcfg->lanes = 1; break; default: - dev_err(dev, "unsupported bus %u\n", bus_cfg->bus_type); + dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); goto out_err; } @@ -2827,28 +2829,28 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) dev_dbg(dev, "nvm %d, clk %d, mode %d\n", hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); - if (!bus_cfg->nr_of_link_frequencies) { + if (!bus_cfg.nr_of_link_frequencies) { dev_warn(dev, "no link frequencies defined\n"); goto out_err; } hwcfg->op_sys_clock = devm_kcalloc( - dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, + dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); if (!hwcfg->op_sys_clock) goto out_err; - for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { - hwcfg->op_sys_clock[i] = bus_cfg->link_frequencies[i]; + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); } - v4l2_fwnode_endpoint_free(bus_cfg); + v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); return hwcfg; out_err: - v4l2_fwnode_endpoint_free(bus_cfg); + v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); return NULL; } @@ -3064,9 +3066,9 @@ static int smiapp_probe(struct i2c_client *client, if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2); - smiapp_create_subdev(sensor, sensor->binner, "binner", 2); - smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1); + smiapp_create_subdev(sensor, sensor->scaler, " scaler", 2); + smiapp_create_subdev(sensor, sensor->binner, " binner", 2); + smiapp_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o -obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o -obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o -obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o -obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o -obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o -obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o -obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o +obj-$(CONFIG_SOC_CAMERA_MT9M001) += soc_mt9m001.o +obj-$(CONFIG_SOC_CAMERA_MT9T112) += soc_mt9t112.o +obj-$(CONFIG_SOC_CAMERA_MT9V022) += soc_mt9v022.o +obj-$(CONFIG_SOC_CAMERA_OV5642) += soc_ov5642.o +obj-$(CONFIG_SOC_CAMERA_OV772X) += soc_ov772x.o +obj-$(CONFIG_SOC_CAMERA_OV9640) += soc_ov9640.o +obj-$(CONFIG_SOC_CAMERA_OV9740) += soc_ov9740.o +obj-$(CONFIG_SOC_CAMERA_RJ54N1) += soc_rj54n1cb0c.o +obj-$(CONFIG_SOC_CAMERA_TW9910) += soc_tw9910.o diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c @@ -1,758 +0,0 @@ -/* - * Driver for MT9M001 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/videodev2.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/log2.h> -#include <linux/module.h> - -#include <media/soc_camera.h> -#include <media/drv-intf/soc_mediabus.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> -#include <media/v4l2-ctrls.h> - -/* - * mt9m001 i2c address 0x5d - * The platform has to define struct i2c_board_info objects and link to them - * from struct soc_camera_host_desc - */ - -/* mt9m001 selected register addresses */ -#define MT9M001_CHIP_VERSION 0x00 -#define MT9M001_ROW_START 0x01 -#define MT9M001_COLUMN_START 0x02 -#define MT9M001_WINDOW_HEIGHT 0x03 -#define MT9M001_WINDOW_WIDTH 0x04 -#define MT9M001_HORIZONTAL_BLANKING 0x05 -#define MT9M001_VERTICAL_BLANKING 0x06 -#define MT9M001_OUTPUT_CONTROL 0x07 -#define MT9M001_SHUTTER_WIDTH 0x09 -#define MT9M001_FRAME_RESTART 0x0b -#define MT9M001_SHUTTER_DELAY 0x0c -#define MT9M001_RESET 0x0d -#define MT9M001_READ_OPTIONS1 0x1e -#define MT9M001_READ_OPTIONS2 0x20 -#define MT9M001_GLOBAL_GAIN 0x35 -#define MT9M001_CHIP_ENABLE 0xF1 - -#define MT9M001_MAX_WIDTH 1280 -#define MT9M001_MAX_HEIGHT 1024 -#define MT9M001_MIN_WIDTH 48 -#define MT9M001_MIN_HEIGHT 32 -#define MT9M001_COLUMN_SKIP 20 -#define MT9M001_ROW_SKIP 12 - -/* MT9M001 has only one fixed colorspace per pixelcode */ -struct mt9m001_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9m001_datafmt *mt9m001_find_datafmt( - u32 code, const struct mt9m001_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { - /* - * Order important: first natively supported, - * second supported with a GPIO extender - */ - {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { - /* Order important - see above */ - {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, -}; - -struct mt9m001 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/auto-exposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct v4l2_rect rect; /* Sensor window */ - struct v4l2_clk *clk; - const struct mt9m001_datafmt *fmt; - const struct mt9m001_datafmt *fmts; - int num_fmts; - unsigned int total_h; - unsigned short y_skip_top; /* Lines to skip at the top */ -}; - -static struct mt9m001 *to_mt9m001(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - return i2c_smbus_read_word_swapped(client, reg); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_swapped(client, reg, data); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int mt9m001_init(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "%s\n", __func__); - - /* - * We don't know, whether platform provides reset, issue a soft reset - * too. This returns all registers to their default values. - */ - ret = reg_write(client, MT9M001_RESET, 1); - if (!ret) - ret = reg_write(client, MT9M001_RESET, 0); - - /* Disable chip, synchronous option update */ - if (!ret) - ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); - - return ret; -} - -static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* Switch to master "normal" mode or stop sensor readout */ - if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) - return -EIO; - return 0; -} - -static int mt9m001_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_rect rect = sel->r; - const u16 hblank = 9, vblank = 25; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (mt9m001->fmts == mt9m001_colour_fmts) - /* - * Bayer format - even number of rows for simplicity, - * but let the user play with the top row. - */ - rect.height = ALIGN(rect.height, 2); - - /* Datasheet requirement: see register description */ - rect.width = ALIGN(rect.width, 2); - rect.left = ALIGN(rect.left, 2); - - soc_camera_limit_side(&rect.left, &rect.width, - MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); - - mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; - - /* Blanking and start values - default... */ - ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); - if (!ret) - ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); - - /* - * The caller provides a supported format, as verified per - * call to .set_fmt(FORMAT_TRY). - */ - if (!ret) - ret = reg_write(client, MT9M001_COLUMN_START, rect.left); - if (!ret) - ret = reg_write(client, MT9M001_ROW_START, rect.top); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_HEIGHT, - rect.height + mt9m001->y_skip_top - 1); - if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); - - if (!ret) - mt9m001->rect = rect; - - return ret; -} - -static int mt9m001_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.left = MT9M001_COLUMN_SKIP; - sel->r.top = MT9M001_ROW_SKIP; - sel->r.width = MT9M001_MAX_WIDTH; - sel->r.height = MT9M001_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = mt9m001->rect; - return 0; - default: - return -EINVAL; - } -} - -static int mt9m001_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_mbus_framefmt *mf = &format->format; - - if (format->pad) - return -EINVAL; - - mf->width = mt9m001->rect.width; - mf->height = mt9m001->rect.height; - mf->code = mt9m001->fmt->code; - mf->colorspace = mt9m001->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9m001_s_fmt(struct v4l2_subdev *sd, - const struct mt9m001_datafmt *fmt, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_subdev_selection sel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = V4L2_SEL_TGT_CROP, - .r.left = mt9m001->rect.left, - .r.top = mt9m001->rect.top, - .r.width = mf->width, - .r.height = mf->height, - }; - int ret; - - /* No support for scaling so far, just crop. TODO: use skipping */ - ret = mt9m001_set_selection(sd, NULL, &sel); - if (!ret) { - mf->width = mt9m001->rect.width; - mf->height = mt9m001->rect.height; - mt9m001->fmt = fmt; - mf->colorspace = fmt->colorspace; - } - - return ret; -} - -static int mt9m001_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - const struct mt9m001_datafmt *fmt; - - if (format->pad) - return -EINVAL; - - v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, - MT9M001_MAX_WIDTH, 1, - &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, - MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0); - - if (mt9m001->fmts == mt9m001_colour_fmts) - mf->height = ALIGN(mf->height - 1, 2); - - fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts, - mt9m001->num_fmts); - if (!fmt) { - fmt = mt9m001->fmt; - mf->code = fmt->code; - } - - mf->colorspace = fmt->colorspace; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return mt9m001_s_fmt(sd, fmt, mf); - cfg->try_fmt = *mf; - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9m001_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - reg->size = 2; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9m001_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int mt9m001_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on); -} - -static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m001 *mt9m001 = container_of(ctrl->handler, - struct mt9m001, hdl); - s32 min, max; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_AUTO: - min = mt9m001->exposure->minimum; - max = mt9m001->exposure->maximum; - mt9m001->exposure->val = - (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min; - break; - } - return 0; -} - -static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m001 *mt9m001 = container_of(ctrl->handler, - struct mt9m001, hdl); - struct v4l2_subdev *sd = &mt9m001->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_ctrl *exp = mt9m001->exposure; - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->val) - data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); - else - data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); - if (data < 0) - return -EIO; - return 0; - - case V4L2_CID_GAIN: - /* See Datasheet Table 7, Gain settings. */ - if (ctrl->val <= ctrl->default_value) { - /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = ctrl->default_value - ctrl->minimum; - data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range; - - dev_dbg(&client->dev, "Setting gain %d\n", data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } else { - /* Pack it into 1.125..15 variable step, register values 9..67 */ - /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = ctrl->maximum - ctrl->default_value - 1; - unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) * - 111 + range / 2) / range + 9; - - if (gain <= 32) - data = gain; - else if (gain <= 64) - data = ((gain - 32) * 16 + 16) / 32 + 80; - else - data = ((gain - 64) * 7 + 28) / 56 + 96; - - dev_dbg(&client->dev, "Setting gain from %d to %d\n", - reg_read(client, MT9M001_GLOBAL_GAIN), data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } - return 0; - - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_MANUAL) { - unsigned long range = exp->maximum - exp->minimum; - unsigned long shutter = ((exp->val - (s32)exp->minimum) * 1048 + - range / 2) / range + 1; - - dev_dbg(&client->dev, - "Setting shutter width from %d to %lu\n", - reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); - if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) - return -EIO; - } else { - const u16 vblank = 25; - - mt9m001->total_h = mt9m001->rect.height + - mt9m001->y_skip_top + vblank; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) - return -EIO; - } - return 0; - } - return -EINVAL; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, - struct i2c_client *client) -{ - struct mt9m001 *mt9m001 = to_mt9m001(client); - s32 data; - unsigned long flags; - int ret; - - ret = mt9m001_s_power(&mt9m001->subdev, 1); - if (ret < 0) - return ret; - - /* Enable the chip */ - data = reg_write(client, MT9M001_CHIP_ENABLE, 1); - dev_dbg(&client->dev, "write: %d\n", data); - - /* Read out the chip version register */ - data = reg_read(client, MT9M001_CHIP_VERSION); - - /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ - switch (data) { - case 0x8411: - case 0x8421: - mt9m001->fmts = mt9m001_colour_fmts; - break; - case 0x8431: - mt9m001->fmts = mt9m001_monochrome_fmts; - break; - default: - dev_err(&client->dev, - "No MT9M001 chip detected, register read %x\n", data); - ret = -ENODEV; - goto done; - } - - mt9m001->num_fmts = 0; - - /* - * This is a 10bit sensor, so by default we only allow 10bit. - * The platform may support different bus widths due to - * different routing of the data lines. - */ - if (ssdd->query_bus_param) - flags = ssdd->query_bus_param(ssdd); - else - flags = SOCAM_DATAWIDTH_10; - - if (flags & SOCAM_DATAWIDTH_10) - mt9m001->num_fmts++; - else - mt9m001->fmts++; - - if (flags & SOCAM_DATAWIDTH_8) - mt9m001->num_fmts++; - - mt9m001->fmt = &mt9m001->fmts[0]; - - dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, - data == 0x8431 ? "C12STM" : "C12ST"); - - ret = mt9m001_init(client); - if (ret < 0) { - dev_err(&client->dev, "Failed to initialise the camera\n"); - goto done; - } - - /* mt9m001_init() has reset the chip, returning registers to defaults */ - ret = v4l2_ctrl_handler_setup(&mt9m001->hdl); - -done: - mt9m001_s_power(&mt9m001->subdev, 0); - return ret; -} - -static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd) -{ - if (ssdd->free_bus) - ssdd->free_bus(ssdd); -} - -static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - *lines = mt9m001->y_skip_top; - - return 0; -} - -static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { - .g_volatile_ctrl = mt9m001_g_volatile_ctrl, - .s_ctrl = mt9m001_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9m001_g_register, - .s_register = mt9m001_s_register, -#endif - .s_power = mt9m001_s_power, -}; - -static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - if (code->pad || code->index >= mt9m001->num_fmts) - return -EINVAL; - - code->code = mt9m001->fmts[code->index].code; - return 0; -} - -static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - /* MT9M001 has all capture_format parameters fixed */ - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - const struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9m001 *mt9m001 = to_mt9m001(client); - unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; - - if (ssdd->set_bus_param) - return ssdd->set_bus_param(ssdd, 1 << (bps - 1)); - - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - return bps == 10 ? 0 : -EINVAL; -} - -static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { - .s_stream = mt9m001_s_stream, - .g_mbus_config = mt9m001_g_mbus_config, - .s_mbus_config = mt9m001_s_mbus_config, -}; - -static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { - .g_skip_top_lines = mt9m001_g_skip_top_lines, -}; - -static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { - .enum_mbus_code = mt9m001_enum_mbus_code, - .get_selection = mt9m001_get_selection, - .set_selection = mt9m001_set_selection, - .get_fmt = mt9m001_get_fmt, - .set_fmt = mt9m001_set_fmt, -}; - -static const struct v4l2_subdev_ops mt9m001_subdev_ops = { - .core = &mt9m001_subdev_core_ops, - .video = &mt9m001_subdev_video_ops, - .sensor = &mt9m001_subdev_sensor_ops, - .pad = &mt9m001_subdev_pad_ops, -}; - -static int mt9m001_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9m001 *mt9m001; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "MT9M001 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL); - if (!mt9m001) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); - v4l2_ctrl_handler_init(&mt9m001->hdl, 4); - v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, - V4L2_CID_GAIN, 0, 127, 1, 64); - mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 255, 1, 255); - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl, - &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, - V4L2_EXPOSURE_AUTO); - mt9m001->subdev.ctrl_handler = &mt9m001->hdl; - if (mt9m001->hdl.error) - return mt9m001->hdl.error; - - v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, - V4L2_EXPOSURE_MANUAL, true); - - /* Second stage probe - when a capture adapter is there */ - mt9m001->y_skip_top = 0; - mt9m001->rect.left = MT9M001_COLUMN_SKIP; - mt9m001->rect.top = MT9M001_ROW_SKIP; - mt9m001->rect.width = MT9M001_MAX_WIDTH; - mt9m001->rect.height = MT9M001_MAX_HEIGHT; - - mt9m001->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(mt9m001->clk)) { - ret = PTR_ERR(mt9m001->clk); - goto eclkget; - } - - ret = mt9m001_video_probe(ssdd, client); - if (ret) { - v4l2_clk_put(mt9m001->clk); -eclkget: - v4l2_ctrl_handler_free(&mt9m001->hdl); - } - - return ret; -} - -static int mt9m001_remove(struct i2c_client *client) -{ - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - v4l2_clk_put(mt9m001->clk); - v4l2_device_unregister_subdev(&mt9m001->subdev); - v4l2_ctrl_handler_free(&mt9m001->hdl); - mt9m001_video_remove(ssdd); - - return 0; -} - -static const struct i2c_device_id mt9m001_id[] = { - { "mt9m001", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9m001_id); - -static struct i2c_driver mt9m001_i2c_driver = { - .driver = { - .name = "mt9m001", - }, - .probe = mt9m001_probe, - .remove = mt9m001_remove, - .id_table = mt9m001_id, -}; - -module_i2c_driver(mt9m001_i2c_driver); - -MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c @@ -1,1163 +0,0 @@ -/* - * mt9t112 Camera Driver - * - * Copyright (C) 2009 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov772x driver, mt9m111 driver, - * - * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> - * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> -#include <linux/videodev2.h> - -#include <media/i2c/mt9t112.h> -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-common.h> -#include <media/v4l2-image-sizes.h> - -/* you can check PLL/clock info */ -/* #define EXT_CLOCK 24000000 */ - -/************************************************************************ - macro -************************************************************************/ -/* - * frame size - */ -#define MAX_WIDTH 2048 -#define MAX_HEIGHT 1536 - -/* - * macro of read/write - */ -#define ECHECKER(ret, x) \ - do { \ - (ret) = (x); \ - if ((ret) < 0) \ - return (ret); \ - } while (0) - -#define mt9t112_reg_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_reg_write(client, a, b)) -#define mt9t112_mcu_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) - -#define mt9t112_reg_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) -#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) - -#define mt9t112_reg_read(ret, client, a) \ - ECHECKER(ret, __mt9t112_reg_read(client, a)) - -/* - * Logical address - */ -#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) -#define VAR(id, offset) _VAR(id, offset, 0x0000) -#define VAR8(id, offset) _VAR(id, offset, 0x8000) - -/************************************************************************ - struct -************************************************************************/ -struct mt9t112_format { - u32 code; - enum v4l2_colorspace colorspace; - u16 fmt; - u16 order; -}; - -struct mt9t112_priv { - struct v4l2_subdev subdev; - struct mt9t112_platform_data *info; - struct i2c_client *client; - struct v4l2_rect frame; - struct v4l2_clk *clk; - const struct mt9t112_format *format; - int num_formats; - u32 flags; -/* for flags */ -#define INIT_DONE (1 << 0) -#define PCLK_RISING (1 << 1) -}; - -/************************************************************************ - supported format -************************************************************************/ - -static const struct mt9t112_format mt9t112_cfmts[] = { - { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 0, - }, { - .code = MEDIA_BUS_FMT_VYUY8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 1, - }, { - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 2, - }, { - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 3, - }, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 8, - .order = 2, - }, { - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 4, - .order = 2, - }, -}; - -/************************************************************************ - general function -************************************************************************/ -static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), - struct mt9t112_priv, - subdev); -} - -static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - int ret; - - command = swab16(command); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = (u8 *)&command; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 2; - msg[1].buf = buf; - - /* - * if return value of this function is < 0, - * it mean error. - * else, under 16bit is valid data. - */ - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) - return ret; - - memcpy(&ret, buf, 2); - return swab16(ret); -} - -static int __mt9t112_reg_write(const struct i2c_client *client, - u16 command, u16 data) -{ - struct i2c_msg msg; - u8 buf[4]; - int ret; - - command = swab16(command); - data = swab16(data); - - memcpy(buf + 0, &command, 2); - memcpy(buf + 2, &data, 2); - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 4; - msg.buf = buf; - - /* - * i2c_transfer return message length, - * but this function should return 0 if correct case - */ - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret >= 0) - ret = 0; - - return ret; -} - -static int __mt9t112_reg_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_reg_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_reg_write(client, command, val); -} - -/* mcu access */ -static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_read(client, 0x0990); -} - -static int __mt9t112_mcu_write(const struct i2c_client *client, - u16 command, u16 data) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_write(client, 0x0990, data); -} - -static int __mt9t112_mcu_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_mcu_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_mcu_write(client, command, val); -} - -static int mt9t112_reset(const struct i2c_client *client) -{ - int ret; - - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); - msleep(1); - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); - - return ret; -} - -#ifndef EXT_CLOCK -#define CLOCK_INFO(a, b) -#else -#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) -static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) -{ - int m, n, p1, p2, p3, p4, p5, p6, p7; - u32 vco, clk; - char *enable; - - ext /= 1000; /* kbyte order */ - - mt9t112_reg_read(n, client, 0x0012); - p1 = n & 0x000f; - n = n >> 4; - p2 = n & 0x000f; - n = n >> 4; - p3 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002a); - p4 = n & 0x000f; - n = n >> 4; - p5 = n & 0x000f; - n = n >> 4; - p6 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002c); - p7 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x0010); - m = n & 0x00ff; - n = (n >> 8) & 0x003f; - - enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; - dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); - - vco = 2 * m * ext / (n+1); - enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; - dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); - - clk = vco / (p1+1) / (p2+1); - enable = (96000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); - - clk = vco / (p3+1); - enable = (768000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); - - clk = vco / (p6+1); - enable = (96000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); - - clk = vco / (p5+1); - enable = (54000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); - - clk = vco / (p4+1); - enable = (70000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); - - clk = vco / (p7+1); - dev_dbg(&client->dev, "External sensor : %10u K\n", clk); - - clk = ext / (n+1); - enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; - dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); - - return 0; -} -#endif - -static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) -{ - soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); - soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); -} - -static int mt9t112_set_a_frame_size(const struct i2c_client *client, - u16 width, - u16 height) -{ - int ret; - u16 wstart = (MAX_WIDTH - width) / 2; - u16 hstart = (MAX_HEIGHT - height) / 2; - - /* (Context A) Image Width/Height */ - mt9t112_mcu_write(ret, client, VAR(26, 0), width); - mt9t112_mcu_write(ret, client, VAR(26, 2), height); - - /* (Context A) Output Width/Height */ - mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); - mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); - - /* (Context A) Start Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); - - /* (Context A) End Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - return ret; -} - -static int mt9t112_set_pll_dividers(const struct i2c_client *client, - u8 m, u8 n, - u8 p1, u8 p2, u8 p3, - u8 p4, u8 p5, u8 p6, - u8 p7) -{ - int ret; - u16 val; - - /* N/M */ - val = (n << 8) | - (m << 0); - mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); - - /* P1/P2/P3 */ - val = ((p3 & 0x0F) << 8) | - ((p2 & 0x0F) << 4) | - ((p1 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); - - /* P4/P5/P6 */ - val = (0x7 << 12) | - ((p6 & 0x0F) << 8) | - ((p5 & 0x0F) << 4) | - ((p4 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); - - /* P7 */ - val = (0x1 << 12) | - ((p7 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); - - return ret; -} - -static int mt9t112_init_pll(const struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - int data, i, ret; - - mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); - - /* PLL control: BYPASS PLL = 8517 */ - mt9t112_reg_write(ret, client, 0x0014, 0x2145); - - /* Replace these registers when new timing parameters are generated */ - mt9t112_set_pll_dividers(client, - priv->info->divider.m, - priv->info->divider.n, - priv->info->divider.p1, - priv->info->divider.p2, - priv->info->divider.p3, - priv->info->divider.p4, - priv->info->divider.p5, - priv->info->divider.p6, - priv->info->divider.p7); - - /* - * TEST_BYPASS on - * PLL_ENABLE on - * SEL_LOCK_DET on - * TEST_BYPASS off - */ - mt9t112_reg_write(ret, client, 0x0014, 0x2525); - mt9t112_reg_write(ret, client, 0x0014, 0x2527); - mt9t112_reg_write(ret, client, 0x0014, 0x3427); - mt9t112_reg_write(ret, client, 0x0014, 0x3027); - - mdelay(10); - - /* - * PLL_BYPASS off - * Reference clock count - * I2C Master Clock Divider - */ - mt9t112_reg_write(ret, client, 0x0014, 0x3046); - mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */ - mt9t112_reg_write(ret, client, 0x0022, 0x0190); - mt9t112_reg_write(ret, client, 0x3B84, 0x0212); - - /* External sensor clock is PLL bypass */ - mt9t112_reg_write(ret, client, 0x002E, 0x0500); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); - mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); - - /* MCU disabled */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); - - /* out of standby */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); - - mdelay(50); - - /* - * Standby Workaround - * Disable Secondary I2C Pads - */ - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - - /* poll to verify out of standby. Must Poll this bit */ - for (i = 0; i < 100; i++) { - mt9t112_reg_read(data, client, 0x0018); - if (!(0x4000 & data)) - break; - - mdelay(10); - } - - return ret; -} - -static int mt9t112_init_setting(const struct i2c_client *client) -{ - - int ret; - - /* Adaptive Output Clock (A) */ - mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); - - /* Read Mode (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); - - /* Fine Correction (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); - - /* Fine IT Min (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); - - /* Fine IT Max Margin (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); - - /* Base Frame Lines (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); - - /* Min Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); - - /* Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); - - /* Adaptive Output Clock (B) */ - mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); - - /* Row Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); - - /* Column Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); - - /* Row End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); - - /* Column End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); - - /* Fine Correction (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); - - /* Fine IT Min (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); - - /* Fine IT Max Margin (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); - - /* Base Frame Lines (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); - - /* Min Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); - - /* Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); - - /* - * Flicker Dectection registers - * This section should be replaced whenever new Timing file is generated - * All the following registers need to be replaced - * Following registers are generated from Register Wizard but user can - * modify them. For detail see auto flicker detection tuning - */ - - /* FD_FDPERIOD_SELECT */ - mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); - - /* PRI_B_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); - - /* PRI_A_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); - - /* - * AFD range detection tuning registers - */ - - /* search_f1_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); - - /* search_f2_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); - - /* search_f1_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); - - /* search_f2_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); - - /* period_50Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); - - /* secret register by aptina */ - /* period_50Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); - - /* period_60Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); - - /* secret register by aptina */ - /* period_60Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); - - /* period_50Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); - - /* secret register by aptina */ - /* period_50Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); - - /* period_60Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); - - /* secret register by aptina */ - /* period_60Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); - - /* FD Mode */ - mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); - - /* Stat_min */ - mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); - - /* Stat_max */ - mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); - - /* Min_amplitude */ - mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); - - /* RX FIFO Watermark (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); - - /* RX FIFO Watermark (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); - - /* MCLK: 16MHz - * PCLK: 73MHz - * CorePixCLK: 36.5 MHz - */ - mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); - mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); - - mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); - - return ret; -} - -static int mt9t112_auto_focus_setting(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); - mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_reg_write(ret, client, 0x0614, 0x0000); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); - mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); - mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); - mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); - mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); - mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - - return ret; -} - -static int mt9t112_auto_focus_trigger(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); - - return ret; -} - -static int mt9t112_init_camera(const struct i2c_client *client) -{ - int ret; - - ECHECKER(ret, mt9t112_reset(client)); - - ECHECKER(ret, mt9t112_init_pll(client)); - - ECHECKER(ret, mt9t112_init_setting(client)); - - ECHECKER(ret, mt9t112_auto_focus_setting(client)); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); - - /* Analog setting B */ - mt9t112_reg_write(ret, client, 0x3084, 0x2409); - mt9t112_reg_write(ret, client, 0x3092, 0x0A49); - mt9t112_reg_write(ret, client, 0x3094, 0x4949); - mt9t112_reg_write(ret, client, 0x3096, 0x4950); - - /* - * Disable adaptive clock - * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR - * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR - */ - mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); - mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); - - /* Configure STatus in Status_before_length Format and enable header */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); - - /* Enable JPEG in context B */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); - - /* Disable Dac_TXLO */ - mt9t112_reg_write(ret, client, 0x316C, 0x350F); - - /* Set max slew rates */ - mt9t112_reg_write(ret, client, 0x1E, 0x777); - - return ret; -} - -/************************************************************************ - v4l2_subdev_core_ops -************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t112_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 2; - mt9t112_reg_read(ret, client, reg->reg); - - reg->val = (__u64)ret; - - return 0; -} - -static int mt9t112_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mt9t112_reg_write(ret, client, reg->reg, reg->val); - - return ret; -} -#endif - -static int mt9t112_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9t112_priv *priv = to_mt9t112(client); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9t112_g_register, - .s_register = mt9t112_s_register, -#endif - .s_power = mt9t112_s_power, -}; - - -/************************************************************************ - v4l2_subdev_video_ops -************************************************************************/ -static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - int ret = 0; - - if (!enable) { - /* FIXME - * - * If user selected large output size, - * and used it long time, - * mt9t112 camera will be very warm. - * - * But current driver can not stop mt9t112 camera. - * So, set small size here to solve this problem. - */ - mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); - return ret; - } - - if (!(priv->flags & INIT_DONE)) { - u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; - - ECHECKER(ret, mt9t112_init_camera(client)); - - /* Invert PCLK (Data sampled on falling edge of pixclk) */ - mt9t112_reg_write(ret, client, 0x3C20, param); - - mdelay(5); - - priv->flags |= INIT_DONE; - } - - mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); - mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_set_a_frame_size(client, - priv->frame.width, - priv->frame.height); - - ECHECKER(ret, mt9t112_auto_focus_trigger(client)); - - dev_dbg(&client->dev, "format : %d\n", priv->format->code); - dev_dbg(&client->dev, "size : %d x %d\n", - priv->frame.width, - priv->frame.height); - - CLOCK_INFO(client, EXT_CLOCK); - - return ret; -} - -static int mt9t112_set_params(struct mt9t112_priv *priv, - const struct v4l2_rect *rect, - u32 code) -{ - int i; - - /* - * get color format - */ - for (i = 0; i < priv->num_formats; i++) - if (mt9t112_cfmts[i].code == code) - break; - - if (i == priv->num_formats) - return -EINVAL; - - priv->frame = *rect; - - /* - * frame size check - */ - mt9t112_frame_check(&priv->frame.width, &priv->frame.height, - &priv->frame.left, &priv->frame.top); - - priv->format = mt9t112_cfmts + i; - - return 0; -} - -static int mt9t112_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = MAX_WIDTH; - sel->r.height = MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = VGA_WIDTH; - sel->r.height = VGA_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = priv->frame; - return 0; - default: - return -EINVAL; - } -} - -static int mt9t112_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - const struct v4l2_rect *rect = &sel->r; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - return mt9t112_set_params(priv, rect, priv->format->code); -} - -static int mt9t112_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (format->pad) - return -EINVAL; - - mf->width = priv->frame.width; - mf->height = priv->frame.height; - mf->colorspace = priv->format->colorspace; - mf->code = priv->format->code; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9t112_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - struct v4l2_rect rect = { - .width = mf->width, - .height = mf->height, - .left = priv->frame.left, - .top = priv->frame.top, - }; - int ret; - - ret = mt9t112_set_params(priv, &rect, mf->code); - - if (!ret) - mf->colorspace = priv->format->colorspace; - - return ret; -} - -static int mt9t112_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - unsigned int top, left; - int i; - - if (format->pad) - return -EINVAL; - - for (i = 0; i < priv->num_formats; i++) - if (mt9t112_cfmts[i].code == mf->code) - break; - - if (i == priv->num_formats) { - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_JPEG; - } else { - mf->colorspace = mt9t112_cfmts[i].colorspace; - } - - mt9t112_frame_check(&mf->width, &mf->height, &left, &top); - - mf->field = V4L2_FIELD_NONE; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return mt9t112_s_fmt(sd, mf); - cfg->try_fmt = *mf; - return 0; -} - -static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (code->pad || code->index >= priv->num_formats) - return -EINVAL; - - code->code = mt9t112_cfmts[code->index].code; - - return 0; -} - -static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) - priv->flags |= PCLK_RISING; - - return 0; -} - -static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { - .s_stream = mt9t112_s_stream, - .g_mbus_config = mt9t112_g_mbus_config, - .s_mbus_config = mt9t112_s_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { - .enum_mbus_code = mt9t112_enum_mbus_code, - .get_selection = mt9t112_get_selection, - .set_selection = mt9t112_set_selection, - .get_fmt = mt9t112_get_fmt, - .set_fmt = mt9t112_set_fmt, -}; - -/************************************************************************ - i2c driver -************************************************************************/ -static const struct v4l2_subdev_ops mt9t112_subdev_ops = { - .core = &mt9t112_subdev_core_ops, - .video = &mt9t112_subdev_video_ops, - .pad = &mt9t112_subdev_pad_ops, -}; - -static int mt9t112_camera_probe(struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - const char *devname; - int chipid; - int ret; - - ret = mt9t112_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show chip ID - */ - mt9t112_reg_read(chipid, client, 0x0000); - - switch (chipid) { - case 0x2680: - devname = "mt9t111"; - priv->num_formats = 1; - break; - case 0x2682: - devname = "mt9t112"; - priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); - break; - default: - dev_err(&client->dev, "Product ID error %04x\n", chipid); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); - -done: - mt9t112_s_power(&priv->subdev, 0); - return ret; -} - -static int mt9t112_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9t112_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct v4l2_rect rect = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .left = (MAX_WIDTH - VGA_WIDTH) / 2, - .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, - }; - int ret; - - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "mt9t112: missing platform data!\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = ssdd->drv_priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = mt9t112_camera_probe(client); - - /* Cannot fail: using the default supported pixel code */ - if (!ret) - mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8); - else - v4l2_clk_put(priv->clk); - - return ret; -} - -static int mt9t112_remove(struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - - v4l2_clk_put(priv->clk); - return 0; -} - -static const struct i2c_device_id mt9t112_id[] = { - { "mt9t112", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9t112_id); - -static struct i2c_driver mt9t112_i2c_driver = { - .driver = { - .name = "mt9t112", - }, - .probe = mt9t112_probe, - .remove = mt9t112_remove, - .id_table = mt9t112_id, -}; - -module_i2c_driver(mt9t112_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c @@ -1,1013 +0,0 @@ -/* - * Driver for MT9V022 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/videodev2.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/log2.h> -#include <linux/module.h> - -#include <media/i2c/mt9v022.h> -#include <media/soc_camera.h> -#include <media/drv-intf/soc_mediabus.h> -#include <media/v4l2-subdev.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-ctrls.h> - -/* - * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c - * The platform has to define struct i2c_board_info objects and link to them - * from struct soc_camera_host_desc - */ - -static char *sensor_type; -module_param(sensor_type, charp, S_IRUGO); -MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); - -/* mt9v022 selected register addresses */ -#define MT9V022_CHIP_VERSION 0x00 -#define MT9V022_COLUMN_START 0x01 -#define MT9V022_ROW_START 0x02 -#define MT9V022_WINDOW_HEIGHT 0x03 -#define MT9V022_WINDOW_WIDTH 0x04 -#define MT9V022_HORIZONTAL_BLANKING 0x05 -#define MT9V022_VERTICAL_BLANKING 0x06 -#define MT9V022_CHIP_CONTROL 0x07 -#define MT9V022_SHUTTER_WIDTH1 0x08 -#define MT9V022_SHUTTER_WIDTH2 0x09 -#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a -#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b -#define MT9V022_RESET 0x0c -#define MT9V022_READ_MODE 0x0d -#define MT9V022_MONITOR_MODE 0x0e -#define MT9V022_PIXEL_OPERATION_MODE 0x0f -#define MT9V022_LED_OUT_CONTROL 0x1b -#define MT9V022_ADC_MODE_CONTROL 0x1c -#define MT9V022_REG32 0x20 -#define MT9V022_ANALOG_GAIN 0x35 -#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 -#define MT9V022_PIXCLK_FV_LV 0x74 -#define MT9V022_DIGITAL_TEST_PATTERN 0x7f -#define MT9V022_AEC_AGC_ENABLE 0xAF -#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD - -/* mt9v024 partial list register addresses changes with respect to mt9v022 */ -#define MT9V024_PIXCLK_FV_LV 0x72 -#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD - -/* Progressive scan, master, defaults */ -#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 - -#define MT9V022_MAX_WIDTH 752 -#define MT9V022_MAX_HEIGHT 480 -#define MT9V022_MIN_WIDTH 48 -#define MT9V022_MIN_HEIGHT 32 -#define MT9V022_COLUMN_SKIP 1 -#define MT9V022_ROW_SKIP 4 - -#define MT9V022_HORIZONTAL_BLANKING_MIN 43 -#define MT9V022_HORIZONTAL_BLANKING_MAX 1023 -#define MT9V022_HORIZONTAL_BLANKING_DEF 94 -#define MT9V022_VERTICAL_BLANKING_MIN 2 -#define MT9V022_VERTICAL_BLANKING_MAX 3000 -#define MT9V022_VERTICAL_BLANKING_DEF 45 - -#define is_mt9v022_rev3(id) (id == 0x1313) -#define is_mt9v024(id) (id == 0x1324) - -/* MT9V022 has only one fixed colorspace per pixelcode */ -struct mt9v022_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9v022_datafmt *mt9v022_find_datafmt( - u32 code, const struct mt9v022_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { - /* - * Order important: first natively supported, - * second supported with a GPIO extender - */ - {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { - /* Order important - see above */ - {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, -}; - -/* only registers with different addresses on different mt9v02x sensors */ -struct mt9v02x_register { - u8 max_total_shutter_width; - u8 pixclk_fv_lv; -}; - -static const struct mt9v02x_register mt9v022_register = { - .max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH, - .pixclk_fv_lv = MT9V022_PIXCLK_FV_LV, -}; - -static const struct mt9v02x_register mt9v024_register = { - .max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH, - .pixclk_fv_lv = MT9V024_PIXCLK_FV_LV, -}; - -enum mt9v022_model { - MT9V022IX7ATM, - MT9V022IX7ATC, -}; - -struct mt9v022 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/auto-exposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct { - /* gain/auto-gain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *vblank; - struct v4l2_rect rect; /* Sensor window */ - struct v4l2_clk *clk; - const struct mt9v022_datafmt *fmt; - const struct mt9v022_datafmt *fmts; - const struct mt9v02x_register *reg; - int num_fmts; - enum mt9v022_model model; - u16 chip_control; - u16 chip_version; - unsigned short y_skip_top; /* Lines to skip at the top */ -}; - -static struct mt9v022 *to_mt9v022(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - return i2c_smbus_read_word_swapped(client, reg); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_swapped(client, reg, data); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int mt9v022_init(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - int ret; - - /* - * Almost the default mode: master, parallel, simultaneous, and an - * undocumented bit 0x200, which is present in table 7, but not in 8, - * plus snapshot mode to disable scan for now - */ - mt9v022->chip_control |= 0x10; - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (!ret) - ret = reg_write(client, MT9V022_READ_MODE, 0x300); - - /* All defaults */ - if (!ret) - /* AEC, AGC on */ - ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); - if (!ret) - ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); - if (!ret) - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); - if (!ret) - ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480); - if (!ret) - /* default - auto */ - ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); - if (!ret) - ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); - if (!ret) - return v4l2_ctrl_handler_setup(&mt9v022->hdl); - - return ret; -} - -static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (enable) { - /* Switch to master "normal" mode */ - mt9v022->chip_control &= ~0x10; - if (is_mt9v022_rev3(mt9v022->chip_version) || - is_mt9v024(mt9v022->chip_version)) { - /* - * Unset snapshot mode specific settings: clear bit 9 - * and bit 2 in reg. 0x20 when in normal mode. - */ - if (reg_clear(client, MT9V022_REG32, 0x204)) - return -EIO; - } - } else { - /* Switch to snapshot mode */ - mt9v022->chip_control |= 0x10; - if (is_mt9v022_rev3(mt9v022->chip_version) || - is_mt9v024(mt9v022->chip_version)) { - /* - * Required settings for snapshot mode: set bit 9 - * (RST enable) and bit 2 (CR enable) in reg. 0x20 - * See TechNote TN0960 or TN-09-225. - */ - if (reg_set(client, MT9V022_REG32, 0x204))