summaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/Kconfig10
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c19
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c4
-rw-r--r--drivers/media/common/siano/sms-cards.c8
-rw-r--r--drivers/media/common/siano/sms-cards.h3
-rw-r--r--drivers/media/common/siano/smscoreapi.c164
-rw-r--r--drivers/media/common/siano/smscoreapi.h32
-rw-r--r--drivers/media/common/siano/smsdvb-debugfs.c6
-rw-r--r--drivers/media/common/siano/smsdvb-main.c74
-rw-r--r--drivers/media/common/siano/smsir.c18
-rw-r--r--drivers/media/dvb-core/dmxdev.c11
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h3
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c30
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c124
-rw-r--r--drivers/media/dvb-core/dvb_net.c6
-rw-r--r--drivers/media/dvb-core/dvbdev.c144
-rw-r--r--drivers/media/dvb-core/dvbdev.h27
-rw-r--r--drivers/media/dvb-frontends/Kconfig8
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/a8293.h2
-rw-r--r--drivers/media/dvb-frontends/af9013.h2
-rw-r--r--drivers/media/dvb-frontends/atbm8830.h2
-rw-r--r--drivers/media/dvb-frontends/au8522.h2
-rw-r--r--drivers/media/dvb-frontends/bcm3510.h2
-rw-r--r--drivers/media/dvb-frontends/cx22700.h2
-rw-r--r--drivers/media/dvb-frontends/cx22702.h2
-rw-r--r--drivers/media/dvb-frontends/cx24110.h2
-rw-r--r--drivers/media/dvb-frontends/cx24113.h2
-rw-r--r--drivers/media/dvb-frontends/cx24116.h2
-rw-r--r--drivers/media/dvb-frontends/cx24117.h2
-rw-r--r--drivers/media/dvb-frontends/cx24123.h2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r.h2
-rw-r--r--drivers/media/dvb-frontends/dib0070.h2
-rw-r--r--drivers/media/dvb-frontends/dib0090.h2
-rw-r--r--drivers/media/dvb-frontends/dib3000.h2
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.h2
-rw-r--r--drivers/media/dvb-frontends/dib7000m.h2
-rw-r--r--drivers/media/dvb-frontends/dib7000p.h2
-rw-r--r--drivers/media/dvb-frontends/dib8000.h2
-rw-r--r--drivers/media/dvb-frontends/dib9000.h2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx39xxj.h2
-rw-r--r--drivers/media/dvb-frontends/drxd.h2
-rw-r--r--drivers/media/dvb-frontends/drxk.h2
-rw-r--r--drivers/media/dvb-frontends/ds3000.h2
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.h2
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.h2
-rw-r--r--drivers/media/dvb-frontends/ec100.h2
-rw-r--r--drivers/media/dvb-frontends/hd29l2.h2
-rw-r--r--drivers/media/dvb-frontends/isl6405.h2
-rw-r--r--drivers/media/dvb-frontends/isl6421.h2
-rw-r--r--drivers/media/dvb-frontends/isl6423.h2
-rw-r--r--drivers/media/dvb-frontends/itd1000.h2
-rw-r--r--drivers/media/dvb-frontends/ix2505v.h2
-rw-r--r--drivers/media/dvb-frontends/l64781.h2
-rw-r--r--drivers/media/dvb-frontends/lg2160.h2
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.h2
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c2144
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.h74
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.h2
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.h2
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.h2
-rw-r--r--drivers/media/dvb-frontends/lnbh24.h2
-rw-r--r--drivers/media/dvb-frontends/lnbp21.h2
-rw-r--r--drivers/media/dvb-frontends/lnbp22.h2
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.h2
-rw-r--r--drivers/media/dvb-frontends/mb86a16.h2
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h2
-rw-r--r--drivers/media/dvb-frontends/mn88472.h12
-rw-r--r--drivers/media/dvb-frontends/mn88473.h6
-rw-r--r--drivers/media/dvb-frontends/mt312.h2
-rw-r--r--drivers/media/dvb-frontends/mt352.h2
-rw-r--r--drivers/media/dvb-frontends/nxt200x.h2
-rw-r--r--drivers/media/dvb-frontends/nxt6000.h2
-rw-r--r--drivers/media/dvb-frontends/or51132.h2
-rw-r--r--drivers/media/dvb-frontends/or51211.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c2
-rw-r--r--drivers/media/dvb-frontends/s5h1409.h2
-rw-r--r--drivers/media/dvb-frontends/s5h1411.h2
-rw-r--r--drivers/media/dvb-frontends/s5h1420.h2
-rw-r--r--drivers/media/dvb-frontends/s5h1432.h2
-rw-r--r--drivers/media/dvb-frontends/s921.h2
-rw-r--r--drivers/media/dvb-frontends/si2165.c2
-rw-r--r--drivers/media/dvb-frontends/si2165.h2
-rw-r--r--drivers/media/dvb-frontends/si21xx.h2
-rw-r--r--drivers/media/dvb-frontends/sp2.c5
-rw-r--r--drivers/media/dvb-frontends/sp8870.h2
-rw-r--r--drivers/media/dvb-frontends/sp887x.h2
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.h2
-rw-r--r--drivers/media/dvb-frontends/stb6000.h2
-rw-r--r--drivers/media/dvb-frontends/stb6100.h2
-rw-r--r--drivers/media/dvb-frontends/stv0288.h2
-rw-r--r--drivers/media/dvb-frontends/stv0297.h2
-rw-r--r--drivers/media/dvb-frontends/stv0299.h2
-rw-r--r--drivers/media/dvb-frontends/stv0367.h2
-rw-r--r--drivers/media/dvb-frontends/stv0900.h2
-rw-r--r--drivers/media/dvb-frontends/stv090x.h2
-rw-r--r--drivers/media/dvb-frontends/stv6110.h2
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h2
-rw-r--r--drivers/media/dvb-frontends/tda1002x.h4
-rw-r--r--drivers/media/dvb-frontends/tda10048.h2
-rw-r--r--drivers/media/dvb-frontends/tda1004x.h2
-rw-r--r--drivers/media/dvb-frontends/tda10071.h2
-rw-r--r--drivers/media/dvb-frontends/tda10086.h2
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.h2
-rw-r--r--drivers/media/dvb-frontends/tda665x.h2
-rw-r--r--drivers/media/dvb-frontends/tda8083.h2
-rw-r--r--drivers/media/dvb-frontends/tda8261.h2
-rw-r--r--drivers/media/dvb-frontends/tda826x.h2
-rw-r--r--drivers/media/dvb-frontends/ts2020.c302
-rw-r--r--drivers/media/dvb-frontends/ts2020.h27
-rw-r--r--drivers/media/dvb-frontends/tua6100.h2
-rw-r--r--drivers/media/dvb-frontends/ves1820.h2
-rw-r--r--drivers/media/dvb-frontends/ves1x93.h2
-rw-r--r--drivers/media/dvb-frontends/zl10036.h2
-rw-r--r--drivers/media/dvb-frontends/zl10039.h2
-rw-r--r--drivers/media/dvb-frontends/zl10353.h2
-rw-r--r--drivers/media/i2c/Kconfig11
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/ad9389b.c10
-rw-r--r--drivers/media/i2c/adv7180.c10
-rw-r--r--drivers/media/i2c/adv7343.c1
-rw-r--r--drivers/media/i2c/adv7511.c26
-rw-r--r--drivers/media/i2c/adv7604.c945
-rw-r--r--drivers/media/i2c/adv7842.c5
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c30
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.h11
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c16
-rw-r--r--drivers/media/i2c/mt9m032.c34
-rw-r--r--drivers/media/i2c/mt9p031.c81
-rw-r--r--drivers/media/i2c/mt9t001.c36
-rw-r--r--drivers/media/i2c/mt9v032.c115
-rw-r--r--drivers/media/i2c/noon010pc30.c17
-rw-r--r--drivers/media/i2c/ov2659.c1509
-rw-r--r--drivers/media/i2c/ov7670.c37
-rw-r--r--drivers/media/i2c/ov9650.c16
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c72
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c2
-rw-r--r--drivers/media/i2c/s5k4ecgx.c16
-rw-r--r--drivers/media/i2c/s5k5baf.c40
-rw-r--r--drivers/media/i2c/s5k6a3.c18
-rw-r--r--drivers/media/i2c/s5k6aa.c34
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c118
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c1
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c125
-rw-r--r--drivers/media/i2c/ths7303.c4
-rw-r--r--drivers/media/i2c/ths8200.c1
-rw-r--r--drivers/media/i2c/tvp514x.c13
-rw-r--r--drivers/media/i2c/tvp7002.c15
-rw-r--r--drivers/media/mmc/siano/smssdio.c17
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c73
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h6
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c2
-rw-r--r--drivers/media/pci/cx18/cx18-driver.h3
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.c27
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c58
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c66
-rw-r--r--drivers/media/pci/cx18/cx18-streams.h2
-rw-r--r--drivers/media/pci/cx23885/Kconfig1
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c3
-rw-r--r--drivers/media/pci/cx23885/altera-ci.h2
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c1
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c30
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c1
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c22
-rw-r--r--drivers/media/pci/cx88/cx88-core.c18
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c3
-rw-r--r--drivers/media/pci/cx88/cx88-video.c61
-rw-r--r--drivers/media/pci/cx88/cx88.h17
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c159
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.c8
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.c113
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.h2
-rw-r--r--drivers/media/pci/meye/meye.c21
-rw-r--r--drivers/media/pci/meye/meye.h2
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c2
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c2
-rw-r--r--drivers/media/pci/saa7146/mxb.c4
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c4
-rw-r--r--drivers/media/pci/smipcie/Kconfig2
-rw-r--r--drivers/media/pci/smipcie/smipcie.c12
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c35
-rw-r--r--drivers/media/pci/ttpci/av7110.h4
-rw-r--r--drivers/media/pci/ttpci/budget-av.c2
-rw-r--r--drivers/media/platform/Kconfig4
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/am437x/Kconfig2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c59
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.h3
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c348
-rw-r--r--drivers/media/platform/coda/Makefile2
-rw-r--r--drivers/media/platform/coda/coda-bit.c205
-rw-r--r--drivers/media/platform/coda/coda-common.c113
-rw-r--r--drivers/media/platform/coda/coda-jpeg.c1
-rw-r--r--drivers/media/platform/coda/coda.h18
-rw-r--r--drivers/media/platform/coda/trace.h203
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c26
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c52
-rw-r--r--drivers/media/platform/davinci/vpif_capture.h2
-rw-r--r--drivers/media/platform/davinci/vpif_display.c49
-rw-r--r--drivers/media/platform/davinci/vpif_display.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c22
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c28
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c33
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c16
-rw-r--r--drivers/media/platform/m2m-deinterlace.c21
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c48
-rw-r--r--drivers/media/platform/omap/omap_vout.c2
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c1
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.h4
-rw-r--r--drivers/media/platform/omap3isp/isp.c563
-rw-r--r--drivers/media/platform/omap3isp/isp.h43
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c112
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c68
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c56
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c48
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c1
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c1
-rw-r--r--drivers/media/platform/omap3isp/isphist.c127
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c70
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c80
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c2
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h5
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c20
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c18
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c63
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h12
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c32
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h3
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c7
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c2
-rw-r--r--drivers/media/platform/sh_vou.c30
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c15
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c1
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c108
-rw-r--r--drivers/media/platform/via-camera.c15
-rw-r--r--drivers/media/platform/vim2m.c23
-rw-r--r--drivers/media/platform/vivid/vivid-core.c93
-rw-r--r--drivers/media/platform/vivid/vivid-core.h8
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c2
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c125
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c66
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c1082
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h112
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c180
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c378
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c85
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c42
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c16
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h4
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c18
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c22
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c22
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c37
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h12
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c30
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c30
-rw-r--r--drivers/media/platform/xilinx/Kconfig23
-rw-r--r--drivers/media/platform/xilinx/Makefile5
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c766
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.h109
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c931
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c323
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h238
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c669
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.h49
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.c380
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.h42
-rw-r--r--drivers/media/radio/radio-wl1273.c27
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c14
-rw-r--r--drivers/media/radio/si4713/si4713.c18
-rw-r--r--drivers/media/radio/wl128x/Kconfig2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c28
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c31
-rw-r--r--drivers/media/rc/img-ir/img-ir.h2
-rw-r--r--drivers/media/rc/ir-hix5hd2.c8
-rw-r--r--drivers/media/tuners/Kconfig8
-rw-r--r--drivers/media/tuners/Makefile1
-rw-r--r--drivers/media/tuners/fc0011.h2
-rw-r--r--drivers/media/tuners/fc0012.h2
-rw-r--r--drivers/media/tuners/fc0013.h2
-rw-r--r--drivers/media/tuners/fc2580.h2
-rw-r--r--drivers/media/tuners/m88ts2022.c579
-rw-r--r--drivers/media/tuners/m88ts2022.h54
-rw-r--r--drivers/media/tuners/m88ts2022_priv.h35
-rw-r--r--drivers/media/tuners/max2165.h2
-rw-r--r--drivers/media/tuners/mc44s803.h2
-rw-r--r--drivers/media/tuners/mt2060.h2
-rw-r--r--drivers/media/tuners/mt2063.h2
-rw-r--r--drivers/media/tuners/mt20xx.h2
-rw-r--r--drivers/media/tuners/mt2131.h2
-rw-r--r--drivers/media/tuners/mt2266.h2
-rw-r--r--drivers/media/tuners/mxl5005s.h2
-rw-r--r--drivers/media/tuners/mxl5007t.h2
-rw-r--r--drivers/media/tuners/qt1010.h2
-rw-r--r--drivers/media/tuners/r820t.c29
-rw-r--r--drivers/media/tuners/r820t.h2
-rw-r--r--drivers/media/tuners/si2157.c25
-rw-r--r--drivers/media/tuners/si2157_priv.h1
-rw-r--r--drivers/media/tuners/tda18218.h2
-rw-r--r--drivers/media/tuners/tda18271.h2
-rw-r--r--drivers/media/tuners/tda827x.h2
-rw-r--r--drivers/media/tuners/tda8290.h2
-rw-r--r--drivers/media/tuners/tda9887.h2
-rw-r--r--drivers/media/tuners/tea5761.h2
-rw-r--r--drivers/media/tuners/tea5767.h2
-rw-r--r--drivers/media/tuners/tua9001.h2
-rw-r--r--drivers/media/tuners/tuner-simple.h2
-rw-r--r--drivers/media/tuners/tuner-xc2028.h2
-rw-r--r--drivers/media/tuners/xc4000.h2
-rw-r--r--drivers/media/tuners/xc5000.c5
-rw-r--r--drivers/media/tuners/xc5000.h2
-rw-r--r--drivers/media/usb/au0828/au0828-video.c104
-rw-r--r--drivers/media/usb/au0828/au0828.h4
-rw-r--r--drivers/media/usb/cx231xx/Kconfig1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c33
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c144
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c13
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c71
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c176
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h21
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h1
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c58
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c26
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c8
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig5
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c155
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c3
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c3
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-dvb.c69
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c192
-rw-r--r--drivers/media/usb/em28xx/Kconfig2
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c13
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c14
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c119
-rw-r--r--drivers/media/usb/em28xx/em28xx.h7
-rw-r--r--drivers/media/usb/gspca/ov534.c11
-rw-r--r--drivers/media/usb/gspca/topro.c4
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c10
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c19
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c84
-rw-r--r--drivers/media/usb/siano/smsusb.c136
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c17
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c6
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c59
-rw-r--r--drivers/media/usb/tm6000/tm6000.h4
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c94
-rw-r--r--drivers/media/usb/usbvision/usbvision.h4
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c30
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c15
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c70
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h2
-rw-r--r--drivers/media/v4l2-core/tuner-core.c22
-rw-r--r--drivers/media/v4l2-core/v4l2-clk.c81
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c22
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c55
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c102
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c33
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c61
370 files changed, 14510 insertions, 4928 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 49cd308..3ef0f90 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -87,13 +87,21 @@ config MEDIA_RC_SUPPORT
config MEDIA_CONTROLLER
bool "Media Controller API"
- depends on MEDIA_CAMERA_SUPPORT
+ depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
---help---
Enable the media controller API used to query media devices internal
topology and configure it dynamically.
This API is mostly used by camera interfaces in embedded platforms.
+config MEDIA_CONTROLLER_DVB
+ bool "Enable Media controller for DVB"
+ depends on MEDIA_CONTROLLER
+ ---help---
+ Enable the media controller API support for DVB.
+
+ This is currently experimental.
+
#
# Video4Linux support
# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index b7d6393..df1e8c9 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -587,26 +587,20 @@ int saa7146_vv_release(struct saa7146_dev* dev)
}
EXPORT_SYMBOL_GPL(saa7146_vv_release);
-int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
char *name, int type)
{
- struct video_device *vfd;
int err;
int i;
DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
- // released by vfd->release
- vfd = video_device_alloc();
- if (vfd == NULL)
- return -ENOMEM;
-
vfd->fops = &video_fops;
if (type == VFL_TYPE_GRABBER)
vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
else
vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->lock = &dev->v4l2_lock;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->tvnorms = 0;
@@ -618,25 +612,20 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
err = video_register_device(vfd, type, -1);
if (err < 0) {
ERR("cannot register v4l2 device. skipping.\n");
- video_device_release(vfd);
return err;
}
pr_info("%s: registered device %s [v4l2]\n",
dev->name, video_device_node_name(vfd));
-
- *vid = vfd;
return 0;
}
EXPORT_SYMBOL_GPL(saa7146_register_device);
-int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
+int saa7146_unregister_device(struct video_device *vfd, struct saa7146_dev *dev)
{
DEB_EE("dev:%p\n", dev);
- video_unregister_device(*vid);
- *vid = NULL;
-
+ video_unregister_device(vfd);
return 0;
}
EXPORT_SYMBOL_GPL(saa7146_unregister_device);
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index 1e71e37..2da9957 100644
--- a/drivers/media/common/saa7146/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -95,7 +95,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
/* prepare to wait to be woken up by the irq-handler */
add_wait_queue(&vv->vbi_wq, &wait);
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
/* start rps1 to enable workaround */
saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
@@ -106,7 +106,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
DEB_VBI("brs bug workaround %d/1\n", i);
remove_wait_queue(&vv->vbi_wq, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
/* disable rps1 irqs */
SAA7146_IER_DISABLE(dev,MASK_28);
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index 82c7a12..ca2f80c 100644
--- a/drivers/media/common/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
@@ -21,10 +21,6 @@
#include "smsir.h"
#include <linux/module.h>
-static int sms_dbg;
-module_param_named(cards_dbg, sms_dbg, int, 0644);
-MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
-
static struct sms_board sms_boards[] = {
[SMS_BOARD_UNKNOWN] = {
.name = "Unknown board",
@@ -232,7 +228,7 @@ int sms_board_event(struct smscore_device_t *coredev,
break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
default:
- sms_err("Unknown SMS board event");
+ pr_err("Unknown SMS board event\n");
break;
}
return 0;
@@ -342,7 +338,7 @@ int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
int board_id = smscore_get_board_id(coredev);
struct sms_board *board = sms_get_board(board_id);
- sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
+ pr_debug("%s: LNA %s\n", __func__, onoff ? "enabled" : "disabled");
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
index 4c4cadd..bb3d733 100644
--- a/drivers/media/common/siano/sms-cards.h
+++ b/drivers/media/common/siano/sms-cards.h
@@ -20,8 +20,9 @@
#ifndef __SMS_CARDS_H__
#define __SMS_CARDS_H__
-#include <linux/usb.h>
#include "smscoreapi.h"
+
+#include <linux/usb.h>
#include "smsir.h"
#define SMS_BOARD_UNKNOWN 0
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index a367743..2a8d9a3 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "smscoreapi.h"
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -34,14 +36,9 @@
#include <linux/wait.h>
#include <asm/byteorder.h>
-#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsir.h"
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
struct smscore_device_notifyee_t {
struct list_head entry;
hotplug_t hotplug;
@@ -460,7 +457,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
strcpy(entry->devpath, devpath);
list_add(&entry->entry, &g_smscore_registry);
} else
- sms_err("failed to create smscore_registry.");
+ pr_err("failed to create smscore_registry.\n");
kmutex_unlock(&g_smscore_registrylock);
return entry;
}
@@ -473,7 +470,7 @@ int smscore_registry_getmode(char *devpath)
if (entry)
return entry->mode;
else
- sms_err("No registry found.");
+ pr_err("No registry found.\n");
return default_mode;
}
@@ -487,7 +484,7 @@ static enum sms_device_type_st smscore_registry_gettype(char *devpath)
if (entry)
return entry->type;
else
- sms_err("No registry found.");
+ pr_err("No registry found.\n");
return -EINVAL;
}
@@ -500,7 +497,7 @@ static void smscore_registry_setmode(char *devpath, int mode)
if (entry)
entry->mode = mode;
else
- sms_err("No registry found.");
+ pr_err("No registry found.\n");
}
static void smscore_registry_settype(char *devpath,
@@ -512,7 +509,7 @@ static void smscore_registry_settype(char *devpath,
if (entry)
entry->type = type;
else
- sms_err("No registry found.");
+ pr_err("No registry found.\n");
}
@@ -635,10 +632,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
struct smscore_buffer_t *cb;
cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
- if (!cb) {
- sms_info("kzalloc(...) failed");
+ if (!cb)
return NULL;
- }
cb->p = buffer;
cb->offset_in_common = buffer - (u8 *) common_buffer;
@@ -658,16 +653,19 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
* @return 0 on success, <0 on error.
*/
int smscore_register_device(struct smsdevice_params_t *params,
- struct smscore_device_t **coredev)
+ struct smscore_device_t **coredev,
+ void *mdev)
{
struct smscore_device_t *dev;
u8 *buffer;
dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
- if (!dev) {
- sms_info("kzalloc(...) failed");
+ if (!dev)
return -ENOMEM;
- }
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ dev->media_dev = mdev;
+#endif
/* init list entry so it could be safe in smscore_unregister_device */
INIT_LIST_HEAD(&dev->entry);
@@ -722,7 +720,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
smscore_putbuffer(dev, cb);
}
- sms_info("allocated %d buffers", dev->num_buffers);
+ pr_debug("allocated %d buffers\n", dev->num_buffers);
dev->mode = DEVICE_MODE_NONE;
dev->board_id = SMS_BOARD_UNKNOWN;
@@ -746,7 +744,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
*coredev = dev;
- sms_info("device %p created", dev);
+ pr_debug("device %p created\n", dev);
return 0;
}
@@ -763,7 +761,7 @@ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
rc = coredev->sendrequest_handler(coredev->context, buffer, size);
if (rc < 0) {
- sms_info("sendrequest returned error %d", rc);
+ pr_info("sendrequest returned error %d\n", rc);
return rc;
}
@@ -786,11 +784,11 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
coredev->ir.dev = NULL;
ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
if (ir_io) {/* only if IR port exist we use IR sub-module */
- sms_info("IR loading");
+ pr_debug("IR loading\n");
rc = sms_ir_init(coredev);
if (rc != 0)
- sms_err("Error initialization DTV IR sub-module");
+ pr_err("Error initialization DTV IR sub-module\n");
else {
buffer = kmalloc(sizeof(struct sms_msg_data2) +
SMS_DMA_ALIGNMENT,
@@ -812,11 +810,10 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
kfree(buffer);
} else
- sms_err
- ("Sending IR initialization message failed");
+ pr_err("Sending IR initialization message failed\n");
}
} else
- sms_info("IR port has not been detected");
+ pr_info("IR port has not been detected\n");
return 0;
}
@@ -835,13 +832,13 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
board = sms_get_board(coredev->board_id);
if (!board) {
- sms_err("no board configuration exist.");
+ pr_err("no board configuration exist.\n");
return -EINVAL;
}
if (board->mtu) {
struct sms_msg_data mtu_msg;
- sms_debug("set max transmit unit %d", board->mtu);
+ pr_debug("set max transmit unit %d\n", board->mtu);
mtu_msg.x_msg_header.msg_src_id = 0;
mtu_msg.x_msg_header.msg_dst_id = HIF_TASK;
@@ -856,7 +853,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
if (board->crystal) {
struct sms_msg_data crys_msg;
- sms_debug("set crystal value %d", board->crystal);
+ pr_debug("set crystal value %d\n", board->crystal);
SMS_INIT_MSG(&crys_msg.x_msg_header,
MSG_SMS_NEW_CRYSTAL_REQ,
@@ -890,12 +887,12 @@ int smscore_start_device(struct smscore_device_t *coredev)
rc = smscore_set_device_mode(coredev, mode);
if (rc < 0) {
- sms_info("set device mode faile , rc %d", rc);
+ pr_info("set device mode failed , rc %d\n", rc);
return rc;
}
rc = smscore_configure_board(coredev);
if (rc < 0) {
- sms_info("configure board failed , rc %d", rc);
+ pr_info("configure board failed , rc %d\n", rc);
return rc;
}
@@ -904,7 +901,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
rc = smscore_notify_callbacks(coredev, coredev->device, 1);
smscore_init_ir(coredev);
- sms_info("device %p started, rc %d", coredev, rc);
+ pr_debug("device %p started, rc %d\n", coredev, rc);
kmutex_unlock(&g_smscore_deviceslock);
@@ -927,7 +924,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
mem_address = firmware->start_address;
- sms_info("loading FW to addr 0x%x size %d",
+ pr_debug("loading FW to addr 0x%x size %d\n",
mem_address, firmware->length);
if (coredev->preload_handler) {
rc = coredev->preload_handler(coredev->context);
@@ -941,14 +938,14 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
return -ENOMEM;
if (coredev->mode != DEVICE_MODE_NONE) {
- sms_debug("sending reload command.");
+ pr_debug("sending reload command.\n");
SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ,
sizeof(struct sms_msg_hdr));
rc = smscore_sendrequest_and_wait(coredev, msg,
msg->x_msg_header.msg_length,
&coredev->reload_start_done);
if (rc < 0) {
- sms_err("device reload failed, rc %d", rc);
+ pr_err("device reload failed, rc %d\n", rc);
goto exit_fw_download;
}
mem_address = *(u32 *) &payload[20];
@@ -982,7 +979,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
if (rc < 0)
goto exit_fw_download;
- sms_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
+ pr_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x\n",
calc_checksum);
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ,
sizeof(msg->x_msg_header) +
@@ -1001,7 +998,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
struct sms_msg_data *trigger_msg =
(struct sms_msg_data *) msg;
- sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
+ pr_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ\n");
SMS_INIT_MSG(&msg->x_msg_header,
MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
sizeof(struct sms_msg_hdr) +
@@ -1037,12 +1034,13 @@ exit_fw_download:
kfree(msg);
if (coredev->postload_handler) {
- sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler);
+ pr_debug("rc=%d, postload=0x%p\n",
+ rc, coredev->postload_handler);
if (rc >= 0)
return coredev->postload_handler(coredev->context);
}
- sms_debug("rc=%d", rc);
+ pr_debug("rc=%d\n", rc);
return rc;
}
@@ -1121,11 +1119,11 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev,
if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX)
return NULL;
- sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
+ pr_debug("trying to get fw name from sms_boards board_id %d mode %d\n",
board_id, mode);
fw = sms_get_board(board_id)->fw;
if (!fw || !fw[mode]) {
- sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d",
+ pr_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d\n",
mode, type);
return smscore_fw_lkup[type][mode];
}
@@ -1154,10 +1152,10 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
char *fw_filename = smscore_get_fw_filename(coredev, mode);
if (!fw_filename) {
- sms_err("mode %d not supported on this device", mode);
+ pr_err("mode %d not supported on this device\n", mode);
return -ENOENT;
}
- sms_debug("Firmware name: %s", fw_filename);
+ pr_debug("Firmware name: %s\n", fw_filename);
if (loadfirmware_handler == NULL && !(coredev->device_flags
& SMS_DEVICE_FAMILY2))
@@ -1165,14 +1163,14 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
rc = request_firmware(&fw, fw_filename, coredev->device);
if (rc < 0) {
- sms_err("failed to open firmware file \"%s\"", fw_filename);
+ pr_err("failed to open firmware file '%s'\n", fw_filename);
return rc;
}
- sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
+ pr_debug("read fw %s, buffer size=0x%zx\n", fw_filename, fw->size);
fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
GFP_KERNEL | GFP_DMA);
if (!fw_buf) {
- sms_err("failed to allocate firmware buffer");
+ pr_err("failed to allocate firmware buffer\n");
rc = -ENOMEM;
} else {
memcpy(fw_buf, fw->data, fw->size);
@@ -1226,18 +1224,18 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
if (num_buffers == coredev->num_buffers)
break;
if (++retry > 10) {
- sms_info("exiting although not all buffers released.");
+ pr_info("exiting although not all buffers released.\n");
break;
}
- sms_info("waiting for %d buffer(s)",
+ pr_debug("waiting for %d buffer(s)\n",
coredev->num_buffers - num_buffers);
kmutex_unlock(&g_smscore_deviceslock);
msleep(100);
kmutex_lock(&g_smscore_deviceslock);
}
- sms_info("freed %d buffers", num_buffers);
+ pr_debug("freed %d buffers\n", num_buffers);
if (coredev->common_buffer)
dma_free_coherent(NULL, coredev->common_buffer_size,
@@ -1250,7 +1248,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
kmutex_unlock(&g_smscore_deviceslock);
- sms_info("device %p destroyed", coredev);
+ pr_debug("device %p destroyed\n", coredev);
}
EXPORT_SYMBOL_GPL(smscore_unregister_device);
@@ -1271,7 +1269,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev)
rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length,
&coredev->version_ex_done);
if (rc == -ETIME) {
- sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+ pr_err("MSG_SMS_GET_VERSION_EX_REQ failed first try\n");
if (wait_for_completion_timeout(&coredev->resume_done,
msecs_to_jiffies(5000))) {
@@ -1279,7 +1277,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev)
coredev, msg, msg->msg_length,
&coredev->version_ex_done);
if (rc < 0)
- sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d",
+ pr_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n",
rc);
} else
rc = -ETIME;
@@ -1308,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode)
buffer = kmalloc(sizeof(struct sms_msg_data) +
SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
if (!buffer) {
- sms_err("Could not allocate buffer for init device message.");
+ pr_err("Could not allocate buffer for init device message.\n");
return -ENOMEM;
}
@@ -1339,10 +1337,10 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
{
int rc = 0;
- sms_debug("set device mode to %d", mode);
+ pr_debug("set device mode to %d\n", mode);
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
- sms_err("invalid mode specified %d", mode);
+ pr_err("invalid mode specified %d\n", mode);
return -EINVAL;
}
@@ -1351,13 +1349,13 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
rc = smscore_detect_mode(coredev);
if (rc < 0) {
- sms_err("mode detect failed %d", rc);
+ pr_err("mode detect failed %d\n", rc);
return rc;
}
}
if (coredev->mode == mode) {
- sms_info("device mode %d already set", mode);
+ pr_debug("device mode %d already set\n", mode);
return 0;
}
@@ -1365,19 +1363,19 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
rc = smscore_load_firmware_from_file(coredev,
mode, NULL);
if (rc >= 0)
- sms_info("firmware download success");
+ pr_debug("firmware download success\n");
} else {
- sms_info("mode %d is already supported by running firmware",
+ pr_debug("mode %d is already supported by running firmware\n",
mode);
}
if (coredev->fw_version >= 0x800) {
rc = smscore_init_device(coredev, mode);
if (rc < 0)
- sms_err("device init failed, rc %d.", rc);
+ pr_err("device init failed, rc %d.\n", rc);
}
} else {
if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
- sms_err("invalid mode specified %d", mode);
+ pr_err("invalid mode specified %d\n", mode);
return -EINVAL;
}
@@ -1414,9 +1412,9 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
}
if (rc < 0)
- sms_err("return error code %d.", rc);
+ pr_err("return error code %d.\n", rc);
else
- sms_debug("Success setting device mode.");
+ pr_debug("Success setting device mode.\n");
return rc;
}
@@ -1495,7 +1493,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
last_sample_time = time_now;
if (time_now - last_sample_time > 10000) {
- sms_debug("data rate %d bytes/secs",
+ pr_debug("data rate %d bytes/secs\n",
(int)((data_total * 1000) /
(time_now - last_sample_time)));
@@ -1539,7 +1537,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
{
struct sms_version_res *ver =
(struct sms_version_res *) phdr;
- sms_debug("Firmware id %d prots 0x%x ver %d.%d",
+ pr_debug("Firmware id %d prots 0x%x ver %d.%d\n",
ver->firmware_id, ver->supported_protocols,
ver->rom_ver_major, ver->rom_ver_minor);
@@ -1562,7 +1560,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
{
struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
- sms_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
+ pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n",
validity->msg_data[0]);
complete(&coredev->data_validity_done);
break;
@@ -1588,7 +1586,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
{
u32 *msgdata = (u32 *) phdr;
coredev->gpio_get_res = msgdata[1];
- sms_debug("gpio level %d",
+ pr_debug("gpio level %d\n",
coredev->gpio_get_res);
complete(&coredev->gpio_get_level_done);
break;
@@ -1615,7 +1613,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
break;
default:
- sms_debug("message %s(%d) not handled.",
+ pr_debug("message %s(%d) not handled.\n",
smscore_translate_msg(phdr->msg_type),
phdr->msg_type);
break;
@@ -1681,7 +1679,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev,
struct smscore_client_t *registered_client;
if (!client) {
- sms_err("bad parameter.");
+ pr_err("bad parameter.\n");
return -EINVAL;
}
registered_client = smscore_find_client(coredev, data_type, id);
@@ -1689,12 +1687,12 @@ static int smscore_validate_client(struct smscore_device_t *coredev,
return 0;
if (registered_client) {
- sms_err("The msg ID already registered to another client.");
+ pr_err("The msg ID already registered to another client.\n");
return -EEXIST;
}
listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
if (!listentry) {
- sms_err("Can't allocate memory for client id.");
+ pr_err("Can't allocate memory for client id.\n");
return -ENOMEM;
}
listentry->id = id;
@@ -1726,13 +1724,13 @@ int smscore_register_client(struct smscore_device_t *coredev,
/* check that no other channel with same parameters exists */
if (smscore_find_client(coredev, params->data_type,
params->initial_id)) {
- sms_err("Client already exist.");
+ pr_err("Client already exist.\n");
return -EEXIST;
}
newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
if (!newclient) {
- sms_err("Failed to allocate memory for client.");
+ pr_err("Failed to allocate memory for client.\n");
return -ENOMEM;
}
@@ -1746,7 +1744,7 @@ int smscore_register_client(struct smscore_device_t *coredev,
smscore_validate_client(coredev, newclient, params->data_type,
params->initial_id);
*client = newclient;
- sms_debug("%p %d %d", params->context, params->data_type,
+ pr_debug("%p %d %d\n", params->context, params->data_type,
params->initial_id);
return 0;
@@ -1775,7 +1773,7 @@ void smscore_unregister_client(struct smscore_client_t *client)
kfree(identry);
}
- sms_info("%p", client->context);
+ pr_debug("%p\n", client->context);
list_del(&client->entry);
kfree(client);
@@ -1803,7 +1801,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
int rc;
if (client == NULL) {
- sms_err("Got NULL client");
+ pr_err("Got NULL client\n");
return -EINVAL;
}
@@ -1811,7 +1809,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
/* check that no other channel with same id exists */
if (coredev == NULL) {
- sms_err("Got NULL coredev");
+ pr_err("Got NULL coredev\n");
return -EINVAL;
}
@@ -2016,9 +2014,9 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
if (rc != 0) {
if (rc == -ETIME)
- sms_err("smscore_gpio_configure timeout");
+ pr_err("smscore_gpio_configure timeout\n");
else
- sms_err("smscore_gpio_configure error");
+ pr_err("smscore_gpio_configure error\n");
}
free:
kfree(buffer);
@@ -2065,9 +2063,9 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num,
if (rc != 0) {
if (rc == -ETIME)
- sms_err("smscore_gpio_set_level timeout");
+ pr_err("smscore_gpio_set_level timeout\n");
else
- sms_err("smscore_gpio_set_level error");
+ pr_err("smscore_gpio_set_level error\n");
}
kfree(buffer);
@@ -2113,9 +2111,9 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
if (rc != 0) {
if (rc == -ETIME)
- sms_err("smscore_gpio_get_level timeout");
+ pr_err("smscore_gpio_get_level timeout\n");
else
- sms_err("smscore_gpio_get_level error");
+ pr_err("smscore_gpio_get_level error\n");
}
kfree(buffer);
@@ -2163,7 +2161,7 @@ static void __exit smscore_module_exit(void)
}
kmutex_unlock(&g_smscore_registrylock);
- sms_debug("");
+ pr_debug("\n");
}
module_init(smscore_module_init);
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index 9c9063c..eb8bd68 100644
--- a/drivers/media/common/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __SMS_CORE_API_H__
#define __SMS_CORE_API_H__
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
#include <linux/device.h>
#include <linux/list.h>
#include <linux/mm.h>
@@ -31,6 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/wait.h>
#include <linux/timer.h>
+#include <media/media-device.h>
+
#include <asm/page.h>
#include "smsir.h"
@@ -215,6 +219,10 @@ struct smscore_device_t {
bool is_usb_device;
int led_state;
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_device *media_dev;
+#endif
};
/* GPIO definitions for antenna frequency domain control (SMS8021) */
@@ -1115,7 +1123,8 @@ extern int smscore_register_hotplug(hotplug_t hotplug);
extern void smscore_unregister_hotplug(hotplug_t hotplug);
extern int smscore_register_device(struct smsdevice_params_t *params,
- struct smscore_device_t **coredev);
+ struct smscore_device_t **coredev,
+ void *mdev);
extern void smscore_unregister_device(struct smscore_device_t *coredev);
extern int smscore_start_device(struct smscore_device_t *coredev);
@@ -1168,25 +1177,4 @@ int smscore_led_state(struct smscore_device_t *core, int led);
/* ------------------------------------------------------------------------ */
-#define DBG_INFO 1
-#define DBG_ADV 2
-
-#define sms_printk(kern, fmt, arg...) \
- printk(kern "%s: " fmt "\n", __func__, ##arg)
-
-#define dprintk(kern, lvl, fmt, arg...) do {\
- if (sms_dbg & lvl) \
- sms_printk(kern, fmt, ##arg); \
-} while (0)
-
-#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
-#define sms_err(fmt, arg...) \
- sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
-#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
-#define sms_info(fmt, arg...) \
- dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
-#define sms_debug(fmt, arg...) \
- dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
-
-
#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c
index 2408d7e..1a8677a 100644
--- a/drivers/media/common/siano/smsdvb-debugfs.c
+++ b/drivers/media/common/siano/smsdvb-debugfs.c
@@ -17,7 +17,7 @@
*
***********************************************************************/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include "smscoreapi.h"
#include <linux/module.h>
#include <linux/slab.h>
@@ -31,8 +31,6 @@
#include "dvb_demux.h"
#include "dvb_frontend.h"
-#include "smscoreapi.h"
-
#include "smsdvb.h"
static struct dentry *smsdvb_debugfs_usb_root;
@@ -536,7 +534,7 @@ int smsdvb_debugfs_register(void)
*/
d = debugfs_create_dir("smsdvb", usb_debug_root);
if (IS_ERR_OR_NULL(d)) {
- sms_err("Couldn't create sysfs node for smsdvb");
+ pr_err("Couldn't create sysfs node for smsdvb\n");
return PTR_ERR(d);
} else {
smsdvb_debugfs_usb_root = d;
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index 85151ef..367b8e7 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************/
+#include "smscoreapi.h"
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -29,7 +31,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dvb_demux.h"
#include "dvb_frontend.h"
-#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsdvb.h"
@@ -39,11 +40,6 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static struct list_head g_smsdvb_clients;
static struct mutex g_smsdvb_clientslock;
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
-
static u32 sms_to_guard_interval_table[] = {
[0] = GUARD_INTERVAL_1_32,
[1] = GUARD_INTERVAL_1_16,
@@ -82,48 +78,48 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
struct smscore_device_t *coredev = client->coredev;
switch (event) {
case DVB3_EVENT_INIT:
- sms_debug("DVB3_EVENT_INIT");
+ pr_debug("DVB3_EVENT_INIT\n");
sms_board_event(coredev, BOARD_EVENT_BIND);
break;
case DVB3_EVENT_SLEEP:
- sms_debug("DVB3_EVENT_SLEEP");
+ pr_debug("DVB3_EVENT_SLEEP\n");
sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
break;
case DVB3_EVENT_HOTPLUG:
- sms_debug("DVB3_EVENT_HOTPLUG");
+ pr_debug("DVB3_EVENT_HOTPLUG\n");
sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
break;
case DVB3_EVENT_FE_LOCK:
if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
client->event_fe_state = DVB3_EVENT_FE_LOCK;
- sms_debug("DVB3_EVENT_FE_LOCK");
+ pr_debug("DVB3_EVENT_FE_LOCK\n");
sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
}
break;
case DVB3_EVENT_FE_UNLOCK:
if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
- sms_debug("DVB3_EVENT_FE_UNLOCK");
+ pr_debug("DVB3_EVENT_FE_UNLOCK\n");
sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
}
break;
case DVB3_EVENT_UNC_OK:
if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
client->event_unc_state = DVB3_EVENT_UNC_OK;
- sms_debug("DVB3_EVENT_UNC_OK");
+ pr_debug("DVB3_EVENT_UNC_OK\n");
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
}
break;
case DVB3_EVENT_UNC_ERR:
if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
client->event_unc_state = DVB3_EVENT_UNC_ERR;
- sms_debug("DVB3_EVENT_UNC_ERR");
+ pr_debug("DVB3_EVENT_UNC_ERR\n");
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
}
break;
default:
- sms_err("Unknown dvb3 api event");
+ pr_err("Unknown dvb3 api event\n");
break;
}
}
@@ -590,7 +586,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
is_status_update = true;
break;
default:
- sms_info("message not handled");
+ pr_debug("message not handled\n");
}
smscore_putbuffer(client->coredev, cb);
@@ -613,6 +609,19 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
return 0;
}
+static void smsdvb_media_device_unregister(struct smsdvb_client_t *client)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct smscore_device_t *coredev = client->coredev;
+
+ if (!coredev->media_dev)
+ return;
+ media_device_unregister(coredev->media_dev);
+ kfree(coredev->media_dev);
+ coredev->media_dev = NULL;
+#endif
+}
+
static void smsdvb_unregister_client(struct smsdvb_client_t *client)
{
/* must be called under clientslock */
@@ -624,6 +633,7 @@ static void smsdvb_unregister_client(struct smsdvb_client_t *client)
dvb_unregister_frontend(&client->frontend);
dvb_dmxdev_release(&client->dmxdev);
dvb_dmx_release(&client->demux);
+ smsdvb_media_device_unregister(client);
dvb_unregister_adapter(&client->adapter);
kfree(client);
}
@@ -643,7 +653,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
container_of(feed->demux, struct smsdvb_client_t, demux);
struct sms_msg_data pid_msg;
- sms_debug("add pid %d(%x)",
+ pr_debug("add pid %d(%x)\n",
feed->pid, feed->pid);
client->feed_users++;
@@ -665,7 +675,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
container_of(feed->demux, struct smsdvb_client_t, demux);
struct sms_msg_data pid_msg;
- sms_debug("remove pid %d(%x)",
+ pr_debug("remove pid %d(%x)\n",
feed->pid, feed->pid);
client->feed_users--;
@@ -835,7 +845,7 @@ static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
- sms_debug("");
+ pr_debug("\n");
tune->min_delay_ms = 400;
tune->step_size = 250000;
@@ -869,7 +879,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
msg.Data[0] = c->frequency;
msg.Data[2] = 12000000;
- sms_info("%s: freq %d band %d", __func__, c->frequency,
+ pr_debug("%s: freq %d band %d\n", __func__, c->frequency,
c->bandwidth_hz);
switch (c->bandwidth_hz / 1000000) {
@@ -954,7 +964,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
c->bandwidth_hz = 6000000;
- sms_info("%s: freq %d segwidth %d segindex %d", __func__,
+ pr_debug("freq %d segwidth %d segindex %d\n",
c->frequency, c->isdbt_sb_segment_count,
c->isdbt_sb_segment_idx);
@@ -1082,10 +1092,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
if (!arrival)
return 0;
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
- if (!client) {
- sms_err("kmalloc() failed");
+ if (!client)
return -ENOMEM;
- }
/* register dvb adapter */
rc = dvb_register_adapter(&client->adapter,
@@ -1093,9 +1101,10 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
smscore_get_board_id(coredev))->name,
THIS_MODULE, device, adapter_nr);
if (rc < 0) {
- sms_err("dvb_register_adapter() failed %d", rc);
+ pr_err("dvb_register_adapter() failed %d\n", rc);
goto adapter_error;
}
+ dvb_register_media_controller(&client->adapter, coredev->media_dev);
/* init dvb demux */
client->demux.dmx.capabilities = DMX_TS_FILTERING;
@@ -1106,7 +1115,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
rc = dvb_dmx_init(&client->demux);
if (rc < 0) {
- sms_err("dvb_dmx_init failed %d", rc);
+ pr_err("dvb_dmx_init failed %d\n", rc);
goto dvbdmx_error;
}
@@ -1117,7 +1126,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
if (rc < 0) {
- sms_err("dvb_dmxdev_init failed %d", rc);
+ pr_err("dvb_dmxdev_init failed %d\n", rc);
goto dmxdev_error;
}
@@ -1138,7 +1147,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
rc = dvb_register_frontend(&client->adapter, &client->frontend);
if (rc < 0) {
- sms_err("frontend registration failed %d", rc);
+ pr_err("frontend registration failed %d\n", rc);
goto frontend_error;
}
@@ -1150,7 +1159,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
rc = smscore_register_client(coredev, &params, &client->smsclient);
if (rc < 0) {
- sms_err("smscore_register_client() failed %d", rc);
+ pr_err("smscore_register_client() failed %d\n", rc);
goto client_error;
}
@@ -1169,12 +1178,14 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
client->event_unc_state = -1;
sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
- sms_info("success");
sms_board_setup(coredev);
if (smsdvb_debugfs_create(client) < 0)
- sms_info("failed to create debugfs node");
+ pr_info("failed to create debugfs node\n");
+
+ dvb_create_media_graph(&client->adapter);
+ pr_info("DVB interface registered.\n");
return 0;
client_error:
@@ -1187,6 +1198,7 @@ dmxdev_error:
dvb_dmx_release(&client->demux);
dvbdmx_error:
+ smsdvb_media_device_unregister(client);
dvb_unregister_adapter(&client->adapter);
adapter_error:
@@ -1205,7 +1217,7 @@ static int __init smsdvb_module_init(void)
rc = smscore_register_hotplug(smsdvb_hotplug);
- sms_debug("");
+ pr_debug("\n");
return rc;
}
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 35d0e88..1d60d20 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -25,10 +25,11 @@
****************************************************************/
+#include "smscoreapi.h"
+
#include <linux/types.h>
#include <linux/input.h>
-#include "smscoreapi.h"
#include "smsir.h"
#include "sms-cards.h"
@@ -56,16 +57,14 @@ int sms_ir_init(struct smscore_device_t *coredev)
int board_id = smscore_get_board_id(coredev);
struct rc_dev *dev;
- sms_log("Allocating rc device");
+ pr_debug("Allocating rc device\n");
dev = rc_allocate_device();
- if (!dev) {
- sms_err("Not enough memory");
+ if (!dev)
return -ENOMEM;
- }
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
- sms_log("IR port %d, timeout %d ms",
+ pr_debug("IR port %d, timeout %d ms\n",
coredev->ir.controller, coredev->ir.timeout);
snprintf(coredev->ir.name, sizeof(coredev->ir.name),
@@ -92,11 +91,12 @@ int sms_ir_init(struct smscore_device_t *coredev)
dev->map_name = sms_get_board(board_id)->rc_codes;
dev->driver_name = MODULE_NAME;
- sms_log("Input device (IR) %s is set for key events", dev->input_name);
+ pr_debug("Input device (IR) %s is set for key events\n",
+ dev->input_name);
err = rc_register_device(dev);
if (err < 0) {
- sms_err("Failed to register device");
+ pr_err("Failed to register device\n");
rc_free_device(dev);
return err;
}
@@ -109,5 +109,5 @@ void sms_ir_exit(struct smscore_device_t *coredev)
{
rc_unregister_device(coredev->ir.dev);
- sms_log("");
+ pr_debug("\n");
}
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index abff803..d0e3f9d 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1136,10 +1136,13 @@ static const struct file_operations dvb_demux_fops = {
.llseek = default_llseek,
};
-static struct dvb_device dvbdev_demux = {
+static const struct dvb_device dvbdev_demux = {
.priv = NULL,
.users = 1,
.writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = "dvb-demux",
+#endif
.fops = &dvb_demux_fops
};
@@ -1209,13 +1212,15 @@ static const struct file_operations dvb_dvr_fops = {
.llseek = default_llseek,
};
-static struct dvb_device dvbdev_dvr = {
+static const struct dvb_device dvbdev_dvr = {
.priv = NULL,
.readers = 1,
.users = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = "dvb-dvr",
+#endif
.fops = &dvb_dvr_fops
};
-
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{
int i;
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 80ab8d0..c117fb3 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -245,6 +245,7 @@
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
+#define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011
#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012
#define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
@@ -318,6 +319,7 @@
#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
#define USB_PID_WINFAST_DTV2000DS 0x6a04
+#define USB_PID_WINFAST_DTV2000DS_PLUS 0x6f12
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
@@ -385,4 +387,5 @@
#define USB_PID_PCTV_2002E 0x025c
#define USB_PID_PCTV_2002E_SE 0x025d
#define USB_PID_SVEON_STV27 0xd3af
+#define USB_PID_TURBOX_DTT_2000 0xd3a4
#endif
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 0aac309..7293775 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -1638,15 +1638,17 @@ static const struct file_operations dvb_ca_fops = {
.llseek = noop_llseek,
};
-static struct dvb_device dvbdev_ca = {
+static const struct dvb_device dvbdev_ca = {
.priv = NULL,
.users = 1,
.readers = 1,
.writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = "dvb-ca-en50221",
+#endif
.fops = &dvb_ca_fops,
};
-
/* ******************************************************************************** */
/* Initialisation/shutdown functions */
@@ -1676,14 +1678,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
/* initialise the system data */
if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
- goto error;
+ goto exit;
}
ca->pub = pubca;
ca->flags = flags;
ca->slot_count = slot_count;
if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
- goto error;
+ goto free_ca;
}
init_waitqueue_head(&ca->wait_queue);
ca->open = 0;
@@ -1694,7 +1696,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
/* register the DVB device */
ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
if (ret)
- goto error;
+ goto free_slot_info;
/* now initialise each slot */
for (i = 0; i < slot_count; i++) {
@@ -1709,7 +1711,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
if (signal_pending(current)) {
ret = -EINTR;
- goto error;
+ goto unregister_device;
}
mb();
@@ -1720,17 +1722,17 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
ret = PTR_ERR(ca->thread);
printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
ret);
- goto error;
+ goto unregister_device;
}
return 0;
-error:
- if (ca != NULL) {
- if (ca->dvbdev != NULL)
- dvb_unregister_device(ca->dvbdev);
- kfree(ca->slot_info);
- kfree(ca);
- }
+unregister_device:
+ dvb_unregister_device(ca->dvbdev);
+free_slot_info:
+ kfree(ca->slot_info);
+free_ca:
+ kfree(ca);
+exit:
pubca->private = NULL;
return ret;
}
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 2cf3057..882ca41 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -131,6 +131,11 @@ struct dvb_frontend_private {
int quality;
unsigned int check_wrapped;
enum dvbfe_search algo_status;
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_pipeline pipe;
+ struct media_entity *pipe_start_entity;
+#endif
};
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@@ -590,12 +595,106 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
wake_up_interruptible(&fepriv->wait_queue);
}
+/**
+ * dvb_enable_media_tuner() - tries to enable the DVB tuner
+ *
+ * @fe: struct dvb_frontend pointer
+ *
+ * This function ensures that just one media tuner is enabled for a given
+ * frontend. It has two different behaviors:
+ * - For trivial devices with just one tuner:
+ * it just enables the existing tuner->fe link
+ * - For devices with more than one tuner:
+ * It is up to the driver to implement the logic that will enable one tuner
+ * and disable the other ones. However, if more than one tuner is enabled for
+ * the same frontend, it will print an error message and return -EINVAL.
+ *
+ * At return, it will return the error code returned by media_entity_setup_link,
+ * or 0 if everything is OK, if no tuner is linked to the frontend or if the
+ * mdev is NULL.
+ */
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+static int dvb_enable_media_tuner(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_adapter *adapter = fe->dvb;
+ struct media_device *mdev = adapter->mdev;
+ struct media_entity *entity, *source;
+ struct media_link *link, *found_link = NULL;
+ int i, ret, n_links = 0, active_links = 0;
+
+ fepriv->pipe_start_entity = NULL;
+
+ if (!mdev)
+ return 0;
+
+ entity = fepriv->dvbdev->entity;
+ fepriv->pipe_start_entity = entity;
+
+ for (i = 0; i < entity->num_links; i++) {
+ link = &entity->links[i];
+ if (link->sink->entity == entity) {
+ found_link = link;
+ n_links++;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ }
+ }
+
+ if (!n_links || active_links == 1 || !found_link)
+ return 0;
+
+ /*
+ * If a frontend has more than one tuner linked, it is up to the driver
+ * to select with one will be the active one, as the frontend core can't
+ * guess. If the driver doesn't do that, it is a bug.
+ */
+ if (n_links > 1 && active_links != 1) {
+ dev_err(fe->dvb->device,
+ "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n",
+ active_links, n_links);
+ return -EINVAL;
+ }
+
+ source = found_link->source->entity;
+ fepriv->pipe_start_entity = source;
+ for (i = 0; i < source->num_links; i++) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ link = &source->links[i];
+ sink = link->sink->entity;
+
+ if (sink == entity)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ dev_err(fe->dvb->device,
+ "Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ } else
+ dev_dbg(fe->dvb->device,
+ "link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
+ }
+ return 0;
+}
+#endif
+
static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
fe_status_t s;
enum dvbfe_algo algo;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ int ret;
+#endif
bool re_tune = false;
bool semheld = false;
@@ -609,6 +708,20 @@ static int dvb_frontend_thread(void *data)
fepriv->wakeup = 0;
fepriv->reinitialise = 0;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ ret = dvb_enable_media_tuner(fe);
+ if (ret) {
+ /* FIXME: return an error if it fails */
+ dev_info(fe->dvb->device,
+ "proceeding with FE task\n");
+ } else if (fepriv->pipe_start_entity) {
+ ret = media_entity_pipeline_start(fepriv->pipe_start_entity,
+ &fepriv->pipe);
+ if (ret)
+ return ret;
+ }
+#endif
+
dvb_frontend_init(fe);
set_freezable();
@@ -718,6 +831,12 @@ restart:
}
}
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fepriv->pipe_start_entity)
+ media_entity_pipeline_stop(fepriv->pipe_start_entity);
+ fepriv->pipe_start_entity = NULL;
+#endif
+
if (dvb_powerdown_on_sleep) {
if (fe->ops.set_voltage)
fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
@@ -2612,11 +2731,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
struct dvb_frontend* fe)
{
struct dvb_frontend_private *fepriv;
- static const struct dvb_device dvbdev_template = {
+ const struct dvb_device dvbdev_template = {
.users = ~0,
.writers = 1,
.readers = (~0)-1,
.fops = &dvb_frontend_fops,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = fe->ops.info.name,
+#endif
.kernel_ioctl = dvb_frontend_ioctl
};
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 4a77cb0..a694fb1 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1461,14 +1461,16 @@ static const struct file_operations dvb_net_fops = {
.llseek = noop_llseek,
};
-static struct dvb_device dvbdev_net = {
+static const struct dvb_device dvbdev_net = {
.priv = NULL,
.users = 1,
.writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = "dvb-net",
+#endif
.fops = &dvb_net_fops,
};
-
void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 983db75..13bb57f 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -180,6 +180,93 @@ skip:
return -ENFILE;
}
+static void dvb_register_media_device(struct dvb_device *dvbdev,
+ int type, int minor)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ int ret = 0, npads;
+
+ if (!dvbdev->adapter->mdev)
+ return;
+
+ dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
+ if (!dvbdev->entity)
+ return;
+
+ dvbdev->entity->info.dev.major = DVB_MAJOR;
+ dvbdev->entity->info.dev.minor = minor;
+ dvbdev->entity->name = dvbdev->name;
+
+ switch (type) {
+ case DVB_DEVICE_CA:
+ case DVB_DEVICE_DEMUX:
+ case DVB_DEVICE_FRONTEND:
+ npads = 2;
+ break;
+ case DVB_DEVICE_NET:
+ npads = 0;
+ break;
+ default:
+ npads = 1;
+ }
+
+ if (npads) {
+ dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
+ GFP_KERNEL);
+ if (!dvbdev->pads) {
+ kfree(dvbdev->entity);
+ return;
+ }
+ }
+
+ switch (type) {
+ case DVB_DEVICE_FRONTEND:
+ dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ case DVB_DEVICE_DEMUX:
+ dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ case DVB_DEVICE_DVR:
+ dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ break;
+ case DVB_DEVICE_CA:
+ dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ case DVB_DEVICE_NET:
+ dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET;
+ break;
+ default:
+ kfree(dvbdev->entity);
+ dvbdev->entity = NULL;
+ return;
+ }
+
+ if (npads)
+ ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0);
+ if (!ret)
+ ret = media_device_register_entity(dvbdev->adapter->mdev,
+ dvbdev->entity);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "%s: media_device_register_entity failed for %s\n",
+ __func__, dvbdev->entity->name);
+ kfree(dvbdev->pads);
+ kfree(dvbdev->entity);
+ dvbdev->entity = NULL;
+ return;
+ }
+
+ printk(KERN_DEBUG "%s: media device '%s' registered.\n",
+ __func__, dvbdev->entity->name);
+#endif
+}
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type)
@@ -258,10 +345,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
return PTR_ERR(clsdev);
}
-
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
+ dvb_register_media_device(dvbdev, type, minor);
+
return 0;
}
EXPORT_SYMBOL(dvb_register_device);
@@ -278,12 +366,66 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ if (dvbdev->entity) {
+ media_device_unregister_entity(dvbdev->entity);
+ kfree(dvbdev->entity);
+ kfree(dvbdev->pads);
+ }
+#endif
+
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+void dvb_create_media_graph(struct dvb_adapter *adap)
+{
+ struct media_device *mdev = adap->mdev;
+ struct media_entity *entity, *tuner = NULL, *fe = NULL;
+ struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL;
+
+ if (!mdev)
+ return;
+
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->type) {
+ case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+ tuner = entity;
+ break;
+ case MEDIA_ENT_T_DEVNODE_DVB_FE:
+ fe = entity;
+ break;
+ case MEDIA_ENT_T_DEVNODE_DVB_DEMUX:
+ demux = entity;
+ break;
+ case MEDIA_ENT_T_DEVNODE_DVB_DVR:
+ dvr = entity;
+ break;
+ case MEDIA_ENT_T_DEVNODE_DVB_CA:
+ ca = entity;
+ break;
+ }
+ }
+
+ if (tuner && fe)
+ media_entity_create_link(tuner, 0, fe, 0, 0);
+
+ if (fe && demux)
+ media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED);
+
+ if (demux && dvr)
+ media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED);
+
+ if (demux && ca)
+ media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED);
+}
+EXPORT_SYMBOL_GPL(dvb_create_media_graph);
+#endif
+
static int dvbdev_check_free_adapter_num(int num)
{
struct list_head *entry;
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index f96b28e..12629b8 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -27,6 +27,7 @@
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/list.h>
+#include <media/media-device.h>
#define DVB_MAJOR 212
@@ -71,6 +72,10 @@ struct dvb_adapter {
int mfe_shared; /* indicates mutually exclusive frontends */
struct dvb_device *mfe_dvbdev; /* frontend device in use */
struct mutex mfe_lock; /* access lock for thread creation */
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_device *mdev;
+#endif
};
@@ -92,6 +97,15 @@ struct dvb_device {
/* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
+ /* Needed for media controller register/unregister */
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ const char *name;
+
+ /* Allocated and filled inside dvbdev.c */
+ struct media_entity *entity;
+ struct media_pad *pads;
+#endif
+
void *priv;
};
@@ -109,6 +123,19 @@ extern int dvb_register_device (struct dvb_adapter *adap,
extern void dvb_unregister_device (struct dvb_device *dvbdev);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+void dvb_create_media_graph(struct dvb_adapter *adap);
+static inline void dvb_register_media_controller(struct dvb_adapter *adap,
+ struct media_device *mdev)
+{
+ adap->mdev = mdev;
+}
+
+#else
+static inline void dvb_create_media_graph(struct dvb_adapter *adap) {}
+#define dvb_register_media_controller(a, b) {}
+#endif
+
extern int dvb_generic_open (struct inode *inode, struct file *file);
extern int dvb_generic_release (struct inode *inode, struct file *file);
extern long dvb_generic_ioctl (struct file *file,
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index bb76727..97c151d 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -577,6 +577,14 @@ config DVB_LGDT3305
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_LGDT3306A
+ tristate "LG Electronics LGDT3306A based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want
+ to support this frontend.
+
config DVB_LG2160
tristate "LG Electronics LG216x based"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index ba59df6..23d399b 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o
obj-$(CONFIG_DVB_LG2160) += lg2160.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h
index b6ef642..5f04119 100644
--- a/drivers/media/dvb-frontends/a8293.h
+++ b/drivers/media/dvb-frontends/a8293.h
@@ -27,7 +27,7 @@ struct a8293_config {
u8 i2c_addr;
};
-#if IS_ENABLED(CONFIG_DVB_A8293)
+#if IS_REACHABLE(CONFIG_DVB_A8293)
extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct a8293_config *cfg);
#else
diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h
index 09273b2..1dcc936 100644
--- a/drivers/media/dvb-frontends/af9013.h
+++ b/drivers/media/dvb-frontends/af9013.h
@@ -103,7 +103,7 @@ struct af9013_config {
u8 gpio[4];
};
-#if IS_ENABLED(CONFIG_DVB_AF9013)
+#if IS_REACHABLE(CONFIG_DVB_AF9013)
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h
index 8e0ac98..5446d13 100644
--- a/drivers/media/dvb-frontends/atbm8830.h
+++ b/drivers/media/dvb-frontends/atbm8830.h
@@ -61,7 +61,7 @@ struct atbm8830_config {
u8 agc_hold_loop;
};
-#if IS_ENABLED(CONFIG_DVB_ATBM8830)
+#if IS_REACHABLE(CONFIG_DVB_ATBM8830)
extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
index 6122519..dde6158 100644
--- a/drivers/media/dvb-frontends/au8522.h
+++ b/drivers/media/dvb-frontends/au8522.h
@@ -61,7 +61,7 @@ struct au8522_config {
enum au8522_if_freq qam_if;
};
-#if IS_ENABLED(CONFIG_DVB_AU8522_DTV)
+#if IS_REACHABLE(CONFIG_DVB_AU8522_DTV)
extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
index 5bd56b1..ff66492 100644
--- a/drivers/media/dvb-frontends/bcm3510.h
+++ b/drivers/media/dvb-frontends/bcm3510.h
@@ -34,7 +34,7 @@ struct bcm3510_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if IS_ENABLED(CONFIG_DVB_BCM3510)
+#if IS_REACHABLE(CONFIG_DVB_BCM3510)
extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h
index 382a7b1..e0a7648 100644
--- a/drivers/media/dvb-frontends/cx22700.h
+++ b/drivers/media/dvb-frontends/cx22700.h
@@ -31,7 +31,7 @@ struct cx22700_config
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_CX22700)
+#if IS_REACHABLE(CONFIG_DVB_CX22700)
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h
index 0b1a6c2..68b69a7 100644
--- a/drivers/media/dvb-frontends/cx22702.h
+++ b/drivers/media/dvb-frontends/cx22702.h
@@ -41,7 +41,7 @@ struct cx22702_config {
u8 output_mode;
};
-#if IS_ENABLED(CONFIG_DVB_CX22702)
+#if IS_REACHABLE(CONFIG_DVB_CX22702)
extern struct dvb_frontend *cx22702_attach(
const struct cx22702_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h
index 527aff1..d5453ed 100644
--- a/drivers/media/dvb-frontends/cx24110.h
+++ b/drivers/media/dvb-frontends/cx24110.h
@@ -46,7 +46,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
return 0;
}
-#if IS_ENABLED(CONFIG_DVB_CX24110)
+#if IS_REACHABLE(CONFIG_DVB_CX24110)
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h
index 782711ba..962919b 100644
--- a/drivers/media/dvb-frontends/cx24113.h
+++ b/drivers/media/dvb-frontends/cx24113.h
@@ -32,7 +32,7 @@ struct cx24113_config {
u32 xtal_khz;
};
-#if IS_ENABLED(CONFIG_DVB_TUNER_CX24113)
+#if IS_REACHABLE(CONFIG_DVB_TUNER_CX24113)
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
const struct cx24113_config *config, struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h
index 2ec84fa..f6dbabc 100644
--- a/drivers/media/dvb-frontends/cx24116.h
+++ b/drivers/media/dvb-frontends/cx24116.h
@@ -41,7 +41,7 @@ struct cx24116_config {
u16 i2c_wr_max;
};
-#if IS_ENABLED(CONFIG_DVB_CX24116)
+#if IS_REACHABLE(CONFIG_DVB_CX24116)
extern struct dvb_frontend *cx24116_attach(
const struct cx24116_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24117.h b/drivers/media/dvb-frontends/cx24117.h
index 4e59e95..1648ab4 100644
--- a/drivers/media/dvb-frontends/cx24117.h
+++ b/drivers/media/dvb-frontends/cx24117.h
@@ -30,7 +30,7 @@ struct cx24117_config {
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_CX24117)
+#if IS_REACHABLE(CONFIG_DVB_CX24117)
extern struct dvb_frontend *cx24117_attach(
const struct cx24117_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h
index 102e70d..758aee5 100644
--- a/drivers/media/dvb-frontends/cx24123.h
+++ b/drivers/media/dvb-frontends/cx24123.h
@@ -39,7 +39,7 @@ struct cx24123_config {
void (*agc_callback) (struct dvb_frontend *);
};
-#if IS_ENABLED(CONFIG_DVB_CX24123)
+#if IS_REACHABLE(CONFIG_DVB_CX24123)
extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index 6095dbc..56d4276 100644
--- a/drivers/media/dvb-frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -72,7 +72,7 @@ struct cxd2820r_config {
};
-#if IS_ENABLED(CONFIG_DVB_CXD2820R)
+#if IS_REACHABLE(CONFIG_DVB_CXD2820R)
extern struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h
index 0c6befc..6c0b667 100644
--- a/drivers/media/dvb-frontends/dib0070.h
+++ b/drivers/media/dvb-frontends/dib0070.h
@@ -48,7 +48,7 @@ struct dib0070_config {
u8 vga_filter;
};
-#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0070)
+#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0070)
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h
index 6a09095..ad74bc8 100644
--- a/drivers/media/dvb-frontends/dib0090.h
+++ b/drivers/media/dvb-frontends/dib0090.h
@@ -75,7 +75,7 @@ struct dib0090_config {
u8 force_crystal_mode;
};
-#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0090)
+#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0090)
extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index 9b6c3bb..6ae9899 100644
--- a/drivers/media/dvb-frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -41,7 +41,7 @@ struct dib_fe_xfer_ops
int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
};
-#if IS_ENABLED(CONFIG_DVB_DIB3000MB)
+#if IS_REACHABLE(CONFIG_DVB_DIB3000MB)
extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
#else
diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h
index 129d142..74816f7 100644
--- a/drivers/media/dvb-frontends/dib3000mc.h
+++ b/drivers/media/dvb-frontends/dib3000mc.h
@@ -41,7 +41,7 @@ struct dib3000mc_config {
#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
#define DEFAULT_DIB3000P_I2C_ADDRESS 24
-#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
+#if IS_REACHABLE(CONFIG_DVB_DIB3000MC)
extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
u8 i2c_addr,
struct dib3000mc_config *cfg);
diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h
index b585413..6468c27 100644
--- a/drivers/media/dvb-frontends/dib7000m.h
+++ b/drivers/media/dvb-frontends/dib7000m.h
@@ -40,7 +40,7 @@ struct dib7000m_config {
#define DEFAULT_DIB7000M_I2C_ADDRESS 18
-#if IS_ENABLED(CONFIG_DVB_DIB7000M)
+#if IS_REACHABLE(CONFIG_DVB_DIB7000M)
extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
u8 i2c_addr,
struct dib7000m_config *cfg);
diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
index 1fea0e9..baa2789 100644
--- a/drivers/media/dvb-frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -66,7 +66,7 @@ struct dib7000p_ops {
struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
};
-#if IS_ENABLED(CONFIG_DVB_DIB7000P)
+#if IS_REACHABLE(CONFIG_DVB_DIB7000P)
void *dib7000p_attach(struct dib7000p_ops *ops);
#else
static inline void *dib7000p_attach(struct dib7000p_ops *ops)
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 84cc103..780c37b 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -63,7 +63,7 @@ struct dib8000_ops {
struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
};
-#if IS_ENABLED(CONFIG_DVB_DIB8000)
+#if IS_REACHABLE(CONFIG_DVB_DIB8000)
void *dib8000_attach(struct dib8000_ops *ops);
#else
static inline int dib8000_attach(struct dib8000_ops *ops)
diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h
index f3639f0..b10a70a 100644
--- a/drivers/media/dvb-frontends/dib9000.h
+++ b/drivers/media/dvb-frontends/dib9000.h
@@ -27,7 +27,7 @@ struct dib9000_config {
#define DEFAULT_DIB9000_I2C_ADDRESS 18
-#if IS_ENABLED(CONFIG_DVB_DIB9000)
+#if IS_REACHABLE(CONFIG_DVB_DIB9000)
extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
index cfd0b96..8188062 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
+++ b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
@@ -34,7 +34,7 @@ struct drx39xxj_state {
const struct firmware *fw;
};
-#if IS_ENABLED(CONFIG_DVB_DRX39XYJ)
+#if IS_REACHABLE(CONFIG_DVB_DRX39XYJ)
struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) {
diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
index d998e4d..a47c22d 100644
--- a/drivers/media/dvb-frontends/drxd.h
+++ b/drivers/media/dvb-frontends/drxd.h
@@ -52,7 +52,7 @@ struct drxd_config {
s16(*osc_deviation) (void *priv, s16 dev, int flag);
};
-#if IS_ENABLED(CONFIG_DVB_DRXD)
+#if IS_REACHABLE(CONFIG_DVB_DRXD)
extern
struct dvb_frontend *drxd_attach(const struct drxd_config *config,
void *priv, struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
index f6cb346..8f0b9ee 100644
--- a/drivers/media/dvb-frontends/drxk.h
+++ b/drivers/media/dvb-frontends/drxk.h
@@ -51,7 +51,7 @@ struct drxk_config {
int qam_demod_parameter_count;
};
-#if IS_ENABLED(CONFIG_DVB_DRXK)
+#if IS_REACHABLE(CONFIG_DVB_DRXK)
extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
index f9c21fb..153169d 100644
--- a/drivers/media/dvb-frontends/ds3000.h
+++ b/drivers/media/dvb-frontends/ds3000.h
@@ -35,7 +35,7 @@ struct ds3000_config {
void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
-#if IS_ENABLED(CONFIG_DVB_DS3000)
+#if IS_REACHABLE(CONFIG_DVB_DS3000)
extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
index f4b5a06..bf9602a 100644
--- a/drivers/media/dvb-frontends/dvb-pll.h
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -38,7 +38,7 @@
* @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
-#if IS_ENABLED(CONFIG_DVB_PLL)
+#if IS_REACHABLE(CONFIG_DVB_PLL)
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h
index 0cbf961..15e4cea 100644
--- a/drivers/media/dvb-frontends/dvb_dummy_fe.h
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h
@@ -26,7 +26,7 @@
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
-#if IS_ENABLED(CONFIG_DVB_DUMMY_FE)
+#if IS_REACHABLE(CONFIG_DVB_DUMMY_FE)
extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h
index 3755840..9544bab 100644
--- a/drivers/media/dvb-frontends/ec100.h
+++ b/drivers/media/dvb-frontends/ec100.h
@@ -31,7 +31,7 @@ struct ec100_config {
};
-#if IS_ENABLED(CONFIG_DVB_EC100)
+#if IS_REACHABLE(CONFIG_DVB_EC100)
extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h
index 05cd130..48e9ab7 100644
--- a/drivers/media/dvb-frontends/hd29l2.h
+++ b/drivers/media/dvb-frontends/hd29l2.h
@@ -51,7 +51,7 @@ struct hd29l2_config {
};
-#if IS_ENABLED(CONFIG_DVB_HD29L2)
+#if IS_REACHABLE(CONFIG_DVB_HD29L2)
extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
index 8abb70c..3c148b8 100644
--- a/drivers/media/dvb-frontends/isl6405.h
+++ b/drivers/media/dvb-frontends/isl6405.h
@@ -55,7 +55,7 @@
#define ISL6405_ENT2 0x20
#define ISL6405_ISEL2 0x40
-#if IS_ENABLED(CONFIG_DVB_ISL6405)
+#if IS_REACHABLE(CONFIG_DVB_ISL6405)
/* override_set and override_clear control which system register bits (above)
* to always set & clear
*/
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index 630e7f8..3273597 100644
--- a/drivers/media/dvb-frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -39,7 +39,7 @@
#define ISL6421_ISEL1 0x20
#define ISL6421_DCL 0x40
-#if IS_ENABLED(CONFIG_DVB_ISL6421)
+#if IS_REACHABLE(CONFIG_DVB_ISL6421)
/* override_set and override_clear control which system register bits (above) to always set & clear */
extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
u8 override_set, u8 override_clear, bool override_tone);
diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h
index 80dfd9c..a64df0e 100644
--- a/drivers/media/dvb-frontends/isl6423.h
+++ b/drivers/media/dvb-frontends/isl6423.h
@@ -42,7 +42,7 @@ struct isl6423_config {
u8 mod_extern;
};
-#if IS_ENABLED(CONFIG_DVB_ISL6423)
+#if IS_REACHABLE(CONFIG_DVB_ISL6423)
extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h
index edae090..a691bb6 100644
--- a/drivers/media/dvb-frontends/itd1000.h
+++ b/drivers/media/dvb-frontends/itd1000.h
@@ -29,7 +29,7 @@ struct itd1000_config {
u8 i2c_address;
};
-#if IS_ENABLED(CONFIG_DVB_TUNER_ITD1000)
+#if IS_REACHABLE(CONFIG_DVB_TUNER_ITD1000)
extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
#else
static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h
index 1a735a7..af107a2 100644
--- a/drivers/media/dvb-frontends/ix2505v.h
+++ b/drivers/media/dvb-frontends/ix2505v.h
@@ -49,7 +49,7 @@ struct ix2505v_config {
};
-#if IS_ENABLED(CONFIG_DVB_IX2505V)
+#if IS_REACHABLE(CONFIG_DVB_IX2505V)
extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
const struct ix2505v_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h
index 6813b08..8697e2c 100644
--- a/drivers/media/dvb-frontends/l64781.h
+++ b/drivers/media/dvb-frontends/l64781.h
@@ -31,7 +31,7 @@ struct l64781_config
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_L64781)
+#if IS_REACHABLE(CONFIG_DVB_L64781)
extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h
index 194a07a..d20bd90 100644
--- a/drivers/media/dvb-frontends/lg2160.h
+++ b/drivers/media/dvb-frontends/lg2160.h
@@ -67,7 +67,7 @@ struct lg2160_config {
enum lg_chip_type lg_chip;
};
-#if IS_ENABLED(CONFIG_DVB_LG2160)
+#if IS_REACHABLE(CONFIG_DVB_LG2160)
extern
struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h
index 9c03e53..f91a1b4 100644
--- a/drivers/media/dvb-frontends/lgdt3305.h
+++ b/drivers/media/dvb-frontends/lgdt3305.h
@@ -80,7 +80,7 @@ struct lgdt3305_config {
enum lgdt_demod_chip_type demod_chip;
};
-#if IS_ENABLED(CONFIG_DVB_LGDT3305)
+#if IS_REACHABLE(CONFIG_DVB_LGDT3305)
extern
struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
new file mode 100644
index 0000000..d9a2b0e
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -0,0 +1,2144 @@
+/*
+ * Support for LGDT3306A - 8VSB/QAM-B
+ *
+ * Copyright (C) 2013 Fred Richter <frichter@hauppauge.com>
+ * - driver structure based on lgdt3305.[ch] by Michael Krufky
+ * - code based on LG3306_V0.35 API by LG Electronics Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <asm/div64.h>
+#include <linux/dvb/frontend.h>
+#include "dvb_math.h"
+#include "lgdt3306a.h"
+
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG 2
+#define DBG_DUMP 4 /* FGR - comment out to remove dump code */
+
+#define lg_debug(fmt, arg...) \
+ printk(KERN_DEBUG pr_fmt(fmt), ## arg)
+
+#define dbg_info(fmt, arg...) \
+ do { \
+ if (debug & DBG_INFO) \
+ lg_debug(fmt, ## arg); \
+ } while (0)
+
+#define dbg_reg(fmt, arg...) \
+ do { \
+ if (debug & DBG_REG) \
+ lg_debug(fmt, ## arg); \
+ } while (0)
+
+#define lg_chkerr(ret) \
+({ \
+ int __ret; \
+ __ret = (ret < 0); \
+ if (__ret) \
+ pr_err("error %d on line %d\n", ret, __LINE__); \
+ __ret; \
+})
+
+struct lgdt3306a_state {
+ struct i2c_adapter *i2c_adap;
+ const struct lgdt3306a_config *cfg;
+
+ struct dvb_frontend frontend;
+
+ fe_modulation_t current_modulation;
+ u32 current_frequency;
+ u32 snr;
+};
+
+/*
+ * LG3306A Register Usage
+ * (LG does not really name the registers, so this code does not either)
+ *
+ * 0000 -> 00FF Common control and status
+ * 1000 -> 10FF Synchronizer control and status
+ * 1F00 -> 1FFF Smart Antenna control and status
+ * 2100 -> 21FF VSB Equalizer control and status
+ * 2800 -> 28FF QAM Equalizer control and status
+ * 3000 -> 30FF FEC control and status
+ */
+
+enum lgdt3306a_lock_status {
+ LG3306_UNLOCK = 0x00,
+ LG3306_LOCK = 0x01,
+ LG3306_UNKNOWN_LOCK = 0xff
+};
+
+enum lgdt3306a_neverlock_status {
+ LG3306_NL_INIT = 0x00,
+ LG3306_NL_PROCESS = 0x01,
+ LG3306_NL_LOCK = 0x02,
+ LG3306_NL_FAIL = 0x03,
+ LG3306_NL_UNKNOWN = 0xff
+};
+
+enum lgdt3306a_modulation {
+ LG3306_VSB = 0x00,
+ LG3306_QAM64 = 0x01,
+ LG3306_QAM256 = 0x02,
+ LG3306_UNKNOWN_MODE = 0xff
+};
+
+enum lgdt3306a_lock_check {
+ LG3306_SYNC_LOCK,
+ LG3306_FEC_LOCK,
+ LG3306_TR_LOCK,
+ LG3306_AGC_LOCK,
+};
+
+
+#ifdef DBG_DUMP
+static void lgdt3306a_DumpAllRegs(struct lgdt3306a_state *state);
+static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state);
+#endif
+
+
+static int lgdt3306a_write_reg(struct lgdt3306a_state *state, u16 reg, u8 val)
+{
+ int ret;
+ u8 buf[] = { reg >> 8, reg & 0xff, val };
+ struct i2c_msg msg = {
+ .addr = state->cfg->i2c_addr, .flags = 0,
+ .buf = buf, .len = 3,
+ };
+
+ dbg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+ ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+ if (ret != 1) {
+ pr_err("error (addr %02x %02x <- %02x, err = %i)\n",
+ msg.buf[0], msg.buf[1], msg.buf[2], ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int lgdt3306a_read_reg(struct lgdt3306a_state *state, u16 reg, u8 *val)
+{
+ int ret;
+ u8 reg_buf[] = { reg >> 8, reg & 0xff };
+ struct i2c_msg msg[] = {
+ { .addr = state->cfg->i2c_addr,
+ .flags = 0, .buf = reg_buf, .len = 2 },
+ { .addr = state->cfg->i2c_addr,
+ .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ pr_err("error (addr %02x reg %04x error (ret == %i)\n",
+ state->cfg->i2c_addr, reg, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+ dbg_reg("reg: 0x%04x, val: 0x%02x\n", reg, *val);
+
+ return 0;
+}
+
+#define read_reg(state, reg) \
+({ \
+ u8 __val; \
+ int ret = lgdt3306a_read_reg(state, reg, &__val); \
+ if (lg_chkerr(ret)) \
+ __val = 0; \
+ __val; \
+})
+
+static int lgdt3306a_set_reg_bit(struct lgdt3306a_state *state,
+ u16 reg, int bit, int onoff)
+{
+ u8 val;
+ int ret;
+
+ dbg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+ ret = lgdt3306a_read_reg(state, reg, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ val &= ~(1 << bit);
+ val |= (onoff & 1) << bit;
+
+ ret = lgdt3306a_write_reg(state, reg, val);
+ lg_chkerr(ret);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3306a_soft_reset(struct lgdt3306a_state *state)
+{
+ int ret;
+
+ dbg_info("\n");
+
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ msleep(20);
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 1);
+ lg_chkerr(ret);
+
+fail:
+ return ret;
+}
+
+static int lgdt3306a_mpeg_mode(struct lgdt3306a_state *state,
+ enum lgdt3306a_mpeg_mode mode)
+{
+ u8 val;
+ int ret;
+
+ dbg_info("(%d)\n", mode);
+ /* transport packet format - TPSENB=0x80 */
+ ret = lgdt3306a_set_reg_bit(state, 0x0071, 7,
+ mode == LGDT3306A_MPEG_PARALLEL ? 1 : 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /*
+ * start of packet signal duration
+ * TPSSOPBITEN=0x40; 0=byte duration, 1=bit duration
+ */
+ ret = lgdt3306a_set_reg_bit(state, 0x0071, 6, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_read_reg(state, 0x0070, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ val |= 0x10; /* TPCLKSUPB=0x10 */
+
+ if (mode == LGDT3306A_MPEG_PARALLEL)
+ val &= ~0x10;
+
+ ret = lgdt3306a_write_reg(state, 0x0070, val);
+ lg_chkerr(ret);
+
+fail:
+ return ret;
+}
+
+static int lgdt3306a_mpeg_mode_polarity(struct lgdt3306a_state *state,
+ enum lgdt3306a_tp_clock_edge edge,
+ enum lgdt3306a_tp_valid_polarity valid)
+{
+ u8 val;
+ int ret;
+
+ dbg_info("edge=%d, valid=%d\n", edge, valid);
+
+ ret = lgdt3306a_read_reg(state, 0x0070, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ val &= ~0x06; /* TPCLKPOL=0x04, TPVALPOL=0x02 */
+
+ if (edge == LGDT3306A_TPCLK_RISING_EDGE)
+ val |= 0x04;
+ if (valid == LGDT3306A_TP_VALID_HIGH)
+ val |= 0x02;
+
+ ret = lgdt3306a_write_reg(state, 0x0070, val);
+ lg_chkerr(ret);
+
+fail:
+ return ret;
+}
+
+static int lgdt3306a_mpeg_tristate(struct lgdt3306a_state *state,
+ int mode)
+{
+ u8 val;
+ int ret;
+
+ dbg_info("(%d)\n", mode);
+
+ if (mode) {
+ ret = lgdt3306a_read_reg(state, 0x0070, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ /*
+ * Tristate bus; TPOUTEN=0x80, TPCLKOUTEN=0x20,
+ * TPDATAOUTEN=0x08
+ */
+ val &= ~0xa8;
+ ret = lgdt3306a_write_reg(state, 0x0070, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* AGCIFOUTENB=0x40; 1=Disable IFAGC pin */
+ ret = lgdt3306a_set_reg_bit(state, 0x0003, 6, 1);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ } else {
+ /* enable IFAGC pin */
+ ret = lgdt3306a_set_reg_bit(state, 0x0003, 6, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_read_reg(state, 0x0070, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ val |= 0xa8; /* enable bus */
+ ret = lgdt3306a_write_reg(state, 0x0070, val);
+ if (lg_chkerr(ret))
+ goto fail;
+ }
+
+fail:
+ return ret;
+}
+
+static int lgdt3306a_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ dbg_info("acquire=%d\n", acquire);
+
+ return lgdt3306a_mpeg_tristate(state, acquire ? 0 : 1);
+
+}
+
+static int lgdt3306a_power(struct lgdt3306a_state *state,
+ int mode)
+{
+ int ret;
+
+ dbg_info("(%d)\n", mode);
+
+ if (mode == 0) {
+ /* into reset */
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* power down */
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 0, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ } else {
+ /* out of reset */
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 1);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* power up */
+ ret = lgdt3306a_set_reg_bit(state, 0x0000, 0, 1);
+ if (lg_chkerr(ret))
+ goto fail;
+ }
+
+#ifdef DBG_DUMP
+ lgdt3306a_DumpAllRegs(state);
+#endif
+fail:
+ return ret;
+}
+
+
+static int lgdt3306a_set_vsb(struct lgdt3306a_state *state)
+{
+ u8 val;
+ int ret;
+
+ dbg_info("\n");
+
+ /* 0. Spectrum inversion detection manual; spectrum inverted */
+ ret = lgdt3306a_read_reg(state, 0x0002, &val);
+ val &= 0xf7; /* SPECINVAUTO Off */
+ val |= 0x04; /* SPECINV On */
+ ret = lgdt3306a_write_reg(state, 0x0002, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 1. Selection of standard mode(0x08=QAM, 0x80=VSB) */
+ ret = lgdt3306a_write_reg(state, 0x0008, 0x80);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 2. Bandwidth mode for VSB(6MHz) */
+ ret = lgdt3306a_read_reg(state, 0x0009, &val);
+ val &= 0xe3;
+ val |= 0x0c; /* STDOPDETTMODE[2:0]=3 */
+ ret = lgdt3306a_write_reg(state, 0x0009, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 3. QAM mode detection mode(None) */
+ ret = lgdt3306a_read_reg(state, 0x0009, &val);
+ val &= 0xfc; /* STDOPDETCMODE[1:0]=0 */
+ ret = lgdt3306a_write_reg(state, 0x0009, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 4. ADC sampling frequency rate(2x sampling) */
+ ret = lgdt3306a_read_reg(state, 0x000d, &val);
+ val &= 0xbf; /* SAMPLING4XFEN=0 */
+ ret = lgdt3306a_write_reg(state, 0x000d, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+#if 0
+ /* FGR - disable any AICC filtering, testing only */
+
+ ret = lgdt3306a_write_reg(state, 0x0024, 0x00);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* AICCFIXFREQ0 NT N-1(Video rejection) */
+ ret = lgdt3306a_write_reg(state, 0x002e, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002f, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0030, 0x00);
+
+ /* AICCFIXFREQ1 NT N-1(Audio rejection) */
+ ret = lgdt3306a_write_reg(state, 0x002b, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002c, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002d, 0x00);
+
+ /* AICCFIXFREQ2 NT Co-Channel(Video rejection) */
+ ret = lgdt3306a_write_reg(state, 0x0028, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0029, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002a, 0x00);
+
+ /* AICCFIXFREQ3 NT Co-Channel(Audio rejection) */
+ ret = lgdt3306a_write_reg(state, 0x0025, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0026, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0027, 0x00);
+
+#else
+ /* FGR - this works well for HVR-1955,1975 */
+
+ /* 5. AICCOPMODE NT N-1 Adj. */
+ ret = lgdt3306a_write_reg(state, 0x0024, 0x5A);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* AICCFIXFREQ0 NT N-1(Video rejection) */
+ ret = lgdt3306a_write_reg(state, 0x002e, 0x5A);
+ ret = lgdt3306a_write_reg(state, 0x002f, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0030, 0x00);
+
+ /* AICCFIXFREQ1 NT N-1(Audio rejection) */
+ ret = lgdt3306a_write_reg(state, 0x002b, 0x36);
+ ret = lgdt3306a_write_reg(state, 0x002c, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002d, 0x00);
+
+ /* AICCFIXFREQ2 NT Co-Channel(Video rejection) */
+ ret = lgdt3306a_write_reg(state, 0x0028, 0x2A);
+ ret = lgdt3306a_write_reg(state, 0x0029, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x002a, 0x00);
+
+ /* AICCFIXFREQ3 NT Co-Channel(Audio rejection) */
+ ret = lgdt3306a_write_reg(state, 0x0025, 0x06);
+ ret = lgdt3306a_write_reg(state, 0x0026, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x0027, 0x00);
+#endif
+
+ ret = lgdt3306a_read_reg(state, 0x001e, &val);
+ val &= 0x0f;
+ val |= 0xa0;
+ ret = lgdt3306a_write_reg(state, 0x001e, val);
+
+ ret = lgdt3306a_write_reg(state, 0x0022, 0x08);
+
+ ret = lgdt3306a_write_reg(state, 0x0023, 0xFF);
+
+ ret = lgdt3306a_read_reg(state, 0x211f, &val);
+ val &= 0xef;
+ ret = lgdt3306a_write_reg(state, 0x211f, val);
+
+ ret = lgdt3306a_write_reg(state, 0x2173, 0x01);
+
+ ret = lgdt3306a_read_reg(state, 0x1061, &val);
+ val &= 0xf8;
+ val |= 0x04;
+ ret = lgdt3306a_write_reg(state, 0x1061, val);
+
+ ret = lgdt3306a_read_reg(state, 0x103d, &val);
+ val &= 0xcf;
+ ret = lgdt3306a_write_reg(state, 0x103d, val);
+
+ ret = lgdt3306a_write_reg(state, 0x2122, 0x40);
+
+ ret = lgdt3306a_read_reg(state, 0x2141, &val);
+ val &= 0x3f;
+ ret = lgdt3306a_write_reg(state, 0x2141, val);
+
+ ret = lgdt3306a_read_reg(state, 0x2135, &val);
+ val &= 0x0f;
+ val |= 0x70;
+ ret = lgdt3306a_write_reg(state, 0x2135, val);
+
+ ret = lgdt3306a_read_reg(state, 0x0003, &val);
+ val &= 0xf7;
+ ret = lgdt3306a_write_reg(state, 0x0003, val);
+
+ ret = lgdt3306a_read_reg(state, 0x001c, &val);
+ val &= 0x7f;
+ ret = lgdt3306a_write_reg(state, 0x001c, val);
+
+ /* 6. EQ step size */
+ ret = lgdt3306a_read_reg(state, 0x2179, &val);
+ val &= 0xf8;
+ ret = lgdt3306a_write_reg(state, 0x2179, val);
+
+ ret = lgdt3306a_read_reg(state, 0x217a, &val);
+ val &= 0xf8;
+ ret = lgdt3306a_write_reg(state, 0x217a, val);
+
+ /* 7. Reset */
+ ret = lgdt3306a_soft_reset(state);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ dbg_info("complete\n");
+fail:
+ return ret;
+}
+
+static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
+{
+ u8 val;
+ int ret;
+
+ dbg_info("modulation=%d\n", modulation);
+
+ /* 1. Selection of standard mode(0x08=QAM, 0x80=VSB) */
+ ret = lgdt3306a_write_reg(state, 0x0008, 0x08);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 1a. Spectrum inversion detection to Auto */
+ ret = lgdt3306a_read_reg(state, 0x0002, &val);
+ val &= 0xfb; /* SPECINV Off */
+ val |= 0x08; /* SPECINVAUTO On */
+ ret = lgdt3306a_write_reg(state, 0x0002, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 2. Bandwidth mode for QAM */
+ ret = lgdt3306a_read_reg(state, 0x0009, &val);
+ val &= 0xe3; /* STDOPDETTMODE[2:0]=0 VSB Off */
+ ret = lgdt3306a_write_reg(state, 0x0009, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 3. : 64QAM/256QAM detection(manual, auto) */
+ ret = lgdt3306a_read_reg(state, 0x0009, &val);
+ val &= 0xfc;
+ val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */
+ ret = lgdt3306a_write_reg(state, 0x0009, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 3a. : 64QAM/256QAM selection for manual */
+ ret = lgdt3306a_read_reg(state, 0x101a, &val);
+ val &= 0xf8;
+ if (modulation == QAM_64)
+ val |= 0x02; /* QMDQMODE[2:0]=2=QAM64 */
+ else
+ val |= 0x04; /* QMDQMODE[2:0]=4=QAM256 */
+
+ ret = lgdt3306a_write_reg(state, 0x101a, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 4. ADC sampling frequency rate(4x sampling) */
+ ret = lgdt3306a_read_reg(state, 0x000d, &val);
+ val &= 0xbf;
+ val |= 0x40; /* SAMPLING4XFEN=1 */
+ ret = lgdt3306a_write_reg(state, 0x000d, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 5. No AICC operation in QAM mode */
+ ret = lgdt3306a_read_reg(state, 0x0024, &val);
+ val &= 0x00;
+ ret = lgdt3306a_write_reg(state, 0x0024, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 6. Reset */
+ ret = lgdt3306a_soft_reset(state);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ dbg_info("complete\n");
+fail:
+ return ret;
+}
+
+static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
+ struct dtv_frontend_properties *p)
+{
+ int ret;
+
+ dbg_info("\n");
+
+ switch (p->modulation) {
+ case VSB_8:
+ ret = lgdt3306a_set_vsb(state);
+ break;
+ case QAM_64:
+ ret = lgdt3306a_set_qam(state, QAM_64);
+ break;
+ case QAM_256:
+ ret = lgdt3306a_set_qam(state, QAM_256);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (lg_chkerr(ret))
+ goto fail;
+
+ state->current_modulation = p->modulation;
+
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
+ struct dtv_frontend_properties *p)
+{
+ /* TODO: anything we want to do here??? */
+ dbg_info("\n");
+
+ switch (p->modulation) {
+ case VSB_8:
+ break;
+ case QAM_64:
+ case QAM_256:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3306a_set_inversion(struct lgdt3306a_state *state,
+ int inversion)
+{
+ int ret;
+
+ dbg_info("(%d)\n", inversion);
+
+ ret = lgdt3306a_set_reg_bit(state, 0x0002, 2, inversion ? 1 : 0);
+ return ret;
+}
+
+static int lgdt3306a_set_inversion_auto(struct lgdt3306a_state *state,
+ int enabled)
+{
+ int ret;
+
+ dbg_info("(%d)\n", enabled);
+
+ /* 0=Manual 1=Auto(QAM only) - SPECINVAUTO=0x04 */
+ ret = lgdt3306a_set_reg_bit(state, 0x0002, 3, enabled);
+ return ret;
+}
+
+static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
+ struct dtv_frontend_properties *p,
+ int inversion)
+{
+ int ret = 0;
+
+ dbg_info("(%d)\n", inversion);
+#if 0
+ /*
+ * FGR - spectral_inversion defaults already set for VSB and QAM;
+ * can enable later if desired
+ */
+
+ ret = lgdt3306a_set_inversion(state, inversion);
+
+ switch (p->modulation) {
+ case VSB_8:
+ /* Manual only for VSB */
+ ret = lgdt3306a_set_inversion_auto(state, 0);
+ break;
+ case QAM_64:
+ case QAM_256:
+ /* Auto ok for QAM */
+ ret = lgdt3306a_set_inversion_auto(state, 1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+#endif
+ return ret;
+}
+
+static int lgdt3306a_set_if(struct lgdt3306a_state *state,
+ struct dtv_frontend_properties *p)
+{
+ int ret;
+ u16 if_freq_khz;
+ u8 nco1, nco2;
+
+ switch (p->modulation) {
+ case VSB_8:
+ if_freq_khz = state->cfg->vsb_if_khz;
+ break;
+ case QAM_64:
+ case QAM_256:
+ if_freq_khz = state->cfg->qam_if_khz;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (if_freq_khz) {
+ default:
+ pr_warn("IF=%d KHz is not supportted, 3250 assumed\n",
+ if_freq_khz);
+ /* fallthrough */
+ case 3250: /* 3.25Mhz */
+ nco1 = 0x34;
+ nco2 = 0x00;
+ break;
+ case 3500: /* 3.50Mhz */
+ nco1 = 0x38;
+ nco2 = 0x00;
+ break;
+ case 4000: /* 4.00Mhz */
+ nco1 = 0x40;
+ nco2 = 0x00;
+ break;
+ case 5000: /* 5.00Mhz */
+ nco1 = 0x50;
+ nco2 = 0x00;
+ break;
+ case 5380: /* 5.38Mhz */
+ nco1 = 0x56;
+ nco2 = 0x14;
+ break;
+ }
+ ret = lgdt3306a_write_reg(state, 0x0010, nco1);
+ if (ret)
+ return ret;
+ ret = lgdt3306a_write_reg(state, 0x0011, nco2);
+ if (ret)
+ return ret;
+
+ dbg_info("if_freq=%d KHz->[%04x]\n", if_freq_khz, nco1<<8 | nco2);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3306a_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ if (state->cfg->deny_i2c_rptr) {
+ dbg_info("deny_i2c_rptr=%d\n", state->cfg->deny_i2c_rptr);
+ return 0;
+ }
+ dbg_info("(%d)\n", enable);
+
+ /* NI2CRPTEN=0x80 */
+ return lgdt3306a_set_reg_bit(state, 0x0002, 7, enable ? 0 : 1);
+}
+
+static int lgdt3306a_sleep(struct lgdt3306a_state *state)
+{
+ int ret;
+
+ dbg_info("\n");
+ state->current_frequency = -1; /* force re-tune, when we wake */
+
+ ret = lgdt3306a_mpeg_tristate(state, 1); /* disable data bus */
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_power(state, 0); /* power down */
+ lg_chkerr(ret);
+
+fail:
+ return 0;
+}
+
+static int lgdt3306a_fe_sleep(struct dvb_frontend *fe)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ return lgdt3306a_sleep(state);
+}
+
+static int lgdt3306a_init(struct dvb_frontend *fe)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ u8 val;
+ int ret;
+
+ dbg_info("\n");
+
+ /* 1. Normal operation mode */
+ ret = lgdt3306a_set_reg_bit(state, 0x0001, 0, 1); /* SIMFASTENB=0x01 */
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 2. Spectrum inversion auto detection (Not valid for VSB) */
+ ret = lgdt3306a_set_inversion_auto(state, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 3. Spectrum inversion(According to the tuner configuration) */
+ ret = lgdt3306a_set_inversion(state, 1);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 4. Peak-to-peak voltage of ADC input signal */
+
+ /* ADCSEL1V=0x80=1Vpp; 0x00=2Vpp */
+ ret = lgdt3306a_set_reg_bit(state, 0x0004, 7, 1);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 5. ADC output data capture clock phase */
+
+ /* 0=same phase as ADC clock */
+ ret = lgdt3306a_set_reg_bit(state, 0x0004, 2, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 5a. ADC sampling clock source */
+
+ /* ADCCLKPLLSEL=0x08; 0=use ext clock, not PLL */
+ ret = lgdt3306a_set_reg_bit(state, 0x0004, 3, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 6. Automatic PLL set */
+
+ /* PLLSETAUTO=0x40; 0=off */
+ ret = lgdt3306a_set_reg_bit(state, 0x0005, 6, 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ if (state->cfg->xtalMHz == 24) { /* 24MHz */
+ /* 7. Frequency for PLL output(0x2564 for 192MHz for 24MHz) */
+ ret = lgdt3306a_read_reg(state, 0x0005, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ val &= 0xc0;
+ val |= 0x25;
+ ret = lgdt3306a_write_reg(state, 0x0005, val);
+ if (lg_chkerr(ret))
+ goto fail;
+ ret = lgdt3306a_write_reg(state, 0x0006, 0x64);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 8. ADC sampling frequency(0x180000 for 24MHz sampling) */
+ ret = lgdt3306a_read_reg(state, 0x000d, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ val &= 0xc0;
+ val |= 0x18;
+ ret = lgdt3306a_write_reg(state, 0x000d, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ } else if (state->cfg->xtalMHz == 25) { /* 25MHz */
+ /* 7. Frequency for PLL output */
+ ret = lgdt3306a_read_reg(state, 0x0005, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ val &= 0xc0;
+ val |= 0x25;
+ ret = lgdt3306a_write_reg(state, 0x0005, val);
+ if (lg_chkerr(ret))
+ goto fail;
+ ret = lgdt3306a_write_reg(state, 0x0006, 0x64);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 8. ADC sampling frequency(0x190000 for 25MHz sampling) */
+ ret = lgdt3306a_read_reg(state, 0x000d, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ val &= 0xc0;
+ val |= 0x19;
+ ret = lgdt3306a_write_reg(state, 0x000d, val);
+ if (lg_chkerr(ret))
+ goto fail;
+ } else {
+ pr_err("Bad xtalMHz=%d\n", state->cfg->xtalMHz);
+ }
+#if 0
+ ret = lgdt3306a_write_reg(state, 0x000e, 0x00);
+ ret = lgdt3306a_write_reg(state, 0x000f, 0x00);
+#endif
+
+ /* 9. Center frequency of input signal of ADC */
+ ret = lgdt3306a_write_reg(state, 0x0010, 0x34); /* 3.25MHz */
+ ret = lgdt3306a_write_reg(state, 0x0011, 0x00);
+
+ /* 10. Fixed gain error value */
+ ret = lgdt3306a_write_reg(state, 0x0014, 0); /* gain error=0 */
+
+ /* 10a. VSB TR BW gear shift initial step */
+ ret = lgdt3306a_read_reg(state, 0x103c, &val);
+ val &= 0x0f;
+ val |= 0x20; /* SAMGSAUTOSTL_V[3:0] = 2 */
+ ret = lgdt3306a_write_reg(state, 0x103c, val);
+
+ /* 10b. Timing offset calibration in low temperature for VSB */
+ ret = lgdt3306a_read_reg(state, 0x103d, &val);
+ val &= 0xfc;
+ val |= 0x03;
+ ret = lgdt3306a_write_reg(state, 0x103d, val);
+
+ /* 10c. Timing offset calibration in low temperature for QAM */
+ ret = lgdt3306a_read_reg(state, 0x1036, &val);
+ val &= 0xf0;
+ val |= 0x0c;
+ ret = lgdt3306a_write_reg(state, 0x1036, val);
+
+ /* 11. Using the imaginary part of CIR in CIR loading */
+ ret = lgdt3306a_read_reg(state, 0x211f, &val);
+ val &= 0xef; /* do not use imaginary of CIR */
+ ret = lgdt3306a_write_reg(state, 0x211f, val);
+
+ /* 12. Control of no signal detector function */
+ ret = lgdt3306a_read_reg(state, 0x2849, &val);
+ val &= 0xef; /* NOUSENOSIGDET=0, enable no signal detector */
+ ret = lgdt3306a_write_reg(state, 0x2849, val);
+
+ /* FGR - put demod in some known mode */
+ ret = lgdt3306a_set_vsb(state);
+
+ /* 13. TP stream format */
+ ret = lgdt3306a_mpeg_mode(state, state->cfg->mpeg_mode);
+
+ /* 14. disable output buses */
+ ret = lgdt3306a_mpeg_tristate(state, 1);
+
+ /* 15. Sleep (in reset) */
+ ret = lgdt3306a_sleep(state);
+ lg_chkerr(ret);
+
+fail:
+ return ret;
+}
+
+static int lgdt3306a_set_parameters(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ int ret;
+
+ dbg_info("(%d, %d)\n", p->frequency, p->modulation);
+
+ if (state->current_frequency == p->frequency &&
+ state->current_modulation == p->modulation) {
+ dbg_info(" (already set, skipping ...)\n");
+ return 0;
+ }
+ state->current_frequency = -1;
+ state->current_modulation = -1;
+
+ ret = lgdt3306a_power(state, 1); /* power up */
+ if (lg_chkerr(ret))
+ goto fail;
+
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+#if 0
+ if (lg_chkerr(ret))
+ goto fail;
+ state->current_frequency = p->frequency;
+#endif
+ }
+
+ ret = lgdt3306a_set_modulation(state, p);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_agc_setup(state, p);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_set_if(state, p);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_spectral_inversion(state, p,
+ state->cfg->spectral_inversion ? 1 : 0);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_mpeg_mode(state, state->cfg->mpeg_mode);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_mpeg_mode_polarity(state,
+ state->cfg->tpclk_edge,
+ state->cfg->tpvalid_polarity);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_mpeg_tristate(state, 0); /* enable data bus */
+ if (lg_chkerr(ret))
+ goto fail;
+
+ ret = lgdt3306a_soft_reset(state);
+ if (lg_chkerr(ret))
+ goto fail;
+
+#ifdef DBG_DUMP
+ lgdt3306a_DumpAllRegs(state);
+#endif
+ state->current_frequency = p->frequency;
+fail:
+ return ret;
+}
+
+static int lgdt3306a_get_frontend(struct dvb_frontend *fe)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+ dbg_info("(%u, %d)\n",
+ state->current_frequency, state->current_modulation);
+
+ p->modulation = state->current_modulation;
+ p->frequency = state->current_frequency;
+ return 0;
+}
+
+static enum dvbfe_algo lgdt3306a_get_frontend_algo(struct dvb_frontend *fe)
+{
+#if 1
+ return DVBFE_ALGO_CUSTOM;
+#else
+ return DVBFE_ALGO_HW;
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+static int lgdt3306a_monitor_vsb(struct lgdt3306a_state *state)
+{
+ u8 val;
+ int ret;
+ u8 snrRef, maxPowerMan, nCombDet;
+ u16 fbDlyCir;
+
+ ret = lgdt3306a_read_reg(state, 0x21a1, &val);
+ if (ret)
+ return ret;
+ snrRef = val & 0x3f;
+
+ ret = lgdt3306a_read_reg(state, 0x2185, &maxPowerMan);
+ if (ret)
+ return ret;
+
+ ret = lgdt3306a_read_reg(state, 0x2191, &val);
+ if (ret)
+ return ret;
+ nCombDet = (val & 0x80) >> 7;
+
+ ret = lgdt3306a_read_reg(state, 0x2180, &val);
+ if (ret)
+ return ret;
+ fbDlyCir = (val & 0x03) << 8;
+
+ ret = lgdt3306a_read_reg(state, 0x2181, &val);
+ if (ret)
+ return ret;
+ fbDlyCir |= val;
+
+ dbg_info("snrRef=%d maxPowerMan=0x%x nCombDet=%d fbDlyCir=0x%x\n",
+ snrRef, maxPowerMan, nCombDet, fbDlyCir);
+
+ /* Carrier offset sub loop bandwidth */
+ ret = lgdt3306a_read_reg(state, 0x1061, &val);
+ if (ret)
+ return ret;
+ val &= 0xf8;
+ if ((snrRef > 18) && (maxPowerMan > 0x68)
+ && (nCombDet == 0x01)
+ && ((fbDlyCir == 0x03FF) || (fbDlyCir < 0x6C))) {
+ /* SNR is over 18dB and no ghosting */
+ val |= 0x00; /* final bandwidth = 0 */
+ } else {
+ val |= 0x04; /* final bandwidth = 4 */
+ }
+ ret = lgdt3306a_write_reg(state, 0x1061, val);
+ if (ret)
+ return ret;
+
+ /* Adjust Notch Filter */
+ ret = lgdt3306a_read_reg(state, 0x0024, &val);
+ if (ret)
+ return ret;
+ val &= 0x0f;
+ if (nCombDet == 0) { /* Turn on the Notch Filter */
+ val |= 0x50;
+ }
+ ret = lgdt3306a_write_reg(state, 0x0024, val);
+ if (ret)
+ return ret;
+
+ /* VSB Timing Recovery output normalization */
+ ret = lgdt3306a_read_reg(state, 0x103d, &val);
+ if (ret)
+ return ret;
+ val &= 0xcf;
+ val |= 0x20;
+ ret = lgdt3306a_write_reg(state, 0x103d, val);
+
+ return ret;
+}
+
+static enum lgdt3306a_modulation
+lgdt3306a_check_oper_mode(struct lgdt3306a_state *state)
+{
+ u8 val = 0;
+ int ret;
+
+ ret = lgdt3306a_read_reg(state, 0x0081, &val);
+ if (ret)
+ goto err;
+
+ if (val & 0x80) {
+ dbg_info("VSB\n");
+ return LG3306_VSB;
+ }
+ if (val & 0x08) {
+ ret = lgdt3306a_read_reg(state, 0x00a6, &val);
+ if (ret)
+ goto err;
+ val = val >> 2;
+ if (val & 0x01) {
+ dbg_info("QAM256\n");
+ return LG3306_QAM256;
+ }
+ dbg_info("QAM64\n");
+ return LG3306_QAM64;
+ }
+err:
+ pr_warn("UNKNOWN\n");
+ return LG3306_UNKNOWN_MODE;
+}
+
+static enum lgdt3306a_lock_status
+lgdt3306a_check_lock_status(struct lgdt3306a_state *state,
+ enum lgdt3306a_lock_check whatLock)
+{
+ u8 val = 0;
+ int ret;
+ enum lgdt3306a_modulation modeOper;
+ enum lgdt3306a_lock_status lockStatus;
+
+ modeOper = LG3306_UNKNOWN_MODE;
+
+ switch (whatLock) {
+ case LG3306_SYNC_LOCK:
+ {
+ ret = lgdt3306a_read_reg(state, 0x00a6, &val);
+ if (ret)
+ return ret;
+
+ if ((val & 0x80) == 0x80)
+ lockStatus = LG3306_LOCK;
+ else
+ lockStatus = LG3306_UNLOCK;
+
+ dbg_info("SYNC_LOCK=%x\n", lockStatus);
+ break;
+ }
+ case LG3306_AGC_LOCK:
+ {
+ ret = lgdt3306a_read_reg(state, 0x0080, &val);
+ if (ret)
+ return ret;
+
+ if ((val & 0x40) == 0x40)
+ lockStatus = LG3306_LOCK;
+ else
+ lockStatus = LG3306_UNLOCK;
+
+ dbg_info("AGC_LOCK=%x\n", lockStatus);
+ break;
+ }
+ case LG3306_TR_LOCK:
+ {
+ modeOper = lgdt3306a_check_oper_mode(state);
+ if ((modeOper == LG3306_QAM64) || (modeOper == LG3306_QAM256)) {
+ ret = lgdt3306a_read_reg(state, 0x1094, &val);
+ if (ret)
+ return ret;
+
+ if ((val & 0x80) == 0x80)
+ lockStatus = LG3306_LOCK;
+ else
+ lockStatus = LG3306_UNLOCK;
+ } else
+ lockStatus = LG3306_UNKNOWN_LOCK;
+
+ dbg_info("TR_LOCK=%x\n", lockStatus);
+ break;
+ }
+ case LG3306_FEC_LOCK:
+ {
+ modeOper = lgdt3306a_check_oper_mode(state);
+ if ((modeOper == LG3306_QAM64) || (modeOper == LG3306_QAM256)) {
+ ret = lgdt3306a_read_reg(state, 0x0080, &val);
+ if (ret)
+ return ret;
+
+ if ((val & 0x10) == 0x10)
+ lockStatus = LG3306_LOCK;
+ else
+ lockStatus = LG3306_UNLOCK;
+ } else
+ lockStatus = LG3306_UNKNOWN_LOCK;
+
+ dbg_info("FEC_LOCK=%x\n", lockStatus);
+ break;
+ }
+
+ default:
+ lockStatus = LG3306_UNKNOWN_LOCK;
+ pr_warn("UNKNOWN whatLock=%d\n", whatLock);
+ break;
+ }
+
+ return lockStatus;
+}
+
+static enum lgdt3306a_neverlock_status
+lgdt3306a_check_neverlock_status(struct lgdt3306a_state *state)
+{
+ u8 val = 0;
+ int ret;
+ enum lgdt3306a_neverlock_status lockStatus;
+
+ ret = lgdt3306a_read_reg(state, 0x0080, &val);
+ if (ret)
+ return ret;
+ lockStatus = (enum lgdt3306a_neverlock_status)(val & 0x03);
+
+ dbg_info("NeverLock=%d", lockStatus);
+
+ return lockStatus;
+}
+
+static int lgdt3306a_pre_monitoring(struct lgdt3306a_state *state)
+{
+ u8 val = 0;
+ int ret;
+ u8 currChDiffACQ, snrRef, mainStrong, aiccrejStatus;
+
+ /* Channel variation */
+ ret = lgdt3306a_read_reg(state, 0x21bc, &currChDiffACQ);
+ if (ret)
+ return ret;
+
+ /* SNR of Frame sync */
+ ret = lgdt3306a_read_reg(state, 0x21a1, &val);
+ if (ret)
+ return ret;
+ snrRef = val & 0x3f;
+
+ /* Strong Main CIR */
+ ret = lgdt3306a_read_reg(state, 0x2199, &val);
+ if (ret)
+ return ret;
+ mainStrong = (val & 0x40) >> 6;
+
+ ret = lgdt3306a_read_reg(state, 0x0090, &val);
+ if (ret)
+ return ret;
+ aiccrejStatus = (val & 0xf0) >> 4;
+
+ dbg_info("snrRef=%d mainStrong=%d aiccrejStatus=%d currChDiffACQ=0x%x\n",
+ snrRef, mainStrong, aiccrejStatus, currChDiffACQ);
+
+#if 0
+ /* Dynamic ghost exists */
+ if ((mainStrong == 0) && (currChDiffACQ > 0x70))
+#endif
+ if (mainStrong == 0) {
+ ret = lgdt3306a_read_reg(state, 0x2135, &val);
+ if (ret)
+ return ret;
+ val &= 0x0f;
+ val |= 0xa0;
+ ret = lgdt3306a_write_reg(state, 0x2135, val);
+ if (ret)
+ return ret;
+
+ ret = lgdt3306a_read_reg(state, 0x2141, &val);
+ if (ret)
+ return ret;
+ val &= 0x3f;
+ val |= 0x80;
+ ret = lgdt3306a_write_reg(state, 0x2141, val);
+ if (ret)
+ return ret;
+
+ ret = lgdt3306a_write_reg(state, 0x2122, 0x70);
+ if (ret)
+ return ret;
+ } else { /* Weak ghost or static channel */
+ ret = lgdt3306a_read_reg(state, 0x2135, &val);
+ if (ret)
+ return ret;
+ val &= 0x0f;
+ val |= 0x70;
+ ret = lgdt3306a_write_reg(state, 0x2135, val);
+ if (ret)
+ return ret;
+
+ ret = lgdt3306a_read_reg(state, 0x2141, &val);
+ if (ret)
+ return ret;
+ val &= 0x3f;
+ val |= 0x40;
+ ret = lgdt3306a_write_reg(state, 0x2141, val);
+ if (ret)
+ return ret;
+
+ ret = lgdt3306a_write_reg(state, 0x2122, 0x40);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static enum lgdt3306a_lock_status
+lgdt3306a_sync_lock_poll(struct lgdt3306a_state *state)
+{
+ enum lgdt3306a_lock_status syncLockStatus = LG3306_UNLOCK;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ msleep(30);
+
+ syncLockStatus = lgdt3306a_check_lock_status(state,
+ LG3306_SYNC_LOCK);
+
+ if (syncLockStatus == LG3306_LOCK) {
+ dbg_info("locked(%d)\n", i);
+ return LG3306_LOCK;
+ }
+ }
+ dbg_info("not locked\n");
+ return LG3306_UNLOCK;
+}
+
+static enum lgdt3306a_lock_status
+lgdt3306a_fec_lock_poll(struct lgdt3306a_state *state)
+{
+ enum lgdt3306a_lock_status FECLockStatus = LG3306_UNLOCK;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ msleep(30);
+
+ FECLockStatus = lgdt3306a_check_lock_status(state,
+ LG3306_FEC_LOCK);
+
+ if (FECLockStatus == LG3306_LOCK) {
+ dbg_info("locked(%d)\n", i);
+ return FECLockStatus;
+ }
+ }
+ dbg_info("not locked\n");
+ return FECLockStatus;
+}
+
+static enum lgdt3306a_neverlock_status
+lgdt3306a_neverlock_poll(struct lgdt3306a_state *state)
+{
+ enum lgdt3306a_neverlock_status NLLockStatus = LG3306_NL_FAIL;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ msleep(30);
+
+ NLLockStatus = lgdt3306a_check_neverlock_status(state);
+
+ if (NLLockStatus == LG3306_NL_LOCK) {
+ dbg_info("NL_LOCK(%d)\n", i);
+ return NLLockStatus;
+ }
+ }
+ dbg_info("NLLockStatus=%d\n", NLLockStatus);
+ return NLLockStatus;
+}
+
+static u8 lgdt3306a_get_packet_error(struct lgdt3306a_state *state)
+{
+ u8 val;
+ int ret;
+
+ ret = lgdt3306a_read_reg(state, 0x00fa, &val);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+static const u32 valx_x10[] = {
+ 10, 11, 13, 15, 17, 20, 25, 33, 41, 50, 59, 73, 87, 100
+};
+static const u32 log10x_x1000[] = {
+ 0, 41, 114, 176, 230, 301, 398, 518, 613, 699, 771, 863, 939, 1000
+};
+
+static u32 log10_x1000(u32 x)
+{
+ u32 diff_val, step_val, step_log10;
+ u32 log_val = 0;
+ u32 i;
+
+ if (x <= 0)
+ return -1000000; /* signal error */
+
+ if (x == 10)
+ return 0; /* log(1)=0 */
+
+ if (x < 10) {
+ while (x < 10) {
+ x = x * 10;
+ log_val--;
+ }
+ } else { /* x > 10 */
+ while (x >= 100) {
+ x = x / 10;
+ log_val++;
+ }
+ }
+ log_val *= 1000;
+
+ if (x == 10) /* was our input an exact multiple of 10 */
+ return log_val; /* don't need to interpolate */
+
+ /* find our place on the log curve */
+ for (i = 1; i < ARRAY_SIZE(valx_x10); i++) {
+ if (valx_x10[i] >= x)
+ break;
+ }
+ if (i == ARRAY_SIZE(valx_x10))
+ return log_val + log10x_x1000[i - 1];
+
+ diff_val = x - valx_x10[i-1];
+ step_val = valx_x10[i] - valx_x10[i - 1];
+ step_log10 = log10x_x1000[i] - log10x_x1000[i - 1];
+
+ /* do a linear interpolation to get in-between values */
+ return log_val + log10x_x1000[i - 1] +
+ ((diff_val*step_log10) / step_val);
+}
+
+static u32 lgdt3306a_calculate_snr_x100(struct lgdt3306a_state *state)
+{
+ u32 mse; /* Mean-Square Error */
+ u32 pwr; /* Constelation power */
+ u32 snr_x100;
+
+ mse = (read_reg(state, 0x00ec) << 8) |
+ (read_reg(state, 0x00ed));
+ pwr = (read_reg(state, 0x00e8) << 8) |
+ (read_reg(state, 0x00e9));
+
+ if (mse == 0) /* no signal */
+ return 0;
+
+ snr_x100 = log10_x1000((pwr * 10000) / mse) - 3000;
+ dbg_info("mse=%u, pwr=%u, snr_x100=%d\n", mse, pwr, snr_x100);
+
+ return snr_x100;
+}
+
+static enum lgdt3306a_lock_status
+lgdt3306a_vsb_lock_poll(struct lgdt3306a_state *state)
+{
+ int ret;
+ u8 cnt = 0;
+ u8 packet_error;
+ u32 snr;
+
+ for (cnt = 0; cnt < 10; cnt++) {
+ if (lgdt3306a_sync_lock_poll(state) == LG3306_UNLOCK) {
+ dbg_info("no sync lock!\n");
+ return LG3306_UNLOCK;
+ }
+
+ msleep(20);
+ ret = lgdt3306a_pre_monitoring(state);
+ if (ret)
+ break;
+
+ packet_error = lgdt3306a_get_packet_error(state);
+ snr = lgdt3306a_calculate_snr_x100(state);
+ dbg_info("cnt=%d errors=%d snr=%d\n", cnt, packet_error, snr);
+
+ if ((snr >= 1500) && (packet_error < 0xff))
+ return LG3306_LOCK;
+ }
+
+ dbg_info("not locked!\n");
+ return LG3306_UNLOCK;
+}
+
+static enum lgdt3306a_lock_status
+lgdt3306a_qam_lock_poll(struct lgdt3306a_state *state)
+{
+ u8 cnt;
+ u8 packet_error;
+ u32 snr;
+
+ for (cnt = 0; cnt < 10; cnt++) {
+ if (lgdt3306a_fec_lock_poll(state) == LG3306_UNLOCK) {
+ dbg_info("no fec lock!\n");
+ return LG3306_UNLOCK;
+ }
+
+ msleep(20);
+
+ packet_error = lgdt3306a_get_packet_error(state);
+ snr = lgdt3306a_calculate_snr_x100(state);
+ dbg_info("cnt=%d errors=%d snr=%d\n", cnt, packet_error, snr);
+
+ if ((snr >= 1500) && (packet_error < 0xff))
+ return LG3306_LOCK;
+ }
+
+ dbg_info("not locked!\n");
+ return LG3306_UNLOCK;
+}
+
+static int lgdt3306a_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ u16 strength = 0;
+ int ret = 0;
+
+ if (fe->ops.tuner_ops.get_rf_strength) {
+ ret = fe->ops.tuner_ops.get_rf_strength(fe, &strength);
+ if (ret == 0)
+ dbg_info("strength=%d\n", strength);
+ else
+ dbg_info("fe->ops.tuner_ops.get_rf_strength() failed\n");
+ }
+
+ *status = 0;
+ if (lgdt3306a_neverlock_poll(state) == LG3306_NL_LOCK) {
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+
+ switch (state->current_modulation) {
+ case QAM_256:
+ case QAM_64:
+ if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) {
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+
+ *status |= FE_HAS_LOCK;
+ }
+ break;
+ case VSB_8:
+ if (lgdt3306a_vsb_lock_poll(state) == LG3306_LOCK) {
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+
+ *status |= FE_HAS_LOCK;
+
+ ret = lgdt3306a_monitor_vsb(state);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+
+static int lgdt3306a_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ state->snr = lgdt3306a_calculate_snr_x100(state);
+ /* report SNR in dB * 10 */
+ *snr = state->snr/10;
+
+ return 0;
+}
+
+static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ /*
+ * Calculate some sort of "strength" from SNR
+ */
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ u16 snr; /* snr_x10 */
+ int ret;
+ u32 ref_snr; /* snr*100 */
+ u32 str;
+
+ *strength = 0;
+
+ switch (state->current_modulation) {
+ case VSB_8:
+ ref_snr = 1600; /* 16dB */
+ break;
+ case QAM_64:
+ ref_snr = 2200; /* 22dB */
+ break;
+ case QAM_256:
+ ref_snr = 2800; /* 28dB */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = fe->ops.read_snr(fe, &snr);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ if (state->snr <= (ref_snr - 100))
+ str = 0;
+ else if (state->snr <= ref_snr)
+ str = (0xffff * 65) / 100; /* 65% */
+ else {
+ str = state->snr - ref_snr;
+ str /= 50;
+ str += 78; /* 78%-100% */
+ if (str > 100)
+ str = 100;
+ str = (0xffff * str) / 100;
+ }
+ *strength = (u16)str;
+ dbg_info("strength=%u\n", *strength);
+
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lgdt3306a_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+ u32 tmp;
+
+ *ber = 0;
+#if 1
+ /* FGR - FIXME - I don't know what value is expected by dvb_core
+ * what is the scale of the value?? */
+ tmp = read_reg(state, 0x00fc); /* NBERVALUE[24-31] */
+ tmp = (tmp << 8) | read_reg(state, 0x00fd); /* NBERVALUE[16-23] */
+ tmp = (tmp << 8) | read_reg(state, 0x00fe); /* NBERVALUE[8-15] */
+ tmp = (tmp << 8) | read_reg(state, 0x00ff); /* NBERVALUE[0-7] */
+ *ber = tmp;
+ dbg_info("ber=%u\n", tmp);
+#endif
+ return 0;
+}
+
+static int lgdt3306a_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ *ucblocks = 0;
+#if 1
+ /* FGR - FIXME - I don't know what value is expected by dvb_core
+ * what happens when value wraps? */
+ *ucblocks = read_reg(state, 0x00f4); /* TPIFTPERRCNT[0-7] */
+ dbg_info("ucblocks=%u\n", *ucblocks);
+#endif
+
+ return 0;
+}
+
+static int lgdt3306a_tune(struct dvb_frontend *fe, bool re_tune,
+ unsigned int mode_flags, unsigned int *delay,
+ fe_status_t *status)
+{
+ int ret = 0;
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ dbg_info("re_tune=%u\n", re_tune);
+
+ if (re_tune) {
+ state->current_frequency = -1; /* force re-tune */
+ ret = lgdt3306a_set_parameters(fe);
+ if (ret != 0)
+ return ret;
+ }
+ *delay = 125;
+ ret = lgdt3306a_read_status(fe, status);
+
+ return ret;
+}
+
+static int lgdt3306a_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings
+ *fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 100;
+ dbg_info("\n");
+ return 0;
+}
+
+static int lgdt3306a_search(struct dvb_frontend *fe)
+{
+ fe_status_t status = 0;
+ int i, ret;
+
+ /* set frontend */
+ ret = lgdt3306a_set_parameters(fe);
+ if (ret)
+ goto error;
+
+ /* wait frontend lock */
+ for (i = 20; i > 0; i--) {
+ dbg_info(": loop=%d\n", i);
+ msleep(50);
+ ret = lgdt3306a_read_status(fe, &status);
+ if (ret)
+ goto error;
+
+ if (status & FE_HAS_LOCK)
+ break;
+ }
+
+ /* check if we have a valid signal */
+ if (status & FE_HAS_LOCK)
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+ else
+ return DVBFE_ALGO_SEARCH_AGAIN;
+
+error:
+ dbg_info("failed (%d)\n", ret);
+ return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static void lgdt3306a_release(struct dvb_frontend *fe)
+{
+ struct lgdt3306a_state *state = fe->demodulator_priv;
+
+ dbg_info("\n");
+ kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3306a_ops;
+
+struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ struct lgdt3306a_state *state = NULL;
+ int ret;
+ u8 val;
+
+ dbg_info("(%d-%04x)\n",
+ i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+ config ? config->i2c_addr : 0);
+
+ state = kzalloc(sizeof(struct lgdt3306a_state), GFP_KERNEL);
+ if (state == NULL)
+ goto fail;
+
+ state->cfg = config;
+ state->i2c_adap = i2c_adap;
+
+ memcpy(&state->frontend.ops, &lgdt3306a_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* verify that we're talking to a lg3306a */
+ /* FGR - NOTE - there is no obvious ChipId to check; we check
+ * some "known" bits after reset, but it's still just a guess */
+ ret = lgdt3306a_read_reg(state, 0x0000, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ if ((val & 0x74) != 0x74) {
+ pr_warn("expected 0x74, got 0x%x\n", (val & 0x74));
+#if 0
+ /* FIXME - re-enable when we know this is right */
+ goto fail;
+#endif
+ }
+ ret = lgdt3306a_read_reg(state, 0x0001, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ if ((val & 0xf6) != 0xc6) {
+ pr_warn("expected 0xc6, got 0x%x\n", (val & 0xf6));
+#if 0
+ /* FIXME - re-enable when we know this is right */
+ goto fail;
+#endif
+ }
+ ret = lgdt3306a_read_reg(state, 0x0002, &val);
+ if (lg_chkerr(ret))
+ goto fail;
+ if ((val & 0x73) != 0x03) {
+ pr_warn("expected 0x03, got 0x%x\n", (val & 0x73));
+#if 0
+ /* FIXME - re-enable when we know this is right */
+ goto fail;
+#endif
+ }
+
+ state->current_frequency = -1;
+ state->current_modulation = -1;
+
+ lgdt3306a_sleep(state);
+
+ return &state->frontend;
+
+fail:
+ pr_warn("unable to detect LGDT3306A hardware\n");
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(lgdt3306a_attach);
+
+#ifdef DBG_DUMP
+
+static const short regtab[] = {
+ 0x0000, /* SOFTRSTB 1'b1 1'b1 1'b1 ADCPDB 1'b1 PLLPDB GBBPDB 11111111 */
+ 0x0001, /* 1'b1 1'b1 1'b0 1'b0 AUTORPTRS */
+ 0x0002, /* NI2CRPTEN 1'b0 1'b0 1'b0 SPECINVAUT */
+ 0x0003, /* AGCRFOUT */
+ 0x0004, /* ADCSEL1V ADCCNT ADCCNF ADCCNS ADCCLKPLL */
+ 0x0005, /* PLLINDIVSE */
+ 0x0006, /* PLLCTRL[7:0] 11100001 */
+ 0x0007, /* SYSINITWAITTIME[7:0] (msec) 00001000 */
+ 0x0008, /* STDOPMODE[7:0] 10000000 */
+ 0x0009, /* 1'b0 1'b0 1'b0 STDOPDETTMODE[2:0] STDOPDETCMODE[1:0] 00011110 */
+ 0x000a, /* DAFTEN 1'b1 x x SCSYSLOCK */
+ 0x000b, /* SCSYSLOCKCHKTIME[7:0] (10msec) 01100100 */
+ 0x000d, /* x SAMPLING4 */
+ 0x000e, /* SAMFREQ[15:8] 00000000 */
+ 0x000f, /* SAMFREQ[7:0] 00000000 */
+ 0x0010, /* IFFREQ[15:8] 01100000 */
+ 0x0011, /* IFFREQ[7:0] 00000000 */
+ 0x0012, /* AGCEN AGCREFMO */
+ 0x0013, /* AGCRFFIXB AGCIFFIXB AGCLOCKDETRNGSEL[1:0] 1'b1 1'b0 1'b0 1'b0 11101000 */
+ 0x0014, /* AGCFIXVALUE[7:0] 01111111 */
+ 0x0015, /* AGCREF[15:8] 00001010 */
+ 0x0016, /* AGCREF[7:0] 11100100 */
+ 0x0017, /* AGCDELAY[7:0] 00100000 */
+ 0x0018, /* AGCRFBW[3:0] AGCIFBW[3:0] 10001000 */
+ 0x0019, /* AGCUDOUTMODE[1:0] AGCUDCTRLLEN[1:0] AGCUDCTRL */
+ 0x001c, /* 1'b1 PFEN MFEN AICCVSYNC */
+ 0x001d, /* 1'b0 1'b1 1'b0 1'b1 AICCVSYNC */
+ 0x001e, /* AICCALPHA[3:0] 1'b1 1'b0 1'b1 1'b0 01111010 */
+ 0x001f, /* AICCDETTH[19:16] AICCOFFTH[19:16] 00000000 */
+ 0x0020, /* AICCDETTH[15:8] 01111100 */
+ 0x0021, /* AICCDETTH[7:0] 00000000 */
+ 0x0022, /* AICCOFFTH[15:8] 00000101 */
+ 0x0023, /* AICCOFFTH[7:0] 11100000 */
+ 0x0024, /* AICCOPMODE3[1:0] AICCOPMODE2[1:0] AICCOPMODE1[1:0] AICCOPMODE0[1:0] 00000000 */
+ 0x0025, /* AICCFIXFREQ3[23:16] 00000000 */
+ 0x0026, /* AICCFIXFREQ3[15:8] 00000000 */
+ 0x0027, /* AICCFIXFREQ3[7:0] 00000000 */
+ 0x0028, /* AICCFIXFREQ2[23:16] 00000000 */
+ 0x0029, /* AICCFIXFREQ2[15:8] 00000000 */
+ 0x002a, /* AICCFIXFREQ2[7:0] 00000000 */
+ 0x002b, /* AICCFIXFREQ1[23:16] 00000000 */
+ 0x002c, /* AICCFIXFREQ1[15:8] 00000000 */
+ 0x002d, /* AICCFIXFREQ1[7:0] 00000000 */
+ 0x002e, /* AICCFIXFREQ0[23:16] 00000000 */
+ 0x002f, /* AICCFIXFREQ0[15:8] 00000000 */
+ 0x0030, /* AICCFIXFREQ0[7:0] 00000000 */
+ 0x0031, /* 1'b0 1'b1 1'b0 1'b0 x DAGC1STER */
+ 0x0032, /* DAGC1STEN DAGC1STER */
+ 0x0033, /* DAGC1STREF[15:8] 00001010 */
+ 0x0034, /* DAGC1STREF[7:0] 11100100 */
+ 0x0035, /* DAGC2NDE */
+ 0x0036, /* DAGC2NDREF[15:8] 00001010 */
+ 0x0037, /* DAGC2NDREF[7:0] 10000000 */
+ 0x0038, /* DAGC2NDLOCKDETRNGSEL[1:0] */
+ 0x003d, /* 1'b1 SAMGEARS */
+ 0x0040, /* SAMLFGMA */
+ 0x0041, /* SAMLFBWM */
+ 0x0044, /* 1'b1 CRGEARSHE */
+ 0x0045, /* CRLFGMAN */
+ 0x0046, /* CFLFBWMA */
+ 0x0047, /* CRLFGMAN */
+ 0x0048, /* x x x x CRLFGSTEP_VS[3:0] xxxx1001 */
+ 0x0049, /* CRLFBWMA */
+ 0x004a, /* CRLFBWMA */
+ 0x0050, /* 1'b0 1'b1 1'b1 1'b0 MSECALCDA */
+ 0x0070, /* TPOUTEN TPIFEN TPCLKOUTE */
+ 0x0071, /* TPSENB TPSSOPBITE */
+ 0x0073, /* TP47HINS x x CHBERINT PERMODE[1:0] PERINT[1:0] 1xx11100 */
+ 0x0075, /* x x x x x IQSWAPCTRL[2:0] xxxxx000 */
+ 0x0076, /* NBERCON NBERST NBERPOL NBERWSYN */
+ 0x0077, /* x NBERLOSTTH[2:0] NBERACQTH[3:0] x0000000 */
+ 0x0078, /* NBERPOLY[31:24] 00000000 */
+ 0x0079, /* NBERPOLY[23:16] 00000000 */
+ 0x007a, /* NBERPOLY[15:8] 00000000 */
+ 0x007b, /* NBERPOLY[7:0] 00000000 */
+ 0x007c, /* NBERPED[31:24] 00000000 */
+ 0x007d, /* NBERPED[23:16] 00000000 */
+ 0x007e, /* NBERPED[15:8] 00000000 */
+ 0x007f, /* NBERPED[7:0] 00000000 */
+ 0x0080, /* x AGCLOCK DAGCLOCK SYSLOCK x x NEVERLOCK[1:0] */
+ 0x0085, /* SPECINVST */
+ 0x0088, /* SYSLOCKTIME[15:8] */
+ 0x0089, /* SYSLOCKTIME[7:0] */
+ 0x008c, /* FECLOCKTIME[15:8] */
+ 0x008d, /* FECLOCKTIME[7:0] */
+ 0x008e, /* AGCACCOUT[15:8] */
+ 0x008f, /* AGCACCOUT[7:0] */
+ 0x0090, /* AICCREJSTATUS[3:0] AICCREJBUSY[3:0] */
+ 0x0091, /* AICCVSYNC */
+ 0x009c, /* CARRFREQOFFSET[15:8] */
+ 0x009d, /* CARRFREQOFFSET[7:0] */
+ 0x00a1, /* SAMFREQOFFSET[23:16] */
+ 0x00a2, /* SAMFREQOFFSET[15:8] */
+ 0x00a3, /* SAMFREQOFFSET[7:0] */
+ 0x00a6, /* SYNCLOCK SYNCLOCKH */
+#if 0 /* covered elsewhere */
+ 0x00e8, /* CONSTPWR[15:8] */
+ 0x00e9, /* CONSTPWR[7:0] */
+ 0x00ea, /* BMSE[15:8] */
+ 0x00eb, /* BMSE[7:0] */
+ 0x00ec, /* MSE[15:8] */
+ 0x00ed, /* MSE[7:0] */
+ 0x00ee, /* CONSTI[7:0] */
+ 0x00ef, /* CONSTQ[7:0] */
+#endif
+ 0x00f4, /* TPIFTPERRCNT[7:0] */
+ 0x00f5, /* TPCORREC */
+ 0x00f6, /* VBBER[15:8] */
+ 0x00f7, /* VBBER[7:0] */
+ 0x00f8, /* VABER[15:8] */
+ 0x00f9, /* VABER[7:0] */
+ 0x00fa, /* TPERRCNT[7:0] */
+ 0x00fb, /* NBERLOCK x x x x x x x */
+ 0x00fc, /* NBERVALUE[31:24] */
+ 0x00fd, /* NBERVALUE[23:16] */
+ 0x00fe, /* NBERVALUE[15:8] */
+ 0x00ff, /* NBERVALUE[7:0] */
+ 0x1000, /* 1'b0 WODAGCOU */
+ 0x1005, /* x x 1'b1 1'b1 x SRD_Q_QM */
+ 0x1009, /* SRDWAITTIME[7:0] (10msec) 00100011 */
+ 0x100a, /* SRDWAITTIME_CQS[7:0] (msec) 01100100 */
+ 0x101a, /* x 1'b1 1'b0 1'b0 x QMDQAMMODE[2:0] x100x010 */
+ 0x1036, /* 1'b0 1'b1 1'b0 1'b0 SAMGSEND_CQS[3:0] 01001110 */
+ 0x103c, /* SAMGSAUTOSTL_V[3:0] SAMGSAUTOEDL_V[3:0] 01000110 */
+ 0x103d, /* 1'b1 1'b1 SAMCNORMBP_V[1:0] 1'b0 1'b0 SAMMODESEL_V[1:0] 11100001 */
+ 0x103f, /* SAMZTEDSE */
+ 0x105d, /* EQSTATUSE */
+ 0x105f, /* x PMAPG2_V[2:0] x DMAPG2_V[2:0] x001x011 */
+ 0x1060, /* 1'b1 EQSTATUSE */
+ 0x1061, /* CRMAPBWSTL_V[3:0] CRMAPBWEDL_V[3:0] 00000100 */
+ 0x1065, /* 1'b0 x CRMODE_V[1:0] 1'b1 x 1'b1 x 0x111x1x */
+ 0x1066, /* 1'b0 1'b0 1'b1 1'b0 1'b1 PNBOOSTSE */
+ 0x1068, /* CREPHNGAIN2_V[3:0] CREPHNPBW_V[3:0] 10010001 */
+ 0x106e, /* x x x x x CREPHNEN_ */
+ 0x106f, /* CREPHNTH_V[7:0] 00010101 */
+ 0x1072, /* CRSWEEPN */
+ 0x1073, /* CRPGAIN_V[3:0] x x 1'b1 1'b1 1001xx11 */
+ 0x1074, /* CRPBW_V[3:0] x x 1'b1 1'b1 0001xx11 */
+ 0x1080, /* DAFTSTATUS[1:0] x x x x x x */
+ 0x1081, /* SRDSTATUS[1:0] x x x x x SRDLOCK */
+ 0x10a9, /* EQSTATUS_CQS[1:0] x x x x x x */
+ 0x10b7, /* EQSTATUS_V[1:0] x x x x x x */
+#if 0 /* SMART_ANT */
+ 0x1f00, /* MODEDETE */
+ 0x1f01, /* x x x x x x x SFNRST xxxxxxx0 */
+ 0x1f03, /* NUMOFANT[7:0] 10000000 */
+ 0x1f04, /* x SELMASK[6:0] x0000000 */
+ 0x1f05, /* x SETMASK[6:0] x0000000 */
+ 0x1f06, /* x TXDATA[6:0] x0000000 */
+ 0x1f07, /* x CHNUMBER[6:0] x0000000 */
+ 0x1f09, /* AGCTIME[23:16] 10011000 */
+ 0x1f0a, /* AGCTIME[15:8] 10010110 */
+ 0x1f0b, /* AGCTIME[7:0] 10000000 */
+ 0x1f0c, /* ANTTIME[31:24] 00000000 */
+ 0x1f0d, /* ANTTIME[23:16] 00000011 */
+ 0x1f0e, /* ANTTIME[15:8] 10010000 */
+ 0x1f0f, /* ANTTIME[7:0] 10010000 */
+ 0x1f11, /* SYNCTIME[23:16] 10011000 */
+ 0x1f12, /* SYNCTIME[15:8] 10010110 */
+ 0x1f13, /* SYNCTIME[7:0] 10000000 */
+ 0x1f14, /* SNRTIME[31:24] 00000001 */
+ 0x1f15, /* SNRTIME[23:16] 01111101 */
+ 0x1f16, /* SNRTIME[15:8] 01111000 */
+ 0x1f17, /* SNRTIME[7:0] 01000000 */
+ 0x1f19, /* FECTIME[23:16] 00000000 */
+ 0x1f1a, /* FECTIME[15:8] 01110010 */
+ 0x1f1b, /* FECTIME[7:0] 01110000 */
+ 0x1f1d, /* FECTHD[7:0] 00000011 */
+ 0x1f1f, /* SNRTHD[23:16] 00001000 */
+ 0x1f20, /* SNRTHD[15:8] 01111111 */
+ 0x1f21, /* SNRTHD[7:0] 10000101 */
+ 0x1f80, /* IRQFLG x x SFSDRFLG MODEBFLG SAVEFLG SCANFLG TRACKFLG */
+ 0x1f81, /* x SYNCCON SNRCON FECCON x STDBUSY SYNCRST AGCFZCO */
+ 0x1f82, /* x x x SCANOPCD[4:0] */
+ 0x1f83, /* x x x x MAINOPCD[3:0] */
+ 0x1f84, /* x x RXDATA[13:8] */
+ 0x1f85, /* RXDATA[7:0] */
+ 0x1f86, /* x x SDTDATA[13:8] */
+ 0x1f87, /* SDTDATA[7:0] */
+ 0x1f89, /* ANTSNR[23:16] */
+ 0x1f8a, /* ANTSNR[15:8] */
+ 0x1f8b, /* ANTSNR[7:0] */
+ 0x1f8c, /* x x x x ANTFEC[13:8] */
+ 0x1f8d, /* ANTFEC[7:0] */
+ 0x1f8e, /* MAXCNT[7:0] */
+ 0x1f8f, /* SCANCNT[7:0] */
+ 0x1f91, /* MAXPW[23:16] */
+ 0x1f92, /* MAXPW[15:8] */
+ 0x1f93, /* MAXPW[7:0] */
+ 0x1f95, /* CURPWMSE[23:16] */
+ 0x1f96, /* CURPWMSE[15:8] */
+ 0x1f97, /* CURPWMSE[7:0] */
+#endif /* SMART_ANT */
+ 0x211f, /* 1'b1 1'b1 1'b1 CIRQEN x x 1'b0 1'b0 1111xx00 */
+ 0x212a, /* EQAUTOST */
+ 0x2122, /* CHFAST[7:0] 01100000 */
+ 0x212b, /* FFFSTEP_V[3:0] x FBFSTEP_V[2:0] 0001x001 */
+ 0x212c, /* PHDEROTBWSEL[3:0] 1'b1 1'b1 1'b1 1'b0 10001110 */
+ 0x212d, /* 1'b1 1'b1 1'b1 1'b1 x x TPIFLOCKS */
+ 0x2135, /* DYNTRACKFDEQ[3:0] x 1'b0 1'b0 1'b0 1010x000 */
+ 0x2141, /* TRMODE[1:0] 1'b1 1'b1 1'b0 1'b1 1'b1 1'b1 01110111 */
+ 0x2162, /* AICCCTRLE */
+ 0x2173, /* PHNCNFCNT[7:0] 00000100 */
+ 0x2179, /* 1'b0 1'b0 1'b0 1'b1 x BADSINGLEDYNTRACKFBF[2:0] 0001x001 */
+ 0x217a, /* 1'b0 1'b0 1'b0 1'b1 x BADSLOWSINGLEDYNTRACKFBF[2:0] 0001x001 */
+ 0x217e, /* CNFCNTTPIF[7:0] 00001000 */
+ 0x217f, /* TPERRCNTTPIF[7:0] 00000001 */
+ 0x2180, /* x x x x x x FBDLYCIR[9:8] */
+ 0x2181, /* FBDLYCIR[7:0] */
+ 0x2185, /* MAXPWRMAIN[7:0] */
+ 0x2191, /* NCOMBDET x x x x x x x */
+ 0x2199, /* x MAINSTRON */
+ 0x219a, /* FFFEQSTEPOUT_V[3:0] FBFSTEPOUT_V[2:0] */
+ 0x21a1, /* x x SNRREF[5:0] */
+ 0x2845, /* 1'b0 1'b1 x x FFFSTEP_CQS[1:0] FFFCENTERTAP[1:0] 01xx1110 */
+ 0x2846, /* 1'b0 x 1'b0 1'b1 FBFSTEP_CQS[1:0] 1'b1 1'b0 0x011110 */
+ 0x2847, /* ENNOSIGDE */
+ 0x2849, /* 1'b1 1'b1 NOUSENOSI */
+ 0x284a, /* EQINITWAITTIME[7:0] 01100100 */
+ 0x3000, /* 1'b1 1'b1 1'b1 x x x 1'b0 RPTRSTM */
+ 0x3001, /* RPTRSTWAITTIME[7:0] (100msec) 00110010 */
+ 0x3031, /* FRAMELOC */
+ 0x3032, /* 1'b1 1'b0 1'b0 1'b0 x x FRAMELOCKMODE_CQS[1:0] 1000xx11 */
+ 0x30a9, /* VDLOCK_Q FRAMELOCK */
+ 0x30aa, /* MPEGLOCK */
+};
+
+#define numDumpRegs (sizeof(regtab)/sizeof(regtab[0]))
+static u8 regval1[numDumpRegs] = {0, };
+static u8 regval2[numDumpRegs] = {0, };
+
+static void lgdt3306a_DumpAllRegs(struct lgdt3306a_state *state)
+{
+ memset(regval2, 0xff, sizeof(regval2));
+ lgdt3306a_DumpRegs(state);
+}
+
+static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state)
+{
+ int i;
+ int sav_debug = debug;
+
+ if ((debug & DBG_DUMP) == 0)
+ return;
+ debug &= ~DBG_REG; /* suppress DBG_REG during reg dump */
+
+ lg_debug("\n");
+
+ for (i = 0; i < numDumpRegs; i++) {
+ lgdt3306a_read_reg(state, regtab[i], &regval1[i]);
+ if (regval1[i] != regval2[i]) {
+ lg_debug(" %04X = %02X\n", regtab[i], regval1[i]);
+ regval2[i] = regval1[i];
+ }
+ }
+ debug = sav_debug;
+}
+#endif /* DBG_DUMP */
+
+
+
+static struct dvb_frontend_ops lgdt3306a_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+ .info = {
+ .name = "LG Electronics LGDT3306A VSB/QAM Frontend",
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl,
+ .init = lgdt3306a_init,
+ .sleep = lgdt3306a_fe_sleep,
+ /* if this is set, it overrides the default swzigzag */
+ .tune = lgdt3306a_tune,
+ .set_frontend = lgdt3306a_set_parameters,
+ .get_frontend = lgdt3306a_get_frontend,
+ .get_frontend_algo = lgdt3306a_get_frontend_algo,
+ .get_tune_settings = lgdt3306a_get_tune_settings,
+ .read_status = lgdt3306a_read_status,
+ .read_ber = lgdt3306a_read_ber,
+ .read_signal_strength = lgdt3306a_read_signal_strength,
+ .read_snr = lgdt3306a_read_snr,
+ .read_ucblocks = lgdt3306a_read_ucblocks,
+ .release = lgdt3306a_release,
+ .ts_bus_ctrl = lgdt3306a_ts_bus_ctrl,
+ .search = lgdt3306a_search,
+};
+
+MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver");
+MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
diff --git a/drivers/media/dvb-frontends/lgdt3306a.h b/drivers/media/dvb-frontends/lgdt3306a.h
new file mode 100644
index 0000000..9dbb2dc
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgdt3306a.h
@@ -0,0 +1,74 @@
+/*
+ * Support for LGDT3306A - 8VSB/QAM-B
+ *
+ * Copyright (C) 2013,2014 Fred Richter <frichter@hauppauge.com>
+ * based on lgdt3305.[ch] by Michael Krufky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LGDT3306A_H_
+#define _LGDT3306A_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+
+enum lgdt3306a_mpeg_mode {
+ LGDT3306A_MPEG_PARALLEL = 0,
+ LGDT3306A_MPEG_SERIAL = 1,
+};
+
+enum lgdt3306a_tp_clock_edge {
+ LGDT3306A_TPCLK_RISING_EDGE = 0,
+ LGDT3306A_TPCLK_FALLING_EDGE = 1,
+};
+
+enum lgdt3306a_tp_valid_polarity {
+ LGDT3306A_TP_VALID_LOW = 0,
+ LGDT3306A_TP_VALID_HIGH = 1,
+};
+
+struct lgdt3306a_config {
+ u8 i2c_addr;
+
+ /* user defined IF frequency in KHz */
+ u16 qam_if_khz;
+ u16 vsb_if_khz;
+
+ /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+ unsigned int deny_i2c_rptr:1;
+
+ /* spectral inversion - 0:disabled 1:enabled */
+ unsigned int spectral_inversion:1;
+
+ enum lgdt3306a_mpeg_mode mpeg_mode;
+ enum lgdt3306a_tp_clock_edge tpclk_edge;
+ enum lgdt3306a_tp_valid_polarity tpvalid_polarity;
+
+ /* demod clock freq in MHz; 24 or 25 supported */
+ int xtalMHz;
+};
+
+#if IS_REACHABLE(CONFIG_DVB_LGDT3306A)
+struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config,
+ struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_LGDT3306A */
+
+#endif /* _LGDT3306A_H_ */
diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
index 8bb3322..c73eeb4 100644
--- a/drivers/media/dvb-frontends/lgdt330x.h
+++ b/drivers/media/dvb-frontends/lgdt330x.h
@@ -52,7 +52,7 @@ struct lgdt330x_config
int clock_polarity_flip;
};
-#if IS_ENABLED(CONFIG_DVB_LGDT330X)
+#if IS_REACHABLE(CONFIG_DVB_LGDT330X)
extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h
index c2da596..a5b3faf 100644
--- a/drivers/media/dvb-frontends/lgs8gl5.h
+++ b/drivers/media/dvb-frontends/lgs8gl5.h
@@ -31,7 +31,7 @@ struct lgs8gl5_config {
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_LGS8GL5)
+#if IS_REACHABLE(CONFIG_DVB_LGS8GL5)
extern struct dvb_frontend *lgs8gl5_attach(
const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h
index dadb78b..368c992 100644
--- a/drivers/media/dvb-frontends/lgs8gxx.h
+++ b/drivers/media/dvb-frontends/lgs8gxx.h
@@ -80,7 +80,7 @@ struct lgs8gxx_config {
u8 tuner_address;
};
-#if IS_ENABLED(CONFIG_DVB_LGS8GXX)
+#if IS_REACHABLE(CONFIG_DVB_LGS8GXX)
extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h
index b327a4f..a088b8e 100644
--- a/drivers/media/dvb-frontends/lnbh24.h
+++ b/drivers/media/dvb-frontends/lnbh24.h
@@ -37,7 +37,7 @@
#include <linux/dvb/frontend.h>
-#if IS_ENABLED(CONFIG_DVB_LNBP21)
+#if IS_REACHABLE(CONFIG_DVB_LNBP21)
/* override_set and override_clear control which
system register bits (above) to always set & clear */
extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h
index dbcbcc2..a9b530d 100644
--- a/drivers/media/dvb-frontends/lnbp21.h
+++ b/drivers/media/dvb-frontends/lnbp21.h
@@ -57,7 +57,7 @@
#include <linux/dvb/frontend.h>
-#if IS_ENABLED(CONFIG_DVB_LNBP21)
+#if IS_REACHABLE(CONFIG_DVB_LNBP21)
/* override_set and override_clear control which
system register bits (above) to always set & clear */
extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h
index 63861b3..6281483 100644
--- a/drivers/media/dvb-frontends/lnbp22.h
+++ b/drivers/media/dvb-frontends/lnbp22.h
@@ -39,7 +39,7 @@
#include <linux/dvb/frontend.h>
-#if IS_ENABLED(CONFIG_DVB_LNBP22)
+#if IS_REACHABLE(CONFIG_DVB_LNBP22)
/*
* override_set and override_clear control which system register bits (above)
* to always set & clear
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h
index 0a50ea9..de74301 100644
--- a/drivers/media/dvb-frontends/m88rs2000.h
+++ b/drivers/media/dvb-frontends/m88rs2000.h
@@ -41,7 +41,7 @@ enum {
CALL_IS_READ,
};
-#if IS_ENABLED(CONFIG_DVB_M88RS2000)
+#if IS_REACHABLE(CONFIG_DVB_M88RS2000)
extern struct dvb_frontend *m88rs2000_attach(
const struct m88rs2000_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h
index 277ce06..e486dc0 100644
--- a/drivers/media/dvb-frontends/mb86a16.h
+++ b/drivers/media/dvb-frontends/mb86a16.h
@@ -33,7 +33,7 @@ struct mb86a16_config {
-#if IS_ENABLED(CONFIG_DVB_MB86A16)
+#if IS_REACHABLE(CONFIG_DVB_MB86A16)
extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index cbeb941..f749c8a 100644
--- a/drivers/media/dvb-frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -34,7 +34,7 @@ struct mb86a20s_config {
bool is_serial;
};
-#if IS_ENABLED(CONFIG_DVB_MB86A20S)
+#if IS_REACHABLE(CONFIG_DVB_MB86A20S)
extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h
index e4e0b80..095294d 100644
--- a/drivers/media/dvb-frontends/mn88472.h
+++ b/drivers/media/dvb-frontends/mn88472.h
@@ -19,6 +19,16 @@
#include <linux/dvb/frontend.h>
+enum ts_clock {
+ VARIABLE_TS_CLOCK,
+ FIXED_TS_CLOCK,
+};
+
+enum ts_mode {
+ SERIAL_TS_MODE,
+ PARALLEL_TS_MODE,
+};
+
struct mn88472_config {
/*
* Max num of bytes given I2C adapter could write at once.
@@ -39,6 +49,8 @@ struct mn88472_config {
* Hz
*/
u32 xtal;
+ int ts_mode;
+ int ts_clock;
};
#endif
diff --git a/drivers/media/dvb-frontends/mn88473.h b/drivers/media/dvb-frontends/mn88473.h
index a373ec9..c717ebed 100644
--- a/drivers/media/dvb-frontends/mn88473.h
+++ b/drivers/media/dvb-frontends/mn88473.h
@@ -33,6 +33,12 @@ struct mn88473_config {
* DVB frontend.
*/
struct dvb_frontend **fe;
+
+ /*
+ * Xtal frequency.
+ * Hz
+ */
+ u32 xtal;
};
#endif
diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h
index 5706621..386939a 100644
--- a/drivers/media/dvb-frontends/mt312.h
+++ b/drivers/media/dvb-frontends/mt312.h
@@ -36,7 +36,7 @@ struct mt312_config {
unsigned int voltage_inverted:1;
};
-#if IS_ENABLED(CONFIG_DVB_MT312)
+#if IS_REACHABLE(CONFIG_DVB_MT312)
struct dvb_frontend *mt312_attach(const struct mt312_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h
index 451d904..5873263 100644
--- a/drivers/media/dvb-frontends/mt352.h
+++ b/drivers/media/dvb-frontends/mt352.h
@@ -51,7 +51,7 @@ struct mt352_config
int (*demod_init)(struct dvb_frontend* fe);
};
-#if IS_ENABLED(CONFIG_DVB_MT352)
+#if IS_REACHABLE(CONFIG_DVB_MT352)
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
index e38d01f..825b928 100644
--- a/drivers/media/dvb-frontends/nxt200x.h
+++ b/drivers/media/dvb-frontends/nxt200x.h
@@ -42,7 +42,7 @@ struct nxt200x_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if IS_ENABLED(CONFIG_DVB_NXT200X)
+#if IS_REACHABLE(CONFIG_DVB_NXT200X)
extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h
index b5867c2..a94cefc 100644
--- a/drivers/media/dvb-frontends/nxt6000.h
+++ b/drivers/media/dvb-frontends/nxt6000.h
@@ -33,7 +33,7 @@ struct nxt6000_config
u8 clock_inversion:1;
};
-#if IS_ENABLED(CONFIG_DVB_NXT6000)
+#if IS_REACHABLE(CONFIG_DVB_NXT6000)
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
index cdb5be3..9acf8dc 100644
--- a/drivers/media/dvb-frontends/or51132.h
+++ b/drivers/media/dvb-frontends/or51132.h
@@ -34,7 +34,7 @@ struct or51132_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if IS_ENABLED(CONFIG_DVB_OR51132)
+#if IS_REACHABLE(CONFIG_DVB_OR51132)
extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h
index 9a8ae93..cc6adab 100644
--- a/drivers/media/dvb-frontends/or51211.h
+++ b/drivers/media/dvb-frontends/or51211.h
@@ -37,7 +37,7 @@ struct or51211_config
void (*sleep)(struct dvb_frontend * fe);
};
-#if IS_ENABLED(CONFIG_DVB_OR51211)
+#if IS_REACHABLE(CONFIG_DVB_OR51211)
extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 67faa8d..b400f7b 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -685,7 +685,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
struct rtl2832_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
int ret;
- u32 tmp;
+ u32 uninitialized_var(tmp);
dev_dbg(&client->dev, "\n");
diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
index 9e143f5..f58b9ca 100644
--- a/drivers/media/dvb-frontends/s5h1409.h
+++ b/drivers/media/dvb-frontends/s5h1409.h
@@ -67,7 +67,7 @@ struct s5h1409_config {
u8 hvr1600_opt;
};
-#if IS_ENABLED(CONFIG_DVB_S5H1409)
+#if IS_REACHABLE(CONFIG_DVB_S5H1409)
extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
index 1d7deb6..f3a87f7 100644
--- a/drivers/media/dvb-frontends/s5h1411.h
+++ b/drivers/media/dvb-frontends/s5h1411.h
@@ -69,7 +69,7 @@ struct s5h1411_config {
u8 status_mode;
};
-#if IS_ENABLED(CONFIG_DVB_S5H1411)
+#if IS_REACHABLE(CONFIG_DVB_S5H1411)
extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h
index 210049b..142d93e 100644
--- a/drivers/media/dvb-frontends/s5h1420.h
+++ b/drivers/media/dvb-frontends/s5h1420.h
@@ -40,7 +40,7 @@ struct s5h1420_config
u8 serial_mpeg:1;
};
-#if IS_ENABLED(CONFIG_DVB_S5H1420)
+#if IS_REACHABLE(CONFIG_DVB_S5H1420)
extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h
index 70917dd..f490c5e 100644
--- a/drivers/media/dvb-frontends/s5h1432.h
+++ b/drivers/media/dvb-frontends/s5h1432.h
@@ -75,7 +75,7 @@ struct s5h1432_config {
u8 status_mode;
};
-#if IS_ENABLED(CONFIG_DVB_S5H1432)
+#if IS_REACHABLE(CONFIG_DVB_S5H1432)
extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h
index 9b20c9e..7d3999a 100644
--- a/drivers/media/dvb-frontends/s921.h
+++ b/drivers/media/dvb-frontends/s921.h
@@ -25,7 +25,7 @@ struct s921_config {
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_S921)
+#if IS_REACHABLE(CONFIG_DVB_S921)
extern struct dvb_frontend *s921_attach(const struct s921_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 98ddb49..4cc5d10 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -505,7 +505,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
/* reset crc */
ret = si2165_writereg8(state, 0x0379, 0x01);
if (ret)
- return ret;
+ goto error;
ret = si2165_upload_firmware_block(state, data, len,
&offset, block_count);
diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h
index efaa081..8a15d6a 100644
--- a/drivers/media/dvb-frontends/si2165.h
+++ b/drivers/media/dvb-frontends/si2165.h
@@ -45,7 +45,7 @@ struct si2165_config {
bool inversion;
};
-#if IS_ENABLED(CONFIG_DVB_SI2165)
+#if IS_REACHABLE(CONFIG_DVB_SI2165)
struct dvb_frontend *si2165_attach(
const struct si2165_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h
index 1509fed..ef5f351 100644
--- a/drivers/media/dvb-frontends/si21xx.h
+++ b/drivers/media/dvb-frontends/si21xx.h
@@ -13,7 +13,7 @@ struct si21xx_config {
int min_delay_ms;
};
-#if IS_ENABLED(CONFIG_DVB_SI21XX)
+#if IS_REACHABLE(CONFIG_DVB_SI21XX)
extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
index cc1ef96..8fd4276 100644
--- a/drivers/media/dvb-frontends/sp2.c
+++ b/drivers/media/dvb-frontends/sp2.c
@@ -413,11 +413,8 @@ static int sp2_remove(struct i2c_client *client)
struct sp2 *s = i2c_get_clientdata(client);
dev_dbg(&client->dev, "\n");
-
sp2_exit(client);
- if (s != NULL)
- kfree(s);
-
+ kfree(s);
return 0;
}
diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h
index 065ec67..f507b9f 100644
--- a/drivers/media/dvb-frontends/sp8870.h
+++ b/drivers/media/dvb-frontends/sp8870.h
@@ -35,7 +35,7 @@ struct sp8870_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if IS_ENABLED(CONFIG_DVB_SP8870)
+#if IS_REACHABLE(CONFIG_DVB_SP8870)
extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h
index 2cdc4e8..412f011 100644
--- a/drivers/media/dvb-frontends/sp887x.h
+++ b/drivers/media/dvb-frontends/sp887x.h
@@ -17,7 +17,7 @@ struct sp887x_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if IS_ENABLED(CONFIG_DVB_SP887X)
+#if IS_REACHABLE(CONFIG_DVB_SP887X)
extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
index 139264d..0a72131 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.h
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
@@ -141,7 +141,7 @@ struct stb0899_config {
int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
};
-#if IS_ENABLED(CONFIG_DVB_STB0899)
+#if IS_REACHABLE(CONFIG_DVB_STB0899)
extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h
index a768189..da581b6 100644
--- a/drivers/media/dvb-frontends/stb6000.h
+++ b/drivers/media/dvb-frontends/stb6000.h
@@ -35,7 +35,7 @@
* @param i2c i2c adapter to use.
* @return FE pointer on success, NULL on failure.
*/
-#if IS_ENABLED(CONFIG_DVB_STB6000)
+#if IS_REACHABLE(CONFIG_DVB_STB6000)
extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
index 3a1e40f..218c818 100644
--- a/drivers/media/dvb-frontends/stb6100.h
+++ b/drivers/media/dvb-frontends/stb6100.h
@@ -94,7 +94,7 @@ struct stb6100_state {
u32 reference;
};
-#if IS_ENABLED(CONFIG_DVB_STB6100)
+#if IS_REACHABLE(CONFIG_DVB_STB6100)
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
const struct stb6100_config *config,
diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h
index a0bd931..b58603c 100644
--- a/drivers/media/dvb-frontends/stv0288.h
+++ b/drivers/media/dvb-frontends/stv0288.h
@@ -43,7 +43,7 @@ struct stv0288_config {
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
-#if IS_ENABLED(CONFIG_DVB_STV0288)
+#if IS_REACHABLE(CONFIG_DVB_STV0288)
extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h
index c8ff363..b30632a 100644
--- a/drivers/media/dvb-frontends/stv0297.h
+++ b/drivers/media/dvb-frontends/stv0297.h
@@ -42,7 +42,7 @@ struct stv0297_config
u8 stop_during_read:1;
};
-#if IS_ENABLED(CONFIG_DVB_STV0297)
+#if IS_REACHABLE(CONFIG_DVB_STV0297)
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h
index 06f70fc8..0aca30a 100644
--- a/drivers/media/dvb-frontends/stv0299.h
+++ b/drivers/media/dvb-frontends/stv0299.h
@@ -95,7 +95,7 @@ struct stv0299_config
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
-#if IS_ENABLED(CONFIG_DVB_STV0299)
+#if IS_REACHABLE(CONFIG_DVB_STV0299)
extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h
index ea80b34..92b3e85 100644
--- a/drivers/media/dvb-frontends/stv0367.h
+++ b/drivers/media/dvb-frontends/stv0367.h
@@ -39,7 +39,7 @@ struct stv0367_config {
int clk_pol;
};
-#if IS_ENABLED(CONFIG_DVB_STV0367)
+#if IS_REACHABLE(CONFIG_DVB_STV0367)
extern struct
dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h
index e2a6dc6..c90bf00 100644
--- a/drivers/media/dvb-frontends/stv0900.h
+++ b/drivers/media/dvb-frontends/stv0900.h
@@ -58,7 +58,7 @@ struct stv0900_config {
void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
-#if IS_ENABLED(CONFIG_DVB_STV0900)
+#if IS_REACHABLE(CONFIG_DVB_STV0900)
extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
struct i2c_adapter *i2c, int demod);
#else
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 742eeda..012e55e 100644
--- a/drivers/media/dvb-frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -107,7 +107,7 @@ struct stv090x_config {
u8 xor_value);
};
-#if IS_ENABLED(CONFIG_DVB_STV090x)
+#if IS_REACHABLE(CONFIG_DVB_STV090x)
struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h
index 8fa07e6..f3c8a5c 100644
--- a/drivers/media/dvb-frontends/stv6110.h
+++ b/drivers/media/dvb-frontends/stv6110.h
@@ -46,7 +46,7 @@ struct stv6110_config {
u8 clk_div; /* divisor value for the output clock */
};
-#if IS_ENABLED(CONFIG_DVB_STV6110)
+#if IS_REACHABLE(CONFIG_DVB_STV6110)
extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
const struct stv6110_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index bc4766d..9f7eb25 100644
--- a/drivers/media/dvb-frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -53,7 +53,7 @@ struct stv6110x_devctl {
};
-#if IS_ENABLED(CONFIG_DVB_STV6110x)
+#if IS_REACHABLE(CONFIG_DVB_STV6110x)
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h
index e404b6e..0d33461 100644
--- a/drivers/media/dvb-frontends/tda1002x.h
+++ b/drivers/media/dvb-frontends/tda1002x.h
@@ -57,7 +57,7 @@ struct tda10023_config {
u16 deltaf;
};
-#if IS_ENABLED(CONFIG_DVB_TDA10021)
+#if IS_REACHABLE(CONFIG_DVB_TDA10021)
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
@@ -69,7 +69,7 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
}
#endif // CONFIG_DVB_TDA10021
-#if IS_ENABLED(CONFIG_DVB_TDA10023)
+#if IS_REACHABLE(CONFIG_DVB_TDA10023)
extern struct dvb_frontend *tda10023_attach(
const struct tda10023_config *config,
struct i2c_adapter *i2c, u8 pwm);
diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h
index 5e7bf4e..bc77a73 100644
--- a/drivers/media/dvb-frontends/tda10048.h
+++ b/drivers/media/dvb-frontends/tda10048.h
@@ -73,7 +73,7 @@ struct tda10048_config {
u8 pll_n;
};
-#if IS_ENABLED(CONFIG_DVB_TDA10048)
+#if IS_REACHABLE(CONFIG_DVB_TDA10048)
extern struct dvb_frontend *tda10048_attach(
const struct tda10048_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h
index dd283fb..efd7659 100644
--- a/drivers/media/dvb-frontends/tda1004x.h
+++ b/drivers/media/dvb-frontends/tda1004x.h
@@ -117,7 +117,7 @@ struct tda1004x_state {
enum tda1004x_demod demod_type;
};
-#if IS_ENABLED(CONFIG_DVB_TDA1004X)
+#if IS_REACHABLE(CONFIG_DVB_TDA1004X)
extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index 331b5a8..da89f42 100644
--- a/drivers/media/dvb-frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -72,7 +72,7 @@ struct tda10071_config {
};
-#if IS_ENABLED(CONFIG_DVB_TDA10071)
+#if IS_REACHABLE(CONFIG_DVB_TDA10071)
extern struct dvb_frontend *tda10071_attach(
const struct tda10071_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h
index 458fe91..690e469 100644
--- a/drivers/media/dvb-frontends/tda10086.h
+++ b/drivers/media/dvb-frontends/tda10086.h
@@ -46,7 +46,7 @@ struct tda10086_config
enum tda10086_xtal xtal_freq;
};
-#if IS_ENABLED(CONFIG_DVB_TDA10086)
+#if IS_REACHABLE(CONFIG_DVB_TDA10086)
extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h
index dd84f7b..7ebd8ea 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd.h
@@ -3,7 +3,7 @@
#include <linux/kconfig.h>
-#if IS_ENABLED(CONFIG_DVB_TDA18271C2DD)
+#if IS_REACHABLE(CONFIG_DVB_TDA18271C2DD)
struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 adr);
#else
diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h
index 03a0da6..baf520b 100644
--- a/drivers/media/dvb-frontends/tda665x.h
+++ b/drivers/media/dvb-frontends/tda665x.h
@@ -31,7 +31,7 @@ struct tda665x_config {
u32 ref_divider;
};
-#if IS_ENABLED(CONFIG_DVB_TDA665x)
+#if IS_REACHABLE(CONFIG_DVB_TDA665x)
extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
const struct tda665x_config *config,
diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h
index de6b186..46be06f 100644
--- a/drivers/media/dvb-frontends/tda8083.h
+++ b/drivers/media/dvb-frontends/tda8083.h
@@ -35,7 +35,7 @@ struct tda8083_config
u8 demod_address;
};
-#if IS_ENABLED(CONFIG_DVB_TDA8083)
+#if IS_REACHABLE(CONFIG_DVB_TDA8083)
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h
index 55cf4ff..9fa5b30 100644
--- a/drivers/media/dvb-frontends/tda8261.h
+++ b/drivers/media/dvb-frontends/tda8261.h
@@ -34,7 +34,7 @@ struct tda8261_config {
enum tda8261_step step_size;
};
-#if IS_ENABLED(CONFIG_DVB_TDA8261)
+#if IS_REACHABLE(CONFIG_DVB_TDA8261)
extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
index 5f0f20e..81abe1a 100644
--- a/drivers/media/dvb-frontends/tda826x.h
+++ b/drivers/media/dvb-frontends/tda826x.h
@@ -35,7 +35,7 @@
* @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
* @return FE pointer on success, NULL on failure.
*/
-#if IS_ENABLED(CONFIG_DVB_TDA826X)
+#if IS_REACHABLE(CONFIG_DVB_TDA826X)
extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
int has_loopthrough);
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index 9aba044..90164a3 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -26,12 +26,23 @@
#define FREQ_OFFSET_LOW_SYM_RATE 3000
struct ts2020_priv {
+ struct dvb_frontend *fe;
/* i2c details */
int i2c_address;
struct i2c_adapter *i2c;
- u8 clk_out_div;
+ u8 clk_out:2;
+ u8 clk_out_div:5;
u32 frequency;
u32 frequency_div;
+#define TS2020_M88TS2020 0
+#define TS2020_M88TS2022 1
+ u8 tuner;
+ u8 loop_through:1;
+};
+
+struct ts2020_reg_val {
+ u8 reg;
+ u8 val;
};
static int ts2020_release(struct dvb_frontend *fe)
@@ -112,40 +123,77 @@ static int ts2020_readreg(struct dvb_frontend *fe, u8 reg)
static int ts2020_sleep(struct dvb_frontend *fe)
{
struct ts2020_priv *priv = fe->tuner_priv;
- int ret;
- u8 buf[] = { 10, 0 };
- struct i2c_msg msg = {
- .addr = priv->i2c_address,
- .flags = 0,
- .buf = buf,
- .len = 2
- };
+ u8 u8tmp;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- ret = i2c_transfer(priv->i2c, &msg, 1);
- if (ret != 1)
- printk(KERN_ERR "%s: i2c error\n", __func__);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (priv->tuner == TS2020_M88TS2020)
+ u8tmp = 0x0a; /* XXX: probably wrong */
+ else
+ u8tmp = 0x00;
- return (ret == 1) ? 0 : ret;
+ return ts2020_writereg(fe, u8tmp, 0x00);
}
static int ts2020_init(struct dvb_frontend *fe)
{
struct ts2020_priv *priv = fe->tuner_priv;
+ int i;
+ u8 u8tmp;
+
+ if (priv->tuner == TS2020_M88TS2020) {
+ ts2020_writereg(fe, 0x42, 0x73);
+ ts2020_writereg(fe, 0x05, priv->clk_out_div);
+ ts2020_writereg(fe, 0x20, 0x27);
+ ts2020_writereg(fe, 0x07, 0x02);
+ ts2020_writereg(fe, 0x11, 0xff);
+ ts2020_writereg(fe, 0x60, 0xf9);
+ ts2020_writereg(fe, 0x08, 0x01);
+ ts2020_writereg(fe, 0x00, 0x41);
+ } else {
+ static const struct ts2020_reg_val reg_vals[] = {
+ {0x7d, 0x9d},
+ {0x7c, 0x9a},
+ {0x7a, 0x76},
+ {0x3b, 0x01},
+ {0x63, 0x88},
+ {0x61, 0x85},
+ {0x22, 0x30},
+ {0x30, 0x40},
+ {0x20, 0x23},
+ {0x24, 0x02},
+ {0x12, 0xa0},
+ };
+
+ ts2020_writereg(fe, 0x00, 0x01);
+ ts2020_writereg(fe, 0x00, 0x03);
+
+ switch (priv->clk_out) {
+ case TS2020_CLK_OUT_DISABLED:
+ u8tmp = 0x60;
+ break;
+ case TS2020_CLK_OUT_ENABLED:
+ u8tmp = 0x70;
+ ts2020_writereg(fe, 0x05, priv->clk_out_div);
+ break;
+ case TS2020_CLK_OUT_ENABLED_XTALOUT:
+ u8tmp = 0x6c;
+ break;
+ default:
+ u8tmp = 0x60;
+ break;
+ }
- ts2020_writereg(fe, 0x42, 0x73);
- ts2020_writereg(fe, 0x05, priv->clk_out_div);
- ts2020_writereg(fe, 0x20, 0x27);
- ts2020_writereg(fe, 0x07, 0x02);
- ts2020_writereg(fe, 0x11, 0xff);
- ts2020_writereg(fe, 0x60, 0xf9);
- ts2020_writereg(fe, 0x08, 0x01);
- ts2020_writereg(fe, 0x00, 0x41);
+ ts2020_writereg(fe, 0x42, u8tmp);
+
+ if (priv->loop_through)
+ u8tmp = 0xec;
+ else
+ u8tmp = 0x6c;
+
+ ts2020_writereg(fe, 0x62, u8tmp);
+
+ for (i = 0; i < ARRAY_SIZE(reg_vals); i++)
+ ts2020_writereg(fe, reg_vals[i].reg, reg_vals[i].val);
+ }
return 0;
}
@@ -203,7 +251,14 @@ static int ts2020_set_params(struct dvb_frontend *fe)
ndiv = ndiv + ndiv % 2;
ndiv = ndiv - 1024;
- ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
+ if (priv->tuner == TS2020_M88TS2020) {
+ lpf_coeff = 2766;
+ ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
+ } else {
+ lpf_coeff = 3200;
+ ret = ts2020_writereg(fe, 0x10, 0x0b);
+ ret |= ts2020_writereg(fe, 0x11, 0x40);
+ }
/* Set frequency divider */
ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf);
@@ -220,7 +275,8 @@ static int ts2020_set_params(struct dvb_frontend *fe)
ret |= ts2020_tuner_gate_ctrl(fe, 0x08);
/* Tuner RF */
- ret |= ts2020_set_tuner_rf(fe);
+ if (priv->tuner == TS2020_M88TS2020)
+ ret |= ts2020_set_tuner_rf(fe);
gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000;
ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff);
@@ -228,6 +284,15 @@ static int ts2020_set_params(struct dvb_frontend *fe)
if (ret < 0)
return -ENODEV;
+ if (priv->tuner == TS2020_M88TS2022) {
+ ret = ts2020_writereg(fe, 0x25, 0x00);
+ ret |= ts2020_writereg(fe, 0x27, 0x70);
+ ret |= ts2020_writereg(fe, 0x41, 0x09);
+ ret |= ts2020_writereg(fe, 0x08, 0x0b);
+ if (ret < 0)
+ return -ENODEV;
+ }
+
value = ts2020_readreg(fe, 0x26);
f3db = (symbol_rate * 135) / 200 + 2000;
@@ -243,8 +308,6 @@ static int ts2020_set_params(struct dvb_frontend *fe)
if (mlpf_max > 63)
mlpf_max = 63;
- lpf_coeff = 2766;
-
nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
(TS2020_XTAL_FREQ / 1000) + 1) / 2;
if (nlpf > 23)
@@ -285,6 +348,13 @@ static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct ts2020_priv *priv = fe->tuner_priv;
*frequency = priv->frequency;
+
+ return 0;
+}
+
+static int ts2020_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ *frequency = 0; /* Zero-IF */
return 0;
}
@@ -324,6 +394,7 @@ static struct dvb_tuner_ops ts2020_tuner_ops = {
.sleep = ts2020_sleep,
.set_params = ts2020_set_params,
.get_frequency = ts2020_get_frequency,
+ .get_if_frequency = ts2020_get_if_frequency,
.get_rf_strength = ts2020_read_signal_strength,
};
@@ -340,8 +411,10 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
priv->i2c_address = config->tuner_address;
priv->i2c = i2c;
+ priv->clk_out = config->clk_out;
priv->clk_out_div = config->clk_out_div;
priv->frequency_div = config->frequency_div;
+ priv->fe = fe;
fe->tuner_priv = priv;
if (!priv->frequency_div)
@@ -358,9 +431,13 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
/* Check the tuner version */
buf = ts2020_readreg(fe, 0x00);
- if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81))
+ if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81)) {
printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__);
- else {
+ priv->tuner = TS2020_M88TS2020;
+ } else if ((buf == 0x83) || (buf == 0xc3)) {
+ printk(KERN_INFO "%s: Find tuner TS2022!\n", __func__);
+ priv->tuner = TS2020_M88TS2022;
+ } else {
printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf);
kfree(priv);
return NULL;
@@ -373,6 +450,165 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
}
EXPORT_SYMBOL(ts2020_attach);
+static int ts2020_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ts2020_config *pdata = client->dev.platform_data;
+ struct dvb_frontend *fe = pdata->fe;
+ struct ts2020_priv *dev;
+ int ret;
+ u8 u8tmp;
+ unsigned int utmp;
+ char *chip_str;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->i2c = client->adapter;
+ dev->i2c_address = client->addr;
+ dev->clk_out = pdata->clk_out;
+ dev->clk_out_div = pdata->clk_out_div;
+ dev->frequency_div = pdata->frequency_div;
+ dev->fe = fe;
+ fe->tuner_priv = dev;
+
+ /* check if the tuner is there */
+ ret = ts2020_readreg(fe, 0x00);
+ if (ret < 0)
+ goto err;
+ utmp = ret;
+
+ if ((utmp & 0x03) == 0x00) {
+ ret = ts2020_writereg(fe, 0x00, 0x01);
+ if (ret)
+ goto err;
+
+ usleep_range(2000, 50000);
+ }
+
+ ret = ts2020_writereg(fe, 0x00, 0x03);
+ if (ret)
+ goto err;
+
+ usleep_range(2000, 50000);
+
+ ret = ts2020_readreg(fe, 0x00);
+ if (ret < 0)
+ goto err;
+ utmp = ret;
+
+ dev_dbg(&client->dev, "chip_id=%02x\n", utmp);
+
+ switch (utmp) {
+ case 0x01:
+ case 0x41:
+ case 0x81:
+ dev->tuner = TS2020_M88TS2020;
+ chip_str = "TS2020";
+ if (!dev->frequency_div)
+ dev->frequency_div = 1060000;
+ break;
+ case 0xc3:
+ case 0x83:
+ dev->tuner = TS2020_M88TS2022;
+ chip_str = "TS2022";
+ if (!dev->frequency_div)
+ dev->frequency_div = 1103000;
+ break;
+ default:
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (dev->tuner == TS2020_M88TS2022) {
+ switch (dev->clk_out) {
+ case TS2020_CLK_OUT_DISABLED:
+ u8tmp = 0x60;
+ break;
+ case TS2020_CLK_OUT_ENABLED:
+ u8tmp = 0x70;
+ ret = ts2020_writereg(fe, 0x05, dev->clk_out_div);
+ if (ret)
+ goto err;
+ break;
+ case TS2020_CLK_OUT_ENABLED_XTALOUT:
+ u8tmp = 0x6c;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = ts2020_writereg(fe, 0x42, u8tmp);
+ if (ret)
+ goto err;
+
+ if (dev->loop_through)
+ u8tmp = 0xec;
+ else
+ u8tmp = 0x6c;
+
+ ret = ts2020_writereg(fe, 0x62, u8tmp);
+ if (ret)
+ goto err;
+ }
+
+ /* sleep */
+ ret = ts2020_writereg(fe, 0x00, 0x00);
+ if (ret)
+ goto err;
+
+ dev_info(&client->dev,
+ "Montage Technology %s successfully identified\n", chip_str);
+
+ memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ fe->ops.tuner_ops.release = NULL;
+
+ i2c_set_clientdata(client, dev);
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ kfree(dev);
+ return ret;
+}
+
+static int ts2020_remove(struct i2c_client *client)
+{
+ struct ts2020_priv *dev = i2c_get_clientdata(client);
+ struct dvb_frontend *fe = dev->fe;
+
+ dev_dbg(&client->dev, "\n");
+
+ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = NULL;
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id ts2020_id_table[] = {
+ {"ts2020", 0},
+ {"ts2022", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ts2020_id_table);
+
+static struct i2c_driver ts2020_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ts2020",
+ },
+ .probe = ts2020_probe,
+ .remove = ts2020_remove,
+ .id_table = ts2020_id_table,
+};
+
+module_i2c_driver(ts2020_driver);
+
MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h
index b2fe6bb..1714af9 100644
--- a/drivers/media/dvb-frontends/ts2020.h
+++ b/drivers/media/dvb-frontends/ts2020.h
@@ -27,11 +27,34 @@
struct ts2020_config {
u8 tuner_address;
- u8 clk_out_div;
u32 frequency_div;
+
+ /*
+ * RF loop-through
+ */
+ u8 loop_through:1;
+
+ /*
+ * clock output
+ */
+#define TS2020_CLK_OUT_DISABLED 0
+#define TS2020_CLK_OUT_ENABLED 1
+#define TS2020_CLK_OUT_ENABLED_XTALOUT 2
+ u8 clk_out:2;
+
+ /*
+ * clock output divider
+ * 1 - 31
+ */
+ u8 clk_out_div:5;
+
+ /*
+ * pointer to DVB frontend
+ */
+ struct dvb_frontend *fe;
};
-#if IS_ENABLED(CONFIG_DVB_TS2020)
+#if IS_REACHABLE(CONFIG_DVB_TS2020)
extern struct dvb_frontend *ts2020_attach(
struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h
index 83a9c30..52919e0 100644
--- a/drivers/media/dvb-frontends/tua6100.h
+++ b/drivers/media/dvb-frontends/tua6100.h
@@ -34,7 +34,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if IS_ENABLED(CONFIG_DVB_TUA6100)
+#if IS_REACHABLE(CONFIG_DVB_TUA6100)
extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h
index c073f35..ece46fd 100644
--- a/drivers/media/dvb-frontends/ves1820.h
+++ b/drivers/media/dvb-frontends/ves1820.h
@@ -41,7 +41,7 @@ struct ves1820_config
u8 selagc:1;
};
-#if IS_ENABLED(CONFIG_DVB_VES1820)
+#if IS_REACHABLE(CONFIG_DVB_VES1820)
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h
index 2307cae..4510fe2 100644
--- a/drivers/media/dvb-frontends/ves1x93.h
+++ b/drivers/media/dvb-frontends/ves1x93.h
@@ -40,7 +40,7 @@ struct ves1x93_config
u8 invert_pwm:1;
};
-#if IS_ENABLED(CONFIG_DVB_VES1X93)
+#if IS_REACHABLE(CONFIG_DVB_VES1X93)
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h
index 5f1e821..670e76a 100644
--- a/drivers/media/dvb-frontends/zl10036.h
+++ b/drivers/media/dvb-frontends/zl10036.h
@@ -38,7 +38,7 @@ struct zl10036_config {
int rf_loop_enable;
};
-#if IS_ENABLED(CONFIG_DVB_ZL10036)
+#if IS_REACHABLE(CONFIG_DVB_ZL10036)
extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
const struct zl10036_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h
index 750b9bc..0709294 100644
--- a/drivers/media/dvb-frontends/zl10039.h
+++ b/drivers/media/dvb-frontends/zl10039.h
@@ -24,7 +24,7 @@
#include <linux/kconfig.h>
-#if IS_ENABLED(CONFIG_DVB_ZL10039)
+#if IS_REACHABLE(CONFIG_DVB_ZL10039)
struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
u8 i2c_addr,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h
index 50c1004..37aa6e8 100644
--- a/drivers/media/dvb-frontends/zl10353.h
+++ b/drivers/media/dvb-frontends/zl10353.h
@@ -47,7 +47,7 @@ struct zl10353_config
u8 pll_0; /* default: 0x15 */
};
-#if IS_ENABLED(CONFIG_DVB_ZL10353)
+#if IS_REACHABLE(CONFIG_DVB_ZL10353)
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index da58c9b..6f30ea7 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -466,6 +466,17 @@ config VIDEO_APTINA_PLL
config VIDEO_SMIAPP_PLL
tristate
+config VIDEO_OV2659
+ tristate "OmniVision OV2659 sensor support"
+ depends on VIDEO_V4L2 && I2C
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV2659 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov2659.
+
config VIDEO_OV7640
tristate "OmniVision OV7640 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 98589001..f165fae 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -77,3 +77,4 @@ obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
+obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index fada175..69094ab 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -239,8 +239,8 @@ static void ad9389b_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
- if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
- /* CEA format, not IT */
+ if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+ /* CE format, not IT */
ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x00);
} else {
/* IT format */
@@ -255,11 +255,11 @@ static int ad9389b_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2
switch (ctrl->val) {
case V4L2_DV_RGB_RANGE_AUTO:
/* automatic */
- if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
- /* cea format, RGB limited range (16-235) */
+ if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+ /* CE format, RGB limited range (16-235) */
ad9389b_csc_rgb_full2limit(sd, true);
} else {
- /* not cea format, RGB full range (0-255) */
+ /* not CE format, RGB full range (0-255) */
ad9389b_csc_rgb_full2limit(sd, false);
}
break;
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index b75878c..a493c0b 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -582,7 +582,7 @@ static void adv7180_exit_controls(struct adv7180_state *state)
}
static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -645,13 +645,13 @@ static int adv7180_set_field_mode(struct adv7180_state *state)
}
static int adv7180_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct adv7180_state *state = to_state(sd);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(fh, 0);
+ format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
} else {
adv7180_mbus_fmt(sd, &format->format);
format->format.field = state->field;
@@ -661,7 +661,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd,
}
static int adv7180_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct adv7180_state *state = to_state(sd);
@@ -686,7 +686,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
adv7180_set_power(state, true);
}
} else {
- framefmt = v4l2_subdev_get_try_format(fh, 0);
+ framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
*framefmt = format->format;
}
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index 9d38f7b..7c50833 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -506,7 +506,6 @@ static int adv7343_remove(struct i2c_client *client)
struct adv7343_state *state = to_state(sd);
v4l2_async_unregister_subdev(&state->sd);
- v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
return 0;
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 81736aa..12d9320 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -312,8 +312,8 @@ static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)
static void adv7511_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd)
{
struct adv7511_state *state = get_adv7511_state(sd);
- if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
- /* CEA format, not IT */
+ if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+ /* CE format, not IT */
adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00);
} else {
/* IT format */
@@ -331,11 +331,11 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2
/* automatic */
struct adv7511_state *state = get_adv7511_state(sd);
- if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
- /* cea format, RGB limited range (16-235) */
+ if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
+ /* CE format, RGB limited range (16-235) */
adv7511_csc_rgb_full2limit(sd, true);
} else {
- /* not cea format, RGB full range (0-255) */
+ /* not CE format, RGB full range (0-255) */
adv7511_csc_rgb_full2limit(sd, false);
}
}
@@ -810,7 +810,7 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
}
static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad != 0)
@@ -842,8 +842,9 @@ static void adv7511_fill_format(struct adv7511_state *state,
format->field = V4L2_FIELD_NONE;
}
-static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *format)
+static int adv7511_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
struct adv7511_state *state = get_adv7511_state(sd);
@@ -855,7 +856,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
format->format.code = fmt->code;
format->format.colorspace = fmt->colorspace;
format->format.ycbcr_enc = fmt->ycbcr_enc;
@@ -870,8 +871,9 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *format)
+static int adv7511_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
struct adv7511_state *state = get_adv7511_state(sd);
/*
@@ -905,7 +907,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
fmt->code = format->format.code;
fmt->colorspace = format->format.colorspace;
fmt->ycbcr_enc = format->format.ycbcr_enc;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index d228b7c..60ffcf0 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -53,41 +53,41 @@ MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
MODULE_LICENSE("GPL");
/* ADV7604 system clock frequency */
-#define ADV7604_fsc (28636360)
+#define ADV76XX_FSC (28636360)
-#define ADV7604_RGB_OUT (1 << 1)
+#define ADV76XX_RGB_OUT (1 << 1)
-#define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0)
+#define ADV76XX_OP_FORMAT_SEL_8BIT (0 << 0)
#define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0)
-#define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0)
+#define ADV76XX_OP_FORMAT_SEL_12BIT (2 << 0)
-#define ADV7604_OP_MODE_SEL_SDR_422 (0 << 5)
+#define ADV76XX_OP_MODE_SEL_SDR_422 (0 << 5)
#define ADV7604_OP_MODE_SEL_DDR_422 (1 << 5)
-#define ADV7604_OP_MODE_SEL_SDR_444 (2 << 5)
+#define ADV76XX_OP_MODE_SEL_SDR_444 (2 << 5)
#define ADV7604_OP_MODE_SEL_DDR_444 (3 << 5)
-#define ADV7604_OP_MODE_SEL_SDR_422_2X (4 << 5)
+#define ADV76XX_OP_MODE_SEL_SDR_422_2X (4 << 5)
#define ADV7604_OP_MODE_SEL_ADI_CM (5 << 5)
-#define ADV7604_OP_CH_SEL_GBR (0 << 5)
-#define ADV7604_OP_CH_SEL_GRB (1 << 5)
-#define ADV7604_OP_CH_SEL_BGR (2 << 5)
-#define ADV7604_OP_CH_SEL_RGB (3 << 5)
-#define ADV7604_OP_CH_SEL_BRG (4 << 5)
-#define ADV7604_OP_CH_SEL_RBG (5 << 5)
+#define ADV76XX_OP_CH_SEL_GBR (0 << 5)
+#define ADV76XX_OP_CH_SEL_GRB (1 << 5)
+#define ADV76XX_OP_CH_SEL_BGR (2 << 5)
+#define ADV76XX_OP_CH_SEL_RGB (3 << 5)
+#define ADV76XX_OP_CH_SEL_BRG (4 << 5)
+#define ADV76XX_OP_CH_SEL_RBG (5 << 5)
-#define ADV7604_OP_SWAP_CB_CR (1 << 0)
+#define ADV76XX_OP_SWAP_CB_CR (1 << 0)
-enum adv7604_type {
+enum adv76xx_type {
ADV7604,
ADV7611,
};
-struct adv7604_reg_seq {
+struct adv76xx_reg_seq {
unsigned int reg;
u8 val;
};
-struct adv7604_format_info {
+struct adv76xx_format_info {
u32 code;
u8 op_ch_sel;
bool rgb_out;
@@ -95,8 +95,8 @@ struct adv7604_format_info {
u8 op_format_sel;
};
-struct adv7604_chip_info {
- enum adv7604_type type;
+struct adv76xx_chip_info {
+ enum adv76xx_type type;
bool has_afe;
unsigned int max_port;
@@ -109,8 +109,9 @@ struct adv7604_chip_info {
unsigned int cable_det_mask;
unsigned int tdms_lock_mask;
unsigned int fmt_change_digital_mask;
+ unsigned int cp_csc;
- const struct adv7604_format_info *formats;
+ const struct adv76xx_format_info *formats;
unsigned int nformats;
void (*set_termination)(struct v4l2_subdev *sd, bool enable);
@@ -119,7 +120,7 @@ struct adv7604_chip_info {
unsigned int (*read_cable_det)(struct v4l2_subdev *sd);
/* 0 = AFE, 1 = HDMI */
- const struct adv7604_reg_seq *recommended_settings[2];
+ const struct adv76xx_reg_seq *recommended_settings[2];
unsigned int num_recommended_settings[2];
unsigned long page_mask;
@@ -133,22 +134,22 @@ struct adv7604_chip_info {
**********************************************************************
*/
-struct adv7604_state {
- const struct adv7604_chip_info *info;
- struct adv7604_platform_data pdata;
+struct adv76xx_state {
+ const struct adv76xx_chip_info *info;
+ struct adv76xx_platform_data pdata;
struct gpio_desc *hpd_gpio[4];
struct v4l2_subdev sd;
- struct media_pad pads[ADV7604_PAD_MAX];
+ struct media_pad pads[ADV76XX_PAD_MAX];
unsigned int source_pad;
struct v4l2_ctrl_handler hdl;
- enum adv7604_pad selected_input;
+ enum adv76xx_pad selected_input;
struct v4l2_dv_timings timings;
- const struct adv7604_format_info *format;
+ const struct adv76xx_format_info *format;
struct {
u8 edid[256];
@@ -163,7 +164,7 @@ struct adv7604_state {
bool restart_stdi_once;
/* i2c clients */
- struct i2c_client *i2c_clients[ADV7604_PAGE_MAX];
+ struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX];
/* controls */
struct v4l2_ctrl *detect_tx_5v_ctrl;
@@ -173,13 +174,13 @@ struct adv7604_state {
struct v4l2_ctrl *rgb_quantization_range_ctrl;
};
-static bool adv7604_has_afe(struct adv7604_state *state)
+static bool adv76xx_has_afe(struct adv76xx_state *state)
{
return state->info->has_afe;
}
/* Supported CEA and DMT timings */
-static const struct v4l2_dv_timings adv7604_timings[] = {
+static const struct v4l2_dv_timings adv76xx_timings[] = {
V4L2_DV_BT_CEA_720X480P59_94,
V4L2_DV_BT_CEA_720X576P50,
V4L2_DV_BT_CEA_1280X720P24,
@@ -243,14 +244,14 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
{ },
};
-struct adv7604_video_standards {
+struct adv76xx_video_standards {
struct v4l2_dv_timings timings;
u8 vid_std;
u8 v_freq;
};
/* sorted by number of lines */
-static const struct adv7604_video_standards adv7604_prim_mode_comp[] = {
+static const struct adv76xx_video_standards adv7604_prim_mode_comp[] = {
/* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */
{ V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
{ V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 },
@@ -265,7 +266,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_comp[] = {
};
/* sorted by number of lines */
-static const struct adv7604_video_standards adv7604_prim_mode_gr[] = {
+static const struct adv76xx_video_standards adv7604_prim_mode_gr[] = {
{ V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
{ V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
{ V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
@@ -293,7 +294,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_gr[] = {
};
/* sorted by number of lines */
-static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = {
+static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_comp[] = {
{ V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 },
{ V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
{ V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 },
@@ -307,7 +308,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = {
};
/* sorted by number of lines */
-static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = {
+static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_gr[] = {
{ V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
{ V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
{ V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
@@ -328,9 +329,9 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = {
/* ----------------------------------------------------------------------- */
-static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
+static inline struct adv76xx_state *to_state(struct v4l2_subdev *sd)
{
- return container_of(sd, struct adv7604_state, sd);
+ return container_of(sd, struct adv76xx_state, sd);
}
static inline unsigned htotal(const struct v4l2_bt_timings *t)
@@ -360,15 +361,15 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
return -EIO;
}
-static s32 adv_smbus_read_byte_data(struct adv7604_state *state,
- enum adv7604_page page, u8 command)
+static s32 adv_smbus_read_byte_data(struct adv76xx_state *state,
+ enum adv76xx_page page, u8 command)
{
return adv_smbus_read_byte_data_check(state->i2c_clients[page],
command, true);
}
-static s32 adv_smbus_write_byte_data(struct adv7604_state *state,
- enum adv7604_page page, u8 command,
+static s32 adv_smbus_write_byte_data(struct adv76xx_state *state,
+ enum adv76xx_page page, u8 command,
u8 value)
{
struct i2c_client *client = state->i2c_clients[page];
@@ -391,8 +392,8 @@ static s32 adv_smbus_write_byte_data(struct adv7604_state *state,
return err;
}
-static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state,
- enum adv7604_page page, u8 command,
+static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state,
+ enum adv76xx_page page, u8 command,
unsigned length, const u8 *values)
{
struct i2c_client *client = state->i2c_clients[page];
@@ -411,16 +412,16 @@ static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state,
static inline int io_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg);
}
static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val);
}
static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -430,73 +431,73 @@ static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v
static inline int avlink_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg);
}
static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val);
}
static inline int cec_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg);
}
static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val);
}
static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg);
}
static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME,
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME,
reg, val);
}
static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg);
}
static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val);
}
static inline int rep_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg);
}
static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val);
}
static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -506,64 +507,60 @@ static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8
static inline int edid_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg);
}
static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val);
}
static inline int edid_write_block(struct v4l2_subdev *sd,
unsigned len, const u8 *val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
int err = 0;
int i;
v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
- err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID,
+ err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID,
i, I2C_SMBUS_BLOCK_MAX, val + i);
return err;
}
-static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd)
+static void adv76xx_set_hpd(struct adv76xx_state *state, unsigned int hpd)
{
unsigned int i;
- for (i = 0; i < state->info->num_dv_ports; ++i) {
- if (IS_ERR(state->hpd_gpio[i]))
- continue;
-
+ for (i = 0; i < state->info->num_dv_ports; ++i)
gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i));
- }
- v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd);
+ v4l2_subdev_notify(&state->sd, ADV76XX_HOTPLUG, &hpd);
}
-static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
+static void adv76xx_delayed_work_enable_hotplug(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
- struct adv7604_state *state = container_of(dwork, struct adv7604_state,
+ struct adv76xx_state *state = container_of(dwork, struct adv76xx_state,
delayed_work_enable_hotplug);
struct v4l2_subdev *sd = &state->sd;
v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
- adv7604_set_hpd(state, state->edid.present);
+ adv76xx_set_hpd(state, state->edid.present);
}
static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg);
}
static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
@@ -573,9 +570,9 @@ static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val);
}
static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -585,16 +582,16 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8
static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val);
}
static inline int cp_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg);
+ return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg);
}
static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
@@ -604,9 +601,9 @@ static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val);
+ return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val);
}
static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -616,25 +613,25 @@ static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v
static inline int vdp_read(struct v4l2_subdev *sd, u8 reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg);
}
static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val);
}
-#define ADV7604_REG(page, offset) (((page) << 8) | (offset))
-#define ADV7604_REG_SEQ_TERM 0xffff
+#define ADV76XX_REG(page, offset) (((page) << 8) | (offset))
+#define ADV76XX_REG_SEQ_TERM 0xffff
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg)
+static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
unsigned int page = reg >> 8;
if (!(BIT(page) & state->info->page_mask))
@@ -646,9 +643,9 @@ static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg)
}
#endif
-static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val)
+static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
unsigned int page = reg >> 8;
if (!(BIT(page) & state->info->page_mask))
@@ -659,91 +656,91 @@ static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val)
return adv_smbus_write_byte_data(state, page, reg, val);
}
-static void adv7604_write_reg_seq(struct v4l2_subdev *sd,
- const struct adv7604_reg_seq *reg_seq)
+static void adv76xx_write_reg_seq(struct v4l2_subdev *sd,
+ const struct adv76xx_reg_seq *reg_seq)
{
unsigned int i;
- for (i = 0; reg_seq[i].reg != ADV7604_REG_SEQ_TERM; i++)
- adv7604_write_reg(sd, reg_seq[i].reg, reg_seq[i].val);
+ for (i = 0; reg_seq[i].reg != ADV76XX_REG_SEQ_TERM; i++)
+ adv76xx_write_reg(sd, reg_seq[i].reg, reg_seq[i].val);
}
/* -----------------------------------------------------------------------------
* Format helpers
*/
-static const struct adv7604_format_info adv7604_formats[] = {
- { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
- ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+static const struct adv76xx_format_info adv7604_formats[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false,
+ ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV10_2X10, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_YVYU10_2X10, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_UYVY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_VYUY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_YUYV10_1X20, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_YVYU10_1X20, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
};
-static const struct adv7604_format_info adv7611_formats[] = {
- { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
- ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
- ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+static const struct adv76xx_format_info adv7611_formats[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false,
+ ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+ { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
+ { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true,
+ ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
};
-static const struct adv7604_format_info *
-adv7604_format_info(struct adv7604_state *state, u32 code)
+static const struct adv76xx_format_info *
+adv76xx_format_info(struct adv76xx_state *state, u32 code)
{
unsigned int i;
@@ -759,7 +756,7 @@ adv7604_format_info(struct adv7604_state *state, u32 code)
static inline bool is_analog_input(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return state->selected_input == ADV7604_PAD_VGA_RGB ||
state->selected_input == ADV7604_PAD_VGA_COMP;
@@ -767,9 +764,9 @@ static inline bool is_analog_input(struct v4l2_subdev *sd)
static inline bool is_digital_input(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- return state->selected_input == ADV7604_PAD_HDMI_PORT_A ||
+ return state->selected_input == ADV76XX_PAD_HDMI_PORT_A ||
state->selected_input == ADV7604_PAD_HDMI_PORT_B ||
state->selected_input == ADV7604_PAD_HDMI_PORT_C ||
state->selected_input == ADV7604_PAD_HDMI_PORT_D;
@@ -778,7 +775,7 @@ static inline bool is_digital_input(struct v4l2_subdev *sd)
/* ----------------------------------------------------------------------- */
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static void adv7604_inv_register(struct v4l2_subdev *sd)
+static void adv76xx_inv_register(struct v4l2_subdev *sd)
{
v4l2_info(sd, "0x000-0x0ff: IO Map\n");
v4l2_info(sd, "0x100-0x1ff: AVLink Map\n");
@@ -795,15 +792,15 @@ static void adv7604_inv_register(struct v4l2_subdev *sd)
v4l2_info(sd, "0xc00-0xcff: VDP Map\n");
}
-static int adv7604_g_register(struct v4l2_subdev *sd,
+static int adv76xx_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
int ret;
- ret = adv7604_read_reg(sd, reg->reg);
+ ret = adv76xx_read_reg(sd, reg->reg);
if (ret < 0) {
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
- adv7604_inv_register(sd);
+ adv76xx_inv_register(sd);
return ret;
}
@@ -813,15 +810,15 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
return 0;
}
-static int adv7604_s_register(struct v4l2_subdev *sd,
+static int adv76xx_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
int ret;
- ret = adv7604_write_reg(sd, reg->reg, reg->val);
+ ret = adv76xx_write_reg(sd, reg->reg, reg->val);
if (ret < 0) {
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
- adv7604_inv_register(sd);
+ adv76xx_inv_register(sd);
return ret;
}
@@ -846,10 +843,10 @@ static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd)
return value & 1;
}
-static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
+static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
info->read_cable_det(sd));
@@ -857,7 +854,7 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
u8 prim_mode,
- const struct adv7604_video_standards *predef_vid_timings,
+ const struct adv76xx_video_standards *predef_vid_timings,
const struct v4l2_dv_timings *timings)
{
int i;
@@ -878,12 +875,12 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
static int configure_predefined_video_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
int err;
v4l2_dbg(1, debug, sd, "%s", __func__);
- if (adv7604_has_afe(state)) {
+ if (adv76xx_has_afe(state)) {
/* reset to default values */
io_write(sd, 0x16, 0x43);
io_write(sd, 0x17, 0x5a);
@@ -909,10 +906,10 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd,
0x02, adv7604_prim_mode_gr, timings);
} else if (is_digital_input(sd)) {
err = find_and_set_predefined_video_timings(sd,
- 0x05, adv7604_prim_mode_hdmi_comp, timings);
+ 0x05, adv76xx_prim_mode_hdmi_comp, timings);
if (err)
err = find_and_set_predefined_video_timings(sd,
- 0x06, adv7604_prim_mode_hdmi_gr, timings);
+ 0x06, adv76xx_prim_mode_hdmi_gr, timings);
} else {
v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
__func__, state->selected_input);
@@ -926,7 +923,7 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd,
static void configure_custom_video_timings(struct v4l2_subdev *sd,
const struct v4l2_bt_timings *bt)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
u32 width = htotal(bt);
u32 height = vtotal(bt);
u16 cp_start_sav = bt->hsync + bt->hbackporch - 4;
@@ -934,7 +931,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
u16 cp_start_vbi = height - bt->vfrontporch;
u16 cp_end_vbi = bt->vsync + bt->vbackporch;
u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ?
- ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0;
+ ((width * (ADV76XX_FSC / 100)) / ((u32)bt->pixelclock / 100)) : 0;
const u8 pll[2] = {
0xc0 | ((width >> 8) & 0x1f),
width & 0xff
@@ -952,7 +949,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
/* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
/* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
/* IO-map reg. 0x16 and 0x17 should be written in sequence */
- if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO,
+ if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO,
0x16, 2, pll))
v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
@@ -983,9 +980,9 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
cp_write(sd, 0xac, (height & 0x0f) << 4);
}
-static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
+static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
u8 offset_buf[4];
if (auto_offset) {
@@ -1004,14 +1001,14 @@ static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off
offset_buf[3] = offset_c & 0x0ff;
/* Registers must be written in this order with no i2c access in between */
- if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP,
+ if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP,
0x77, 4, offset_buf))
v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
}
-static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
+static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
u8 gain_buf[4];
u8 gain_man = 1;
u8 agc_mode_man = 1;
@@ -1034,14 +1031,14 @@ static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a,
gain_buf[3] = ((gain_c & 0x0ff));
/* Registers must be written in this order with no i2c access in between */
- if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP,
+ if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP,
0x73, 4, gain_buf))
v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
}
static void set_rgb_quantization_range(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
bool rgb_output = io_read(sd, 0x02) & 0x02;
bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
@@ -1049,8 +1046,8 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
__func__, state->rgb_quantization_range,
rgb_output, hdmi_signal);
- adv7604_set_gain(sd, true, 0x0, 0x0, 0x0);
- adv7604_set_offset(sd, true, 0x0, 0x0, 0x0);
+ adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0);
+ adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0);
switch (state->rgb_quantization_range) {
case V4L2_DV_RGB_RANGE_AUTO:
@@ -1078,7 +1075,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
/* Receiving DVI-D signal
* ADV7604 selects RGB limited range regardless of
* input format (CE/IT) in automatic mode */
- if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
+ if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
/* RGB limited range (16-235) */
io_write_clr_set(sd, 0x02, 0xf0, 0x00);
} else {
@@ -1086,10 +1083,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
io_write_clr_set(sd, 0x02, 0xf0, 0x10);
if (is_digital_input(sd) && rgb_output) {
- adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
+ adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40);
} else {
- adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
- adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
+ adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+ adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70);
}
}
break;
@@ -1119,21 +1116,21 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
/* Adjust gain/offset for DVI-D signals only */
if (rgb_output) {
- adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
+ adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40);
} else {
- adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
- adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
+ adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+ adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70);
}
break;
}
}
-static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
+static int adv76xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd =
- &container_of(ctrl->handler, struct adv7604_state, hdl)->sd;
+ &container_of(ctrl->handler, struct adv76xx_state, hdl)->sd;
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1153,7 +1150,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
set_rgb_quantization_range(sd);
return 0;
case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE:
- if (!adv7604_has_afe(state))
+ if (!adv76xx_has_afe(state))
return -EINVAL;
/* Set the analog sampling phase. This is needed to find the
best sampling phase for analog video: an application or
@@ -1185,15 +1182,15 @@ static inline bool no_power(struct v4l2_subdev *sd)
static inline bool no_signal_tmds(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input));
}
static inline bool no_lock_tmds(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask;
}
@@ -1205,13 +1202,13 @@ static inline bool is_hdmi(struct v4l2_subdev *sd)
static inline bool no_lock_sspd(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
/*
* Chips without a AFE don't expose registers for the SSPD, so just assume
* that we have a lock.
*/
- if (adv7604_has_afe(state))
+ if (adv76xx_has_afe(state))
return false;
/* TODO channel 2 */
@@ -1243,9 +1240,9 @@ static inline bool no_signal(struct v4l2_subdev *sd)
static inline bool no_lock_cp(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- if (!adv7604_has_afe(state))
+ if (!adv76xx_has_afe(state))
return false;
/* CP has detected a non standard number of lines on the incoming
@@ -1253,13 +1250,19 @@ static inline bool no_lock_cp(struct v4l2_subdev *sd)
return io_read(sd, 0x12) & 0x01;
}
-static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status)
+static inline bool in_free_run(struct v4l2_subdev *sd)
+{
+ return cp_read(sd, 0xff) & 0x10;
+}
+
+static int adv76xx_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
*status = 0;
*status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0;
*status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
- if (no_lock_cp(sd))
- *status |= is_digital_input(sd) ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK;
+ if (!in_free_run(sd) && no_lock_cp(sd))
+ *status |= is_digital_input(sd) ?
+ V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK;
v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
@@ -1278,22 +1281,22 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
struct stdi_readback *stdi,
struct v4l2_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
- u32 hfreq = (ADV7604_fsc * 8) / stdi->bl;
+ struct adv76xx_state *state = to_state(sd);
+ u32 hfreq = (ADV76XX_FSC * 8) / stdi->bl;
u32 pix_clk;
int i;
- for (i = 0; adv7604_timings[i].bt.height; i++) {
- if (vtotal(&adv7604_timings[i].bt) != stdi->lcf + 1)
+ for (i = 0; adv76xx_timings[i].bt.height; i++) {
+ if (vtotal(&adv76xx_timings[i].bt) != stdi->lcf + 1)
continue;
- if (adv7604_timings[i].bt.vsync != stdi->lcvs)
+ if (adv76xx_timings[i].bt.vsync != stdi->lcvs)
continue;
- pix_clk = hfreq * htotal(&adv7604_timings[i].bt);
+ pix_clk = hfreq * htotal(&adv76xx_timings[i].bt);
- if ((pix_clk < adv7604_timings[i].bt.pixelclock + 1000000) &&
- (pix_clk > adv7604_timings[i].bt.pixelclock - 1000000)) {
- *timings = adv7604_timings[i];
+ if ((pix_clk < adv76xx_timings[i].bt.pixelclock + 1000000) &&
+ (pix_clk > adv76xx_timings[i].bt.pixelclock - 1000000)) {
+ *timings = adv76xx_timings[i];
return 0;
}
}
@@ -1319,8 +1322,8 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
u8 polarity;
if (no_lock_stdi(sd) || no_lock_sspd(sd)) {
@@ -1334,7 +1337,7 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
stdi->lcvs = cp_read(sd, 0xb3) >> 3;
stdi->interlaced = io_read(sd, 0x12) & 0x10;
- if (adv7604_has_afe(state)) {
+ if (adv76xx_has_afe(state)) {
/* read SSPD */
polarity = cp_read(sd, 0xb5);
if ((polarity & 0x03) == 0x01) {
@@ -1373,26 +1376,26 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
return 0;
}
-static int adv7604_enum_dv_timings(struct v4l2_subdev *sd,
+static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
- if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1)
+ if (timings->index >= ARRAY_SIZE(adv76xx_timings) - 1)
return -EINVAL;
if (timings->pad >= state->source_pad)
return -EINVAL;
memset(timings->reserved, 0, sizeof(timings->reserved));
- timings->timings = adv7604_timings[timings->index];
+ timings->timings = adv76xx_timings[timings->index];
return 0;
}
-static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
+static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
if (cap->pad >= state->source_pad)
return -EINVAL;
@@ -1403,7 +1406,7 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
cap->bt.min_pixelclock = 25000000;
switch (cap->pad) {
- case ADV7604_PAD_HDMI_PORT_A:
+ case ADV76XX_PAD_HDMI_PORT_A:
case ADV7604_PAD_HDMI_PORT_B:
case ADV7604_PAD_HDMI_PORT_C:
case ADV7604_PAD_HDMI_PORT_D:
@@ -1424,16 +1427,16 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
}
/* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
- if the format is listed in adv7604_timings[] */
-static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
+ if the format is listed in adv76xx_timings[] */
+static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
int i;
- for (i = 0; adv7604_timings[i].bt.width; i++) {
- if (v4l2_match_dv_timings(timings, &adv7604_timings[i],
+ for (i = 0; adv76xx_timings[i].bt.width; i++) {
+ if (v4l2_match_dv_timings(timings, &adv76xx_timings[i],
is_digital_input(sd) ? 250000 : 1000000)) {
- *timings = adv7604_timings[i];
+ *timings = adv76xx_timings[i];
break;
}
}
@@ -1471,11 +1474,11 @@ static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd)
return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128;
}
-static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
+static int adv76xx_query_dv_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
struct v4l2_bt_timings *bt = &timings->bt;
struct stdi_readback stdi;
@@ -1519,7 +1522,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2;
bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
}
- adv7604_fill_optional_dv_timings_fields(sd, timings);
+ adv76xx_fill_optional_dv_timings_fields(sd, timings);
} else {
/* find format
* Since LCVS values are inaccurate [REF_03, p. 275-276],
@@ -1576,16 +1579,16 @@ found:
}
if (debug > 1)
- v4l2_print_dv_timings(sd->name, "adv7604_query_dv_timings: ",
+ v4l2_print_dv_timings(sd->name, "adv76xx_query_dv_timings: ",
timings, true);
return 0;
}
-static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
+static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
struct v4l2_bt_timings *bt;
int err;
@@ -1606,7 +1609,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
return -ERANGE;
}
- adv7604_fill_optional_dv_timings_fields(sd, timings);
+ adv76xx_fill_optional_dv_timings_fields(sd, timings);
state->timings = *timings;
@@ -1623,15 +1626,15 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
set_rgb_quantization_range(sd);
if (debug > 1)
- v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ",
+ v4l2_print_dv_timings(sd->name, "adv76xx_s_dv_timings: ",
timings, true);
return 0;
}
-static int adv7604_g_dv_timings(struct v4l2_subdev *sd,
+static int adv76xx_g_dv_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
*timings = state->timings;
return 0;
@@ -1649,7 +1652,7 @@ static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable)
static void enable_input(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
if (is_analog_input(sd)) {
io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */
@@ -1666,7 +1669,7 @@ static void enable_input(struct v4l2_subdev *sd)
static void disable_input(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
hdmi_write_clr_set(sd, 0x1a, 0x10, 0x10); /* Mute audio */
msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */
@@ -1676,11 +1679,11 @@ static void disable_input(struct v4l2_subdev *sd)
static void select_input(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
if (is_analog_input(sd)) {
- adv7604_write_reg_seq(sd, info->recommended_settings[0]);
+ adv76xx_write_reg_seq(sd, info->recommended_settings[0]);
afe_write(sd, 0x00, 0x08); /* power up ADC */
afe_write(sd, 0x01, 0x06); /* power up Analog Front End */
@@ -1688,9 +1691,9 @@ static void select_input(struct v4l2_subdev *sd)
} else if (is_digital_input(sd)) {
hdmi_write(sd, 0x00, state->selected_input & 0x03);
- adv7604_write_reg_seq(sd, info->recommended_settings[1]);
+ adv76xx_write_reg_seq(sd, info->recommended_settings[1]);
- if (adv7604_has_afe(state)) {
+ if (adv76xx_has_afe(state)) {
afe_write(sd, 0x00, 0xff); /* power down ADC */
afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */
afe_write(sd, 0xc8, 0x40); /* phase control */
@@ -1705,10 +1708,10 @@ static void select_input(struct v4l2_subdev *sd)
}
}
-static int adv7604_s_routing(struct v4l2_subdev *sd,
+static int adv76xx_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d",
__func__, input, state->selected_input);
@@ -1730,11 +1733,11 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int adv7604_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
if (code->index >= state->info->nformats)
return -EINVAL;
@@ -1744,7 +1747,7 @@ static int adv7604_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static void adv7604_fill_format(struct adv7604_state *state,
+static void adv76xx_fill_format(struct adv76xx_state *state,
struct v4l2_mbus_framefmt *format)
{
memset(format, 0, sizeof(*format));
@@ -1752,8 +1755,9 @@ static void adv7604_fill_format(struct adv7604_state *state,
format->width = state->timings.bt.width;
format->height = state->timings.bt.height;
format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
- if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861)
+ if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO)
format->colorspace = (state->timings.bt.height <= 576) ?
V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
}
@@ -1765,7 +1769,7 @@ static void adv7604_fill_format(struct adv7604_state *state,
*
* The following table gives the op_ch_value from the format component order
* (expressed as op_ch_sel value in column) and the bus reordering (expressed as
- * adv7604_bus_order value in row).
+ * adv76xx_bus_order value in row).
*
* | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5)
* ----------+-------------------------------------------------
@@ -1776,11 +1780,11 @@ static void adv7604_fill_format(struct adv7604_state *state,
* BRG (ROR) | BRG RBG GRB GBR RGB BGR
* GBR (ROL) | RGB BGR RBG BRG GBR GRB
*/
-static unsigned int adv7604_op_ch_sel(struct adv7604_state *state)
+static unsigned int adv76xx_op_ch_sel(struct adv76xx_state *state)
{
#define _SEL(a,b,c,d,e,f) { \
- ADV7604_OP_CH_SEL_##a, ADV7604_OP_CH_SEL_##b, ADV7604_OP_CH_SEL_##c, \
- ADV7604_OP_CH_SEL_##d, ADV7604_OP_CH_SEL_##e, ADV7604_OP_CH_SEL_##f }
+ ADV76XX_OP_CH_SEL_##a, ADV76XX_OP_CH_SEL_##b, ADV76XX_OP_CH_SEL_##c, \
+ ADV76XX_OP_CH_SEL_##d, ADV76XX_OP_CH_SEL_##e, ADV76XX_OP_CH_SEL_##f }
#define _BUS(x) [ADV7604_BUS_ORDER_##x]
static const unsigned int op_ch_sel[6][6] = {
@@ -1795,33 +1799,34 @@ static unsigned int adv7604_op_ch_sel(struct adv7604_state *state)
return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5];
}
-static void adv7604_setup_format(struct adv7604_state *state)
+static void adv76xx_setup_format(struct adv76xx_state *state)
{
struct v4l2_subdev *sd = &state->sd;
io_write_clr_set(sd, 0x02, 0x02,
- state->format->rgb_out ? ADV7604_RGB_OUT : 0);
+ state->format->rgb_out ? ADV76XX_RGB_OUT : 0);
io_write(sd, 0x03, state->format->op_format_sel |
state->pdata.op_format_mode_sel);
- io_write_clr_set(sd, 0x04, 0xe0, adv7604_op_ch_sel(state));
+ io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state));
io_write_clr_set(sd, 0x05, 0x01,
- state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0);
+ state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0);
}
-static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int adv76xx_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
if (format->pad != state->source_pad)
return -EINVAL;
- adv7604_fill_format(state, &format->format);
+ adv76xx_fill_format(state, &format->format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
format->format.code = fmt->code;
} else {
format->format.code = state->format->code;
@@ -1830,39 +1835,40 @@ static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int adv76xx_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_format_info *info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_format_info *info;
if (format->pad != state->source_pad)
return -EINVAL;
- info = adv7604_format_info(state, format->format.code);
+ info = adv76xx_format_info(state, format->format.code);
if (info == NULL)
- info = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
+ info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
- adv7604_fill_format(state, &format->format);
+ adv76xx_fill_format(state, &format->format);
format->format.code = info->code;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
fmt->code = format->format.code;
} else {
state->format = info;
- adv7604_setup_format(state);
+ adv76xx_setup_format(state);
}
return 0;
}
-static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
+static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
const u8 irq_reg_0x43 = io_read(sd, 0x43);
const u8 irq_reg_0x6b = io_read(sd, 0x6b);
const u8 irq_reg_0x70 = io_read(sd, 0x70);
@@ -1890,7 +1896,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
"%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
__func__, fmt_change, fmt_change_digital);
- v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
+ v4l2_subdev_notify(sd, ADV76XX_FMT_CHANGE, NULL);
if (handled)
*handled = true;
@@ -1909,22 +1915,22 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
if (tx_5v) {
v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
io_write(sd, 0x71, tx_5v);
- adv7604_s_detect_tx_5v_ctrl(sd);
+ adv76xx_s_detect_tx_5v_ctrl(sd);
if (handled)
*handled = true;
}
return 0;
}
-static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
u8 *data = NULL;
memset(edid->reserved, 0, sizeof(edid->reserved));
switch (edid->pad) {
- case ADV7604_PAD_HDMI_PORT_A:
+ case ADV76XX_PAD_HDMI_PORT_A:
case ADV7604_PAD_HDMI_PORT_B:
case ADV7604_PAD_HDMI_PORT_C:
case ADV7604_PAD_HDMI_PORT_D:
@@ -1982,10 +1988,10 @@ static int get_edid_spa_location(const u8 *edid)
return -1;
}
-static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
int spa_loc;
int err;
int i;
@@ -1999,7 +2005,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
if (edid->blocks == 0) {
/* Disable hotplug and I2C access to EDID RAM from DDC port */
state->edid.present &= ~(1 << edid->pad);
- adv7604_set_hpd(state, state->edid.present);
+ adv76xx_set_hpd(state, state->edid.present);
rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present);
/* Fall back to a 16:9 aspect ratio */
@@ -2023,7 +2029,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
/* Disable hotplug and I2C access to EDID RAM from DDC port */
cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
- adv7604_set_hpd(state, 0);
+ adv76xx_set_hpd(state, 0);
rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00);
spa_loc = get_edid_spa_location(edid->edid);
@@ -2031,7 +2037,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
spa_loc = 0xc0; /* Default value [REF_02, p. 116] */
switch (edid->pad) {
- case ADV7604_PAD_HDMI_PORT_A:
+ case ADV76XX_PAD_HDMI_PORT_A:
state->spa_port_a[0] = edid->edid[spa_loc];
state->spa_port_a[1] = edid->edid[spa_loc + 1];
break;
@@ -2074,7 +2080,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return err;
}
- /* adv7604 calculates the checksums and enables I2C access to internal
+ /* adv76xx calculates the checksums and enables I2C access to internal
EDID RAM from DDC port. */
rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present);
@@ -2138,10 +2144,10 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
}
-static int adv7604_log_status(struct v4l2_subdev *sd)
+static int adv76xx_log_status(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
struct v4l2_dv_timings timings;
struct stdi_readback stdi;
u8 reg_io_0x02 = io_read(sd, 0x02);
@@ -2200,7 +2206,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "STDI locked: %s\n", no_lock_stdi(sd) ? "false" : "true");
v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true");
v4l2_info(sd, "CP free run: %s\n",
- (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off"));
+ (in_free_run(sd)) ? "on" : "off");
v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n",
io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f,
(io_read(sd, 0x01) & 0x70) >> 4);
@@ -2213,7 +2219,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
stdi.lcf, stdi.bl, stdi.lcvs,
stdi.interlaced ? "interlaced" : "progressive",
stdi.hs_pol, stdi.vs_pol);
- if (adv7604_query_dv_timings(sd, &timings))
+ if (adv76xx_query_dv_timings(sd, &timings))
v4l2_info(sd, "No video detected\n");
else
v4l2_print_dv_timings(sd->name, "Detected format: ",
@@ -2235,7 +2241,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ?
"enabled" : "disabled");
v4l2_info(sd, "Color space conversion: %s\n",
- csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]);
+ csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]);
if (!is_digital_input(sd))
return 0;
@@ -2279,47 +2285,47 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
/* ----------------------------------------------------------------------- */
-static const struct v4l2_ctrl_ops adv7604_ctrl_ops = {
- .s_ctrl = adv7604_s_ctrl,
+static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = {
+ .s_ctrl = adv76xx_s_ctrl,
};
-static const struct v4l2_subdev_core_ops adv7604_core_ops = {
- .log_status = adv7604_log_status,
- .interrupt_service_routine = adv7604_isr,
+static const struct v4l2_subdev_core_ops adv76xx_core_ops = {
+ .log_status = adv76xx_log_status,
+ .interrupt_service_routine = adv76xx_isr,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = adv7604_g_register,
- .s_register = adv7604_s_register,
+ .g_register = adv76xx_g_register,
+ .s_register = adv76xx_s_register,
#endif
};
-static const struct v4l2_subdev_video_ops adv7604_video_ops = {
- .s_routing = adv7604_s_routing,
- .g_input_status = adv7604_g_input_status,
- .s_dv_timings = adv7604_s_dv_timings,
- .g_dv_timings = adv7604_g_dv_timings,
- .query_dv_timings = adv7604_query_dv_timings,
+static const struct v4l2_subdev_video_ops adv76xx_video_ops = {
+ .s_routing = adv76xx_s_routing,
+ .g_input_status = adv76xx_g_input_status,
+ .s_dv_timings = adv76xx_s_dv_timings,
+ .g_dv_timings = adv76xx_g_dv_timings,
+ .query_dv_timings = adv76xx_query_dv_timings,
};
-static const struct v4l2_subdev_pad_ops adv7604_pad_ops = {
- .enum_mbus_code = adv7604_enum_mbus_code,
- .get_fmt = adv7604_get_format,
- .set_fmt = adv7604_set_format,
- .get_edid = adv7604_get_edid,
- .set_edid = adv7604_set_edid,
- .dv_timings_cap = adv7604_dv_timings_cap,
- .enum_dv_timings = adv7604_enum_dv_timings,
+static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = {
+ .enum_mbus_code = adv76xx_enum_mbus_code,
+ .get_fmt = adv76xx_get_format,
+ .set_fmt = adv76xx_set_format,
+ .get_edid = adv76xx_get_edid,
+ .set_edid = adv76xx_set_edid,
+ .dv_timings_cap = adv76xx_dv_timings_cap,
+ .enum_dv_timings = adv76xx_enum_dv_timings,
};
-static const struct v4l2_subdev_ops adv7604_ops = {
- .core = &adv7604_core_ops,
- .video = &adv7604_video_ops,
- .pad = &adv7604_pad_ops,
+static const struct v4l2_subdev_ops adv76xx_ops = {
+ .core = &adv76xx_core_ops,
+ .video = &adv76xx_video_ops,
+ .pad = &adv76xx_pad_ops,
};
/* -------------------------- custom ctrls ---------------------------------- */
static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = {
- .ops = &adv7604_ctrl_ops,
+ .ops = &adv76xx_ctrl_ops,
.id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE,
.name = "Analog Sampling Phase",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -2329,8 +2335,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = {
.def = 0,
};
-static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = {
- .ops = &adv7604_ctrl_ops,
+static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color_manual = {
+ .ops = &adv76xx_ctrl_ops,
.id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL,
.name = "Free Running Color, Manual",
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -2340,8 +2346,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = {
.def = false,
};
-static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = {
- .ops = &adv7604_ctrl_ops,
+static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = {
+ .ops = &adv76xx_ctrl_ops,
.id = V4L2_CID_ADV_RX_FREE_RUN_COLOR,
.name = "Free Running Color",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -2353,11 +2359,11 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = {
/* ----------------------------------------------------------------------- */
-static int adv7604_core_init(struct v4l2_subdev *sd)
+static int adv76xx_core_init(struct v4l2_subdev *sd)
{
- struct adv7604_state *state = to_state(sd);
- const struct adv7604_chip_info *info = state->info;
- struct adv7604_platform_data *pdata = &state->pdata;
+ struct adv76xx_state *state = to_state(sd);
+ const struct adv76xx_chip_info *info = state->info;
+ struct adv76xx_platform_data *pdata = &state->pdata;
hdmi_write(sd, 0x48,
(pdata->disable_pwrdnb ? 0x80 : 0) |
@@ -2385,7 +2391,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 |
pdata->insert_av_codes << 2 |
pdata->replicate_av_codes << 1);
- adv7604_setup_format(state);
+ adv76xx_setup_format(state);
cp_write(sd, 0x69, 0x30); /* Enable CP CSC */
@@ -2415,7 +2421,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
/* TODO from platform data */
afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */
- if (adv7604_has_afe(state)) {
+ if (adv76xx_has_afe(state)) {
afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */
io_write_clr_set(sd, 0x30, 1 << 4, pdata->output_bus_lsb_to_msb << 4);
}
@@ -2440,7 +2446,7 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd)
io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */
}
-static void adv7604_unregister_clients(struct adv7604_state *state)
+static void adv76xx_unregister_clients(struct adv76xx_state *state)
{
unsigned int i;
@@ -2450,7 +2456,7 @@ static void adv7604_unregister_clients(struct adv7604_state *state)
}
}
-static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd,
+static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd,
u8 addr, u8 io_reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -2460,74 +2466,74 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd,
return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
}
-static const struct adv7604_reg_seq adv7604_recommended_settings_afe[] = {
+static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = {
/* reset ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */
/* set ADI recommended settings for digitizer */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
- { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */
- { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */
- { ADV7604_REG(ADV7604_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */
- { ADV7604_REG(ADV7604_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */
- { ADV7604_REG(ADV7604_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */
+ { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */
+ { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */
+ { ADV76XX_REG(ADV76XX_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */
+ { ADV76XX_REG(ADV76XX_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */
+ { ADV76XX_REG(ADV76XX_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */
- { ADV7604_REG_SEQ_TERM, 0 },
+ { ADV76XX_REG_SEQ_TERM, 0 },
};
-static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = {
+static const struct adv76xx_reg_seq adv7604_recommended_settings_hdmi[] = {
/* set ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */
/* reset ADI recommended settings for digitizer */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
- { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */
- { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */
+ { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */
+ { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */
- { ADV7604_REG_SEQ_TERM, 0 },
+ { ADV76XX_REG_SEQ_TERM, 0 },
};
-static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = {
+static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = {
/* ADV7611 Register Settings Recommendations Rev 1.5, May 2014 */
- { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x9b), 0x03 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x08 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x85), 0x1f },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x03), 0x98 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4c), 0x44 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x04 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x1e },
-
- { ADV7604_REG_SEQ_TERM, 0 },
+ { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x04 },
+ { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x1e },
+
+ { ADV76XX_REG_SEQ_TERM, 0 },
};
-static const struct adv7604_chip_info adv7604_chip_info[] = {
+static const struct adv76xx_chip_info adv76xx_chip_info[] = {
[ADV7604] = {
.type = ADV7604,
.has_afe = true,
@@ -2539,6 +2545,7 @@ static const struct adv7604_chip_info adv7604_chip_info[] = {
.tdms_lock_mask = 0xe0,
.cable_det_mask = 0x1e,
.fmt_change_digital_mask = 0xc1,
+ .cp_csc = 0xfc,
.formats = adv7604_formats,
.nformats = ARRAY_SIZE(adv7604_formats),
.set_termination = adv7604_set_termination,
@@ -2553,18 +2560,18 @@ static const struct adv7604_chip_info adv7604_chip_info[] = {
[0] = ARRAY_SIZE(adv7604_recommended_settings_afe),
[1] = ARRAY_SIZE(adv7604_recommended_settings_hdmi),
},
- .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) |
- BIT(ADV7604_PAGE_CEC) | BIT(ADV7604_PAGE_INFOFRAME) |
+ .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) |
+ BIT(ADV76XX_PAGE_CEC) | BIT(ADV76XX_PAGE_INFOFRAME) |
BIT(ADV7604_PAGE_ESDP) | BIT(ADV7604_PAGE_DPP) |
- BIT(ADV7604_PAGE_AFE) | BIT(ADV7604_PAGE_REP) |
- BIT(ADV7604_PAGE_EDID) | BIT(ADV7604_PAGE_HDMI) |
- BIT(ADV7604_PAGE_TEST) | BIT(ADV7604_PAGE_CP) |
+ BIT(ADV76XX_PAGE_AFE) | BIT(ADV76XX_PAGE_REP) |
+ BIT(ADV76XX_PAGE_EDID) | BIT(ADV76XX_PAGE_HDMI) |
+ BIT(ADV76XX_PAGE_TEST) | BIT(ADV76XX_PAGE_CP) |
BIT(ADV7604_PAGE_VDP),
},
[ADV7611] = {
.type = ADV7611,
.has_afe = false,
- .max_port = ADV7604_PAD_HDMI_PORT_A,
+ .max_port = ADV76XX_PAD_HDMI_PORT_A,
.num_dv_ports = 1,
.edid_enable_reg = 0x74,
.edid_status_reg = 0x76,
@@ -2572,6 +2579,7 @@ static const struct adv7604_chip_info adv7604_chip_info[] = {
.tdms_lock_mask = 0x43,
.cable_det_mask = 0x01,
.fmt_change_digital_mask = 0x03,
+ .cp_csc = 0xf4,
.formats = adv7611_formats,
.nformats = ARRAY_SIZE(adv7611_formats),
.set_termination = adv7611_set_termination,
@@ -2584,34 +2592,34 @@ static const struct adv7604_chip_info adv7604_chip_info[] = {
.num_recommended_settings = {
[1] = ARRAY_SIZE(adv7611_recommended_settings_hdmi),
},
- .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_CEC) |
- BIT(ADV7604_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_AFE) |
- BIT(ADV7604_PAGE_REP) | BIT(ADV7604_PAGE_EDID) |
- BIT(ADV7604_PAGE_HDMI) | BIT(ADV7604_PAGE_CP),
+ .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) |
+ BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) |
+ BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) |
+ BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP),
},
};
-static struct i2c_device_id adv7604_i2c_id[] = {
- { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] },
- { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] },
+static struct i2c_device_id adv76xx_i2c_id[] = {
+ { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] },
+ { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] },
{ }
};
-MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id);
+MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id);
-static struct of_device_id adv7604_of_id[] __maybe_unused = {
- { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] },
+static struct of_device_id adv76xx_of_id[] __maybe_unused = {
+ { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] },
{ }
};
-MODULE_DEVICE_TABLE(of, adv7604_of_id);
+MODULE_DEVICE_TABLE(of, adv76xx_of_id);
-static int adv7604_parse_dt(struct adv7604_state *state)
+static int adv76xx_parse_dt(struct adv76xx_state *state)
{
struct v4l2_of_endpoint bus_cfg;
struct device_node *endpoint;
struct device_node *np;
unsigned int flags;
- np = state->i2c_clients[ADV7604_PAGE_IO]->dev.of_node;
+ np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node;
/* Parse the endpoint. */
endpoint = of_graph_get_next_endpoint(np, NULL);
@@ -2638,20 +2646,20 @@ static int adv7604_parse_dt(struct adv7604_state *state)
}
/* Disable the interrupt for now as no DT-based board uses it. */
- state->pdata.int1_config = ADV7604_INT1_CONFIG_DISABLED;
+ state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED;
/* Use the default I2C addresses. */
state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42;
- state->pdata.i2c_addresses[ADV7604_PAGE_CEC] = 0x40;
- state->pdata.i2c_addresses[ADV7604_PAGE_INFOFRAME] = 0x3e;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e;
state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38;
state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c;
- state->pdata.i2c_addresses[ADV7604_PAGE_AFE] = 0x26;
- state->pdata.i2c_addresses[ADV7604_PAGE_REP] = 0x32;
- state->pdata.i2c_addresses[ADV7604_PAGE_EDID] = 0x36;
- state->pdata.i2c_addresses[ADV7604_PAGE_HDMI] = 0x34;
- state->pdata.i2c_addresses[ADV7604_PAGE_TEST] = 0x30;
- state->pdata.i2c_addresses[ADV7604_PAGE_CP] = 0x22;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30;
+ state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22;
state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24;
/* Hardcode the remaining platform data fields. */
@@ -2666,12 +2674,12 @@ static int adv7604_parse_dt(struct adv7604_state *state)
return 0;
}
-static int adv7604_probe(struct i2c_client *client,
+static int adv76xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
static const struct v4l2_dv_timings cea640x480 =
V4L2_DV_BT_CEA_640X480P59_94;
- struct adv7604_state *state;
+ struct adv76xx_state *state;
struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
unsigned int i;
@@ -2681,16 +2689,16 @@ static int adv7604_probe(struct i2c_client *client,
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n",
+ v4l_dbg(1, debug, client, "detecting adv76xx client on address 0x%x\n",
client->addr << 1);
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (!state) {
- v4l_err(client, "Could not allocate adv7604_state memory!\n");
+ v4l_err(client, "Could not allocate adv76xx_state memory!\n");
return -ENOMEM;
}
- state->i2c_clients[ADV7604_PAGE_IO] = client;
+ state->i2c_clients[ADV76XX_PAGE_IO] = client;
/* initialize variables */
state->restart_stdi_once = true;
@@ -2699,18 +2707,18 @@ static int adv7604_probe(struct i2c_client *client,
if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) {
const struct of_device_id *oid;
- oid = of_match_node(adv7604_of_id, client->dev.of_node);
+ oid = of_match_node(adv76xx_of_id, client->dev.of_node);
state->info = oid->data;
- err = adv7604_parse_dt(state);
+ err = adv76xx_parse_dt(state);
if (err < 0) {
v4l_err(client, "DT parsing error\n");
return err;
}
} else if (client->dev.platform_data) {
- struct adv7604_platform_data *pdata = client->dev.platform_data;
+ struct adv76xx_platform_data *pdata = client->dev.platform_data;
- state->info = (const struct adv7604_chip_info *)id->driver_data;
+ state->info = (const struct adv76xx_chip_info *)id->driver_data;
state->pdata = *pdata;
} else {
v4l_err(client, "No platform data!\n");
@@ -2720,20 +2728,20 @@ static int adv7604_probe(struct i2c_client *client,
/* Request GPIOs. */
for (i = 0; i < state->info->num_dv_ports; ++i) {
state->hpd_gpio[i] =
- devm_gpiod_get_index(&client->dev, "hpd", i);
+ devm_gpiod_get_index_optional(&client->dev, "hpd", i,
+ GPIOD_OUT_LOW);
if (IS_ERR(state->hpd_gpio[i]))
- continue;
-
- gpiod_direction_output(state->hpd_gpio[i], 0);
+ return PTR_ERR(state->hpd_gpio[i]);
- v4l_info(client, "Handling HPD %u GPIO\n", i);
+ if (state->hpd_gpio[i])
+ v4l_info(client, "Handling HPD %u GPIO\n", i);
}
state->timings = cea640x480;
- state->format = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
+ state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7604_ops);
+ v4l2_i2c_subdev_init(sd, client, &adv76xx_ops);
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
id->name, i2c_adapter_id(client->adapter),
client->addr);
@@ -2763,15 +2771,15 @@ static int adv7604_probe(struct i2c_client *client,
/* control handlers */
hdl = &state->hdl;
- v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8);
+ v4l2_ctrl_handler_init(hdl, adv76xx_has_afe(state) ? 9 : 8);
- v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
+ v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
+ v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 128);
- v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
+ v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_SATURATION, 0, 255, 1, 128);
- v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
+ v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops,
V4L2_CID_HUE, 0, 128, 1, 0);
/* private controls */
@@ -2779,18 +2787,18 @@ static int adv7604_probe(struct i2c_client *client,
V4L2_CID_DV_RX_POWER_PRESENT, 0,
(1 << state->info->num_dv_ports) - 1, 0, 0);
state->rgb_quantization_range_ctrl =
- v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops,
+ v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops,
V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
0, V4L2_DV_RGB_RANGE_AUTO);
/* custom controls */
- if (adv7604_has_afe(state))
+ if (adv76xx_has_afe(state))
state->analog_sampling_phase_ctrl =
v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL);
state->free_run_color_manual_ctrl =
- v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL);
+ v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color_manual, NULL);
state->free_run_color_ctrl =
- v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color, NULL);
+ v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color, NULL);
sd->ctrl_handler = hdl;
if (hdl->error) {
@@ -2799,22 +2807,22 @@ static int adv7604_probe(struct i2c_client *client,
}
state->detect_tx_5v_ctrl->is_private = true;
state->rgb_quantization_range_ctrl->is_private = true;
- if (adv7604_has_afe(state))
+ if (adv76xx_has_afe(state))
state->analog_sampling_phase_ctrl->is_private = true;
state->free_run_color_manual_ctrl->is_private = true;
state->free_run_color_ctrl->is_private = true;
- if (adv7604_s_detect_tx_5v_ctrl(sd)) {
+ if (adv76xx_s_detect_tx_5v_ctrl(sd)) {
err = -ENODEV;
goto err_hdl;
}
- for (i = 1; i < ADV7604_PAGE_MAX; ++i) {
+ for (i = 1; i < ADV76XX_PAGE_MAX; ++i) {
if (!(BIT(i) & state->info->page_mask))
continue;
state->i2c_clients[i] =
- adv7604_dummy_client(sd, state->pdata.i2c_addresses[i],
+ adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i],
0xf2 + i);
if (state->i2c_clients[i] == NULL) {
err = -ENOMEM;
@@ -2832,7 +2840,7 @@ static int adv7604_probe(struct i2c_client *client,
}
INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
- adv7604_delayed_work_enable_hotplug);
+ adv76xx_delayed_work_enable_hotplug);
state->source_pad = state->info->num_dv_ports
+ (state->info->has_afe ? 2 : 0);
@@ -2845,7 +2853,7 @@ static int adv7604_probe(struct i2c_client *client,
if (err)
goto err_work_queues;
- err = adv7604_core_init(sd);
+ err = adv76xx_core_init(sd);
if (err)
goto err_entity;
v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
@@ -2863,7 +2871,7 @@ err_work_queues:
cancel_delayed_work(&state->delayed_work_enable_hotplug);
destroy_workqueue(state->work_queues);
err_i2c:
- adv7604_unregister_clients(state);
+ adv76xx_unregister_clients(state);
err_hdl:
v4l2_ctrl_handler_free(hdl);
return err;
@@ -2871,32 +2879,31 @@ err_hdl:
/* ----------------------------------------------------------------------- */
-static int adv7604_remove(struct i2c_client *client)
+static int adv76xx_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct adv7604_state *state = to_state(sd);
+ struct adv76xx_state *state = to_state(sd);
cancel_delayed_work(&state->delayed_work_enable_hotplug);
destroy_workqueue(state->work_queues);
v4l2_async_unregister_subdev(sd);
- v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
- adv7604_unregister_clients(to_state(sd));
+ adv76xx_unregister_clients(to_state(sd));
v4l2_ctrl_handler_free(sd->ctrl_handler);
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver adv7604_driver = {
+static struct i2c_driver adv76xx_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "adv7604",
- .of_match_table = of_match_ptr(adv7604_of_id),
+ .of_match_table = of_match_ptr(adv76xx_of_id),
},
- .probe = adv7604_probe,
- .remove = adv7604_remove,
- .id_table = adv7604_i2c_id,
+ .probe = adv76xx_probe,
+ .remove = adv76xx_remove,
+ .id_table = adv76xx_i2c_id,
};
-module_i2c_driver(adv7604_driver);
+module_i2c_driver(adv76xx_driver);
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 7c215ee..b5a37fe 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1119,7 +1119,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
/* Receiving DVI-D signal
* ADV7842 selects RGB limited range regardless of
* input format (CE/IT) in automatic mode */
- if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
+ if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
/* RGB limited range (16-235) */
io_write_and_or(sd, 0x02, 0x0f, 0x00);
} else {
@@ -1901,7 +1901,8 @@ static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd,
return 0;
}
- if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
fmt->colorspace = (state->timings.bt.height <= 576) ?
V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
}
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 573e088..bd49644 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -5137,6 +5137,9 @@ static int cx25840_probe(struct i2c_client *client,
int default_volume;
u32 id;
u16 device_id;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ int ret;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -5178,6 +5181,33 @@ static int cx25840_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ /*
+ * TODO: add media controller support for analog video inputs like
+ * composite, svideo, etc.
+ * A real input pad for this analog demod would be like:
+ * ___________
+ * TUNER --------> | |
+ * | |
+ * SVIDEO .......> | cx25840 |
+ * | |
+ * COMPOSITE1 ...> |_________|
+ *
+ * However, at least for now, there's no much gain on modelling
+ * those extra inputs. So, let's add it only when needed.
+ */
+ state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+
+ ret = media_entity_init(&sd->entity, ARRAY_SIZE(state->pads),
+ state->pads, 0);
+ if (ret < 0) {
+ v4l_info(client, "failed to initialize media entity!\n");
+ return ret;
+ }
+#endif
switch (id) {
case CX23885_AV:
diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
index 37bc042..fdea48c 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.h
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
@@ -41,6 +41,14 @@ enum cx25840_model {
CX25837,
};
+enum cx25840_media_pads {
+ CX25840_PAD_INPUT,
+ CX25840_PAD_VID_OUT,
+ CX25840_PAD_VBI_OUT,
+
+ CX25840_NUM_PADS
+};
+
struct cx25840_state {
struct i2c_client *c;
struct v4l2_subdev sd;
@@ -64,6 +72,9 @@ struct cx25840_state {
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
struct work_struct fw_work; /* work entry for fw load */
struct cx25840_ir_state *ir_state;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_pad pads[CX25840_NUM_PADS];
+#endif
};
static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 6ed16e5..6404c0d 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -531,17 +531,17 @@ static int __find_resolution(struct v4l2_subdev *sd,
}
static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which,
enum m5mols_restype type)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
+ return cfg ? v4l2_subdev_get_try_format(&info->sd, cfg, 0) : NULL;
return &info->ffmt[type];
}
-static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct m5mols_info *info = to_m5mols(sd);
@@ -550,7 +550,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
mutex_lock(&info->lock);
- format = __find_format(info, fh, fmt->which, info->res_type);
+ format = __find_format(info, cfg, fmt->which, info->res_type);
if (format)
fmt->format = *format;
else
@@ -560,7 +560,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return ret;
}
-static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct m5mols_info *info = to_m5mols(sd);
@@ -574,7 +574,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
if (ret < 0)
return ret;
- sfmt = __find_format(info, fh, fmt->which, type);
+ sfmt = __find_format(info, cfg, fmt->which, type);
if (!sfmt)
return 0;
@@ -640,7 +640,7 @@ static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (!code || code->index >= SIZE_DEFAULT_FFMT)
@@ -895,7 +895,7 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = {
*/
static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
*format = m5mols_default_ffmt[0];
return 0;
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 7643122..c7747bd 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -317,7 +317,7 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
*/
static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -328,7 +328,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8)
@@ -345,18 +345,18 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
/**
* __mt9m032_get_pad_crop() - get crop rect
* @sensor: pointer to the sensor struct
- * @fh: file handle for getting the try crop rect from
+ * @cfg: v4l2_subdev_pad_config for getting the try crop rect from
* @which: select try or active crop rect
*
* Returns a pointer the current active or fh relative try crop rect
*/
static struct v4l2_rect *
-__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, 0);
+ return v4l2_subdev_get_try_crop(&sensor->subdev, cfg, 0);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->crop;
default:
@@ -367,18 +367,18 @@ __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
/**
* __mt9m032_get_pad_format() - get format
* @sensor: pointer to the sensor struct
- * @fh: file handle for getting the try format from
+ * @cfg: v4l2_subdev_pad_config for getting the try format from
* @which: select try or active format
*
* Returns a pointer the current active or fh relative try format
*/
static struct v4l2_mbus_framefmt *
-__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, 0);
+ return v4l2_subdev_get_try_format(&sensor->subdev, cfg, 0);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->format;
default:
@@ -387,20 +387,20 @@ __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
}
static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
mutex_lock(&sensor->lock);
- fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+ fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
mutex_unlock(&sensor->lock);
return 0;
}
static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -414,7 +414,7 @@ static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
}
/* Scaling is not supported, the format is thus fixed. */
- fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+ fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
ret = 0;
done:
@@ -423,7 +423,7 @@ done:
}
static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -432,14 +432,14 @@ static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&sensor->lock);
- sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which);
+ sel->r = *__mt9m032_get_pad_crop(sensor, cfg, sel->which);
mutex_unlock(&sensor->lock);
return 0;
}
static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -475,13 +475,13 @@ static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which);
+ __crop = __mt9m032_get_pad_crop(sensor, cfg, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- format = __mt9m032_get_pad_format(sensor, fh, sel->which);
+ format = __mt9m032_get_pad_format(sensor, cfg, sel->which);
format->width = rect.width;
format->height = rect.height;
}
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e3acae9..0db15f5 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -15,12 +15,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
@@ -28,6 +27,7 @@
#include <linux/videodev2.h>
#include <media/mt9p031.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
@@ -135,7 +135,7 @@ struct mt9p031 {
struct aptina_pll pll;
unsigned int clk_div;
bool use_pll;
- int reset;
+ struct gpio_desc *reset;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *blc_auto;
@@ -251,7 +251,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq);
div = roundup_pow_of_two(div) / 2;
- mt9p031->clk_div = max_t(unsigned int, div, 64);
+ mt9p031->clk_div = min_t(unsigned int, div, 64);
mt9p031->use_pll = false;
return 0;
@@ -308,9 +308,9 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
{
int ret;
- /* Ensure RESET_BAR is low */
- if (gpio_is_valid(mt9p031->reset)) {
- gpio_set_value(mt9p031->reset, 0);
+ /* Ensure RESET_BAR is active */
+ if (mt9p031->reset) {
+ gpiod_set_value(mt9p031->reset, 1);
usleep_range(1000, 2000);
}
@@ -331,8 +331,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
}
/* Now RESET_BAR must be high */
- if (gpio_is_valid(mt9p031->reset)) {
- gpio_set_value(mt9p031->reset, 1);
+ if (mt9p031->reset) {
+ gpiod_set_value(mt9p031->reset, 0);
usleep_range(1000, 2000);
}
@@ -341,8 +341,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
static void mt9p031_power_off(struct mt9p031 *mt9p031)
{
- if (gpio_is_valid(mt9p031->reset)) {
- gpio_set_value(mt9p031->reset, 0);
+ if (mt9p031->reset) {
+ gpiod_set_value(mt9p031->reset, 1);
usleep_range(1000, 2000);
}
@@ -474,7 +474,7 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -487,7 +487,7 @@ static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -505,12 +505,12 @@ static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
}
static struct v4l2_mbus_framefmt *
-__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&mt9p031->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->format;
default:
@@ -519,12 +519,12 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
}
static struct v4l2_rect *
-__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
+__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, pad);
+ return v4l2_subdev_get_try_crop(&mt9p031->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->crop;
default:
@@ -533,18 +533,18 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
}
static int mt9p031_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
- fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad,
+ fmt->format = *__mt9p031_get_pad_format(mt9p031, cfg, fmt->pad,
fmt->which);
return 0;
}
static int mt9p031_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -555,7 +555,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad,
+ __crop = __mt9p031_get_pad_crop(mt9p031, cfg, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -571,7 +571,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
- __format = __mt9p031_get_pad_format(mt9p031, fh, format->pad,
+ __format = __mt9p031_get_pad_format(mt9p031, cfg, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -582,7 +582,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
}
static int mt9p031_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -590,12 +590,12 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
+ sel->r = *__mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
return 0;
}
static int mt9p031_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -625,13 +625,13 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
+ __crop = __mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad,
+ __format = __mt9p031_get_pad_format(mt9p031, cfg, sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -946,13 +946,13 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
crop->left = MT9P031_COLUMN_START_DEF;
crop->top = MT9P031_ROW_START_DEF;
crop->width = MT9P031_WINDOW_WIDTH_DEF;
crop->height = MT9P031_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(fh, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
format->code = MEDIA_BUS_FMT_Y12_1X12;
@@ -1022,7 +1022,6 @@ mt9p031_get_pdata(struct i2c_client *client)
if (!pdata)
goto done;
- pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
@@ -1059,7 +1058,6 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF;
mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
mt9p031->model = did->driver_data;
- mt9p031->reset = -1;
mt9p031->regulators[0].supply = "vdd";
mt9p031->regulators[1].supply = "vdd_io";
@@ -1071,6 +1069,8 @@ static int mt9p031_probe(struct i2c_client *client,
return ret;
}
+ mutex_init(&mt9p031->power_lock);
+
v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
@@ -1108,7 +1108,6 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
V4L2_CID_BLC_DIGITAL_OFFSET);
- mutex_init(&mt9p031->power_lock);
v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
@@ -1134,21 +1133,20 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->format.field = V4L2_FIELD_NONE;
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
- if (gpio_is_valid(pdata->reset)) {
- ret = devm_gpio_request_one(&client->dev, pdata->reset,
- GPIOF_OUT_INIT_LOW, "mt9p031_rst");
- if (ret < 0)
- goto done;
-
- mt9p031->reset = pdata->reset;
- }
+ mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
ret = mt9p031_clk_setup(mt9p031);
+ if (ret)
+ goto done;
+
+ ret = v4l2_async_register_subdev(&mt9p031->subdev);
done:
if (ret < 0) {
v4l2_ctrl_handler_free(&mt9p031->ctrls);
media_entity_cleanup(&mt9p031->subdev.entity);
+ mutex_destroy(&mt9p031->power_lock);
}
return ret;
@@ -1160,8 +1158,9 @@ static int mt9p031_remove(struct i2c_client *client)
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
v4l2_ctrl_handler_free(&mt9p031->ctrls);
- v4l2_device_unregister_subdev(subdev);
+ v4l2_async_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
+ mutex_destroy(&mt9p031->power_lock);
return 0;
}
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index f6ca636..8ae99f7 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -244,12 +244,12 @@ static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on)
*/
static struct v4l2_mbus_framefmt *
-__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&mt9t001->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9t001->format;
default:
@@ -258,12 +258,12 @@ __mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
}
static struct v4l2_rect *
-__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh,
+__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, pad);
+ return v4l2_subdev_get_try_crop(&mt9t001->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9t001->crop;
default:
@@ -327,7 +327,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -338,7 +338,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -353,18 +353,18 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9t001_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad,
+ format->format = *__mt9t001_get_pad_format(mt9t001, cfg, format->pad,
format->which);
return 0;
}
static int mt9t001_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -375,7 +375,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad,
+ __crop = __mt9t001_get_pad_crop(mt9t001, cfg, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -391,7 +391,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
- __format = __mt9t001_get_pad_format(mt9t001, fh, format->pad,
+ __format = __mt9t001_get_pad_format(mt9t001, cfg, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -402,7 +402,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
}
static int mt9t001_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -410,12 +410,12 @@ static int mt9t001_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
+ sel->r = *__mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
return 0;
}
static int mt9t001_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -447,13 +447,13 @@ static int mt9t001_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
+ __crop = __mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad,
+ __format = __mt9t001_get_pad_format(mt9t001, cfg, sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -790,13 +790,13 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
crop->left = MT9T001_COLUMN_START_DEF;
crop->top = MT9T001_ROW_START_DEF;
crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
- format = v4l2_subdev_get_try_format(fh, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index bd3f979..977f400 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -17,6 +17,8 @@
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
@@ -26,6 +28,7 @@
#include <media/mt9v032.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
/* The first four rows are black rows. The active area spans 753x481 pixels. */
@@ -371,12 +374,12 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
*/
static struct v4l2_mbus_framefmt *
-__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->format;
default:
@@ -385,12 +388,12 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
}
static struct v4l2_rect *
-__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, pad);
+ return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->crop;
default:
@@ -448,7 +451,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -459,7 +462,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -474,12 +477,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9v032_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
- format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad,
format->which);
return 0;
}
@@ -509,7 +512,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
}
static int mt9v032_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -520,7 +523,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+ __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -536,7 +539,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
hratio = mt9v032_calc_ratio(__crop->width, width);
vratio = mt9v032_calc_ratio(__crop->height, height);
- __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -553,7 +556,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
}
static int mt9v032_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -561,12 +564,12 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
+ sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
return 0;
}
static int mt9v032_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -598,13 +601,13 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int,
rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
+ __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -810,13 +813,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
crop->left = MT9V032_COLUMN_START_DEF;
crop->top = MT9V032_ROW_START_DEF;
crop->width = MT9V032_WINDOW_WIDTH_DEF;
crop->height = MT9V032_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(fh, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
if (mt9v032->model->color)
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
@@ -876,10 +879,58 @@ static const struct regmap_config mt9v032_regmap_config = {
* Driver initialization and probing
*/
+static struct mt9v032_platform_data *
+mt9v032_get_pdata(struct i2c_client *client)
+{
+ struct mt9v032_platform_data *pdata;
+ struct v4l2_of_endpoint endpoint;
+ struct device_node *np;
+ struct property *prop;
+
+ if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+ return client->dev.platform_data;
+
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
+ if (!np)
+ return NULL;
+
+ if (v4l2_of_parse_endpoint(np, &endpoint) < 0)
+ goto done;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ prop = of_find_property(np, "link-frequencies", NULL);
+ if (prop) {
+ u64 *link_freqs;
+ size_t size = prop->length / sizeof(*link_freqs);
+
+ link_freqs = devm_kcalloc(&client->dev, size,
+ sizeof(*link_freqs), GFP_KERNEL);
+ if (!link_freqs)
+ goto done;
+
+ if (of_property_read_u64_array(np, "link-frequencies",
+ link_freqs, size) < 0)
+ goto done;
+
+ pdata->link_freqs = link_freqs;
+ pdata->link_def_freq = link_freqs[0];
+ }
+
+ pdata->clk_pol = !!(endpoint.bus.parallel.flags &
+ V4L2_MBUS_PCLK_SAMPLE_RISING);
+
+done:
+ of_node_put(np);
+ return pdata;
+}
+
static int mt9v032_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
- struct mt9v032_platform_data *pdata = client->dev.platform_data;
+ struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client);
struct mt9v032 *mt9v032;
unsigned int i;
int ret;
@@ -961,9 +1012,12 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
- if (mt9v032->ctrls.error)
- printk(KERN_INFO "%s: control initialization error %d\n",
- __func__, mt9v032->ctrls.error);
+ if (mt9v032->ctrls.error) {
+ dev_err(&client->dev, "control initialization error %d\n",
+ mt9v032->ctrls.error);
+ ret = mt9v032->ctrls.error;
+ goto err;
+ }
mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
mt9v032->crop.top = MT9V032_ROW_START_DEF;
@@ -1016,7 +1070,6 @@ static int mt9v032_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(subdev);
v4l2_ctrl_handler_free(&mt9v032->ctrls);
- v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
return 0;
@@ -1035,9 +1088,25 @@ static const struct i2c_device_id mt9v032_id[] = {
};
MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt9v032_of_match[] = {
+ { .compatible = "aptina,mt9v022" },
+ { .compatible = "aptina,mt9v022m" },
+ { .compatible = "aptina,mt9v024" },
+ { .compatible = "aptina,mt9v024m" },
+ { .compatible = "aptina,mt9v032" },
+ { .compatible = "aptina,mt9v032m" },
+ { .compatible = "aptina,mt9v034" },
+ { .compatible = "aptina,mt9v034m" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt9v032_of_match);
+#endif
+
static struct i2c_driver mt9v032_driver = {
.driver = {
.name = "mt9v032",
+ .of_match_table = of_match_ptr(mt9v032_of_match),
},
.probe = mt9v032_probe,
.remove = mt9v032_remove,
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 00c7b26..f197b6c 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -492,7 +492,7 @@ unlock:
}
static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(noon010_formats))
@@ -502,15 +502,16 @@ static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int noon010_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct noon010_info *info = to_noon010(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (fh) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ if (cfg) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
fmt->format = *mf;
}
return 0;
@@ -542,7 +543,7 @@ static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
return &noon010_formats[i];
}
-static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct noon010_info *info = to_noon010(sd);
@@ -557,8 +558,8 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (fh) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ if (cfg) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
*mf = fmt->format;
}
return 0;
@@ -640,7 +641,7 @@ static int noon010_log_status(struct v4l2_subdev *sd)
static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
mf->width = noon010_sizes[0].width;
mf->height = noon010_sizes[0].height;
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
new file mode 100644
index 0000000..edebd11
--- /dev/null
+++ b/drivers/media/i2c/ov2659.c
@@ -0,0 +1,1509 @@
+/*
+ * Omnivision OV2659 CMOS Image Sensor driver
+ *
+ * Copyright (C) 2015 Texas Instruments, Inc.
+ *
+ * Benoit Parrot <bparrot@ti.com>
+ * Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/ov2659.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+
+#define DRIVER_NAME "ov2659"
+
+/*
+ * OV2659 register definitions
+ */
+#define REG_SOFTWARE_STANDBY 0x0100
+#define REG_SOFTWARE_RESET 0x0103
+#define REG_IO_CTRL00 0x3000
+#define REG_IO_CTRL01 0x3001
+#define REG_IO_CTRL02 0x3002
+#define REG_OUTPUT_VALUE00 0x3008
+#define REG_OUTPUT_VALUE01 0x3009
+#define REG_OUTPUT_VALUE02 0x300d
+#define REG_OUTPUT_SELECT00 0x300e
+#define REG_OUTPUT_SELECT01 0x300f
+#define REG_OUTPUT_SELECT02 0x3010
+#define REG_OUTPUT_DRIVE 0x3011
+#define REG_INPUT_READOUT00 0x302d
+#define REG_INPUT_READOUT01 0x302e
+#define REG_INPUT_READOUT02 0x302f
+
+#define REG_SC_PLL_CTRL0 0x3003
+#define REG_SC_PLL_CTRL1 0x3004
+#define REG_SC_PLL_CTRL2 0x3005
+#define REG_SC_PLL_CTRL3 0x3006
+#define REG_SC_CHIP_ID_H 0x300a
+#define REG_SC_CHIP_ID_L 0x300b
+#define REG_SC_PWC 0x3014
+#define REG_SC_CLKRST0 0x301a
+#define REG_SC_CLKRST1 0x301b
+#define REG_SC_CLKRST2 0x301c
+#define REG_SC_CLKRST3 0x301d
+#define REG_SC_SUB_ID 0x302a
+#define REG_SC_SCCB_ID 0x302b
+
+#define REG_GROUP_ADDRESS_00 0x3200
+#define REG_GROUP_ADDRESS_01 0x3201
+#define REG_GROUP_ADDRESS_02 0x3202
+#define REG_GROUP_ADDRESS_03 0x3203
+#define REG_GROUP_ACCESS 0x3208
+
+#define REG_AWB_R_GAIN_H 0x3400
+#define REG_AWB_R_GAIN_L 0x3401
+#define REG_AWB_G_GAIN_H 0x3402
+#define REG_AWB_G_GAIN_L 0x3403
+#define REG_AWB_B_GAIN_H 0x3404
+#define REG_AWB_B_GAIN_L 0x3405
+#define REG_AWB_MANUAL_CONTROL 0x3406
+
+#define REG_TIMING_HS_H 0x3800
+#define REG_TIMING_HS_L 0x3801
+#define REG_TIMING_VS_H 0x3802
+#define REG_TIMING_VS_L 0x3803
+#define REG_TIMING_HW_H 0x3804
+#define REG_TIMING_HW_L 0x3805
+#define REG_TIMING_VH_H 0x3806
+#define REG_TIMING_VH_L 0x3807
+#define REG_TIMING_DVPHO_H 0x3808
+#define REG_TIMING_DVPHO_L 0x3809
+#define REG_TIMING_DVPVO_H 0x380a
+#define REG_TIMING_DVPVO_L 0x380b
+#define REG_TIMING_HTS_H 0x380c
+#define REG_TIMING_HTS_L 0x380d
+#define REG_TIMING_VTS_H 0x380e
+#define REG_TIMING_VTS_L 0x380f
+#define REG_TIMING_HOFFS_H 0x3810
+#define REG_TIMING_HOFFS_L 0x3811
+#define REG_TIMING_VOFFS_H 0x3812
+#define REG_TIMING_VOFFS_L 0x3813
+#define REG_TIMING_XINC 0x3814
+#define REG_TIMING_YINC 0x3815
+#define REG_TIMING_VERT_FORMAT 0x3820
+#define REG_TIMING_HORIZ_FORMAT 0x3821
+
+#define REG_FORMAT_CTRL00 0x4300
+
+#define REG_VFIFO_READ_START_H 0x4608
+#define REG_VFIFO_READ_START_L 0x4609
+
+#define REG_DVP_CTRL02 0x4708
+
+#define REG_ISP_CTRL00 0x5000
+#define REG_ISP_CTRL01 0x5001
+#define REG_ISP_CTRL02 0x5002
+
+#define REG_LENC_RED_X0_H 0x500c
+#define REG_LENC_RED_X0_L 0x500d
+#define REG_LENC_RED_Y0_H 0x500e
+#define REG_LENC_RED_Y0_L 0x500f
+#define REG_LENC_RED_A1 0x5010
+#define REG_LENC_RED_B1 0x5011
+#define REG_LENC_RED_A2_B2 0x5012
+#define REG_LENC_GREEN_X0_H 0x5013
+#define REG_LENC_GREEN_X0_L 0x5014
+#define REG_LENC_GREEN_Y0_H 0x5015
+#define REG_LENC_GREEN_Y0_L 0x5016
+#define REG_LENC_GREEN_A1 0x5017
+#define REG_LENC_GREEN_B1 0x5018
+#define REG_LENC_GREEN_A2_B2 0x5019
+#define REG_LENC_BLUE_X0_H 0x501a
+#define REG_LENC_BLUE_X0_L 0x501b
+#define REG_LENC_BLUE_Y0_H 0x501c
+#define REG_LENC_BLUE_Y0_L 0x501d
+#define REG_LENC_BLUE_A1 0x501e
+#define REG_LENC_BLUE_B1 0x501f
+#define REG_LENC_BLUE_A2_B2 0x5020
+
+#define REG_AWB_CTRL00 0x5035
+#define REG_AWB_CTRL01 0x5036
+#define REG_AWB_CTRL02 0x5037
+#define REG_AWB_CTRL03 0x5038
+#define REG_AWB_CTRL04 0x5039
+#define REG_AWB_LOCAL_LIMIT 0x503a
+#define REG_AWB_CTRL12 0x5049
+#define REG_AWB_CTRL13 0x504a
+#define REG_AWB_CTRL14 0x504b
+
+#define REG_SHARPENMT_THRESH1 0x5064
+#define REG_SHARPENMT_THRESH2 0x5065
+#define REG_SHARPENMT_OFFSET1 0x5066
+#define REG_SHARPENMT_OFFSET2 0x5067
+#define REG_DENOISE_THRESH1 0x5068
+#define REG_DENOISE_THRESH2 0x5069
+#define REG_DENOISE_OFFSET1 0x506a
+#define REG_DENOISE_OFFSET2 0x506b
+#define REG_SHARPEN_THRESH1 0x506c
+#define REG_SHARPEN_THRESH2 0x506d
+#define REG_CIP_CTRL00 0x506e
+#define REG_CIP_CTRL01 0x506f
+
+#define REG_CMX_SIGN 0x5079
+#define REG_CMX_MISC_CTRL 0x507a
+
+#define REG_PRE_ISP_CTRL00 0x50a0
+#define TEST_PATTERN_ENABLE BIT(7)
+#define VERTICAL_COLOR_BAR_MASK 0x53
+
+#define REG_NULL 0x0000 /* Array end token */
+
+#define OV265X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb))
+#define OV2659_ID 0x2656
+
+struct sensor_register {
+ u16 addr;
+ u8 value;
+};
+
+struct ov2659_framesize {
+ u16 width;
+ u16 height;
+ u16 max_exp_lines;
+ const struct sensor_register *regs;
+};
+
+struct ov2659_pll_ctrl {
+ u8 ctrl1;
+ u8 ctrl2;
+ u8 ctrl3;
+};
+
+struct ov2659_pixfmt {
+ u32 code;
+ /* Output format Register Value (REG_FORMAT_CTRL00) */
+ struct sensor_register *format_ctrl_regs;
+};
+
+struct pll_ctrl_reg {
+ unsigned int div;
+ unsigned char reg;
+};
+
+struct ov2659 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
+ unsigned int xvclk_frequency;
+ const struct ov2659_platform_data *pdata;
+ struct mutex lock;
+ struct i2c_client *client;
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *link_frequency;
+ const struct ov2659_framesize *frame_size;
+ struct sensor_register *format_ctrl_regs;
+ struct ov2659_pll_ctrl pll;
+ int streaming;
+};
+
+static const struct sensor_register ov2659_init_regs[] = {
+ { REG_IO_CTRL00, 0x03 },
+ { REG_IO_CTRL01, 0xff },
+ { REG_IO_CTRL02, 0xe0 },
+ { 0x3633, 0x3d },
+ { 0x3620, 0x02 },
+ { 0x3631, 0x11 },
+ { 0x3612, 0x04 },
+ { 0x3630, 0x20 },
+ { 0x4702, 0x02 },
+ { 0x370c, 0x34 },
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x03 },
+ { REG_TIMING_DVPHO_L, 0x20 },
+ { REG_TIMING_DVPVO_H, 0x02 },
+ { REG_TIMING_DVPVO_L, 0x58 },
+ { REG_TIMING_HTS_H, 0x05 },
+ { REG_TIMING_HTS_L, 0x14 },
+ { REG_TIMING_VTS_H, 0x02 },
+ { REG_TIMING_VTS_L, 0x68 },
+ { REG_TIMING_HOFFS_L, 0x08 },
+ { REG_TIMING_VOFFS_L, 0x02 },
+ { REG_TIMING_XINC, 0x31 },
+ { REG_TIMING_YINC, 0x31 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { REG_DVP_CTRL02, 0x01 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x81 },
+ { REG_TIMING_HORIZ_FORMAT, 0x01 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_FORMAT_CTRL00, 0x30 },
+ { 0x5086, 0x02 },
+ { REG_ISP_CTRL00, 0xfb },
+ { REG_ISP_CTRL01, 0x1f },
+ { REG_ISP_CTRL02, 0x00 },
+ { 0x5025, 0x0e },
+ { 0x5026, 0x18 },
+ { 0x5027, 0x34 },
+ { 0x5028, 0x4c },
+ { 0x5029, 0x62 },
+ { 0x502a, 0x74 },
+ { 0x502b, 0x85 },
+ { 0x502c, 0x92 },
+ { 0x502d, 0x9e },
+ { 0x502e, 0xb2 },
+ { 0x502f, 0xc0 },
+ { 0x5030, 0xcc },
+ { 0x5031, 0xe0 },
+ { 0x5032, 0xee },
+ { 0x5033, 0xf6 },
+ { 0x5034, 0x11 },
+ { 0x5070, 0x1c },
+ { 0x5071, 0x5b },
+ { 0x5072, 0x05 },
+ { 0x5073, 0x20 },
+ { 0x5074, 0x94 },
+ { 0x5075, 0xb4 },
+ { 0x5076, 0xb4 },
+ { 0x5077, 0xaf },
+ { 0x5078, 0x05 },
+ { REG_CMX_SIGN, 0x98 },
+ { REG_CMX_MISC_CTRL, 0x21 },
+ { REG_AWB_CTRL00, 0x6a },
+ { REG_AWB_CTRL01, 0x11 },
+ { REG_AWB_CTRL02, 0x92 },
+ { REG_AWB_CTRL03, 0x21 },
+ { REG_AWB_CTRL04, 0xe1 },
+ { REG_AWB_LOCAL_LIMIT, 0x01 },
+ { 0x503c, 0x05 },
+ { 0x503d, 0x08 },
+ { 0x503e, 0x08 },
+ { 0x503f, 0x64 },
+ { 0x5040, 0x58 },
+ { 0x5041, 0x2a },
+ { 0x5042, 0xc5 },
+ { 0x5043, 0x2e },
+ { 0x5044, 0x3a },
+ { 0x5045, 0x3c },
+ { 0x5046, 0x44 },
+ { 0x5047, 0xf8 },
+ { 0x5048, 0x08 },
+ { REG_AWB_CTRL12, 0x70 },
+ { REG_AWB_CTRL13, 0xf0 },
+ { REG_AWB_CTRL14, 0xf0 },
+ { REG_LENC_RED_X0_H, 0x03 },
+ { REG_LENC_RED_X0_L, 0x20 },
+ { REG_LENC_RED_Y0_H, 0x02 },
+ { REG_LENC_RED_Y0_L, 0x5c },
+ { REG_LENC_RED_A1, 0x48 },
+ { REG_LENC_RED_B1, 0x00 },
+ { REG_LENC_RED_A2_B2, 0x66 },
+ { REG_LENC_GREEN_X0_H, 0x03 },
+ { REG_LENC_GREEN_X0_L, 0x30 },
+ { REG_LENC_GREEN_Y0_H, 0x02 },
+ { REG_LENC_GREEN_Y0_L, 0x7c },
+ { REG_LENC_GREEN_A1, 0x40 },
+ { REG_LENC_GREEN_B1, 0x00 },
+ { REG_LENC_GREEN_A2_B2, 0x66 },
+ { REG_LENC_BLUE_X0_H, 0x03 },
+ { REG_LENC_BLUE_X0_L, 0x10 },
+ { REG_LENC_BLUE_Y0_H, 0x02 },
+ { REG_LENC_BLUE_Y0_L, 0x7c },
+ { REG_LENC_BLUE_A1, 0x3a },
+ { REG_LENC_BLUE_B1, 0x00 },
+ { REG_LENC_BLUE_A2_B2, 0x66 },
+ { REG_CIP_CTRL00, 0x44 },
+ { REG_SHARPENMT_THRESH1, 0x08 },
+ { REG_SHARPENMT_THRESH2, 0x10 },
+ { REG_SHARPENMT_OFFSET1, 0x12 },
+ { REG_SHARPENMT_OFFSET2, 0x02 },
+ { REG_SHARPEN_THRESH1, 0x08 },
+ { REG_SHARPEN_THRESH2, 0x10 },
+ { REG_CIP_CTRL01, 0xa6 },
+ { REG_DENOISE_THRESH1, 0x08 },
+ { REG_DENOISE_THRESH2, 0x10 },
+ { REG_DENOISE_OFFSET1, 0x04 },
+ { REG_DENOISE_OFFSET2, 0x12 },
+ { 0x507e, 0x40 },
+ { 0x507f, 0x20 },
+ { 0x507b, 0x02 },
+ { REG_CMX_MISC_CTRL, 0x01 },
+ { 0x5084, 0x0c },
+ { 0x5085, 0x3e },
+ { 0x5005, 0x80 },
+ { 0x3a0f, 0x30 },
+ { 0x3a10, 0x28 },
+ { 0x3a1b, 0x32 },
+ { 0x3a1e, 0x26 },
+ { 0x3a11, 0x60 },
+ { 0x3a1f, 0x14 },
+ { 0x5060, 0x69 },
+ { 0x5061, 0x7d },
+ { 0x5062, 0x7d },
+ { 0x5063, 0x69 },
+ { REG_NULL, 0x00 },
+};
+
+/* 1280X720 720p */
+static struct sensor_register ov2659_720p[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0xa0 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0xf0 },
+ { REG_TIMING_HW_H, 0x05 },
+ { REG_TIMING_HW_L, 0xbf },
+ { REG_TIMING_VH_H, 0x03 },
+ { REG_TIMING_VH_L, 0xcb },
+ { REG_TIMING_DVPHO_H, 0x05 },
+ { REG_TIMING_DVPHO_L, 0x00 },
+ { REG_TIMING_DVPVO_H, 0x02 },
+ { REG_TIMING_DVPVO_L, 0xd0 },
+ { REG_TIMING_HTS_H, 0x06 },
+ { REG_TIMING_HTS_L, 0x4c },
+ { REG_TIMING_VTS_H, 0x02 },
+ { REG_TIMING_VTS_L, 0xe8 },
+ { REG_TIMING_HOFFS_L, 0x10 },
+ { REG_TIMING_VOFFS_L, 0x06 },
+ { REG_TIMING_XINC, 0x11 },
+ { REG_TIMING_YINC, 0x11 },
+ { REG_TIMING_VERT_FORMAT, 0x80 },
+ { REG_TIMING_HORIZ_FORMAT, 0x00 },
+ { 0x3a03, 0xe8 },
+ { 0x3a09, 0x6f },
+ { 0x3a0b, 0x5d },
+ { 0x3a15, 0x9a },
+ { REG_NULL, 0x00 },
+};
+
+/* 1600X1200 UXGA */
+static struct sensor_register ov2659_uxga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xbb },
+ { REG_TIMING_DVPHO_H, 0x06 },
+ { REG_TIMING_DVPHO_L, 0x40 },
+ { REG_TIMING_DVPVO_H, 0x04 },
+ { REG_TIMING_DVPVO_L, 0xb0 },
+ { REG_TIMING_HTS_H, 0x07 },
+ { REG_TIMING_HTS_L, 0x9f },
+ { REG_TIMING_VTS_H, 0x04 },
+ { REG_TIMING_VTS_L, 0xd0 },
+ { REG_TIMING_HOFFS_L, 0x10 },
+ { REG_TIMING_VOFFS_L, 0x06 },
+ { REG_TIMING_XINC, 0x11 },
+ { REG_TIMING_YINC, 0x11 },
+ { 0x3a02, 0x04 },
+ { 0x3a03, 0xd0 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0xb8 },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x9a },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x04 },
+ { 0x3a15, 0x50 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x44 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x30 },
+ { 0x3703, 0x48 },
+ { 0x3704, 0x48 },
+ { 0x3705, 0x18 },
+ { REG_TIMING_VERT_FORMAT, 0x80 },
+ { REG_TIMING_HORIZ_FORMAT, 0x00 },
+ { 0x370a, 0x12 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x00 },
+ { REG_NULL, 0x00 },
+};
+
+/* 1280X1024 SXGA */
+static struct sensor_register ov2659_sxga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x05 },
+ { REG_TIMING_DVPHO_L, 0x00 },
+ { REG_TIMING_DVPVO_H, 0x04 },
+ { REG_TIMING_DVPVO_L, 0x00 },
+ { REG_TIMING_HTS_H, 0x07 },
+ { REG_TIMING_HTS_L, 0x9c },
+ { REG_TIMING_VTS_H, 0x04 },
+ { REG_TIMING_VTS_L, 0xd0 },
+ { REG_TIMING_HOFFS_L, 0x10 },
+ { REG_TIMING_VOFFS_L, 0x06 },
+ { REG_TIMING_XINC, 0x11 },
+ { REG_TIMING_YINC, 0x11 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x80 },
+ { REG_TIMING_HORIZ_FORMAT, 0x00 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x00 },
+ { REG_NULL, 0x00 },
+};
+
+/* 1024X768 SXGA */
+static struct sensor_register ov2659_xga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x04 },
+ { REG_TIMING_DVPHO_L, 0x00 },
+ { REG_TIMING_DVPVO_H, 0x03 },
+ { REG_TIMING_DVPVO_L, 0x00 },
+ { REG_TIMING_HTS_H, 0x07 },
+ { REG_TIMING_HTS_L, 0x9c },
+ { REG_TIMING_VTS_H, 0x04 },
+ { REG_TIMING_VTS_L, 0xd0 },
+ { REG_TIMING_HOFFS_L, 0x10 },
+ { REG_TIMING_VOFFS_L, 0x06 },
+ { REG_TIMING_XINC, 0x11 },
+ { REG_TIMING_YINC, 0x11 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x80 },
+ { REG_TIMING_HORIZ_FORMAT, 0x00 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x00 },
+ { REG_NULL, 0x00 },
+};
+
+/* 800X600 SVGA */
+static struct sensor_register ov2659_svga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x03 },
+ { REG_TIMING_DVPHO_L, 0x20 },
+ { REG_TIMING_DVPVO_H, 0x02 },
+ { REG_TIMING_DVPVO_L, 0x58 },
+ { REG_TIMING_HTS_H, 0x05 },
+ { REG_TIMING_HTS_L, 0x14 },
+ { REG_TIMING_VTS_H, 0x02 },
+ { REG_TIMING_VTS_L, 0x68 },
+ { REG_TIMING_HOFFS_L, 0x08 },
+ { REG_TIMING_VOFFS_L, 0x02 },
+ { REG_TIMING_XINC, 0x31 },
+ { REG_TIMING_YINC, 0x31 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x81 },
+ { REG_TIMING_HORIZ_FORMAT, 0x01 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x00 },
+ { REG_NULL, 0x00 },
+};
+
+/* 640X480 VGA */
+static struct sensor_register ov2659_vga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x02 },
+ { REG_TIMING_DVPHO_L, 0x80 },
+ { REG_TIMING_DVPVO_H, 0x01 },
+ { REG_TIMING_DVPVO_L, 0xe0 },
+ { REG_TIMING_HTS_H, 0x05 },
+ { REG_TIMING_HTS_L, 0x14 },
+ { REG_TIMING_VTS_H, 0x02 },
+ { REG_TIMING_VTS_L, 0x68 },
+ { REG_TIMING_HOFFS_L, 0x08 },
+ { REG_TIMING_VOFFS_L, 0x02 },
+ { REG_TIMING_XINC, 0x31 },
+ { REG_TIMING_YINC, 0x31 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x81 },
+ { REG_TIMING_HORIZ_FORMAT, 0x01 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x10 },
+ { REG_NULL, 0x00 },
+};
+
+/* 320X240 QVGA */
+static struct sensor_register ov2659_qvga[] = {
+ { REG_TIMING_HS_H, 0x00 },
+ { REG_TIMING_HS_L, 0x00 },
+ { REG_TIMING_VS_H, 0x00 },
+ { REG_TIMING_VS_L, 0x00 },
+ { REG_TIMING_HW_H, 0x06 },
+ { REG_TIMING_HW_L, 0x5f },
+ { REG_TIMING_VH_H, 0x04 },
+ { REG_TIMING_VH_L, 0xb7 },
+ { REG_TIMING_DVPHO_H, 0x01 },
+ { REG_TIMING_DVPHO_L, 0x40 },
+ { REG_TIMING_DVPVO_H, 0x00 },
+ { REG_TIMING_DVPVO_L, 0xf0 },
+ { REG_TIMING_HTS_H, 0x05 },
+ { REG_TIMING_HTS_L, 0x14 },
+ { REG_TIMING_VTS_H, 0x02 },
+ { REG_TIMING_VTS_L, 0x68 },
+ { REG_TIMING_HOFFS_L, 0x08 },
+ { REG_TIMING_VOFFS_L, 0x02 },
+ { REG_TIMING_XINC, 0x31 },
+ { REG_TIMING_YINC, 0x31 },
+ { 0x3a02, 0x02 },
+ { 0x3a03, 0x68 },
+ { 0x3a08, 0x00 },
+ { 0x3a09, 0x5c },
+ { 0x3a0a, 0x00 },
+ { 0x3a0b, 0x4d },
+ { 0x3a0d, 0x08 },
+ { 0x3a0e, 0x06 },
+ { 0x3a14, 0x02 },
+ { 0x3a15, 0x28 },
+ { 0x3623, 0x00 },
+ { 0x3634, 0x76 },
+ { 0x3701, 0x44 },
+ { 0x3702, 0x18 },
+ { 0x3703, 0x24 },
+ { 0x3704, 0x24 },
+ { 0x3705, 0x0c },
+ { REG_TIMING_VERT_FORMAT, 0x81 },
+ { REG_TIMING_HORIZ_FORMAT, 0x01 },
+ { 0x370a, 0x52 },
+ { REG_VFIFO_READ_START_H, 0x00 },
+ { REG_VFIFO_READ_START_L, 0x80 },
+ { REG_ISP_CTRL02, 0x10 },
+ { REG_NULL, 0x00 },
+};
+
+static const struct pll_ctrl_reg ctrl3[] = {
+ { 1, 0x00 },
+ { 2, 0x02 },
+ { 3, 0x03 },
+ { 4, 0x06 },
+ { 6, 0x0d },
+ { 8, 0x0e },
+ { 12, 0x0f },
+ { 16, 0x12 },
+ { 24, 0x13 },
+ { 32, 0x16 },
+ { 48, 0x1b },
+ { 64, 0x1e },
+ { 96, 0x1f },
+ { 0, 0x00 },
+};
+
+static const struct pll_ctrl_reg ctrl1[] = {
+ { 2, 0x10 },
+ { 4, 0x20 },
+ { 6, 0x30 },
+ { 8, 0x40 },
+ { 10, 0x50 },
+ { 12, 0x60 },
+ { 14, 0x70 },
+ { 16, 0x80 },
+ { 18, 0x90 },
+ { 20, 0xa0 },
+ { 22, 0xb0 },
+ { 24, 0xc0 },
+ { 26, 0xd0 },
+ { 28, 0xe0 },
+ { 30, 0xf0 },
+ { 0, 0x00 },
+};
+
+static const struct ov2659_framesize ov2659_framesizes[] = {
+ { /* QVGA */
+ .width = 320,
+ .height = 240,
+ .regs = ov2659_qvga,
+ .max_exp_lines = 248,
+ }, { /* VGA */
+ .width = 640,
+ .height = 480,
+ .regs = ov2659_vga,
+ .max_exp_lines = 498,
+ }, { /* SVGA */
+ .width = 800,
+ .height = 600,
+ .regs = ov2659_svga,
+ .max_exp_lines = 498,
+ }, { /* XGA */
+ .width = 1024,
+ .height = 768,
+ .regs = ov2659_xga,
+ .max_exp_lines = 498,
+ }, { /* 720P */
+ .width = 1280,
+ .height = 720,
+ .regs = ov2659_720p,
+ .max_exp_lines = 498,
+ }, { /* SXGA */
+ .width = 1280,
+ .height = 1024,
+ .regs = ov2659_sxga,
+ .max_exp_lines = 1048,
+ }, { /* UXGA */
+ .width = 1600,
+ .height = 1200,
+ .regs = ov2659_uxga,
+ .max_exp_lines = 498,
+ },
+};
+
+/* YUV422 YUYV*/
+static struct sensor_register ov2659_format_yuyv[] = {
+ { REG_FORMAT_CTRL00, 0x30 },
+ { REG_NULL, 0x0 },
+};
+
+/* YUV422 UYVY */
+static struct sensor_register ov2659_format_uyvy[] = {
+ { REG_FORMAT_CTRL00, 0x32 },
+ { REG_NULL, 0x0 },
+};
+
+/* Raw Bayer BGGR */
+static struct sensor_register ov2659_format_bggr[] = {
+ { REG_FORMAT_CTRL00, 0x00 },
+ { REG_NULL, 0x0 },
+};
+
+/* RGB565 */
+static struct sensor_register ov2659_format_rgb565[] = {
+ { REG_FORMAT_CTRL00, 0x60 },
+ { REG_NULL, 0x0 },
+};
+
+static const struct ov2659_pixfmt ov2659_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .format_ctrl_regs = ov2659_format_yuyv,
+ }, {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .format_ctrl_regs = ov2659_format_uyvy,
+ }, {
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .format_ctrl_regs = ov2659_format_rgb565,
+ }, {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .format_ctrl_regs = ov2659_format_bggr,
+ },
+};
+
+static inline struct ov2659 *to_ov2659(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov2659, sd);
+}
+
+/* sensor register write */
+static int ov2659_write(struct i2c_client *client, u16 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[3];
+ int ret;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xFF;
+ buf[2] = val;
+
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.buf = buf;
+ msg.len = sizeof(buf);
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret >= 0)
+ return 0;
+
+ dev_dbg(&client->dev,
+ "ov2659 write reg(0x%x val:0x%x) failed !\n", reg, val);
+
+ return ret;
+}
+
+/* sensor register read */
+static int ov2659_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ int ret;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xFF;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags;
+ msg[0].buf = buf;
+ msg[0].len = sizeof(buf);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = 1;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret >= 0) {
+ *val = buf[0];
+ return 0;
+ }
+
+ dev_dbg(&client->dev,
+ "ov2659 read reg(0x%x val:0x%x) failed !\n", reg, *val);
+
+ return ret;
+}
+
+static int ov2659_write_array(struct i2c_client *client,
+ const struct sensor_register *regs)
+{
+ int i, ret = 0;
+
+ for (i = 0; ret == 0 && regs[i].addr; i++)
+ ret = ov2659_write(client, regs[i].addr, regs[i].value);
+
+ return ret;
+}
+
+static void ov2659_pll_calc_params(struct ov2659 *ov2659)
+{
+ const struct ov2659_platform_data *pdata = ov2659->pdata;
+ u8 ctrl1_reg = 0, ctrl2_reg = 0, ctrl3_reg = 0;
+ struct i2c_client *client = ov2659->client;
+ unsigned int desired = pdata->link_frequency;
+ u32 s_prediv = 1, s_postdiv = 1, s_mult = 1;
+ u32 prediv, postdiv, mult;
+ u32 bestdelta = -1;
+ u32 delta, actual;
+ int i, j;
+
+ for (i = 0; ctrl1[i].div != 0; i++) {
+ postdiv = ctrl1[i].div;
+ for (j = 0; ctrl3[j].div != 0; j++) {
+ prediv = ctrl3[j].div;
+ for (mult = 1; mult <= 63; mult++) {
+ actual = ov2659->xvclk_frequency;
+ actual *= mult;
+ actual /= prediv;
+ actual /= postdiv;
+ delta = actual - desired;
+ delta = abs(delta);
+
+ if ((delta < bestdelta) || (bestdelta == -1)) {
+ bestdelta = delta;
+ s_mult = mult;
+ s_prediv = prediv;
+ s_postdiv = postdiv;
+ ctrl1_reg = ctrl1[i].reg;
+ ctrl2_reg = mult;
+ ctrl3_reg = ctrl3[j].reg;
+ }
+ }
+ }
+ }
+
+ ov2659->pll.ctrl1 = ctrl1_reg;
+ ov2659->pll.ctrl2 = ctrl2_reg;
+ ov2659->pll.ctrl3 = ctrl3_reg;
+
+ dev_dbg(&client->dev,
+ "Actual reg config: ctrl1_reg: %02x ctrl2_reg: %02x ctrl3_reg: %02x\n",
+ ctrl1_reg, ctrl2_reg, ctrl3_reg);
+}
+
+static int ov2659_set_pixel_clock(struct ov2659 *ov2659)
+{
+ struct i2c_client *client = ov2659->client;
+ struct sensor_register pll_regs[] = {
+ {REG_SC_PLL_CTRL1, ov2659->pll.ctrl1},
+ {REG_SC_PLL_CTRL2, ov2659->pll.ctrl2},
+ {REG_SC_PLL_CTRL3, ov2659->pll.ctrl3},
+ {REG_NULL, 0x00},
+ };
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ return ov2659_write_array(client, pll_regs);
+};
+
+static void ov2659_get_default_format(struct v4l2_mbus_framefmt *format)
+{
+ format->width = ov2659_framesizes[2].width;
+ format->height = ov2659_framesizes[2].height;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+ format->code = ov2659_formats[0].code;
+ format->field = V4L2_FIELD_NONE;
+}
+
+static void ov2659_set_streaming(struct ov2659 *ov2659, int on)
+{
+ struct i2c_client *client = ov2659->client;
+ int ret;
+
+ on = !!on;
+
+ dev_dbg(&client->dev, "%s: on: %d\n", __func__, on);
+
+ ret = ov2659_write(client, REG_SOFTWARE_STANDBY, on);
+ if (ret)
+ dev_err(&client->dev, "ov2659 soft standby failed\n");
+}
+
+static int ov2659_init(struct v4l2_subdev *sd, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return ov2659_write_array(client, ov2659_init_regs);
+}
+
+/*
+ * V4L2 subdev video and pad level operations
+ */
+
+static int ov2659_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);
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ if (code->index >= ARRAY_SIZE(ov2659_formats))
+ return -EINVAL;
+
+ code->code = ov2659_formats[code->index].code;
+
+ return 0;
+}
+
+static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int i = ARRAY_SIZE(ov2659_formats);
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ if (fse->index >= ARRAY_SIZE(ov2659_framesizes))
+ return -EINVAL;
+
+ while (--i)
+ if (fse->code == ov2659_formats[i].code)
+ break;
+
+ fse->code = ov2659_formats[i].code;
+
+ fse->min_width = ov2659_framesizes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = ov2659_framesizes[fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int ov2659_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2659 *ov2659 = to_ov2659(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ dev_dbg(&client->dev, "ov2659_get_fmt\n");
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mutex_lock(&ov2659->lock);
+ fmt->format = *mf;
+ mutex_unlock(&ov2659->lock);
+ return 0;
+ }
+
+ mutex_lock(&ov2659->lock);
+ fmt->format = ov2659->format;
+ mutex_unlock(&ov2659->lock);
+
+ dev_dbg(&client->dev, "ov2659_get_fmt: %x %dx%d\n",
+ ov2659->format.code, ov2659->format.width,
+ ov2659->format.height);
+
+ return 0;
+}
+
+static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf,
+ const struct ov2659_framesize **size)
+{
+ const struct ov2659_framesize *fsize = &ov2659_framesizes[0];
+ const struct ov2659_framesize *match = NULL;
+ int i = ARRAY_SIZE(ov2659_framesizes);
+ unsigned int min_err = UINT_MAX;
+
+ while (i--) {
+ int err = abs(fsize->width - mf->width)
+ + abs(fsize->height - mf->height);
+ if ((err < min_err) && (fsize->regs[0].addr)) {
+ min_err = err;
+ match = fsize;
+ }
+ fsize++;
+ }
+
+ if (!match)
+ match = &ov2659_framesizes[2];
+
+ mf->width = match->width;
+ mf->height = match->height;
+
+ if (size)
+ *size = match;
+}
+
+static int ov2659_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ unsigned int index = ARRAY_SIZE(ov2659_formats);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ const struct ov2659_framesize *size = NULL;
+ struct ov2659 *ov2659 = to_ov2659(sd);
+ int ret = 0;
+
+ dev_dbg(&client->dev, "ov2659_set_fmt\n");
+
+ __ov2659_try_frame_size(mf, &size);
+
+ while (--index >= 0)
+ if (ov2659_formats[index].code == mf->code)
+ break;
+
+ if (index < 0)
+ return -EINVAL;
+
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ mf->code = ov2659_formats[index].code;
+ mf->field = V4L2_FIELD_NONE;
+
+ mutex_lock(&ov2659->lock);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ *mf = fmt->format;
+ } else {
+ s64 val;
+
+ if (ov2659->streaming) {
+ mutex_unlock(&ov2659->lock);
+ return -EBUSY;
+ }
+
+ ov2659->frame_size = size;
+ ov2659->format = fmt->format;
+ ov2659->format_ctrl_regs =
+ ov2659_formats[index].format_ctrl_regs;
+
+ if (ov2659->format.code != MEDIA_BUS_FMT_SBGGR8_1X8)
+ val = ov2659->pdata->link_frequency / 2;
+ else
+ val = ov2659->pdata->link_frequency;
+
+ ret = v4l2_ctrl_s_ctrl_int64(ov2659->link_frequency, val);
+ if (ret < 0)
+ dev_warn(&client->dev,
+ "failed to set link_frequency rate (%d)\n",
+ ret);
+ }
+
+ mutex_unlock(&ov2659->lock);
+ return ret;
+}
+
+static int ov2659_set_frame_size(struct ov2659 *ov2659)
+{
+ struct i2c_client *client = ov2659->client;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ return ov2659_write_array(ov2659->client, ov2659->frame_size->regs);
+}
+
+static int ov2659_set_format(struct ov2659 *ov2659)
+{
+ struct i2c_client *client = ov2659->client;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ return ov2659_write_array(ov2659->client, ov2659->format_ctrl_regs);
+}
+
+static int ov2659_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2659 *ov2659 = to_ov2659(sd);
+ int ret = 0;
+
+ dev_dbg(&client->dev, "%s: on: %d\n", __func__, on);
+
+ mutex_lock(&ov2659->lock);
+
+ on = !!on;
+
+ if (ov2659->streaming == on)
+ goto unlock;
+
+ if (!on) {
+ /* Stop Streaming Sequence */
+ ov2659_set_streaming(ov2659, 0);
+ ov2659->streaming = on;
+ goto unlock;
+ }
+
+ ov2659_set_pixel_clock(ov2659);
+ ov2659_set_frame_size(ov2659);
+ ov2659_set_format(ov2659);
+ ov2659_set_streaming(ov2659, 1);
+ ov2659->streaming = on;
+
+unlock:
+ mutex_unlock(&ov2659->lock);
+ return ret;
+}
+
+static int ov2659_set_test_pattern(struct ov2659 *ov2659, int value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov2659->sd);
+ int ret;
+ u8 val;
+
+ ret = ov2659_read(client, REG_PRE_ISP_CTRL00, &val);
+ if (ret < 0)
+ return ret;
+
+ switch (value) {
+ case 0:
+ val &= ~TEST_PATTERN_ENABLE;
+ break;
+ case 1:
+ val &= VERTICAL_COLOR_BAR_MASK;
+ val |= TEST_PATTERN_ENABLE;
+ break;
+ }
+
+ return ov2659_write(client, REG_PRE_ISP_CTRL00, val);
+}
+
+static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov2659 *ov2659 =
+ container_of(ctrl->handler, struct ov2659, ctrls);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ return ov2659_set_test_pattern(ov2659, ctrl->val);
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops ov2659_ctrl_ops = {
+ .s_ctrl = ov2659_s_ctrl,
+};
+
+static const char * const ov2659_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bars",
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ ov2659_get_default_format(format);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops ov2659_subdev_video_ops = {
+ .s_stream = ov2659_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = {
+ .enum_mbus_code = ov2659_enum_mbus_code,
+ .enum_frame_size = ov2659_enum_frame_sizes,
+ .get_fmt = ov2659_get_fmt,
+ .set_fmt = ov2659_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov2659_subdev_ops = {
+ .core = &ov2659_subdev_core_ops,
+ .video = &ov2659_subdev_video_ops,
+ .pad = &ov2659_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = {
+ .open = ov2659_open,
+};
+
+static int ov2659_detect(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 pid, ver;
+ int ret;
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ ret = ov2659_write(client, REG_SOFTWARE_RESET, 0x01);
+ if (ret != 0) {
+ dev_err(&client->dev, "Sensor soft reset failed\n");
+ return -ENODEV;
+ }
+ usleep_range(1000, 2000);
+
+ ret = ov2659_init(sd, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Check sensor revision */
+ ret = ov2659_read(client, REG_SC_CHIP_ID_H, &pid);
+ if (!ret)
+ ret = ov2659_read(client, REG_SC_CHIP_ID_L, &ver);
+
+ if (!ret) {
+ unsigned short id;
+
+ id = OV265X_ID(pid, ver);
+ if (id != OV2659_ID)
+ dev_err(&client->dev,
+ "Sensor detection failed (%04X, %d)\n",
+ id, ret);
+ else
+ dev_info(&client->dev, "Found OV%04X sensor\n", id);
+ }
+
+ return ret;
+}
+
+static struct ov2659_platform_data *
+ov2659_get_pdata(struct i2c_client *client)
+{
+ struct ov2659_platform_data *pdata;
+ struct device_node *endpoint;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+ return client->dev.platform_data;
+
+ endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
+ if (!endpoint)
+ return NULL;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ ret = of_property_read_u64(endpoint, "link-frequencies",
+ &pdata->link_frequency);
+ if (ret) {
+ dev_err(&client->dev, "link-frequencies property not found\n");
+ pdata = NULL;
+ }
+
+done:
+ of_node_put(endpoint);
+ return pdata;
+}
+
+static int ov2659_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct ov2659_platform_data *pdata = ov2659_get_pdata(client);
+ struct v4l2_subdev *sd;
+ struct ov2659 *ov2659;
+ struct clk *clk;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not specified\n");
+ return -EINVAL;
+ }
+
+ ov2659 = devm_kzalloc(&client->dev, sizeof(*ov2659), GFP_KERNEL);
+ if (!ov2659)
+ return -ENOMEM;
+
+ ov2659->pdata = pdata;
+ ov2659->client = client;
+
+ clk = devm_clk_get(&client->dev, "xvclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ov2659->xvclk_frequency = clk_get_rate(clk);
+ if (ov2659->xvclk_frequency < 6000000 ||
+ ov2659->xvclk_frequency > 27000000)
+ return -EINVAL;
+
+ v4l2_ctrl_handler_init(&ov2659->ctrls, 2);
+ ov2659->link_frequency =
+ v4l2_ctrl_new_std(&ov2659->ctrls, &ov2659_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ pdata->link_frequency / 2,
+ pdata->link_frequency, 1,
+ pdata->link_frequency);
+ v4l2_ctrl_new_std_menu_items(&ov2659->ctrls, &ov2659_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov2659_test_pattern_menu) - 1,
+ 0, 0, ov2659_test_pattern_menu);
+ ov2659->sd.ctrl_handler = &ov2659->ctrls;
+
+ if (ov2659->ctrls.error) {
+ dev_err(&client->dev, "%s: control initialization error %d\n",
+ __func__, ov2659->ctrls.error);
+ return ov2659->ctrls.error;
+ }
+
+ sd = &ov2659->sd;
+ client->flags |= I2C_CLIENT_SCCB;
+ v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops);
+
+ sd->internal_ops = &ov2659_subdev_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ ov2659->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&ov2659->ctrls);
+ return ret;
+ }
+#endif
+
+ mutex_init(&ov2659->lock);
+
+ ov2659_get_default_format(&ov2659->format);
+ ov2659->frame_size = &ov2659_framesizes[2];
+ ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs;
+
+ ret = ov2659_detect(sd);
+ if (ret < 0)
+ goto error;
+
+ /* Calculate the PLL register value needed */
+ ov2659_pll_calc_params(ov2659);
+
+ ret = v4l2_async_register_subdev(&ov2659->sd);
+ if (ret)
+ goto error;
+
+ dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name);
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&ov2659->ctrls);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&sd->entity);
+#endif
+ mutex_destroy(&ov2659->lock);
+ return ret;
+}
+
+static int ov2659_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov2659 *ov2659 = to_ov2659(sd);
+
+ v4l2_ctrl_handler_free(&ov2659->ctrls);
+ v4l2_async_unregister_subdev(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&sd->entity);
+#endif
+ mutex_destroy(&ov2659->lock);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov2659_id[] = {
+ { "ov2659", 0 },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, ov2659_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov2659_of_match[] = {
+ { .compatible = "ovti,ov2659", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov2659_of_match);
+#endif
+
+static struct i2c_driver ov2659_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(ov2659_of_match),
+ },
+ .probe = ov2659_probe,
+ .remove = ov2659_remove,
+ .id_table = ov2659_id,
+};
+
+module_i2c_driver(ov2659_i2c_driver);
+
+MODULE_AUTHOR("Benoit Parrot <bparrot@ti.com>");
+MODULE_DESCRIPTION("OV2659 CMOS Image Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 957927f..b984752 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1069,29 +1069,35 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
-static int ov7670_enum_frameintervals(struct v4l2_subdev *sd,
- struct v4l2_frmivalenum *interval)
+static int ov7670_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
{
- if (interval->index >= ARRAY_SIZE(ov7670_frame_rates))
+ if (fie->pad)
return -EINVAL;
- interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- interval->discrete.numerator = 1;
- interval->discrete.denominator = ov7670_frame_rates[interval->index];
+ if (fie->index >= ARRAY_SIZE(ov7670_frame_rates))
+ return -EINVAL;
+ fie->interval.numerator = 1;
+ fie->interval.denominator = ov7670_frame_rates[fie->index];
return 0;
}
/*
* Frame size enumeration
*/
-static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
- struct v4l2_frmsizeenum *fsize)
+static int ov7670_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
{
struct ov7670_info *info = to_state(sd);
int i;
int num_valid = -1;
- __u32 index = fsize->index;
+ __u32 index = fse->index;
unsigned int n_win_sizes = info->devtype->n_win_sizes;
+ if (fse->pad)
+ return -EINVAL;
+
/*
* If a minimum width/height was requested, filter out the capture
* windows that fall outside that.
@@ -1103,9 +1109,8 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
if (info->min_height && win->height < info->min_height)
continue;
if (index == ++num_valid) {
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = win->width;
- fsize->discrete.height = win->height;
+ fse->min_width = fse->max_width = win->width;
+ fse->min_height = fse->max_height = win->height;
return 0;
}
}
@@ -1485,13 +1490,17 @@ static const struct v4l2_subdev_video_ops ov7670_video_ops = {
.s_mbus_fmt = ov7670_s_mbus_fmt,
.s_parm = ov7670_s_parm,
.g_parm = ov7670_g_parm,
- .enum_frameintervals = ov7670_enum_frameintervals,
- .enum_framesizes = ov7670_enum_framesizes,
+};
+
+static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
+ .enum_frame_interval = ov7670_enum_frame_interval,
+ .enum_frame_size = ov7670_enum_frame_size,
};
static const struct v4l2_subdev_ops ov7670_ops = {
.core = &ov7670_core_ops,
.video = &ov7670_video_ops,
+ .pad = &ov7670_pad_ops,
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 2246bd5..2bc4733 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1067,7 +1067,7 @@ static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf)
}
static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(ov965x_formats))
@@ -1078,7 +1078,7 @@ static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
int i = ARRAY_SIZE(ov965x_formats);
@@ -1164,14 +1164,14 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
return ret;
}
-static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct ov965x *ov965x = to_ov965x(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
fmt->format = *mf;
return 0;
}
@@ -1208,7 +1208,7 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf,
*size = match;
}
-static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
unsigned int index = ARRAY_SIZE(ov965x_formats);
@@ -1230,8 +1230,8 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
mutex_lock(&ov965x->lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (fh != NULL) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ if (cfg != NULL) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
}
} else {
@@ -1361,7 +1361,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
*/
static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
ov965x_get_default_format(mf);
return 0;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index ee0f57e..08b234b 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -824,10 +824,11 @@ static const struct s5c73m3_frame_size *s5c73m3_find_frame_size(
}
static void s5c73m3_oif_try_format(struct s5c73m3 *state,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt,
const struct s5c73m3_frame_size **fs)
{
+ struct v4l2_subdev *sd = &state->sensor_sd;
u32 code;
switch (fmt->pad) {
@@ -850,7 +851,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
*fs = state->oif_pix_size[RES_ISP];
else
*fs = s5c73m3_find_frame_size(
- v4l2_subdev_get_try_format(fh,
+ v4l2_subdev_get_try_format(sd, cfg,
OIF_ISP_PAD),
RES_ISP);
break;
@@ -860,7 +861,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
}
static void s5c73m3_try_format(struct s5c73m3 *state,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt,
const struct s5c73m3_frame_size **fs)
{
@@ -952,7 +953,7 @@ static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -990,7 +991,7 @@ static int s5c73m3_oif_get_pad_code(int pad, int index)
}
static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
@@ -998,7 +999,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
return 0;
}
@@ -1024,7 +1025,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -1032,7 +1033,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
return 0;
}
@@ -1062,7 +1063,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1072,10 +1073,10 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&state->lock);
- s5c73m3_try_format(state, fh, fmt, &frame_size);
+ s5c73m3_try_format(state, cfg, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
} else {
switch (fmt->pad) {
@@ -1101,7 +1102,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1111,13 +1112,13 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&state->lock);
- s5c73m3_oif_try_format(state, fh, fmt, &frame_size);
+ s5c73m3_oif_try_format(state, cfg, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
if (fmt->pad == OIF_ISP_PAD) {
- mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD);
+ mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD);
mf->width = fmt->format.width;
mf->height = fmt->format.height;
}
@@ -1189,7 +1190,7 @@ static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
}
static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const int codes[] = {
@@ -1205,7 +1206,7 @@ static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
int ret;
@@ -1220,7 +1221,7 @@ static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
int idx;
@@ -1247,9 +1248,10 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
int idx;
if (fse->pad == OIF_SOURCE_PAD) {
@@ -1259,11 +1261,25 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
switch (fse->code) {
case S5C73M3_JPEG_FMT:
case S5C73M3_ISP_FMT: {
- struct v4l2_mbus_framefmt *mf =
- v4l2_subdev_get_try_format(fh, OIF_ISP_PAD);
+ unsigned w, h;
+
+ if (fse->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = v4l2_subdev_get_try_format(sd, cfg,
+ OIF_ISP_PAD);
+
+ w = mf->width;
+ h = mf->height;
+ } else {
+ const struct s5c73m3_frame_size *fs;
- fse->max_width = fse->min_width = mf->width;
- fse->max_height = fse->min_height = mf->height;
+ fs = state->oif_pix_size[RES_ISP];
+ w = fs->width;
+ h = fs->height;
+ }
+ fse->max_width = fse->min_width = w;
+ fse->max_height = fse->min_height = h;
return 0;
}
default:
@@ -1306,11 +1322,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
@@ -1321,15 +1337,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
- mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
return 0;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
index f60b265..63eb190 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -52,7 +52,7 @@ static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
xfer.rx_buf = addr;
if (spi_dev == NULL) {
- dev_err(&spi_dev->dev, "SPI device is uninitialized\n");
+ pr_err("SPI device is uninitialized\n");
return -ENODEV;
}
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 7007131..9708423 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -531,7 +531,7 @@ static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf,
}
static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
@@ -541,15 +541,15 @@ static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k4ecgx *priv = to_s5k4ecgx(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (fh) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ if (cfg) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
fmt->format = *mf;
}
return 0;
@@ -581,7 +581,7 @@ static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd,
return &s5k4ecgx_formats[i];
}
-static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k4ecgx *priv = to_s5k4ecgx(sd);
@@ -596,8 +596,8 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (fh) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ if (cfg) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
*mf = fmt->format;
}
return 0;
@@ -692,7 +692,7 @@ static int s5k4ecgx_registered(struct v4l2_subdev *sd)
*/
static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
mf->width = s5k4ecgx_prev_sizes[0].size.width;
mf->height = s5k4ecgx_prev_sizes[0].size.height;
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index a3d7d03..297ef04 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -374,6 +374,8 @@ static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
count -= S5K5BAG_FW_TAG_LEN;
d = devm_kzalloc(dev, count * sizeof(u16), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
for (i = 0; i < count; ++i)
d[i] = le16_to_cpu(data[i]);
@@ -1182,7 +1184,7 @@ static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
* V4L2 subdev pad level and video operations
*/
static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
{
if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME ||
@@ -1201,7 +1203,7 @@ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
}
static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad == PAD_CIS) {
@@ -1219,7 +1221,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
int i;
@@ -1276,7 +1278,7 @@ static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf)
return pixfmt;
}
-static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k5baf *state = to_s5k5baf(sd);
@@ -1284,7 +1286,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1306,7 +1308,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
@@ -1317,7 +1319,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
mf->field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(fh, fmt->pad) = *mf;
+ *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = *mf;
return 0;
}
@@ -1369,7 +1371,7 @@ static int s5k5baf_is_bound_target(u32 target)
}
static int s5k5baf_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
static enum selection_rect rtype;
@@ -1389,9 +1391,9 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
if (rtype == R_COMPOSE)
- sel->r = *v4l2_subdev_get_try_compose(fh, sel->pad);
+ sel->r = *v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
else
- sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
return 0;
}
@@ -1460,7 +1462,7 @@ static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1,
}
static int s5k5baf_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
static enum selection_rect rtype;
@@ -1481,9 +1483,9 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
rects = (struct v4l2_rect * []) {
&s5k5baf_cis_rect,
- v4l2_subdev_get_try_crop(fh, PAD_CIS),
- v4l2_subdev_get_try_compose(fh, PAD_CIS),
- v4l2_subdev_get_try_crop(fh, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
+ v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
@@ -1701,22 +1703,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(fh, PAD_CIS);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_CIS);
s5k5baf_try_cis_format(mf);
if (s5k5baf_is_cis_subdev(sd))
return 0;
- mf = v4l2_subdev_get_try_format(fh, PAD_OUT);
+ mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_OUT);
mf->colorspace = s5k5baf_formats[0].colorspace;
mf->code = s5k5baf_formats[0].code;
mf->width = s5k5baf_cis_rect.width;
mf->height = s5k5baf_cis_rect.height;
mf->field = V4L2_FIELD_NONE;
- *v4l2_subdev_get_try_crop(fh, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_compose(fh, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_crop(fh, PAD_OUT) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_compose(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_OUT) = s5k5baf_cis_rect;
return 0;
}
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index 91b841a..bc389d5 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -99,7 +99,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format(
}
static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k6a3_formats))
@@ -123,17 +123,17 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
}
static struct v4l2_mbus_framefmt *__s5k6a3_get_format(
- struct s5k6a3 *sensor, struct v4l2_subdev_fh *fh,
+ struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg,
u32 pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+ return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL;
return &sensor->format;
}
static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
@@ -141,7 +141,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
s5k6a3_try_format(&fmt->format);
- mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which);
+ mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
if (mf) {
mutex_lock(&sensor->lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -152,13 +152,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
}
static int s5k6a3_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
{
struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
struct v4l2_mbus_framefmt *mf;
- mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which);
+ mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
mutex_lock(&sensor->lock);
fmt->format = *mf;
@@ -174,7 +174,7 @@ static struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
*format = s5k6a3_formats[0];
format->width = S5K6A3_DEFAULT_WIDTH;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index b1c5832..de803a1 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -996,7 +996,7 @@ static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
* V4L2 subdev pad level and video operations
*/
static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1023,7 +1023,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
}
static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k6aa_formats))
@@ -1034,7 +1034,7 @@ static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
int i = ARRAY_SIZE(s5k6aa_formats);
@@ -1056,14 +1056,14 @@ static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
}
static struct v4l2_rect *
-__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh,
+__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
return &s5k6aa->ccd_rect;
WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
- return v4l2_subdev_get_try_crop(fh, 0);
+ return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0);
}
static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
@@ -1087,7 +1087,7 @@ static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
mf->field = V4L2_FIELD_NONE;
}
-static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1096,7 +1096,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
memset(fmt->reserved, 0, sizeof(fmt->reserved));
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
fmt->format = *mf;
return 0;
}
@@ -1108,7 +1108,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1121,8 +1121,8 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
s5k6aa_try_format(s5k6aa, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
- crop = v4l2_subdev_get_try_crop(fh, 0);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ crop = v4l2_subdev_get_try_crop(sd, cfg, 0);
} else {
if (s5k6aa->streaming) {
ret = -EBUSY;
@@ -1162,7 +1162,7 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
static int s5k6aa_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1174,7 +1174,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
memset(sel->reserved, 0, sizeof(sel->reserved));
mutex_lock(&s5k6aa->lock);
- rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
+ rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
sel->r = *rect;
mutex_unlock(&s5k6aa->lock);
@@ -1185,7 +1185,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
}
static int s5k6aa_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1197,13 +1197,13 @@ static int s5k6aa_set_selection(struct v4l2_subdev *sd,
return -EINVAL;
mutex_lock(&s5k6aa->lock);
- crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
+ crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mf = &s5k6aa->preset->mbus_fmt;
s5k6aa->apply_crop = 1;
} else {
- mf = v4l2_subdev_get_try_format(fh, 0);
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
}
v4l_bound_align_image(&sel->r.width, mf->width,
S5K6AA_WIN_WIDTH_MAX, 1,
@@ -1424,8 +1424,8 @@ static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
*/
static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
format->colorspace = s5k6aa_formats[0].colorspace;
format->code = s5k6aa_formats[0].code;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index d47eff5..557f25d 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -344,7 +344,7 @@ static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
{ MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
};
-const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \
- (unsigned long)smiapp_csi_data_formats) \
@@ -1557,7 +1557,7 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
}
static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct i2c_client *client = v4l2_get_subdevdata(subdev);
@@ -1611,13 +1611,13 @@ static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
}
static int __smiapp_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
} else {
struct v4l2_rect *r;
@@ -1636,21 +1636,21 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev,
}
static int smiapp_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
int rval;
mutex_lock(&sensor->mutex);
- rval = __smiapp_get_format(subdev, fh, fmt);
+ rval = __smiapp_get_format(subdev, cfg, fmt);
mutex_unlock(&sensor->mutex);
return rval;
}
static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_rect **crops,
struct v4l2_rect **comps, int which)
{
@@ -1666,12 +1666,12 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
} else {
if (crops) {
for (i = 0; i < subdev->entity.num_pads; i++) {
- crops[i] = v4l2_subdev_get_try_crop(fh, i);
+ crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i);
BUG_ON(!crops[i]);
}
}
if (comps) {
- *comps = v4l2_subdev_get_try_compose(fh,
+ *comps = v4l2_subdev_get_try_compose(subdev, cfg,
SMIAPP_PAD_SINK);
BUG_ON(!*comps);
}
@@ -1680,14 +1680,14 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
/* Changes require propagation only on sink pad. */
static void smiapp_propagate(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh, int which,
+ struct v4l2_subdev_pad_config *cfg, int which,
int target)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
struct v4l2_rect *comp, *crops[SMIAPP_PADS];
- smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
+ smiapp_get_crop_compose(subdev, cfg, crops, &comp, which);
switch (target) {
case V4L2_SEL_TGT_CROP:
@@ -1730,7 +1730,7 @@ static const struct smiapp_csi_data_format
}
static int smiapp_set_format_source(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -1741,7 +1741,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev,
unsigned int i;
int rval;
- rval = __smiapp_get_format(subdev, fh, fmt);
+ rval = __smiapp_get_format(subdev, cfg, fmt);
if (rval)
return rval;
@@ -1783,7 +1783,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev,
}
static int smiapp_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -1795,7 +1795,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
if (fmt->pad == ssd->source_pad) {
int rval;
- rval = smiapp_set_format_source(subdev, fh, fmt);
+ rval = smiapp_set_format_source(subdev, cfg, fmt);
mutex_unlock(&sensor->mutex);
@@ -1817,7 +1817,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
- smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
+ smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which);
crops[ssd->sink_pad]->left = 0;
crops[ssd->sink_pad]->top = 0;
@@ -1825,7 +1825,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
crops[ssd->sink_pad]->height = fmt->format.height;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
ssd->sink_fmt = *crops[ssd->sink_pad];
- smiapp_propagate(subdev, fh, fmt->which,
+ smiapp_propagate(subdev, cfg, fmt->which,
V4L2_SEL_TGT_CROP);
mutex_unlock(&sensor->mutex);
@@ -1878,7 +1878,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
}
static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel,
struct v4l2_rect **crops,
struct v4l2_rect *comp)
@@ -1926,7 +1926,7 @@ static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
* result.
*/
static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel,
struct v4l2_rect **crops,
struct v4l2_rect *comp)
@@ -2042,25 +2042,25 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
}
/* We're only called on source pads. This function sets scaling. */
static int smiapp_set_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
struct v4l2_rect *comp, *crops[SMIAPP_PADS];
- smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+ smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
sel->r.top = 0;
sel->r.left = 0;
if (ssd == sensor->binner)
- smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
+ smiapp_set_compose_binner(subdev, cfg, sel, crops, comp);
else
- smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
+ smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp);
*comp = sel->r;
- smiapp_propagate(subdev, fh, sel->which,
+ smiapp_propagate(subdev, cfg, sel->which,
V4L2_SEL_TGT_COMPOSE);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -2113,7 +2113,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
}
static int smiapp_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -2121,7 +2121,7 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
struct v4l2_rect _r;
- smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
+ smiapp_get_crop_compose(subdev, cfg, crops, NULL, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
if (sel->pad == ssd->sink_pad)
@@ -2132,15 +2132,15 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
if (sel->pad == ssd->sink_pad) {
_r.left = 0;
_r.top = 0;
- _r.width = v4l2_subdev_get_try_format(fh, sel->pad)
+ _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad)
->width;
- _r.height = v4l2_subdev_get_try_format(fh, sel->pad)
+ _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad)
->height;
src_size = &_r;
} else {
src_size =
v4l2_subdev_get_try_compose(
- fh, ssd->sink_pad);
+ subdev, cfg, ssd->sink_pad);
}
}
@@ -2158,14 +2158,14 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
*crops[sel->pad] = sel->r;
if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
- smiapp_propagate(subdev, fh, sel->which,
+ smiapp_propagate(subdev, cfg, sel->which,
V4L2_SEL_TGT_CROP);
return 0;
}
static int __smiapp_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -2178,13 +2178,13 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
if (ret)
return ret;
- smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+ smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
sink_fmt = ssd->sink_fmt;
} else {
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(fh, ssd->sink_pad);
+ v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad);
sink_fmt.left = 0;
sink_fmt.top = 0;
@@ -2220,20 +2220,20 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
}
static int smiapp_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
int rval;
mutex_lock(&sensor->mutex);
- rval = __smiapp_get_selection(subdev, fh, sel);
+ rval = __smiapp_get_selection(subdev, cfg, sel);
mutex_unlock(&sensor->mutex);
return rval;
}
static int smiapp_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -2259,10 +2259,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- ret = smiapp_set_crop(subdev, fh, sel);
+ ret = smiapp_set_crop(subdev, cfg, sel);
break;
case V4L2_SEL_TGT_COMPOSE:
- ret = smiapp_set_compose(subdev, fh, sel);
+ ret = smiapp_set_compose(subdev, cfg, sel);
break;
default:
ret = -EINVAL;
@@ -2841,8 +2841,8 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
for (i = 0; i < ssd->npads; i++) {
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(fh, i);
- struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
+ v4l2_subdev_get_try_format(sd, fh->pad, i);
+ struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i);
struct v4l2_rect *try_comp;
try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2858,7 +2858,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
if (ssd != sensor->pixel_array)
continue;
- try_comp = v4l2_subdev_get_try_compose(fh, i);
+ try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i);
*try_comp = *try_crop;
}
@@ -2977,12 +2977,7 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
struct smiapp_platform_data *pdata;
struct v4l2_of_endpoint bus_cfg;
struct device_node *ep;
- struct property *prop;
- __be32 *val;
uint32_t asize;
-#ifdef CONFIG_OF
- unsigned int i;
-#endif
int rval;
if (!dev->of_node)
@@ -2993,10 +2988,8 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- rval = -ENOMEM;
+ if (!pdata)
goto out_err;
- }
v4l2_of_parse_endpoint(ep, &bus_cfg);
@@ -3006,7 +2999,6 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
break;
/* FIXME: add CCP2 support. */
default:
- rval = -EINVAL;
goto out_err;
}
@@ -3030,8 +3022,7 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown,
pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode);
- rval = of_get_property(
- dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT;
+ rval = of_get_property(ep, "link-frequencies", &asize) ? 0 : -ENOENT;
if (rval) {
dev_warn(dev, "can't get link-frequencies array size\n");
goto out_err;
@@ -3044,25 +3035,12 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
}
asize /= sizeof(*pdata->op_sys_clock);
- /*
- * Read a 64-bit array --- this will be replaced with a
- * of_property_read_u64_array() once it's merged.
- */
- prop = of_find_property(dev->of_node, "link-frequencies", NULL);
- if (!prop)
- goto out_err;
- if (!prop->value)
- goto out_err;
- if (asize * sizeof(*pdata->op_sys_clock) > prop->length)
- goto out_err;
- val = prop->value;
- if (IS_ERR(val))
+ rval = of_property_read_u64_array(
+ ep, "link-frequencies", pdata->op_sys_clock, asize);
+ if (rval) {
+ dev_warn(dev, "can't get link-frequencies\n");
goto out_err;
-
-#ifdef CONFIG_OF
- for (i = 0; i < asize; i++)
- pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2);
-#endif
+ }
for (; asize > 0; asize--)
dev_dbg(dev, "freq %d: %lld\n", asize - 1,
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index 5992ea9..441e0fd 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -1016,7 +1016,6 @@ static int mt9m111_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(&mt9m111->subdev);
v4l2_clk_put(mt9m111->clk);
- v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index 1fdce2f..e3c907a 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -18,6 +18,9 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_gpio.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
@@ -283,6 +286,10 @@ struct ov2640_priv {
u32 cfmt_code;
struct v4l2_clk *clk;
const struct ov2640_win_size *win;
+
+ struct soc_camera_subdev_desc ssdd_dt;
+ struct gpio_desc *resetb_gpio;
+ struct gpio_desc *pwdn_gpio;
};
/*
@@ -1038,6 +1045,63 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = {
.video = &ov2640_subdev_video_ops,
};
+/* OF probe functions */
+static int ov2640_hw_power(struct device *dev, int on)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ dev_dbg(&client->dev, "%s: %s the camera\n",
+ __func__, on ? "ENABLE" : "DISABLE");
+
+ if (priv->pwdn_gpio)
+ gpiod_direction_output(priv->pwdn_gpio, !on);
+
+ return 0;
+}
+
+static int ov2640_hw_reset(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ if (priv->resetb_gpio) {
+ /* Active the resetb pin to perform a reset pulse */
+ gpiod_direction_output(priv->resetb_gpio, 1);
+ usleep_range(3000, 5000);
+ gpiod_direction_output(priv->resetb_gpio, 0);
+ }
+
+ return 0;
+}
+
+static int ov2640_probe_dt(struct i2c_client *client,
+ struct ov2640_priv *priv)
+{
+ /* Request the reset GPIO deasserted */
+ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb",
+ GPIOD_OUT_LOW);
+ if (!priv->resetb_gpio)
+ dev_dbg(&client->dev, "resetb gpio is not assigned!\n");
+ else if (IS_ERR(priv->resetb_gpio))
+ return PTR_ERR(priv->resetb_gpio);
+
+ /* Request the power down GPIO asserted */
+ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn",
+ GPIOD_OUT_HIGH);
+ if (!priv->pwdn_gpio)
+ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n");
+ else if (IS_ERR(priv->pwdn_gpio))
+ return PTR_ERR(priv->pwdn_gpio);
+
+ /* Initialize the soc_camera_subdev_desc */
+ priv->ssdd_dt.power = ov2640_hw_power;
+ priv->ssdd_dt.reset = ov2640_hw_reset;
+ client->dev.platform_data = &priv->ssdd_dt;
+
+ return 0;
+}
+
/*
* i2c_driver functions
*/
@@ -1049,12 +1113,6 @@ static int ov2640_probe(struct i2c_client *client,
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
- if (!ssdd) {
- dev_err(&adapter->dev,
- "OV2640: Missing platform_data for driver\n");
- return -EINVAL;
- }
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
"OV2640: I2C-Adapter doesn't support SMBUS\n");
@@ -1068,6 +1126,22 @@ static int ov2640_probe(struct i2c_client *client,
return -ENOMEM;
}
+ priv->clk = v4l2_clk_get(&client->dev, "xvclk");
+ if (IS_ERR(priv->clk))
+ return -EPROBE_DEFER;
+
+ if (!ssdd && !client->dev.of_node) {
+ dev_err(&client->dev, "Missing platform_data for driver\n");
+ ret = -EINVAL;
+ goto err_clk;
+ }
+
+ if (!ssdd) {
+ ret = ov2640_probe_dt(client, priv);
+ if (ret)
+ goto err_clk;
+ }
+
v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
v4l2_ctrl_handler_init(&priv->hdl, 2);
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
@@ -1075,24 +1149,27 @@ static int ov2640_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error)
- return priv->hdl.error;
-
- priv->clk = v4l2_clk_get(&client->dev, "mclk");
- if (IS_ERR(priv->clk)) {
- ret = PTR_ERR(priv->clk);
- goto eclkget;
+ if (priv->hdl.error) {
+ ret = priv->hdl.error;
+ goto err_clk;
}
ret = ov2640_video_probe(client);
- if (ret) {
- v4l2_clk_put(priv->clk);
-eclkget:
- v4l2_ctrl_handler_free(&priv->hdl);
- } else {
- dev_info(&adapter->dev, "OV2640 Probed\n");
- }
+ if (ret < 0)
+ goto err_videoprobe;
+
+ ret = v4l2_async_register_subdev(&priv->subdev);
+ if (ret < 0)
+ goto err_videoprobe;
+
+ dev_info(&adapter->dev, "OV2640 Probed\n");
+ return 0;
+
+err_videoprobe:
+ v4l2_ctrl_handler_free(&priv->hdl);
+err_clk:
+ v4l2_clk_put(priv->clk);
return ret;
}
@@ -1100,6 +1177,7 @@ static int ov2640_remove(struct i2c_client *client)
{
struct ov2640_priv *priv = to_ov2640(client);
+ v4l2_async_unregister_subdev(&priv->subdev);
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
@@ -1112,9 +1190,16 @@ static const struct i2c_device_id ov2640_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ov2640_id);
+static const struct of_device_id ov2640_of_match[] = {
+ {.compatible = "ovti,ov2640", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ov2640_of_match);
+
static struct i2c_driver ov2640_i2c_driver = {
.driver = {
.name = "ov2640",
+ .of_match_table = of_match_ptr(ov2640_of_match),
},
.probe = ov2640_probe,
.remove = ov2640_remove,
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index ed9ae88..9f7fdb6 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -52,10 +52,6 @@ MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
MODULE_AUTHOR("Chaithrika U S");
MODULE_LICENSE("GPL");
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level 0-1");
-
static inline struct ths7303_state *to_state(struct v4l2_subdev *sd)
{
return container_of(sd, struct ths7303_state, sd);
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
index 4ebd329..73fc42b 100644
--- a/drivers/media/i2c/ths8200.c
+++ b/drivers/media/i2c/ths8200.c
@@ -479,7 +479,6 @@ static int ths8200_remove(struct i2c_client *client)
ths8200_s_power(sd, false);
v4l2_async_unregister_subdev(&decoder->sd);
- v4l2_device_unregister_subdev(sd);
return 0;
}
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 2042042..1c6bc30 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -923,13 +923,13 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
/**
* tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle
+ * @cfg: pad configuration
* @code: pointer to v4l2_subdev_mbus_code_enum structure
*
* Enumertaes mbus codes supported
*/
static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
u32 pad = code->pad;
@@ -950,13 +950,13 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
/**
* tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle
+ * @cfg: pad configuration
* @format: pointer to v4l2_subdev_format structure
*
* Retrieves pad format which is active or tried based on requirement
*/
static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
@@ -979,13 +979,13 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
/**
* tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle
+ * @cfg: pad configuration
* @format: pointer to v4l2_subdev_format structure
*
* Set pad format for the output pad
*/
static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
@@ -1209,7 +1209,6 @@ static int tvp514x_remove(struct i2c_client *client)
struct tvp514x_decoder *decoder = to_decoder(sd);
v4l2_async_unregister_subdev(&decoder->sd);
- v4l2_device_unregister_subdev(sd);
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&decoder->sd.entity);
#endif
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index fe4870e..787cdfb 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -846,13 +846,13 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
/*
* tvp7002_enum_mbus_code() - Enum supported digital video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle for the subdev
+ * @cfg: pad configuration
* @code: pointer to subdev enum mbus code struct
*
* Enumerate supported digital video formats for pad.
*/
static int
-tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Check requested format index is within range */
@@ -867,13 +867,13 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* tvp7002_get_pad_format() - get video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle for the subdev
+ * @cfg: pad configuration
* @fmt: pointer to subdev format struct
*
* get video format for pad.
*/
static int
-tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct tvp7002 *tvp7002 = to_tvp7002(sd);
@@ -890,16 +890,16 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* tvp7002_set_pad_format() - set video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @fh: file handle for the subdev
+ * @cfg: pad configuration
* @fmt: pointer to subdev format struct
*
* set video format for pad.
*/
static int
-tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
- return tvp7002_get_pad_format(sd, fh, fmt);
+ return tvp7002_get_pad_format(sd, cfg, fmt);
}
/* V4L2 core operation handlers */
@@ -1116,7 +1116,6 @@ static int tvp7002_remove(struct i2c_client *c)
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&device->sd.entity);
#endif
- v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&device->hdl);
return 0;
}
diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c
index 912c281..fee2d71 100644
--- a/drivers/media/mmc/siano/smssdio.c
+++ b/drivers/media/mmc/siano/smssdio.c
@@ -32,6 +32,8 @@
* Fix stop command
*/
+#include "smscoreapi.h"
+
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/firmware.h>
@@ -41,7 +43,6 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
-#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsendian.h"
@@ -141,14 +142,14 @@ static void smssdio_interrupt(struct sdio_func *func)
*/
(void)sdio_readb(func, SMSSDIO_INT, &ret);
if (ret) {
- sms_err("Unable to read interrupt register!\n");
+ pr_err("Unable to read interrupt register!\n");
return;
}
if (smsdev->split_cb == NULL) {
cb = smscore_getbuffer(smsdev->coredev);
if (!cb) {
- sms_err("Unable to allocate data buffer!\n");
+ pr_err("Unable to allocate data buffer!\n");
return;
}
@@ -157,7 +158,7 @@ static void smssdio_interrupt(struct sdio_func *func)
SMSSDIO_DATA,
SMSSDIO_BLOCK_SIZE);
if (ret) {
- sms_err("Error %d reading initial block!\n", ret);
+ pr_err("Error %d reading initial block!\n", ret);
return;
}
@@ -198,7 +199,7 @@ static void smssdio_interrupt(struct sdio_func *func)
size);
if (ret && ret != -EINVAL) {
smscore_putbuffer(smsdev->coredev, cb);
- sms_err("Error %d reading data from card!\n", ret);
+ pr_err("Error %d reading data from card!\n", ret);
return;
}
@@ -216,8 +217,8 @@ static void smssdio_interrupt(struct sdio_func *func)
smsdev->func->cur_blksize);
if (ret) {
smscore_putbuffer(smsdev->coredev, cb);
- sms_err("Error %d reading "
- "data from card!\n", ret);
+ pr_err("Error %d reading data from card!\n",
+ ret);
return;
}
@@ -278,7 +279,7 @@ static int smssdio_probe(struct sdio_func *func,
goto free;
}
- ret = smscore_register_device(&params, &smsdev->coredev);
+ ret = smscore_register_device(&params, &smsdev->coredev, NULL);
if (ret < 0)
goto free;
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 4ec2a3c..bc12060 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -2474,7 +2474,7 @@ static int bttv_querycap(struct file *file, void *priv,
return -EINVAL;
strlcpy(cap->driver, "bttv", sizeof(cap->driver));
- strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
+ strlcpy(cap->card, btv->video_dev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(btv->c.pci));
cap->capabilities =
@@ -2484,9 +2484,9 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_DEVICE_CAPS;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
- if (btv->vbi_dev)
+ if (video_is_registered(&btv->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
- if (btv->radio_dev)
+ if (video_is_registered(&btv->radio_dev))
cap->capabilities |= V4L2_CAP_RADIO;
/*
@@ -3905,18 +3905,14 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
/* ----------------------------------------------------------------------- */
/* initialization */
-static struct video_device *vdev_init(struct bttv *btv,
- const struct video_device *template,
- const char *type_name)
+static void vdev_init(struct bttv *btv,
+ struct video_device *vfd,
+ const struct video_device *template,
+ const char *type_name)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
*vfd = *template;
vfd->v4l2_dev = &btv->c.v4l2_dev;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
video_set_drvdata(vfd, btv);
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
@@ -3927,32 +3923,13 @@ static struct video_device *vdev_init(struct bttv *btv,
v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
}
- return vfd;
}
static void bttv_unregister_video(struct bttv *btv)
{
- if (btv->video_dev) {
- if (video_is_registered(btv->video_dev))
- video_unregister_device(btv->video_dev);
- else
- video_device_release(btv->video_dev);
- btv->video_dev = NULL;
- }
- if (btv->vbi_dev) {
- if (video_is_registered(btv->vbi_dev))
- video_unregister_device(btv->vbi_dev);
- else
- video_device_release(btv->vbi_dev);
- btv->vbi_dev = NULL;
- }
- if (btv->radio_dev) {
- if (video_is_registered(btv->radio_dev))
- video_unregister_device(btv->radio_dev);
- else
- video_device_release(btv->radio_dev);
- btv->radio_dev = NULL;
- }
+ video_unregister_device(&btv->video_dev);
+ video_unregister_device(&btv->vbi_dev);
+ video_unregister_device(&btv->radio_dev);
}
/* register video4linux devices */
@@ -3962,44 +3939,38 @@ static int bttv_register_video(struct bttv *btv)
pr_notice("Overlay support disabled\n");
/* video */
- btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video");
- if (NULL == btv->video_dev)
- goto err;
- if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
+ if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER,
video_nr[btv->c.nr]) < 0)
goto err;
pr_info("%d: registered device %s\n",
- btv->c.nr, video_device_node_name(btv->video_dev));
- if (device_create_file(&btv->video_dev->dev,
+ btv->c.nr, video_device_node_name(&btv->video_dev));
+ if (device_create_file(&btv->video_dev.dev,
&dev_attr_card)<0) {
pr_err("%d: device_create_file 'card' failed\n", btv->c.nr);
goto err;
}
/* vbi */
- btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi");
+ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi");
- if (NULL == btv->vbi_dev)
- goto err;
- if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
+ if (video_register_device(&btv->vbi_dev, VFL_TYPE_VBI,
vbi_nr[btv->c.nr]) < 0)
goto err;
pr_info("%d: registered device %s\n",
- btv->c.nr, video_device_node_name(btv->vbi_dev));
+ btv->c.nr, video_device_node_name(&btv->vbi_dev));
if (!btv->has_radio)
return 0;
/* radio */
- btv->radio_dev = vdev_init(btv, &radio_template, "radio");
- if (NULL == btv->radio_dev)
- goto err;
- btv->radio_dev->ctrl_handler = &btv->radio_ctrl_handler;
- if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
+ vdev_init(btv, &btv->radio_dev, &radio_template, "radio");
+ btv->radio_dev.ctrl_handler = &btv->radio_ctrl_handler;
+ if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO,
radio_nr[btv->c.nr]) < 0)
goto err;
pr_info("%d: registered device %s\n",
- btv->c.nr, video_device_node_name(btv->radio_dev));
+ btv->c.nr, video_device_node_name(&btv->radio_dev));
/* all done */
return 0;
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index bc048c5..a444cfb 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -404,9 +404,9 @@ struct bttv {
struct v4l2_subdev *sd_tda7432;
/* video4linux (1) */
- struct video_device *video_dev;
- struct video_device *radio_dev;
- struct video_device *vbi_dev;
+ struct video_device video_dev;
+ struct video_device radio_dev;
+ struct video_device vbi_dev;
/* controls */
struct v4l2_ctrl_handler ctrl_handler;
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index ea272bc..0b0e801 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -216,7 +216,7 @@ static int cx18_alsa_load(struct cx18 *cx)
}
s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
- if (s->video_dev == NULL) {
+ if (s->video_dev.v4l2_dev == NULL) {
CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - "
"skipping\n", __func__);
return 0;
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
index 207d6e82..b15beed 100644
--- a/drivers/media/pci/cx18/cx18-driver.h
+++ b/drivers/media/pci/cx18/cx18-driver.h
@@ -373,7 +373,7 @@ struct cx18_in_work_order {
struct cx18_stream {
/* These first five fields are always set, even if the stream
is not actually created. */
- struct video_device *video_dev; /* NULL when stream not created */
+ struct video_device video_dev; /* v4l2_dev is NULL when stream not created */
struct cx18_dvb *dvb; /* DVB / Digital Transport */
struct cx18 *cx; /* for ease of use */
const char *name; /* name of the stream */
@@ -409,6 +409,7 @@ struct cx18_stream {
/* Videobuf for YUV video */
u32 pixelformat;
u32 vb_bytes_per_frame;
+ u32 vb_bytes_per_line;
struct list_head vb_capture; /* video capture queue */
spinlock_t vb_lock;
struct timer_list vb_timeout;
diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c
index 76a3b4a..df83740 100644
--- a/drivers/media/pci/cx18/cx18-fileops.c
+++ b/drivers/media/pci/cx18/cx18-fileops.c
@@ -34,6 +34,7 @@
#include "cx18-controls.h"
#include "cx18-ioctl.h"
#include "cx18-cards.h"
+#include <media/v4l2-event.h>
/* This function tries to claim the stream for a specific file descriptor.
If no one else is using this stream then the stream is claimed and
@@ -609,13 +610,16 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct cx18_open_id *id = file2id(filp);
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ unsigned res = 0;
/* Start a capture if there is none */
- if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
int rc;
mutex_lock(&cx->serialize_lock);
@@ -632,21 +636,26 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
+
+ if (v4l2_event_pending(&id->fh))
+ res |= POLLPRI;
if (eof && videobuf_poll == POLLERR)
- return POLLHUP;
- else
- return videobuf_poll;
+ return res | POLLHUP;
+ return res | videobuf_poll;
}
/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n");
- poll_wait(filp, &s->waitq, wait);
+ if (v4l2_event_pending(&id->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(filp, &s->waitq, wait);
if (atomic_read(&s->q_full.depth))
- return POLLIN | POLLRDNORM;
+ return res | POLLIN | POLLRDNORM;
if (eof)
- return POLLHUP;
- return 0;
+ return res | POLLHUP;
+ return res;
}
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
@@ -797,7 +806,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
CX18_DEBUG_WARN("nomem on v4l2 open\n");
return -ENOMEM;
}
- v4l2_fh_init(&item->fh, s->video_dev);
+ v4l2_fh_init(&item->fh, &s->video_dev);
item->cx = cx;
item->type = s->type;
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index b8e4b68..79aee30 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -39,6 +39,7 @@
#include "cx18-cards.h"
#include "cx18-av-core.h"
#include <media/tveeprom.h>
+#include <media/v4l2-event.h>
u16 cx18_service2vbi(int type)
{
@@ -159,7 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
pixfmt->pixelformat = s->pixelformat;
pixfmt->sizeimage = s->vb_bytes_per_frame;
- pixfmt->bytesperline = 720;
+ pixfmt->bytesperline = s->vb_bytes_per_line;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
pixfmt->sizeimage = 128 * 1024;
@@ -287,10 +288,13 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
s->pixelformat = fmt->fmt.pix.pixelformat;
/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
- if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ if (s->pixelformat == V4L2_PIX_FMT_HM12) {
s->vb_bytes_per_frame = h * 720 * 3 / 2;
- else
+ s->vb_bytes_per_line = 720; /* First plane */
+ } else {
s->vb_bytes_per_frame = h * 720 * 2;
+ s->vb_bytes_per_line = 1440; /* Packed */
+ }
mbus_fmt.width = cx->cxhdl.width = w;
mbus_fmt.height = cx->cxhdl.height = h;
@@ -447,34 +451,29 @@ static int cx18_cropcap(struct file *file, void *fh,
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = cx->is_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
- cropcap->defrect = cropcap->bounds;
return 0;
}
-static int cx18_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
-{
- struct cx18_open_id *id = fh2id(fh);
- struct cx18 *cx = id->cx;
-
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
- return -EINVAL;
-}
-
-static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+static int cx18_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
{
struct cx18 *cx = fh2id(fh)->cx;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
- return -EINVAL;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = sel->r.left = 0;
+ sel->r.width = 720;
+ sel->r.height = cx->is_50hz ? 576 : 480;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
@@ -510,6 +509,9 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
+ v4l2_std_id std = V4L2_STD_ALL;
+ const struct cx18_card_video_input *card_input =
+ cx->card->video_inputs + inp;
if (inp >= cx->nof_inputs)
return -EINVAL;
@@ -525,6 +527,11 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
cx->active_input = inp;
/* Set the audio input to whatever is appropriate for the input type. */
cx->audio_input = cx->card->video_inputs[inp].audio_index;
+ if (card_input->video_type == V4L2_INPUT_TYPE_TUNER)
+ std = cx->tuner_std;
+ cx->streams[CX18_ENC_STREAM_TYPE_MPG].video_dev.tvnorms = std;
+ cx->streams[CX18_ENC_STREAM_TYPE_YUV].video_dev.tvnorms = std;
+ cx->streams[CX18_ENC_STREAM_TYPE_VBI].video_dev.tvnorms = std;
/* prevent others from messing with the streams until
we're finished changing inputs. */
@@ -1036,7 +1043,7 @@ static int cx18_log_status(struct file *file, void *fh)
for (i = 0; i < CX18_MAX_STREAMS; i++) {
struct cx18_stream *s = &cx->streams[i];
- if (s->video_dev == NULL || s->buffers == 0)
+ if (s->video_dev.v4l2_dev == NULL || s->buffers == 0)
continue;
CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
s->name, s->s_flags,
@@ -1078,8 +1085,7 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_enumaudio = cx18_enumaudio,
.vidioc_enum_input = cx18_enum_input,
.vidioc_cropcap = cx18_cropcap,
- .vidioc_s_crop = cx18_s_crop,
- .vidioc_g_crop = cx18_g_crop,
+ .vidioc_g_selection = cx18_g_selection,
.vidioc_g_input = cx18_g_input,
.vidioc_s_input = cx18_s_input,
.vidioc_g_frequency = cx18_g_frequency,
@@ -1114,6 +1120,8 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_querybuf = cx18_querybuf,
.vidioc_qbuf = cx18_qbuf,
.vidioc_dqbuf = cx18_dqbuf,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
void cx18_set_funcs(struct video_device *vdev)
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 369445f..c82d25d 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -254,11 +254,8 @@ static struct videobuf_queue_ops cx18_videobuf_qops = {
static void cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
- struct video_device *video_dev = s->video_dev;
- /* we need to keep video_dev, so restore it afterwards */
memset(s, 0, sizeof(*s));
- s->video_dev = video_dev;
/* initialize cx18_stream fields */
s->dvb = NULL;
@@ -307,6 +304,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
/* Assume the previous pixel default */
s->pixelformat = V4L2_PIX_FMT_HM12;
s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
+ s->vb_bytes_per_line = 720;
}
}
@@ -319,12 +317,12 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
/*
* These five fields are always initialized.
- * For analog capture related streams, if video_dev == NULL then the
+ * For analog capture related streams, if video_dev.v4l2_dev == NULL then the
* stream is not in use.
* For the TS stream, if dvb == NULL then the stream is not in use.
* In those cases no other fields but these four can be used.
*/
- s->video_dev = NULL;
+ s->video_dev.v4l2_dev = NULL;
s->dvb = NULL;
s->cx = cx;
s->type = type;
@@ -367,24 +365,20 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
if (num_offset == -1)
return 0;
- /* allocate and initialize the v4l2 video device structure */
- s->video_dev = video_device_alloc();
- if (s->video_dev == NULL) {
- CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
- s->name);
- return -ENOMEM;
- }
-
- snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s",
+ /* initialize the v4l2 video device structure */
+ snprintf(s->video_dev.name, sizeof(s->video_dev.name), "%s %s",
cx->v4l2_dev.name, s->name);
- s->video_dev->num = num;
- s->video_dev->v4l2_dev = &cx->v4l2_dev;
- s->video_dev->fops = &cx18_v4l2_enc_fops;
- s->video_dev->release = video_device_release;
- s->video_dev->tvnorms = V4L2_STD_ALL;
- s->video_dev->lock = &cx->serialize_lock;
- cx18_set_funcs(s->video_dev);
+ s->video_dev.num = num;
+ s->video_dev.v4l2_dev = &cx->v4l2_dev;
+ s->video_dev.fops = &cx18_v4l2_enc_fops;
+ s->video_dev.release = video_device_release_empty;
+ if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER)
+ s->video_dev.tvnorms = cx->tuner_std;
+ else
+ s->video_dev.tvnorms = V4L2_STD_ALL;
+ s->video_dev.lock = &cx->serialize_lock;
+ cx18_set_funcs(&s->video_dev);
return 0;
}
@@ -428,31 +422,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
}
}
- if (s->video_dev == NULL)
+ if (s->video_dev.v4l2_dev == NULL)
return 0;
- num = s->video_dev->num;
+ num = s->video_dev.num;
/* card number + user defined offset + device offset */
if (type != CX18_ENC_STREAM_TYPE_MPG) {
struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
- if (s_mpg->video_dev)
- num = s_mpg->video_dev->num
+ if (s_mpg->video_dev.v4l2_dev)
+ num = s_mpg->video_dev.num
+ cx18_stream_info[type].num_offset;
}
- video_set_drvdata(s->video_dev, s);
+ video_set_drvdata(&s->video_dev, s);
/* Register device. First try the desired minor, then any free one. */
- ret = video_register_device_no_warn(s->video_dev, vfl_type, num);
+ ret = video_register_device_no_warn(&s->video_dev, vfl_type, num);
if (ret < 0) {
CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
s->name, num);
- video_device_release(s->video_dev);
- s->video_dev = NULL;
+ s->video_dev.v4l2_dev = NULL;
return ret;
}
- name = video_device_node_name(s->video_dev);
+ name = video_device_node_name(&s->video_dev);
switch (vfl_type) {
case VFL_TYPE_GRABBER:
@@ -542,10 +535,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
}
/* If struct video_device exists, can have buffers allocated */
- vdev = cx->streams[type].video_dev;
+ vdev = &cx->streams[type].video_dev;
- cx->streams[type].video_dev = NULL;
- if (vdev == NULL)
+ if (vdev->v4l2_dev == NULL)
continue;
if (type == CX18_ENC_STREAM_TYPE_YUV)
@@ -553,11 +545,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
cx18_stream_free(&cx->streams[type]);
- /* Unregister or release device */
- if (unregister)
- video_unregister_device(vdev);
- else
- video_device_release(vdev);
+ video_unregister_device(vdev);
}
}
@@ -1042,7 +1030,7 @@ u32 cx18_find_handle(struct cx18 *cx)
for (i = 0; i < CX18_MAX_STREAMS; i++) {
struct cx18_stream *s = &cx->streams[i];
- if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
+ if (s->video_dev.v4l2_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
return s->handle;
}
return CX18_INVALID_TASK_HANDLE;
diff --git a/drivers/media/pci/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h
index 713b0e6..27f8af9 100644
--- a/drivers/media/pci/cx18/cx18-streams.h
+++ b/drivers/media/pci/cx18/cx18-streams.h
@@ -33,7 +33,7 @@ void cx18_stream_rotate_idx_mdls(struct cx18 *cx);
static inline bool cx18_stream_enabled(struct cx18_stream *s)
{
- return s->video_dev ||
+ return s->video_dev.v4l2_dev ||
(s->dvb && s->dvb->enabled) ||
(s->type == CX18_ENC_STREAM_TYPE_IDX &&
s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0);
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index 74d774e..2e1b88c 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -40,7 +40,6 @@ config VIDEO_CX23885
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
- select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
---help---
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 2bbbf54..0a91df2 100644
--- a/drivers/media/pci/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -483,7 +483,6 @@ static void altera_hw_filt_release(void *main_dev, int filt_nr)
}
}
-EXPORT_SYMBOL(altera_hw_filt_release);
void altera_ci_release(void *dev, int ci_nr)
{
@@ -598,7 +597,6 @@ static int altera_pid_feed_control(void *demux_dev, int filt_nr,
return 0;
}
-EXPORT_SYMBOL(altera_pid_feed_control);
static int altera_ci_start_feed(struct dvb_demux_feed *feed, int num)
{
@@ -699,7 +697,6 @@ err:
return ret;
}
-EXPORT_SYMBOL(altera_hw_filt_init);
int altera_ci_init(struct altera_ci_config *config, int ci_nr)
{
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 5028f0c..6c51172 100644
--- a/drivers/media/pci/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -39,7 +39,7 @@ struct altera_ci_config {
int (*fpga_rw) (void *dev, int ad_rg, int val, int rw);
};
-#if IS_ENABLED(CONFIG_MEDIA_ALTERA_CI)
+#if IS_REACHABLE(CONFIG_MEDIA_ALTERA_CI)
extern int altera_ci_init(struct altera_ci_config *config, int ci_nr);
extern void altera_ci_release(void *dev, int ci_nr);
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 1ad4994..7aee76a 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -825,6 +825,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
int i;
spin_lock_init(&dev->pci_irqmask_lock);
+ spin_lock_init(&dev->slock);
mutex_init(&dev->lock);
mutex_init(&dev->gpio_lock);
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 45fbe1e..745caab 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -73,7 +73,6 @@
#include "si2157.h"
#include "sp2.h"
#include "m88ds3103.h"
-#include "m88ts2022.h"
#include "m88rs6000t.h"
static unsigned int debug;
@@ -1187,7 +1186,7 @@ static int dvb_register(struct cx23885_tsport *port)
struct vb2_dvb_frontend *fe0, *fe1 = NULL;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
- struct m88ts2022_config m88ts2022_config;
+ struct ts2020_config ts2020_config;
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client_demod = NULL, *client_tuner = NULL;
@@ -1856,13 +1855,12 @@ static int dvb_register(struct cx23885_tsport *port)
break;
/* attach tuner */
- memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
- m88ts2022_config.fe = fe0->dvb.frontend;
- m88ts2022_config.clock = 27000000;
+ memset(&ts2020_config, 0, sizeof(ts2020_config));
+ ts2020_config.fe = fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
+ info.platform_data = &ts2020_config;
request_module(info.type);
client_tuner = i2c_new_device(adapter, &info);
if (client_tuner == NULL ||
@@ -1986,13 +1984,12 @@ static int dvb_register(struct cx23885_tsport *port)
break;
/* attach tuner */
- memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
- m88ts2022_config.fe = fe0->dvb.frontend;
- m88ts2022_config.clock = 27000000;
+ memset(&ts2020_config, 0, sizeof(ts2020_config));
+ ts2020_config.fe = fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
+ info.platform_data = &ts2020_config;
request_module(info.type);
client_tuner = i2c_new_device(adapter, &info);
if (client_tuner == NULL || client_tuner->dev.driver == NULL)
@@ -2032,13 +2029,12 @@ static int dvb_register(struct cx23885_tsport *port)
break;
/* attach tuner */
- memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
- m88ts2022_config.fe = fe0->dvb.frontend;
- m88ts2022_config.clock = 27000000;
+ memset(&ts2020_config, 0, sizeof(ts2020_config));
+ ts2020_config.fe = fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
+ info.platform_data = &ts2020_config;
request_module(info.type);
client_tuner = i2c_new_device(adapter, &info);
if (client_tuner == NULL || client_tuner->dev.driver == NULL)
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 5e93c68..2232b38 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -1137,7 +1137,6 @@ int cx23885_video_register(struct cx23885_dev *dev)
int err;
dprintk(1, "%s()\n", __func__);
- spin_lock_init(&dev->slock);
/* Initialize VBI template */
cx23885_vbi_template = cx23885_video_template;
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index b6be46e..24216ef 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -1102,32 +1102,26 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
static void blackbird_unregister_video(struct cx8802_dev *dev)
{
- if (dev->mpeg_dev) {
- if (video_is_registered(dev->mpeg_dev))
- video_unregister_device(dev->mpeg_dev);
- else
- video_device_release(dev->mpeg_dev);
- dev->mpeg_dev = NULL;
- }
+ video_unregister_device(&dev->mpeg_dev);
}
static int blackbird_register_video(struct cx8802_dev *dev)
{
int err;
- dev->mpeg_dev = cx88_vdev_init(dev->core, dev->pci,
- &cx8802_mpeg_template, "mpeg");
- dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl;
- video_set_drvdata(dev->mpeg_dev, dev);
- dev->mpeg_dev->queue = &dev->vb2_mpegq;
- err = video_register_device(dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
+ cx88_vdev_init(dev->core, dev->pci, &dev->mpeg_dev,
+ &cx8802_mpeg_template, "mpeg");
+ dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl;
+ video_set_drvdata(&dev->mpeg_dev, dev);
+ dev->mpeg_dev.queue = &dev->vb2_mpegq;
+ err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
if (err < 0) {
printk(KERN_INFO "%s/2: can't register mpeg device\n",
dev->core->name);
return err;
}
printk(KERN_INFO "%s/2: registered device %s [mpeg]\n",
- dev->core->name, video_device_node_name(dev->mpeg_dev));
+ dev->core->name, video_device_node_name(&dev->mpeg_dev));
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index c38d5a1..3501be9 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -985,17 +985,14 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
/* ------------------------------------------------------------------ */
-struct video_device *cx88_vdev_init(struct cx88_core *core,
- struct pci_dev *pci,
- const struct video_device *template_,
- const char *type)
+void cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ struct video_device *vfd,
+ const struct video_device *template_,
+ const char *type)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
*vfd = *template_;
+
/*
* The dev pointer of v4l2_device is NULL, instead we set the
* video_device dev_parent pointer to the correct PCI bus device.
@@ -1004,11 +1001,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
*/
vfd->v4l2_dev = &core->v4l2_dev;
vfd->dev_parent = &pci->dev;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->lock = &core->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
- return vfd;
}
struct cx88_core* cx88_core_get(struct pci_dev *pci)
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index a369b08..9834454 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -732,7 +732,7 @@ static int cx8802_probe(struct pci_dev *pci_dev,
dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
if (IS_ERR(dev->alloc_ctx)) {
err = PTR_ERR(dev->alloc_ctx);
- goto fail_core;
+ goto fail_dev;
}
dev->core = core;
@@ -754,6 +754,7 @@ static int cx8802_probe(struct pci_dev *pci_dev,
fail_free:
vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
+ fail_dev:
kfree(dev);
fail_core:
core->dvbdev = NULL;
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 860c98fc..c9decd8 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1274,27 +1274,9 @@ static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = {
static void cx8800_unregister_video(struct cx8800_dev *dev)
{
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
- if (dev->vbi_dev) {
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
- }
- if (dev->video_dev) {
- if (video_is_registered(dev->video_dev))
- video_unregister_device(dev->video_dev);
- else
- video_device_release(dev->video_dev);
- dev->video_dev = NULL;
- }
+ video_unregister_device(&dev->radio_dev);
+ video_unregister_device(&dev->vbi_dev);
+ video_unregister_device(&dev->video_dev);
}
static int cx8800_initdev(struct pci_dev *pci_dev,
@@ -1485,12 +1467,12 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
/* register v4l devices */
- dev->video_dev = cx88_vdev_init(core,dev->pci,
- &cx8800_video_template,"video");
- video_set_drvdata(dev->video_dev, dev);
- dev->video_dev->ctrl_handler = &core->video_hdl;
- dev->video_dev->queue = &dev->vb2_vidq;
- err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
+ cx88_vdev_init(core, dev->pci, &dev->video_dev,
+ &cx8800_video_template, "video");
+ video_set_drvdata(&dev->video_dev, dev);
+ dev->video_dev.ctrl_handler = &core->video_hdl;
+ dev->video_dev.queue = &dev->vb2_vidq;
+ err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER,
video_nr[core->nr]);
if (err < 0) {
printk(KERN_ERR "%s/0: can't register video device\n",
@@ -1498,12 +1480,13 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device %s [v4l2]\n",
- core->name, video_device_node_name(dev->video_dev));
+ core->name, video_device_node_name(&dev->video_dev));
- dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
- video_set_drvdata(dev->vbi_dev, dev);
- dev->vbi_dev->queue = &dev->vb2_vbiq;
- err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+ cx88_vdev_init(core, dev->pci, &dev->vbi_dev,
+ &cx8800_vbi_template, "vbi");
+ video_set_drvdata(&dev->vbi_dev, dev);
+ dev->vbi_dev.queue = &dev->vb2_vbiq;
+ err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[core->nr]);
if (err < 0) {
printk(KERN_ERR "%s/0: can't register vbi device\n",
@@ -1511,14 +1494,14 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device %s\n",
- core->name, video_device_node_name(dev->vbi_dev));
+ core->name, video_device_node_name(&dev->vbi_dev));
if (core->board.radio.type == CX88_RADIO) {
- dev->radio_dev = cx88_vdev_init(core,dev->pci,
- &cx8800_radio_template,"radio");
- video_set_drvdata(dev->radio_dev, dev);
- dev->radio_dev->ctrl_handler = &core->audio_hdl;
- err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
+ cx88_vdev_init(core, dev->pci, &dev->radio_dev,
+ &cx8800_radio_template, "radio");
+ video_set_drvdata(&dev->radio_dev, dev);
+ dev->radio_dev.ctrl_handler = &core->audio_hdl;
+ err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[core->nr]);
if (err < 0) {
printk(KERN_ERR "%s/0: can't register radio device\n",
@@ -1526,7 +1509,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device %s\n",
- core->name, video_device_node_name(dev->radio_dev));
+ core->name, video_device_node_name(&dev->radio_dev));
}
/* start tvaudio thread */
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index 7748ca9..b9fe1ac 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -478,9 +478,9 @@ struct cx8800_dev {
/* various device info */
unsigned int resources;
- struct video_device *video_dev;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
+ struct video_device video_dev;
+ struct video_device vbi_dev;
+ struct video_device radio_dev;
/* pci i/o */
struct pci_dev *pci;
@@ -563,7 +563,7 @@ struct cx8802_dev {
/* for blackbird only */
struct list_head devlist;
#if IS_ENABLED(CONFIG_VIDEO_CX88_BLACKBIRD)
- struct video_device *mpeg_dev;
+ struct video_device mpeg_dev;
u32 mailbox;
/* mpeg params */
@@ -647,10 +647,11 @@ extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
unsigned int height, enum v4l2_field field);
extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
-extern struct video_device *cx88_vdev_init(struct cx88_core *core,
- struct pci_dev *pci,
- const struct video_device *template_,
- const char *type);
+extern void cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ struct video_device *vfd,
+ const struct video_device *template_,
+ const char *type);
extern struct cx88_core *cx88_core_get(struct pci_dev *pci);
extern void cx88_core_put(struct cx88_core *core,
struct pci_dev *pci);
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index 39b5292..41fa215 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -224,7 +224,7 @@ static int ivtv_alsa_load(struct ivtv *itv)
}
s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
- if (s->vdev == NULL) {
+ if (s->vdev.v4l2_dev == NULL) {
IVTV_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - "
"skipping\n", __func__);
return 0;
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index 7bf9cbc..f198b98 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -167,7 +167,7 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
- v4l2_fh_init(&item.fh, s->vdev);
+ v4l2_fh_init(&item.fh, &s->vdev);
item.itv = itv;
item.type = s->type;
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index 802642d..c2e60b4 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -1284,7 +1284,7 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
return 0;
free_streams:
- ivtv_streams_cleanup(itv, 1);
+ ivtv_streams_cleanup(itv);
free_irq:
free_irq(itv->pdev->irq, (void *)itv);
free_i2c:
@@ -1444,7 +1444,7 @@ static void ivtv_remove(struct pci_dev *pdev)
flush_kthread_worker(&itv->irq_worker);
kthread_stop(itv->irq_worker_task);
- ivtv_streams_cleanup(itv, 1);
+ ivtv_streams_cleanup(itv);
ivtv_udma_free(itv);
v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
index bc309f42c..e8b6c7a 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.h
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
@@ -327,7 +327,7 @@ struct ivtv; /* forward reference */
struct ivtv_stream {
/* These first four fields are always set, even if the stream
is not actually created. */
- struct video_device *vdev; /* NULL when stream not created */
+ struct video_device vdev; /* vdev.v4l2_dev is NULL if there is no device */
struct ivtv *itv; /* for ease of use */
const char *name; /* name of the stream */
int type; /* stream type */
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
index e5ff627..605d280 100644
--- a/drivers/media/pci/ivtv/ivtv-fileops.c
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -995,7 +995,7 @@ static int ivtv_open(struct file *filp)
IVTV_DEBUG_WARN("nomem on v4l2 open\n");
return -ENOMEM;
}
- v4l2_fh_init(&item->fh, s->vdev);
+ v4l2_fh_init(&item->fh, &s->vdev);
item->itv = itv;
item->type = s->type;
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 4d8ee18..6fe6c4a 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -448,9 +448,12 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv *itv = fh2id(fh)->itv;
+ struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
struct v4l2_window *winfmt = &fmt->fmt.win;
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ if (!itv->osd_video_pbase)
return -EINVAL;
winfmt->chromakey = itv->osd_chroma_key;
winfmt->global_alpha = itv->osd_global_alpha;
@@ -555,10 +558,13 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format
static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv *itv = fh2id(fh)->itv;
+ struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
u32 chromakey = fmt->fmt.win.chromakey;
u8 global_alpha = fmt->fmt.win.global_alpha;
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ if (!itv->osd_video_pbase)
return -EINVAL;
ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
fmt->fmt.win.chromakey = chromakey;
@@ -741,6 +747,11 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
vcap->device_caps = s->caps;
+ if ((s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) &&
+ !itv->osd_video_pbase) {
+ vcap->capabilities &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ vcap->device_caps &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ }
return 0;
}
@@ -816,80 +827,103 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
- struct yuv_playback_info *yi = &itv->yuv_info;
- int streamtype;
-
- streamtype = id->type;
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- cropcap->bounds.height = itv->is_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
- } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- if (yi->track_osd) {
- cropcap->bounds.width = yi->osd_full_w;
- cropcap->bounds.height = yi->osd_full_h;
- } else {
- cropcap->bounds.width = 720;
- cropcap->bounds.height =
- itv->is_out_50hz ? 576 : 480;
- }
+ } else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
} else {
- cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
- cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+ return -EINVAL;
}
- cropcap->defrect = cropcap->bounds;
return 0;
}
-static int ivtv_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
+static int ivtv_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
- int streamtype;
+ struct v4l2_rect r = { 0, 0, 720, 0 };
+ int streamtype = id->type;
- streamtype = id->type;
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
- if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- yi->main_rect = crop->c;
- return 0;
- } else {
- if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
- crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
- itv->main_rect = crop->c;
- return 0;
- }
- }
+ if (sel->target != V4L2_SEL_TGT_COMPOSE)
return -EINVAL;
+
+
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
+
+ r.height = itv->is_out_50hz ? 576 : 480;
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) {
+ r.width = yi->osd_full_w;
+ r.height = yi->osd_full_h;
+ }
+ sel->r.width = clamp(sel->r.width, 16U, r.width);
+ sel->r.height = clamp(sel->r.height, 16U, r.height);
+ sel->r.left = clamp_t(unsigned, sel->r.left, 0, r.width - sel->r.width);
+ sel->r.top = clamp_t(unsigned, sel->r.top, 0, r.height - sel->r.height);
+
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ yi->main_rect = sel->r;
+ return 0;
+ }
+ if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+ sel->r.width, sel->r.height, sel->r.left, sel->r.top)) {
+ itv->main_rect = sel->r;
+ return 0;
}
return -EINVAL;
}
-static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+static int ivtv_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
- int streamtype;
+ struct v4l2_rect r = { 0, 0, 720, 0 };
+ int streamtype = id->type;
+
+ if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = sel->r.left = 0;
+ sel->r.width = 720;
+ sel->r.height = itv->is_50hz ? 576 : 480;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ }
- streamtype = id->type;
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
- if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ switch (sel->target) {
+ case V4L2_SEL_TGT_COMPOSE:
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
- crop->c = yi->main_rect;
+ sel->r = yi->main_rect;
else
- crop->c = itv->main_rect;
+ sel->r = itv->main_rect;
+ return 0;
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ r.height = itv->is_out_50hz ? 576 : 480;
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) {
+ r.width = yi->osd_full_w;
+ r.height = yi->osd_full_h;
+ }
+ sel->r = r;
return 0;
}
return -EINVAL;
@@ -987,7 +1021,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
else
std = V4L2_STD_ALL;
for (i = 0; i <= IVTV_ENC_STREAM_TYPE_VBI; i++)
- itv->streams[i].vdev->tvnorms = std;
+ itv->streams[i].vdev.tvnorms = std;
/* prevent others from messing with the streams until
we're finished changing inputs. */
@@ -1038,7 +1072,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
struct ivtv *itv = fh2id(fh)->itv;
struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
- if (s->vdev->vfl_dir)
+ if (s->vdev.vfl_dir)
return -ENOTTY;
if (vf->tuner != 0)
return -EINVAL;
@@ -1052,7 +1086,7 @@ int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v
struct ivtv *itv = fh2id(fh)->itv;
struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
- if (s->vdev->vfl_dir)
+ if (s->vdev.vfl_dir)
return -ENOTTY;
if (vf->tuner != 0)
return -EINVAL;
@@ -1340,6 +1374,7 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder
static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
{
struct ivtv *itv = fh2id(fh)->itv;
+ struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
u32 data[CX2341X_MBOX_MAX_DATA];
struct yuv_playback_info *yi = &itv->yuv_info;
@@ -1363,10 +1398,10 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
0,
};
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
+ if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -ENOTTY;
if (!itv->osd_video_pbase)
- return -EINVAL;
+ return -ENOTTY;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_GLOBAL_ALPHA;
@@ -1427,12 +1462,13 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
struct yuv_playback_info *yi = &itv->yuv_info;
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
+ if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -ENOTTY;
if (!itv->osd_video_pbase)
- return -EINVAL;
+ return -ENOTTY;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state =
@@ -1447,9 +1483,12 @@ static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
+ if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -ENOTTY;
+ if (!itv->osd_video_pbase)
+ return -ENOTTY;
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
@@ -1547,7 +1586,7 @@ static int ivtv_log_status(struct file *file, void *fh)
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
- if (s->vdev == NULL || s->buffers == 0)
+ if (s->vdev.v4l2_dev == NULL || s->buffers == 0)
continue;
IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
@@ -1837,8 +1876,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
.vidioc_enum_output = ivtv_enum_output,
.vidioc_enumaudout = ivtv_enumaudout,
.vidioc_cropcap = ivtv_cropcap,
- .vidioc_s_crop = ivtv_s_crop,
- .vidioc_g_crop = ivtv_g_crop,
+ .vidioc_s_selection = ivtv_s_selection,
+ .vidioc_g_selection = ivtv_g_selection,
.vidioc_g_input = ivtv_g_input,
.vidioc_s_input = ivtv_s_input,
.vidioc_g_output = ivtv_g_output,
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index e7d7017..36ca2d6 100644
--- a/drivers/media/pci/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -75,7 +75,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
- s->vdev == NULL || !ivtv_use_pio(s)) {
+ s->vdev.v4l2_dev == NULL || !ivtv_use_pio(s)) {
itv->cur_pio_stream = -1;
/* trigger PIO complete user interrupt */
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
@@ -132,7 +132,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
int rc;
/* sanity checks */
- if (s->vdev == NULL) {
+ if (s->vdev.v4l2_dev == NULL) {
IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
return -1;
}
@@ -890,8 +890,8 @@ static void ivtv_irq_vsync(struct ivtv *itv)
if (s)
wake_up(&s->waitq);
}
- if (s && s->vdev)
- v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom);
+ if (s && s->vdev.v4l2_dev)
+ v4l2_event_queue(&s->vdev, frame ? &evtop : &evbottom);
wake_up(&itv->vsync_waitq);
/* Send VBI to saa7127 */
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
index f0a1cc4..d27c6df 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -130,7 +130,8 @@ static struct {
"decoder MPG",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
PCI_DMA_TODEVICE, 0,
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
&ivtv_v4l2_dec_fops
},
{ /* IVTV_DEC_STREAM_TYPE_VBI */
@@ -151,7 +152,8 @@ static struct {
"decoder YUV",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
PCI_DMA_TODEVICE, 0,
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
&ivtv_v4l2_dec_fops
}
};
@@ -159,11 +161,9 @@ static struct {
static void ivtv_stream_init(struct ivtv *itv, int type)
{
struct ivtv_stream *s = &itv->streams[type];
- struct video_device *vdev = s->vdev;
/* we need to keep vdev, so restore it afterwards */
memset(s, 0, sizeof(*s));
- s->vdev = vdev;
/* initialize ivtv_stream fields */
s->itv = itv;
@@ -194,10 +194,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
int num_offset = ivtv_stream_info[type].num_offset;
int num = itv->instance + ivtv_first_minor + num_offset;
- /* These four fields are always initialized. If vdev == NULL, then
+ /* These four fields are always initialized. If vdev.v4l2_dev == NULL, then
this stream is not in use. In that case no other fields but these
four can be used. */
- s->vdev = NULL;
+ s->vdev.v4l2_dev = NULL;
s->itv = itv;
s->type = type;
s->name = ivtv_stream_info[type].name;
@@ -218,40 +218,33 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
ivtv_stream_init(itv, type);
- /* allocate and initialize the v4l2 video device structure */
- s->vdev = video_device_alloc();
- if (s->vdev == NULL) {
- IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
- return -ENOMEM;
- }
-
- snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
+ snprintf(s->vdev.name, sizeof(s->vdev.name), "%s %s",
itv->v4l2_dev.name, s->name);
- s->vdev->num = num;
- s->vdev->v4l2_dev = &itv->v4l2_dev;
+ s->vdev.num = num;
+ s->vdev.v4l2_dev = &itv->v4l2_dev;
if (ivtv_stream_info[type].v4l2_caps &
(V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT))
- s->vdev->vfl_dir = VFL_DIR_TX;
- s->vdev->fops = ivtv_stream_info[type].fops;
- s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
- s->vdev->release = video_device_release;
- s->vdev->tvnorms = V4L2_STD_ALL;
- s->vdev->lock = &itv->serialize_lock;
+ s->vdev.vfl_dir = VFL_DIR_TX;
+ s->vdev.fops = ivtv_stream_info[type].fops;
+ s->vdev.ctrl_handler = itv->v4l2_dev.ctrl_handler;
+ s->vdev.release = video_device_release_empty;
+ s->vdev.tvnorms = V4L2_STD_ALL;
+ s->vdev.lock = &itv->serialize_lock;
if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- v4l2_disable_ioctl(s->vdev, VIDIOC_S_AUDIO);
- v4l2_disable_ioctl(s->vdev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(s->vdev, VIDIOC_ENUMAUDIO);
- v4l2_disable_ioctl(s->vdev, VIDIOC_ENUMINPUT);
- v4l2_disable_ioctl(s->vdev, VIDIOC_S_INPUT);
- v4l2_disable_ioctl(s->vdev, VIDIOC_G_INPUT);
- v4l2_disable_ioctl(s->vdev, VIDIOC_S_FREQUENCY);
- v4l2_disable_ioctl(s->vdev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(s->vdev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(s->vdev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(s->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMINPUT);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_S_INPUT);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_G_INPUT);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&s->vdev, VIDIOC_S_STD);
}
- ivtv_set_funcs(s->vdev);
+ ivtv_set_funcs(&s->vdev);
return 0;
}
@@ -266,7 +259,7 @@ int ivtv_streams_setup(struct ivtv *itv)
if (ivtv_prep_dev(itv, type))
break;
- if (itv->streams[type].vdev == NULL)
+ if (itv->streams[type].vdev.v4l2_dev == NULL)
continue;
/* Allocate Stream */
@@ -277,7 +270,7 @@ int ivtv_streams_setup(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv, 0);
+ ivtv_streams_cleanup(itv);
return -ENOMEM;
}
@@ -288,28 +281,26 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
const char *name;
int num;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return 0;
- num = s->vdev->num;
+ num = s->vdev.num;
/* card number + user defined offset + device offset */
if (type != IVTV_ENC_STREAM_TYPE_MPG) {
struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
- if (s_mpg->vdev)
- num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
+ if (s_mpg->vdev.v4l2_dev)
+ num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset;
}
- video_set_drvdata(s->vdev, s);
+ video_set_drvdata(&s->vdev, s);
/* Register device. First try the desired minor, then any free one. */
- if (video_register_device_no_warn(s->vdev, vfl_type, num)) {
+ if (video_register_device_no_warn(&s->vdev, vfl_type, num)) {
IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
s->name, num);
- video_device_release(s->vdev);
- s->vdev = NULL;
return -ENOMEM;
}
- name = video_device_node_name(s->vdev);
+ name = video_device_node_name(&s->vdev);
switch (vfl_type) {
case VFL_TYPE_GRABBER:
@@ -346,29 +337,25 @@ int ivtv_streams_register(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv, 1);
+ ivtv_streams_cleanup(itv);
return -ENOMEM;
}
/* Unregister v4l2 devices */
-void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
+void ivtv_streams_cleanup(struct ivtv *itv)
{
int type;
/* Teardown all streams */
for (type = 0; type < IVTV_MAX_STREAMS; type++) {
- struct video_device *vdev = itv->streams[type].vdev;
+ struct video_device *vdev = &itv->streams[type].vdev;
- itv->streams[type].vdev = NULL;
- if (vdev == NULL)
+ if (vdev->v4l2_dev == NULL)
continue;
+ video_unregister_device(vdev);
ivtv_stream_free(&itv->streams[type]);
- /* Unregister or release device */
- if (unregister)
- video_unregister_device(vdev);
- else
- video_device_release(vdev);
+ itv->streams[type].vdev.v4l2_dev = NULL;
}
}
@@ -492,7 +479,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
int captype = 0, subtype = 0;
int enable_passthrough = 0;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
@@ -661,7 +648,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
u16 width;
u16 height;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
@@ -723,7 +710,7 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
struct ivtv *itv = s->itv;
int rc;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return -EINVAL;
if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
@@ -778,7 +765,7 @@ void ivtv_stop_all_captures(struct ivtv *itv)
for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
struct ivtv_stream *s = &itv->streams[i];
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
continue;
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
ivtv_stop_v4l2_encode_stream(s, 0);
@@ -793,7 +780,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
int cap_type;
int stopmode;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return -EINVAL;
/* This function assumes that you are allowed to stop the capture
@@ -917,7 +904,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
};
struct ivtv *itv = s->itv;
- if (s->vdev == NULL)
+ if (s->vdev.v4l2_dev == NULL)
return -EINVAL;
if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
@@ -969,7 +956,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
wake_up(&itv->event_waitq);
- v4l2_event_queue(s->vdev, &ev);
+ v4l2_event_queue(&s->vdev, &ev);
/* wake up wait queues */
wake_up(&s->waitq);
@@ -982,7 +969,7 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
- if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
+ if (yuv_stream->vdev.v4l2_dev == NULL || dec_stream->vdev.v4l2_dev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
diff --git a/drivers/media/pci/ivtv/ivtv-streams.h b/drivers/media/pci/ivtv/ivtv-streams.h
index a653a513..3d76a41 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.h
+++ b/drivers/media/pci/ivtv/ivtv-streams.h
@@ -23,7 +23,7 @@
int ivtv_streams_setup(struct ivtv *itv);
int ivtv_streams_register(struct ivtv *itv);
-void ivtv_streams_cleanup(struct ivtv *itv, int unregister);
+void ivtv_streams_cleanup(struct ivtv *itv);
/* Capture related */
int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 9d9f90c..ba887e8 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1546,7 +1546,7 @@ static struct video_device meye_template = {
.name = "meye",
.fops = &meye_fops,
.ioctl_ops = &meye_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
};
static const struct v4l2_ctrl_ops meye_ctrl_ops = {
@@ -1623,7 +1623,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
if (meye.mchip_dev != NULL) {
printk(KERN_ERR "meye: only one device allowed!\n");
- goto outnotdev;
+ return ret;
}
ret = v4l2_device_register(&pcidev->dev, v4l2_dev);
@@ -1633,11 +1633,6 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
}
ret = -ENOMEM;
meye.mchip_dev = pcidev;
- meye.vdev = video_device_alloc();
- if (!meye.vdev) {
- v4l2_err(v4l2_dev, "video_device_alloc() failed!\n");
- goto outnotdev;
- }
meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
if (!meye.grab_temp) {
@@ -1658,8 +1653,8 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
goto outkfifoalloc2;
}
- memcpy(meye.vdev, &meye_template, sizeof(meye_template));
- meye.vdev->v4l2_dev = &meye.v4l2_dev;
+ meye.vdev = meye_template;
+ meye.vdev.v4l2_dev = &meye.v4l2_dev;
ret = -EIO;
if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
@@ -1743,9 +1738,9 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
}
v4l2_ctrl_handler_setup(&meye.hdl);
- meye.vdev->ctrl_handler = &meye.hdl;
+ meye.vdev.ctrl_handler = &meye.hdl;
- if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
+ if (video_register_device(&meye.vdev, VFL_TYPE_GRABBER,
video_nr) < 0) {
v4l2_err(v4l2_dev, "video_register_device failed\n");
goto outvideoreg;
@@ -1777,14 +1772,12 @@ outkfifoalloc2:
outkfifoalloc1:
vfree(meye.grab_temp);
outvmalloc:
- video_device_release(meye.vdev);
-outnotdev:
return ret;
}
static void meye_remove(struct pci_dev *pcidev)
{
- video_unregister_device(meye.vdev);
+ video_unregister_device(&meye.vdev);
mchip_hic_stop();
diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h
index 6fed9274..751be5e 100644
--- a/drivers/media/pci/meye/meye.h
+++ b/drivers/media/pci/meye/meye.h
@@ -311,7 +311,7 @@ struct meye {
struct kfifo doneq; /* queue for grabbed buffers */
spinlock_t doneq_lock; /* lock protecting the queue */
wait_queue_head_t proc_list; /* wait queue */
- struct video_device *vdev; /* video device parameters */
+ struct video_device vdev; /* video device parameters */
u16 brightness;
u16 hue;
u16 contrast;
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 366434f..03cbcd2 100644
--- a/drivers/media/pci/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -66,7 +66,7 @@ struct hexium
{
int type;
- struct video_device *video_dev;
+ struct video_device video_dev;
struct i2c_adapter i2c_adapter;
int cur_input; /* current input */
diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index a1eb26d..15f0d66 100644
--- a/drivers/media/pci/saa7146/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -63,7 +63,7 @@ struct hexium_data
struct hexium
{
int type;
- struct video_device *video_dev;
+ struct video_device video_dev;
struct i2c_adapter i2c_adapter;
int cur_input; /* current input */
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index c4c8fce..0ca1e07 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -151,8 +151,8 @@ static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
struct mxb
{
- struct video_device *video_dev;
- struct video_device *vbi_dev;
+ struct video_device video_dev;
+ struct video_device vbi_dev;
struct i2c_adapter i2c_adapter;
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 4b0bec3..9cf3c6c 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1436,11 +1436,11 @@ static void saa7164_finidev(struct pci_dev *pci_dev)
saa7164_i2c_unregister(&dev->i2c_bus[1]);
saa7164_i2c_unregister(&dev->i2c_bus[2]);
- pci_disable_device(pci_dev);
-
/* unregister stuff */
free_irq(pci_dev->irq, dev);
+ pci_disable_device(pci_dev);
+
mutex_lock(&devlist);
list_del(&dev->devlist);
mutex_unlock(&devlist);
diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig
index c8de53f..21a1583 100644
--- a/drivers/media/pci/smipcie/Kconfig
+++ b/drivers/media/pci/smipcie/Kconfig
@@ -4,7 +4,7 @@ config DVB_SMIPCIE
select I2C_ALGOBIT
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
- select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
help
diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c
index 36c8ed7..4115925 100644
--- a/drivers/media/pci/smipcie/smipcie.c
+++ b/drivers/media/pci/smipcie/smipcie.c
@@ -16,7 +16,7 @@
#include "smipcie.h"
#include "m88ds3103.h"
-#include "m88ts2022.h"
+#include "ts2020.h"
#include "m88rs6000t.h"
#include "si2168.h"
#include "si2157.h"
@@ -532,9 +532,7 @@ static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port)
struct i2c_adapter *tuner_i2c_adapter;
struct i2c_client *tuner_client;
struct i2c_board_info tuner_info;
- struct m88ts2022_config m88ts2022_config = {
- .clock = 27000000,
- };
+ struct ts2020_config ts2020_config = {};
memset(&tuner_info, 0, sizeof(struct i2c_board_info));
i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1];
@@ -546,10 +544,10 @@ static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port)
return ret;
}
/* attach tuner */
- m88ts2022_config.fe = port->fe;
- strlcpy(tuner_info.type, "m88ts2022", I2C_NAME_SIZE);
+ ts2020_config.fe = port->fe;
+ strlcpy(tuner_info.type, "ts2020", I2C_NAME_SIZE);
tuner_info.addr = 0x60;
- tuner_info.platform_data = &m88ts2022_config;
+ tuner_info.platform_data = &ts2020_config;
tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info);
if (!tuner_client) {
ret = -ENODEV;
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 22450f5..d384a6b 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -127,7 +127,7 @@ static inline struct vip_buffer *to_vip_buffer(struct vb2_buffer *vb2)
*/
struct sta2x11_vip {
struct v4l2_device v4l2_dev;
- struct video_device *video_dev;
+ struct video_device video_dev;
struct pci_dev *pdev;
struct i2c_adapter *adapter;
unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
@@ -763,7 +763,7 @@ static const struct v4l2_ioctl_ops vip_ioctl_ops = {
static struct video_device video_dev_template = {
.name = KBUILD_MODNAME,
- .release = video_device_release,
+ .release = video_device_release_empty,
.fops = &vip_fops,
.ioctl_ops = &vip_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
@@ -1082,19 +1082,13 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
goto release_buf;
}
- /* Alloc, initialize and register video device */
- vip->video_dev = video_device_alloc();
- if (!vip->video_dev) {
- ret = -ENOMEM;
- goto release_irq;
- }
+ /* Initialize and register video device */
+ vip->video_dev = video_dev_template;
+ vip->video_dev.v4l2_dev = &vip->v4l2_dev;
+ vip->video_dev.queue = &vip->vb_vidq;
+ video_set_drvdata(&vip->video_dev, vip);
- vip->video_dev = &video_dev_template;
- vip->video_dev->v4l2_dev = &vip->v4l2_dev;
- vip->video_dev->queue = &vip->vb_vidq;
- video_set_drvdata(vip->video_dev, vip);
-
- ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
+ ret = video_register_device(&vip->video_dev, VFL_TYPE_GRABBER, -1);
if (ret)
goto vrelease;
@@ -1124,13 +1118,9 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
return 0;
vunreg:
- video_set_drvdata(vip->video_dev, NULL);
+ video_set_drvdata(&vip->video_dev, NULL);
vrelease:
- if (video_is_registered(vip->video_dev))
- video_unregister_device(vip->video_dev);
- else
- video_device_release(vip->video_dev);
-release_irq:
+ video_unregister_device(&vip->video_dev);
free_irq(pdev->irq, vip);
release_buf:
sta2x11_vip_release_buffer(vip);
@@ -1175,9 +1165,8 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev)
sta2x11_vip_clear_register(vip);
- video_set_drvdata(vip->video_dev, NULL);
- video_unregister_device(vip->video_dev);
- /*do not call video_device_release() here, is already done */
+ video_set_drvdata(&vip->video_dev, NULL);
+ video_unregister_device(&vip->video_dev);
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
vb2_queue_release(&vip->vb_vidq);
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index ef3d960..835635b 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -102,8 +102,8 @@ struct av7110 {
struct dvb_device dvb_dev;
struct dvb_net dvb_net;
- struct video_device *v4l_dev;
- struct video_device *vbi_dev;
+ struct video_device v4l_dev;
+ struct video_device vbi_dev;
struct saa7146_dev *dev;
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 0ba3875..54c9910 100644
--- a/drivers/media/pci/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -68,7 +68,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct budget_av {
struct budget budget;
- struct video_device *vd;
+ struct video_device vd;
int cur_input;
int has_saa7113;
struct tasklet_struct ciintf_irq_tasklet;
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index d9b872b..421f531 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -56,7 +56,7 @@ config VIDEO_VIU
config VIDEO_TIMBERDALE
tristate "Support for timberdale Video In/LogiWIN"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA
depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST
select VIDEO_ADV7180
select VIDEOBUF_DMA_CONTIG
@@ -90,6 +90,7 @@ config VIDEO_OMAP3
select ARM_DMA_USE_IOMMU
select OMAP_IOMMU
select VIDEOBUF2_DMA_CONTIG
+ select MFD_SYSCON
---help---
Driver for an OMAP 3 camera controller.
@@ -117,6 +118,7 @@ source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/s5p-tv/Kconfig"
source "drivers/media/platform/am437x/Kconfig"
+source "drivers/media/platform/xilinx/Kconfig"
endif # V4L_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 3ec1547..8f85561 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -48,4 +48,6 @@ obj-y += omap/
obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
+obj-$(CONFIG_VIDEO_XILINX) += xilinx/
+
ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig
index 7b023a76..42d9c18 100644
--- a/drivers/media/platform/am437x/Kconfig
+++ b/drivers/media/platform/am437x/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_AM437X_VPFE
tristate "TI AM437x VPFE video capture driver"
- depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
depends on SOC_AM43XX || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
help
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index 0d07fca..a30cc2f 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1645,6 +1645,7 @@ static int vpfe_enum_size(struct file *file, void *priv,
fse.index = fsize->index;
fse.pad = 0;
fse.code = mbus.code;
+ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse);
if (ret)
return -EINVAL;
@@ -1700,11 +1701,16 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe,
{
struct vpfe_config *cfg = vpfe->cfg;
struct vpfe_subdev_info *sdinfo;
+ struct i2c_client *client;
+ struct i2c_client *curr_client;
int i, j = 0;
+ curr_client = v4l2_get_subdevdata(vpfe->current_subdev->sd);
for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
sdinfo = &cfg->sub_devs[i];
- if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) {
+ client = v4l2_get_subdevdata(sdinfo->sd);
+ if (client->addr == curr_client->addr &&
+ client->adapter->nr == client->adapter->nr) {
if (vpfe->current_input >= 1)
return -1;
*app_input_index = j + vpfe->current_input;
@@ -2296,20 +2302,10 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
vpfe_dbg(1, vpfe, "vpfe_async_bound\n");
for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
- sdinfo = &vpfe->cfg->sub_devs[i];
-
- if (!strcmp(sdinfo->name, subdev->name)) {
+ if (vpfe->cfg->asd[i]->match.of.node == asd[i].match.of.node) {
+ sdinfo = &vpfe->cfg->sub_devs[i];
vpfe->sd[i] = subdev;
- vpfe_info(vpfe,
- "v4l2 sub device %s registered\n",
- subdev->name);
- vpfe->sd[i]->grp_id =
- sdinfo->grp_id;
- /* update tvnorms from the sub devices */
- for (j = 0; j < 1; j++)
- vpfe->video_dev->tvnorms |=
- sdinfo->inputs[j].std;
-
+ vpfe->sd[i]->grp_id = sdinfo->grp_id;
found = true;
break;
}
@@ -2320,6 +2316,8 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
return -EINVAL;
}
+ vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std;
+
/* setup the supported formats & indexes */
for (j = 0, i = 0; ; ++j) {
struct vpfe_fmt *fmt;
@@ -2327,6 +2325,7 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
memset(&mbus_code, 0, sizeof(mbus_code));
mbus_code.index = j;
+ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
NULL, &mbus_code);
if (ret)
@@ -2390,9 +2389,9 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
INIT_LIST_HEAD(&vpfe->dma_queue);
- vdev = vpfe->video_dev;
+ vdev = &vpfe->video_dev;
strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name));
- vdev->release = video_device_release;
+ vdev->release = video_device_release_empty;
vdev->fops = &vpfe_fops;
vdev->ioctl_ops = &vpfe_ioctl_ops;
vdev->v4l2_dev = &vpfe->v4l2_dev;
@@ -2400,7 +2399,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
vdev->queue = q;
vdev->lock = &vpfe->lock;
video_set_drvdata(vdev, vpfe);
- err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1);
+ err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1);
if (err) {
vpfe_err(vpfe,
"Unable to register video device.\n");
@@ -2425,7 +2424,7 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier)
static struct vpfe_config *
vpfe_get_pdata(struct platform_device *pdev)
{
- struct device_node *endpoint = NULL, *rem = NULL;
+ struct device_node *endpoint = NULL;
struct v4l2_of_endpoint bus_cfg;
struct vpfe_subdev_info *sdinfo;
struct vpfe_config *pdata;
@@ -2443,6 +2442,8 @@ vpfe_get_pdata(struct platform_device *pdev)
return NULL;
for (i = 0; ; i++) {
+ struct device_node *rem;
+
endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
endpoint);
if (!endpoint)
@@ -2497,11 +2498,15 @@ vpfe_get_pdata(struct platform_device *pdev)
goto done;
}
- strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name));
-
pdata->asd[i] = devm_kzalloc(&pdev->dev,
sizeof(struct v4l2_async_subdev),
GFP_KERNEL);
+ if (!pdata->asd[i]) {
+ of_node_put(rem);
+ pdata = NULL;
+ goto done;
+ }
+
pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF;
pdata->asd[i]->match.of.node = rem;
of_node_put(rem);
@@ -2512,7 +2517,6 @@ vpfe_get_pdata(struct platform_device *pdev)
done:
of_node_put(endpoint);
- of_node_put(rem);
return NULL;
}
@@ -2560,17 +2564,11 @@ static int vpfe_probe(struct platform_device *pdev)
return -EINVAL;
}
- vpfe->video_dev = video_device_alloc();
- if (!vpfe->video_dev) {
- dev_err(&pdev->dev, "Unable to allocate video device\n");
- return -ENOMEM;
- }
-
ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
if (ret) {
vpfe_err(vpfe,
"Unable to register v4l2 device.\n");
- goto probe_out_video_release;
+ return ret;
}
/* set the driver data in platform device */
@@ -2608,9 +2606,6 @@ static int vpfe_probe(struct platform_device *pdev)
probe_out_v4l2_unregister:
v4l2_device_unregister(&vpfe->v4l2_dev);
-probe_out_video_release:
- if (!video_is_registered(vpfe->video_dev))
- video_device_release(vpfe->video_dev);
return ret;
}
@@ -2627,7 +2622,7 @@ static int vpfe_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&vpfe->notifier);
v4l2_device_unregister(&vpfe->v4l2_dev);
- video_unregister_device(vpfe->video_dev);
+ video_unregister_device(&vpfe->video_dev);
return 0;
}
diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h
index 0f55735..5bfb356 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.h
+++ b/drivers/media/platform/am437x/am437x-vpfe.h
@@ -83,7 +83,6 @@ struct vpfe_route {
};
struct vpfe_subdev_info {
- char name[32];
/* Sub device group id */
int grp_id;
/* inputs available at the sub device */
@@ -223,7 +222,7 @@ struct vpfe_ccdc {
struct vpfe_device {
/* V4l2 specific parameters */
/* Identifies video device for this channel */
- struct video_device *video_dev;
+ struct video_device video_dev;
/* sub devices */
struct v4l2_subdev **sd;
/* vpfe cfg */
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 8f66986..6a437f8 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -44,7 +44,6 @@
#include <media/blackfin/ppi.h>
#define CAPTURE_DRV_NAME "bfin_capture"
-#define BCAP_MIN_NUM_BUF 2
struct bcap_format {
char *desc;
@@ -65,7 +64,7 @@ struct bcap_device {
/* v4l2 control handler */
struct v4l2_ctrl_handler ctrl_handler;
/* device node data */
- struct video_device *video_dev;
+ struct video_device video_dev;
/* sub device instance */
struct v4l2_subdev *sd;
/* capture config */
@@ -104,12 +103,8 @@ struct bcap_device {
struct completion comp;
/* prepare to stop */
bool stop;
-};
-
-struct bcap_fh {
- struct v4l2_fh fh;
- /* indicates whether this file handle is doing IO */
- bool io_allowed;
+ /* vb2 buffer sequence counter */
+ unsigned sequence;
};
static const struct bcap_format bcap_formats[] = {
@@ -201,90 +196,6 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
bcap_dev->sensor_formats = NULL;
}
-static int bcap_open(struct file *file)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct video_device *vfd = bcap_dev->video_dev;
- struct bcap_fh *bcap_fh;
-
- if (!bcap_dev->sd) {
- v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n");
- return -ENODEV;
- }
-
- bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL);
- if (!bcap_fh) {
- v4l2_err(&bcap_dev->v4l2_dev,
- "unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
-
- v4l2_fh_init(&bcap_fh->fh, vfd);
-
- /* store pointer to v4l2_fh in private_data member of file */
- file->private_data = &bcap_fh->fh;
- v4l2_fh_add(&bcap_fh->fh);
- bcap_fh->io_allowed = false;
- return 0;
-}
-
-static int bcap_release(struct file *file)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
- struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
-
- /* if this instance is doing IO */
- if (bcap_fh->io_allowed)
- vb2_queue_release(&bcap_dev->buffer_queue);
-
- file->private_data = NULL;
- v4l2_fh_del(&bcap_fh->fh);
- v4l2_fh_exit(&bcap_fh->fh);
- kfree(bcap_fh);
- return 0;
-}
-
-static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- int ret;
-
- if (mutex_lock_interruptible(&bcap_dev->mutex))
- return -ERESTARTSYS;
- ret = vb2_mmap(&bcap_dev->buffer_queue, vma);
- mutex_unlock(&bcap_dev->mutex);
- return ret;
-}
-
-#ifndef CONFIG_MMU
-static unsigned long bcap_get_unmapped_area(struct file *file,
- unsigned long addr,
- unsigned long len,
- unsigned long pgoff,
- unsigned long flags)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
-
- return vb2_get_unmapped_area(&bcap_dev->buffer_queue,
- addr,
- len,
- pgoff,
- flags);
-}
-#endif
-
-static unsigned int bcap_poll(struct file *file, poll_table *wait)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- unsigned int res;
-
- mutex_lock(&bcap_dev->mutex);
- res = vb2_poll(&bcap_dev->buffer_queue, file, wait);
- mutex_unlock(&bcap_dev->mutex);
- return res;
-}
-
static int bcap_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
@@ -292,37 +203,32 @@ static int bcap_queue_setup(struct vb2_queue *vq,
{
struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
- if (*nbuffers < BCAP_MIN_NUM_BUF)
- *nbuffers = BCAP_MIN_NUM_BUF;
+ if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage)
+ return -EINVAL;
+
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2;
*nplanes = 1;
- sizes[0] = bcap_dev->fmt.sizeimage;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage;
alloc_ctxs[0] = bcap_dev->alloc_ctx;
return 0;
}
-static int bcap_buffer_init(struct vb2_buffer *vb)
-{
- struct bcap_buffer *buf = to_bcap_vb(vb);
-
- INIT_LIST_HEAD(&buf->list);
- return 0;
-}
-
static int bcap_buffer_prepare(struct vb2_buffer *vb)
{
struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
- struct bcap_buffer *buf = to_bcap_vb(vb);
- unsigned long size;
+ unsigned long size = bcap_dev->fmt.sizeimage;
- size = bcap_dev->fmt.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n",
vb2_plane_size(vb, 0), size);
return -EINVAL;
}
- vb2_set_plane_payload(&buf->vb, 0, size);
+ vb2_set_plane_payload(vb, 0, size);
+
+ vb->v4l2_buf.field = bcap_dev->fmt.field;
return 0;
}
@@ -353,14 +259,16 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
struct ppi_if *ppi = bcap_dev->ppi;
+ struct bcap_buffer *buf, *tmp;
struct ppi_params params;
+ dma_addr_t addr;
int ret;
/* enable streamon on the sub device */
ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1);
if (ret && (ret != -ENOIOCTLCMD)) {
v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n");
- return ret;
+ goto err;
}
/* set ppi params */
@@ -399,7 +307,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret < 0) {
v4l2_err(&bcap_dev->v4l2_dev,
"Error in setting ppi params\n");
- return ret;
+ goto err;
}
/* attach ppi DMA irq handler */
@@ -407,12 +315,34 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret < 0) {
v4l2_err(&bcap_dev->v4l2_dev,
"Error in attaching interrupt handler\n");
- return ret;
+ goto err;
}
+ bcap_dev->sequence = 0;
+
reinit_completion(&bcap_dev->comp);
bcap_dev->stop = false;
+
+ /* get the next frame from the dma queue */
+ bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
+ struct bcap_buffer, list);
+ /* remove buffer from the dma queue */
+ list_del_init(&bcap_dev->cur_frm->list);
+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+ /* update DMA address */
+ ppi->ops->update_addr(ppi, (unsigned long)addr);
+ /* enable ppi */
+ ppi->ops->start(ppi);
+
return 0;
+
+err:
+ list_for_each_entry_safe(buf, tmp, &bcap_dev->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+
+ return ret;
}
static void bcap_stop_streaming(struct vb2_queue *vq)
@@ -431,6 +361,9 @@ static void bcap_stop_streaming(struct vb2_queue *vq)
"stream off failed in subdev\n");
/* release all active buffers */
+ if (bcap_dev->cur_frm)
+ vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR);
+
while (!list_empty(&bcap_dev->dma_queue)) {
bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
@@ -441,7 +374,6 @@ static void bcap_stop_streaming(struct vb2_queue *vq)
static struct vb2_ops bcap_video_qops = {
.queue_setup = bcap_queue_setup,
- .buf_init = bcap_buffer_init,
.buf_prepare = bcap_buffer_prepare,
.buf_cleanup = bcap_buffer_cleanup,
.buf_queue = bcap_buffer_queue,
@@ -451,57 +383,6 @@ static struct vb2_ops bcap_video_qops = {
.stop_streaming = bcap_stop_streaming,
};
-static int bcap_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req_buf)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct vb2_queue *vq = &bcap_dev->buffer_queue;
- struct v4l2_fh *fh = file->private_data;
- struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
-
- if (vb2_is_busy(vq))
- return -EBUSY;
-
- bcap_fh->io_allowed = true;
-
- return vb2_reqbufs(vq, req_buf);
-}
-
-static int bcap_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
-
- return vb2_querybuf(&bcap_dev->buffer_queue, buf);
-}
-
-static int bcap_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
- struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
-
- if (!bcap_fh->io_allowed)
- return -EBUSY;
-
- return vb2_qbuf(&bcap_dev->buffer_queue, buf);
-}
-
-static int bcap_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
- struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
-
- if (!bcap_fh->io_allowed)
- return -EBUSY;
-
- return vb2_dqbuf(&bcap_dev->buffer_queue,
- buf, file->f_flags & O_NONBLOCK);
-}
-
static irqreturn_t bcap_isr(int irq, void *dev_id)
{
struct ppi_if *ppi = dev_id;
@@ -517,6 +398,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
ppi->err = false;
} else {
+ vb->v4l2_buf.sequence = bcap_dev->sequence++;
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
@@ -543,62 +425,14 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int bcap_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct bcap_fh *fh = file->private_data;
- struct ppi_if *ppi = bcap_dev->ppi;
- dma_addr_t addr;
- int ret;
-
- if (!fh->io_allowed)
- return -EBUSY;
-
- /* call streamon to start streaming in videobuf */
- ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type);
- if (ret)
- return ret;
-
- /* if dma queue is empty, return error */
- if (list_empty(&bcap_dev->dma_queue)) {
- v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n");
- ret = -EINVAL;
- goto err;
- }
-
- /* get the next frame from the dma queue */
- bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
- struct bcap_buffer, list);
- /* remove buffer from the dma queue */
- list_del_init(&bcap_dev->cur_frm->list);
- addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
- /* update DMA address */
- ppi->ops->update_addr(ppi, (unsigned long)addr);
- /* enable ppi */
- ppi->ops->start(ppi);
-
- return 0;
-err:
- vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
- return ret;
-}
-
-static int bcap_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
- struct bcap_fh *fh = file->private_data;
-
- if (!fh->io_allowed)
- return -EBUSY;
-
- return vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
-}
-
static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_STD))
+ return -ENODATA;
return v4l2_subdev_call(bcap_dev->sd, video, querystd, std);
}
@@ -606,6 +440,11 @@ static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_STD))
+ return -ENODATA;
*std = bcap_dev->std;
return 0;
@@ -614,8 +453,13 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
int ret;
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_STD))
+ return -ENODATA;
+
if (vb2_is_busy(&bcap_dev->buffer_queue))
return -EBUSY;
@@ -631,6 +475,11 @@ static int bcap_enum_dv_timings(struct file *file, void *priv,
struct v4l2_enum_dv_timings *timings)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS))
+ return -ENODATA;
timings->pad = 0;
@@ -642,6 +491,11 @@ static int bcap_query_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS))
+ return -ENODATA;
return v4l2_subdev_call(bcap_dev->sd, video,
query_dv_timings, timings);
@@ -651,6 +505,11 @@ static int bcap_g_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS))
+ return -ENODATA;
*timings = bcap_dev->dv_timings;
return 0;
@@ -660,7 +519,13 @@ static int bcap_s_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_input input;
int ret;
+
+ input = bcap_dev->cfg->inputs[bcap_dev->cur_input];
+ if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS))
+ return -ENODATA;
+
if (vb2_is_busy(&bcap_dev->buffer_queue))
return -EBUSY;
@@ -881,12 +746,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
.vidioc_g_dv_timings = bcap_g_dv_timings,
.vidioc_query_dv_timings = bcap_query_dv_timings,
.vidioc_enum_dv_timings = bcap_enum_dv_timings,
- .vidioc_reqbufs = bcap_reqbufs,
- .vidioc_querybuf = bcap_querybuf,
- .vidioc_qbuf = bcap_qbuf,
- .vidioc_dqbuf = bcap_dqbuf,
- .vidioc_streamon = bcap_streamon,
- .vidioc_streamoff = bcap_streamoff,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_parm = bcap_g_parm,
.vidioc_s_parm = bcap_s_parm,
.vidioc_log_status = bcap_log_status,
@@ -894,14 +761,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
static struct v4l2_file_operations bcap_fops = {
.owner = THIS_MODULE,
- .open = bcap_open,
- .release = bcap_release,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
.unlocked_ioctl = video_ioctl2,
- .mmap = bcap_mmap,
+ .mmap = vb2_fop_mmap,
#ifndef CONFIG_MMU
- .get_unmapped_area = bcap_get_unmapped_area,
+ .get_unmapped_area = vb2_fop_get_unmapped_area,
#endif
- .poll = bcap_poll
+ .poll = vb2_fop_poll
};
static int bcap_probe(struct platform_device *pdev)
@@ -942,27 +809,20 @@ static int bcap_probe(struct platform_device *pdev)
goto err_free_ppi;
}
- vfd = video_device_alloc();
- if (!vfd) {
- ret = -ENOMEM;
- v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
- goto err_cleanup_ctx;
- }
-
+ vfd = &bcap_dev->video_dev;
/* initialize field of video device */
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->fops = &bcap_fops;
vfd->ioctl_ops = &bcap_ioctl_ops;
vfd->tvnorms = 0;
vfd->v4l2_dev = &bcap_dev->v4l2_dev;
strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
- bcap_dev->video_dev = vfd;
ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev);
if (ret) {
v4l2_err(pdev->dev.driver,
"Unable to register v4l2 device\n");
- goto err_release_vdev;
+ goto err_cleanup_ctx;
}
v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n");
@@ -978,13 +838,14 @@ static int bcap_probe(struct platform_device *pdev)
/* initialize queue */
q = &bcap_dev->buffer_queue;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
q->drv_priv = bcap_dev;
q->buf_struct_size = sizeof(struct bcap_buffer);
q->ops = &bcap_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &bcap_dev->mutex;
+ q->min_buffers_needed = 1;
ret = vb2_queue_init(q);
if (ret)
@@ -997,15 +858,16 @@ static int bcap_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&bcap_dev->dma_queue);
vfd->lock = &bcap_dev->mutex;
+ vfd->queue = q;
/* register video device */
- ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
+ ret = video_register_device(&bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
if (ret) {
v4l2_err(&bcap_dev->v4l2_dev,
"Unable to register video device\n");
goto err_free_handler;
}
- video_set_drvdata(bcap_dev->video_dev, bcap_dev);
+ video_set_drvdata(&bcap_dev->video_dev, bcap_dev);
v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n",
video_device_node_name(vfd));
@@ -1083,15 +945,11 @@ static int bcap_probe(struct platform_device *pdev)
}
return 0;
err_unreg_vdev:
- video_unregister_device(bcap_dev->video_dev);
- bcap_dev->video_dev = NULL;
+ video_unregister_device(&bcap_dev->video_dev);
err_free_handler:
v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
err_unreg_v4l2:
v4l2_device_unregister(&bcap_dev->v4l2_dev);
-err_release_vdev:
- if (bcap_dev->video_dev)
- video_device_release(bcap_dev->video_dev);
err_cleanup_ctx:
vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
err_free_ppi:
@@ -1108,7 +966,7 @@ static int bcap_remove(struct platform_device *pdev)
struct bcap_device, v4l2_dev);
bcap_free_sensor_formats(bcap_dev);
- video_unregister_device(bcap_dev->video_dev);
+ video_unregister_device(&bcap_dev->video_dev);
v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
index 25ce155..834e504 100644
--- a/drivers/media/platform/coda/Makefile
+++ b/drivers/media/platform/coda/Makefile
@@ -1,3 +1,5 @@
+ccflags-y += -I$(src)
+
coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o
obj-$(CONFIG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 856b542..d043007 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
+#include <linux/log2.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -29,13 +30,18 @@
#include <media/videobuf2-vmalloc.h>
#include "coda.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA7_PS_BUF_SIZE 0x28000
#define CODA9_PS_SAVE_SIZE (512 * 1024)
#define CODA_DEFAULT_GAMMA 4096
#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx);
+
static inline int coda_is_initialized(struct coda_dev *dev)
{
return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
@@ -84,15 +90,21 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd)
coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+ trace_coda_bit_run(ctx, cmd);
+
coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
}
static int coda_command_sync(struct coda_ctx *ctx, int cmd)
{
struct coda_dev *dev = ctx->dev;
+ int ret;
coda_command_async(ctx, cmd);
- return coda_wait_timeout(dev);
+ ret = coda_wait_timeout(dev);
+ trace_coda_bit_done(ctx);
+
+ return ret;
}
int coda_hw_reset(struct coda_ctx *ctx)
@@ -177,10 +189,6 @@ static int coda_bitstream_queue(struct coda_ctx *ctx,
if (n < src_size)
return -ENOSPC;
- dma_sync_single_for_device(&ctx->dev->plat_dev->dev,
- ctx->bitstream.paddr, ctx->bitstream.size,
- DMA_TO_DEVICE);
-
src_buf->v4l2_buf.sequence = ctx->qsequence++;
return 0;
@@ -214,7 +222,7 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
return true;
}
-void coda_fill_bitstream(struct coda_ctx *ctx)
+void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming)
{
struct vb2_buffer *src_buf;
struct coda_buffer_meta *meta;
@@ -235,9 +243,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx)
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
!coda_jpeg_check_buffer(ctx, src_buf)) {
v4l2_err(&ctx->dev->v4l2_dev,
- "dropping invalid JPEG frame\n");
+ "dropping invalid JPEG frame %d\n",
+ ctx->qsequence);
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(src_buf, streaming ?
+ VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_QUEUED);
continue;
}
@@ -262,6 +273,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx)
ctx->bitstream_fifo.kfifo.mask;
list_add_tail(&meta->list,
&ctx->buffer_meta_list);
+
+ trace_coda_bit_queue(ctx, src_buf, meta);
}
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
@@ -297,6 +310,14 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
p[index ^ 1] = value;
}
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+ struct coda_aux_buf *buf, size_t size,
+ const char *name)
+{
+ return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
+}
+
+
static void coda_free_framebuffers(struct coda_ctx *ctx)
{
int i;
@@ -377,6 +398,7 @@ static void coda_free_context_buffers(struct coda_ctx *ctx)
coda_free_aux_buf(dev, &ctx->psbuf);
if (dev->devtype->product != CODA_DX6)
coda_free_aux_buf(dev, &ctx->workbuf);
+ coda_free_aux_buf(dev, &ctx->parabuf);
}
static int coda_alloc_context_buffers(struct coda_ctx *ctx,
@@ -386,57 +408,42 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
size_t size;
int ret;
+ if (!ctx->parabuf.vaddr) {
+ ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
+ CODA_PARA_BUF_SIZE, "parabuf");
+ if (ret < 0)
+ return ret;
+ }
+
if (dev->devtype->product == CODA_DX6)
return 0;
- if (ctx->psbuf.vaddr) {
- v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
- return -EBUSY;
- }
- if (ctx->slicebuf.vaddr) {
- v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
- return -EBUSY;
- }
- if (ctx->workbuf.vaddr) {
- v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
- ret = -EBUSY;
- return -ENOMEM;
- }
-
- if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+ if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
/* worst case slice size */
size = (DIV_ROUND_UP(q_data->width, 16) *
DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
"slicebuf");
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev,
- "failed to allocate %d byte slice buffer",
- ctx->slicebuf.size);
- return ret;
- }
+ if (ret < 0)
+ goto err;
}
- if (dev->devtype->product == CODA_7541) {
+ if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) {
ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
CODA7_PS_BUF_SIZE, "psbuf");
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev,
- "failed to allocate psmem buffer");
+ if (ret < 0)
goto err;
- }
}
- size = dev->devtype->workbuf_size;
- if (dev->devtype->product == CODA_960 &&
- q_data->fourcc == V4L2_PIX_FMT_H264)
- size += CODA9_PS_SAVE_SIZE;
- ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev,
- "failed to allocate %d byte context buffer",
- ctx->workbuf.size);
- goto err;
+ if (!ctx->workbuf.vaddr) {
+ size = dev->devtype->workbuf_size;
+ if (dev->devtype->product == CODA_960 &&
+ q_data->fourcc == V4L2_PIX_FMT_H264)
+ size += CODA9_PS_SAVE_SIZE;
+ ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size,
+ "workbuf");
+ if (ret < 0)
+ goto err;
}
return 0;
@@ -709,6 +716,27 @@ err_clk_per:
* Encoder context operations
*/
+static int coda_encoder_reqbufs(struct coda_ctx *ctx,
+ struct v4l2_requestbuffers *rb)
+{
+ struct coda_q_data *q_data_src;
+ int ret;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return 0;
+
+ if (rb->count) {
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ ret = coda_alloc_context_buffers(ctx, q_data_src);
+ if (ret < 0)
+ return ret;
+ } else {
+ coda_free_context_buffers(ctx);
+ }
+
+ return 0;
+}
+
static int coda_start_encoding(struct coda_ctx *ctx)
{
struct coda_dev *dev = ctx->dev;
@@ -725,11 +753,6 @@ static int coda_start_encoding(struct coda_ctx *ctx)
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
dst_fourcc = q_data_dst->fourcc;
- /* Allocate per-instance buffers */
- ret = coda_alloc_context_buffers(ctx, q_data_src);
- if (ret < 0)
- return ret;
-
buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
bitstream_size = q_data_dst->sizeimage;
@@ -1227,6 +1250,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
coda_write(dev, ctx->iram_info.axi_sram_use,
CODA7_REG_BIT_AXI_SRAM_USE);
+ trace_coda_enc_pic_run(ctx, src_buf);
+
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
return 0;
@@ -1241,6 +1266,8 @@ static void coda_finish_encode(struct coda_ctx *ctx)
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ trace_coda_enc_pic_done(ctx, dst_buf);
+
/* Get results from the coda */
start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
@@ -1311,7 +1338,6 @@ static void coda_seq_end_work(struct work_struct *work)
ctx->bitstream.vaddr, ctx->bitstream.size);
coda_free_framebuffers(ctx);
- coda_free_context_buffers(ctx);
mutex_unlock(&dev->coda_mutex);
mutex_unlock(&ctx->buffer_mutex);
@@ -1322,11 +1348,13 @@ static void coda_bit_release(struct coda_ctx *ctx)
mutex_lock(&ctx->buffer_mutex);
coda_free_framebuffers(ctx);
coda_free_context_buffers(ctx);
+ coda_free_bitstream_buffer(ctx);
mutex_unlock(&ctx->buffer_mutex);
}
const struct coda_context_ops coda_bit_encode_ops = {
.queue_init = coda_encoder_queue_init,
+ .reqbufs = coda_encoder_reqbufs,
.start_streaming = coda_start_encoding,
.prepare_run = coda_prepare_encode,
.finish_run = coda_finish_encode,
@@ -1338,6 +1366,65 @@ const struct coda_context_ops coda_bit_encode_ops = {
* Decoder context operations
*/
+static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
+ struct coda_q_data *q_data)
+{
+ if (ctx->bitstream.vaddr)
+ return 0;
+
+ ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
+ ctx->bitstream.vaddr = dma_alloc_writecombine(
+ &ctx->dev->plat_dev->dev, ctx->bitstream.size,
+ &ctx->bitstream.paddr, GFP_KERNEL);
+ if (!ctx->bitstream.vaddr) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "failed to allocate bitstream ringbuffer");
+ return -ENOMEM;
+ }
+ kfifo_init(&ctx->bitstream_fifo,
+ ctx->bitstream.vaddr, ctx->bitstream.size);
+
+ return 0;
+}
+
+static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
+{
+ if (ctx->bitstream.vaddr == NULL)
+ return;
+
+ dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
+ ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ ctx->bitstream.vaddr = NULL;
+ kfifo_init(&ctx->bitstream_fifo, NULL, 0);
+}
+
+static int coda_decoder_reqbufs(struct coda_ctx *ctx,
+ struct v4l2_requestbuffers *rb)
+{
+ struct coda_q_data *q_data_src;
+ int ret;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return 0;
+
+ if (rb->count) {
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ ret = coda_alloc_context_buffers(ctx, q_data_src);
+ if (ret < 0)
+ return ret;
+ ret = coda_alloc_bitstream_buffer(ctx, q_data_src);
+ if (ret < 0) {
+ coda_free_context_buffers(ctx);
+ return ret;
+ }
+ } else {
+ coda_free_bitstream_buffer(ctx);
+ coda_free_context_buffers(ctx);
+ }
+
+ return 0;
+}
+
static int __coda_start_decoding(struct coda_ctx *ctx)
{
struct coda_q_data *q_data_src, *q_data_dst;
@@ -1356,11 +1443,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
src_fourcc = q_data_src->fourcc;
dst_fourcc = q_data_dst->fourcc;
- /* Allocate per-instance buffers */
- ret = coda_alloc_context_buffers(ctx, q_data_src);
- if (ret < 0)
- return ret;
-
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
/* Update coda bitstream read and write pointers from kfifo */
@@ -1579,7 +1661,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
/* Try to copy source buffer contents into the bitstream ringbuffer */
mutex_lock(&ctx->bitstream_mutex);
- coda_fill_bitstream(ctx);
+ coda_fill_bitstream(ctx, true);
mutex_unlock(&ctx->bitstream_mutex);
if (coda_get_bitstream_payload(ctx) < 512 &&
@@ -1675,6 +1757,8 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
/* Clear decode success flag */
coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
+ trace_coda_dec_pic_run(ctx, meta);
+
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
return 0;
@@ -1704,7 +1788,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
* by up to 512 bytes
*/
if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
- if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+ if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512)
kfifo_init(&ctx->bitstream_fifo,
ctx->bitstream.vaddr, ctx->bitstream.size);
}
@@ -1835,6 +1919,8 @@ static void coda_finish_decode(struct coda_ctx *ctx)
}
mutex_unlock(&ctx->bitstream_mutex);
+ trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]);
+
val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
if (val == 0)
ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
@@ -1874,6 +1960,8 @@ static void coda_finish_decode(struct coda_ctx *ctx)
dst_buf->v4l2_buf.timecode = meta->timecode;
dst_buf->v4l2_buf.timestamp = meta->timestamp;
+ trace_coda_dec_rot_done(ctx, meta, dst_buf);
+
switch (q_data_dst->fourcc) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
@@ -1906,6 +1994,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
const struct coda_context_ops coda_bit_decode_ops = {
.queue_init = coda_decoder_queue_init,
+ .reqbufs = coda_decoder_reqbufs,
.start_streaming = coda_start_decoding,
.prepare_run = coda_prepare_decode,
.finish_run = coda_finish_decode,
@@ -1931,6 +2020,8 @@ irqreturn_t coda_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+ trace_coda_bit_done(ctx);
+
if (ctx->aborting) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"task has been aborted\n");
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 6f32e6d..8e6fe02 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -46,7 +46,6 @@
#define CODADX6_MAX_INSTANCES 4
#define CODA_MAX_FORMATS 4
-#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA_ISRAM_SIZE (2048 * 2)
#define MIN_W 176
@@ -696,6 +695,26 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
return coda_s_fmt(ctx, &f_cap);
}
+static int coda_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+ int ret;
+
+ ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb);
+ if (ret)
+ return ret;
+
+ /*
+ * Allow to allocate instance specific per-context buffers, such as
+ * bitstream ringbuffer, slice buffer, work buffer, etc. if needed.
+ */
+ if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs)
+ return ctx->ops->reqbufs(ctx, rb);
+
+ return 0;
+}
+
static int coda_qbuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
@@ -841,7 +860,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = coda_s_fmt_vid_out,
- .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_reqbufs = coda_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = coda_qbuf,
@@ -1173,7 +1192,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
mutex_lock(&ctx->bitstream_mutex);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
if (vb2_is_streaming(vb->vb2_queue))
- coda_fill_bitstream(ctx);
+ coda_fill_bitstream(ctx, true);
mutex_unlock(&ctx->bitstream_mutex);
} else {
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
@@ -1215,8 +1234,9 @@ void coda_free_aux_buf(struct coda_dev *dev,
buf->vaddr, buf->paddr);
buf->vaddr = NULL;
buf->size = 0;
+ debugfs_remove(buf->dentry);
+ buf->dentry = NULL;
}
- debugfs_remove(buf->dentry);
}
static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
@@ -1232,9 +1252,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
if (q_data_src->fourcc == V4L2_PIX_FMT_H264 ||
(q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
ctx->dev->devtype->product == CODA_7541)) {
- /* copy the buffers that where queued before streamon */
+ /* copy the buffers that were queued before streamon */
mutex_lock(&ctx->bitstream_mutex);
- coda_fill_bitstream(ctx);
+ coda_fill_bitstream(ctx, false);
mutex_unlock(&ctx->bitstream_mutex);
if (coda_get_bitstream_payload(ctx) < 512) {
@@ -1262,12 +1282,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
if (!(ctx->streamon_out & ctx->streamon_cap))
return 0;
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if ((q_data_src->width != q_data_dst->width &&
+ round_up(q_data_src->width, 16) != q_data_dst->width) ||
+ (q_data_src->height != q_data_dst->height &&
+ round_up(q_data_src->height, 16) != q_data_dst->height)) {
+ v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n",
+ q_data_src->width, q_data_src->height,
+ q_data_dst->width, q_data_dst->height);
+ ret = -EINVAL;
+ goto err;
+ }
+
/* Allow BIT decoder device_run with no new buffers queued */
if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit)
v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
ctx->gopcounter = ctx->params.gop_size - 1;
- q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
q_data_dst->fourcc);
@@ -1308,6 +1339,9 @@ static void coda_stop_streaming(struct vb2_queue *q)
struct coda_ctx *ctx = vb2_get_drv_priv(q);
struct coda_dev *dev = ctx->dev;
struct vb2_buffer *buf;
+ bool stop;
+
+ stop = ctx->streamon_out && ctx->streamon_cap;
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
@@ -1332,7 +1366,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
}
- if (!ctx->streamon_out && !ctx->streamon_cap) {
+ if (stop) {
struct coda_buffer_meta *meta;
if (ctx->ops->seq_end_work) {
@@ -1457,7 +1491,7 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = {
static void coda_encode_ctrls(struct coda_ctx *ctx)
{
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+ V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -1541,6 +1575,13 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
vq->lock = &ctx->dev->dev_mutex;
+ /* One way to indicate end-of-stream for coda is to set the
+ * bytesused == 0. However by default videobuf2 handles bytesused
+ * equal to 0 as a special case and changes its value to the size
+ * of the buffer. Set the allow_zero_bytesused flag, so
+ * that videobuf2 will keep the value of bytesused intact.
+ */
+ vq->allow_zero_bytesused = 1;
return vb2_queue_init(vq);
}
@@ -1621,6 +1662,11 @@ static int coda_open(struct file *file)
set_bit(idx, &dev->instance_mask);
name = kasprintf(GFP_KERNEL, "context%d", idx);
+ if (!name) {
+ ret = -ENOMEM;
+ goto err_coda_name_init;
+ }
+
ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
kfree(name);
@@ -1682,28 +1728,6 @@ static int coda_open(struct file *file)
ctx->fh.ctrl_handler = &ctx->ctrls;
- if (ctx->use_bit) {
- ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
- CODA_PARA_BUF_SIZE, "parabuf");
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
- goto err_dma_alloc;
- }
- }
- if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) {
- ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
- ctx->bitstream.vaddr = dma_alloc_writecombine(
- &dev->plat_dev->dev, ctx->bitstream.size,
- &ctx->bitstream.paddr, GFP_KERNEL);
- if (!ctx->bitstream.vaddr) {
- v4l2_err(&dev->v4l2_dev,
- "failed to allocate bitstream ringbuffer");
- ret = -ENOMEM;
- goto err_dma_writecombine;
- }
- }
- kfifo_init(&ctx->bitstream_fifo,
- ctx->bitstream.vaddr, ctx->bitstream.size);
mutex_init(&ctx->bitstream_mutex);
mutex_init(&ctx->buffer_mutex);
INIT_LIST_HEAD(&ctx->buffer_meta_list);
@@ -1717,12 +1741,6 @@ static int coda_open(struct file *file)
return 0;
-err_dma_writecombine:
- if (ctx->dev->devtype->product == CODA_DX6)
- coda_free_aux_buf(dev, &ctx->workbuf);
- coda_free_aux_buf(dev, &ctx->parabuf);
-err_dma_alloc:
- v4l2_ctrl_handler_free(&ctx->ctrls);
err_ctrls_setup:
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_ctx_init:
@@ -1735,6 +1753,7 @@ err_pm_get:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask);
+err_coda_name_init:
err_coda_max:
kfree(ctx);
return ret;
@@ -1764,14 +1783,9 @@ static int coda_release(struct file *file)
list_del(&ctx->list);
coda_unlock(ctx);
- if (ctx->bitstream.vaddr) {
- dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
- ctx->bitstream.vaddr, ctx->bitstream.paddr);
- }
if (ctx->dev->devtype->product == CODA_DX6)
coda_free_aux_buf(dev, &ctx->workbuf);
- coda_free_aux_buf(dev, &ctx->parabuf);
v4l2_ctrl_handler_free(&ctx->ctrls);
clk_disable_unprepare(dev->clk_ahb);
clk_disable_unprepare(dev->clk_per);
@@ -1901,8 +1915,7 @@ static int coda_register_device(struct coda_dev *dev, int i)
if (i >= dev->devtype->num_vdevs)
return -EINVAL;
- snprintf(vfd->name, sizeof(vfd->name), "%s",
- dev->devtype->vdevs[i]->name);
+ strlcpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name));
vfd->fops = &coda_fops;
vfd->ioctl_ops = &coda_ioctl_ops;
vfd->release = video_device_release_empty,
@@ -1933,10 +1946,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
/* allocate auxiliary per-device code buffer for the BIT processor */
ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
dev->debugfs_root);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to allocate code buffer\n");
+ if (ret < 0)
goto put_pm;
- }
/* Copy the whole firmware image to the code buffer */
memcpy(dev->codebuf.vaddr, fw->data, fw->size);
@@ -2174,20 +2185,16 @@ static int coda_probe(struct platform_device *pdev)
ret = coda_alloc_aux_buf(dev, &dev->workbuf,
dev->devtype->workbuf_size, "workbuf",
dev->debugfs_root);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to allocate work buffer\n");
+ if (ret < 0)
goto err_v4l2_register;
- }
}
if (dev->devtype->tempbuf_size) {
ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
dev->devtype->tempbuf_size, "tempbuf",
dev->debugfs_root);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+ if (ret < 0)
goto err_v4l2_register;
- }
}
dev->iram.size = dev->devtype->iram_size;
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c
index 8fa3e35..11e734b 100644
--- a/drivers/media/platform/coda/coda-jpeg.c
+++ b/drivers/media/platform/coda/coda-jpeg.c
@@ -13,6 +13,7 @@
#include <linux/swab.h>
#include "coda.h"
+#include "trace.h"
#define SOI_MARKER 0xffd8
#define EOI_MARKER 0xffd9
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 0c35cd5..6a5c8f6 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -12,6 +12,9 @@
* (at your option) any later version.
*/
+#ifndef __CODA_H__
+#define __CODA_H__
+
#include <linux/debugfs.h>
#include <linux/irqreturn.h>
#include <linux/mutex.h>
@@ -26,7 +29,6 @@
#include "coda_regs.h"
#define CODA_MAX_FRAMEBUFFERS 8
-#define CODA_MAX_FRAME_SIZE 0x100000
#define FMO_SLICE_SAVE_BUF_SIZE (32)
enum {
@@ -178,6 +180,7 @@ struct coda_ctx;
struct coda_context_ops {
int (*queue_init)(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
+ int (*reqbufs)(struct coda_ctx *ctx, struct v4l2_requestbuffers *rb);
int (*start_streaming)(struct coda_ctx *ctx);
int (*prepare_run)(struct coda_ctx *ctx);
void (*finish_run)(struct coda_ctx *ctx);
@@ -249,13 +252,6 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
size_t size, const char *name, struct dentry *parent);
void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf);
-static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
- struct coda_aux_buf *buf, size_t size,
- const char *name)
-{
- return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
-}
-
int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -263,7 +259,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
int coda_hw_reset(struct coda_ctx *ctx);
-void coda_fill_bitstream(struct coda_ctx *ctx);
+void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming);
void coda_set_gdi_regs(struct coda_ctx *ctx);
@@ -284,7 +280,7 @@ const char *coda_product_name(int product);
int coda_check_firmware(struct coda_dev *dev);
-static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
+static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx)
{
return kfifo_len(&ctx->bitstream_fifo);
}
@@ -301,3 +297,5 @@ extern const struct coda_context_ops coda_bit_encode_ops;
extern const struct coda_context_ops coda_bit_decode_ops;
irqreturn_t coda_irq_handler(int irq, void *data);
+
+#endif /* __CODA_H__ */
diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h
new file mode 100644
index 0000000..d1d06cb
--- /dev/null
+++ b/drivers/media/platform/coda/trace.h
@@ -0,0 +1,203 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM coda
+
+#if !defined(__CODA_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
+#define __CODA_TRACE_H__
+
+#include <linux/tracepoint.h>
+#include <media/videobuf2-core.h>
+
+#include "coda.h"
+
+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
+
+TRACE_EVENT(coda_bit_run,
+ TP_PROTO(struct coda_ctx *ctx, int cmd),
+
+ TP_ARGS(ctx, cmd),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, ctx)
+ __field(int, cmd)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->ctx = ctx->idx;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("minor = %d, ctx = %d, cmd = %d",
+ __entry->minor, __entry->ctx, __entry->cmd)
+);
+
+TRACE_EVENT(coda_bit_done,
+ TP_PROTO(struct coda_ctx *ctx),
+
+ TP_ARGS(ctx),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx)
+);
+
+TRACE_EVENT(coda_enc_pic_run,
+ TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf),
+
+ TP_ARGS(ctx, buf),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, index)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->index = buf->v4l2_buf.index;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, index = %d, ctx = %d",
+ __entry->minor, __entry->index, __entry->ctx)
+);
+
+TRACE_EVENT(coda_enc_pic_done,
+ TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf),
+
+ TP_ARGS(ctx, buf),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, index)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->index = buf->v4l2_buf.index;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, index = %d, ctx = %d",
+ __entry->minor, __entry->index, __entry->ctx)
+);
+
+TRACE_EVENT(coda_bit_queue,
+ TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf,
+ struct coda_buffer_meta *meta),
+
+ TP_ARGS(ctx, buf, meta),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, index)
+ __field(int, start)
+ __field(int, end)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->index = buf->v4l2_buf.index;
+ __entry->start = meta->start;
+ __entry->end = meta->end;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, index = %d, start = 0x%x, end = 0x%x, ctx = %d",
+ __entry->minor, __entry->index, __entry->start, __entry->end,
+ __entry->ctx)
+);
+
+TRACE_EVENT(coda_dec_pic_run,
+ TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta),
+
+ TP_ARGS(ctx, meta),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, start)
+ __field(int, end)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->start = meta ? meta->start : 0;
+ __entry->end = meta ? meta->end : 0;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d",
+ __entry->minor, __entry->start, __entry->end, __entry->ctx)
+);
+
+TRACE_EVENT(coda_dec_pic_done,
+ TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta),
+
+ TP_ARGS(ctx, meta),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, start)
+ __field(int, end)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->start = meta->start;
+ __entry->end = meta->end;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d",
+ __entry->minor, __entry->start, __entry->end, __entry->ctx)
+);
+
+TRACE_EVENT(coda_dec_rot_done,
+ TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta,
+ struct vb2_buffer *buf),
+
+ TP_ARGS(ctx, meta, buf),
+
+ TP_STRUCT__entry(
+ __field(int, minor)
+ __field(int, start)
+ __field(int, end)
+ __field(int, index)
+ __field(int, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->minor = ctx->fh.vdev->minor;
+ __entry->start = meta->start;
+ __entry->end = meta->end;
+ __entry->index = buf->v4l2_buf.index;
+ __entry->ctx = ctx->idx;
+ ),
+
+ TP_printk("minor = %d, start = 0x%x, end = 0x%x, index = %d, ctx = %d",
+ __entry->minor, __entry->start, __entry->end, __entry->index,
+ __entry->ctx)
+);
+
+#endif /* __CODA_TRACE_H__ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index b41bf7e..ccfcf3f 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1871,16 +1871,9 @@ static int vpfe_probe(struct platform_device *pdev)
goto probe_free_ccdc_cfg_mem;
}
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (NULL == vfd) {
- ret = -ENOMEM;
- v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
- goto probe_out_release_irq;
- }
-
+ vfd = &vpfe_dev->video_dev;
/* Initialize field of video device */
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->fops = &vpfe_fops;
vfd->ioctl_ops = &vpfe_ioctl_ops;
vfd->tvnorms = 0;
@@ -1891,14 +1884,12 @@ static int vpfe_probe(struct platform_device *pdev)
(VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
(VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
(VPFE_CAPTURE_VERSION_CODE) & 0xff);
- /* Set video_dev to the video device */
- vpfe_dev->video_dev = vfd;
ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
if (ret) {
v4l2_err(pdev->dev.driver,
"Unable to register v4l2 device.\n");
- goto probe_out_video_release;
+ goto probe_out_release_irq;
}
v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
spin_lock_init(&vpfe_dev->irqlock);
@@ -1914,7 +1905,7 @@ static int vpfe_probe(struct platform_device *pdev)
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
"video_dev=%p\n", &vpfe_dev->video_dev);
vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = video_register_device(vpfe_dev->video_dev,
+ ret = video_register_device(&vpfe_dev->video_dev,
VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -1927,7 +1918,7 @@ static int vpfe_probe(struct platform_device *pdev)
/* set the driver data in platform device */
platform_set_drvdata(pdev, vpfe_dev);
/* set driver private data */
- video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
+ video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev);
i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id);
num_subdevs = vpfe_cfg->num_subdevs;
vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
@@ -1979,12 +1970,9 @@ static int vpfe_probe(struct platform_device *pdev)
probe_sd_out:
kfree(vpfe_dev->sd);
probe_out_video_unregister:
- video_unregister_device(vpfe_dev->video_dev);
+ video_unregister_device(&vpfe_dev->video_dev);
probe_out_v4l2_unregister:
v4l2_device_unregister(&vpfe_dev->v4l2_dev);
-probe_out_video_release:
- if (!video_is_registered(vpfe_dev->video_dev))
- video_device_release(vpfe_dev->video_dev);
probe_out_release_irq:
free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
probe_free_ccdc_cfg_mem:
@@ -2007,7 +1995,7 @@ static int vpfe_remove(struct platform_device *pdev)
free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
kfree(vpfe_dev->sd);
v4l2_device_unregister(&vpfe_dev->v4l2_dev);
- video_unregister_device(vpfe_dev->video_dev);
+ video_unregister_device(&vpfe_dev->video_dev);
kfree(vpfe_dev);
kfree(ccdc_cfg);
return 0;
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index fa0a515..a5f5481 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -712,7 +712,7 @@ static int vpif_set_input(
ch->vpifparams.iface = chan_cfg->vpif_if;
/* update tvnorms from the sub device input info */
- ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
+ ch->video_dev.tvnorms = chan_cfg->inputs[index].input.std;
return 0;
}
@@ -1337,7 +1337,7 @@ static int vpif_probe_complete(void)
struct video_device *vdev;
struct channel_obj *ch;
struct vb2_queue *q;
- int i, j, err, k;
+ int j, err, k;
for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
ch = vpif_obj.dev[j];
@@ -1384,16 +1384,16 @@ static int vpif_probe_complete(void)
INIT_LIST_HEAD(&common->dma_queue);
/* Initialize the video_device structure */
- vdev = ch->video_dev;
+ vdev = &ch->video_dev;
strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
- vdev->release = video_device_release;
+ vdev->release = video_device_release_empty;
vdev->fops = &vpif_fops;
vdev->ioctl_ops = &vpif_ioctl_ops;
vdev->v4l2_dev = &vpif_obj.v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = q;
vdev->lock = &common->lock;
- video_set_drvdata(ch->video_dev, ch);
+ video_set_drvdata(&ch->video_dev, ch);
err = video_register_device(vdev,
VFL_TYPE_GRABBER, (j ? 1 : 0));
if (err)
@@ -1410,14 +1410,9 @@ probe_out:
common = &ch->common[k];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
- video_unregister_device(ch->video_dev);
+ video_unregister_device(&ch->video_dev);
}
kfree(vpif_obj.sd);
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- ch = vpif_obj.dev[i];
- /* Note: does nothing if ch->video_dev == NULL */
- video_device_release(ch->video_dev);
- }
v4l2_device_unregister(&vpif_obj.v4l2_dev);
return err;
@@ -1438,13 +1433,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
static __init int vpif_probe(struct platform_device *pdev)
{
struct vpif_subdev_info *subdevdata;
- int i, j, err;
- int res_idx = 0;
struct i2c_adapter *i2c_adap;
- struct channel_obj *ch;
- struct video_device *vfd;
struct resource *res;
int subdev_count;
+ int res_idx = 0;
+ int i, err;
vpif_dev = &pdev->dev;
@@ -1472,24 +1465,6 @@ static __init int vpif_probe(struct platform_device *pdev)
res_idx++;
}
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (NULL == vfd) {
- for (j = 0; j < i; j++) {
- ch = vpif_obj.dev[j];
- video_device_release(ch->video_dev);
- }
- err = -ENOMEM;
- goto vpif_unregister;
- }
-
- /* Set video_dev to the video device */
- ch->video_dev = vfd;
- }
-
vpif_obj.config = pdev->dev.platform_data;
subdev_count = vpif_obj.config->subdev_count;
@@ -1498,7 +1473,7 @@ static __init int vpif_probe(struct platform_device *pdev)
if (vpif_obj.sd == NULL) {
vpif_err("unable to allocate memory for subdevice pointers\n");
err = -ENOMEM;
- goto vpif_sd_error;
+ goto vpif_unregister;
}
if (!vpif_obj.config->asd_sizes) {
@@ -1541,13 +1516,6 @@ static __init int vpif_probe(struct platform_device *pdev)
probe_subdev_out:
/* free sub devices memory */
kfree(vpif_obj.sd);
-
-vpif_sd_error:
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- ch = vpif_obj.dev[i];
- /* Note: does nothing if ch->video_dev == NULL */
- video_device_release(ch->video_dev);
- }
vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
@@ -1576,7 +1544,7 @@ static int vpif_remove(struct platform_device *device)
common = &ch->common[VPIF_VIDEO_INDEX];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
- video_unregister_device(ch->video_dev);
+ video_unregister_device(&ch->video_dev);
kfree(vpif_obj.dev[i]);
}
return 0;
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
index f65d28d..8b8a663 100644
--- a/drivers/media/platform/davinci/vpif_capture.h
+++ b/drivers/media/platform/davinci/vpif_capture.h
@@ -92,7 +92,7 @@ struct common_obj {
struct channel_obj {
/* Identifies video device for this channel */
- struct video_device *video_dev;
+ struct video_device video_dev;
/* Indicates id of the field which is being displayed */
u32 field_id;
/* flag to indicate whether decoder is initialized */
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 839c24d..682e5d5 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -829,7 +829,7 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg,
ch->sd = sd;
if (chan_cfg->outputs != NULL)
/* update tvnorms from the sub device output info */
- ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std;
+ ch->video_dev.tvnorms = chan_cfg->outputs[index].output.std;
return 0;
}
@@ -1204,16 +1204,16 @@ static int vpif_probe_complete(void)
ch, &ch->video_dev);
/* Initialize the video_device structure */
- vdev = ch->video_dev;
+ vdev = &ch->video_dev;
strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
- vdev->release = video_device_release;
+ vdev->release = video_device_release_empty;
vdev->fops = &vpif_fops;
vdev->ioctl_ops = &vpif_ioctl_ops;
vdev->v4l2_dev = &vpif_obj.v4l2_dev;
vdev->vfl_dir = VFL_DIR_TX;
vdev->queue = q;
vdev->lock = &common->lock;
- video_set_drvdata(ch->video_dev, ch);
+ video_set_drvdata(&ch->video_dev, ch);
err = video_register_device(vdev, VFL_TYPE_GRABBER,
(j ? 3 : 2));
if (err < 0)
@@ -1227,9 +1227,7 @@ probe_out:
ch = vpif_obj.dev[k];
common = &ch->common[k];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
- video_unregister_device(ch->video_dev);
- video_device_release(ch->video_dev);
- ch->video_dev = NULL;
+ video_unregister_device(&ch->video_dev);
}
return err;
}
@@ -1246,13 +1244,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
static __init int vpif_probe(struct platform_device *pdev)
{
struct vpif_subdev_info *subdevdata;
- int i, j = 0, err = 0;
- int res_idx = 0;
struct i2c_adapter *i2c_adap;
- struct channel_obj *ch;
- struct video_device *vfd;
struct resource *res;
int subdev_count;
+ int res_idx = 0;
+ int i, err;
vpif_dev = &pdev->dev;
err = initialize_vpif();
@@ -1281,25 +1277,6 @@ static __init int vpif_probe(struct platform_device *pdev)
res_idx++;
}
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
-
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (vfd == NULL) {
- for (j = 0; j < i; j++) {
- ch = vpif_obj.dev[j];
- video_device_release(ch->video_dev);
- }
- err = -ENOMEM;
- goto vpif_unregister;
- }
-
- /* Set video_dev to the video device */
- ch->video_dev = vfd;
- }
-
vpif_obj.config = pdev->dev.platform_data;
subdev_count = vpif_obj.config->subdev_count;
subdevdata = vpif_obj.config->subdevinfo;
@@ -1308,7 +1285,7 @@ static __init int vpif_probe(struct platform_device *pdev)
if (vpif_obj.sd == NULL) {
vpif_err("unable to allocate memory for subdevice pointers\n");
err = -ENOMEM;
- goto vpif_sd_error;
+ goto vpif_unregister;
}
if (!vpif_obj.config->asd_sizes) {
@@ -1348,12 +1325,6 @@ static __init int vpif_probe(struct platform_device *pdev)
probe_subdev_out:
kfree(vpif_obj.sd);
-vpif_sd_error:
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- ch = vpif_obj.dev[i];
- /* Note: does nothing if ch->video_dev == NULL */
- video_device_release(ch->video_dev);
- }
vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
@@ -1379,9 +1350,7 @@ static int vpif_remove(struct platform_device *device)
common = &ch->common[VPIF_VIDEO_INDEX];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
- video_unregister_device(ch->video_dev);
-
- ch->video_dev = NULL;
+ video_unregister_device(&ch->video_dev);
kfree(vpif_obj.dev[i]);
}
diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h
index 7b21a76..849e0e3 100644
--- a/drivers/media/platform/davinci/vpif_display.h
+++ b/drivers/media/platform/davinci/vpif_display.h
@@ -100,7 +100,7 @@ struct common_obj {
struct channel_obj {
/* V4l2 specific parameters */
- struct video_device *video_dev; /* Identifies video device for
+ struct video_device video_dev; /* Identifies video device for
* this channel */
u32 field_id; /* Indicates id of the field
* which is being displayed */
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 8a2fd8c..cfebf29 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1482,7 +1482,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
}
static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct fimc_fmt *fmt;
@@ -1495,7 +1495,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1504,7 +1504,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1536,7 +1536,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
}
static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1559,7 +1559,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_JPEG;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
return 0;
}
@@ -1602,7 +1602,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1628,10 +1628,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
return 0;
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
f = &ctx->d_frame;
break;
default:
@@ -1657,7 +1657,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
}
static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1675,10 +1675,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
f = &ctx->d_frame;
break;
default:
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 60c7449..5d78f57 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -112,7 +112,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = {
};
static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
const struct fimc_fmt *fmt;
@@ -125,14 +125,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *mf = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
return 0;
}
@@ -162,7 +162,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
}
static void __isp_subdev_try_format(struct fimc_isp *isp,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
@@ -178,7 +178,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
} else {
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- format = v4l2_subdev_get_try_format(fh,
+ format = v4l2_subdev_get_try_format(&isp->subdev, cfg,
FIMC_ISP_SD_PAD_SINK);
else
format = &isp->sink_fmt;
@@ -197,7 +197,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
}
static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
@@ -209,10 +209,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
__func__, fmt->pad, mf->code, mf->width, mf->height);
mutex_lock(&isp->subdev_lock);
- __isp_subdev_try_format(isp, fh, fmt);
+ __isp_subdev_try_format(isp, cfg, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
/* Propagate format to the source pads */
@@ -223,8 +223,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
pad < FIMC_ISP_SD_PADS_NUM; pad++) {
format.pad = pad;
- __isp_subdev_try_format(isp, fh, &format);
- mf = v4l2_subdev_get_try_format(fh, pad);
+ __isp_subdev_try_format(isp, cfg, &format);
+ mf = v4l2_subdev_get_try_format(sd, cfg, pad);
*mf = format.format;
}
}
@@ -236,7 +236,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
isp->sink_fmt = *mf;
format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
- __isp_subdev_try_format(isp, fh, &format);
+ __isp_subdev_try_format(isp, cfg, &format);
isp->src_fmt = format.format;
__is_set_frame_size(is, &isp->src_fmt);
@@ -369,7 +369,7 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt fmt;
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK);
+ format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK);
fmt.colorspace = V4L2_COLORSPACE_SRGB;
fmt.code = fimc_isp_formats[0].mbus_code;
@@ -378,12 +378,12 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
fmt.field = V4L2_FIELD_NONE;
*format = fmt;
- format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO);
+ format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO);
fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
*format = fmt;
- format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA);
+ format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA);
*format = fmt;
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 2510f18..ca6261a 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -568,7 +568,7 @@ static const struct v4l2_file_operations fimc_lite_fops = {
*/
static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct flite_drvdata *dd = fimc->dd;
@@ -592,13 +592,13 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
struct v4l2_rect *rect;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sink_fmt = v4l2_subdev_get_try_format(fh,
+ sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg,
FLITE_SD_PAD_SINK);
mf->code = sink_fmt->code;
mf->colorspace = sink_fmt->colorspace;
- rect = v4l2_subdev_get_try_crop(fh,
+ rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg,
FLITE_SD_PAD_SINK);
} else {
mf->code = sink->fmt->mbus_code;
@@ -1047,7 +1047,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = {
};
static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
const struct fimc_fmt *fmt;
@@ -1060,16 +1060,17 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
- struct v4l2_subdev_fh *fh, unsigned int pad)
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg, unsigned int pad)
{
if (pad != FLITE_SD_PAD_SINK)
pad = FLITE_SD_PAD_SOURCE_DMA;
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(sd, cfg, pad);
}
static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1077,7 +1078,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
struct flite_frame *f = &fimc->inp_frame;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
+ mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1100,7 +1101,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1122,17 +1123,17 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
return -EBUSY;
}
- ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt);
+ ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *src_fmt;
- mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
+ mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
*mf = fmt->format;
if (fmt->pad == FLITE_SD_PAD_SINK) {
unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
- src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad);
+ src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad);
*src_fmt = *mf;
}
@@ -1160,7 +1161,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1172,7 +1173,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
return 0;
}
@@ -1195,7 +1196,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1209,7 +1210,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
fimc_lite_try_crop(fimc, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
+ *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
} else {
unsigned long flags;
spin_lock_irqsave(&fimc->slock, flags);
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 2504aa8..d74e1be 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -540,7 +540,7 @@ unlock:
}
static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5pcsis_formats))
@@ -568,23 +568,23 @@ static struct csis_pix_format const *s5pcsis_try_format(
}
static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
- struct csis_state *state, struct v4l2_subdev_fh *fh,
+ struct csis_state *state, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
+ return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL;
return &state->format;
}
-static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct csis_state *state = sd_to_csis_state(sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *mf;
- mf = __s5pcsis_get_format(state, fh, fmt->which);
+ mf = __s5pcsis_get_format(state, cfg, fmt->which);
if (fmt->pad == CSIS_PAD_SOURCE) {
if (mf) {
@@ -605,13 +605,13 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct csis_state *state = sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *mf;
- mf = __s5pcsis_get_format(state, fh, fmt->which);
+ mf = __s5pcsis_get_format(state, cfg, fmt->which);
if (!mf)
return -EINVAL;
@@ -651,7 +651,7 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd)
static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
format->colorspace = V4L2_COLORSPACE_JPEG;
format->code = s5pcsis_formats[0].code;
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index b70c1ae..92d9549 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -127,7 +127,7 @@ static struct deinterlace_fmt *find_format(struct v4l2_format *f)
struct deinterlace_dev {
struct v4l2_device v4l2_dev;
- struct video_device *vfd;
+ struct video_device vfd;
atomic_t busy;
struct mutex dev_mutex;
@@ -983,7 +983,7 @@ static struct video_device deinterlace_videodev = {
.fops = &deinterlace_fops,
.ioctl_ops = &deinterlace_ioctl_ops,
.minor = -1,
- .release = video_device_release,
+ .release = video_device_release_empty,
.vfl_dir = VFL_DIR_M2M,
};
@@ -1026,13 +1026,7 @@ static int deinterlace_probe(struct platform_device *pdev)
atomic_set(&pcdev->busy, 0);
mutex_init(&pcdev->dev_mutex);
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
- ret = -ENOMEM;
- goto unreg_dev;
- }
-
+ vfd = &pcdev->vfd;
*vfd = deinterlace_videodev;
vfd->lock = &pcdev->dev_mutex;
vfd->v4l2_dev = &pcdev->v4l2_dev;
@@ -1040,12 +1034,11 @@ static int deinterlace_probe(struct platform_device *pdev)
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
- goto rel_vdev;
+ goto unreg_dev;
}
video_set_drvdata(vfd, pcdev);
snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name);
- pcdev->vfd = vfd;
v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
" Device registered as /dev/video%d\n", vfd->num);
@@ -1069,11 +1062,9 @@ static int deinterlace_probe(struct platform_device *pdev)
v4l2_m2m_release(pcdev->m2m_dev);
err_m2m:
- video_unregister_device(pcdev->vfd);
+ video_unregister_device(&pcdev->vfd);
err_ctx:
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-rel_vdev:
- video_device_release(vfd);
unreg_dev:
v4l2_device_unregister(&pcdev->v4l2_dev);
rel_dma:
@@ -1088,7 +1079,7 @@ static int deinterlace_remove(struct platform_device *pdev)
v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
v4l2_m2m_release(pcdev->m2m_dev);
- video_unregister_device(pcdev->vfd);
+ video_unregister_device(&pcdev->vfd);
v4l2_device_unregister(&pcdev->v4l2_dev);
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
dma_release_channel(pcdev->dma_chan);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index dd5b141..9c64b5d 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1568,24 +1568,64 @@ static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
struct v4l2_frmsizeenum *sizes)
{
struct mcam_camera *cam = priv;
+ struct mcam_format_struct *f;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = sizes->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
+ f = mcam_find_format(sizes->pixel_format);
+ if (f->pixelformat != sizes->pixel_format)
+ return -EINVAL;
+ fse.code = f->mbus_code;
mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, enum_framesizes, sizes);
+ ret = sensor_call(cam, pad, enum_frame_size, NULL, &fse);
mutex_unlock(&cam->s_mutex);
- return ret;
+ if (ret)
+ return ret;
+ if (fse.min_width == fse.max_width &&
+ fse.min_height == fse.max_height) {
+ sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ sizes->discrete.width = fse.min_width;
+ sizes->discrete.height = fse.min_height;
+ return 0;
+ }
+ sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ sizes->stepwise.min_width = fse.min_width;
+ sizes->stepwise.max_width = fse.max_width;
+ sizes->stepwise.min_height = fse.min_height;
+ sizes->stepwise.max_height = fse.max_height;
+ sizes->stepwise.step_width = 1;
+ sizes->stepwise.step_height = 1;
+ return 0;
}
static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv,
struct v4l2_frmivalenum *interval)
{
struct mcam_camera *cam = priv;
+ struct mcam_format_struct *f;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = interval->index,
+ .width = interval->width,
+ .height = interval->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
+ f = mcam_find_format(interval->pixel_format);
+ if (f->pixelformat != interval->pixel_format)
+ return -EINVAL;
+ fie.code = f->mbus_code;
mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, enum_frameintervals, interval);
+ ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie);
mutex_unlock(&cam->s_mutex);
- return ret;
+ if (ret)
+ return ret;
+ interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ interval->discrete = fie.interval;
+ return 0;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index ba2d8f9..17b189a 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -1978,7 +1978,7 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
vout->cropped_offset = 0;
if (ovid->rotation_type == VOUT_ROT_VRFB) {
- int static_vrfb_allocation = (vid_num == 0) ?
+ bool static_vrfb_allocation = (vid_num == 0) ?
vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
static_vrfb_allocation);
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index aa39306..c6e2527 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -21,6 +21,7 @@
#include "omap_voutdef.h"
#include "omap_voutlib.h"
+#include "omap_vout_vrfb.h"
#define OMAP_DMA_NO_DEVICE 0
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
index 4c23148..c976975 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.h
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
@@ -15,7 +15,7 @@
#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
- u32 static_vrfb_allocation);
+ bool static_vrfb_allocation);
void omap_vout_release_vrfb(struct omap_vout_device *vout);
int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
unsigned int *count, unsigned int startindex);
@@ -25,7 +25,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
#else
static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { };
static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
- u32 static_vrfb_allocation)
+ bool static_vrfb_allocation)
{ return 0; };
static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { };
static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index deca809..18d0a87 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -51,6 +51,7 @@
#include <linux/dma-mapping.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/omap-iommu.h>
#include <linux/platform_device.h>
@@ -63,6 +64,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
#include "isp.h"
#include "ispreg.h"
@@ -85,35 +87,45 @@ static void isp_restore_ctx(struct isp_device *isp);
static const struct isp_res_mapping isp_res_maps[] = {
{
.isp_rev = ISP_REVISION_2_0,
- .map = 1 << OMAP3_ISP_IOMEM_MAIN |
- 1 << OMAP3_ISP_IOMEM_CCP2 |
- 1 << OMAP3_ISP_IOMEM_CCDC |
- 1 << OMAP3_ISP_IOMEM_HIST |
- 1 << OMAP3_ISP_IOMEM_H3A |
- 1 << OMAP3_ISP_IOMEM_PREV |
- 1 << OMAP3_ISP_IOMEM_RESZ |
- 1 << OMAP3_ISP_IOMEM_SBL |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY2 |
- 1 << OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE,
+ .offset = {
+ /* first MMIO area */
+ 0x0000, /* base, len 0x0070 */
+ 0x0400, /* ccp2, len 0x01f0 */
+ 0x0600, /* ccdc, len 0x00a8 */
+ 0x0a00, /* hist, len 0x0048 */
+ 0x0c00, /* h3a, len 0x0060 */
+ 0x0e00, /* preview, len 0x00a0 */
+ 0x1000, /* resizer, len 0x00ac */
+ 0x1200, /* sbl, len 0x00fc */
+ /* second MMIO area */
+ 0x0000, /* csi2a, len 0x0170 */
+ 0x0170, /* csiphy2, len 0x000c */
+ },
+ .syscon_offset = 0xdc,
+ .phy_type = ISP_PHY_TYPE_3430,
},
{
.isp_rev = ISP_REVISION_15_0,
- .map = 1 << OMAP3_ISP_IOMEM_MAIN |
- 1 << OMAP3_ISP_IOMEM_CCP2 |
- 1 << OMAP3_ISP_IOMEM_CCDC |
- 1 << OMAP3_ISP_IOMEM_HIST |
- 1 << OMAP3_ISP_IOMEM_H3A |
- 1 << OMAP3_ISP_IOMEM_PREV |
- 1 << OMAP3_ISP_IOMEM_RESZ |
- 1 << OMAP3_ISP_IOMEM_SBL |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY2 |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
- 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY1 |
- 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2 |
- 1 << OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL,
+ .offset = {
+ /* first MMIO area */
+ 0x0000, /* base, len 0x0070 */
+ 0x0400, /* ccp2, len 0x01f0 */
+ 0x0600, /* ccdc, len 0x00a8 */
+ 0x0a00, /* hist, len 0x0048 */
+ 0x0c00, /* h3a, len 0x0060 */
+ 0x0e00, /* preview, len 0x00a0 */
+ 0x1000, /* resizer, len 0x00ac */
+ 0x1200, /* sbl, len 0x00fc */
+ /* second MMIO area */
+ 0x0000, /* csi2a, len 0x0170 (1st area) */
+ 0x0170, /* csiphy2, len 0x000c */
+ 0x01c0, /* csi2a, len 0x0040 (2nd area) */
+ 0x0400, /* csi2c, len 0x0170 (1st area) */
+ 0x0570, /* csiphy1, len 0x000c */
+ 0x05c0, /* csi2c, len 0x0040 (2nd area) */
+ },
+ .syscon_offset = 0x2f0,
+ .phy_type = ISP_PHY_TYPE_3630,
},
};
@@ -279,9 +291,20 @@ static const struct clk_init_data isp_xclk_init_data = {
.num_parents = 1,
};
+static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data)
+{
+ unsigned int idx = clkspec->args[0];
+ struct isp_device *isp = data;
+
+ if (idx >= ARRAY_SIZE(isp->xclks))
+ return ERR_PTR(-ENOENT);
+
+ return isp->xclks[idx].clk;
+}
+
static int isp_xclk_init(struct isp_device *isp)
{
- struct isp_platform_data *pdata = isp->pdata;
+ struct device_node *np = isp->dev->of_node;
struct clk_init_data init;
unsigned int i;
@@ -311,37 +334,27 @@ static int isp_xclk_init(struct isp_device *isp)
xclk->clk = clk_register(NULL, &xclk->hw);
if (IS_ERR(xclk->clk))
return PTR_ERR(xclk->clk);
-
- if (pdata->xclks[i].con_id == NULL &&
- pdata->xclks[i].dev_id == NULL)
- continue;
-
- xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL);
- if (xclk->lookup == NULL)
- return -ENOMEM;
-
- xclk->lookup->con_id = pdata->xclks[i].con_id;
- xclk->lookup->dev_id = pdata->xclks[i].dev_id;
- xclk->lookup->clk = xclk->clk;
-
- clkdev_add(xclk->lookup);
}
+ if (np)
+ of_clk_add_provider(np, isp_xclk_src_get, isp);
+
return 0;
}
static void isp_xclk_cleanup(struct isp_device *isp)
{
+ struct device_node *np = isp->dev->of_node;
unsigned int i;
+ if (np)
+ of_clk_del_provider(np);
+
for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) {
struct isp_xclk *xclk = &isp->xclks[i];
if (!IS_ERR(xclk->clk))
clk_unregister(xclk->clk);
-
- if (xclk->lookup)
- clkdev_drop(xclk->lookup);
}
}
@@ -422,7 +435,7 @@ static void isp_core_init(struct isp_device *isp, int idle)
*/
void omap3isp_configure_bridge(struct isp_device *isp,
enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata,
+ const struct isp_parallel_cfg *parcfg,
unsigned int shift, unsigned int bridge)
{
u32 ispctrl_val;
@@ -437,8 +450,8 @@ void omap3isp_configure_bridge(struct isp_device *isp,
switch (input) {
case CCDC_INPUT_PARALLEL:
ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
- ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
- shift += pdata->data_lane_shift * 2;
+ ispctrl_val |= parcfg->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
+ shift += parcfg->data_lane_shift * 2;
break;
case CCDC_INPUT_CSI2A:
@@ -1784,58 +1797,121 @@ static void isp_unregister_entities(struct isp_device *isp)
}
/*
- * isp_register_subdev_group - Register a group of subdevices
+ * isp_register_subdev - Register a sub-device
* @isp: OMAP3 ISP device
- * @board_info: I2C subdevs board information array
+ * @isp_subdev: platform data related to a sub-device
*
- * Register all I2C subdevices in the board_info array. The array must be
- * terminated by a NULL entry, and the first entry must be the sensor.
+ * Register an I2C sub-device which has not been registered by other
+ * means (such as the Device Tree).
*
- * Return a pointer to the sensor media entity if it has been successfully
+ * Return a pointer to the sub-device if it has been successfully
* registered, or NULL otherwise.
*/
static struct v4l2_subdev *
-isp_register_subdev_group(struct isp_device *isp,
- struct isp_subdev_i2c_board_info *board_info)
+isp_register_subdev(struct isp_device *isp,
+ struct isp_platform_subdev *isp_subdev)
{
- struct v4l2_subdev *sensor = NULL;
- unsigned int first;
+ struct i2c_adapter *adapter;
+ struct v4l2_subdev *sd;
- if (board_info->board_info == NULL)
+ if (isp_subdev->board_info == NULL)
return NULL;
- for (first = 1; board_info->board_info; ++board_info, first = 0) {
- struct v4l2_subdev *subdev;
- struct i2c_adapter *adapter;
+ adapter = i2c_get_adapter(isp_subdev->i2c_adapter_id);
+ if (adapter == NULL) {
+ dev_err(isp->dev,
+ "%s: Unable to get I2C adapter %d for device %s\n",
+ __func__, isp_subdev->i2c_adapter_id,
+ isp_subdev->board_info->type);
+ return NULL;
+ }
- adapter = i2c_get_adapter(board_info->i2c_adapter_id);
- if (adapter == NULL) {
- dev_err(isp->dev, "%s: Unable to get I2C adapter %d for "
- "device %s\n", __func__,
- board_info->i2c_adapter_id,
- board_info->board_info->type);
- continue;
- }
+ sd = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
+ isp_subdev->board_info, NULL);
+ if (sd == NULL) {
+ dev_err(isp->dev, "%s: Unable to register subdev %s\n",
+ __func__, isp_subdev->board_info->type);
+ return NULL;
+ }
- subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
- board_info->board_info, NULL);
- if (subdev == NULL) {
- dev_err(isp->dev, "%s: Unable to register subdev %s\n",
- __func__, board_info->board_info->type);
- continue;
- }
+ return sd;
+}
+
+static int isp_link_entity(
+ struct isp_device *isp, struct media_entity *entity,
+ enum isp_interface_type interface)
+{
+ struct media_entity *input;
+ unsigned int flags;
+ unsigned int pad;
+ unsigned int i;
+
+ /* Connect the sensor to the correct interface module.
+ * Parallel sensors are connected directly to the CCDC, while
+ * serial sensors are connected to the CSI2a, CCP2b or CSI2c
+ * receiver through CSIPHY1 or CSIPHY2.
+ */
+ switch (interface) {
+ case ISP_INTERFACE_PARALLEL:
+ input = &isp->isp_ccdc.subdev.entity;
+ pad = CCDC_PAD_SINK;
+ flags = 0;
+ break;
+
+ case ISP_INTERFACE_CSI2A_PHY2:
+ input = &isp->isp_csi2a.subdev.entity;
+ pad = CSI2_PAD_SINK;
+ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
+ break;
+
+ case ISP_INTERFACE_CCP2B_PHY1:
+ case ISP_INTERFACE_CCP2B_PHY2:
+ input = &isp->isp_ccp2.subdev.entity;
+ pad = CCP2_PAD_SINK;
+ flags = 0;
+ break;
+
+ case ISP_INTERFACE_CSI2C_PHY1:
+ input = &isp->isp_csi2c.subdev.entity;
+ pad = CSI2_PAD_SINK;
+ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
+ break;
- if (first)
- sensor = subdev;
+ default:
+ dev_err(isp->dev, "%s: invalid interface type %u\n", __func__,
+ interface);
+ return -EINVAL;
+ }
+
+ /*
+ * Not all interfaces are available on all revisions of the
+ * ISP. The sub-devices of those interfaces aren't initialised
+ * in such a case. Check this by ensuring the num_pads is
+ * non-zero.
+ */
+ if (!input->num_pads) {
+ dev_err(isp->dev, "%s: invalid input %u\n", entity->name,
+ interface);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < entity->num_pads; i++) {
+ if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE)
+ break;
+ }
+ if (i == entity->num_pads) {
+ dev_err(isp->dev, "%s: no source pad in external entity\n",
+ __func__);
+ return -EINVAL;
}
- return sensor;
+ return media_entity_create_link(entity, i, input, pad, flags);
}
static int isp_register_entities(struct isp_device *isp)
{
struct isp_platform_data *pdata = isp->pdata;
- struct isp_v4l2_subdevs_group *subdevs;
+ struct isp_platform_subdev *isp_subdev;
int ret;
isp->media_dev.dev = isp->dev;
@@ -1892,74 +1968,31 @@ static int isp_register_entities(struct isp_device *isp)
if (ret < 0)
goto done;
+ /*
+ * Device Tree --- the external sub-devices will be registered
+ * later. The same goes for the sub-device node registration.
+ */
+ if (isp->dev->of_node)
+ return 0;
+
/* Register external entities */
- for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
- struct v4l2_subdev *sensor;
- struct media_entity *input;
- unsigned int flags;
- unsigned int pad;
- unsigned int i;
-
- sensor = isp_register_subdev_group(isp, subdevs->subdevs);
- if (sensor == NULL)
- continue;
+ for (isp_subdev = pdata ? pdata->subdevs : NULL;
+ isp_subdev && isp_subdev->board_info; isp_subdev++) {
+ struct v4l2_subdev *sd;
- sensor->host_priv = subdevs;
+ sd = isp_register_subdev(isp, isp_subdev);
- /* Connect the sensor to the correct interface module. Parallel
- * sensors are connected directly to the CCDC, while serial
- * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
- * through CSIPHY1 or CSIPHY2.
+ /*
+ * No bus information --- this is either a flash or a
+ * lens subdev.
*/
- switch (subdevs->interface) {
- case ISP_INTERFACE_PARALLEL:
- input = &isp->isp_ccdc.subdev.entity;
- pad = CCDC_PAD_SINK;
- flags = 0;
- break;
-
- case ISP_INTERFACE_CSI2A_PHY2:
- input = &isp->isp_csi2a.subdev.entity;
- pad = CSI2_PAD_SINK;
- flags = MEDIA_LNK_FL_IMMUTABLE
- | MEDIA_LNK_FL_ENABLED;
- break;
-
- case ISP_INTERFACE_CCP2B_PHY1:
- case ISP_INTERFACE_CCP2B_PHY2:
- input = &isp->isp_ccp2.subdev.entity;
- pad = CCP2_PAD_SINK;
- flags = 0;
- break;
-
- case ISP_INTERFACE_CSI2C_PHY1:
- input = &isp->isp_csi2c.subdev.entity;
- pad = CSI2_PAD_SINK;
- flags = MEDIA_LNK_FL_IMMUTABLE
- | MEDIA_LNK_FL_ENABLED;
- break;
-
- default:
- dev_err(isp->dev, "%s: invalid interface type %u\n",
- __func__, subdevs->interface);
- ret = -EINVAL;
- goto done;
- }
+ if (!sd || !isp_subdev->bus)
+ continue;
- for (i = 0; i < sensor->entity.num_pads; i++) {
- if (sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
- break;
- }
- if (i == sensor->entity.num_pads) {
- dev_err(isp->dev,
- "%s: no source pad in external entity\n",
- __func__);
- ret = -EINVAL;
- goto done;
- }
+ sd->host_priv = isp_subdev->bus;
- ret = media_entity_create_link(&sensor->entity, i, input, pad,
- flags);
+ ret = isp_link_entity(isp, &sd->entity,
+ isp_subdev->bus->interface);
if (ret < 0)
goto done;
}
@@ -1967,8 +2000,10 @@ static int isp_register_entities(struct isp_device *isp)
ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
done:
- if (ret < 0)
+ if (ret < 0) {
isp_unregister_entities(isp);
+ v4l2_async_notifier_unregister(&isp->notifier);
+ }
return ret;
}
@@ -2183,6 +2218,7 @@ static int isp_remove(struct platform_device *pdev)
{
struct isp_device *isp = platform_get_drvdata(pdev);
+ v4l2_async_notifier_unregister(&isp->notifier);
isp_unregister_entities(isp);
isp_cleanup_modules(isp);
isp_xclk_cleanup(isp);
@@ -2194,26 +2230,156 @@ static int isp_remove(struct platform_device *pdev)
return 0;
}
-static int isp_map_mem_resource(struct platform_device *pdev,
- struct isp_device *isp,
- enum isp_mem_resources res)
+enum isp_of_phy {
+ ISP_OF_PHY_PARALLEL = 0,
+ ISP_OF_PHY_CSIPHY1,
+ ISP_OF_PHY_CSIPHY2,
+};
+
+static int isp_of_parse_node(struct device *dev, struct device_node *node,
+ struct isp_async_subdev *isd)
{
- struct resource *mem;
+ struct isp_bus_cfg *buscfg = &isd->bus;
+ struct v4l2_of_endpoint vep;
+ unsigned int i;
- /* request the mem region for the camera registers */
+ v4l2_of_parse_endpoint(node, &vep);
+
+ dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name,
+ vep.base.port);
+
+ switch (vep.base.port) {
+ case ISP_OF_PHY_PARALLEL:
+ buscfg->interface = ISP_INTERFACE_PARALLEL;
+ buscfg->bus.parallel.data_lane_shift =
+ vep.bus.parallel.data_shift;
+ buscfg->bus.parallel.clk_pol =
+ !!(vep.bus.parallel.flags
+ & V4L2_MBUS_PCLK_SAMPLE_FALLING);
+ buscfg->bus.parallel.hs_pol =
+ !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+ buscfg->bus.parallel.vs_pol =
+ !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+ buscfg->bus.parallel.fld_pol =
+ !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
+ buscfg->bus.parallel.data_pol =
+ !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
+ break;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
+ case ISP_OF_PHY_CSIPHY1:
+ case ISP_OF_PHY_CSIPHY2:
+ /* FIXME: always assume CSI-2 for now. */
+ switch (vep.base.port) {
+ case ISP_OF_PHY_CSIPHY1:
+ buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
+ break;
+ case ISP_OF_PHY_CSIPHY2:
+ buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
+ break;
+ }
+ buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane;
+ buscfg->bus.csi2.lanecfg.clk.pol =
+ vep.bus.mipi_csi2.lane_polarities[0];
+ dev_dbg(dev, "clock lane polarity %u, pos %u\n",
+ buscfg->bus.csi2.lanecfg.clk.pol,
+ buscfg->bus.csi2.lanecfg.clk.pos);
+
+ for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) {
+ buscfg->bus.csi2.lanecfg.data[i].pos =
+ vep.bus.mipi_csi2.data_lanes[i];
+ buscfg->bus.csi2.lanecfg.data[i].pol =
+ vep.bus.mipi_csi2.lane_polarities[i + 1];
+ dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i,
+ buscfg->bus.csi2.lanecfg.data[i].pol,
+ buscfg->bus.csi2.lanecfg.data[i].pos);
+ }
- /* map the region */
- isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem);
- if (IS_ERR(isp->mmio_base[res]))
- return PTR_ERR(isp->mmio_base[res]);
+ /*
+ * FIXME: now we assume the CRC is always there.
+ * Implement a way to obtain this information from the
+ * sensor. Frame descriptors, perhaps?
+ */
+ buscfg->bus.csi2.crc = 1;
+ break;
- isp->mmio_base_phys[res] = mem->start;
+ default:
+ dev_warn(dev, "%s: invalid interface %u\n", node->full_name,
+ vep.base.port);
+ break;
+ }
return 0;
}
+static int isp_of_parse_nodes(struct device *dev,
+ struct v4l2_async_notifier *notifier)
+{
+ struct device_node *node = NULL;
+
+ notifier->subdevs = devm_kcalloc(
+ dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
+ if (!notifier->subdevs)
+ return -ENOMEM;
+
+ while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
+ (node = of_graph_get_next_endpoint(dev->of_node, node))) {
+ struct isp_async_subdev *isd;
+
+ isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
+ if (!isd) {
+ of_node_put(node);
+ return -ENOMEM;
+ }
+
+ notifier->subdevs[notifier->num_subdevs] = &isd->asd;
+
+ if (isp_of_parse_node(dev, node, isd)) {
+ of_node_put(node);
+ return -EINVAL;
+ }
+
+ isd->asd.match.of.node = of_graph_get_remote_port_parent(node);
+ of_node_put(node);
+ if (!isd->asd.match.of.node) {
+ dev_warn(dev, "bad remote port parent\n");
+ return -EINVAL;
+ }
+
+ isd->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ notifier->num_subdevs++;
+ }
+
+ return notifier->num_subdevs;
+}
+
+static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct isp_device *isp = container_of(async, struct isp_device,
+ notifier);
+ struct isp_async_subdev *isd =
+ container_of(asd, struct isp_async_subdev, asd);
+ int ret;
+
+ ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface);
+ if (ret < 0)
+ return ret;
+
+ isd->sd = subdev;
+ isd->sd->host_priv = &isd->bus;
+
+ return ret;
+}
+
+static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
+{
+ struct isp_device *isp = container_of(async, struct isp_device,
+ notifier);
+
+ return v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+}
+
/*
* isp_probe - Probe ISP platform device
* @pdev: Pointer to ISP platform device
@@ -2227,47 +2393,86 @@ static int isp_map_mem_resource(struct platform_device *pdev,
*/
static int isp_probe(struct platform_device *pdev)
{
- struct isp_platform_data *pdata = pdev->dev.platform_data;
struct isp_device *isp;
+ struct resource *mem;
int ret;
int i, m;
- if (pdata == NULL)
- return -EINVAL;
-
isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
if (!isp) {
dev_err(&pdev->dev, "could not allocate memory\n");
return -ENOMEM;
}
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+ ret = of_property_read_u32(pdev->dev.of_node, "ti,phy-type",
+ &isp->phy_type);
+ if (ret)
+ return ret;
+
+ isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "syscon");
+ if (IS_ERR(isp->syscon))
+ return PTR_ERR(isp->syscon);
+
+ ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1,
+ &isp->syscon_offset);
+ if (ret)
+ return ret;
+
+ ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier);
+ if (ret < 0)
+ return ret;
+ ret = v4l2_async_notifier_register(&isp->v4l2_dev,
+ &isp->notifier);
+ if (ret)
+ return ret;
+ } else {
+ isp->pdata = pdev->dev.platform_data;
+ isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0");
+ if (IS_ERR(isp->syscon))
+ return PTR_ERR(isp->syscon);
+ dev_warn(&pdev->dev,
+ "Platform data support is deprecated! Please move to DT now!\n");
+ }
+
isp->autoidle = autoidle;
mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock);
isp->dev = &pdev->dev;
- isp->pdata = pdata;
isp->ref_count = 0;
ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32));
if (ret)
- return ret;
+ goto error;
platform_set_drvdata(pdev, isp);
/* Regulators */
- isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY1");
- isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY2");
+ isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1");
+ isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2");
/* Clocks
*
* The ISP clock tree is revision-dependent. We thus need to enable ICLK
* manually to read the revision before calling __omap3isp_get().
+ *
+ * Start by mapping the ISP MMIO area, which is in two pieces.
+ * The ISP IOMMU is in between. Map both now, and fill in the
+ * ISP revision specific portions a little later in the
+ * function.
*/
- ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
- if (ret < 0)
- goto error;
+ for (i = 0; i < 2; i++) {
+ unsigned int map_idx = i ? OMAP3_ISP_IOMEM_CSI2A_REGS1 : 0;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ isp->mmio_base[map_idx] =
+ devm_ioremap_resource(isp->dev, mem);
+ if (IS_ERR(isp->mmio_base[map_idx]))
+ return PTR_ERR(isp->mmio_base[map_idx]);
+ }
ret = isp_get_clocks(isp);
if (ret < 0)
@@ -2308,14 +2513,23 @@ static int isp_probe(struct platform_device *pdev)
goto error_isp;
}
- for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp_res_maps[m].map & 1 << i) {
- ret = isp_map_mem_resource(pdev, isp, i);
- if (ret)
- goto error_isp;
- }
+ if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) {
+ isp->syscon_offset = isp_res_maps[m].syscon_offset;
+ isp->phy_type = isp_res_maps[m].phy_type;
}
+ for (i = 1; i < OMAP3_ISP_IOMEM_CSI2A_REGS1; i++)
+ isp->mmio_base[i] =
+ isp->mmio_base[0] + isp_res_maps[m].offset[i];
+
+ for (i = OMAP3_ISP_IOMEM_CSIPHY2; i < OMAP3_ISP_IOMEM_LAST; i++)
+ isp->mmio_base[i] =
+ isp->mmio_base[OMAP3_ISP_IOMEM_CSI2A_REGS1]
+ + isp_res_maps[m].offset[i];
+
+ isp->mmio_hist_base_phys =
+ mem->start + isp_res_maps[m].offset[OMAP3_ISP_IOMEM_HIST];
+
/* IOMMU */
ret = isp_attach_iommu(isp);
if (ret < 0) {
@@ -2343,6 +2557,9 @@ static int isp_probe(struct platform_device *pdev)
if (ret < 0)
goto error_iommu;
+ isp->notifier.bound = isp_subdev_notifier_bound;
+ isp->notifier.complete = isp_subdev_notifier_complete;
+
ret = isp_register_entities(isp);
if (ret < 0)
goto error_modules;
@@ -2378,6 +2595,11 @@ static struct platform_device_id omap3isp_id_table[] = {
};
MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
+static const struct of_device_id omap3isp_of_table[] = {
+ { .compatible = "ti,omap3-isp" },
+ { },
+};
+
static struct platform_driver omap3isp_driver = {
.probe = isp_probe,
.remove = isp_remove,
@@ -2385,6 +2607,7 @@ static struct platform_driver omap3isp_driver = {
.driver = {
.name = "omap3isp",
.pm = &omap3isp_pm_ops,
+ .of_match_table = omap3isp_of_table,
},
};
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index cfdfc87..e579943 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -18,6 +18,7 @@
#define OMAP3_ISP_CORE_H
#include <media/omap3isp.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
@@ -59,8 +60,6 @@ enum isp_mem_resources {
OMAP3_ISP_IOMEM_CSI2C_REGS1,
OMAP3_ISP_IOMEM_CSIPHY1,
OMAP3_ISP_IOMEM_CSI2C_REGS2,
- OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE,
- OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL,
OMAP3_ISP_IOMEM_LAST
};
@@ -93,14 +92,25 @@ enum isp_subclk_resource {
/* ISP2P: OMAP 36xx */
#define ISP_REVISION_15_0 0xF0
+#define ISP_PHY_TYPE_3430 0
+#define ISP_PHY_TYPE_3630 1
+
+struct regmap;
+
/*
* struct isp_res_mapping - Map ISP io resources to ISP revision.
* @isp_rev: ISP_REVISION_x_x
- * @map: bitmap for enum isp_mem_resources
+ * @offset: register offsets of various ISP sub-blocks
+ * @syscon_offset: offset of the syscon register for 343x / 3630
+ * (CONTROL_CSIRXFE / CONTROL_CAMERA_PHY_CTRL, respectively)
+ * from the syscon base address
+ * @phy_type: ISP_PHY_TYPE_{3430,3630}
*/
struct isp_res_mapping {
u32 isp_rev;
- u32 map;
+ u32 offset[OMAP3_ISP_IOMEM_LAST];
+ u32 syscon_offset;
+ u32 phy_type;
};
/*
@@ -122,7 +132,6 @@ enum isp_xclk_id {
struct isp_xclk {
struct isp_device *isp;
struct clk_hw hw;
- struct clk_lookup *lookup;
struct clk *clk;
enum isp_xclk_id id;
@@ -138,8 +147,11 @@ struct isp_xclk {
* @irq_num: Currently used IRQ number.
* @mmio_base: Array with kernel base addresses for ioremapped ISP register
* regions.
- * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
- * regions.
+ * @mmio_hist_base_phys: Physical L4 bus address for ISP hist block register
+ * region.
+ * @syscon: Regmap for the syscon register space
+ * @syscon_offset: Offset of the CSIPHY control register in syscon
+ * @phy_type: ISP_PHY_TYPE_{3430,3630}
* @mapping: IOMMU mapping
* @stat_lock: Spinlock for handling statistics
* @isp_mutex: Mutex for serializing requests to ISP.
@@ -166,6 +178,7 @@ struct isp_xclk {
*/
struct isp_device {
struct v4l2_device v4l2_dev;
+ struct v4l2_async_notifier notifier;
struct media_device media_dev;
struct device *dev;
u32 revision;
@@ -175,7 +188,10 @@ struct isp_device {
unsigned int irq_num;
void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
- unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
+ unsigned long mmio_hist_base_phys;
+ struct regmap *syscon;
+ u32 syscon_offset;
+ u32 phy_type;
struct dma_iommu_mapping *mapping;
@@ -209,6 +225,15 @@ struct isp_device {
unsigned int sbl_resources;
unsigned int subclk_resources;
+
+#define ISP_MAX_SUBDEVS 8
+ struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS];
+};
+
+struct isp_async_subdev {
+ struct v4l2_subdev *sd;
+ struct isp_bus_cfg bus;
+ struct v4l2_async_subdev asd;
};
#define v4l2_dev_to_isp_device(dev) \
@@ -229,7 +254,7 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe);
void omap3isp_configure_bridge(struct isp_device *isp,
enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata,
+ const struct isp_parallel_cfg *buscfg,
unsigned int shift, unsigned int bridge);
struct isp_device *omap3isp_get(struct isp_device *isp);
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 587489a..a6a61cc 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -32,7 +32,7 @@
#define CCDC_MIN_HEIGHT 32
static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which);
static const unsigned int ccdc_fmts[] = {
@@ -958,11 +958,11 @@ void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
/*
* ccdc_config_sync_if - Set CCDC sync interface configuration
* @ccdc: Pointer to ISP CCDC device.
- * @pdata: Parallel interface platform data (may be NULL)
+ * @parcfg: Parallel interface platform data (may be NULL)
* @data_size: Data size
*/
static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
- struct isp_parallel_platform_data *pdata,
+ struct isp_parallel_cfg *parcfg,
unsigned int data_size)
{
struct isp_device *isp = to_isp_device(ccdc);
@@ -1000,19 +1000,19 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
break;
}
- if (pdata && pdata->data_pol)
+ if (parcfg && parcfg->data_pol)
syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
- if (pdata && pdata->hs_pol)
+ if (parcfg && parcfg->hs_pol)
syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
/* The polarity of the vertical sync signal output by the BT.656
* decoder is not documented and seems to be active low.
*/
- if ((pdata && pdata->vs_pol) || ccdc->bt656)
+ if ((parcfg && parcfg->vs_pol) || ccdc->bt656)
syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
- if (pdata && pdata->fld_pol)
+ if (parcfg && parcfg->fld_pol)
syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1115,7 +1115,7 @@ static const u32 ccdc_sgbrg_pattern =
static void ccdc_configure(struct isp_ccdc_device *ccdc)
{
struct isp_device *isp = to_isp_device(ccdc);
- struct isp_parallel_platform_data *pdata = NULL;
+ struct isp_parallel_cfg *parcfg = NULL;
struct v4l2_subdev *sensor;
struct v4l2_mbus_framefmt *format;
const struct v4l2_rect *crop;
@@ -1145,7 +1145,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
if (!ret)
ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
- pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
+ parcfg = &((struct isp_bus_cfg *)sensor->host_priv)
->bus.parallel;
}
@@ -1175,10 +1175,10 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
else
bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
- omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
+ omap3isp_configure_bridge(isp, ccdc->input, parcfg, shift, bridge);
/* Configure the sync interface. */
- ccdc_config_sync_if(ccdc, pdata, depth_out);
+ ccdc_config_sync_if(ccdc, parcfg, depth_out);
syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1935,21 +1935,21 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
}
static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad);
else
return &ccdc->formats[pad];
}
static struct v4l2_rect *
-__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
+ return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF);
else
return &ccdc->crop;
}
@@ -1957,12 +1957,12 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
/*
* ccdc_try_format - Try video format on a pad
* @ccdc: ISP CCDC device
- * @fh : V4L2 subdev file handle
+ * @cfg : V4L2 subdev pad configuration
* @pad: Pad number
* @fmt: Format
*/
static void
-ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1998,7 +1998,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
case CCDC_PAD_SOURCE_OF:
pixelcode = fmt->code;
field = fmt->field;
- *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+ *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
/* In SYNC mode the bridge converts YUV formats from 2X8 to
* 1X16. In BT.656 no such conversion occurs. As we don't know
@@ -2023,7 +2023,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
}
/* Hardcode the output size to the crop rectangle size. */
- crop = __ccdc_get_crop(ccdc, fh, which);
+ crop = __ccdc_get_crop(ccdc, cfg, which);
fmt->width = crop->width;
fmt->height = crop->height;
@@ -2040,7 +2040,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
break;
case CCDC_PAD_SOURCE_VP:
- *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+ *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
/* The video port interface truncates the data to 10 bits. */
info = omap3isp_video_format_info(fmt->code);
@@ -2112,12 +2112,12 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
/*
* ccdc_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg : V4L2 subdev pad configuration
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2132,8 +2132,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
break;
case CCDC_PAD_SOURCE_OF:
- format = __ccdc_get_format(ccdc, fh, code->pad,
- V4L2_SUBDEV_FORMAT_TRY);
+ format = __ccdc_get_format(ccdc, cfg, code->pad,
+ code->which);
if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
format->code == MEDIA_BUS_FMT_UYVY8_2X8) {
@@ -2163,8 +2163,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __ccdc_get_format(ccdc, fh, code->pad,
- V4L2_SUBDEV_FORMAT_TRY);
+ format = __ccdc_get_format(ccdc, cfg, code->pad,
+ code->which);
/* A pixel code equal to 0 means that the video port doesn't
* support the input format. Don't enumerate any pixel code.
@@ -2183,7 +2183,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2195,7 +2195,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -2205,7 +2205,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -2215,7 +2215,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
/*
* ccdc_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP CCDC V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the output formatter
@@ -2223,7 +2223,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
*
* Return 0 on success or a negative error code otherwise.
*/
-static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2239,12 +2239,12 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
sel->r.width = INT_MAX;
sel->r.height = INT_MAX;
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
ccdc_try_crop(ccdc, format, &sel->r);
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
break;
default:
@@ -2257,7 +2257,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* ccdc_set_selection - Set a selection rectangle on a pad
* @sd: ISP CCDC V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the output
@@ -2265,7 +2265,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
*
* Return 0 on success or a negative error code otherwise.
*/
-static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2284,17 +2284,17 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
* rectangle.
*/
if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
return 0;
}
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
ccdc_try_crop(ccdc, format, &sel->r);
- *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
+ *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r;
/* Update the source format. */
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
+ format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which);
+ ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which);
return 0;
}
@@ -2302,19 +2302,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* ccdc_get_format - Retrieve the video format on a pad
* @sd : ISP CCDC V4L2 subdevice
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
* to the format type.
*/
-static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+ format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -2325,30 +2325,30 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* ccdc_set_format - Set the video format on a pad
* @sd : ISP CCDC V4L2 subdevice
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
* to the format type.
*/
-static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+ format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
+ ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CCDC_PAD_SINK) {
/* Reset the crop rectangle. */
- crop = __ccdc_get_crop(ccdc, fh, fmt->which);
+ crop = __ccdc_get_crop(ccdc, cfg, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -2357,16 +2357,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
ccdc_try_crop(ccdc, &fmt->format, crop);
/* Update the source formats. */
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
+ format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF,
fmt->which);
*format = fmt->format;
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
+ ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format,
fmt->which);
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
+ format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP,
fmt->which);
*format = fmt->format;
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
+ ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format,
fmt->which);
}
@@ -2417,11 +2417,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd,
/* We've got a parallel sensor here. */
if (ccdc->input == CCDC_INPUT_PARALLEL) {
- struct isp_parallel_platform_data *pdata =
- &((struct isp_v4l2_subdevs_group *)
+ struct isp_parallel_cfg *parcfg =
+ &((struct isp_bus_cfg *)
media_entity_to_v4l2_subdev(link->source->entity)
->host_priv)->bus.parallel;
- parallel_shift = pdata->data_lane_shift * 2;
+ parallel_shift = parcfg->data_lane_shift * 2;
} else {
parallel_shift = 0;
}
@@ -2453,7 +2453,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ccdc_set_format(sd, fh, &format);
+ ccdc_set_format(sd, fh ? fh->pad : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index f4aedb3..38e6a97 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -201,14 +201,14 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable)
/*
* ccp2_phyif_config - Initialize CCP2 phy interface config
* @ccp2: Pointer to ISP CCP2 device
- * @pdata: CCP2 platform data
+ * @buscfg: CCP2 platform data
*
* Configure the CCP2 physical interface module from platform data.
*
* Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success.
*/
static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
- const struct isp_ccp2_platform_data *pdata)
+ const struct isp_ccp2_cfg *buscfg)
{
struct isp_device *isp = to_isp_device(ccp2);
u32 val;
@@ -218,16 +218,16 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE;
/* Data/strobe physical layer */
BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK,
- pdata->phy_layer);
+ buscfg->phy_layer);
BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK,
- pdata->strobe_clk_pol);
+ buscfg->strobe_clk_pol);
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
if (!(val & ISPCCP2_CTRL_MODE)) {
- if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2)
+ if (buscfg->ccp2_mode == ISP_CCP2_MODE_CCP2)
dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n");
- if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE)
+ if (buscfg->phy_layer == ISP_CCP2_PHY_DATA_STROBE)
/* Strobe mode requires CCP2 */
return -EIO;
}
@@ -347,7 +347,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
*/
static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
{
- const struct isp_v4l2_subdevs_group *pdata;
+ const struct isp_bus_cfg *buscfg;
struct v4l2_mbus_framefmt *format;
struct media_pad *pad;
struct v4l2_subdev *sensor;
@@ -358,20 +358,20 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
- pdata = sensor->host_priv;
+ buscfg = sensor->host_priv;
- ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2);
+ ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2);
if (ret < 0)
return ret;
- ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1);
+ ccp2_vp_config(ccp2, buscfg->bus.ccp2.vpclk_div + 1);
v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines);
format = &ccp2->formats[CCP2_PAD_SINK];
ccp2->if_cfg.data_start = lines;
- ccp2->if_cfg.crc = pdata->bus.ccp2.crc;
+ ccp2->if_cfg.crc = buscfg->bus.ccp2.crc;
ccp2->if_cfg.format = format->code;
ccp2->if_cfg.data_size = format->height;
@@ -611,17 +611,17 @@ static const unsigned int ccp2_fmts[] = {
/*
* __ccp2_get_format - helper function for getting ccp2 format
* @ccp2 : Pointer to ISP CCP2 device
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @pad : pad number
* @which : wanted subdev format
* return format structure or NULL on error
*/
static struct v4l2_mbus_framefmt *
-__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh,
+__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad);
else
return &ccp2->formats[pad];
}
@@ -629,13 +629,13 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh,
/*
* ccp2_try_format - Handle try format by pad subdev method
* @ccp2 : Pointer to ISP CCP2 device
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @pad : pad num
* @fmt : pointer to v4l2 mbus format structure
* @which : wanted subdev format
*/
static void ccp2_try_format(struct isp_ccp2_device *ccp2,
- struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_subdev_pad_config *cfg, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -669,7 +669,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
* When CCP2 write to memory feature will be added this
* should be changed properly.
*/
- format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which);
+ format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
break;
@@ -682,12 +682,12 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
/*
* ccp2_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -702,8 +702,8 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
+ format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK,
+ code->which);
code->code = format->code;
}
@@ -711,7 +711,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -723,7 +723,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -733,7 +733,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -743,17 +743,17 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
/*
* ccp2_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+ format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -764,29 +764,29 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* ccp2_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt : pointer to v4l2 subdev format structure
* returns zero
*/
-static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+ format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which);
+ ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CCP2_PAD_SINK) {
- format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE,
+ format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which);
+ ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which);
}
return 0;
@@ -811,7 +811,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ccp2_set_format(sd, fh, &format);
+ ccp2_set_format(sd, fh ? fh->pad : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index 09c686d..a78338d 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -548,7 +548,8 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
static int csi2_configure(struct isp_csi2_device *csi2)
{
- const struct isp_v4l2_subdevs_group *pdata;
+ struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
+ const struct isp_bus_cfg *buscfg;
struct isp_device *isp = csi2->isp;
struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
struct v4l2_subdev *sensor;
@@ -565,14 +566,19 @@ static int csi2_configure(struct isp_csi2_device *csi2)
pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
- pdata = sensor->host_priv;
+ buscfg = sensor->host_priv;
csi2->frame_skip = 0;
v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
- csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
+ csi2->ctrl.vp_out_ctrl =
+ clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1,
+ 1, 3);
+ dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n",
+ __func__, pipe->l3_ick, pipe->external_rate,
+ csi2->ctrl.vp_out_ctrl);
csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
- csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
+ csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc;
timing->ionum = 1;
timing->force_rx_mode = 1;
@@ -829,17 +835,17 @@ static const struct isp_video_operations csi2_ispvideo_ops = {
*/
static struct v4l2_mbus_framefmt *
-__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
else
return &csi2->formats[pad];
}
static void
-csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -869,7 +875,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
* compression.
*/
pixelcode = fmt->code;
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
+ format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
/*
@@ -890,12 +896,12 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
/*
* csi2_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -908,8 +914,8 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
code->code = csi2_input_fmts[code->index];
} else {
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
+ format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK,
+ code->which);
switch (code->index) {
case 0:
/* Passthrough sink pad code */
@@ -932,7 +938,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
}
static int csi2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -944,7 +950,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -954,7 +960,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -964,17 +970,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
/*
* csi2_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -985,29 +991,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* csi2_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
+ csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CSI2_PAD_SINK) {
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
+ format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
+ csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which);
}
return 0;
@@ -1032,7 +1038,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- csi2_set_format(sd, fh, &format);
+ csi2_set_format(sd, fh ? fh->pad : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index e033f22..495447d 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "isp.h"
@@ -26,10 +27,11 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
enum isp_interface_type iface,
bool ccp2_strobe)
{
- u32 reg = isp_reg_readl(
- phy->isp, OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0);
+ u32 reg;
u32 shift, mode;
+ regmap_read(phy->isp->syscon, phy->isp->syscon_offset, &reg);
+
switch (iface) {
default:
/* Should not happen in practice, but let's keep the compiler happy. */
@@ -63,8 +65,7 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift);
reg |= mode << shift;
- isp_reg_writel(phy->isp, reg,
- OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0);
+ regmap_write(phy->isp->syscon, phy->isp->syscon_offset, reg);
}
static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
@@ -78,16 +79,14 @@ static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
return;
if (!on) {
- isp_reg_writel(phy->isp, 0,
- OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0);
+ regmap_write(phy->isp->syscon, phy->isp->syscon_offset, 0);
return;
}
if (ccp2_strobe)
csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM;
- isp_reg_writel(phy->isp, csirxfe,
- OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0);
+ regmap_write(phy->isp->syscon, phy->isp->syscon_offset, csirxfe);
}
/*
@@ -106,10 +105,9 @@ static void csiphy_routing_cfg(struct isp_csiphy *phy,
enum isp_interface_type iface, bool on,
bool ccp2_strobe)
{
- if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL]
- && on)
+ if (phy->isp->phy_type == ISP_PHY_TYPE_3630 && on)
return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe);
- if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE])
+ if (phy->isp->phy_type == ISP_PHY_TYPE_3430)
return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe);
}
@@ -168,18 +166,25 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
{
struct isp_csi2_device *csi2 = phy->csi2;
struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
- struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv;
+ struct isp_bus_cfg *buscfg = pipe->external->host_priv;
struct isp_csiphy_lanes_cfg *lanes;
int csi2_ddrclk_khz;
unsigned int used_lanes = 0;
unsigned int i;
u32 reg;
- if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
- || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
- lanes = &subdevs->bus.ccp2.lanecfg;
+ if (!buscfg) {
+ struct isp_async_subdev *isd =
+ container_of(pipe->external->asd,
+ struct isp_async_subdev, asd);
+ buscfg = &isd->bus;
+ }
+
+ if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1
+ || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2)
+ lanes = &buscfg->bus.ccp2.lanecfg;
else
- lanes = &subdevs->bus.csi2.lanecfg;
+ lanes = &buscfg->bus.csi2.lanecfg;
/* Clock and data lanes verification */
for (i = 0; i < phy->num_data_lanes; i++) {
@@ -203,8 +208,8 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
* issue since the MPU power domain is forced on whilst the
* ISP is in use.
*/
- csiphy_routing_cfg(phy, subdevs->interface, true,
- subdevs->bus.ccp2.phy_layer);
+ csiphy_routing_cfg(phy, buscfg->interface, true,
+ buscfg->bus.ccp2.phy_layer);
/* DPHY timing configuration */
/* CSI-2 is DDR and we only count used lanes. */
@@ -302,11 +307,10 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy)
struct isp_csi2_device *csi2 = phy->csi2;
struct isp_pipeline *pipe =
to_isp_pipeline(&csi2->subdev.entity);
- struct isp_v4l2_subdevs_group *subdevs =
- pipe->external->host_priv;
+ struct isp_bus_cfg *buscfg = pipe->external->host_priv;
- csiphy_routing_cfg(phy, subdevs->interface, false,
- subdevs->bus.ccp2.phy_layer);
+ csiphy_routing_cfg(phy, buscfg->interface, false,
+ buscfg->bus.ccp2.phy_layer);
csiphy_power_autoswitch_enable(phy, false);
csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
regulator_disable(phy->vdd);
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
index b208c54..ccaf92f 100644
--- a/drivers/media/platform/omap3isp/isph3a_aewb.c
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -297,7 +297,6 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
aewb->ops = &h3a_aewb_ops;
aewb->priv = aewb_cfg;
- aewb->dma_ch = -1;
aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
aewb->isp = isp;
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
index 8a83e19..92937f7 100644
--- a/drivers/media/platform/omap3isp/isph3a_af.c
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -360,7 +360,6 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
af->ops = &h3a_af_ops;
af->priv = af_cfg;
- af->dma_ch = -1;
af->event_type = V4L2_EVENT_OMAP3ISP_AF;
af->isp = isp;
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
index ce822c3..7138b04 100644
--- a/drivers/media/platform/omap3isp/isphist.c
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -16,20 +16,18 @@
*/
#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dmaengine.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "isphist.h"
-#define OMAP24XX_DMA_NO_DEVICE 0
-
#define HIST_CONFIG_DMA 1
-#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
-
/*
* hist_reset_mem - clear Histogram memory before start stats engine.
*/
@@ -62,20 +60,6 @@ static void hist_reset_mem(struct ispstat *hist)
hist->wait_acc_frames = conf->num_acc_frames;
}
-static void hist_dma_config(struct ispstat *hist)
-{
- struct isp_device *isp = hist->isp;
-
- hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
- hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
- hist->dma_config.frame_count = 1;
- hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
- hist->dma_config.src_start = isp->mmio_base_phys[OMAP3_ISP_IOMEM_HIST]
- + ISPHIST_DATA;
- hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
- hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
-}
-
/*
* hist_setup_regs - Helper function to update Histogram registers.
*/
@@ -176,17 +160,12 @@ static int hist_busy(struct ispstat *hist)
& ISPHIST_PCR_BUSY;
}
-static void hist_dma_cb(int lch, u16 ch_status, void *data)
+static void hist_dma_cb(void *data)
{
struct ispstat *hist = data;
- if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
- dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
- ch_status);
- omap_stop_dma(lch);
- hist_reset_mem(hist);
- atomic_set(&hist->buf_err, 1);
- }
+ /* FIXME: The DMA engine API can't report transfer errors :-/ */
+
isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
ISPHIST_CNT_CLEAR);
@@ -198,24 +177,57 @@ static void hist_dma_cb(int lch, u16 ch_status, void *data)
static int hist_buf_dma(struct ispstat *hist)
{
dma_addr_t dma_addr = hist->active_buf->dma_addr;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_slave_config cfg;
+ dma_cookie_t cookie;
+ int ret;
if (unlikely(!dma_addr)) {
dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
- hist_reset_mem(hist);
- return STAT_NO_BUF;
+ goto error;
}
isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
ISPHIST_CNT_CLEAR);
omap3isp_flush(hist->isp);
- hist->dma_config.dst_start = dma_addr;
- hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
- omap_set_dma_params(hist->dma_ch, &hist->dma_config);
- omap_start_dma(hist->dma_ch);
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.src_addr = hist->isp->mmio_hist_base_phys + ISPHIST_DATA;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = hist->buf_size / 4;
+
+ ret = dmaengine_slave_config(hist->dma_ch, &cfg);
+ if (ret < 0) {
+ dev_dbg(hist->isp->dev,
+ "hist: DMA slave configuration failed\n");
+ goto error;
+ }
+
+ tx = dmaengine_prep_slave_single(hist->dma_ch, dma_addr,
+ hist->buf_size, DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK);
+ if (tx == NULL) {
+ dev_dbg(hist->isp->dev,
+ "hist: DMA slave preparation failed\n");
+ goto error;
+ }
+
+ tx->callback = hist_dma_cb;
+ tx->callback_param = hist;
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ dev_dbg(hist->isp->dev, "hist: DMA submission failed\n");
+ goto error;
+ }
+
+ dma_async_issue_pending(hist->dma_ch);
return STAT_BUF_WAITING_DMA;
+
+error:
+ hist_reset_mem(hist);
+ return STAT_NO_BUF;
}
static int hist_buf_pio(struct ispstat *hist)
@@ -272,7 +284,7 @@ static int hist_buf_process(struct ispstat *hist)
if (--(hist->wait_acc_frames))
return STAT_NO_BUF;
- if (HIST_USING_DMA(hist))
+ if (hist->dma_ch)
ret = hist_buf_dma(hist);
else
ret = hist_buf_pio(hist);
@@ -473,18 +485,28 @@ int omap3isp_hist_init(struct isp_device *isp)
hist->isp = isp;
- if (HIST_CONFIG_DMA)
- ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
- hist_dma_cb, hist, &hist->dma_ch);
- if (ret) {
- if (HIST_CONFIG_DMA)
- dev_warn(isp->dev, "hist: DMA request channel failed. "
- "Using PIO only.\n");
- hist->dma_ch = -1;
- } else {
- dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
- hist_dma_config(hist);
- omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+ if (HIST_CONFIG_DMA) {
+ struct platform_device *pdev = to_platform_device(isp->dev);
+ struct resource *res;
+ unsigned int sig = 0;
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+ "hist");
+ if (res)
+ sig = res->start;
+
+ hist->dma_ch = dma_request_slave_channel_compat(mask,
+ omap_dma_filter_fn, &sig, isp->dev, "hist");
+ if (!hist->dma_ch)
+ dev_warn(isp->dev,
+ "hist: DMA channel request failed, using PIO\n");
+ else
+ dev_dbg(isp->dev, "hist: using DMA channel %s\n",
+ dma_chan_name(hist->dma_ch));
}
hist->ops = &hist_ops;
@@ -493,8 +515,8 @@ int omap3isp_hist_init(struct isp_device *isp)
ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
if (ret) {
- if (HIST_USING_DMA(hist))
- omap_free_dma(hist->dma_ch);
+ if (hist->dma_ch)
+ dma_release_channel(hist->dma_ch);
}
return ret;
@@ -505,7 +527,10 @@ int omap3isp_hist_init(struct isp_device *isp)
*/
void omap3isp_hist_cleanup(struct isp_device *isp)
{
- if (HIST_USING_DMA(&isp->isp_hist))
- omap_free_dma(isp->isp_hist.dma_ch);
- omap3isp_stat_cleanup(&isp->isp_hist);
+ struct ispstat *hist = &isp->isp_hist;
+
+ if (hist->dma_ch)
+ dma_release_channel(hist->dma_ch);
+
+ omap3isp_stat_cleanup(hist);
}
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index dd9eed4..15cb254 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -1686,21 +1686,21 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
}
static struct v4l2_mbus_framefmt *
-__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad);
else
return &prev->formats[pad];
}
static struct v4l2_rect *
-__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK);
+ return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK);
else
return &prev->crop;
}
@@ -1727,7 +1727,7 @@ static const unsigned int preview_output_fmts[] = {
/*
* preview_try_format - Validate a format
* @prev: ISP preview engine
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @pad: pad number
* @fmt: format to be validated
* @which: try/active format selector
@@ -1736,7 +1736,7 @@ static const unsigned int preview_output_fmts[] = {
* engine limits and the format and crop rectangles on other pads.
*/
static void preview_try_format(struct isp_prev_device *prev,
- struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_subdev_pad_config *cfg, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1777,7 +1777,7 @@ static void preview_try_format(struct isp_prev_device *prev,
case PREV_PAD_SOURCE:
pixelcode = fmt->code;
- *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);
+ *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which);
switch (pixelcode) {
case MEDIA_BUS_FMT_YUYV8_1X16:
@@ -1795,7 +1795,7 @@ static void preview_try_format(struct isp_prev_device *prev,
* is not supported yet, hardcode the output size to the crop
* rectangle size.
*/
- crop = __preview_get_crop(prev, fh, which);
+ crop = __preview_get_crop(prev, cfg, which);
fmt->width = crop->width;
fmt->height = crop->height;
@@ -1864,12 +1864,12 @@ static void preview_try_crop(struct isp_prev_device *prev,
/*
* preview_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
static int preview_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
switch (code->pad) {
@@ -1893,7 +1893,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd,
}
static int preview_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1905,7 +1905,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ preview_try_format(prev, cfg, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -1915,7 +1915,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ preview_try_format(prev, cfg, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1925,7 +1925,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
/*
* preview_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the sink pad.
@@ -1933,7 +1933,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int preview_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1949,13 +1949,13 @@ static int preview_get_selection(struct v4l2_subdev *sd,
sel->r.width = INT_MAX;
sel->r.height = INT_MAX;
- format = __preview_get_format(prev, fh, PREV_PAD_SINK,
+ format = __preview_get_format(prev, cfg, PREV_PAD_SINK,
sel->which);
preview_try_crop(prev, format, &sel->r);
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__preview_get_crop(prev, fh, sel->which);
+ sel->r = *__preview_get_crop(prev, cfg, sel->which);
break;
default:
@@ -1968,7 +1968,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
/*
* preview_set_selection - Set a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the sink pad.
@@ -1976,7 +1976,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int preview_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1995,17 +1995,17 @@ static int preview_set_selection(struct v4l2_subdev *sd,
* rectangle.
*/
if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__preview_get_crop(prev, fh, sel->which);
+ sel->r = *__preview_get_crop(prev, cfg, sel->which);
return 0;
}
- format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
+ format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which);
preview_try_crop(prev, format, &sel->r);
- *__preview_get_crop(prev, fh, sel->which) = sel->r;
+ *__preview_get_crop(prev, cfg, sel->which) = sel->r;
/* Update the source format. */
- format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
- preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
+ format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which);
+ preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which);
return 0;
}
@@ -2013,17 +2013,17 @@ static int preview_set_selection(struct v4l2_subdev *sd,
/*
* preview_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+ format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -2034,28 +2034,28 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* preview_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+ format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
+ preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == PREV_PAD_SINK) {
/* Reset the crop rectangle. */
- crop = __preview_get_crop(prev, fh, fmt->which);
+ crop = __preview_get_crop(prev, cfg, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -2064,9 +2064,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
preview_try_crop(prev, &fmt->format, crop);
/* Update the source format. */
- format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
+ format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE,
fmt->which);
- preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
+ preview_try_format(prev, cfg, PREV_PAD_SOURCE, format,
fmt->which);
}
@@ -2093,7 +2093,7 @@ static int preview_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- preview_set_format(sd, fh, &format);
+ preview_set_format(sd, fh ? fh->pad : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 2b9bc48..7cfb43d 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -112,16 +112,16 @@ static const struct isprsz_coef filter_coefs = {
* __resizer_get_format - helper function for getting resizer format
* @res : pointer to resizer private structure
* @pad : pad number
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @which : wanted subdev format
* return zero
*/
static struct v4l2_mbus_framefmt *
-__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&res->subdev, cfg, pad);
else
return &res->formats[pad];
}
@@ -129,15 +129,15 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
/*
* __resizer_get_crop - helper function for getting resizer crop rectangle
* @res : pointer to resizer private structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @which : wanted subdev crop rectangle
*/
static struct v4l2_rect *
-__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
+ return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK);
else
return &res->crop.request;
}
@@ -1215,7 +1215,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
/*
* resizer_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP resizer V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the sink pad.
@@ -1223,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
* Return 0 on success or a negative error code otherwise.
*/
static int resizer_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1234,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
if (sel->pad != RESZ_PAD_SINK)
return -EINVAL;
- format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
sel->which);
- format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
sel->which);
switch (sel->target) {
@@ -1251,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__resizer_get_crop(res, fh, sel->which);
+ sel->r = *__resizer_get_crop(res, cfg, sel->which);
resizer_calc_ratios(res, &sel->r, format_source, &ratio);
break;
@@ -1265,7 +1265,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
/*
* resizer_set_selection - Set a selection rectangle on a pad
* @sd: ISP resizer V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the sink pad.
@@ -1276,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int resizer_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1290,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
sel->pad != RESZ_PAD_SINK)
return -EINVAL;
- format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
sel->which);
- format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
sel->which);
dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1310,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
* stored the mangled rectangle.
*/
resizer_try_crop(format_sink, &format_source, &sel->r);
- *__resizer_get_crop(res, fh, sel->which) = sel->r;
+ *__resizer_get_crop(res, cfg, sel->which) = sel->r;
resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1320,7 +1320,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
format_source.width, format_source.height);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+ *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
format_source;
return 0;
}
@@ -1331,7 +1331,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
*/
spin_lock_irqsave(&res->lock, flags);
- *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+ *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
format_source;
res->ratio = ratio;
@@ -1368,13 +1368,13 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res)
/*
* resizer_try_format - Handle try format by pad subdev method
* @res : ISP resizer device
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @pad : pad num
* @fmt : pointer to v4l2 format structure
* @which : wanted subdev format
*/
static void resizer_try_format(struct isp_res_device *res,
- struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_subdev_pad_config *cfg, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1395,10 +1395,10 @@ static void resizer_try_format(struct isp_res_device *res,
break;
case RESZ_PAD_SOURCE:
- format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
+ format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which);
fmt->code = format->code;
- crop = *__resizer_get_crop(res, fh, which);
+ crop = *__resizer_get_crop(res, cfg, which);
resizer_calc_ratios(res, &crop, fmt, &ratio);
break;
}
@@ -1410,12 +1410,12 @@ static void resizer_try_format(struct isp_res_device *res,
/*
* resizer_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1430,8 +1430,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
+ format = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+ code->which);
code->code = format->code;
}
@@ -1439,7 +1439,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
}
static int resizer_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1451,7 +1451,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ resizer_try_format(res, cfg, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -1461,7 +1461,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ resizer_try_format(res, cfg, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1471,17 +1471,17 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
/*
* resizer_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+ format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -1492,37 +1492,37 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/*
* resizer_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+ format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
+ resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
if (fmt->pad == RESZ_PAD_SINK) {
/* reset crop rectangle */
- crop = __resizer_get_crop(res, fh, fmt->which);
+ crop = __resizer_get_crop(res, cfg, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
crop->height = fmt->format.height;
/* Propagate the format from sink to source */
- format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
+ resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format,
fmt->which);
}
@@ -1573,7 +1573,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
format.format.width = 4096;
format.format.height = 4096;
- resizer_set_format(sd, fh, &format);
+ resizer_set_format(sd, fh ? fh->pad : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index a94e834..20434e8 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -21,7 +21,7 @@
#include "isp.h"
-#define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch >= 0)
+#define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch != NULL)
/*
* MAGIC_SIZE must always be the greatest common divisor of
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index b32b296..b79380d 100644
--- a/drivers/media/platform/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/omap3isp.h>
-#include <linux/omap-dma.h>
#include <media/v4l2-event.h>
#include "isp.h"
@@ -33,6 +32,7 @@
#define STAT_NO_BUF 1 /* An error has occurred */
#define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */
+struct dma_chan;
struct ispstat;
struct ispstat_buffer {
@@ -96,7 +96,6 @@ struct ispstat {
u8 inc_config;
atomic_t buf_err;
enum ispstat_state_t state; /* enabling/disabling state */
- struct omap_dma_channel_params dma_config;
struct isp_device *isp;
void *priv; /* pointer to priv config struct */
void *recover_priv; /* pointer to recover priv configuration */
@@ -110,7 +109,7 @@ struct ispstat {
u32 frame_number;
u32 buf_size;
u32 buf_alloc_size;
- int dma_ch;
+ struct dma_chan *dma_ch;
unsigned long event_type;
struct ispstat_buffer *buf;
struct ispstat_buffer *active_buf;
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 3fe9047..d285af1 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -452,7 +452,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
enum isp_pipeline_state state;
struct isp_buffer *buf;
unsigned long flags;
- struct timespec ts;
spin_lock_irqsave(&video->irqlock, flags);
if (WARN_ON(list_empty(&video->dmaqueue))) {
@@ -465,9 +464,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
list_del(&buf->irqlist);
spin_unlock_irqrestore(&video->irqlock, flags);
- ktime_get_ts(&ts);
- buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
- buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
/* Do frame number propagation only if this is the output video node.
* Frame number either comes from the CSI receivers or it gets
@@ -524,7 +521,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
irqlist);
- buf->vb.state = VB2_BUF_STATE_ACTIVE;
spin_unlock_irqrestore(&video->irqlock, flags);
@@ -1022,7 +1018,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe->entities = 0;
- if (video->isp->pdata->set_constraints)
+ if (video->isp->pdata && video->isp->pdata->set_constraints)
video->isp->pdata->set_constraints(video->isp, true);
pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
pipe->max_rate = pipe->l3_ick;
@@ -1104,7 +1100,7 @@ err_set_stream:
err_check_format:
media_entity_pipeline_stop(&video->video.entity);
err_pipeline_start:
- if (video->isp->pdata->set_constraints)
+ if (video->isp->pdata && video->isp->pdata->set_constraints)
video->isp->pdata->set_constraints(video->isp, false);
/* The DMA queue must be emptied here, otherwise CCDC interrupts that
* will get triggered the next time the CCDC is powered up will try to
@@ -1165,7 +1161,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
video->queue = NULL;
video->error = false;
- if (video->isp->pdata->set_constraints)
+ if (video->isp->pdata && video->isp->pdata->set_constraints)
video->isp->pdata->set_constraints(video->isp, false);
media_entity_pipeline_stop(&video->video.entity);
@@ -1326,14 +1322,8 @@ static unsigned int isp_video_poll(struct file *file, poll_table *wait)
static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
- struct isp_video *video = video_drvdata(file);
- int ret;
-
- mutex_lock(&video->queue_lock);
- ret = vb2_mmap(&vfh->queue, vma);
- mutex_unlock(&video->queue_lock);
- return ret;
+ return vb2_mmap(&vfh->queue, vma);
}
static struct v4l2_file_operations isp_video_fops = {
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 54479d6..f6a61b9 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1219,7 +1219,7 @@ static const u32 camif_mbus_formats[] = {
*/
static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(camif_mbus_formats))
@@ -1230,14 +1230,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1297,7 +1297,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif,
}
static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1325,7 +1325,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
__camif_subdev_try_format(camif, mf, fmt->pad);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*mf = fmt->format;
mutex_unlock(&camif->lock);
return 0;
@@ -1364,7 +1364,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1377,7 +1377,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
return 0;
}
@@ -1451,7 +1451,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r)
}
static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1465,7 +1465,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
__camif_try_crop(camif, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
+ *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
} else {
unsigned long flags;
unsigned int i;
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index a92ff42..bfbf157 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -621,6 +621,7 @@ static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
return ctx->subsampling;
case SJPEG_EXYNOS3250:
+ case SJPEG_EXYNOS5420:
if (ctx->subsampling > 3)
return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
return exynos3250_decoded_subsampling[ctx->subsampling];
@@ -1142,13 +1143,13 @@ static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
w_step = 1 << walign;
h_step = 1 << halign;
- if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) {
+ if (ctx->jpeg->variant->hw3250_compat) {
/*
* Rightmost and bottommost pixels are cropped by the
- * Exynos3250 JPEG IP for RGB formats, for the specific
- * width and height values respectively. This assignment
- * will result in v4l_bound_align_image returning dimensions
- * reduced by 1 for the aforementioned cases.
+ * Exynos3250/compatible JPEG IP for RGB formats, for the
+ * specific width and height values respectively. This
+ * assignment will result in v4l_bound_align_image returning
+ * dimensions reduced by 1 for the aforementioned cases.
*/
if (w_step == 4 && ((width & 3) == 1)) {
wmax = width;
@@ -1384,12 +1385,12 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
/*
* Prevent downscaling to YUV420 format by more than 2
- * for Exynos3250 SoC as it produces broken raw image
+ * for Exynos3250/compatible SoC as it produces broken raw image
* in such cases.
*/
if (ct->mode == S5P_JPEG_DECODE &&
f_type == FMT_TYPE_CAPTURE &&
- ct->jpeg->variant->version == SJPEG_EXYNOS3250 &&
+ ct->jpeg->variant->hw3250_compat &&
pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
ct->scale_factor > 2) {
scale_rect.width = ct->out_q.w / 2;
@@ -1569,12 +1570,12 @@ static int s5p_jpeg_s_selection(struct file *file, void *fh,
if (s->target == V4L2_SEL_TGT_COMPOSE) {
if (ctx->mode != S5P_JPEG_DECODE)
return -EINVAL;
- if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
+ if (ctx->jpeg->variant->hw3250_compat)
ret = exynos3250_jpeg_try_downscale(ctx, rect);
} else if (s->target == V4L2_SEL_TGT_CROP) {
if (ctx->mode != S5P_JPEG_ENCODE)
return -EINVAL;
- if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
+ if (ctx->jpeg->variant->hw3250_compat)
ret = exynos3250_jpeg_try_crop(ctx, rect);
}
@@ -1604,8 +1605,9 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
case SJPEG_S5P:
return 0;
case SJPEG_EXYNOS3250:
+ case SJPEG_EXYNOS5420:
/*
- * The exynos3250 device can produce JPEG image only
+ * The exynos3250/compatible device can produce JPEG image only
* of 4:4:4 subsampling when given RGB32 source image.
*/
if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
@@ -1624,7 +1626,7 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
}
/*
- * The exynos4x12 and exynos3250 devices require resulting
+ * The exynos4x12 and exynos3250/compatible devices require resulting
* jpeg subsampling not to be lower than the input raw image
* subsampling.
*/
@@ -1842,7 +1844,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
struct s5p_jpeg *jpeg = ctx->jpeg;
struct s5p_jpeg_fmt *fmt;
struct vb2_buffer *vb;
- struct s5p_jpeg_addr jpeg_addr;
+ struct s5p_jpeg_addr jpeg_addr = {};
u32 pix_size, padding_bytes = 0;
jpeg_addr.cb = 0;
@@ -1946,7 +1948,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
struct s5p_jpeg *jpeg = ctx->jpeg;
struct s5p_jpeg_fmt *fmt;
struct vb2_buffer *vb;
- struct s5p_jpeg_addr jpeg_addr;
+ struct s5p_jpeg_addr jpeg_addr = {};
u32 pix_size;
pix_size = ctx->cap_q.w * ctx->cap_q.h;
@@ -2020,6 +2022,16 @@ static void exynos3250_jpeg_device_run(void *priv)
exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
+ /*
+ * Some SoCs require setting Huffman tables before each run
+ */
+ if (jpeg->variant->htbl_reinit) {
+ s5p_jpeg_set_hdctbl(jpeg->regs);
+ s5p_jpeg_set_hdctblg(jpeg->regs);
+ s5p_jpeg_set_hactbl(jpeg->regs);
+ s5p_jpeg_set_hactblg(jpeg->regs);
+ }
+
/* Y, Cb, Cr use Huffman table 0 */
exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
@@ -2663,13 +2675,12 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
/*
* JPEG IP allows storing two Huffman tables for each component.
* We fill table 0 for each component and do this here only
- * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires
- * programming its Huffman tables each time the encoding process
- * is initialized, and thus it is accomplished in the device_run
- * callback of m2m_ops.
+ * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
+ * require programming their Huffman tables each time the encoding
+ * process is initialized, and thus it is accomplished in the
+ * device_run callback of m2m_ops.
*/
- if (jpeg->variant->version == SJPEG_S5P ||
- jpeg->variant->version == SJPEG_EXYNOS3250) {
+ if (!jpeg->variant->htbl_reinit) {
s5p_jpeg_set_hdctbl(jpeg->regs);
s5p_jpeg_set_hdctblg(jpeg->regs);
s5p_jpeg_set_hactbl(jpeg->regs);
@@ -2717,6 +2728,7 @@ static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
.jpeg_irq = exynos3250_jpeg_irq,
.m2m_ops = &exynos3250_jpeg_m2m_ops,
.fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
+ .hw3250_compat = 1,
};
static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
@@ -2724,6 +2736,16 @@ static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
.jpeg_irq = exynos4_jpeg_irq,
.m2m_ops = &exynos4_jpeg_m2m_ops,
.fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
+ .htbl_reinit = 1,
+};
+
+static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
+ .version = SJPEG_EXYNOS5420,
+ .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
+ .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
+ .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
+ .hw3250_compat = 1,
+ .htbl_reinit = 1,
};
static const struct of_device_id samsung_jpeg_match[] = {
@@ -2739,6 +2761,9 @@ static const struct of_device_id samsung_jpeg_match[] = {
}, {
.compatible = "samsung,exynos4212-jpeg",
.data = &exynos4_jpeg_drvdata,
+ }, {
+ .compatible = "samsung,exynos5420-jpeg",
+ .data = &exynos5420_jpeg_drvdata,
},
{},
};
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 764b32d..7d9a9ed 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -67,10 +67,12 @@
#define SJPEG_SUBSAMPLING_420 0x22
/* Version numbers */
-
-#define SJPEG_S5P 1
-#define SJPEG_EXYNOS3250 2
-#define SJPEG_EXYNOS4 3
+enum sjpeg_version {
+ SJPEG_S5P,
+ SJPEG_EXYNOS3250,
+ SJPEG_EXYNOS4,
+ SJPEG_EXYNOS5420,
+};
enum exynos4_jpeg_result {
OK_ENC_OR_DEC,
@@ -130,6 +132,8 @@ struct s5p_jpeg {
struct s5p_jpeg_variant {
unsigned int version;
unsigned int fmt_ver_flag;
+ unsigned int hw3250_compat:1;
+ unsigned int htbl_reinit:1;
struct v4l2_m2m_ops *m2m_ops;
irqreturn_t (*jpeg_irq)(int irq, void *priv);
};
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
index e3b8e67..b5f20e7 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
@@ -51,18 +51,6 @@ void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
writel(reg, regs + S5P_JPGCMOD);
}
-void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGCMOD);
- if (y16)
- reg |= S5P_MODE_Y16;
- else
- reg &= ~S5P_MODE_Y16_MASK;
- writel(reg, regs + S5P_JPGCMOD);
-}
-
void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode)
{
unsigned long reg, m;
@@ -208,26 +196,6 @@ void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
writel(reg, regs + S5P_JPGINTSE);
}
-void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_TIMER_SE);
- reg |= S5P_TIMER_INT_EN;
- reg &= ~S5P_TIMER_INIT_MASK;
- reg |= val & S5P_TIMER_INIT_MASK;
- writel(reg, regs + S5P_JPG_TIMER_SE);
-}
-
-void s5p_jpeg_timer_disable(void __iomem *regs)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_TIMER_SE);
- reg &= ~S5P_TIMER_INT_EN_MASK;
- writel(reg, regs + S5P_JPG_TIMER_SE);
-}
-
int s5p_jpeg_timer_stat(void __iomem *regs)
{
return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
index c11ebe8..f208fa3 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
@@ -29,7 +29,6 @@
void s5p_jpeg_reset(void __iomem *regs);
void s5p_jpeg_poweron(void __iomem *regs);
void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode);
-void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16);
void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode);
void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode);
unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs);
@@ -42,8 +41,6 @@ void s5p_jpeg_x(void __iomem *regs, unsigned int x);
void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable);
void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable);
void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl);
-void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val);
-void s5p_jpeg_timer_disable(void __iomem *regs);
int s5p_jpeg_timer_stat(void __iomem *regs);
void s5p_jpeg_clear_timer_stat(void __iomem *regs);
void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 98374e8..8333fbc2 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -844,6 +844,13 @@ static int s5p_mfc_open(struct file *file)
ret = -ENOENT;
goto err_queue_init;
}
+ /* One way to indicate end-of-stream for MFC is to set the
+ * bytesused == 0. However by default videobuf2 handles bytesused
+ * equal to 0 as a special case and changes its value to the size
+ * of the buffer. Set the allow_zero_bytesused flag so that videobuf2
+ * will keep the value of bytesused intact.
+ */
+ q->allow_zero_bytesused = 1;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index 72d4f2e..751f3b6 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -287,7 +287,7 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
u32 bl_width = divup(width, blk->width);
u32 bl_height = divup(height, blk->height);
u32 sizeimage = bl_width * bl_height * blk->size;
- u16 bytesperline = bl_width * blk->size / blk->height;
+ u32 bytesperline = bl_width * blk->size / blk->height;
plane->sizeimage += sizeimage;
plane->bytesperline = max(plane->bytesperline, bytesperline);
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 261f119..dde1ccc 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -62,7 +62,7 @@ enum sh_vou_status {
struct sh_vou_device {
struct v4l2_device v4l2_dev;
- struct video_device *vdev;
+ struct video_device vdev;
atomic_t use_count;
struct sh_vou_pdata *pdata;
spinlock_t lock;
@@ -890,7 +890,7 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id)
dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id);
- if (std_id & ~vou_dev->vdev->tvnorms)
+ if (std_id & ~vou_dev->vdev.tvnorms)
return -EINVAL;
ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
@@ -1168,10 +1168,10 @@ static int sh_vou_open(struct file *file)
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
- file->private_data = vou_file;
-
- if (mutex_lock_interruptible(&vou_dev->fop_lock))
+ if (mutex_lock_interruptible(&vou_dev->fop_lock)) {
+ kfree(vou_file);
return -ERESTARTSYS;
+ }
if (atomic_inc_return(&vou_dev->use_count) == 1) {
int ret;
/* First open */
@@ -1183,6 +1183,7 @@ static int sh_vou_open(struct file *file)
pm_runtime_put(vou_dev->v4l2_dev.dev);
vou_dev->status = SH_VOU_IDLE;
mutex_unlock(&vou_dev->fop_lock);
+ kfree(vou_file);
return ret;
}
}
@@ -1192,9 +1193,11 @@ static int sh_vou_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
sizeof(struct videobuf_buffer),
- vou_dev->vdev, &vou_dev->fop_lock);
+ &vou_dev->vdev, &vou_dev->fop_lock);
mutex_unlock(&vou_dev->fop_lock);
+ file->private_data = vou_file;
+
return 0;
}
@@ -1358,21 +1361,14 @@ static int sh_vou_probe(struct platform_device *pdev)
goto ev4l2devreg;
}
- /* Allocate memory for video device */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- ret = -ENOMEM;
- goto evdevalloc;
- }
-
+ vdev = &vou_dev->vdev;
*vdev = sh_vou_video_template;
if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev;
- vdev->release = video_device_release;
+ vdev->release = video_device_release_empty;
vdev->lock = &vou_dev->fop_lock;
- vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
pm_runtime_enable(&pdev->dev);
@@ -1406,9 +1402,7 @@ ei2cnd:
ereset:
i2c_put_adapter(i2c_adap);
ei2cgadap:
- video_device_release(vdev);
pm_runtime_disable(&pdev->dev);
-evdevalloc:
v4l2_device_unregister(&vou_dev->v4l2_dev);
ev4l2devreg:
free_irq(irq, vou_dev);
@@ -1435,7 +1429,7 @@ static int sh_vou_remove(struct platform_device *pdev)
if (irq > 0)
free_irq(irq, vou_dev);
pm_runtime_disable(&pdev->dev);
- video_unregister_device(vou_dev->vdev);
+ video_unregister_device(&vou_dev->vdev);
i2c_put_adapter(client->adapter);
v4l2_device_unregister(&vou_dev->v4l2_dev);
iounmap(vou_dev->base);
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 279ab9f..9351f64 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -977,19 +977,6 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd)
icd->devnum);
}
-/* Called with .host_lock held */
-static int rcar_vin_clock_start(struct soc_camera_host *ici)
-{
- /* VIN does not have "mclk" */
- return 0;
-}
-
-/* Called with .host_lock held */
-static void rcar_vin_clock_stop(struct soc_camera_host *ici)
-{
- /* VIN does not have "mclk" */
-}
-
static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs)
{
int i;
@@ -1803,8 +1790,6 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
.owner = THIS_MODULE,
.add = rcar_vin_add_device,
.remove = rcar_vin_remove_device,
- .clock_start = rcar_vin_clock_start,
- .clock_stop = rcar_vin_clock_stop,
.get_formats = rcar_vin_get_formats,
.put_formats = rcar_vin_put_formats,
.get_crop = rcar_vin_get_crop,
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index c4e7aa0..cd93241 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -380,7 +380,6 @@ static int sh_csi2_remove(struct platform_device *pdev)
struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev);
v4l2_async_unregister_subdev(&priv->subdev);
- v4l2_device_unregister_subdev(subdev);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 9039d989..7bfe7665 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -177,6 +177,30 @@ static int __soc_camera_power_off(struct soc_camera_device *icd)
return 0;
}
+static int soc_camera_clock_start(struct soc_camera_host *ici)
+{
+ int ret;
+
+ if (!ici->ops->clock_start)
+ return 0;
+
+ mutex_lock(&ici->clk_lock);
+ ret = ici->ops->clock_start(ici);
+ mutex_unlock(&ici->clk_lock);
+
+ return ret;
+}
+
+static void soc_camera_clock_stop(struct soc_camera_host *ici)
+{
+ if (!ici->ops->clock_stop)
+ return;
+
+ mutex_lock(&ici->clk_lock);
+ ici->ops->clock_stop(ici);
+ mutex_unlock(&ici->clk_lock);
+}
+
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
@@ -584,9 +608,7 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
return -EBUSY;
if (!icd->clk) {
- mutex_lock(&ici->clk_lock);
- ret = ici->ops->clock_start(ici);
- mutex_unlock(&ici->clk_lock);
+ ret = soc_camera_clock_start(ici);
if (ret < 0)
return ret;
}
@@ -602,11 +624,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
return 0;
eadd:
- if (!icd->clk) {
- mutex_lock(&ici->clk_lock);
- ici->ops->clock_stop(ici);
- mutex_unlock(&ici->clk_lock);
- }
+ if (!icd->clk)
+ soc_camera_clock_stop(ici);
return ret;
}
@@ -619,11 +638,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd)
if (ici->ops->remove)
ici->ops->remove(icd);
- if (!icd->clk) {
- mutex_lock(&ici->clk_lock);
- ici->ops->clock_stop(ici);
- mutex_unlock(&ici->clk_lock);
- }
+ if (!icd->clk)
+ soc_camera_clock_stop(ici);
ici->icd = NULL;
}
@@ -688,7 +704,8 @@ static int soc_camera_open(struct file *file)
/* The camera could have been already on, try to reset */
if (sdesc->subdev_desc.reset)
- sdesc->subdev_desc.reset(icd->pdev);
+ if (icd->control)
+ sdesc->subdev_desc.reset(icd->control);
ret = soc_camera_add_device(icd);
if (ret < 0) {
@@ -1159,7 +1176,8 @@ static void scan_add_host(struct soc_camera_host *ici)
/* The camera could have been already on, try to reset */
if (ssdd->reset)
- ssdd->reset(icd->pdev);
+ if (icd->control)
+ ssdd->reset(icd->control);
icd->parent = ici->v4l2_dev.dev;
@@ -1178,7 +1196,6 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk)
{
struct soc_camera_device *icd = clk->priv;
struct soc_camera_host *ici;
- int ret;
if (!icd || !icd->parent)
return -ENODEV;
@@ -1192,10 +1209,7 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk)
* If a different client is currently being probed, the host will tell
* you to go
*/
- mutex_lock(&ici->clk_lock);
- ret = ici->ops->clock_start(ici);
- mutex_unlock(&ici->clk_lock);
- return ret;
+ return soc_camera_clock_start(ici);
}
static void soc_camera_clk_disable(struct v4l2_clk *clk)
@@ -1208,9 +1222,7 @@ static void soc_camera_clk_disable(struct v4l2_clk *clk)
ici = to_soc_camera_host(icd->parent);
- mutex_lock(&ici->clk_lock);
- ici->ops->clock_stop(ici);
- mutex_unlock(&ici->clk_lock);
+ soc_camera_clock_stop(ici);
module_put(ici->ops->owner);
}
@@ -1364,7 +1376,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
snprintf(clk_name, sizeof(clk_name), "%d-%04x",
shd->i2c_adapter_id, shd->board_info->addr);
- icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
ret = PTR_ERR(icd->clk);
goto eclkreg;
@@ -1445,7 +1457,7 @@ static int soc_camera_async_bound(struct v4l2_async_notifier *notifier,
memcpy(&sdesc->subdev_desc, ssdd,
sizeof(sdesc->subdev_desc));
if (ssdd->reset)
- ssdd->reset(icd->pdev);
+ ssdd->reset(&client->dev);
}
icd->control = &client->dev;
@@ -1545,7 +1557,7 @@ static int scan_async_group(struct soc_camera_host *ici,
snprintf(clk_name, sizeof(clk_name), "%d-%04x",
sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
- icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
ret = PTR_ERR(icd->clk);
goto eclkreg;
@@ -1650,7 +1662,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
snprintf(clk_name, sizeof(clk_name), "of-%s",
of_node_full_name(remote));
- icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
ret = PTR_ERR(icd->clk);
goto eclkreg;
@@ -1659,6 +1671,8 @@ static int soc_of_bind(struct soc_camera_host *ici,
ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
if (!ret)
return 0;
+
+ v4l2_clk_unregister(icd->clk);
eclkreg:
icd->clk = NULL;
platform_device_del(sasc->pdev);
@@ -1751,9 +1765,7 @@ static int soc_camera_probe(struct soc_camera_host *ici,
ret = -EINVAL;
goto eadd;
} else {
- mutex_lock(&ici->clk_lock);
- ret = ici->ops->clock_start(ici);
- mutex_unlock(&ici->clk_lock);
+ ret = soc_camera_clock_start(ici);
if (ret < 0)
goto eadd;
@@ -1793,9 +1805,7 @@ efinish:
module_put(control->driver->owner);
enodrv:
eadddev:
- mutex_lock(&ici->clk_lock);
- ici->ops->clock_stop(ici);
- mutex_unlock(&ici->clk_lock);
+ soc_camera_clock_stop(ici);
}
eadd:
if (icd->vdev) {
@@ -1889,22 +1899,34 @@ static int default_enum_framesizes(struct soc_camera_device *icd,
int ret;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
- __u32 pixfmt = fsize->pixel_format;
- struct v4l2_frmsizeenum fsize_mbus = *fsize;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = fsize->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format);
if (!xlate)
return -EINVAL;
- /* map xlate-code to pixel_format, sensor only handle xlate-code*/
- fsize_mbus.pixel_format = xlate->code;
+ fse.code = xlate->code;
- ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
if (ret < 0)
return ret;
- *fsize = fsize_mbus;
- fsize->pixel_format = pixfmt;
-
+ if (fse.min_width == fse.max_width &&
+ fse.min_height == fse.max_height) {
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fse.min_width;
+ fsize->discrete.height = fse.min_height;
+ return 0;
+ }
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = fse.min_width;
+ fsize->stepwise.max_width = fse.max_width;
+ fsize->stepwise.min_height = fse.min_height;
+ fsize->stepwise.max_height = fse.max_height;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
return 0;
}
@@ -1921,8 +1943,6 @@ int soc_camera_host_register(struct soc_camera_host *ici)
((!ici->ops->init_videobuf ||
!ici->ops->reqbufs) &&
!ici->ops->init_videobuf2) ||
- !ici->ops->clock_start ||
- !ici->ops->clock_stop ||
!ici->ops->poll ||
!ici->v4l2_dev.dev)
return -EINVAL;
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index 86989d8..678ed9f 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -1147,12 +1147,23 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
struct v4l2_frmivalenum *interval)
{
struct via_camera *cam = priv;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = interval->index,
+ .code = cam->mbus_code,
+ .width = cam->sensor_format.width,
+ .height = cam->sensor_format.height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
int ret;
mutex_lock(&cam->lock);
- ret = sensor_call(cam, video, enum_frameintervals, interval);
+ ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie);
mutex_unlock(&cam->lock);
- return ret;
+ if (ret)
+ return ret;
+ interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ interval->discrete = fie.interval;
+ return 0;
}
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index d9d844a..4d6b4cc 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -142,7 +142,7 @@ static struct vim2m_fmt *find_format(struct v4l2_format *f)
struct vim2m_dev {
struct v4l2_device v4l2_dev;
- struct video_device *vfd;
+ struct video_device vfd;
atomic_t num_inst;
struct mutex dev_mutex;
@@ -968,7 +968,7 @@ static struct video_device vim2m_videodev = {
.fops = &vim2m_fops,
.ioctl_ops = &vim2m_ioctl_ops,
.minor = -1,
- .release = video_device_release,
+ .release = video_device_release_empty,
};
static struct v4l2_m2m_ops m2m_ops = {
@@ -996,26 +996,19 @@ static int vim2m_probe(struct platform_device *pdev)
atomic_set(&dev->num_inst, 0);
mutex_init(&dev->dev_mutex);
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
- ret = -ENOMEM;
- goto unreg_dev;
- }
-
- *vfd = vim2m_videodev;
+ dev->vfd = vim2m_videodev;
+ vfd = &dev->vfd;
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- goto rel_vdev;
+ goto unreg_dev;
}
video_set_drvdata(vfd, dev);
snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name);
- dev->vfd = vfd;
v4l2_info(&dev->v4l2_dev,
"Device registered as /dev/video%d\n", vfd->num);
@@ -1033,9 +1026,7 @@ static int vim2m_probe(struct platform_device *pdev)
err_m2m:
v4l2_m2m_release(dev->m2m_dev);
- video_unregister_device(dev->vfd);
-rel_vdev:
- video_device_release(vfd);
+ video_unregister_device(&dev->vfd);
unreg_dev:
v4l2_device_unregister(&dev->v4l2_dev);
@@ -1049,7 +1040,7 @@ static int vim2m_remove(struct platform_device *pdev)
v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
v4l2_m2m_release(dev->m2m_dev);
del_timer_sync(&dev->timer);
- video_unregister_device(dev->vfd);
+ video_unregister_device(&dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
return 0;
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index a7e033a..d33f164 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -26,6 +26,7 @@
#include <linux/vmalloc.h>
#include <linux/font.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <linux/v4l2-dv-timings.h>
#include <media/videobuf2-vmalloc.h>
@@ -618,7 +619,23 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
Initialization and module stuff
------------------------------------------------------------------*/
-static int __init vivid_create_instance(int inst)
+static void vivid_dev_release(struct v4l2_device *v4l2_dev)
+{
+ struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev);
+
+ vivid_free_controls(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ vfree(dev->scaled_line);
+ vfree(dev->blended_line);
+ vfree(dev->edid);
+ vfree(dev->bitmap_cap);
+ vfree(dev->bitmap_out);
+ tpg_free(&dev->tpg);
+ kfree(dev->query_dv_timings_qmenu);
+ kfree(dev);
+}
+
+static int vivid_create_instance(struct platform_device *pdev, int inst)
{
static const struct v4l2_dv_timings def_dv_timings =
V4L2_DV_BT_CEA_1280X720P60;
@@ -646,9 +663,12 @@ static int __init vivid_create_instance(int inst)
/* register v4l2_device */
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
"%s-%03d", VIVID_MODULE_NAME, inst);
- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
- if (ret)
- goto free_dev;
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ kfree(dev);
+ return ret;
+ }
+ dev->v4l2_dev.release = vivid_dev_release;
/* start detecting feature set */
@@ -1256,15 +1276,8 @@ unreg_dev:
video_unregister_device(&dev->vbi_cap_dev);
video_unregister_device(&dev->vid_out_dev);
video_unregister_device(&dev->vid_cap_dev);
- vivid_free_controls(dev);
- v4l2_device_unregister(&dev->v4l2_dev);
free_dev:
- vfree(dev->scaled_line);
- vfree(dev->blended_line);
- vfree(dev->edid);
- tpg_free(&dev->tpg);
- kfree(dev->query_dv_timings_qmenu);
- kfree(dev);
+ v4l2_device_put(&dev->v4l2_dev);
return ret;
}
@@ -1274,7 +1287,7 @@ free_dev:
will succeed. This is limited to the maximum number of devices that
videodev supports, which is equal to VIDEO_NUM_DEVICES.
*/
-static int __init vivid_init(void)
+static int vivid_probe(struct platform_device *pdev)
{
const struct font_desc *font = find_font("VGA8x16");
int ret = 0, i;
@@ -1289,7 +1302,7 @@ static int __init vivid_init(void)
n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS);
for (i = 0; i < n_devs; i++) {
- ret = vivid_create_instance(i);
+ ret = vivid_create_instance(pdev, i);
if (ret) {
/* If some instantiations succeeded, keep driver */
if (i)
@@ -1309,7 +1322,7 @@ static int __init vivid_init(void)
return ret;
}
-static void __exit vivid_exit(void)
+static int vivid_remove(struct platform_device *pdev)
{
struct vivid_dev *dev;
unsigned i;
@@ -1358,18 +1371,48 @@ static void __exit vivid_exit(void)
unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev);
}
- v4l2_device_unregister(&dev->v4l2_dev);
- vivid_free_controls(dev);
- vfree(dev->scaled_line);
- vfree(dev->blended_line);
- vfree(dev->edid);
- vfree(dev->bitmap_cap);
- vfree(dev->bitmap_out);
- tpg_free(&dev->tpg);
- kfree(dev->query_dv_timings_qmenu);
- kfree(dev);
+ v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}
+ return 0;
+}
+
+static void vivid_pdev_release(struct device *dev)
+{
+}
+
+static struct platform_device vivid_pdev = {
+ .name = "vivid",
+ .dev.release = vivid_pdev_release,
+};
+
+static struct platform_driver vivid_pdrv = {
+ .probe = vivid_probe,
+ .remove = vivid_remove,
+ .driver = {
+ .name = "vivid",
+ },
+};
+
+static int __init vivid_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&vivid_pdev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&vivid_pdrv);
+ if (ret)
+ platform_device_unregister(&vivid_pdev);
+
+ return ret;
+}
+
+static void __exit vivid_exit(void)
+{
+ platform_driver_unregister(&vivid_pdrv);
+ platform_device_unregister(&vivid_pdev);
}
module_init(vivid_init);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 4b497df..9e15aee 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -79,12 +79,14 @@ extern unsigned vivid_debug;
struct vivid_fmt {
const char *name;
u32 fourcc; /* v4l2 format id */
- u8 depth;
bool is_yuv;
bool can_do_overlay;
+ u8 vdownsampling[TPG_MAX_PLANES];
u32 alpha_mask;
u8 planes;
- u32 data_offset[2];
+ u8 buffers;
+ u32 data_offset[TPG_MAX_PLANES];
+ u32 bit_depth[TPG_MAX_PLANES];
};
extern struct vivid_fmt vivid_formats[];
@@ -332,7 +334,7 @@ struct vivid_dev {
u32 ycbcr_enc_out;
u32 quantization_out;
u32 service_set_out;
- u32 bytesperline_out[2];
+ unsigned bytesperline_out[TPG_MAX_PLANES];
unsigned tv_field_out;
unsigned tv_audio_output;
bool vbi_out_have_wss;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 32a798f..2b90700 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -818,7 +818,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
if (!vivid_is_hdmi_out(dev))
break;
- if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
if (bt->width == 720 && bt->height <= 576)
dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
else
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 39a67cf..1727f54 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -229,14 +229,29 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
}
+static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf,
+ unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h)
+{
+ unsigned i;
+ void *vbuf;
+
+ if (p == 0 || tpg_g_buffers(tpg) > 1)
+ return vb2_plane_vaddr(&buf->vb, p);
+ vbuf = vb2_plane_vaddr(&buf->vb, 0);
+ for (i = 0; i < p; i++)
+ vbuf += bpl[i] * h / tpg->vdownsampling[i];
+ return vbuf;
+}
+
static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
struct vivid_buffer *vid_cap_buf)
{
bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
struct tpg_data *tpg = &dev->tpg;
struct vivid_buffer *vid_out_buf = NULL;
- unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
- unsigned img_width = dev->compose_cap.width;
+ unsigned vdiv = dev->fmt_out->vdownsampling[p];
+ unsigned twopixsize = tpg_g_twopixelsize(tpg, p);
+ unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width);
unsigned img_height = dev->compose_cap.height;
unsigned stride_cap = tpg->bytesperline[p];
unsigned stride_out = dev->bytesperline_out[p];
@@ -255,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
unsigned vid_overlay_fract_part = 0;
unsigned vid_overlay_y = 0;
unsigned vid_overlay_error = 0;
+ unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left);
unsigned vid_cap_right;
bool quick;
@@ -269,25 +285,29 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field;
- voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) +
- vid_out_buf->vb.v4l2_planes[p].data_offset;
- voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
- vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+ voutbuf = plane_vaddr(tpg, vid_out_buf, p,
+ dev->bytesperline_out, dev->fmt_out_rect.height);
+ if (p < dev->fmt_out->buffers)
+ voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset;
+ voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) +
+ (dev->loop_vid_out.top / vdiv) * stride_out;
+ vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) +
+ (dev->compose_cap.top / vdiv) * stride_cap;
if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
/*
* If there is nothing to copy, then just fill the capture window
* with black.
*/
- for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
- memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+ for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap)
+ memcpy(vcapbuf, tpg->black_line[p], img_width);
return 0;
}
if (dev->overlay_out_enabled &&
dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
vosdbuf = dev->video_vbase;
- vosdbuf += dev->loop_fb_copy.left * pixsize +
+ vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 +
dev->loop_fb_copy.top * stride_osd;
vid_overlay_int_part = dev->loop_vid_overlay.height /
dev->loop_vid_overlay_cap.height;
@@ -295,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
dev->loop_vid_overlay_cap.height;
}
- vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+ vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width);
/* quick is true if no video scaling is needed */
quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
dev->cur_scaled_line = dev->loop_vid_out.height;
- for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+ for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) {
/* osdline is true if this line requires overlay blending */
bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
@@ -311,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
*/
if (y < dev->loop_vid_cap.top ||
y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
- memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+ memcpy(vcapbuf, tpg->black_line[p], img_width);
continue;
}
/* fill the left border with black */
if (dev->loop_vid_cap.left)
- memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+ memcpy(vcapbuf, tpg->black_line[p], vid_cap_left);
/* fill the right border with black */
if (vid_cap_right < img_width)
- memcpy(vcapbuf + vid_cap_right * pixsize,
- tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+ memcpy(vcapbuf + vid_cap_right, tpg->black_line[p],
+ img_width - vid_cap_right);
if (quick && !osdline) {
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+ memcpy(vcapbuf + vid_cap_left,
voutbuf + vid_out_y * stride_out,
- dev->loop_vid_cap.width * pixsize);
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
goto update_vid_out_y;
}
if (dev->cur_scaled_line == vid_out_y) {
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
- dev->scaled_line,
- dev->loop_vid_cap.width * pixsize);
+ memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
goto update_vid_out_y;
}
if (!osdline) {
scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
- dev->loop_vid_out.width, dev->loop_vid_cap.width,
+ tpg_hdiv(tpg, p, dev->loop_vid_out.width),
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width),
tpg_g_twopixelsize(tpg, p));
} else {
/*
@@ -346,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
* loop_vid_overlay rectangle.
*/
unsigned offset =
- (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+ ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) *
+ twopixsize) / 2;
u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
@@ -356,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
dev->loop_vid_overlay.left,
dev->blended_line + offset, osd,
- dev->loop_vid_overlay.width, pixsize);
+ dev->loop_vid_overlay.width, twopixsize / 2);
else
memcpy(dev->blended_line + offset,
- osd, dev->loop_vid_overlay.width * pixsize);
+ osd, (dev->loop_vid_overlay.width * twopixsize) / 2);
scale_line(dev->blended_line, dev->scaled_line,
dev->loop_vid_copy.width, dev->loop_vid_cap.width,
tpg_g_twopixelsize(tpg, p));
}
dev->cur_scaled_line = vid_out_y;
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
- dev->scaled_line,
- dev->loop_vid_cap.width * pixsize);
+ memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
update_vid_out_y:
if (osdline) {
@@ -380,21 +400,22 @@ update_vid_out_y:
}
vid_out_y += vid_out_int_part;
vid_out_error += vid_out_fract_part;
- if (vid_out_error >= dev->loop_vid_cap.height) {
- vid_out_error -= dev->loop_vid_cap.height;
+ if (vid_out_error >= dev->loop_vid_cap.height / vdiv) {
+ vid_out_error -= dev->loop_vid_cap.height / vdiv;
vid_out_y++;
}
}
if (!blank)
return 0;
- for (; y < img_height; y++, vcapbuf += stride_cap)
- memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+ for (; y < img_height; y += vdiv, vcapbuf += stride_cap)
+ memcpy(vcapbuf, tpg->contrast_line[p], img_width);
return 0;
}
static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
{
+ struct tpg_data *tpg = &dev->tpg;
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
unsigned line_height = 16 / factor;
bool is_tv = vivid_is_sdtv_cap(dev);
@@ -427,7 +448,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
* standards.
*/
buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
- V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+ V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
/*
* The sequence counter counts frames, not fields. So divide
* by two.
@@ -436,27 +457,29 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
} else {
buf->vb.v4l2_buf.field = dev->field_cap;
}
- tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field);
- tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
+ tpg_s_field(tpg, buf->vb.v4l2_buf.field,
+ dev->field_cap == V4L2_FIELD_ALTERNATE);
+ tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
vivid_precalc_copy_rects(dev);
- for (p = 0; p < tpg_g_planes(&dev->tpg); p++) {
- void *vbuf = vb2_plane_vaddr(&buf->vb, p);
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ void *vbuf = plane_vaddr(tpg, buf, p,
+ tpg->bytesperline, tpg->buf_height);
/*
* The first plane of a multiplanar format has a non-zero
* data_offset. This helps testing whether the application
* correctly supports non-zero data offsets.
*/
- if (dev->fmt_cap->data_offset[p]) {
+ if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) {
memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
dev->fmt_cap->data_offset[p]);
vbuf += dev->fmt_cap->data_offset[p];
}
- tpg_calc_text_basep(&dev->tpg, basep, p, vbuf);
+ tpg_calc_text_basep(tpg, basep, p, vbuf);
if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
- tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf);
+ tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), p, vbuf);
}
dev->must_blank[buf->vb.v4l2_buf.index] = false;
@@ -475,12 +498,12 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
(dev->field_cap == V4L2_FIELD_ALTERNATE) ?
(buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ?
" top" : " bottom") : "");
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
}
if (dev->osd_mode == 0) {
snprintf(str, sizeof(str), " %dx%d, input %d ",
dev->src_rect.width, dev->src_rect.height, dev->input);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
gain = v4l2_ctrl_g_ctrl(dev->gain);
mutex_lock(dev->ctrl_hdl_user_vid.lock);
@@ -490,38 +513,38 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
dev->contrast->cur.val,
dev->saturation->cur.val,
dev->hue->cur.val);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str),
" autogain %d, gain %3d, alpha 0x%02x ",
dev->autogain->cur.val, gain, dev->alpha->cur.val);
mutex_unlock(dev->ctrl_hdl_user_vid.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
mutex_lock(dev->ctrl_hdl_user_aud.lock);
snprintf(str, sizeof(str),
" volume %3d, mute %d ",
dev->volume->cur.val, dev->mute->cur.val);
mutex_unlock(dev->ctrl_hdl_user_aud.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
mutex_lock(dev->ctrl_hdl_user_gen.lock);
snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
dev->int32->cur.val,
*dev->int64->p_cur.p_s64,
dev->bitmask->cur.val);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
dev->boolean->cur.val,
dev->menu->qmenu[dev->menu->cur.val],
dev->string->p_cur.p_char);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
dev->int_menu->qmenu_int[dev->int_menu->cur.val],
dev->int_menu->cur.val);
mutex_unlock(dev->ctrl_hdl_user_gen.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
if (dev->button_pressed) {
dev->button_pressed--;
snprintf(str, sizeof(str), " button pressed!");
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
}
}
@@ -585,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
int x, y, w, out_x = 0;
+ /*
+ * Overlay support is only supported for formats that have a twopixelsize
+ * that's >= 2. Warn and bail out if that's not the case.
+ */
+ if (WARN_ON(pixsize == 0))
+ return;
if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
dev->overlay_cap_field != buf->vb.v4l2_buf.field)
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 4af55f1..caf1316 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -27,6 +27,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-dv-timings.h>
+#include <linux/fixp-arith.h>
#include "vivid-core.h"
#include "vivid-ctrls.h"
@@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
return 0;
}
-#define FIXP_FRAC (1 << 15)
-#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589))
-
-/* cos() from cx88 driver: cx88-dsp.c */
-static s32 fixp_cos(unsigned int x)
-{
- u32 t2, t4, t6, t8;
- u16 period = x / FIXP_PI;
-
- if (period % 2)
- return -fixp_cos(x - FIXP_PI);
- x = x % FIXP_PI;
- if (x > FIXP_PI/2)
- return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2)));
- /* Now x is between 0 and FIXP_PI/2.
- * To calculate cos(x) we use it's Taylor polinom. */
- t2 = x*x/FIXP_FRAC/2;
- t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4;
- t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6;
- t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8;
- return FIXP_FRAC-t2+t4-t6+t8;
-}
-
-static inline s32 fixp_sin(unsigned int x)
-{
- return -fixp_cos(x + (FIXP_PI / 2));
-}
+#define FIXP_N (15)
+#define FIXP_FRAC (1 << FIXP_N)
+#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC))
void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
{
u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned long i;
unsigned long plane_size = vb2_plane_size(&buf->vb, 0);
- int fixp_src_phase_step, fixp_i, fixp_q;
+ s32 src_phase_step;
+ s32 mod_phase_step;
+ s32 fixp_i;
+ s32 fixp_q;
/*
* TODO: Generated beep tone goes very crackly when sample rate is
@@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
/* calculate phase step */
#define BEEP_FREQ 1000 /* 1kHz beep */
- fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ,
+ src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ,
dev->sdr_adc_freq);
for (i = 0; i < plane_size; i += 2) {
- dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase);
- dev->sdr_fixp_src_phase += fixp_src_phase_step;
+ mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase,
+ FIXP_2PI) >> (31 - FIXP_N);
+
+ dev->sdr_fixp_src_phase += src_phase_step;
+ dev->sdr_fixp_mod_phase += mod_phase_step / 4;
/*
* Transfer phases to [0 / 2xPI] in order to avoid variable
* overflow and make it suitable for cosine implementation
* used, which does not support negative angles.
*/
- while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI))
- dev->sdr_fixp_mod_phase += (2 * FIXP_PI);
- while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI))
- dev->sdr_fixp_mod_phase -= (2 * FIXP_PI);
+ while (dev->sdr_fixp_mod_phase < FIXP_2PI)
+ dev->sdr_fixp_mod_phase += FIXP_2PI;
+ while (dev->sdr_fixp_mod_phase > FIXP_2PI)
+ dev->sdr_fixp_mod_phase -= FIXP_2PI;
+
+ while (dev->sdr_fixp_src_phase > FIXP_2PI)
+ dev->sdr_fixp_src_phase -= FIXP_2PI;
- while (dev->sdr_fixp_src_phase > (2 * FIXP_PI))
- dev->sdr_fixp_src_phase -= (2 * FIXP_PI);
+ fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
+ fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
- fixp_i = fixp_cos(dev->sdr_fixp_mod_phase);
- fixp_q = fixp_sin(dev->sdr_fixp_mod_phase);
+ /* Normalize fraction values represented with 32 bit precision
+ * to fixed point representation with FIXP_N bits */
+ fixp_i >>= (31 - FIXP_N);
+ fixp_q >>= (31 - FIXP_N);
/* convert 'fixp float' to u8 */
/* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index 34493f4..cb766eb 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -35,7 +35,10 @@ const char * const tpg_pattern_strings[] = {
"100% Green",
"100% Blue",
"16x16 Checkers",
+ "2x2 Checkers",
"1x1 Checkers",
+ "2x2 Red/Green Checkers",
+ "1x1 Red/Green Checkers",
"Alternating Hor Lines",
"Alternating Vert Lines",
"One Pixel Wide Cross",
@@ -120,15 +123,20 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
tpg->max_line_width = max_w;
for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
- unsigned pixelsz = plane ? 1 : 4;
+ unsigned pixelsz = plane ? 2 : 4;
tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
if (!tpg->lines[pat][plane])
return -ENOMEM;
+ if (plane == 0)
+ continue;
+ tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+ if (!tpg->downsampled_lines[pat][plane])
+ return -ENOMEM;
}
}
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
- unsigned pixelsz = plane ? 1 : 4;
+ unsigned pixelsz = plane ? 2 : 4;
tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
if (!tpg->contrast_line[plane])
@@ -152,6 +160,10 @@ void tpg_free(struct tpg_data *tpg)
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
vfree(tpg->lines[pat][plane]);
tpg->lines[pat][plane] = NULL;
+ if (plane == 0)
+ continue;
+ vfree(tpg->downsampled_lines[pat][plane]);
+ tpg->downsampled_lines[pat][plane] = NULL;
}
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
vfree(tpg->contrast_line[plane]);
@@ -167,14 +179,38 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
{
tpg->fourcc = fourcc;
tpg->planes = 1;
+ tpg->buffers = 1;
tpg->recalc_colors = true;
+ tpg->interleaved = false;
+ tpg->vdownsampling[0] = 1;
+ tpg->hdownsampling[0] = 1;
+ tpg->hmask[0] = ~0;
+ tpg->hmask[1] = ~0;
+ tpg->hmask[2] = ~0;
+
switch (fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ tpg->interleaved = true;
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->planes = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_RGB332:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
+ case V4L2_PIX_FMT_BGR666:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB32:
@@ -183,16 +219,72 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_XBGR32:
case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_GREY:
tpg->is_yuv = false;
break;
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
+ case V4L2_PIX_FMT_YUV32:
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ tpg->buffers = 3;
+ /* fall through */
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ tpg->vdownsampling[1] = 2;
+ tpg->vdownsampling[2] = 2;
+ tpg->hdownsampling[1] = 2;
+ tpg->hdownsampling[2] = 2;
+ tpg->planes = 3;
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ tpg->vdownsampling[1] = 1;
+ tpg->vdownsampling[2] = 1;
+ tpg->hdownsampling[1] = 2;
+ tpg->hdownsampling[2] = 2;
+ tpg->planes = 3;
+ tpg->is_yuv = true;
+ break;
case V4L2_PIX_FMT_NV16M:
case V4L2_PIX_FMT_NV61M:
+ tpg->buffers = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->hmask[1] = ~1;
tpg->planes = 2;
- /* fall-through */
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ tpg->buffers = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ tpg->vdownsampling[1] = 2;
+ tpg->hdownsampling[1] = 1;
+ tpg->hmask[1] = ~1;
+ tpg->planes = 2;
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV42:
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->planes = 2;
+ tpg->is_yuv = true;
+ break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ tpg->hmask[0] = ~1;
tpg->is_yuv = true;
break;
default:
@@ -200,35 +292,75 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
}
switch (fourcc) {
+ case V4L2_PIX_FMT_RGB332:
+ tpg->twopixelsize[0] = 2;
+ break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
tpg->twopixelsize[0] = 2 * 2;
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
tpg->twopixelsize[0] = 2 * 3;
break;
+ case V4L2_PIX_FMT_BGR666:
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_XRGB32:
case V4L2_PIX_FMT_XBGR32:
case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_YUV32:
tpg->twopixelsize[0] = 2 * 4;
break;
+ case V4L2_PIX_FMT_GREY:
+ tpg->twopixelsize[0] = 2;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV16M:
case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
tpg->twopixelsize[0] = 2;
tpg->twopixelsize[1] = 2;
break;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ tpg->twopixelsize[0] = 2;
+ tpg->twopixelsize[1] = 2;
+ tpg->twopixelsize[2] = 2;
+ break;
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV42:
+ tpg->twopixelsize[0] = 2;
+ tpg->twopixelsize[1] = 4;
+ break;
}
return true;
}
@@ -267,7 +399,8 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
tpg->compose.width = width;
tpg->compose.height = tpg->buf_height;
for (p = 0; p < tpg->planes; p++)
- tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
+ tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
+ (2 * tpg->hdownsampling[p]);
tpg->recalc_square_border = true;
}
@@ -347,9 +480,9 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
{ COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
};
static const int bt2020[3][3] = {
- { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
+ { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
{ COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
- { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
+ { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
};
bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
unsigned y_offset = full ? 0 : 16;
@@ -524,10 +657,10 @@ static void precalculate_color(struct tpg_data *tpg, int k)
g <<= 4;
b <<= 4;
}
- if (tpg->qual == TPG_QUAL_GRAY) {
+ if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
/* Rec. 709 Luma function */
/* (0.2126, 0.7152, 0.0722) * (255 * 256) */
- r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4);
+ r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
}
/*
@@ -601,9 +734,29 @@ static void precalculate_color(struct tpg_data *tpg, int k)
cb = clamp(cb, 16 << 4, 240 << 4);
cr = clamp(cr, 16 << 4, 240 << 4);
}
- tpg->colors[k][0] = clamp(y >> 4, 1, 254);
- tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
- tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+ y = clamp(y >> 4, 1, 254);
+ cb = clamp(cb >> 4, 1, 254);
+ cr = clamp(cr >> 4, 1, 254);
+ switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_YUV444:
+ y >>= 4;
+ cb >>= 4;
+ cr >>= 4;
+ break;
+ case V4L2_PIX_FMT_YUV555:
+ y >>= 3;
+ cb >>= 3;
+ cr >>= 3;
+ break;
+ case V4L2_PIX_FMT_YUV565:
+ y >>= 3;
+ cb >>= 2;
+ cr >>= 3;
+ break;
+ }
+ tpg->colors[k][0] = y;
+ tpg->colors[k][1] = cb;
+ tpg->colors[k][2] = cr;
} else {
if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
r = (r * 219) / 255 + (16 << 4);
@@ -611,20 +764,39 @@ static void precalculate_color(struct tpg_data *tpg, int k)
b = (b * 219) / 255 + (16 << 4);
}
switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_RGB332:
+ r >>= 9;
+ g >>= 9;
+ b >>= 10;
+ break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
r >>= 7;
g >>= 6;
b >>= 7;
break;
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ break;
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
r >>= 7;
g >>= 7;
b >>= 7;
break;
+ case V4L2_PIX_FMT_BGR666:
+ r >>= 6;
+ g >>= 6;
+ b >>= 6;
+ break;
default:
r >>= 4;
g >>= 4;
@@ -665,31 +837,120 @@ static void gen_twopix(struct tpg_data *tpg,
b_v = tpg->colors[color][2]; /* B or precalculated V */
switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_GREY:
+ buf[0][offset] = r_y;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV420M:
+ buf[0][offset] = r_y;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + g_u) / 2;
+ buf[2][0] = (buf[2][0] + b_v) / 2;
+ buf[1][1] = buf[1][0];
+ buf[2][1] = buf[2][0];
+ break;
+ }
+ buf[1][0] = g_u;
+ buf[2][0] = b_v;
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YVU420M:
+ buf[0][offset] = r_y;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + b_v) / 2;
+ buf[2][0] = (buf[2][0] + g_u) / 2;
+ buf[1][1] = buf[1][0];
+ buf[2][1] = buf[2][0];
+ break;
+ }
+ buf[1][0] = b_v;
+ buf[2][0] = g_u;
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV16M:
buf[0][offset] = r_y;
- buf[1][offset] = odd ? b_v : g_u;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + g_u) / 2;
+ buf[1][1] = (buf[1][1] + b_v) / 2;
+ break;
+ }
+ buf[1][0] = g_u;
+ buf[1][1] = b_v;
break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV61M:
buf[0][offset] = r_y;
- buf[1][offset] = odd ? g_u : b_v;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + b_v) / 2;
+ buf[1][1] = (buf[1][1] + g_u) / 2;
+ break;
+ }
+ buf[1][0] = b_v;
+ buf[1][1] = g_u;
+ break;
+
+ case V4L2_PIX_FMT_NV24:
+ buf[0][offset] = r_y;
+ buf[1][2 * offset] = g_u;
+ buf[1][2 * offset + 1] = b_v;
+ break;
+
+ case V4L2_PIX_FMT_NV42:
+ buf[0][offset] = r_y;
+ buf[1][2 * offset] = b_v;
+ buf[1][2 * offset + 1] = g_u;
break;
case V4L2_PIX_FMT_YUYV:
buf[0][offset] = r_y;
- buf[0][offset + 1] = odd ? b_v : g_u;
+ if (odd) {
+ buf[0][1] = (buf[0][1] + g_u) / 2;
+ buf[0][3] = (buf[0][3] + b_v) / 2;
+ break;
+ }
+ buf[0][1] = g_u;
+ buf[0][3] = b_v;
break;
case V4L2_PIX_FMT_UYVY:
- buf[0][offset] = odd ? b_v : g_u;
buf[0][offset + 1] = r_y;
+ if (odd) {
+ buf[0][0] = (buf[0][0] + g_u) / 2;
+ buf[0][2] = (buf[0][2] + b_v) / 2;
+ break;
+ }
+ buf[0][0] = g_u;
+ buf[0][2] = b_v;
break;
case V4L2_PIX_FMT_YVYU:
buf[0][offset] = r_y;
- buf[0][offset + 1] = odd ? g_u : b_v;
+ if (odd) {
+ buf[0][1] = (buf[0][1] + b_v) / 2;
+ buf[0][3] = (buf[0][3] + g_u) / 2;
+ break;
+ }
+ buf[0][1] = b_v;
+ buf[0][3] = g_u;
break;
case V4L2_PIX_FMT_VYUY:
- buf[0][offset] = odd ? g_u : b_v;
buf[0][offset + 1] = r_y;
+ if (odd) {
+ buf[0][0] = (buf[0][0] + b_v) / 2;
+ buf[0][2] = (buf[0][2] + g_u) / 2;
+ break;
+ }
+ buf[0][0] = b_v;
+ buf[0][2] = g_u;
+ break;
+ case V4L2_PIX_FMT_RGB332:
+ buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
break;
+ case V4L2_PIX_FMT_YUV565:
case V4L2_PIX_FMT_RGB565:
buf[0][offset] = (g_u << 5) | b_v;
buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
@@ -698,15 +959,29 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset] = (r_y << 3) | (g_u >> 3);
buf[0][offset + 1] = (g_u << 5) | b_v;
break;
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ alpha = 0;
+ /* fall through */
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_ARGB444:
+ buf[0][offset] = (g_u << 4) | b_v;
+ buf[0][offset + 1] = (alpha & 0xf0) | r_y;
+ break;
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
alpha = 0;
/* fall through */
+ case V4L2_PIX_FMT_YUV555:
case V4L2_PIX_FMT_ARGB555:
buf[0][offset] = (g_u << 5) | b_v;
buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
break;
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ alpha = 0;
+ /* fall through */
+ case V4L2_PIX_FMT_ARGB555X:
buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
buf[0][offset + 1] = (g_u << 5) | b_v;
break;
@@ -720,10 +995,17 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset + 1] = g_u;
buf[0][offset + 2] = r_y;
break;
+ case V4L2_PIX_FMT_BGR666:
+ buf[0][offset] = (b_v << 2) | (g_u >> 4);
+ buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
+ buf[0][offset + 2] = r_y << 6;
+ buf[0][offset + 3] = 0;
+ break;
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_XRGB32:
alpha = 0;
/* fall through */
+ case V4L2_PIX_FMT_YUV32:
case V4L2_PIX_FMT_ARGB32:
buf[0][offset] = alpha;
buf[0][offset + 1] = r_y;
@@ -740,15 +1022,47 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset + 2] = r_y;
buf[0][offset + 3] = alpha;
break;
+ case V4L2_PIX_FMT_SBGGR8:
+ buf[0][offset] = odd ? g_u : b_v;
+ buf[1][offset] = odd ? r_y : g_u;
+ break;
+ case V4L2_PIX_FMT_SGBRG8:
+ buf[0][offset] = odd ? b_v : g_u;
+ buf[1][offset] = odd ? g_u : r_y;
+ break;
+ case V4L2_PIX_FMT_SGRBG8:
+ buf[0][offset] = odd ? r_y : g_u;
+ buf[1][offset] = odd ? g_u : b_v;
+ break;
+ case V4L2_PIX_FMT_SRGGB8:
+ buf[0][offset] = odd ? g_u : r_y;
+ buf[1][offset] = odd ? b_v : g_u;
+ break;
+ }
+}
+
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
+{
+ switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return buf_line & 1;
+ default:
+ return 0;
}
}
/* Return how many pattern lines are used by the current pattern. */
-static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
+static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
{
switch (tpg->pattern) {
case TPG_PAT_CHECKERS_16X16:
+ case TPG_PAT_CHECKERS_2X2:
case TPG_PAT_CHECKERS_1X1:
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ case TPG_PAT_COLOR_CHECKERS_1X1:
case TPG_PAT_ALTERNATING_HLINES:
case TPG_PAT_CROSS_1_PIXEL:
case TPG_PAT_CROSS_2_PIXELS:
@@ -763,14 +1077,18 @@ static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
}
/* Which pattern line should be used for the given frame line. */
-static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
+static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
{
switch (tpg->pattern) {
case TPG_PAT_CHECKERS_16X16:
return (line >> 4) & 1;
case TPG_PAT_CHECKERS_1X1:
+ case TPG_PAT_COLOR_CHECKERS_1X1:
case TPG_PAT_ALTERNATING_HLINES:
return line & 1;
+ case TPG_PAT_CHECKERS_2X2:
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ return (line & 2) >> 1;
case TPG_PAT_100_COLORSQUARES:
case TPG_PAT_100_HCOLORBAR:
return (line * 8) / tpg->src_height;
@@ -789,7 +1107,8 @@ static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
* Which color should be used for the given pattern line and X coordinate.
* Note: x is in the range 0 to 2 * tpg->src_width.
*/
-static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
+static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
+ unsigned pat_line, unsigned x)
{
/* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
should be modified */
@@ -836,6 +1155,15 @@ static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, uns
case TPG_PAT_CHECKERS_1X1:
return ((x & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+ case TPG_PAT_COLOR_CHECKERS_1X1:
+ return ((x & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
+ case TPG_PAT_CHECKERS_2X2:
+ return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
case TPG_PAT_ALTERNATING_HLINES:
return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
case TPG_PAT_ALTERNATING_VLINES:
@@ -948,6 +1276,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg)
static void tpg_precalculate_line(struct tpg_data *tpg)
{
enum tpg_color contrast;
+ u8 pix[TPG_MAX_PLANES][8];
unsigned pat;
unsigned p;
unsigned x;
@@ -974,7 +1303,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
for (x = 0; x < tpg->scaled_width * 2; x += 2) {
unsigned real_x = src_x;
enum tpg_color color1, color2;
- u8 pix[TPG_MAX_PLANES][8];
real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
color1 = tpg_get_color(tpg, pat, real_x);
@@ -1001,39 +1329,53 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
for (p = 0; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
+ unsigned hdiv = tpg->hdownsampling[p];
+ u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
- memcpy(pos, pix[p], twopixsize);
+ memcpy(pos, pix[p], twopixsize / hdiv);
}
}
}
- for (x = 0; x < tpg->scaled_width; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
- gen_twopix(tpg, pix, contrast, 0);
- gen_twopix(tpg, pix, contrast, 1);
- for (p = 0; p < tpg->planes; p++) {
- unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
+ if (tpg->vdownsampling[tpg->planes - 1] > 1) {
+ unsigned pat_lines = tpg_get_pat_lines(tpg);
- memcpy(pos, pix[p], twopixsize);
+ for (pat = 0; pat < pat_lines; pat++) {
+ unsigned next_pat = (pat + 1) % pat_lines;
+
+ for (p = 1; p < tpg->planes; p++) {
+ unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
+ u8 *pos1 = tpg->lines[pat][p];
+ u8 *pos2 = tpg->lines[next_pat][p];
+ u8 *dest = tpg->downsampled_lines[pat][p];
+
+ for (x = 0; x < w; x++, pos1++, pos2++, dest++)
+ *dest = ((u16)*pos1 + (u16)*pos2) / 2;
+ }
}
}
- for (x = 0; x < tpg->scaled_width; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
- gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
- gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
- for (p = 0; p < tpg->planes; p++) {
- unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
+ gen_twopix(tpg, pix, contrast, 0);
+ gen_twopix(tpg, pix, contrast, 1);
+ for (p = 0; p < tpg->planes; p++) {
+ unsigned twopixsize = tpg->twopixelsize[p];
+ u8 *pos = tpg->contrast_line[p];
+ for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
+ memcpy(pos, pix[p], twopixsize);
+ }
+
+ gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+ gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+ for (p = 0; p < tpg->planes; p++) {
+ unsigned twopixsize = tpg->twopixelsize[p];
+ u8 *pos = tpg->black_line[p];
+
+ for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
memcpy(pos, pix[p], twopixsize);
- }
}
- for (x = 0; x < tpg->scaled_width * 2; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
+ for (x = 0; x < tpg->scaled_width * 2; x += 2) {
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
for (p = 0; p < tpg->planes; p++) {
@@ -1043,6 +1385,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
memcpy(pos, pix[p], twopixsize);
}
}
+
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
@@ -1052,8 +1395,8 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
/* need this to do rgb24 rendering */
typedef struct { u16 __; u8 _; } __packed x24;
-void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
- int y, int x, char *text)
+void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+ int y, int x, char *text)
{
int line;
unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
@@ -1083,24 +1426,37 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
div = 2;
for (p = 0; p < tpg->planes; p++) {
- /* Print stream time */
+ unsigned vdiv = tpg->vdownsampling[p];
+ unsigned hdiv = tpg->hdownsampling[p];
+
+ /* Print text */
#define PRINTSTR(PIXTYPE) do { \
PIXTYPE fg; \
PIXTYPE bg; \
memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
\
- for (line = first; line < 16; line += step) { \
+ for (line = first; line < 16; line += vdiv * step) { \
int l = tpg->vflip ? 15 - line : line; \
- PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
- ((y * step + l) / div) * tpg->bytesperline[p] + \
- x * sizeof(PIXTYPE)); \
+ PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
+ ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
+ (x / hdiv) * sizeof(PIXTYPE)); \
unsigned s; \
\
for (s = 0; s < len; s++) { \
u8 chr = font8x16[text[s] * 16 + line]; \
\
- if (tpg->hflip) { \
+ if (hdiv == 2 && tpg->hflip) { \
+ pos[3] = (chr & (0x01 << 6) ? fg : bg); \
+ pos[2] = (chr & (0x01 << 4) ? fg : bg); \
+ pos[1] = (chr & (0x01 << 2) ? fg : bg); \
+ pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+ } else if (hdiv == 2) { \
+ pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+ pos[1] = (chr & (0x01 << 5) ? fg : bg); \
+ pos[2] = (chr & (0x01 << 3) ? fg : bg); \
+ pos[3] = (chr & (0x01 << 1) ? fg : bg); \
+ } else if (tpg->hflip) { \
pos[7] = (chr & (0x01 << 7) ? fg : bg); \
pos[6] = (chr & (0x01 << 6) ? fg : bg); \
pos[5] = (chr & (0x01 << 5) ? fg : bg); \
@@ -1120,7 +1476,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
pos[7] = (chr & (0x01 << 0) ? fg : bg); \
} \
\
- pos += tpg->hflip ? -8 : 8; \
+ pos += (tpg->hflip ? -8 : 8) / hdiv; \
} \
} \
} while (0)
@@ -1187,7 +1543,7 @@ void tpg_update_mv_step(struct tpg_data *tpg)
}
/* Map the line number relative to the crop rectangle to a frame line number */
-static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
+static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
unsigned field)
{
switch (field) {
@@ -1204,7 +1560,7 @@ static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
* Map the line number relative to the compose rectangle to a destination
* buffer line number.
*/
-static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
+static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
unsigned field)
{
y += tpg->compose.top;
@@ -1265,6 +1621,10 @@ static void tpg_recalc(struct tpg_data *tpg)
V4L2_QUANTIZATION_LIM_RANGE;
break;
}
+ } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
+ /* R'G'B' BT.2020 is limited range */
+ tpg->real_quantization =
+ V4L2_QUANTIZATION_LIM_RANGE;
}
}
tpg_precalculate_colors(tpg);
@@ -1283,191 +1643,388 @@ void tpg_calc_text_basep(struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
{
unsigned stride = tpg->bytesperline[p];
+ unsigned h = tpg->buf_height;
tpg_recalc(tpg);
basep[p][0] = vbuf;
basep[p][1] = vbuf;
+ h /= tpg->vdownsampling[p];
if (tpg->field == V4L2_FIELD_SEQ_TB)
- basep[p][1] += tpg->buf_height * stride / 2;
+ basep[p][1] += h * stride / 2;
else if (tpg->field == V4L2_FIELD_SEQ_BT)
- basep[p][0] += tpg->buf_height * stride / 2;
+ basep[p][0] += h * stride / 2;
+ if (p == 0 && tpg->interleaved)
+ tpg_calc_text_basep(tpg, basep, 1, vbuf);
}
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+static int tpg_pattern_avg(const struct tpg_data *tpg,
+ unsigned pat1, unsigned pat2)
{
- bool is_tv = std;
- bool is_60hz = is_tv && (std & V4L2_STD_525_60);
- unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
- unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
- unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
- unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+ unsigned pat_lines = tpg_get_pat_lines(tpg);
+
+ if (pat1 == (pat2 + 1) % pat_lines)
+ return pat2;
+ if (pat2 == (pat1 + 1) % pat_lines)
+ return pat1;
+ return -1;
+}
+
+/*
+ * This struct contains common parameters used by both the drawing of the
+ * test pattern and the drawing of the extras (borders, square, etc.)
+ */
+struct tpg_draw_params {
+ /* common data */
+ bool is_tv;
+ bool is_60hz;
+ unsigned twopixsize;
+ unsigned img_width;
+ unsigned stride;
+ unsigned hmax;
+ unsigned frame_line;
+ unsigned frame_line_next;
+
+ /* test pattern */
+ unsigned mv_hor_old;
+ unsigned mv_hor_new;
+ unsigned mv_vert_old;
+ unsigned mv_vert_new;
+
+ /* extras */
unsigned wss_width;
- unsigned f;
- int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
- int h;
- unsigned twopixsize = tpg->twopixelsize[p];
- unsigned img_width = tpg->compose.width * twopixsize / 2;
- unsigned line_offset;
- unsigned left_pillar_width = 0;
- unsigned right_pillar_start = img_width;
- unsigned stride = tpg->bytesperline[p];
- unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
- u8 *orig_vbuf = vbuf;
+ unsigned wss_random_offset;
+ unsigned sav_eav_f;
+ unsigned left_pillar_width;
+ unsigned right_pillar_start;
+};
- /* Coarse scaling with Bresenham */
- unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
- unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
- unsigned src_y = 0;
- unsigned error = 0;
+static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
+ struct tpg_draw_params *params)
+{
+ params->mv_hor_old =
+ tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
+ params->mv_hor_new =
+ tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
+ tpg->src_width);
+ params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+ params->mv_vert_new =
+ (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+}
- tpg_recalc(tpg);
+static void tpg_fill_params_extras(const struct tpg_data *tpg,
+ unsigned p,
+ struct tpg_draw_params *params)
+{
+ unsigned left_pillar_width = 0;
+ unsigned right_pillar_start = params->img_width;
+
+ params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
+ tpg->src_width / 2 - tpg->crop.left : 0;
+ if (params->wss_width > tpg->crop.width)
+ params->wss_width = tpg->crop.width;
+ params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
+ params->wss_random_offset =
+ params->twopixsize * prandom_u32_max(tpg->src_width / 2);
- mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
- mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
- wss_width = tpg->crop.left < tpg->src_width / 2 ?
- tpg->src_width / 2 - tpg->crop.left : 0;
- if (wss_width > tpg->crop.width)
- wss_width = tpg->crop.width;
- wss_width = wss_width * tpg->scaled_width / tpg->src_width;
-
- vbuf += tpg->compose.left * twopixsize / 2;
- line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
- line_offset = (line_offset & ~1) * twopixsize / 2;
if (tpg->crop.left < tpg->border.left) {
left_pillar_width = tpg->border.left - tpg->crop.left;
if (left_pillar_width > tpg->crop.width)
left_pillar_width = tpg->crop.width;
- left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
- left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
+ left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
}
- if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
- right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
- right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
- right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
- if (right_pillar_start > img_width)
- right_pillar_start = img_width;
+ params->left_pillar_width = left_pillar_width;
+
+ if (tpg->crop.left + tpg->crop.width >
+ tpg->border.left + tpg->border.width) {
+ right_pillar_start =
+ tpg->border.left + tpg->border.width - tpg->crop.left;
+ right_pillar_start =
+ tpg_hscale_div(tpg, p, right_pillar_start);
+ if (right_pillar_start > params->img_width)
+ right_pillar_start = params->img_width;
}
+ params->right_pillar_start = right_pillar_start;
- f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+ params->sav_eav_f = tpg->field ==
+ (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+}
- for (h = 0; h < tpg->compose.height; h++) {
- bool even;
- bool fill_blank = false;
- unsigned frame_line;
- unsigned buf_line;
- unsigned pat_line_old;
- unsigned pat_line_new;
- u8 *linestart_older;
- u8 *linestart_newer;
- u8 *linestart_top;
- u8 *linestart_bottom;
-
- frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
- even = !(frame_line & 1);
- buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
- src_y += int_part;
- error += fract_part;
- if (error >= tpg->compose.height) {
- error -= tpg->compose.height;
- src_y++;
- }
+static void tpg_fill_plane_extras(const struct tpg_data *tpg,
+ const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
+{
+ unsigned twopixsize = params->twopixsize;
+ unsigned img_width = params->img_width;
+ unsigned frame_line = params->frame_line;
+ const struct v4l2_rect *sq = &tpg->square;
+ const struct v4l2_rect *b = &tpg->border;
+ const struct v4l2_rect *c = &tpg->crop;
+
+ if (params->is_tv && !params->is_60hz &&
+ frame_line == 0 && params->wss_width) {
+ /*
+ * Replace the first half of the top line of a 50 Hz frame
+ * with random data to simulate a WSS signal.
+ */
+ u8 *wss = tpg->random_line[p] + params->wss_random_offset;
- if (h >= hmax) {
- if (hmax == tpg->compose.height)
- continue;
- if (!tpg->perc_fill_blank)
- continue;
- fill_blank = true;
- }
+ memcpy(vbuf, wss, params->wss_width);
+ }
+
+ if (tpg->show_border && frame_line >= b->top &&
+ frame_line < b->top + b->height) {
+ unsigned bottom = b->top + b->height - 1;
+ unsigned left = params->left_pillar_width;
+ unsigned right = params->right_pillar_start;
- if (tpg->vflip)
- frame_line = tpg->src_height - frame_line - 1;
-
- if (fill_blank) {
- linestart_older = tpg->contrast_line[p];
- linestart_newer = tpg->contrast_line[p];
- } else if (tpg->qual != TPG_QUAL_NOISE &&
- (frame_line < tpg->border.top ||
- frame_line >= tpg->border.top + tpg->border.height)) {
- linestart_older = tpg->black_line[p];
- linestart_newer = tpg->black_line[p];
- } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
- linestart_older = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
- linestart_newer = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
+ if (frame_line == b->top || frame_line == b->top + 1 ||
+ frame_line == bottom || frame_line == bottom - 1) {
+ memcpy(vbuf + left, tpg->contrast_line[p],
+ right - left);
} else {
- pat_line_old = tpg_get_pat_line(tpg,
- (frame_line + mv_vert_old) % tpg->src_height);
- pat_line_new = tpg_get_pat_line(tpg,
- (frame_line + mv_vert_new) % tpg->src_height);
- linestart_older = tpg->lines[pat_line_old][p] +
- mv_hor_old * twopixsize / 2;
- linestart_newer = tpg->lines[pat_line_new][p] +
- mv_hor_new * twopixsize / 2;
- linestart_older += line_offset;
- linestart_newer += line_offset;
+ if (b->left >= c->left &&
+ b->left < c->left + c->width)
+ memcpy(vbuf + left,
+ tpg->contrast_line[p], twopixsize);
+ if (b->left + b->width > c->left &&
+ b->left + b->width <= c->left + c->width)
+ memcpy(vbuf + right - twopixsize,
+ tpg->contrast_line[p], twopixsize);
}
- if (is_60hz) {
- linestart_top = linestart_newer;
- linestart_bottom = linestart_older;
- } else {
- linestart_top = linestart_older;
- linestart_bottom = linestart_newer;
+ }
+ if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+ frame_line < b->top + b->height) {
+ memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
+ memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
+ img_width - params->right_pillar_start);
+ }
+ if (tpg->show_square && frame_line >= sq->top &&
+ frame_line < sq->top + sq->height &&
+ sq->left < c->left + c->width &&
+ sq->left + sq->width >= c->left) {
+ unsigned left = sq->left;
+ unsigned width = sq->width;
+
+ if (c->left > left) {
+ width -= c->left - left;
+ left = c->left;
}
+ if (c->left + c->width < left + width)
+ width -= left + width - c->left - c->width;
+ left -= c->left;
+ left = tpg_hscale_div(tpg, p, left);
+ width = tpg_hscale_div(tpg, p, width);
+ memcpy(vbuf + left, tpg->contrast_line[p], width);
+ }
+ if (tpg->insert_sav) {
+ unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
+ u8 *p = vbuf + offset;
+ unsigned vact = 0, hact = 0;
+
+ p[0] = 0xff;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0x80 | (params->sav_eav_f << 6) |
+ (vact << 5) | (hact << 4) |
+ ((hact ^ vact) << 3) |
+ ((hact ^ params->sav_eav_f) << 2) |
+ ((params->sav_eav_f ^ vact) << 1) |
+ (hact ^ vact ^ params->sav_eav_f);
+ }
+ if (tpg->insert_eav) {
+ unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
+ u8 *p = vbuf + offset;
+ unsigned vact = 0, hact = 1;
+
+ p[0] = 0xff;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0x80 | (params->sav_eav_f << 6) |
+ (vact << 5) | (hact << 4) |
+ ((hact ^ vact) << 3) |
+ ((hact ^ params->sav_eav_f) << 2) |
+ ((params->sav_eav_f ^ vact) << 1) |
+ (hact ^ vact ^ params->sav_eav_f);
+ }
+}
- switch (tpg->field) {
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_SEQ_TB:
- case V4L2_FIELD_SEQ_BT:
- if (even)
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- else
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- break;
- case V4L2_FIELD_INTERLACED_BT:
- if (even)
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- else
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- break;
- case V4L2_FIELD_TOP:
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- break;
- case V4L2_FIELD_BOTTOM:
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- break;
- case V4L2_FIELD_NONE:
- default:
- memcpy(vbuf + buf_line * stride, linestart_older, img_width);
- break;
- }
+static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
+ const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
+{
+ unsigned twopixsize = params->twopixsize;
+ unsigned img_width = params->img_width;
+ unsigned mv_hor_old = params->mv_hor_old;
+ unsigned mv_hor_new = params->mv_hor_new;
+ unsigned mv_vert_old = params->mv_vert_old;
+ unsigned mv_vert_new = params->mv_vert_new;
+ unsigned frame_line = params->frame_line;
+ unsigned frame_line_next = params->frame_line_next;
+ unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
+ bool even;
+ bool fill_blank = false;
+ unsigned pat_line_old;
+ unsigned pat_line_new;
+ u8 *linestart_older;
+ u8 *linestart_newer;
+ u8 *linestart_top;
+ u8 *linestart_bottom;
+
+ even = !(frame_line & 1);
+
+ if (h >= params->hmax) {
+ if (params->hmax == tpg->compose.height)
+ return;
+ if (!tpg->perc_fill_blank)
+ return;
+ fill_blank = true;
+ }
- if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
- /*
- * Replace the first half of the top line of a 50 Hz frame
- * with random data to simulate a WSS signal.
- */
- u8 *wss = tpg->random_line[p] +
+ if (tpg->vflip) {
+ frame_line = tpg->src_height - frame_line - 1;
+ frame_line_next = tpg->src_height - frame_line_next - 1;
+ }
+
+ if (fill_blank) {
+ linestart_older = tpg->contrast_line[p];
+ linestart_newer = tpg->contrast_line[p];
+ } else if (tpg->qual != TPG_QUAL_NOISE &&
+ (frame_line < tpg->border.top ||
+ frame_line >= tpg->border.top + tpg->border.height)) {
+ linestart_older = tpg->black_line[p];
+ linestart_newer = tpg->black_line[p];
+ } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+ linestart_older = tpg->random_line[p] +
+ twopixsize * prandom_u32_max(tpg->src_width / 2);
+ linestart_newer = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2);
+ } else {
+ unsigned frame_line_old =
+ (frame_line + mv_vert_old) % tpg->src_height;
+ unsigned frame_line_new =
+ (frame_line + mv_vert_new) % tpg->src_height;
+ unsigned pat_line_next_old;
+ unsigned pat_line_next_new;
- memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
+ pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
+ pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
+ linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
+ linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
+
+ if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
+ int avg_pat;
+
+ /*
+ * Now decide whether we need to use downsampled_lines[].
+ * That's necessary if the two lines use different patterns.
+ */
+ pat_line_next_old = tpg_get_pat_line(tpg,
+ (frame_line_next + mv_vert_old) % tpg->src_height);
+ pat_line_next_new = tpg_get_pat_line(tpg,
+ (frame_line_next + mv_vert_new) % tpg->src_height);
+
+ switch (tpg->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED_TB:
+ avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
+ if (avg_pat < 0)
+ break;
+ linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
+ linestart_newer = linestart_older;
+ break;
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_SEQ_BT:
+ case V4L2_FIELD_SEQ_TB:
+ avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
+ if (avg_pat >= 0)
+ linestart_older = tpg->downsampled_lines[avg_pat][p] +
+ mv_hor_old;
+ avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
+ if (avg_pat >= 0)
+ linestart_newer = tpg->downsampled_lines[avg_pat][p] +
+ mv_hor_new;
+ break;
+ }
}
+ linestart_older += line_offset;
+ linestart_newer += line_offset;
+ }
+ if (tpg->field_alternate) {
+ linestart_top = linestart_bottom = linestart_older;
+ } else if (params->is_60hz) {
+ linestart_top = linestart_newer;
+ linestart_bottom = linestart_older;
+ } else {
+ linestart_top = linestart_older;
+ linestart_bottom = linestart_newer;
+ }
+
+ switch (tpg->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
+ if (even)
+ memcpy(vbuf, linestart_top, img_width);
+ else
+ memcpy(vbuf, linestart_bottom, img_width);
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ if (even)
+ memcpy(vbuf, linestart_bottom, img_width);
+ else
+ memcpy(vbuf, linestart_top, img_width);
+ break;
+ case V4L2_FIELD_TOP:
+ memcpy(vbuf, linestart_top, img_width);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ memcpy(vbuf, linestart_bottom, img_width);
+ break;
+ case V4L2_FIELD_NONE:
+ default:
+ memcpy(vbuf, linestart_older, img_width);
+ break;
}
+}
+
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf)
+{
+ struct tpg_draw_params params;
+ unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+
+ /* Coarse scaling with Bresenham */
+ unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+ unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+ unsigned src_y = 0;
+ unsigned error = 0;
+ unsigned h;
+
+ tpg_recalc(tpg);
+
+ params.is_tv = std;
+ params.is_60hz = std & V4L2_STD_525_60;
+ params.twopixsize = tpg->twopixelsize[p];
+ params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
+ params.stride = tpg->bytesperline[p];
+ params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+
+ tpg_fill_params_pattern(tpg, p, &params);
+ tpg_fill_params_extras(tpg, p, &params);
+
+ vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
- vbuf = orig_vbuf;
- vbuf += tpg->compose.left * twopixsize / 2;
- src_y = 0;
- error = 0;
for (h = 0; h < tpg->compose.height; h++) {
- unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
- unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
- const struct v4l2_rect *sq = &tpg->square;
- const struct v4l2_rect *b = &tpg->border;
- const struct v4l2_rect *c = &tpg->crop;
+ unsigned buf_line;
+ params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+ params.frame_line_next = params.frame_line;
+ buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
src_y += int_part;
error += fract_part;
if (error >= tpg->compose.height) {
@@ -1475,80 +2032,61 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
src_y++;
}
- if (tpg->show_border && frame_line >= b->top &&
- frame_line < b->top + b->height) {
- unsigned bottom = b->top + b->height - 1;
- unsigned left = left_pillar_width;
- unsigned right = right_pillar_start;
+ /*
+ * For line-interleaved formats determine the 'plane'
+ * based on the buffer line.
+ */
+ if (tpg_g_interleaved(tpg))
+ p = tpg_g_interleaved_plane(tpg, buf_line);
- if (frame_line == b->top || frame_line == b->top + 1 ||
- frame_line == bottom || frame_line == bottom - 1) {
- memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
- right - left);
+ if (tpg->vdownsampling[p] > 1) {
+ /*
+ * When doing vertical downsampling the field setting
+ * matters: for SEQ_BT/TB we downsample each field
+ * separately (i.e. lines 0+2 are combined, as are
+ * lines 1+3), for the other field settings we combine
+ * odd and even lines. Doing that for SEQ_BT/TB would
+ * be really weird.
+ */
+ if (tpg->field == V4L2_FIELD_SEQ_BT ||
+ tpg->field == V4L2_FIELD_SEQ_TB) {
+ unsigned next_src_y = src_y;
+
+ if ((h & 3) >= 2)
+ continue;
+ next_src_y += int_part;
+ if (error + fract_part >= tpg->compose.height)
+ next_src_y++;
+ params.frame_line_next =
+ tpg_calc_frameline(tpg, next_src_y, tpg->field);
} else {
- if (b->left >= c->left &&
- b->left < c->left + c->width)
- memcpy(vbuf + buf_line * stride + left,
- tpg->contrast_line[p], twopixsize);
- if (b->left + b->width > c->left &&
- b->left + b->width <= c->left + c->width)
- memcpy(vbuf + buf_line * stride + right - twopixsize,
- tpg->contrast_line[p], twopixsize);
+ if (h & 1)
+ continue;
+ params.frame_line_next =
+ tpg_calc_frameline(tpg, src_y, tpg->field);
}
+
+ buf_line /= tpg->vdownsampling[p];
}
- if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
- frame_line < b->top + b->height) {
- memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
- memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
- img_width - right_pillar_start);
- }
- if (tpg->show_square && frame_line >= sq->top &&
- frame_line < sq->top + sq->height &&
- sq->left < c->left + c->width &&
- sq->left + sq->width >= c->left) {
- unsigned left = sq->left;
- unsigned width = sq->width;
-
- if (c->left > left) {
- width -= c->left - left;
- left = c->left;
- }
- if (c->left + c->width < left + width)
- width -= left + width - c->left - c->width;
- left -= c->left;
- left = (left * tpg->scaled_width) / tpg->src_width;
- left = (left & ~1) * twopixsize / 2;
- width = (width * tpg->scaled_width) / tpg->src_width;
- width = (width & ~1) * twopixsize / 2;
- memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
- }
- if (tpg->insert_sav) {
- unsigned offset = (tpg->compose.width / 6) * twopixsize;
- u8 *p = vbuf + buf_line * stride + offset;
- unsigned vact = 0, hact = 0;
-
- p[0] = 0xff;
- p[1] = 0;
- p[2] = 0;
- p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
- ((hact ^ vact) << 3) |
- ((hact ^ f) << 2) |
- ((f ^ vact) << 1) |
- (hact ^ vact ^ f);
- }
- if (tpg->insert_eav) {
- unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
- u8 *p = vbuf + buf_line * stride + offset;
- unsigned vact = 0, hact = 1;
-
- p[0] = 0xff;
- p[1] = 0;
- p[2] = 0;
- p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
- ((hact ^ vact) << 3) |
- ((hact ^ f) << 2) |
- ((f ^ vact) << 1) |
- (hact ^ vact ^ f);
- }
+ tpg_fill_plane_pattern(tpg, &params, p, h,
+ vbuf + buf_line * params.stride);
+ tpg_fill_plane_extras(tpg, &params, p, h,
+ vbuf + buf_line * params.stride);
+ }
+}
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+ unsigned offset = 0;
+ unsigned i;
+
+ if (tpg->buffers > 1) {
+ tpg_fill_plane_buffer(tpg, std, p, vbuf);
+ return;
+ }
+
+ for (i = 0; i < tpg_g_planes(tpg); i++) {
+ tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
+ offset += tpg_calc_plane_size(tpg, i);
}
}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index bd8b1c7..a50cd2e 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -41,7 +41,10 @@ enum tpg_pattern {
TPG_PAT_GREEN,
TPG_PAT_BLUE,
TPG_PAT_CHECKERS_16X16,
+ TPG_PAT_CHECKERS_2X2,
TPG_PAT_CHECKERS_1X1,
+ TPG_PAT_COLOR_CHECKERS_2X2,
+ TPG_PAT_COLOR_CHECKERS_1X1,
TPG_PAT_ALTERNATING_HLINES,
TPG_PAT_ALTERNATING_VLINES,
TPG_PAT_CROSS_1_PIXEL,
@@ -87,7 +90,7 @@ enum tpg_move_mode {
extern const char * const tpg_aspect_strings[];
-#define TPG_MAX_PLANES 2
+#define TPG_MAX_PLANES 3
#define TPG_MAX_PAT_LINES 8
struct tpg_data {
@@ -98,6 +101,7 @@ struct tpg_data {
/* Scaled output frame size */
unsigned scaled_width;
u32 field;
+ bool field_alternate;
/* crop coordinates are frame-based */
struct v4l2_rect crop;
/* compose coordinates are format-based */
@@ -134,7 +138,16 @@ struct tpg_data {
enum tpg_pixel_aspect pix_aspect;
unsigned rgb_range;
unsigned real_rgb_range;
+ unsigned buffers;
unsigned planes;
+ bool interleaved;
+ u8 vdownsampling[TPG_MAX_PLANES];
+ u8 hdownsampling[TPG_MAX_PLANES];
+ /*
+ * horizontal positions must be ANDed with this value to enforce
+ * correct boundaries for packed YUYV values.
+ */
+ unsigned hmask[TPG_MAX_PLANES];
/* Used to store the colors in native format, either RGB or YUV */
u8 colors[TPG_COLOR_MAX][3];
u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
@@ -168,6 +181,7 @@ struct tpg_data {
/* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
unsigned max_line_width;
u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+ u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
u8 *random_line[TPG_MAX_PLANES];
u8 *contrast_line[TPG_MAX_PLANES];
u8 *black_line[TPG_MAX_PLANES];
@@ -180,11 +194,15 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
u32 field);
void tpg_set_font(const u8 *f);
-void tpg_gen_text(struct tpg_data *tpg,
+void tpg_gen_text(const struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
void tpg_calc_text_basep(struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf);
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line);
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf);
bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
const struct v4l2_rect *compose);
@@ -323,9 +341,19 @@ static inline u32 tpg_g_quantization(const struct tpg_data *tpg)
return tpg->quantization;
}
+static inline unsigned tpg_g_buffers(const struct tpg_data *tpg)
+{
+ return tpg->buffers;
+}
+
static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
{
- return tpg->planes;
+ return tpg->interleaved ? 1 : tpg->planes;
+}
+
+static inline bool tpg_g_interleaved(const struct tpg_data *tpg)
+{
+ return tpg->interleaved;
}
static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
@@ -333,6 +361,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p
return tpg->twopixelsize[plane];
}
+static inline unsigned tpg_hdiv(const struct tpg_data *tpg,
+ unsigned plane, unsigned x)
+{
+ return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) *
+ tpg->twopixelsize[plane] / 2;
+}
+
+static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x)
+{
+ return (x * tpg->scaled_width) / tpg->src_width;
+}
+
+static inline unsigned tpg_hscale_div(const struct tpg_data *tpg,
+ unsigned plane, unsigned x)
+{
+ return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x));
+}
+
static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
{
return tpg->bytesperline[plane];
@@ -340,7 +386,60 @@ static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned p
static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
{
- tpg->bytesperline[plane] = bpl;
+ unsigned p;
+
+ if (tpg->buffers > 1) {
+ tpg->bytesperline[plane] = bpl;
+ return;
+ }
+
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+ tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
+ }
+}
+
+
+static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane)
+{
+ unsigned w = 0;
+ unsigned p;
+
+ if (tpg->buffers > 1)
+ return tpg_g_bytesperline(tpg, plane);
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = tpg_g_bytesperline(tpg, p);
+
+ w += plane_w / tpg->vdownsampling[p];
+ }
+ return w;
+}
+
+static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg,
+ unsigned plane, unsigned bpl)
+{
+ unsigned w = 0;
+ unsigned p;
+
+ if (tpg->buffers > 1)
+ return bpl;
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+ plane_w /= tpg->hdownsampling[p];
+ w += plane_w / tpg->vdownsampling[p];
+ }
+ return w;
+}
+
+static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane)
+{
+ if (plane >= tpg_g_planes(tpg))
+ return 0;
+
+ return tpg_g_bytesperline(tpg, plane) * tpg->buf_height /
+ tpg->vdownsampling[plane];
}
static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
@@ -348,9 +447,10 @@ static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
tpg->buf_height = h;
}
-static inline void tpg_s_field(struct tpg_data *tpg, unsigned field)
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate)
{
tpg->field = field;
+ tpg->field_alternate = alternate;
}
static inline void tpg_s_perc_fill(struct tpg_data *tpg,
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 867a29a..dab5990 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -42,20 +42,26 @@ static const struct vivid_fmt formats_ovl[] = {
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB555 (LE)",
.fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "ARGB555 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
};
@@ -94,7 +100,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
unsigned sizes[], void *alloc_ctxs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
- unsigned planes = tpg_g_planes(&dev->tpg);
+ unsigned buffers = tpg_g_buffers(&dev->tpg);
unsigned h = dev->fmt_cap_rect.height;
unsigned p;
@@ -127,39 +133,36 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
mp = &fmt->fmt.pix_mp;
/*
* Check if the number of planes in the specified format match
- * the number of planes in the current format. You can't mix that.
+ * the number of buffers in the current format. You can't mix that.
*/
- if (mp->num_planes != planes)
+ if (mp->num_planes != buffers)
return -EINVAL;
vfmt = vivid_get_format(dev, mp->pixelformat);
- for (p = 0; p < planes; p++) {
+ for (p = 0; p < buffers; p++) {
sizes[p] = mp->plane_fmt[p].sizeimage;
- if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h +
+ if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
vfmt->data_offset[p])
return -EINVAL;
}
} else {
- for (p = 0; p < planes; p++)
- sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h +
+ for (p = 0; p < buffers; p++)
+ sizes[p] = tpg_g_line_width(&dev->tpg, p) * h +
dev->fmt_cap->data_offset[p];
}
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
- *nplanes = planes;
+ *nplanes = buffers;
/*
* videobuf2-vmalloc allocator is context-less so no need to set
* alloc_ctxs array.
*/
- if (planes == 2)
- dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
- *nbuffers, sizes[0], sizes[1]);
- else
- dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
- *nbuffers, sizes[0]);
+ dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
+ for (p = 0; p < buffers; p++)
+ dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]);
return 0;
}
@@ -168,7 +171,7 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
unsigned long size;
- unsigned planes = tpg_g_planes(&dev->tpg);
+ unsigned buffers = tpg_g_buffers(&dev->tpg);
unsigned p;
dprintk(dev, 1, "%s\n", __func__);
@@ -184,13 +187,13 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb)
dev->buf_prepare_error = false;
return -EINVAL;
}
- for (p = 0; p < planes; p++) {
- size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height +
+ for (p = 0; p < buffers; p++) {
+ size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height +
dev->fmt_cap->data_offset[p];
- if (vb2_plane_size(vb, 0) < size) {
+ if (vb2_plane_size(vb, p) < size) {
dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n",
- __func__, p, vb2_plane_size(vb, 0), size);
+ __func__, p, vb2_plane_size(vb, p), size);
return -EINVAL;
}
@@ -441,7 +444,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
*/
if (keep_controls || !dev->colorspace)
break;
- if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+ if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) {
if (bt->width == 720 && bt->height <= 576)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
@@ -526,11 +529,11 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv,
mp->colorspace = vivid_colorspace_cap(dev);
mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
mp->quantization = vivid_quantization_cap(dev);
- mp->num_planes = dev->fmt_cap->planes;
+ mp->num_planes = dev->fmt_cap->buffers;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
mp->plane_fmt[p].sizeimage =
- mp->plane_fmt[p].bytesperline * mp->height +
+ tpg_g_line_width(&dev->tpg, p) * mp->height +
dev->fmt_cap->data_offset[p];
}
return 0;
@@ -596,18 +599,19 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
/* This driver supports custom bytesperline values */
- /* Calculate the minimum supported bytesperline value */
- bytesperline = (mp->width * fmt->depth) >> 3;
- /* Calculate the maximum supported bytesperline value */
- max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
- mp->num_planes = fmt->planes;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
+ /* Calculate the minimum supported bytesperline value */
+ bytesperline = (mp->width * fmt->bit_depth[p]) >> 3;
+ /* Calculate the maximum supported bytesperline value */
+ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3;
+
if (pfmt[p].bytesperline > max_bpl)
pfmt[p].bytesperline = max_bpl;
if (pfmt[p].bytesperline < bytesperline)
pfmt[p].bytesperline = bytesperline;
- pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height +
- fmt->data_offset[p];
+ pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) *
+ mp->height + fmt->data_offset[p];
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
mp->colorspace = vivid_colorspace_cap(dev);
@@ -627,6 +631,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
struct vb2_queue *q = &dev->vb_vid_cap_q;
int ret = vivid_try_fmt_vid_cap(file, priv, f);
unsigned factor = 1;
+ unsigned p;
unsigned i;
if (ret < 0)
@@ -729,13 +734,15 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
dev->fmt_cap_rect.width = mp->width;
dev->fmt_cap_rect.height = mp->height;
tpg_s_buf_height(&dev->tpg, mp->height);
- tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline);
- if (tpg_g_planes(&dev->tpg) > 1)
- tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline);
+ tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+ for (p = 0; p < tpg_g_buffers(&dev->tpg); p++)
+ tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline);
dev->field_cap = mp->field;
- tpg_s_field(&dev->tpg, dev->field_cap);
+ if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+ tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true);
+ else
+ tpg_s_field(&dev->tpg, dev->field_cap, false);
tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap);
- tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
if (vivid_is_sdtv_cap(dev))
dev->tv_field_cap = mp->field;
tpg_update_mv_step(&dev->tpg);
@@ -1012,8 +1019,12 @@ int vivid_vid_cap_cropcap(struct file *file, void *priv,
int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
+ struct vivid_dev *dev = video_drvdata(file);
const struct vivid_fmt *fmt;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (f->index >= ARRAY_SIZE(formats_ovl))
return -EINVAL;
@@ -1032,6 +1043,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_window *win = &f->fmt.win;
unsigned clipcount = win->clipcount;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
win->w.top = dev->overlay_cap_top;
win->w.left = dev->overlay_cap_left;
win->w.width = compose->width;
@@ -1063,6 +1077,9 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_window *win = &f->fmt.win;
int i, j;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
win->w.left = clamp_t(int, win->w.left,
-dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
win->w.top = clamp_t(int, win->w.top,
@@ -1150,6 +1167,9 @@ int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
{
struct vivid_dev *dev = video_drvdata(file);
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (i && dev->fb_vbase_cap == NULL)
return -EINVAL;
@@ -1169,6 +1189,9 @@ int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
{
struct vivid_dev *dev = video_drvdata(file);
+ if (dev->multiplanar)
+ return -ENOTTY;
+
*a = dev->fb_cap;
a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
V4L2_FBUF_CAP_LIST_CLIPPING;
@@ -1185,6 +1208,9 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
struct vivid_dev *dev = video_drvdata(file);
const struct vivid_fmt *fmt;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
@@ -1202,7 +1228,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
fmt = vivid_get_format(dev, a->fmt.pixelformat);
if (!fmt || !fmt->can_do_overlay)
return -EINVAL;
- if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8)
+ if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8)
return -EINVAL;
if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
return -EINVAL;
@@ -1332,7 +1358,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
break;
case HDMI:
- if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+ if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) {
if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
@@ -1552,6 +1578,65 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
return 0;
}
+static void find_aspect_ratio(u32 width, u32 height,
+ u32 *num, u32 *denom)
+{
+ if (!(height % 3) && ((height * 4 / 3) == width)) {
+ *num = 4;
+ *denom = 3;
+ } else if (!(height % 9) && ((height * 16 / 9) == width)) {
+ *num = 16;
+ *denom = 9;
+ } else if (!(height % 10) && ((height * 16 / 10) == width)) {
+ *num = 16;
+ *denom = 10;
+ } else if (!(height % 4) && ((height * 5 / 4) == width)) {
+ *num = 5;
+ *denom = 4;
+ } else if (!(height % 9) && ((height * 15 / 9) == width)) {
+ *num = 15;
+ *denom = 9;
+ } else { /* default to 16:9 */
+ *num = 16;
+ *denom = 9;
+ }
+}
+
+static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
+{
+ struct v4l2_bt_timings *bt = &timings->bt;
+ u32 total_h_pixel;
+ u32 total_v_lines;
+ u32 h_freq;
+
+ if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap,
+ NULL, NULL))
+ return false;
+
+ total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt);
+ total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+ h_freq = (u32)bt->pixelclock / total_h_pixel;
+
+ if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) {
+ if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync,
+ bt->polarities, timings))
+ return true;
+ }
+
+ if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) {
+ struct v4l2_fract aspect_ratio;
+
+ find_aspect_ratio(bt->width, bt->height,
+ &aspect_ratio.numerator,
+ &aspect_ratio.denominator);
+ if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync,
+ bt->polarities, aspect_ratio, timings))
+ return true;
+ }
+ return false;
+}
+
int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
struct v4l2_dv_timings *timings)
{
@@ -1559,13 +1644,16 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
if (!vivid_is_hdmi_cap(dev))
return -ENODATA;
- if (vb2_is_busy(&dev->vb_vid_cap_q))
- return -EBUSY;
if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
- 0, NULL, NULL))
+ 0, NULL, NULL) &&
+ !valid_cvt_gtf_timings(timings))
return -EINVAL;
+
if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
return 0;
+ if (vb2_is_busy(&dev->vb_vid_cap_q))
+ return -EBUSY;
+
dev->dv_timings_cap = *timings;
vivid_update_format_cap(dev, false);
return 0;
@@ -1663,18 +1751,14 @@ int vidioc_enum_frameintervals(struct file *file, void *priv,
return -EINVAL;
if (!vivid_is_webcam(dev)) {
- static const struct v4l2_fract step = { 1, 1 };
-
if (fival->index)
return -EINVAL;
if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM)
return -EINVAL;
if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM)
return -EINVAL;
- fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
- fival->stepwise.min = tpf_min;
- fival->stepwise.max = tpf_max;
- fival->stepwise.step = step;
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = dev->timeperframe_vid_cap;
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 6bef1e6..aa44627 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -33,8 +33,9 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000,
- V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+ V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000,
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+ V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
};
@@ -46,145 +47,435 @@ struct vivid_fmt vivid_formats[] = {
{
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
- .data_offset = { PLANE0_DATA_OFFSET, 0 },
+ .buffers = 1,
+ .data_offset = { PLANE0_DATA_OFFSET },
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
},
{
.name = "4:2:2, packed, YVYU",
.fourcc = V4L2_PIX_FMT_YVYU,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
},
{
.name = "4:2:2, packed, VYUY",
.fourcc = V4L2_PIX_FMT_VYUY,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .is_yuv = true,
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:2 triplanar",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:0 triplanar",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:0 triplanar",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:0 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:0 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:2 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:2 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:4:4 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV24,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 16 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:4:4 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV42,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 16 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV555 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x8000,
+ },
+ {
+ .name = "YUV565 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV444",
+ .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0xf000,
+ },
+ {
+ .name = "YUV32 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x000000ff,
+ },
+ {
+ .name = "Monochrome",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "RGB332",
+ .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
+ .name = "RGB444",
+ .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "XRGB444",
+ .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "ARGB444",
+ .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x00f0,
+ },
+ {
.name = "RGB555 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "XRGB555 (LE)",
- .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "ARGB555 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
.alpha_mask = 0x8000,
},
{
.name = "RGB555 (BE)",
- .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
- .can_do_overlay = true,
+ .buffers = 1,
+ },
+ {
+ .name = "XRGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "ARGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x0080,
},
{
.name = "RGB24 (LE)",
.fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
- .depth = 24,
+ .vdownsampling = { 1 },
+ .bit_depth = { 24 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "RGB24 (BE)",
.fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
- .depth = 24,
+ .vdownsampling = { 1 },
+ .bit_depth = { 24 },
.planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "BGR666",
+ .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
},
{
.name = "RGB32 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "RGB32 (BE)",
- .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB32 (LE)",
- .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB32 (BE)",
- .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "ARGB32 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB32, /* argb */
- .depth = 32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
.alpha_mask = 0x000000ff,
},
{
.name = "ARGB32 (BE)",
.fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */
- .depth = 32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
.alpha_mask = 0xff000000,
},
{
- .name = "4:2:2, planar, YUV",
+ .name = "Bayer BG/GR",
+ .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer GB/RG",
+ .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer GR/BG",
+ .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer RG/GB",
+ .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "4:2:2, biplanar, YUV",
.fourcc = V4L2_PIX_FMT_NV16M,
- .depth = 8,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
.is_yuv = true,
.planes = 2,
+ .buffers = 2,
.data_offset = { PLANE0_DATA_OFFSET, 0 },
},
{
- .name = "4:2:2, planar, YVU",
+ .name = "4:2:2, biplanar, YVU",
.fourcc = V4L2_PIX_FMT_NV61M,
- .depth = 8,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
.is_yuv = true,
.planes = 2,
+ .buffers = 2,
.data_offset = { 0, PLANE0_DATA_OFFSET },
},
+ {
+ .name = "4:2:0, triplanar, YUV",
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .name = "4:2:0, triplanar, YVU",
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .name = "4:2:0, biplanar, YUV",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 2,
+ },
+ {
+ .name = "4:2:0, biplanar, YVU",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 2,
+ },
};
-/* There are 2 multiplanar formats in the list */
-#define VIVID_MPLANAR_FORMATS 2
+/* There are 6 multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 6
const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
{
@@ -194,7 +485,7 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) {
fmt = &vivid_formats[k];
if (fmt->fourcc == pixelformat)
- if (fmt->planes == 1 || dev->multiplanar)
+ if (fmt->buffers == 1 || dev->multiplanar)
return fmt;
}
@@ -210,6 +501,13 @@ bool vivid_vid_can_loop(struct vivid_dev *dev)
return false;
if (dev->field_cap != dev->field_out)
return false;
+ /*
+ * While this can be supported, it is just too much work
+ * to actually implement.
+ */
+ if (dev->field_cap == V4L2_FIELD_SEQ_TB ||
+ dev->field_cap == V4L2_FIELD_SEQ_BT)
+ return false;
if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
if (!(dev->std_cap & V4L2_STD_525_60) !=
!(dev->std_out & V4L2_STD_525_60))
@@ -397,6 +695,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
unsigned w = r->width;
unsigned h = r->height;
+ /* sanitize w and h in case someone passes ~0 as the value */
+ w &= 0xffff;
+ h &= 0xffff;
if (!(flags & V4L2_SEL_FLAG_LE)) {
w++;
h++;
@@ -421,8 +722,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
r->top = 0;
if (r->left < 0)
r->left = 0;
- r->left &= ~1;
- r->top &= ~1;
+ /* sanitize left and top in case someone passes ~0 as the value */
+ r->left &= 0xfffe;
+ r->top &= 0xfffe;
if (r->left + w > MAX_WIDTH)
r->left = MAX_WIDTH - w;
if (r->top + h > MAX_HEIGHT)
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 39ff79f..0af43dc 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -36,9 +36,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
unsigned sizes[], void *alloc_ctxs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
- unsigned planes = dev->fmt_out->planes;
+ const struct vivid_fmt *vfmt = dev->fmt_out;
+ unsigned planes = vfmt->buffers;
unsigned h = dev->fmt_out_rect.height;
unsigned size = dev->bytesperline_out[0] * h;
+ unsigned p;
+
+ for (p = vfmt->buffers; p < vfmt->planes; p++)
+ size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p];
if (dev->field_out == V4L2_FIELD_ALTERNATE) {
/*
@@ -74,21 +79,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
if (mp->num_planes != planes)
return -EINVAL;
sizes[0] = mp->plane_fmt[0].sizeimage;
- if (planes == 2) {
- sizes[1] = mp->plane_fmt[1].sizeimage;
- if (sizes[0] < dev->bytesperline_out[0] * h ||
- sizes[1] < dev->bytesperline_out[1] * h)
- return -EINVAL;
- } else if (sizes[0] < size) {
+ if (sizes[0] < size)
return -EINVAL;
+ for (p = 1; p < planes; p++) {
+ sizes[p] = mp->plane_fmt[p].sizeimage;
+ if (sizes[p] < dev->bytesperline_out[p] * h)
+ return -EINVAL;
}
} else {
- if (planes == 2) {
- sizes[0] = dev->bytesperline_out[0] * h;
- sizes[1] = dev->bytesperline_out[1] * h;
- } else {
- sizes[0] = size;
- }
+ for (p = 0; p < planes; p++)
+ sizes[p] = p ? dev->bytesperline_out[p] * h : size;
}
if (vq->num_buffers + *nbuffers < 2)
@@ -101,12 +101,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
* alloc_ctxs array.
*/
- if (planes == 2)
- dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
- *nbuffers, sizes[0], sizes[1]);
- else
- dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
- *nbuffers, sizes[0]);
+ dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
+ for (p = 0; p < planes; p++)
+ dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]);
return 0;
}
@@ -114,7 +111,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
unsigned long size;
- unsigned planes = dev->fmt_out->planes;
+ unsigned planes;
unsigned p;
dprintk(dev, 1, "%s\n", __func__);
@@ -122,6 +119,8 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb)
if (WARN_ON(NULL == dev->fmt_out))
return -EINVAL;
+ planes = dev->fmt_out->planes;
+
if (dev->buf_prepare_error) {
/*
* Error injection: test what happens if buf_prepare() returns
@@ -220,7 +219,7 @@ const struct vb2_ops vivid_vid_out_qops = {
void vivid_update_format_out(struct vivid_dev *dev)
{
struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
- unsigned size;
+ unsigned size, p;
switch (dev->output_type[dev->output]) {
case SVID:
@@ -249,7 +248,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
dev->field_out = V4L2_FIELD_ALTERNATE;
else
dev->field_out = V4L2_FIELD_NONE;
- if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
if (bt->width == 720 && bt->height <= 576)
dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
else
@@ -267,9 +266,9 @@ void vivid_update_format_out(struct vivid_dev *dev)
if (V4L2_FIELD_HAS_T_OR_B(dev->field_out))
dev->crop_out.height /= 2;
dev->fmt_out_rect = dev->crop_out;
- dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
- if (dev->fmt_out->planes == 2)
- dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+ for (p = 0; p < dev->fmt_out->planes; p++)
+ dev->bytesperline_out[p] =
+ (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8;
}
/* Map the field to something that is valid for the current output */
@@ -313,21 +312,28 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
{
struct vivid_dev *dev = video_drvdata(file);
struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+ const struct vivid_fmt *fmt = dev->fmt_out;
unsigned p;
mp->width = dev->fmt_out_rect.width;
mp->height = dev->fmt_out_rect.height;
mp->field = dev->field_out;
- mp->pixelformat = dev->fmt_out->fourcc;
+ mp->pixelformat = fmt->fourcc;
mp->colorspace = dev->colorspace_out;
mp->ycbcr_enc = dev->ycbcr_enc_out;
mp->quantization = dev->quantization_out;
- mp->num_planes = dev->fmt_out->planes;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
mp->plane_fmt[p].sizeimage =
mp->plane_fmt[p].bytesperline * mp->height;
}
+ for (p = fmt->buffers; p < fmt->planes; p++) {
+ unsigned stride = dev->bytesperline_out[p];
+
+ mp->plane_fmt[0].sizeimage +=
+ (stride * mp->height) / fmt->vdownsampling[p];
+ }
return 0;
}
@@ -386,10 +392,10 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
/* This driver supports custom bytesperline values */
/* Calculate the minimum supported bytesperline value */
- bytesperline = (mp->width * fmt->depth) >> 3;
+ bytesperline = (mp->width * fmt->bit_depth[0]) >> 3;
/* Calculate the maximum supported bytesperline value */
- max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
- mp->num_planes = fmt->planes;
+ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
if (pfmt[p].bytesperline > max_bpl)
pfmt[p].bytesperline = max_bpl;
@@ -398,11 +404,14 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
+ for (p = fmt->buffers; p < fmt->planes; p++)
+ pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) /
+ (fmt->bit_depth[0] * fmt->vdownsampling[p]);
mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
mp->quantization = V4L2_QUANTIZATION_DEFAULT;
if (vivid_is_svid_out(dev)) {
mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
- } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
mp->colorspace = V4L2_COLORSPACE_SRGB;
if (dev->dvi_d_out)
mp->quantization = V4L2_QUANTIZATION_LIM_RANGE;
@@ -429,6 +438,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
struct vb2_queue *q = &dev->vb_vid_out_q;
int ret = vivid_try_fmt_vid_out(file, priv, f);
unsigned factor = 1;
+ unsigned p;
if (ret < 0)
return ret;
@@ -524,9 +534,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
dev->fmt_out_rect.width = mp->width;
dev->fmt_out_rect.height = mp->height;
- dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline;
- if (mp->num_planes > 1)
- dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline;
+ for (p = 0; p < mp->num_planes; p++)
+ dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline;
+ for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++)
+ dev->bytesperline_out[p] =
+ (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) /
+ dev->fmt_out->bit_depth[0];
dev->field_out = mp->field;
if (vivid_is_svid_out(dev))
dev->tv_field_out = mp->field;
@@ -1114,13 +1127,13 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
if (!vivid_is_hdmi_out(dev))
return -ENODATA;
- if (vb2_is_busy(&dev->vb_vid_out_q))
- return -EBUSY;
if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
0, NULL, NULL))
return -EINVAL;
if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
return 0;
+ if (vb2_is_busy(&dev->vb_vid_out_q))
+ return -EBUSY;
dev->dv_timings_out = *timings;
vivid_update_format_out(dev);
return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 401e2b7..7dd7633 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -183,13 +183,14 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
MEDIA_BUS_FMT_ARGB8888_1X32,
MEDIA_BUS_FMT_AYUV8_1X32,
};
+ struct vsp1_bru *bru = to_bru(subdev);
struct v4l2_mbus_framefmt *format;
if (code->pad == BRU_PAD_SINK(0)) {
@@ -201,7 +202,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0));
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg,
+ BRU_PAD_SINK(0), code->which);
code->code = format->code;
}
@@ -209,7 +211,7 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int bru_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index)
@@ -228,12 +230,12 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev,
}
static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, pad);
+ return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &bru->inputs[pad].compose;
default:
@@ -241,18 +243,18 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
}
}
-static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_bru *bru = to_bru(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
+static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -268,7 +270,7 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
default:
/* The BRU can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&bru->entity, fh,
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg,
BRU_PAD_SINK(0), which);
fmt->code = format->code;
break;
@@ -280,15 +282,15 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
fmt->colorspace = V4L2_COLORSPACE_SRGB;
}
-static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_bru *bru = to_bru(subdev);
struct v4l2_mbus_framefmt *format;
- bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which);
+ bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which);
- format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
fmt->which);
*format = fmt->format;
@@ -296,7 +298,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
if (fmt->pad != BRU_PAD_SOURCE) {
struct v4l2_rect *compose;
- compose = bru_get_compose(bru, fh, fmt->pad, fmt->which);
+ compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which);
compose->left = 0;
compose->top = 0;
compose->width = format->width;
@@ -308,7 +310,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
unsigned int i;
for (i = 0; i <= BRU_PAD_SOURCE; ++i) {
- format = vsp1_entity_get_pad_format(&bru->entity, fh,
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg,
i, fmt->which);
format->code = fmt->format.code;
}
@@ -318,7 +320,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
}
static int bru_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct vsp1_bru *bru = to_bru(subdev);
@@ -335,7 +337,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
return 0;
case V4L2_SEL_TGT_COMPOSE:
- sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which);
+ sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which);
return 0;
default:
@@ -344,7 +346,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
}
static int bru_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct vsp1_bru *bru = to_bru(subdev);
@@ -360,7 +362,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
/* The compose rectangle top left corner must be inside the output
* frame.
*/
- format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SOURCE,
sel->which);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -368,12 +370,12 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
/* Scaling isn't supported, the compose rectangle size must be identical
* to the sink format size.
*/
- format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad,
+ format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad,
sel->which);
sel->r.width = format->width;
sel->r.height = format->height;
- compose = bru_get_compose(bru, fh, sel->pad, sel->which);
+ compose = bru_get_compose(bru, cfg, sel->pad, sel->which);
*compose = sel->r;
return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 79af71d5..a453bb4 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -63,12 +63,12 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &entity->formats[pad];
default:
@@ -79,14 +79,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
/*
* vsp1_entity_init_formats - Initialize formats on all pads
* @subdev: V4L2 subdevice
- * @fh: V4L2 subdev file handle
+ * @cfg: V4L2 subdev pad configuration
*
- * Initialize all pad formats with default values. If fh is not NULL, try
+ * Initialize all pad formats with default values. If cfg is not NULL, try
* formats are initialized on the file handle. Otherwise active formats are
* initialized on the device.
*/
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh)
+ struct v4l2_subdev_pad_config *cfg)
{
struct v4l2_subdev_format format;
unsigned int pad;
@@ -95,17 +95,17 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
memset(&format, 0, sizeof(format));
format.pad = pad;
- format.which = fh ? V4L2_SUBDEV_FORMAT_TRY
+ format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
: V4L2_SUBDEV_FORMAT_ACTIVE;
- v4l2_subdev_call(subdev, pad, set_fmt, fh, &format);
+ v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
}
}
static int vsp1_entity_open(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh)
{
- vsp1_entity_init_formats(subdev, fh);
+ vsp1_entity_init_formats(subdev, fh->pad);
return 0;
}
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index aa20aaa..62c768d 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -91,10 +91,10 @@ extern const struct media_entity_operations vsp1_media_ops;
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
unsigned int pad, u32 which);
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh);
+ struct v4l2_subdev_pad_config *cfg);
bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 0bc0471..8ffb817 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -55,7 +55,7 @@ static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
@@ -73,12 +73,14 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct vsp1_hsit *hsit = to_hsit(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, fse->pad);
+ format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad,
+ fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -102,25 +104,25 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
}
static int hsit_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
static int hsit_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
struct v4l2_mbus_framefmt *format;
- format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
fmt->which);
if (fmt->pad == HSIT_PAD_SOURCE) {
@@ -143,7 +145,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE,
fmt->which);
*format = fmt->format;
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 17a6ca7..39fa5ef 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -74,13 +74,14 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
MEDIA_BUS_FMT_ARGB8888_1X32,
MEDIA_BUS_FMT_AYUV8_1X32,
};
+ struct vsp1_lif *lif = to_lif(subdev);
if (code->pad == LIF_PAD_SINK) {
if (code->index >= ARRAY_SIZE(codes))
@@ -96,7 +97,8 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&lif->entity, cfg,
+ LIF_PAD_SINK, code->which);
code->code = format->code;
}
@@ -104,12 +106,14 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int lif_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct vsp1_lif *lif = to_lif(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK,
+ fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -129,18 +133,18 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_lif *lif = to_lif(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_lif *lif = to_lif(subdev);
@@ -151,7 +155,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
fmt->which);
if (fmt->pad == LIF_PAD_SOURCE) {
@@ -173,7 +177,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&lif->entity, fh, LIF_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE,
fmt->which);
*format = fmt->format;
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 6f185c3..656ec27 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -82,7 +82,7 @@ static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -90,6 +90,7 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
MEDIA_BUS_FMT_AHSV8888_1X32,
MEDIA_BUS_FMT_AYUV8_1X32,
};
+ struct vsp1_lut *lut = to_lut(subdev);
struct v4l2_mbus_framefmt *format;
if (code->pad == LUT_PAD_SINK) {
@@ -104,7 +105,8 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&lut->entity, cfg,
+ LUT_PAD_SINK, code->which);
code->code = format->code;
}
@@ -112,12 +114,14 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int lut_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct vsp1_lut *lut = to_lut(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, fse->pad);
+ format = vsp1_entity_get_pad_format(&lut->entity, cfg,
+ fse->pad, fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -140,18 +144,18 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_lut *lut = to_lut(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_lut *lut = to_lut(subdev);
@@ -163,7 +167,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
fmt->which);
if (fmt->pad == LUT_PAD_SOURCE) {
@@ -182,7 +186,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE,
fmt->which);
*format = fmt->format;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 1f1ba26..fa71f46 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -25,7 +25,7 @@
*/
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -42,13 +42,14 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
}
int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, fse->pad);
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad,
+ fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -72,11 +73,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
}
static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
+vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK);
+ return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &rwpf->crop;
default:
@@ -84,18 +85,18 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
}
}
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
@@ -107,7 +108,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
fmt->which);
if (fmt->pad == RWPF_PAD_SOURCE) {
@@ -130,14 +131,14 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
fmt->format = *format;
/* Update the sink crop rectangle. */
- crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which);
+ crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
crop->height = fmt->format.height;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
fmt->which);
*format = fmt->format;
@@ -145,7 +146,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
}
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
@@ -157,11 +158,11 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which);
+ sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- format = vsp1_entity_get_pad_format(&rwpf->entity, fh,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
RWPF_PAD_SINK, sel->which);
sel->r.left = 0;
sel->r.top = 0;
@@ -177,7 +178,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
}
int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
@@ -194,7 +195,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
/* Make sure the crop rectangle is entirely contained in the image. The
* WPF top and left offsets are limited to 255.
*/
- format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK,
sel->which);
sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
@@ -207,11 +208,11 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
sel->r.height = min_t(unsigned int, sel->r.height,
format->height - sel->r.top);
- crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which);
+ crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
*crop = sel->r;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
sel->which);
format->width = crop->width;
format->height = crop->height;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 2cf1f13..f452dce 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -51,20 +51,20 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code);
int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt);
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel);
int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel);
#endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 1129494..6310aca 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -166,13 +166,14 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
MEDIA_BUS_FMT_ARGB8888_1X32,
MEDIA_BUS_FMT_AYUV8_1X32,
};
+ struct vsp1_sru *sru = to_sru(subdev);
struct v4l2_mbus_framefmt *format;
if (code->pad == SRU_PAD_SINK) {
@@ -187,7 +188,8 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&sru->entity, cfg,
+ SRU_PAD_SINK, code->which);
code->code = format->code;
}
@@ -195,12 +197,14 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int sru_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct vsp1_sru *sru = to_sru(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&sru->entity, cfg,
+ SRU_PAD_SINK, fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -226,18 +230,18 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_sru *sru = to_sru(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
+static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -258,7 +262,7 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
case SRU_PAD_SOURCE:
/* The SRU can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&sru->entity, fh,
+ format = vsp1_entity_get_pad_format(&sru->entity, cfg,
SRU_PAD_SINK, which);
fmt->code = format->code;
@@ -288,25 +292,25 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
fmt->colorspace = V4L2_COLORSPACE_SRGB;
}
-static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_sru *sru = to_sru(subdev);
struct v4l2_mbus_framefmt *format;
- sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which);
+ sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which);
- format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
fmt->which);
*format = fmt->format;
if (fmt->pad == SRU_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&sru->entity, fh,
+ format = vsp1_entity_get_pad_format(&sru->entity, cfg,
SRU_PAD_SOURCE, fmt->which);
*format = fmt->format;
- sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which);
+ sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which);
}
return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index a4afec1..ccc8243 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -169,13 +169,14 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
MEDIA_BUS_FMT_ARGB8888_1X32,
MEDIA_BUS_FMT_AYUV8_1X32,
};
+ struct vsp1_uds *uds = to_uds(subdev);
if (code->pad == UDS_PAD_SINK) {
if (code->index >= ARRAY_SIZE(codes))
@@ -191,7 +192,8 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&uds->entity, cfg,
+ UDS_PAD_SINK, code->which);
code->code = format->code;
}
@@ -199,12 +201,14 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int uds_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct vsp1_uds *uds = to_uds(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&uds->entity, cfg,
+ UDS_PAD_SINK, fse->which);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -224,18 +228,18 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_uds *uds = to_uds(subdev);
- fmt->format = *vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad,
+ fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
fmt->which);
return 0;
}
-static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh,
+static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -256,7 +260,7 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh,
case UDS_PAD_SOURCE:
/* The UDS scales but can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&uds->entity, fh,
+ format = vsp1_entity_get_pad_format(&uds->entity, cfg,
UDS_PAD_SINK, which);
fmt->code = format->code;
@@ -271,25 +275,25 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh,
fmt->colorspace = V4L2_COLORSPACE_SRGB;
}
-static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct vsp1_uds *uds = to_uds(subdev);
struct v4l2_mbus_framefmt *format;
- uds_try_format(uds, fh, fmt->pad, &fmt->format, fmt->which);
+ uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which);
- format = vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad,
+ format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
fmt->which);
*format = fmt->format;
if (fmt->pad == UDS_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&uds->entity, fh,
+ format = vsp1_entity_get_pad_format(&uds->entity, cfg,
UDS_PAD_SOURCE, fmt->which);
*format = fmt->format;
- uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which);
+ uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which);
}
return 0;
diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig
new file mode 100644
index 0000000..d7324c7
--- /dev/null
+++ b/drivers/media/platform/xilinx/Kconfig
@@ -0,0 +1,23 @@
+config VIDEO_XILINX
+ tristate "Xilinx Video IP (EXPERIMENTAL)"
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ Driver for Xilinx Video IP Pipelines
+
+if VIDEO_XILINX
+
+config VIDEO_XILINX_TPG
+ tristate "Xilinx Video Test Pattern Generator"
+ depends on VIDEO_XILINX
+ select VIDEO_XILINX_VTC
+ ---help---
+ Driver for the Xilinx Video Test Pattern Generator
+
+config VIDEO_XILINX_VTC
+ tristate "Xilinx Video Timing Controller"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video Timing Controller
+
+endif #VIDEO_XILINX
diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile
new file mode 100644
index 0000000..e8a0f2a
--- /dev/null
+++ b/drivers/media/platform/xilinx/Makefile
@@ -0,0 +1,5 @@
+xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o
+
+obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o
+obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o
+obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
new file mode 100644
index 0000000..10209c2
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -0,0 +1,766 @@
+/*
+ * Xilinx Video DMA
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/amba/xilinx_dma.h>
+#include <linux/lcm.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "xilinx-dma.h"
+#include "xilinx-vip.h"
+#include "xilinx-vipp.h"
+
+#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV
+#define XVIP_DMA_DEF_WIDTH 1920
+#define XVIP_DMA_DEF_HEIGHT 1080
+
+/* Minimum and maximum widths are expressed in bytes */
+#define XVIP_DMA_MIN_WIDTH 1U
+#define XVIP_DMA_MAX_WIDTH 65535U
+#define XVIP_DMA_MIN_HEIGHT 1U
+#define XVIP_DMA_MAX_HEIGHT 8191U
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+static struct v4l2_subdev *
+xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
+{
+ struct media_pad *remote;
+
+ remote = media_entity_remote_pad(local);
+ if (remote == NULL ||
+ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return NULL;
+
+ if (pad)
+ *pad = remote->index;
+
+ return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+static int xvip_dma_verify_format(struct xvip_dma *dma)
+{
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad);
+ if (subdev == NULL)
+ return -EPIPE;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ if (dma->fmtinfo->code != fmt.format.code ||
+ dma->format.height != fmt.format.height ||
+ dma->format.width != fmt.format.width ||
+ dma->format.colorspace != fmt.format.colorspace)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline Stream Management
+ */
+
+/**
+ * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
+ * @pipe: The pipeline
+ * @start: Start (when true) or stop (when false) the pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * or stop all of them.
+ *
+ * Return: 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
+{
+ struct xvip_dma *dma = pipe->output;
+ struct media_entity *entity;
+ struct media_pad *pad;
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ entity = &dma->video.entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_pad(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, start);
+ if (start && ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: The pipeline
+ * @on: Turn the stream on when true or off when false
+ *
+ * The pipeline is shared between all DMA engines connect at its input and
+ * output. While the stream state of DMA engines can be controlled
+ * independently, pipelines have a shared stream state that enable or disable
+ * all entities in the pipeline. For this reason the pipeline uses a streaming
+ * counter that tracks the number of DMA engines that have requested the stream
+ * to be enabled.
+ *
+ * When called with the @on argument set to true, this function will increment
+ * the pipeline streaming count. If the streaming count reaches the number of
+ * DMA engines in the pipeline it will enable all entities that belong to the
+ * pipeline.
+ *
+ * Similarly, when called with the @on argument set to false, this function will
+ * decrement the pipeline streaming count and disable all entities in the
+ * pipeline when the streaming count reaches zero.
+ *
+ * Return: 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. Stopping the pipeline never fails. The pipeline state is
+ * not updated when the operation fails.
+ */
+static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
+{
+ int ret = 0;
+
+ mutex_lock(&pipe->lock);
+
+ if (on) {
+ if (pipe->stream_count == pipe->num_dmas - 1) {
+ ret = xvip_pipeline_start_stop(pipe, true);
+ if (ret < 0)
+ goto done;
+ }
+ pipe->stream_count++;
+ } else {
+ if (--pipe->stream_count == 0)
+ xvip_pipeline_start_stop(pipe, false);
+ }
+
+done:
+ mutex_unlock(&pipe->lock);
+ return ret;
+}
+
+static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
+ struct xvip_dma *start)
+{
+ struct media_entity_graph graph;
+ struct media_entity *entity = &start->video.entity;
+ struct media_device *mdev = entity->parent;
+ unsigned int num_inputs = 0;
+ unsigned int num_outputs = 0;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /* Walk the graph to locate the video nodes. */
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ struct xvip_dma *dma;
+
+ if (entity->type != MEDIA_ENT_T_DEVNODE_V4L)
+ continue;
+
+ dma = to_xvip_dma(media_entity_to_video_device(entity));
+
+ if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
+ pipe->output = dma;
+ num_outputs++;
+ } else {
+ num_inputs++;
+ }
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ /* We need exactly one output and zero or one input. */
+ if (num_outputs != 1 || num_inputs > 1)
+ return -EPIPE;
+
+ pipe->num_dmas = num_inputs + num_outputs;
+
+ return 0;
+}
+
+static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
+{
+ pipe->num_dmas = 0;
+ pipe->output = NULL;
+}
+
+/**
+ * xvip_pipeline_cleanup - Cleanup the pipeline after streaming
+ * @pipe: the pipeline
+ *
+ * Decrease the pipeline use count and clean it up if we were the last user.
+ */
+static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
+{
+ mutex_lock(&pipe->lock);
+
+ /* If we're the last user clean up the pipeline. */
+ if (--pipe->use_count == 0)
+ __xvip_pipeline_cleanup(pipe);
+
+ mutex_unlock(&pipe->lock);
+}
+
+/**
+ * xvip_pipeline_prepare - Prepare the pipeline for streaming
+ * @pipe: the pipeline
+ * @dma: DMA engine at one end of the pipeline
+ *
+ * Validate the pipeline if no user exists yet, otherwise just increase the use
+ * count.
+ *
+ * Return: 0 if successful or -EPIPE if the pipeline is not valid.
+ */
+static int xvip_pipeline_prepare(struct xvip_pipeline *pipe,
+ struct xvip_dma *dma)
+{
+ int ret;
+
+ mutex_lock(&pipe->lock);
+
+ /* If we're the first user validate and initialize the pipeline. */
+ if (pipe->use_count == 0) {
+ ret = xvip_pipeline_validate(pipe, dma);
+ if (ret < 0) {
+ __xvip_pipeline_cleanup(pipe);
+ goto done;
+ }
+ }
+
+ pipe->use_count++;
+ ret = 0;
+
+done:
+ mutex_unlock(&pipe->lock);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
+ */
+
+/**
+ * struct xvip_dma_buffer - Video DMA buffer
+ * @buf: vb2 buffer base object
+ * @queue: buffer list entry in the DMA engine queued buffers list
+ * @dma: DMA channel that uses the buffer
+ */
+struct xvip_dma_buffer {
+ struct vb2_buffer buf;
+ struct list_head queue;
+ struct xvip_dma *dma;
+};
+
+#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf)
+
+static void xvip_dma_complete(void *param)
+{
+ struct xvip_dma_buffer *buf = param;
+ struct xvip_dma *dma = buf->dma;
+
+ spin_lock(&dma->queued_lock);
+ list_del(&buf->queue);
+ spin_unlock(&dma->queued_lock);
+
+ buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;
+ buf->buf.v4l2_buf.sequence = dma->sequence++;
+ v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp);
+ vb2_set_plane_payload(&buf->buf, 0, dma->format.sizeimage);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
+}
+
+static int
+xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct xvip_dma *dma = vb2_get_drv_priv(vq);
+
+ /* Make sure the image size is large enough. */
+ if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage)
+ return -EINVAL;
+
+ *nplanes = 1;
+
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage;
+ alloc_ctxs[0] = dma->alloc_ctx;
+
+ return 0;
+}
+
+static int xvip_dma_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue);
+ struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb);
+
+ buf->dma = dma;
+
+ return 0;
+}
+
+static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
+{
+ struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue);
+ struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb);
+ struct dma_async_tx_descriptor *desc;
+ dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ u32 flags;
+
+ if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ dma->xt.dir = DMA_DEV_TO_MEM;
+ dma->xt.src_sgl = false;
+ dma->xt.dst_sgl = true;
+ dma->xt.dst_start = addr;
+ } else {
+ flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ dma->xt.dir = DMA_MEM_TO_DEV;
+ dma->xt.src_sgl = true;
+ dma->xt.dst_sgl = false;
+ dma->xt.src_start = addr;
+ }
+
+ dma->xt.frame_size = 1;
+ dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp;
+ dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size;
+ dma->xt.numf = dma->format.height;
+
+ desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags);
+ if (!desc) {
+ dev_err(dma->xdev->dev, "Failed to prepare DMA transfer\n");
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
+ return;
+ }
+ desc->callback = xvip_dma_complete;
+ desc->callback_param = buf;
+
+ spin_lock_irq(&dma->queued_lock);
+ list_add_tail(&buf->queue, &dma->queued_bufs);
+ spin_unlock_irq(&dma->queued_lock);
+
+ dmaengine_submit(desc);
+
+ if (vb2_is_streaming(&dma->queue))
+ dma_async_issue_pending(dma->dma);
+}
+
+static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct xvip_dma *dma = vb2_get_drv_priv(vq);
+ struct xvip_dma_buffer *buf, *nbuf;
+ struct xvip_pipeline *pipe;
+ int ret;
+
+ dma->sequence = 0;
+
+ /*
+ * Start streaming on the pipeline. No link touching an entity in the
+ * pipeline can be activated or deactivated once streaming is started.
+ *
+ * Use the pipeline object embedded in the first DMA object that starts
+ * streaming.
+ */
+ pipe = dma->video.entity.pipe
+ ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
+
+ ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe);
+ if (ret < 0)
+ goto error;
+
+ /* Verify that the configured format matches the output of the
+ * connected subdev.
+ */
+ ret = xvip_dma_verify_format(dma);
+ if (ret < 0)
+ goto error_stop;
+
+ ret = xvip_pipeline_prepare(pipe, dma);
+ if (ret < 0)
+ goto error_stop;
+
+ /* Start the DMA engine. This must be done before starting the blocks
+ * in the pipeline to avoid DMA synchronization issues.
+ */
+ dma_async_issue_pending(dma->dma);
+
+ /* Start the pipeline. */
+ xvip_pipeline_set_stream(pipe, true);
+
+ return 0;
+
+error_stop:
+ media_entity_pipeline_stop(&dma->video.entity);
+
+error:
+ /* Give back all queued buffers to videobuf2. */
+ spin_lock_irq(&dma->queued_lock);
+ list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_QUEUED);
+ list_del(&buf->queue);
+ }
+ spin_unlock_irq(&dma->queued_lock);
+
+ return ret;
+}
+
+static void xvip_dma_stop_streaming(struct vb2_queue *vq)
+{
+ struct xvip_dma *dma = vb2_get_drv_priv(vq);
+ struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity);
+ struct xvip_dma_buffer *buf, *nbuf;
+
+ /* Stop the pipeline. */
+ xvip_pipeline_set_stream(pipe, false);
+
+ /* Stop and reset the DMA engine. */
+ dmaengine_terminate_all(dma->dma);
+
+ /* Cleanup the pipeline and mark it as being stopped. */
+ xvip_pipeline_cleanup(pipe);
+ media_entity_pipeline_stop(&dma->video.entity);
+
+ /* Give back all queued buffers to videobuf2. */
+ spin_lock_irq(&dma->queued_lock);
+ list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
+ list_del(&buf->queue);
+ }
+ spin_unlock_irq(&dma->queued_lock);
+}
+
+static struct vb2_ops xvip_dma_queue_qops = {
+ .queue_setup = xvip_dma_queue_setup,
+ .buf_prepare = xvip_dma_buffer_prepare,
+ .buf_queue = xvip_dma_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = xvip_dma_start_streaming,
+ .stop_streaming = xvip_dma_stop_streaming,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+
+ cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
+ | dma->xdev->v4l2_caps;
+
+ if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ else
+ cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+ strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
+ strlcpy(cap->card, dma->video.name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u",
+ dma->xdev->dev->of_node->name, dma->port);
+
+ return 0;
+}
+
+/* FIXME: without this callback function, some applications are not configured
+ * with correct formats, and it results in frames in wrong format. Whether this
+ * callback needs to be required is not clearly defined, so it should be
+ * clarified through the mailing list.
+ */
+static int
+xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+
+ if (f->index > 0)
+ return -EINVAL;
+
+ f->pixelformat = dma->format.pixelformat;
+ strlcpy(f->description, dma->fmtinfo->description,
+ sizeof(f->description));
+
+ return 0;
+}
+
+static int
+xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+
+ format->fmt.pix = dma->format;
+
+ return 0;
+}
+
+static void
+__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
+ const struct xvip_video_format **fmtinfo)
+{
+ const struct xvip_video_format *info;
+ unsigned int min_width;
+ unsigned int max_width;
+ unsigned int min_bpl;
+ unsigned int max_bpl;
+ unsigned int width;
+ unsigned int align;
+ unsigned int bpl;
+
+ /* Retrieve format information and select the default format if the
+ * requested format isn't supported.
+ */
+ info = xvip_get_format_by_fourcc(pix->pixelformat);
+ if (IS_ERR(info))
+ info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
+
+ pix->pixelformat = info->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+
+ /* The transfer alignment requirements are expressed in bytes. Compute
+ * the minimum and maximum values, clamp the requested width and convert
+ * it back to pixels.
+ */
+ align = lcm(dma->align, info->bpp);
+ min_width = roundup(XVIP_DMA_MIN_WIDTH, align);
+ max_width = rounddown(XVIP_DMA_MAX_WIDTH, align);
+ width = rounddown(pix->width * info->bpp, align);
+
+ pix->width = clamp(width, min_width, max_width) / info->bpp;
+ pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT,
+ XVIP_DMA_MAX_HEIGHT);
+
+ /* Clamp the requested bytes per line value. If the maximum bytes per
+ * line value is zero, the module doesn't support user configurable line
+ * sizes. Override the requested value with the minimum in that case.
+ */
+ min_bpl = pix->width * info->bpp;
+ max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
+ bpl = rounddown(pix->bytesperline, dma->align);
+
+ pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
+ pix->sizeimage = pix->bytesperline * pix->height;
+
+ if (fmtinfo)
+ *fmtinfo = info;
+}
+
+static int
+xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+
+ __xvip_dma_try_format(dma, &format->fmt.pix, NULL);
+ return 0;
+}
+
+static int
+xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+ const struct xvip_video_format *info;
+
+ __xvip_dma_try_format(dma, &format->fmt.pix, &info);
+
+ if (vb2_is_busy(&dma->queue))
+ return -EBUSY;
+
+ dma->format = format->fmt.pix;
+ dma->fmtinfo = info;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = {
+ .vidioc_querycap = xvip_dma_querycap,
+ .vidioc_enum_fmt_vid_cap = xvip_dma_enum_format,
+ .vidioc_g_fmt_vid_cap = xvip_dma_get_format,
+ .vidioc_g_fmt_vid_out = xvip_dma_get_format,
+ .vidioc_s_fmt_vid_cap = xvip_dma_set_format,
+ .vidioc_s_fmt_vid_out = xvip_dma_set_format,
+ .vidioc_try_fmt_vid_cap = xvip_dma_try_format,
+ .vidioc_try_fmt_vid_out = xvip_dma_try_format,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static const struct v4l2_file_operations xvip_dma_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * Xilinx Video DMA Core
+ */
+
+int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
+ enum v4l2_buf_type type, unsigned int port)
+{
+ char name[14];
+ int ret;
+
+ dma->xdev = xdev;
+ dma->port = port;
+ mutex_init(&dma->lock);
+ mutex_init(&dma->pipe.lock);
+ INIT_LIST_HEAD(&dma->queued_bufs);
+ spin_lock_init(&dma->queued_lock);
+
+ dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
+ dma->format.pixelformat = dma->fmtinfo->fourcc;
+ dma->format.colorspace = V4L2_COLORSPACE_SRGB;
+ dma->format.field = V4L2_FIELD_NONE;
+ dma->format.width = XVIP_DMA_DEF_WIDTH;
+ dma->format.height = XVIP_DMA_DEF_HEIGHT;
+ dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp;
+ dma->format.sizeimage = dma->format.bytesperline * dma->format.height;
+
+ /* Initialize the media entity... */
+ dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0);
+ if (ret < 0)
+ goto error;
+
+ /* ... and the video node... */
+ dma->video.fops = &xvip_dma_fops;
+ dma->video.v4l2_dev = &xdev->v4l2_dev;
+ dma->video.queue = &dma->queue;
+ snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u",
+ xdev->dev->of_node->name,
+ type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
+ port);
+ dma->video.vfl_type = VFL_TYPE_GRABBER;
+ dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ ? VFL_DIR_RX : VFL_DIR_TX;
+ dma->video.release = video_device_release_empty;
+ dma->video.ioctl_ops = &xvip_dma_ioctl_ops;
+ dma->video.lock = &dma->lock;
+
+ video_set_drvdata(&dma->video, dma);
+
+ /* ... and the buffers queue... */
+ dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev);
+ if (IS_ERR(dma->alloc_ctx))
+ goto error;
+
+ /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write()
+ * V4L2 APIs would be inefficient. Testing on the command line with a
+ * 'cat /dev/video?' thus won't be possible, but given that the driver
+ * anyway requires a test tool to setup the pipeline before any video
+ * stream can be started, requiring a specific V4L2 test tool as well
+ * instead of 'cat' isn't really a drawback.
+ */
+ dma->queue.type = type;
+ dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dma->queue.lock = &dma->lock;
+ dma->queue.drv_priv = dma;
+ dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer);
+ dma->queue.ops = &xvip_dma_queue_qops;
+ dma->queue.mem_ops = &vb2_dma_contig_memops;
+ dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
+ | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
+ ret = vb2_queue_init(&dma->queue);
+ if (ret < 0) {
+ dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n");
+ goto error;
+ }
+
+ /* ... and the DMA channel. */
+ sprintf(name, "port%u", port);
+ dma->dma = dma_request_slave_channel(dma->xdev->dev, name);
+ if (dma->dma == NULL) {
+ dev_err(dma->xdev->dev, "no VDMA channel found\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ dma->align = 1 << dma->dma->device->copy_align;
+
+ ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ dev_err(dma->xdev->dev, "failed to register video device\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ xvip_dma_cleanup(dma);
+ return ret;
+}
+
+void xvip_dma_cleanup(struct xvip_dma *dma)
+{
+ if (video_is_registered(&dma->video))
+ video_unregister_device(&dma->video);
+
+ if (dma->dma)
+ dma_release_channel(dma->dma);
+
+ if (!IS_ERR_OR_NULL(dma->alloc_ctx))
+ vb2_dma_contig_cleanup_ctx(dma->alloc_ctx);
+
+ media_entity_cleanup(&dma->video.entity);
+
+ mutex_destroy(&dma->lock);
+ mutex_destroy(&dma->pipe.lock);
+}
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
new file mode 100644
index 0000000..a540111
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -0,0 +1,109 @@
+/*
+ * Xilinx Video DMA
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_VIP_DMA_H__
+#define __XILINX_VIP_DMA_H__
+
+#include <linux/dmaengine.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+
+struct dma_chan;
+struct xvip_composite_device;
+struct xvip_video_format;
+
+/**
+ * struct xvip_pipeline - Xilinx Video IP pipeline structure
+ * @pipe: media pipeline
+ * @lock: protects the pipeline @stream_count
+ * @use_count: number of DMA engines using the pipeline
+ * @stream_count: number of DMA engines currently streaming
+ * @num_dmas: number of DMA engines in the pipeline
+ * @output: DMA engine at the output of the pipeline
+ */
+struct xvip_pipeline {
+ struct media_pipeline pipe;
+
+ struct mutex lock;
+ unsigned int use_count;
+ unsigned int stream_count;
+
+ unsigned int num_dmas;
+ struct xvip_dma *output;
+};
+
+static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
+{
+ return container_of(e->pipe, struct xvip_pipeline, pipe);
+}
+
+/**
+ * struct xvip_dma - Video DMA channel
+ * @list: list entry in a composite device dmas list
+ * @video: V4L2 video device associated with the DMA channel
+ * @pad: media pad for the video device entity
+ * @xdev: composite device the DMA channel belongs to
+ * @pipe: pipeline belonging to the DMA channel
+ * @port: composite device DT node port number for the DMA channel
+ * @lock: protects the @format, @fmtinfo and @queue fields
+ * @format: active V4L2 pixel format
+ * @fmtinfo: format information corresponding to the active @format
+ * @queue: vb2 buffers queue
+ * @alloc_ctx: allocation context for the vb2 @queue
+ * @sequence: V4L2 buffers sequence number
+ * @queued_bufs: list of queued buffers
+ * @queued_lock: protects the buf_queued list
+ * @dma: DMA engine channel
+ * @align: transfer alignment required by the DMA channel (in bytes)
+ * @xt: dma interleaved template for dma configuration
+ * @sgl: data chunk structure for dma_interleaved_template
+ */
+struct xvip_dma {
+ struct list_head list;
+ struct video_device video;
+ struct media_pad pad;
+
+ struct xvip_composite_device *xdev;
+ struct xvip_pipeline pipe;
+ unsigned int port;
+
+ struct mutex lock;
+ struct v4l2_pix_format format;
+ const struct xvip_video_format *fmtinfo;
+
+ struct vb2_queue queue;
+ void *alloc_ctx;
+ unsigned int sequence;
+
+ struct list_head queued_bufs;
+ spinlock_t queued_lock;
+
+ struct dma_chan *dma;
+ unsigned int align;
+ struct dma_interleaved_template xt;
+ struct data_chunk sgl[1];
+};
+
+#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video)
+
+int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
+ enum v4l2_buf_type type, unsigned int port);
+void xvip_dma_cleanup(struct xvip_dma *dma);
+
+#endif /* __XILINX_VIP_DMA_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
new file mode 100644
index 0000000..b5f7d5e
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -0,0 +1,931 @@
+/*
+ * Xilinx Test Pattern Generator
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+#include "xilinx-vtc.h"
+
+#define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16)
+#define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16)
+
+#define XTPG_PATTERN_CONTROL 0x0100
+#define XTPG_PATTERN_MASK (0xf << 0)
+#define XTPG_PATTERN_CONTROL_CROSS_HAIRS (1 << 4)
+#define XTPG_PATTERN_CONTROL_MOVING_BOX (1 << 5)
+#define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT 6
+#define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK (0xf << 6)
+#define XTPG_PATTERN_CONTROL_STUCK_PIXEL (1 << 9)
+#define XTPG_PATTERN_CONTROL_NOISE (1 << 10)
+#define XTPG_PATTERN_CONTROL_MOTION (1 << 12)
+#define XTPG_MOTION_SPEED 0x0104
+#define XTPG_CROSS_HAIRS 0x0108
+#define XTPG_CROSS_HAIRS_ROW_SHIFT 0
+#define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0)
+#define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16
+#define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16)
+#define XTPG_ZPLATE_HOR_CONTROL 0x010c
+#define XTPG_ZPLATE_VER_CONTROL 0x0110
+#define XTPG_ZPLATE_START_SHIFT 0
+#define XTPG_ZPLATE_START_MASK (0xffff << 0)
+#define XTPG_ZPLATE_SPEED_SHIFT 16
+#define XTPG_ZPLATE_SPEED_MASK (0xffff << 16)
+#define XTPG_BOX_SIZE 0x0114
+#define XTPG_BOX_COLOR 0x0118
+#define XTPG_STUCK_PIXEL_THRESH 0x011c
+#define XTPG_NOISE_GAIN 0x0120
+#define XTPG_BAYER_PHASE 0x0124
+#define XTPG_BAYER_PHASE_RGGB 0
+#define XTPG_BAYER_PHASE_GRBG 1
+#define XTPG_BAYER_PHASE_GBRG 2
+#define XTPG_BAYER_PHASE_BGGR 3
+#define XTPG_BAYER_PHASE_OFF 4
+
+/*
+ * The minimum blanking value is one clock cycle for the front porch, one clock
+ * cycle for the sync pulse and one clock cycle for the back porch.
+ */
+#define XTPG_MIN_HBLANK 3
+#define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH)
+#define XTPG_MIN_VBLANK 3
+#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT)
+
+/**
+ * struct xtpg_device - Xilinx Test Pattern Generator device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @npads: number of pads (1 or 2)
+ * @has_input: whether an input is connected to the sink pad
+ * @formats: active V4L2 media bus format for each pad
+ * @default_format: default V4L2 media bus format
+ * @vip_format: format information corresponding to the active format
+ * @bayer: boolean flag if TPG is set to any bayer format
+ * @ctrl_handler: control handler
+ * @hblank: horizontal blanking control
+ * @vblank: vertical blanking control
+ * @pattern: test pattern control
+ * @streaming: is the video stream active
+ * @vtc: video timing controller
+ * @vtmux_gpio: video timing mux GPIO
+ */
+struct xtpg_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+ unsigned int npads;
+ bool has_input;
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_format;
+ const struct xvip_video_format *vip_format;
+ bool bayer;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *pattern;
+ bool streaming;
+
+ struct xvtc_device *vtc;
+ struct gpio_desc *vtmux_gpio;
+};
+
+static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xtpg_device, xvip.subdev);
+}
+
+static u32 xtpg_get_bayer_phase(unsigned int code)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ return XTPG_BAYER_PHASE_RGGB;
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ return XTPG_BAYER_PHASE_GRBG;
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ return XTPG_BAYER_PHASE_GBRG;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return XTPG_BAYER_PHASE_BGGR;
+ default:
+ return XTPG_BAYER_PHASE_OFF;
+ }
+}
+
+static void __xtpg_update_pattern_control(struct xtpg_device *xtpg,
+ bool passthrough, bool pattern)
+{
+ u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1;
+
+ /*
+ * If the TPG has no sink pad or no input connected to its sink pad
+ * passthrough mode can't be enabled.
+ */
+ if (xtpg->npads == 1 || !xtpg->has_input)
+ passthrough = false;
+
+ /* If passthrough mode is allowed unmask bit 0. */
+ if (passthrough)
+ pattern_mask &= ~1;
+
+ /* If test pattern mode is allowed unmask all other bits. */
+ if (pattern)
+ pattern_mask &= 1;
+
+ __v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum,
+ pattern_mask, pattern ? 9 : 0);
+}
+
+static void xtpg_update_pattern_control(struct xtpg_device *xtpg,
+ bool passthrough, bool pattern)
+{
+ mutex_lock(xtpg->ctrl_handler.lock);
+ __xtpg_update_pattern_control(xtpg, passthrough, pattern);
+ mutex_unlock(xtpg->ctrl_handler.lock);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+ unsigned int width = xtpg->formats[0].width;
+ unsigned int height = xtpg->formats[0].height;
+ bool passthrough;
+ u32 bayer_phase;
+
+ if (!enable) {
+ xvip_stop(&xtpg->xvip);
+ if (xtpg->vtc)
+ xvtc_generator_stop(xtpg->vtc);
+
+ xtpg_update_pattern_control(xtpg, true, true);
+ xtpg->streaming = false;
+ return 0;
+ }
+
+ xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]);
+
+ if (xtpg->vtc) {
+ struct xvtc_config config = {
+ .hblank_start = width,
+ .hsync_start = width + 1,
+ .vblank_start = height,
+ .vsync_start = height + 1,
+ };
+ unsigned int htotal;
+ unsigned int vtotal;
+
+ htotal = min_t(unsigned int, XVTC_MAX_HSIZE,
+ v4l2_ctrl_g_ctrl(xtpg->hblank) + width);
+ vtotal = min_t(unsigned int, XVTC_MAX_VSIZE,
+ v4l2_ctrl_g_ctrl(xtpg->vblank) + height);
+
+ config.hsync_end = htotal - 1;
+ config.hsize = htotal;
+ config.vsync_end = vtotal - 1;
+ config.vsize = vtotal;
+
+ xvtc_generator_start(xtpg->vtc, &config);
+ }
+
+ /*
+ * Configure the bayer phase and video timing mux based on the
+ * operation mode (passthrough or test pattern generation). The test
+ * pattern can be modified by the control set handler, we thus need to
+ * take the control lock here to avoid races.
+ */
+ mutex_lock(xtpg->ctrl_handler.lock);
+
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_MASK, xtpg->pattern->cur.val);
+
+ /*
+ * Switching between passthrough and test pattern generation modes isn't
+ * allowed during streaming, update the control range accordingly.
+ */
+ passthrough = xtpg->pattern->cur.val == 0;
+ __xtpg_update_pattern_control(xtpg, passthrough, !passthrough);
+
+ xtpg->streaming = true;
+
+ mutex_unlock(xtpg->ctrl_handler.lock);
+
+ /*
+ * For TPG v5.0, the bayer phase needs to be off for the pass through
+ * mode, otherwise the external input would be subsampled.
+ */
+ bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF
+ : xtpg_get_bayer_phase(xtpg->formats[0].code);
+ xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase);
+
+ if (xtpg->vtmux_gpio)
+ gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough);
+
+ xvip_start(&xtpg->xvip);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__xtpg_get_pad_format(struct xtpg_device *xtpg,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xtpg->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xtpg_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+
+ fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+
+ return 0;
+}
+
+static int xtpg_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ u32 bayer_phase;
+
+ __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+
+ /* In two pads mode the source pad format is always identical to the
+ * sink pad format.
+ */
+ if (xtpg->npads == 2 && fmt->pad == 1) {
+ fmt->format = *__format;
+ return 0;
+ }
+
+ /* Bayer phase is configurable at runtime */
+ if (xtpg->bayer) {
+ bayer_phase = xtpg_get_bayer_phase(fmt->format.code);
+ if (bayer_phase != XTPG_BAYER_PHASE_OFF)
+ __format->code = fmt->format.code;
+ }
+
+ xvip_set_format_size(__format, fmt);
+
+ fmt->format = *__format;
+
+ /* Propagate the format to the source pad. */
+ if (xtpg->npads == 2) {
+ __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which);
+ *__format = fmt->format;
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+
+ if (fse->index || fse->code != format->code)
+ return -EINVAL;
+
+ /* Min / max values for pad 0 is always fixed in both one and two pads
+ * modes. In two pads mode, the source pad(= 1) size is identical to
+ * the sink pad size */
+ if (fse->pad == 0) {
+ fse->min_width = XVIP_MIN_WIDTH;
+ fse->max_width = XVIP_MAX_WIDTH;
+ fse->min_height = XVIP_MIN_HEIGHT;
+ fse->max_height = XVIP_MAX_HEIGHT;
+ } else {
+ fse->min_width = format->width;
+ fse->max_width = format->width;
+ fse->min_height = format->height;
+ fse->max_height = format->height;
+ }
+
+ return 0;
+}
+
+static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+ *format = xtpg->default_format;
+
+ if (xtpg->npads == 2) {
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 1);
+ *format = xtpg->default_format;
+ }
+
+ return 0;
+}
+
+static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct xtpg_device *xtpg = container_of(ctrl->handler,
+ struct xtpg_device,
+ ctrl_handler);
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_MASK, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_CROSS_HAIRS:
+ xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_MOVING_BOX:
+ xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_COLOR_MASK:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_COLOR_MASK_MASK,
+ ctrl->val <<
+ XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_STUCK_PIXEL:
+ xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_NOISE:
+ xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_NOISE, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_MOTION:
+ xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_MOTION, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_MOTION_SPEED:
+ xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
+ XTPG_CROSS_HAIRS_ROW_MASK,
+ ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
+ XTPG_CROSS_HAIRS_COLUMN_MASK,
+ ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
+ XTPG_ZPLATE_START_MASK,
+ ctrl->val << XTPG_ZPLATE_START_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
+ XTPG_ZPLATE_SPEED_MASK,
+ ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_ZPLATE_VER_START:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
+ XTPG_ZPLATE_START_MASK,
+ ctrl->val << XTPG_ZPLATE_START_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED:
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
+ XTPG_ZPLATE_SPEED_MASK,
+ ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
+ return 0;
+ case V4L2_CID_XILINX_TPG_BOX_SIZE:
+ xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_BOX_COLOR:
+ xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH:
+ xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_TPG_NOISE_GAIN:
+ xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val);
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops xtpg_ctrl_ops = {
+ .s_ctrl = xtpg_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops xtpg_core_ops = {
+};
+
+static struct v4l2_subdev_video_ops xtpg_video_ops = {
+ .s_stream = xtpg_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xtpg_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xtpg_enum_frame_size,
+ .get_fmt = xtpg_get_format,
+ .set_fmt = xtpg_set_format,
+};
+
+static struct v4l2_subdev_ops xtpg_ops = {
+ .core = &xtpg_core_ops,
+ .video = &xtpg_video_ops,
+ .pad = &xtpg_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xtpg_internal_ops = {
+ .open = xtpg_open,
+ .close = xtpg_close,
+};
+
+/*
+ * Control Config
+ */
+
+static const char *const xtpg_pattern_strings[] = {
+ "Passthrough",
+ "Horizontal Ramp",
+ "Vertical Ramp",
+ "Temporal Ramp",
+ "Solid Red",
+ "Solid Green",
+ "Solid Blue",
+ "Solid Black",
+ "Solid White",
+ "Color Bars",
+ "Zone Plate",
+ "Tartan Color Bars",
+ "Cross Hatch",
+ "None",
+ "Vertical/Horizontal Ramps",
+ "Black/White Checker Board",
+};
+
+static struct v4l2_ctrl_config xtpg_ctrls[] = {
+ {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS,
+ .name = "Test Pattern: Cross Hairs",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_MOVING_BOX,
+ .name = "Test Pattern: Moving Box",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_COLOR_MASK,
+ .name = "Test Pattern: Color Mask",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .min = 0,
+ .max = 0xf,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL,
+ .name = "Test Pattern: Stuck Pixel",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_NOISE,
+ .name = "Test Pattern: Noise",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_MOTION,
+ .name = "Test Pattern: Motion",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_MOTION_SPEED,
+ .name = "Test Pattern: Motion Speed",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 8) - 1,
+ .step = 1,
+ .def = 4,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW,
+ .name = "Test Pattern: Cross Hairs Row",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 12) - 1,
+ .step = 1,
+ .def = 0x64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN,
+ .name = "Test Pattern: Cross Hairs Column",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 12) - 1,
+ .step = 1,
+ .def = 0x64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_START,
+ .name = "Test Pattern: Zplate Horizontal Start Pos",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ .def = 0x1e,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED,
+ .name = "Test Pattern: Zplate Horizontal Speed",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_START,
+ .name = "Test Pattern: Zplate Vertical Start Pos",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ .def = 1,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED,
+ .name = "Test Pattern: Zplate Vertical Speed",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_BOX_SIZE,
+ .name = "Test Pattern: Box Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 12) - 1,
+ .step = 1,
+ .def = 0x32,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_BOX_COLOR,
+ .name = "Test Pattern: Box Color(RGB)",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 24) - 1,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH,
+ .name = "Test Pattern: Stuck Pixel threshold",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_NOISE_GAIN,
+ .name = "Test Pattern: Noise Gain",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 8) - 1,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xtpg_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int __maybe_unused xtpg_pm_suspend(struct device *dev)
+{
+ struct xtpg_device *xtpg = dev_get_drvdata(dev);
+
+ xvip_suspend(&xtpg->xvip);
+
+ return 0;
+}
+
+static int __maybe_unused xtpg_pm_resume(struct device *dev)
+{
+ struct xtpg_device *xtpg = dev_get_drvdata(dev);
+
+ xvip_resume(&xtpg->xvip);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xtpg_parse_of(struct xtpg_device *xtpg)
+{
+ struct device *dev = xtpg->xvip.dev;
+ struct device_node *node = xtpg->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ unsigned int nports = 0;
+ bool has_endpoint = false;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ for_each_child_of_node(ports, port) {
+ const struct xvip_video_format *format;
+ struct device_node *endpoint;
+
+ if (!port->name || of_node_cmp(port->name, "port"))
+ continue;
+
+ format = xvip_of_get_format(port);
+ if (IS_ERR(format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(format);
+ }
+
+ /* Get and check the format description */
+ if (!xtpg->vip_format) {
+ xtpg->vip_format = format;
+ } else if (xtpg->vip_format != format) {
+ dev_err(dev, "in/out format mismatch in DT");
+ return -EINVAL;
+ }
+
+ if (nports == 0) {
+ endpoint = of_get_next_child(port, NULL);
+ if (endpoint)
+ has_endpoint = true;
+ of_node_put(endpoint);
+ }
+
+ /* Count the number of ports. */
+ nports++;
+ }
+
+ if (nports != 1 && nports != 2) {
+ dev_err(dev, "invalid number of ports %u\n", nports);
+ return -EINVAL;
+ }
+
+ xtpg->npads = nports;
+ if (nports == 2 && has_endpoint)
+ xtpg->has_input = true;
+
+ return 0;
+}
+
+static int xtpg_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xtpg_device *xtpg;
+ u32 i, bayer_phase;
+ int ret;
+
+ xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL);
+ if (!xtpg)
+ return -ENOMEM;
+
+ xtpg->xvip.dev = &pdev->dev;
+
+ ret = xtpg_parse_of(xtpg);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xtpg->xvip);
+ if (ret < 0)
+ return ret;
+
+ xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(xtpg->vtmux_gpio)) {
+ ret = PTR_ERR(xtpg->vtmux_gpio);
+ goto error_resource;
+ }
+
+ xtpg->vtc = xvtc_of_get(pdev->dev.of_node);
+ if (IS_ERR(xtpg->vtc)) {
+ ret = PTR_ERR(xtpg->vtc);
+ goto error_resource;
+ }
+
+ /* Reset and initialize the core */
+ xvip_reset(&xtpg->xvip);
+
+ /* Initialize V4L2 subdevice and media entity. Pad numbers depend on the
+ * number of pads.
+ */
+ if (xtpg->npads == 2) {
+ xtpg->pads[0].flags = MEDIA_PAD_FL_SINK;
+ xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ } else {
+ xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+ }
+
+ /* Initialize the default format */
+ xtpg->default_format.code = xtpg->vip_format->code;
+ xtpg->default_format.field = V4L2_FIELD_NONE;
+ xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB;
+ xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format);
+
+ bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code);
+ if (bayer_phase != XTPG_BAYER_PHASE_OFF)
+ xtpg->bayer = true;
+
+ xtpg->formats[0] = xtpg->default_format;
+ if (xtpg->npads == 2)
+ xtpg->formats[1] = xtpg->default_format;
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xtpg->xvip.subdev;
+ v4l2_subdev_init(subdev, &xtpg_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xtpg_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xtpg);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->entity.ops = &xtpg_media_ops;
+
+ ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0);
+ if (ret < 0)
+ goto error;
+
+ v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls));
+
+ xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
+ V4L2_CID_VBLANK, XTPG_MIN_VBLANK,
+ XTPG_MAX_VBLANK, 1, 100);
+ xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
+ V4L2_CID_HBLANK, XTPG_MIN_HBLANK,
+ XTPG_MAX_HBLANK, 1, 100);
+ xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
+ &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(xtpg_pattern_strings) - 1,
+ 1, 9, xtpg_pattern_strings);
+
+ for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++)
+ v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL);
+
+ if (xtpg->ctrl_handler.error) {
+ dev_err(&pdev->dev, "failed to add controls\n");
+ ret = xtpg->ctrl_handler.error;
+ goto error;
+ }
+ subdev->ctrl_handler = &xtpg->ctrl_handler;
+
+ xtpg_update_pattern_control(xtpg, true, true);
+
+ ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set controls\n");
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, xtpg);
+
+ xvip_print_version(&xtpg->xvip);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ xvtc_put(xtpg->vtc);
+error_resource:
+ xvip_cleanup_resources(&xtpg->xvip);
+ return ret;
+}
+
+static int xtpg_remove(struct platform_device *pdev)
+{
+ struct xtpg_device *xtpg = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xtpg->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xtpg->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xtpg->xvip);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume);
+
+static const struct of_device_id xtpg_of_id_table[] = {
+ { .compatible = "xlnx,v-tpg-5.0" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xtpg_of_id_table);
+
+static struct platform_driver xtpg_driver = {
+ .driver = {
+ .name = "xilinx-tpg",
+ .pm = &xtpg_pm_ops,
+ .of_match_table = xtpg_of_id_table,
+ },
+ .probe = xtpg_probe,
+ .remove = xtpg_remove,
+};
+
+module_platform_driver(xtpg_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
new file mode 100644
index 0000000..3112591
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -0,0 +1,323 @@
+/*
+ * Xilinx Video IP Core
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/media/xilinx-vip.h>
+
+#include "xilinx-vip.h"
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+static const struct xvip_video_format xvip_video_formats[] = {
+ { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
+ 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" },
+ { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
+ 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" },
+ { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
+ 3, 0, NULL },
+ { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
+ 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" },
+ { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
+ 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" },
+ { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
+ 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" },
+ { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
+ 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" },
+ { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8,
+ 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" },
+};
+
+/**
+ * xvip_get_format_by_code - Retrieve format information for a media bus code
+ * @code: the format media bus code
+ *
+ * Return: a pointer to the format information structure corresponding to the
+ * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can
+ * be found.
+ */
+const struct xvip_video_format *xvip_get_format_by_code(unsigned int code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
+ const struct xvip_video_format *format = &xvip_video_formats[i];
+
+ if (format->code == code)
+ return format;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(xvip_get_format_by_code);
+
+/**
+ * xvip_get_format_by_fourcc - Retrieve format information for a 4CC
+ * @fourcc: the format 4CC
+ *
+ * Return: a pointer to the format information structure corresponding to the
+ * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be
+ * found.
+ */
+const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
+ const struct xvip_video_format *format = &xvip_video_formats[i];
+
+ if (format->fourcc == fourcc)
+ return format;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
+
+/**
+ * xvip_of_get_format - Parse a device tree node and return format information
+ * @node: the device tree node
+ *
+ * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties
+ * from the device tree @node passed as an argument and return the corresponding
+ * format information.
+ *
+ * Return: a pointer to the format information structure corresponding to the
+ * format name and width, or ERR_PTR if no corresponding format can be found.
+ */
+const struct xvip_video_format *xvip_of_get_format(struct device_node *node)
+{
+ const char *pattern = "mono";
+ unsigned int vf_code;
+ unsigned int i;
+ u32 width;
+ int ret;
+
+ ret = of_property_read_u32(node, "xlnx,video-format", &vf_code);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ret = of_property_read_u32(node, "xlnx,video-width", &width);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (vf_code == XVIP_VF_MONO_SENSOR)
+ of_property_read_string(node, "xlnx,cfa-pattern", &pattern);
+
+ for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
+ const struct xvip_video_format *format = &xvip_video_formats[i];
+
+ if (format->vf_code != vf_code || format->width != width)
+ continue;
+
+ if (vf_code == XVIP_VF_MONO_SENSOR &&
+ strcmp(pattern, format->pattern))
+ continue;
+
+ return format;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(xvip_of_get_format);
+
+/**
+ * xvip_set_format_size - Set the media bus frame format size
+ * @format: V4L2 frame format on media bus
+ * @fmt: media bus format
+ *
+ * Set the media bus frame format size. The width / height from the subdevice
+ * format are set to the given media bus format. The new format size is stored
+ * in @format. The width and height are clamped using default min / max values.
+ */
+void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
+ const struct v4l2_subdev_format *fmt)
+{
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XVIP_MIN_WIDTH, XVIP_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT);
+}
+EXPORT_SYMBOL_GPL(xvip_set_format_size);
+
+/**
+ * xvip_clr_or_set - Clear or set the register with a bitmask
+ * @xvip: Xilinx Video IP device
+ * @addr: address of register
+ * @mask: bitmask to be set or cleared
+ * @set: boolean flag indicating whether to set or clear
+ *
+ * Clear or set the register at address @addr with a bitmask @mask depending on
+ * the boolean flag @set. When the flag @set is true, the bitmask is set in
+ * the register, otherwise the bitmask is cleared from the register
+ * when the flag @set is false.
+ *
+ * Fox eample, this function can be used to set a control with a boolean value
+ * requested by users. If the caller knows whether to set or clear in the first
+ * place, the caller should call xvip_clr() or xvip_set() directly instead of
+ * using this function.
+ */
+void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set)
+{
+ u32 reg;
+
+ reg = xvip_read(xvip, addr);
+ reg = set ? reg | mask : reg & ~mask;
+ xvip_write(xvip, addr, reg);
+}
+EXPORT_SYMBOL_GPL(xvip_clr_or_set);
+
+/**
+ * xvip_clr_and_set - Clear and set the register with a bitmask
+ * @xvip: Xilinx Video IP device
+ * @addr: address of register
+ * @clr: bitmask to be cleared
+ * @set: bitmask to be set
+ *
+ * Clear a bit(s) of mask @clr in the register at address @addr, then set
+ * a bit(s) of mask @set in the register after.
+ */
+void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set)
+{
+ u32 reg;
+
+ reg = xvip_read(xvip, addr);
+ reg &= ~clr;
+ reg |= set;
+ xvip_write(xvip, addr, reg);
+}
+EXPORT_SYMBOL_GPL(xvip_clr_and_set);
+
+int xvip_init_resources(struct xvip_device *xvip)
+{
+ struct platform_device *pdev = to_platform_device(xvip->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xvip->iomem = devm_ioremap_resource(xvip->dev, res);
+ if (IS_ERR(xvip->iomem))
+ return PTR_ERR(xvip->iomem);
+
+ xvip->clk = devm_clk_get(xvip->dev, NULL);
+ if (IS_ERR(xvip->clk))
+ return PTR_ERR(xvip->clk);
+
+ clk_prepare_enable(xvip->clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xvip_init_resources);
+
+void xvip_cleanup_resources(struct xvip_device *xvip)
+{
+ clk_disable_unprepare(xvip->clk);
+}
+EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
+
+/* -----------------------------------------------------------------------------
+ * Subdev operations handlers
+ */
+
+/**
+ * xvip_enum_mbus_code - Enumerate the media format code
+ * @subdev: V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @code: returning media bus code
+ *
+ * Enumerate the media bus code of the subdevice. Return the corresponding
+ * pad format code. This function only works for subdevices with fixed format
+ * on all pads. Subdevices with multiple format should have their own
+ * function to enumerate mbus codes.
+ *
+ * Return: 0 if the media bus code is found, or -EINVAL if the format index
+ * is not valid.
+ */
+int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ /* Enumerating frame sizes based on the active configuration isn't
+ * supported yet.
+ */
+ if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (code->index)
+ return -EINVAL;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, code->pad);
+
+ code->code = format->code;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
+
+/**
+ * xvip_enum_frame_size - Enumerate the media bus frame size
+ * @subdev: V4L2 subdevice
+ * @cfg: V4L2 subdev pad configuration
+ * @fse: returning media bus frame size
+ *
+ * This function is a drop-in implementation of the subdev enum_frame_size pad
+ * operation. It assumes that the subdevice has one sink pad and one source
+ * pad, and that the format on the source pad is always identical to the
+ * format on the sink pad. Entities with different requirements need to
+ * implement their own enum_frame_size handlers.
+ *
+ * Return: 0 if the media bus frame size is found, or -EINVAL
+ * if the index or the code is not valid.
+ */
+int xvip_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ /* Enumerating frame sizes based on the active configuration isn't
+ * supported yet.
+ */
+ if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+
+ if (fse->index || fse->code != format->code)
+ return -EINVAL;
+
+ if (fse->pad == XVIP_PAD_SINK) {
+ fse->min_width = XVIP_MIN_WIDTH;
+ fse->max_width = XVIP_MAX_WIDTH;
+ fse->min_height = XVIP_MIN_HEIGHT;
+ fse->max_height = XVIP_MAX_HEIGHT;
+ } else {
+ /* The size on the source pad is fixed and always identical to
+ * the size on the sink pad.
+ */
+ fse->min_width = format->width;
+ fse->max_width = format->width;
+ fse->min_height = format->height;
+ fse->max_height = format->height;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xvip_enum_frame_size);
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
new file mode 100644
index 0000000..42fee20
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -0,0 +1,238 @@
+/*
+ * Xilinx Video IP Core
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_VIP_H__
+#define __XILINX_VIP_H__
+
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct clk;
+
+/*
+ * Minimum and maximum width and height common to most video IP cores. IP
+ * cores with different requirements must define their own values.
+ */
+#define XVIP_MIN_WIDTH 32
+#define XVIP_MAX_WIDTH 7680
+#define XVIP_MIN_HEIGHT 32
+#define XVIP_MAX_HEIGHT 7680
+
+/*
+ * Pad IDs. IP cores with with multiple inputs or outputs should define
+ * their own values.
+ */
+#define XVIP_PAD_SINK 0
+#define XVIP_PAD_SOURCE 1
+
+/* Xilinx Video IP Control Registers */
+#define XVIP_CTRL_CONTROL 0x0000
+#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0)
+#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1)
+#define XVIP_CTRL_CONTROL_BYPASS (1 << 4)
+#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5)
+#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30)
+#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31)
+#define XVIP_CTRL_STATUS 0x0004
+#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0)
+#define XVIP_CTRL_STATUS_EOF (1 << 1)
+#define XVIP_CTRL_ERROR 0x0008
+#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0)
+#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1)
+#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2)
+#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3)
+#define XVIP_CTRL_IRQ_ENABLE 0x000c
+#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0)
+#define XVIP_CTRL_IRQ_EOF (1 << 1)
+#define XVIP_CTRL_VERSION 0x0010
+#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24)
+#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24
+#define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16)
+#define XVIP_CTRL_VERSION_MINOR_SHIFT 16
+#define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12)
+#define XVIP_CTRL_VERSION_REVISION_SHIFT 12
+#define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8)
+#define XVIP_CTRL_VERSION_PATCH_SHIFT 8
+#define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0)
+#define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0
+
+/* Xilinx Video IP Timing Registers */
+#define XVIP_ACTIVE_SIZE 0x0020
+#define XVIP_ACTIVE_VSIZE_MASK (0x7ff << 16)
+#define XVIP_ACTIVE_VSIZE_SHIFT 16
+#define XVIP_ACTIVE_HSIZE_MASK (0x7ff << 0)
+#define XVIP_ACTIVE_HSIZE_SHIFT 0
+#define XVIP_ENCODING 0x0028
+#define XVIP_ENCODING_NBITS_8 (0 << 4)
+#define XVIP_ENCODING_NBITS_10 (1 << 4)
+#define XVIP_ENCODING_NBITS_12 (2 << 4)
+#define XVIP_ENCODING_NBITS_16 (3 << 4)
+#define XVIP_ENCODING_NBITS_MASK (3 << 4)
+#define XVIP_ENCODING_NBITS_SHIFT 4
+#define XVIP_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0)
+#define XVIP_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0)
+#define XVIP_ENCODING_VIDEO_FORMAT_RGB (2 << 0)
+#define XVIP_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0)
+#define XVIP_ENCODING_VIDEO_FORMAT_MASK (3 << 0)
+#define XVIP_ENCODING_VIDEO_FORMAT_SHIFT 0
+
+/**
+ * struct xvip_device - Xilinx Video IP device structure
+ * @subdev: V4L2 subdevice
+ * @dev: (OF) device
+ * @iomem: device I/O register space remapped to kernel virtual memory
+ * @clk: video core clock
+ * @saved_ctrl: saved control register for resume / suspend
+ */
+struct xvip_device {
+ struct v4l2_subdev subdev;
+ struct device *dev;
+ void __iomem *iomem;
+ struct clk *clk;
+ u32 saved_ctrl;
+};
+
+/**
+ * struct xvip_video_format - Xilinx Video IP video format description
+ * @vf_code: AXI4 video format code
+ * @width: AXI4 format width in bits per component
+ * @pattern: CFA pattern for Mono/Sensor formats
+ * @code: media bus format code
+ * @bpp: bytes per pixel (when stored in memory)
+ * @fourcc: V4L2 pixel format FCC identifier
+ * @description: format description, suitable for userspace
+ */
+struct xvip_video_format {
+ unsigned int vf_code;
+ unsigned int width;
+ const char *pattern;
+ unsigned int code;
+ unsigned int bpp;
+ u32 fourcc;
+ const char *description;
+};
+
+const struct xvip_video_format *xvip_get_format_by_code(unsigned int code);
+const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc);
+const struct xvip_video_format *xvip_of_get_format(struct device_node *node);
+void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
+ const struct v4l2_subdev_format *fmt);
+int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code);
+int xvip_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse);
+
+static inline u32 xvip_read(struct xvip_device *xvip, u32 addr)
+{
+ return ioread32(xvip->iomem + addr);
+}
+
+static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value)
+{
+ iowrite32(value, xvip->iomem + addr);
+}
+
+static inline void xvip_clr(struct xvip_device *xvip, u32 addr, u32 clr)
+{
+ xvip_write(xvip, addr, xvip_read(xvip, addr) & ~clr);
+}
+
+static inline void xvip_set(struct xvip_device *xvip, u32 addr, u32 set)
+{
+ xvip_write(xvip, addr, xvip_read(xvip, addr) | set);
+}
+
+void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set);
+void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set);
+
+int xvip_init_resources(struct xvip_device *xvip);
+void xvip_cleanup_resources(struct xvip_device *xvip);
+
+static inline void xvip_reset(struct xvip_device *xvip)
+{
+ xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET);
+}
+
+static inline void xvip_start(struct xvip_device *xvip)
+{
+ xvip_set(xvip, XVIP_CTRL_CONTROL,
+ XVIP_CTRL_CONTROL_SW_ENABLE | XVIP_CTRL_CONTROL_REG_UPDATE);
+}
+
+static inline void xvip_stop(struct xvip_device *xvip)
+{
+ xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE);
+}
+
+static inline void xvip_resume(struct xvip_device *xvip)
+{
+ xvip_write(xvip, XVIP_CTRL_CONTROL,
+ xvip->saved_ctrl | XVIP_CTRL_CONTROL_SW_ENABLE);
+}
+
+static inline void xvip_suspend(struct xvip_device *xvip)
+{
+ xvip->saved_ctrl = xvip_read(xvip, XVIP_CTRL_CONTROL);
+ xvip_write(xvip, XVIP_CTRL_CONTROL,
+ xvip->saved_ctrl & ~XVIP_CTRL_CONTROL_SW_ENABLE);
+}
+
+static inline void xvip_set_frame_size(struct xvip_device *xvip,
+ const struct v4l2_mbus_framefmt *format)
+{
+ xvip_write(xvip, XVIP_ACTIVE_SIZE,
+ (format->height << XVIP_ACTIVE_VSIZE_SHIFT) |
+ (format->width << XVIP_ACTIVE_HSIZE_SHIFT));
+}
+
+static inline void xvip_get_frame_size(struct xvip_device *xvip,
+ struct v4l2_mbus_framefmt *format)
+{
+ u32 reg;
+
+ reg = xvip_read(xvip, XVIP_ACTIVE_SIZE);
+ format->width = (reg & XVIP_ACTIVE_HSIZE_MASK) >>
+ XVIP_ACTIVE_HSIZE_SHIFT;
+ format->height = (reg & XVIP_ACTIVE_VSIZE_MASK) >>
+ XVIP_ACTIVE_VSIZE_SHIFT;
+}
+
+static inline void xvip_enable_reg_update(struct xvip_device *xvip)
+{
+ xvip_set(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE);
+}
+
+static inline void xvip_disable_reg_update(struct xvip_device *xvip)
+{
+ xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE);
+}
+
+static inline void xvip_print_version(struct xvip_device *xvip)
+{
+ u32 version;
+
+ version = xvip_read(xvip, XVIP_CTRL_VERSION);
+
+ dev_info(xvip->dev, "device found, version %u.%02x%x\n",
+ ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >>
+ XVIP_CTRL_VERSION_MAJOR_SHIFT),
+ ((version & XVIP_CTRL_VERSION_MINOR_MASK) >>
+ XVIP_CTRL_VERSION_MINOR_SHIFT),
+ ((version & XVIP_CTRL_VERSION_REVISION_MASK) >>
+ XVIP_CTRL_VERSION_REVISION_SHIFT));
+}
+
+#endif /* __XILINX_VIP_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
new file mode 100644
index 0000000..7b7cb9c
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -0,0 +1,669 @@
+/*
+ * Xilinx Video IP Composite Device
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
+
+#include "xilinx-dma.h"
+#include "xilinx-vipp.h"
+
+#define XVIPP_DMA_S2MM 0
+#define XVIPP_DMA_MM2S 1
+
+/**
+ * struct xvip_graph_entity - Entity in the video graph
+ * @list: list entry in a graph entities list
+ * @node: the entity's DT node
+ * @entity: media entity, from the corresponding V4L2 subdev
+ * @asd: subdev asynchronous registration information
+ * @subdev: V4L2 subdev
+ */
+struct xvip_graph_entity {
+ struct list_head list;
+ struct device_node *node;
+ struct media_entity *entity;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_subdev *subdev;
+};
+
+/* -----------------------------------------------------------------------------
+ * Graph Management
+ */
+
+static struct xvip_graph_entity *
+xvip_graph_find_entity(struct xvip_composite_device *xdev,
+ const struct device_node *node)
+{
+ struct xvip_graph_entity *entity;
+
+ list_for_each_entry(entity, &xdev->entities, list) {
+ if (entity->node == node)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static int xvip_graph_build_one(struct xvip_composite_device *xdev,
+ struct xvip_graph_entity *entity)
+{
+ u32 link_flags = MEDIA_LNK_FL_ENABLED;
+ struct media_entity *local = entity->entity;
+ struct media_entity *remote;
+ struct media_pad *local_pad;
+ struct media_pad *remote_pad;
+ struct xvip_graph_entity *ent;
+ struct v4l2_of_link link;
+ struct device_node *ep = NULL;
+ struct device_node *next;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "creating links for entity %s\n", local->name);
+
+ while (1) {
+ /* Get the next endpoint and parse its link. */
+ next = of_graph_get_next_endpoint(entity->node, ep);
+ if (next == NULL)
+ break;
+
+ of_node_put(ep);
+ ep = next;
+
+ dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name);
+
+ ret = v4l2_of_parse_link(ep, &link);
+ if (ret < 0) {
+ dev_err(xdev->dev, "failed to parse link for %s\n",
+ ep->full_name);
+ continue;
+ }
+
+ /* Skip sink ports, they will be processed from the other end of
+ * the link.
+ */
+ if (link.local_port >= local->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u on %s\n",
+ link.local_port, link.local_node->full_name);
+ v4l2_of_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ local_pad = &local->pads[link.local_port];
+
+ if (local_pad->flags & MEDIA_PAD_FL_SINK) {
+ dev_dbg(xdev->dev, "skipping sink port %s:%u\n",
+ link.local_node->full_name, link.local_port);
+ v4l2_of_put_link(&link);
+ continue;
+ }
+
+ /* Skip DMA engines, they will be processed separately. */
+ if (link.remote_node == xdev->dev->of_node) {
+ dev_dbg(xdev->dev, "skipping DMA port %s:%u\n",
+ link.local_node->full_name, link.local_port);
+ v4l2_of_put_link(&link);
+ continue;
+ }
+
+ /* Find the remote entity. */
+ ent = xvip_graph_find_entity(xdev, link.remote_node);
+ if (ent == NULL) {
+ dev_err(xdev->dev, "no entity found for %s\n",
+ link.remote_node->full_name);
+ v4l2_of_put_link(&link);
+ ret = -ENODEV;
+ break;
+ }
+
+ remote = ent->entity;
+
+ if (link.remote_port >= remote->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u on %s\n",
+ link.remote_port, link.remote_node->full_name);
+ v4l2_of_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ remote_pad = &remote->pads[link.remote_port];
+
+ v4l2_of_put_link(&link);
+
+ /* Create the media link. */
+ dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
+ local->name, local_pad->index,
+ remote->name, remote_pad->index);
+
+ ret = media_entity_create_link(local, local_pad->index,
+ remote, remote_pad->index,
+ link_flags);
+ if (ret < 0) {
+ dev_err(xdev->dev,
+ "failed to create %s:%u -> %s:%u link\n",
+ local->name, local_pad->index,
+ remote->name, remote_pad->index);
+ break;
+ }
+ }
+
+ of_node_put(ep);
+ return ret;
+}
+
+static struct xvip_dma *
+xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port)
+{
+ struct xvip_dma *dma;
+
+ list_for_each_entry(dma, &xdev->dmas, list) {
+ if (dma->port == port)
+ return dma;
+ }
+
+ return NULL;
+}
+
+static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
+{
+ u32 link_flags = MEDIA_LNK_FL_ENABLED;
+ struct device_node *node = xdev->dev->of_node;
+ struct media_entity *source;
+ struct media_entity *sink;
+ struct media_pad *source_pad;
+ struct media_pad *sink_pad;
+ struct xvip_graph_entity *ent;
+ struct v4l2_of_link link;
+ struct device_node *ep = NULL;
+ struct device_node *next;
+ struct xvip_dma *dma;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "creating links for DMA engines\n");
+
+ while (1) {
+ /* Get the next endpoint and parse its link. */
+ next = of_graph_get_next_endpoint(node, ep);
+ if (next == NULL)
+ break;
+
+ of_node_put(ep);
+ ep = next;
+
+ dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name);
+
+ ret = v4l2_of_parse_link(ep, &link);
+ if (ret < 0) {
+ dev_err(xdev->dev, "failed to parse link for %s\n",
+ ep->full_name);
+ continue;
+ }
+
+ /* Find the DMA engine. */
+ dma = xvip_graph_find_dma(xdev, link.local_port);
+ if (dma == NULL) {
+ dev_err(xdev->dev, "no DMA engine found for port %u\n",
+ link.local_port);
+ v4l2_of_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ dev_dbg(xdev->dev, "creating link for DMA engine %s\n",
+ dma->video.name);
+
+ /* Find the remote entity. */
+ ent = xvip_graph_find_entity(xdev, link.remote_node);
+ if (ent == NULL) {
+ dev_err(xdev->dev, "no entity found for %s\n",
+ link.remote_node->full_name);
+ v4l2_of_put_link(&link);
+ ret = -ENODEV;
+ break;
+ }
+
+ if (link.remote_port >= ent->entity->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u on %s\n",
+ link.remote_port, link.remote_node->full_name);
+ v4l2_of_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) {
+ source = &dma->video.entity;
+ source_pad = &dma->pad;
+ sink = ent->entity;
+ sink_pad = &sink->pads[link.remote_port];
+ } else {
+ source = ent->entity;
+ source_pad = &source->pads[link.remote_port];
+ sink = &dma->video.entity;
+ sink_pad = &dma->pad;
+ }
+
+ v4l2_of_put_link(&link);
+
+ /* Create the media link. */
+ dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
+ source->name, source_pad->index,
+ sink->name, sink_pad->index);
+
+ ret = media_entity_create_link(source, source_pad->index,
+ sink, sink_pad->index,
+ link_flags);
+ if (ret < 0) {
+ dev_err(xdev->dev,
+ "failed to create %s:%u -> %s:%u link\n",
+ source->name, source_pad->index,
+ sink->name, sink_pad->index);
+ break;
+ }
+ }
+
+ of_node_put(ep);
+ return ret;
+}
+
+static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct xvip_composite_device *xdev =
+ container_of(notifier, struct xvip_composite_device, notifier);
+ struct xvip_graph_entity *entity;
+ int ret;
+
+ dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
+
+ /* Create links for every entity. */
+ list_for_each_entry(entity, &xdev->entities, list) {
+ ret = xvip_graph_build_one(xdev, entity);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Create links for DMA channels. */
+ ret = xvip_graph_build_dma(xdev);
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev);
+ if (ret < 0)
+ dev_err(xdev->dev, "failed to register subdev nodes\n");
+
+ return ret;
+}
+
+static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct xvip_composite_device *xdev =
+ container_of(notifier, struct xvip_composite_device, notifier);
+ struct xvip_graph_entity *entity;
+
+ /* Locate the entity corresponding to the bound subdev and store the
+ * subdev pointer.
+ */
+ list_for_each_entry(entity, &xdev->entities, list) {
+ if (entity->node != subdev->dev->of_node)
+ continue;
+
+ if (entity->subdev) {
+ dev_err(xdev->dev, "duplicate subdev for node %s\n",
+ entity->node->full_name);
+ return -EINVAL;
+ }
+
+ dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name);
+ entity->entity = &subdev->entity;
+ entity->subdev = subdev;
+ return 0;
+ }
+
+ dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name);
+ return -EINVAL;
+}
+
+static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
+ struct device_node *node)
+{
+ struct xvip_graph_entity *entity;
+ struct device_node *remote;
+ struct device_node *ep = NULL;
+ struct device_node *next;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "parsing node %s\n", node->full_name);
+
+ while (1) {
+ next = of_graph_get_next_endpoint(node, ep);
+ if (next == NULL)
+ break;
+
+ of_node_put(ep);
+ ep = next;
+
+ dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name);
+
+ remote = of_graph_get_remote_port_parent(ep);
+ if (remote == NULL) {
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Skip entities that we have already processed. */
+ if (remote == xdev->dev->of_node ||
+ xvip_graph_find_entity(xdev, remote)) {
+ of_node_put(remote);
+ continue;
+ }
+
+ entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL);
+ if (entity == NULL) {
+ of_node_put(remote);
+ ret = -ENOMEM;
+ break;
+ }
+
+ entity->node = remote;
+ entity->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ entity->asd.match.of.node = remote;
+ list_add_tail(&entity->list, &xdev->entities);
+ xdev->num_subdevs++;
+ }
+
+ of_node_put(ep);
+ return ret;
+}
+
+static int xvip_graph_parse(struct xvip_composite_device *xdev)
+{
+ struct xvip_graph_entity *entity;
+ int ret;
+
+ /*
+ * Walk the links to parse the full graph. Start by parsing the
+ * composite node and then parse entities in turn. The list_for_each
+ * loop will handle entities added at the end of the list while walking
+ * the links.
+ */
+ ret = xvip_graph_parse_one(xdev, xdev->dev->of_node);
+ if (ret < 0)
+ return 0;
+
+ list_for_each_entry(entity, &xdev->entities, list) {
+ ret = xvip_graph_parse_one(xdev, entity->node);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
+ struct device_node *node)
+{
+ struct xvip_dma *dma;
+ enum v4l2_buf_type type;
+ const char *direction;
+ unsigned int index;
+ int ret;
+
+ ret = of_property_read_string(node, "direction", &direction);
+ if (ret < 0)
+ return ret;
+
+ if (strcmp(direction, "input") == 0)
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ else if (strcmp(direction, "output") == 0)
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ else
+ return -EINVAL;
+
+ of_property_read_u32(node, "reg", &index);
+
+ dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL);
+ if (dma == NULL)
+ return -ENOMEM;
+
+ ret = xvip_dma_init(xdev, dma, type, index);
+ if (ret < 0) {
+ dev_err(xdev->dev, "%s initialization failed\n",
+ node->full_name);
+ return ret;
+ }
+
+ list_add_tail(&dma->list, &xdev->dmas);
+
+ xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT;
+
+ return 0;
+}
+
+static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
+{
+ struct device_node *ports;
+ struct device_node *port;
+ int ret;
+
+ ports = of_get_child_by_name(xdev->dev->of_node, "ports");
+ if (ports == NULL) {
+ dev_err(xdev->dev, "ports node not present\n");
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(ports, port) {
+ ret = xvip_graph_dma_init_one(xdev, port);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void xvip_graph_cleanup(struct xvip_composite_device *xdev)
+{
+ struct xvip_graph_entity *entityp;
+ struct xvip_graph_entity *entity;
+ struct xvip_dma *dmap;
+ struct xvip_dma *dma;
+
+ v4l2_async_notifier_unregister(&xdev->notifier);
+
+ list_for_each_entry_safe(entity, entityp, &xdev->entities, list) {
+ of_node_put(entity->node);
+ list_del(&entity->list);
+ }
+
+ list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) {
+ xvip_dma_cleanup(dma);
+ list_del(&dma->list);
+ }
+}
+
+static int xvip_graph_init(struct xvip_composite_device *xdev)
+{
+ struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev **subdevs = NULL;
+ unsigned int num_subdevs;
+ unsigned int i;
+ int ret;
+
+ /* Init the DMA channels. */
+ ret = xvip_graph_dma_init(xdev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "DMA initialization failed\n");
+ goto done;
+ }
+
+ /* Parse the graph to extract a list of subdevice DT nodes. */
+ ret = xvip_graph_parse(xdev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "graph parsing failed\n");
+ goto done;
+ }
+
+ if (!xdev->num_subdevs) {
+ dev_err(xdev->dev, "no subdev found in graph\n");
+ goto done;
+ }
+
+ /* Register the subdevices notifier. */
+ num_subdevs = xdev->num_subdevs;
+ subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs,
+ GFP_KERNEL);
+ if (subdevs == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ i = 0;
+ list_for_each_entry(entity, &xdev->entities, list)
+ subdevs[i++] = &entity->asd;
+
+ xdev->notifier.subdevs = subdevs;
+ xdev->notifier.num_subdevs = num_subdevs;
+ xdev->notifier.bound = xvip_graph_notify_bound;
+ xdev->notifier.complete = xvip_graph_notify_complete;
+
+ ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
+ if (ret < 0) {
+ dev_err(xdev->dev, "notifier registration failed\n");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret < 0)
+ xvip_graph_cleanup(xdev);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Media Controller and V4L2
+ */
+
+static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev)
+{
+ v4l2_device_unregister(&xdev->v4l2_dev);
+ media_device_unregister(&xdev->media_dev);
+}
+
+static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev)
+{
+ int ret;
+
+ xdev->media_dev.dev = xdev->dev;
+ strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device",
+ sizeof(xdev->media_dev.model));
+ xdev->media_dev.hw_revision = 0;
+
+ ret = media_device_register(&xdev->media_dev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "media device registration failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ xdev->v4l2_dev.mdev = &xdev->media_dev;
+ ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "V4L2 device registration failed (%d)\n",
+ ret);
+ media_device_unregister(&xdev->media_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xvip_composite_probe(struct platform_device *pdev)
+{
+ struct xvip_composite_device *xdev;
+ int ret;
+
+ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->dev = &pdev->dev;
+ INIT_LIST_HEAD(&xdev->entities);
+ INIT_LIST_HEAD(&xdev->dmas);
+
+ ret = xvip_composite_v4l2_init(xdev);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_graph_init(xdev);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xdev);
+
+ dev_info(xdev->dev, "device registered\n");
+
+ return 0;
+
+error:
+ xvip_composite_v4l2_cleanup(xdev);
+ return ret;
+}
+
+static int xvip_composite_remove(struct platform_device *pdev)
+{
+ struct xvip_composite_device *xdev = platform_get_drvdata(pdev);
+
+ xvip_graph_cleanup(xdev);
+ xvip_composite_v4l2_cleanup(xdev);
+
+ return 0;
+}
+
+static const struct of_device_id xvip_composite_of_id_table[] = {
+ { .compatible = "xlnx,video" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table);
+
+static struct platform_driver xvip_composite_driver = {
+ .driver = {
+ .name = "xilinx-video",
+ .of_match_table = xvip_composite_of_id_table,
+ },
+ .probe = xvip_composite_probe,
+ .remove = xvip_composite_remove,
+};
+
+module_platform_driver(xvip_composite_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx Video IP Composite Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
new file mode 100644
index 0000000..faf6b6e
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -0,0 +1,49 @@
+/*
+ * Xilinx Video IP Composite Device
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_VIPP_H__
+#define __XILINX_VIPP_H__
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+/**
+ * struct xvip_composite_device - Xilinx Video IP device structure
+ * @v4l2_dev: V4L2 device
+ * @media_dev: media device
+ * @dev: (OF) device
+ * @notifier: V4L2 asynchronous subdevs notifier
+ * @entities: entities in the graph as a list of xvip_graph_entity
+ * @num_subdevs: number of subdevs in the pipeline
+ * @dmas: list of DMA channels at the pipeline output and input
+ * @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP)
+ */
+struct xvip_composite_device {
+ struct v4l2_device v4l2_dev;
+ struct media_device media_dev;
+ struct device *dev;
+
+ struct v4l2_async_notifier notifier;
+ struct list_head entities;
+ unsigned int num_subdevs;
+
+ struct list_head dmas;
+ u32 v4l2_caps;
+};
+
+#endif /* __XILINX_VIPP_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c
new file mode 100644
index 0000000..01c750e
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vtc.c
@@ -0,0 +1,380 @@
+/*
+ * Xilinx Video Timing Controller
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "xilinx-vip.h"
+#include "xilinx-vtc.h"
+
+#define XVTC_CONTROL_FIELD_ID_POL_SRC (1 << 26)
+#define XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC (1 << 25)
+#define XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC (1 << 24)
+#define XVTC_CONTROL_HSYNC_POL_SRC (1 << 23)
+#define XVTC_CONTROL_VSYNC_POL_SRC (1 << 22)
+#define XVTC_CONTROL_HBLANK_POL_SRC (1 << 21)
+#define XVTC_CONTROL_VBLANK_POL_SRC (1 << 20)
+#define XVTC_CONTROL_CHROMA_SRC (1 << 18)
+#define XVTC_CONTROL_VBLANK_HOFF_SRC (1 << 17)
+#define XVTC_CONTROL_VSYNC_END_SRC (1 << 16)
+#define XVTC_CONTROL_VSYNC_START_SRC (1 << 15)
+#define XVTC_CONTROL_ACTIVE_VSIZE_SRC (1 << 14)
+#define XVTC_CONTROL_FRAME_VSIZE_SRC (1 << 13)
+#define XVTC_CONTROL_HSYNC_END_SRC (1 << 11)
+#define XVTC_CONTROL_HSYNC_START_SRC (1 << 10)
+#define XVTC_CONTROL_ACTIVE_HSIZE_SRC (1 << 9)
+#define XVTC_CONTROL_FRAME_HSIZE_SRC (1 << 8)
+#define XVTC_CONTROL_SYNC_ENABLE (1 << 5)
+#define XVTC_CONTROL_DET_ENABLE (1 << 3)
+#define XVTC_CONTROL_GEN_ENABLE (1 << 2)
+
+#define XVTC_STATUS_FSYNC(n) ((n) << 16)
+#define XVTC_STATUS_GEN_ACTIVE_VIDEO (1 << 13)
+#define XVTC_STATUS_GEN_VBLANK (1 << 12)
+#define XVTC_STATUS_DET_ACTIVE_VIDEO (1 << 11)
+#define XVTC_STATUS_DET_VBLANK (1 << 10)
+#define XVTC_STATUS_LOCK_LOSS (1 << 9)
+#define XVTC_STATUS_LOCK (1 << 8)
+
+#define XVTC_ERROR_ACTIVE_CHROMA_LOCK (1 << 21)
+#define XVTC_ERROR_ACTIVE_VIDEO_LOCK (1 << 20)
+#define XVTC_ERROR_HSYNC_LOCK (1 << 19)
+#define XVTC_ERROR_VSYNC_LOCK (1 << 18)
+#define XVTC_ERROR_HBLANK_LOCK (1 << 17)
+#define XVTC_ERROR_VBLANK_LOCK (1 << 16)
+
+#define XVTC_IRQ_ENABLE_FSYNC(n) ((n) << 16)
+#define XVTC_IRQ_ENABLE_GEN_ACTIVE_VIDEO (1 << 13)
+#define XVTC_IRQ_ENABLE_GEN_VBLANK (1 << 12)
+#define XVTC_IRQ_ENABLE_DET_ACTIVE_VIDEO (1 << 11)
+#define XVTC_IRQ_ENABLE_DET_VBLANK (1 << 10)
+#define XVTC_IRQ_ENABLE_LOCK_LOSS (1 << 9)
+#define XVTC_IRQ_ENABLE_LOCK (1 << 8)
+
+/*
+ * The following registers exist in two blocks, one at 0x0020 for the detector
+ * and one at 0x0060 for the generator.
+ */
+
+#define XVTC_DETECTOR_OFFSET 0x0020
+#define XVTC_GENERATOR_OFFSET 0x0060
+
+#define XVTC_ACTIVE_SIZE 0x0000
+#define XVTC_ACTIVE_VSIZE_SHIFT 16
+#define XVTC_ACTIVE_VSIZE_MASK (0x1fff << 16)
+#define XVTC_ACTIVE_HSIZE_SHIFT 0
+#define XVTC_ACTIVE_HSIZE_MASK (0x1fff << 0)
+
+#define XVTC_TIMING_STATUS 0x0004
+#define XVTC_TIMING_STATUS_ACTIVE_VIDEO (1 << 2)
+#define XVTC_TIMING_STATUS_VBLANK (1 << 1)
+#define XVTC_TIMING_STATUS_LOCKED (1 << 0)
+
+#define XVTC_ENCODING 0x0008
+#define XVTC_ENCODING_CHROMA_PARITY_SHIFT 8
+#define XVTC_ENCODING_CHROMA_PARITY_MASK (3 << 8)
+#define XVTC_ENCODING_CHROMA_PARITY_EVEN_ALL (0 << 8)
+#define XVTC_ENCODING_CHROMA_PARITY_ODD_ALL (1 << 8)
+#define XVTC_ENCODING_CHROMA_PARITY_EVEN_EVEN (2 << 8)
+#define XVTC_ENCODING_CHROMA_PARITY_ODD_EVEN (3 << 8)
+#define XVTC_ENCODING_VIDEO_FORMAT_SHIFT 0
+#define XVTC_ENCODING_VIDEO_FORMAT_MASK (0xf << 0)
+#define XVTC_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0)
+#define XVTC_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0)
+#define XVTC_ENCODING_VIDEO_FORMAT_RGB (2 << 0)
+#define XVTC_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0)
+
+#define XVTC_POLARITY 0x000c
+#define XVTC_POLARITY_ACTIVE_CHROMA_POL (1 << 5)
+#define XVTC_POLARITY_ACTIVE_VIDEO_POL (1 << 4)
+#define XVTC_POLARITY_HSYNC_POL (1 << 3)
+#define XVTC_POLARITY_VSYNC_POL (1 << 2)
+#define XVTC_POLARITY_HBLANK_POL (1 << 1)
+#define XVTC_POLARITY_VBLANK_POL (1 << 0)
+
+#define XVTC_HSIZE 0x0010
+#define XVTC_HSIZE_MASK (0x1fff << 0)
+
+#define XVTC_VSIZE 0x0014
+#define XVTC_VSIZE_MASK (0x1fff << 0)
+
+#define XVTC_HSYNC 0x0018
+#define XVTC_HSYNC_END_SHIFT 16
+#define XVTC_HSYNC_END_MASK (0x1fff << 16)
+#define XVTC_HSYNC_START_SHIFT 0
+#define XVTC_HSYNC_START_MASK (0x1fff << 0)
+
+#define XVTC_F0_VBLANK_H 0x001c
+#define XVTC_F0_VBLANK_HEND_SHIFT 16
+#define XVTC_F0_VBLANK_HEND_MASK (0x1fff << 16)
+#define XVTC_F0_VBLANK_HSTART_SHIFT 0
+#define XVTC_F0_VBLANK_HSTART_MASK (0x1fff << 0)
+
+#define XVTC_F0_VSYNC_V 0x0020
+#define XVTC_F0_VSYNC_VEND_SHIFT 16
+#define XVTC_F0_VSYNC_VEND_MASK (0x1fff << 16)
+#define XVTC_F0_VSYNC_VSTART_SHIFT 0
+#define XVTC_F0_VSYNC_VSTART_MASK (0x1fff << 0)
+
+#define XVTC_F0_VSYNC_H 0x0024
+#define XVTC_F0_VSYNC_HEND_SHIFT 16
+#define XVTC_F0_VSYNC_HEND_MASK (0x1fff << 16)
+#define XVTC_F0_VSYNC_HSTART_SHIFT 0
+#define XVTC_F0_VSYNC_HSTART_MASK (0x1fff << 0)
+
+#define XVTC_FRAME_SYNC_CONFIG(n) (0x0100 + 4 * (n))
+#define XVTC_FRAME_SYNC_V_START_SHIFT 16
+#define XVTC_FRAME_SYNC_V_START_MASK (0x1fff << 16)
+#define XVTC_FRAME_SYNC_H_START_SHIFT 0
+#define XVTC_FRAME_SYNC_H_START_MASK (0x1fff << 0)
+
+#define XVTC_GENERATOR_GLOBAL_DELAY 0x0104
+
+/**
+ * struct xvtc_device - Xilinx Video Timing Controller device structure
+ * @xvip: Xilinx Video IP device
+ * @list: entry in the global VTC list
+ * @has_detector: the VTC has a timing detector
+ * @has_generator: the VTC has a timing generator
+ * @config: generator timings configuration
+ */
+struct xvtc_device {
+ struct xvip_device xvip;
+ struct list_head list;
+
+ bool has_detector;
+ bool has_generator;
+
+ struct xvtc_config config;
+};
+
+static LIST_HEAD(xvtc_list);
+static DEFINE_MUTEX(xvtc_lock);
+
+static inline void xvtc_gen_write(struct xvtc_device *xvtc, u32 addr, u32 value)
+{
+ xvip_write(&xvtc->xvip, XVTC_GENERATOR_OFFSET + addr, value);
+}
+
+/* -----------------------------------------------------------------------------
+ * Generator Operations
+ */
+
+int xvtc_generator_start(struct xvtc_device *xvtc,
+ const struct xvtc_config *config)
+{
+ int ret;
+
+ if (!xvtc->has_generator)
+ return -ENXIO;
+
+ ret = clk_prepare_enable(xvtc->xvip.clk);
+ if (ret < 0)
+ return ret;
+
+ /* We don't care about the chroma active signal, encoding parameters are
+ * not important for now.
+ */
+ xvtc_gen_write(xvtc, XVTC_POLARITY,
+ XVTC_POLARITY_ACTIVE_CHROMA_POL |
+ XVTC_POLARITY_ACTIVE_VIDEO_POL |
+ XVTC_POLARITY_HSYNC_POL | XVTC_POLARITY_VSYNC_POL |
+ XVTC_POLARITY_HBLANK_POL | XVTC_POLARITY_VBLANK_POL);
+
+ /* Hardcode the polarity to active high, as required by the video in to
+ * AXI4-stream core.
+ */
+ xvtc_gen_write(xvtc, XVTC_ENCODING, 0);
+
+ /* Configure the timings. The VBLANK and VSYNC signals assertion and
+ * deassertion are hardcoded to the first pixel of the line.
+ */
+ xvtc_gen_write(xvtc, XVTC_ACTIVE_SIZE,
+ (config->vblank_start << XVTC_ACTIVE_VSIZE_SHIFT) |
+ (config->hblank_start << XVTC_ACTIVE_HSIZE_SHIFT));
+ xvtc_gen_write(xvtc, XVTC_HSIZE, config->hsize);
+ xvtc_gen_write(xvtc, XVTC_VSIZE, config->vsize);
+ xvtc_gen_write(xvtc, XVTC_HSYNC,
+ (config->hsync_end << XVTC_HSYNC_END_SHIFT) |
+ (config->hsync_start << XVTC_HSYNC_START_SHIFT));
+ xvtc_gen_write(xvtc, XVTC_F0_VBLANK_H, 0);
+ xvtc_gen_write(xvtc, XVTC_F0_VSYNC_V,
+ (config->vsync_end << XVTC_F0_VSYNC_VEND_SHIFT) |
+ (config->vsync_start << XVTC_F0_VSYNC_VSTART_SHIFT));
+ xvtc_gen_write(xvtc, XVTC_F0_VSYNC_H, 0);
+
+ /* Enable the generator. Set the source of all generator parameters to
+ * generator registers.
+ */
+ xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL,
+ XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC |
+ XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC |
+ XVTC_CONTROL_HSYNC_POL_SRC | XVTC_CONTROL_VSYNC_POL_SRC |
+ XVTC_CONTROL_HBLANK_POL_SRC | XVTC_CONTROL_VBLANK_POL_SRC |
+ XVTC_CONTROL_CHROMA_SRC | XVTC_CONTROL_VBLANK_HOFF_SRC |
+ XVTC_CONTROL_VSYNC_END_SRC | XVTC_CONTROL_VSYNC_START_SRC |
+ XVTC_CONTROL_ACTIVE_VSIZE_SRC |
+ XVTC_CONTROL_FRAME_VSIZE_SRC | XVTC_CONTROL_HSYNC_END_SRC |
+ XVTC_CONTROL_HSYNC_START_SRC |
+ XVTC_CONTROL_ACTIVE_HSIZE_SRC |
+ XVTC_CONTROL_FRAME_HSIZE_SRC | XVTC_CONTROL_GEN_ENABLE |
+ XVIP_CTRL_CONTROL_REG_UPDATE);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xvtc_generator_start);
+
+int xvtc_generator_stop(struct xvtc_device *xvtc)
+{
+ if (!xvtc->has_generator)
+ return -ENXIO;
+
+ xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, 0);
+
+ clk_disable_unprepare(xvtc->xvip.clk);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xvtc_generator_stop);
+
+struct xvtc_device *xvtc_of_get(struct device_node *np)
+{
+ struct device_node *xvtc_node;
+ struct xvtc_device *found = NULL;
+ struct xvtc_device *xvtc;
+
+ if (!of_find_property(np, "xlnx,vtc", NULL))
+ return NULL;
+
+ xvtc_node = of_parse_phandle(np, "xlnx,vtc", 0);
+ if (xvtc_node == NULL)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&xvtc_lock);
+ list_for_each_entry(xvtc, &xvtc_list, list) {
+ if (xvtc->xvip.dev->of_node == xvtc_node) {
+ found = xvtc;
+ break;
+ }
+ }
+ mutex_unlock(&xvtc_lock);
+
+ of_node_put(xvtc_node);
+
+ if (!found)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return found;
+}
+EXPORT_SYMBOL_GPL(xvtc_of_get);
+
+void xvtc_put(struct xvtc_device *xvtc)
+{
+}
+EXPORT_SYMBOL_GPL(xvtc_put);
+
+/* -----------------------------------------------------------------------------
+ * Registration and Unregistration
+ */
+
+static void xvtc_register_device(struct xvtc_device *xvtc)
+{
+ mutex_lock(&xvtc_lock);
+ list_add_tail(&xvtc->list, &xvtc_list);
+ mutex_unlock(&xvtc_lock);
+}
+
+static void xvtc_unregister_device(struct xvtc_device *xvtc)
+{
+ mutex_lock(&xvtc_lock);
+ list_del(&xvtc->list);
+ mutex_unlock(&xvtc_lock);
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xvtc_parse_of(struct xvtc_device *xvtc)
+{
+ struct device_node *node = xvtc->xvip.dev->of_node;
+
+ xvtc->has_detector = of_property_read_bool(node, "xlnx,detector");
+ xvtc->has_generator = of_property_read_bool(node, "xlnx,generator");
+
+ return 0;
+}
+
+static int xvtc_probe(struct platform_device *pdev)
+{
+ struct xvtc_device *xvtc;
+ int ret;
+
+ xvtc = devm_kzalloc(&pdev->dev, sizeof(*xvtc), GFP_KERNEL);
+ if (!xvtc)
+ return -ENOMEM;
+
+ xvtc->xvip.dev = &pdev->dev;
+
+ ret = xvtc_parse_of(xvtc);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xvtc->xvip);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, xvtc);
+
+ xvip_print_version(&xvtc->xvip);
+
+ xvtc_register_device(xvtc);
+
+ return 0;
+}
+
+static int xvtc_remove(struct platform_device *pdev)
+{
+ struct xvtc_device *xvtc = platform_get_drvdata(pdev);
+
+ xvtc_unregister_device(xvtc);
+
+ xvip_cleanup_resources(&xvtc->xvip);
+
+ return 0;
+}
+
+static const struct of_device_id xvtc_of_id_table[] = {
+ { .compatible = "xlnx,v-tc-6.1" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xvtc_of_id_table);
+
+static struct platform_driver xvtc_driver = {
+ .driver = {
+ .name = "xilinx-vtc",
+ .of_match_table = xvtc_of_id_table,
+ },
+ .probe = xvtc_probe,
+ .remove = xvtc_remove,
+};
+
+module_platform_driver(xvtc_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx Video Timing Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h
new file mode 100644
index 0000000..e1bb2cf
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vtc.h
@@ -0,0 +1,42 @@
+/*
+ * Xilinx Video Timing Controller
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_VTC_H__
+#define __XILINX_VTC_H__
+
+struct device_node;
+struct xvtc_device;
+
+#define XVTC_MAX_HSIZE 8191
+#define XVTC_MAX_VSIZE 8191
+
+struct xvtc_config {
+ unsigned int hblank_start;
+ unsigned int hsync_start;
+ unsigned int hsync_end;
+ unsigned int hsize;
+ unsigned int vblank_start;
+ unsigned int vsync_start;
+ unsigned int vsync_end;
+ unsigned int vsize;
+};
+
+struct xvtc_device *xvtc_of_get(struct device_node *np);
+void xvtc_put(struct xvtc_device *xvtc);
+
+int xvtc_generator_start(struct xvtc_device *xvtc,
+ const struct xvtc_config *config);
+int xvtc_generator_stop(struct xvtc_device *xvtc);
+
+#endif /* __XILINX_VTC_H__ */
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index b8f3644..a93f681 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -347,6 +347,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
{
struct wl1273_core *core = radio->core;
int r = 0;
+ unsigned long t;
if (freq < WL1273_BAND_TX_LOW) {
dev_err(radio->dev,
@@ -378,11 +379,11 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
reinit_completion(&radio->busy);
/* wait for the FR IRQ */
- r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
- if (!r)
+ t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!t)
return -ETIMEDOUT;
- dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r);
+ dev_dbg(radio->dev, "WL1273_CHANL_SET: %lu\n", t);
/* Enable the output power */
r = core->write(core, WL1273_POWER_ENB_SET, 1);
@@ -392,12 +393,12 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
reinit_completion(&radio->busy);
/* wait for the POWER_ENB IRQ */
- r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
- if (!r)
+ t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ if (!t)
return -ETIMEDOUT;
radio->tx_frequency = freq;
- dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r);
+ dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %lu\n", t);
return 0;
}
@@ -406,6 +407,7 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq)
{
struct wl1273_core *core = radio->core;
int r, f;
+ unsigned long t;
if (freq < radio->rangelow) {
dev_err(radio->dev,
@@ -446,8 +448,8 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq)
reinit_completion(&radio->busy);
- r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
- if (!r) {
+ t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!t) {
dev_err(radio->dev, "%s: TIMEOUT\n", __func__);
return -ETIMEDOUT;
}
@@ -826,9 +828,12 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio,
if (r)
goto out;
+ /* wait for the FR IRQ */
wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
- if (!(radio->irq_received & WL1273_BL_EVENT))
+ if (!(radio->irq_received & WL1273_BL_EVENT)) {
+ r = -ETIMEDOUT;
goto out;
+ }
radio->irq_received &= ~WL1273_BL_EVENT;
@@ -854,7 +859,9 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio,
if (r)
goto out;
- wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ /* wait for the FR IRQ */
+ if (!wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)))
+ r = -ETIMEDOUT;
out:
dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r);
return r;
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 909c3f9..1d827ad 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -208,6 +208,7 @@ static int si470x_set_band(struct si470x_device *radio, int band)
static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
{
int retval;
+ unsigned long time_left;
bool timed_out = false;
/* start tuning */
@@ -219,9 +220,9 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
/* wait till tune operation has completed */
reinit_completion(&radio->completion);
- retval = wait_for_completion_timeout(&radio->completion,
- msecs_to_jiffies(tune_timeout));
- if (!retval)
+ time_left = wait_for_completion_timeout(&radio->completion,
+ msecs_to_jiffies(tune_timeout));
+ if (time_left == 0)
timed_out = true;
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
@@ -301,6 +302,7 @@ static int si470x_set_seek(struct si470x_device *radio,
int band, retval;
unsigned int freq;
bool timed_out = false;
+ unsigned long time_left;
/* set band */
if (seek->rangelow || seek->rangehigh) {
@@ -342,9 +344,9 @@ static int si470x_set_seek(struct si470x_device *radio,
/* wait till tune operation has completed */
reinit_completion(&radio->completion);
- retval = wait_for_completion_timeout(&radio->completion,
- msecs_to_jiffies(seek_timeout));
- if (!retval)
+ time_left = wait_for_completion_timeout(&radio->completion,
+ msecs_to_jiffies(seek_timeout));
+ if (time_left == 0)
timed_out = true;
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index c90004d..e9d03ac 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -383,7 +383,7 @@ static int si4713_powerup(struct si4713_device *sdev)
}
}
- if (!IS_ERR(sdev->gpio_reset)) {
+ if (sdev->gpio_reset) {
udelay(50);
gpiod_set_value(sdev->gpio_reset, 1);
}
@@ -407,8 +407,7 @@ static int si4713_powerup(struct si4713_device *sdev)
SI4713_STC_INT | SI4713_CTS);
return err;
}
- if (!IS_ERR(sdev->gpio_reset))
- gpiod_set_value(sdev->gpio_reset, 0);
+ gpiod_set_value(sdev->gpio_reset, 0);
if (sdev->vdd) {
@@ -447,7 +446,7 @@ static int si4713_powerdown(struct si4713_device *sdev)
v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
resp[0]);
v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
- if (!IS_ERR(sdev->gpio_reset))
+ if (sdev->gpio_reset)
gpiod_set_value(sdev->gpio_reset, 0);
if (sdev->vdd) {
@@ -1460,14 +1459,9 @@ static int si4713_probe(struct i2c_client *client,
goto exit;
}
- sdev->gpio_reset = devm_gpiod_get(&client->dev, "reset");
- if (!IS_ERR(sdev->gpio_reset)) {
- gpiod_direction_output(sdev->gpio_reset, 0);
- } else if (PTR_ERR(sdev->gpio_reset) == -ENOENT) {
- dev_dbg(&client->dev, "No reset GPIO assigned\n");
- } else if (PTR_ERR(sdev->gpio_reset) == -ENOSYS) {
- dev_dbg(&client->dev, "No reset GPIO support\n");
- } else {
+ sdev->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(sdev->gpio_reset)) {
rval = PTR_ERR(sdev->gpio_reset);
dev_err(&client->dev, "Failed to request gpio: %d\n", rval);
goto exit;
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
index f359be7..9d6574b 100644
--- a/drivers/media/radio/wl128x/Kconfig
+++ b/drivers/media/radio/wl128x/Kconfig
@@ -5,7 +5,7 @@ menu "Texas Instruments WL128x FM driver (ST based)"
config RADIO_WL128X
tristate "Texas Instruments WL128x FM Radio"
depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY
- select TI_ST if NET
+ depends on TI_ST
help
Choose Y here if you have this FM radio chip.
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index a5bd3f6..fb42f0f 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -36,7 +36,7 @@
#include "fmdrv_rx.h"
#include "fmdrv_tx.h"
-static struct video_device *gradio_dev;
+static struct video_device gradio_dev;
static u8 radio_disconnected;
/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
@@ -517,7 +517,7 @@ static struct video_device fm_viddev_template = {
.fops = &fm_drv_fops,
.ioctl_ops = &fm_drv_ioctl_ops,
.name = FM_DRV_NAME,
- .release = video_device_release,
+ .release = video_device_release_empty,
/*
* To ensure both the tuner and modulator ioctls are accessible we
* set the vfl_dir to M2M to indicate this.
@@ -543,29 +543,21 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
/* Init mutex for core locking */
mutex_init(&fmdev->mutex);
- /* Allocate new video device */
- gradio_dev = video_device_alloc();
- if (NULL == gradio_dev) {
- fmerr("Can't allocate video device\n");
- return -ENOMEM;
- }
-
/* Setup FM driver's V4L2 properties */
- memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template));
+ gradio_dev = fm_viddev_template;
- video_set_drvdata(gradio_dev, fmdev);
+ video_set_drvdata(&gradio_dev, fmdev);
- gradio_dev->lock = &fmdev->mutex;
- gradio_dev->v4l2_dev = &fmdev->v4l2_dev;
+ gradio_dev.lock = &fmdev->mutex;
+ gradio_dev.v4l2_dev = &fmdev->v4l2_dev;
/* Register with V4L2 subsystem as RADIO device */
- if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
- video_device_release(gradio_dev);
+ if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
fmerr("Could not register video device\n");
return -ENOMEM;
}
- fmdev->radio_dev = gradio_dev;
+ fmdev->radio_dev = &gradio_dev;
/* Register to v4l2 ctrl handler framework */
fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler;
@@ -611,13 +603,13 @@ void *fm_v4l2_deinit_video_device(void)
struct fmdev *fmdev;
- fmdev = video_get_drvdata(gradio_dev);
+ fmdev = video_get_drvdata(&gradio_dev);
/* Unregister to v4l2 ctrl handler framework*/
v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
/* Unregister RADIO device from V4L2 subsystem */
- video_unregister_device(gradio_dev);
+ video_unregister_device(&gradio_dev);
v4l2_device_unregister(&fmdev->v4l2_dev);
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
index 77c78de..03fe080 100644
--- a/drivers/media/rc/img-ir/img-ir-core.c
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -110,16 +110,32 @@ static int img_ir_probe(struct platform_device *pdev)
priv->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(priv->clk))
dev_warn(&pdev->dev, "cannot get core clock resource\n");
+
+ /* Get sys clock */
+ priv->sys_clk = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(priv->sys_clk))
+ dev_warn(&pdev->dev, "cannot get sys clock resource\n");
/*
- * The driver doesn't need to know about the system ("sys") or power
- * modulation ("mod") clocks yet
+ * Enabling the system clock before the register interface is
+ * accessed. ISR shouldn't get called with Sys Clock disabled,
+ * hence exiting probe with an error.
*/
+ if (!IS_ERR(priv->sys_clk)) {
+ error = clk_prepare_enable(priv->sys_clk);
+ if (error) {
+ dev_err(&pdev->dev, "cannot enable sys clock\n");
+ return error;
+ }
+ }
/* Set up raw & hw decoder */
error = img_ir_probe_raw(priv);
error2 = img_ir_probe_hw(priv);
- if (error && error2)
- return (error == -ENODEV) ? error2 : error;
+ if (error && error2) {
+ if (error == -ENODEV)
+ error = error2;
+ goto err_probe;
+ }
/* Get the IRQ */
priv->irq = irq;
@@ -139,6 +155,9 @@ static int img_ir_probe(struct platform_device *pdev)
err_irq:
img_ir_remove_hw(priv);
img_ir_remove_raw(priv);
+err_probe:
+ if (!IS_ERR(priv->sys_clk))
+ clk_disable_unprepare(priv->sys_clk);
return error;
}
@@ -146,12 +165,14 @@ static int img_ir_remove(struct platform_device *pdev)
{
struct img_ir_priv *priv = platform_get_drvdata(pdev);
- free_irq(priv->irq, img_ir_isr);
+ free_irq(priv->irq, priv);
img_ir_remove_hw(priv);
img_ir_remove_raw(priv);
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
+ if (!IS_ERR(priv->sys_clk))
+ clk_disable_unprepare(priv->sys_clk);
return 0;
}
diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h
index 2ddf560..f1387c0 100644
--- a/drivers/media/rc/img-ir/img-ir.h
+++ b/drivers/media/rc/img-ir/img-ir.h
@@ -138,6 +138,7 @@ struct clk;
* @dev: Platform device.
* @irq: IRQ number.
* @clk: Input clock.
+ * @sys_clk: System clock.
* @reg_base: Iomem base address of IR register block.
* @lock: Protects IR registers and variables in this struct.
* @raw: Driver data for raw decoder.
@@ -147,6 +148,7 @@ struct img_ir_priv {
struct device *dev;
int irq;
struct clk *clk;
+ struct clk *sys_clk;
void __iomem *reg_base;
spinlock_t lock;
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index b0df629..58ec598 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -16,14 +16,6 @@
#include <linux/regmap.h>
#include <media/rc-core.h>
-/* Allow the driver to compile on all architectures */
-#ifndef writel_relaxed
-# define writel_relaxed writel
-#endif
-#ifndef readl_relaxed
-# define readl_relaxed readl
-#endif
-
#define IR_ENABLE 0x00
#define IR_CONFIG 0x04
#define CNT_LEADS 0x08
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 42e5a01..983510d 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -224,14 +224,6 @@ config MEDIA_TUNER_FC2580
help
FCI FC2580 silicon tuner driver.
-config MEDIA_TUNER_M88TS2022
- tristate "Montage M88TS2022 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- select REGMAP_I2C
- default m if !MEDIA_SUBDRV_AUTOSELECT
- help
- Montage M88TS2022 silicon tuner driver.
-
config MEDIA_TUNER_M88RS6000T
tristate "Montage M88RS6000 internal tuner"
depends on MEDIA_SUPPORT && I2C
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index da4fe6e..06a9ab6 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -33,7 +33,6 @@ obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o
obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o
obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
obj-$(CONFIG_MEDIA_TUNER_SI2157) += si2157.o
-obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o
obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h
index 43ec893..81bb568 100644
--- a/drivers/media/tuners/fc0011.h
+++ b/drivers/media/tuners/fc0011.h
@@ -23,7 +23,7 @@ enum fc0011_fe_callback_commands {
FC0011_FE_CALLBACK_RESET,
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0011)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0011)
struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct fc0011_config *config);
diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h
index 1d08057..9ad3285 100644
--- a/drivers/media/tuners/fc0012.h
+++ b/drivers/media/tuners/fc0012.h
@@ -49,7 +49,7 @@ struct fc0012_config {
bool clock_out;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0012)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0012)
extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct fc0012_config *cfg);
diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h
index d65d5b3..e130bd7 100644
--- a/drivers/media/tuners/fc0013.h
+++ b/drivers/media/tuners/fc0013.h
@@ -26,7 +26,7 @@
#include "dvb_frontend.h"
#include "fc001x-common.h"
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0013)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0013)
extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
u8 i2c_address, int dual_master,
diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h
index 9c43c1c..b1ce677 100644
--- a/drivers/media/tuners/fc2580.h
+++ b/drivers/media/tuners/fc2580.h
@@ -37,7 +37,7 @@ struct fc2580_config {
u32 clock;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC2580)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC2580)
extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct fc2580_config *cfg);
#else
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c
deleted file mode 100644
index 066e543..0000000
--- a/drivers/media/tuners/m88ts2022.c
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Montage M88TS2022 silicon tuner driver
- *
- * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Some calculations are taken from existing TS2020 driver.
- */
-
-#include "m88ts2022_priv.h"
-
-static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg,
- u8 mask, u8 val, u8 *reg_val)
-{
- int ret, i;
- unsigned int utmp;
- struct m88ts2022_reg_val reg_vals[] = {
- {0x51, 0x1f - op},
- {0x51, 0x1f},
- {0x50, 0x00 + op},
- {0x50, 0x00},
- };
-
- for (i = 0; i < 2; i++) {
- dev_dbg(&dev->client->dev,
- "i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
- i, op, reg, mask, val);
-
- for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
- ret = regmap_write(dev->regmap, reg_vals[i].reg,
- reg_vals[i].val);
- if (ret)
- goto err;
- }
-
- usleep_range(sleep * 1000, sleep * 10000);
-
- ret = regmap_read(dev->regmap, reg, &utmp);
- if (ret)
- goto err;
-
- if ((utmp & mask) != val)
- break;
- }
-
- if (reg_val)
- *reg_val = utmp;
-err:
- return ret;
-}
-
-static int m88ts2022_set_params(struct dvb_frontend *fe)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret;
- unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz;
- unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28;
- u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min;
- u16 u16tmp;
-
- dev_dbg(&dev->client->dev,
- "frequency=%d symbol_rate=%d rolloff=%d\n",
- c->frequency, c->symbol_rate, c->rolloff);
- /*
- * Integer-N PLL synthesizer
- * kHz is used for all calculations to keep calculations within 32-bit
- */
- f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000);
- div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
-
- if (c->symbol_rate < 5000000)
- frequency_offset_khz = 3000; /* 3 MHz */
- else
- frequency_offset_khz = 0;
-
- frequency_khz = c->frequency + frequency_offset_khz;
-
- if (frequency_khz < 1103000) {
- div_out = 4;
- u8tmp = 0x1b;
- } else {
- div_out = 2;
- u8tmp = 0x0b;
- }
-
- buf[0] = u8tmp;
- buf[1] = 0x40;
- ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2);
- if (ret)
- goto err;
-
- f_vco_khz = frequency_khz * div_out;
- pll_n = f_vco_khz * div_ref / f_ref_khz;
- pll_n += pll_n % 2;
- dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
-
- if (pll_n < 4095)
- u16tmp = pll_n - 1024;
- else if (pll_n < 6143)
- u16tmp = pll_n + 1024;
- else
- u16tmp = pll_n + 3072;
-
- buf[0] = (u16tmp >> 8) & 0x3f;
- buf[1] = (u16tmp >> 0) & 0xff;
- buf[2] = div_ref - 8;
- ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3);
- if (ret)
- goto err;
-
- dev_dbg(&dev->client->dev,
- "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
- dev->frequency_khz, dev->frequency_khz - c->frequency,
- f_vco_khz, pll_n, div_ref, div_out);
-
- ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
- if (ret)
- goto err;
-
- ret = regmap_read(dev->regmap, 0x14, &utmp);
- if (ret)
- goto err;
-
- utmp &= 0x7f;
- if (utmp < 64) {
- ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x11, 0x6f);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
- if (ret)
- goto err;
- }
-
- ret = regmap_read(dev->regmap, 0x14, &utmp);
- if (ret)
- goto err;
-
- utmp &= 0x1f;
- if (utmp > 19) {
- ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00);
- if (ret)
- goto err;
- }
-
- ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x25, 0x00);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x27, 0x70);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x41, 0x09);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x08, 0x0b);
- if (ret)
- goto err;
-
- /* filters */
- gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U);
-
- ret = regmap_write(dev->regmap, 0x04, gdiv28);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
- if (ret)
- goto err;
-
- cap_code = u8tmp & 0x3f;
-
- ret = regmap_write(dev->regmap, 0x41, 0x0d);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
- if (ret)
- goto err;
-
- u8tmp &= 0x3f;
- cap_code = (cap_code + u8tmp) / 2;
- gdiv28 = gdiv28 * 207 / (cap_code * 2 + 151);
- div_max = gdiv28 * 135 / 100;
- div_min = gdiv28 * 78 / 100;
- div_max = clamp_val(div_max, 0U, 63U);
-
- f_3db_hz = mult_frac(c->symbol_rate, 135, 200);
- f_3db_hz += 2000000U + (frequency_offset_khz * 1000U);
- f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U);
-
-#define LPF_COEFF 3200U
- lpf_gm = DIV_ROUND_CLOSEST(f_3db_hz * gdiv28, LPF_COEFF * f_ref_khz);
- lpf_gm = clamp_val(lpf_gm, 1U, 23U);
-
- lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
- if (lpf_mxdiv < div_min)
- lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
- lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max);
-
- ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x06, lpf_gm);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
- if (ret)
- goto err;
-
- cap_code = u8tmp & 0x3f;
-
- ret = regmap_write(dev->regmap, 0x41, 0x09);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
- if (ret)
- goto err;
-
- u8tmp &= 0x3f;
- cap_code = (cap_code + u8tmp) / 2;
-
- u8tmp = cap_code | 0x80;
- ret = regmap_write(dev->regmap, 0x25, u8tmp);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x27, 0x30);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x08, 0x09);
- if (ret)
- goto err;
-
- ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL);
- if (ret)
- goto err;
-err:
- if (ret)
- dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
- return ret;
-}
-
-static int m88ts2022_init(struct dvb_frontend *fe)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
- int ret, i;
- u8 u8tmp;
- static const struct m88ts2022_reg_val reg_vals[] = {
- {0x7d, 0x9d},
- {0x7c, 0x9a},
- {0x7a, 0x76},
- {0x3b, 0x01},
- {0x63, 0x88},
- {0x61, 0x85},
- {0x22, 0x30},
- {0x30, 0x40},
- {0x20, 0x23},
- {0x24, 0x02},
- {0x12, 0xa0},
- };
-
- dev_dbg(&dev->client->dev, "\n");
-
- ret = regmap_write(dev->regmap, 0x00, 0x01);
- if (ret)
- goto err;
-
- ret = regmap_write(dev->regmap, 0x00, 0x03);
- if (ret)
- goto err;
-
- switch (dev->cfg.clock_out) {
- case M88TS2022_CLOCK_OUT_DISABLED:
- u8tmp = 0x60;
- break;
- case M88TS2022_CLOCK_OUT_ENABLED:
- u8tmp = 0x70;
- ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
- if (ret)
- goto err;
- break;
- case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
- u8tmp = 0x6c;
- break;
- default:
- goto err;
- }
-
- ret = regmap_write(dev->regmap, 0x42, u8tmp);
- if (ret)
- goto err;
-
- if (dev->cfg.loop_through)
- u8tmp = 0xec;
- else
- u8tmp = 0x6c;
-
- ret = regmap_write(dev->regmap, 0x62, u8tmp);
- if (ret)
- goto err;
-
- for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
- ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val);
- if (ret)
- goto err;
- }
-err:
- if (ret)
- dev_dbg(&dev->client->dev, "failed=%d\n", ret);
- return ret;
-}
-
-static int m88ts2022_sleep(struct dvb_frontend *fe)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
- int ret;
-
- dev_dbg(&dev->client->dev, "\n");
-
- ret = regmap_write(dev->regmap, 0x00, 0x00);
- if (ret)
- goto err;
-err:
- if (ret)
- dev_dbg(&dev->client->dev, "failed=%d\n", ret);
- return ret;
-}
-
-static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
-
- dev_dbg(&dev->client->dev, "\n");
-
- *frequency = dev->frequency_khz;
- return 0;
-}
-
-static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
-
- dev_dbg(&dev->client->dev, "\n");
-
- *frequency = 0; /* Zero-IF */
- return 0;
-}
-
-static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct m88ts2022_dev *dev = fe->tuner_priv;
- int ret;
- u16 gain, u16tmp;
- unsigned int utmp, gain1, gain2, gain3;
-
- ret = regmap_read(dev->regmap, 0x3d, &utmp);
- if (ret)
- goto err;
-
- gain1 = (utmp >> 0) & 0x1f;
- gain1 = clamp(gain1, 0U, 15U);
-
- ret = regmap_read(dev->regmap, 0x21, &utmp);
- if (ret)
- goto err;
-
- gain2 = (utmp >> 0) & 0x1f;
- gain2 = clamp(gain2, 2U, 16U);
-
- ret = regmap_read(dev->regmap, 0x66, &utmp);
- if (ret)
- goto err;
-
- gain3 = (utmp >> 3) & 0x07;
- gain3 = clamp(gain3, 0U, 6U);
-
- gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
-
- /* scale value to 0x0000-0xffff */
- u16tmp = (0xffff - gain);
- u16tmp = clamp_val(u16tmp, 59000U, 61500U);
-
- *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
-err:
- if (ret)
- dev_dbg(&dev->client->dev, "failed=%d\n", ret);
- return ret;
-}
-
-static const struct dvb_tuner_ops m88ts2022_tuner_ops = {
- .info = {
- .name = "Montage M88TS2022",
- .frequency_min = 950000,
- .frequency_max = 2150000,
- },
-
- .init = m88ts2022_init,
- .sleep = m88ts2022_sleep,
- .set_params = m88ts2022_set_params,
-
- .get_frequency = m88ts2022_get_frequency,
- .get_if_frequency = m88ts2022_get_if_frequency,
- .get_rf_strength = m88ts2022_get_rf_strength,
-};
-
-static int m88ts2022_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct m88ts2022_config *cfg = client->dev.platform_data;
- struct dvb_frontend *fe = cfg->fe;
- struct m88ts2022_dev *dev;
- int ret;
- u8 u8tmp;
- unsigned int utmp;
- static const struct regmap_config regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- };
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- ret = -ENOMEM;
- dev_err(&client->dev, "kzalloc() failed\n");
- goto err;
- }
-
- memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config));
- dev->client = client;
- dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(dev->regmap)) {
- ret = PTR_ERR(dev->regmap);
- goto err;
- }
-
- /* check if the tuner is there */
- ret = regmap_read(dev->regmap, 0x00, &utmp);
- if (ret)
- goto err;
-
- if ((utmp & 0x03) == 0x00) {
- ret = regmap_write(dev->regmap, 0x00, 0x01);
- if (ret)
- goto err;
-
- usleep_range(2000, 50000);
- }
-
- ret = regmap_write(dev->regmap, 0x00, 0x03);
- if (ret)
- goto err;
-
- usleep_range(2000, 50000);
-
- ret = regmap_read(dev->regmap, 0x00, &utmp);
- if (ret)
- goto err;
-
- dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp);
-
- switch (utmp) {
- case 0xc3:
- case 0x83:
- break;
- default:
- ret = -ENODEV;
- goto err;
- }
-
- switch (dev->cfg.clock_out) {
- case M88TS2022_CLOCK_OUT_DISABLED:
- u8tmp = 0x60;
- break;
- case M88TS2022_CLOCK_OUT_ENABLED:
- u8tmp = 0x70;
- ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
- if (ret)
- goto err;
- break;
- case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
- u8tmp = 0x6c;
- break;
- default:
- ret = -EINVAL;
- goto err;
- }
-
- ret = regmap_write(dev->regmap, 0x42, u8tmp);
- if (ret)
- goto err;
-
- if (dev->cfg.loop_through)
- u8tmp = 0xec;
- else
- u8tmp = 0x6c;
-
- ret = regmap_write(dev->regmap, 0x62, u8tmp);
- if (ret)
- goto err;
-
- /* sleep */
- ret = regmap_write(dev->regmap, 0x00, 0x00);
- if (ret)
- goto err;
-
- dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n");
-
- fe->tuner_priv = dev;
- memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- i2c_set_clientdata(client, dev);
- return 0;
-err:
- dev_dbg(&client->dev, "failed=%d\n", ret);
- kfree(dev);
- return ret;
-}
-
-static int m88ts2022_remove(struct i2c_client *client)
-{
- struct m88ts2022_dev *dev = i2c_get_clientdata(client);
- struct dvb_frontend *fe = dev->cfg.fe;
-
- dev_dbg(&client->dev, "\n");
-
- memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
- fe->tuner_priv = NULL;
- kfree(dev);
-
- return 0;
-}
-
-static const struct i2c_device_id m88ts2022_id[] = {
- {"m88ts2022", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, m88ts2022_id);
-
-static struct i2c_driver m88ts2022_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "m88ts2022",
- },
- .probe = m88ts2022_probe,
- .remove = m88ts2022_remove,
- .id_table = m88ts2022_id,
-};
-
-module_i2c_driver(m88ts2022_driver);
-
-MODULE_DESCRIPTION("Montage M88TS2022 silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/m88ts2022.h b/drivers/media/tuners/m88ts2022.h
deleted file mode 100644
index 659fa1b..0000000
--- a/drivers/media/tuners/m88ts2022.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Montage M88TS2022 silicon tuner driver
- *
- * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef M88TS2022_H
-#define M88TS2022_H
-
-#include "dvb_frontend.h"
-
-struct m88ts2022_config {
- /*
- * clock
- * 16000000 - 32000000
- */
- u32 clock;
-
- /*
- * RF loop-through
- */
- u8 loop_through:1;
-
- /*
- * clock output
- */
-#define M88TS2022_CLOCK_OUT_DISABLED 0
-#define M88TS2022_CLOCK_OUT_ENABLED 1
-#define M88TS2022_CLOCK_OUT_ENABLED_XTALOUT 2
- u8 clock_out:2;
-
- /*
- * clock output divider
- * 1 - 31
- */
- u8 clock_out_div:5;
-
- /*
- * pointer to DVB frontend
- */
- struct dvb_frontend *fe;
-};
-
-#endif
diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h
deleted file mode 100644
index feeb5ad..0000000
--- a/drivers/media/tuners/m88ts2022_priv.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Montage M88TS2022 silicon tuner driver
- *
- * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef M88TS2022_PRIV_H
-#define M88TS2022_PRIV_H
-
-#include "m88ts2022.h"
-#include <linux/regmap.h>
-
-struct m88ts2022_dev {
- struct m88ts2022_config cfg;
- struct i2c_client *client;
- struct regmap *regmap;
- u32 frequency_khz;
-};
-
-struct m88ts2022_reg_val {
- u8 reg;
- u8 val;
-};
-
-#endif
diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h
index 26e1dc6..5054f01 100644
--- a/drivers/media/tuners/max2165.h
+++ b/drivers/media/tuners/max2165.h
@@ -32,7 +32,7 @@ struct max2165_config {
u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MAX2165)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MAX2165)
extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct max2165_config *cfg);
diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h
index 9aae50a..b3e614b 100644
--- a/drivers/media/tuners/mc44s803.h
+++ b/drivers/media/tuners/mc44s803.h
@@ -32,7 +32,7 @@ struct mc44s803_config {
u8 dig_out;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MC44S803)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MC44S803)
extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct mc44s803_config *cfg);
#else
diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h
index c64fc19..6efed35 100644
--- a/drivers/media/tuners/mt2060.h
+++ b/drivers/media/tuners/mt2060.h
@@ -30,7 +30,7 @@ struct mt2060_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2060)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2060)
extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
#else
static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h
index e1acfc8..e55e0a6 100644
--- a/drivers/media/tuners/mt2063.h
+++ b/drivers/media/tuners/mt2063.h
@@ -8,7 +8,7 @@ struct mt2063_config {
u32 refclock;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2063)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2063)
struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
struct mt2063_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h
index f56241c..9912362 100644
--- a/drivers/media/tuners/mt20xx.h
+++ b/drivers/media/tuners/mt20xx.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT20XX)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT20XX)
extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h
index 837c854..8267a6a 100644
--- a/drivers/media/tuners/mt2131.h
+++ b/drivers/media/tuners/mt2131.h
@@ -30,7 +30,7 @@ struct mt2131_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2131)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2131)
extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mt2131_config *cfg,
diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h
index fad6dd6..69abefa 100644
--- a/drivers/media/tuners/mt2266.h
+++ b/drivers/media/tuners/mt2266.h
@@ -24,7 +24,7 @@ struct mt2266_config {
u8 i2c_address;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2266)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2266)
extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
#else
static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h
index ae8db88..5764b12 100644
--- a/drivers/media/tuners/mxl5005s.h
+++ b/drivers/media/tuners/mxl5005s.h
@@ -118,7 +118,7 @@ struct mxl5005s_config {
u8 AgcMasterByte;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5005S)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5005S)
extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mxl5005s_config *config);
diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h
index ae7037d..e786d1f 100644
--- a/drivers/media/tuners/mxl5007t.h
+++ b/drivers/media/tuners/mxl5007t.h
@@ -77,7 +77,7 @@ struct mxl5007t_config {
unsigned int clk_out_enable:1;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5007T)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5007T)
extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 addr,
struct mxl5007t_config *cfg);
diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h
index 8ab5d47..e3198f2 100644
--- a/drivers/media/tuners/qt1010.h
+++ b/drivers/media/tuners/qt1010.h
@@ -36,7 +36,7 @@ struct qt1010_config {
* @param cfg tuner hw based configuration
* @return fe pointer on success, NULL on failure
*/
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_QT1010)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_QT1010)
extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct qt1010_config *cfg);
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index 8e040cf..71159a5 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -775,6 +775,19 @@ static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq,
div_buf_cur = 0x30; /* 11, 150u */
filter_cur = 0x40; /* 10, low */
break;
+ case SYS_DVBC_ANNEX_A:
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5;
+ lna_vth_l = 0x62;
+ mixer_vth_l = 0x75;
+ air_cable1_in = 0x60;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
default: /* DVB-T 8M */
mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
@@ -957,7 +970,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv,
ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
loop_through = 0x00; /* r5[7], lt on */
lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ flt_ext_widest = 0x80; /* r15[7]: flt_ext_wide on */
polyfil_cur = 0x60; /* r25[6:5]:min */
} else if (delsys == SYS_DVBC_ANNEX_A) {
if_khz = 5070;
@@ -971,6 +984,18 @@ static int r820t_set_tv_standard(struct r820t_priv *priv,
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else if (delsys == SYS_DVBC_ANNEX_C) {
+ if_khz = 4063;
+ filt_cal_lo = 55000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6a; /* 1.7m disable, +0cap, 1.0mhz */
+ ext_enable = 0x40; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x80; /* r15[7]: flt_ext_wide on */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
} else {
if (bw <= 6) {
if_khz = 3570;
@@ -1186,7 +1211,7 @@ static int r820t_read_gain(struct r820t_priv *priv)
if (rc < 0)
return rc;
- return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4);
+ return ((data[3] & 0x08) << 1) + ((data[3] & 0xf0) >> 4);
}
#if 0
diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h
index 48af354..b1e5661 100644
--- a/drivers/media/tuners/r820t.h
+++ b/drivers/media/tuners/r820t.h
@@ -42,7 +42,7 @@ struct r820t_config {
bool use_predetect;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_R820T)
struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct r820t_config *cfg);
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index fcf139d..d74ae26 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -244,6 +244,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
int ret;
struct si2157_cmd cmd;
u8 bandwidth, delivery_system;
+ u32 if_frequency = 5000000;
dev_dbg(&client->dev,
"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
@@ -266,9 +267,11 @@ static int si2157_set_params(struct dvb_frontend *fe)
switch (c->delivery_system) {
case SYS_ATSC:
delivery_system = 0x00;
+ if_frequency = 3250000;
break;
case SYS_DVBC_ANNEX_B:
delivery_system = 0x10;
+ if_frequency = 4000000;
break;
case SYS_DVBT:
case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
@@ -302,6 +305,20 @@ static int si2157_set_params(struct dvb_frontend *fe)
if (ret)
goto err;
+ /* set if frequency if needed */
+ if (if_frequency != dev->if_frequency) {
+ memcpy(cmd.args, "\x14\x00\x06\x07", 4);
+ cmd.args[4] = (if_frequency / 1000) & 0xff;
+ cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ ret = si2157_cmd_execute(client, &cmd);
+ if (ret)
+ goto err;
+
+ dev->if_frequency = if_frequency;
+ }
+
/* set frequency */
memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
cmd.args[4] = (c->frequency >> 0) & 0xff;
@@ -322,14 +339,17 @@ err:
static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- *frequency = 5000000; /* default value of property 0x0706 */
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+
+ *frequency = dev->if_frequency;
return 0;
}
static const struct dvb_tuner_ops si2157_ops = {
.info = {
.name = "Silicon Labs Si2146/2147/2148/2157/2158",
- .frequency_min = 110000000,
+ .frequency_min = 55000000,
.frequency_max = 862000000,
},
@@ -360,6 +380,7 @@ static int si2157_probe(struct i2c_client *client,
dev->inversion = cfg->inversion;
dev->fw_loaded = false;
dev->chiptype = (u8)id->driver_data;
+ dev->if_frequency = 5000000; /* default value of property 0x0706 */
mutex_init(&dev->i2c_mutex);
/* check if the tuner is there */
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 7aa53bc..cd8fa5b 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -28,6 +28,7 @@ struct si2157_dev {
bool fw_loaded;
bool inversion;
u8 chiptype;
+ u32 if_frequency;
};
#define SI2157_CHIPTYPE_SI2157 0
diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h
index 366410e..1eacb4f 100644
--- a/drivers/media/tuners/tda18218.h
+++ b/drivers/media/tuners/tda18218.h
@@ -30,7 +30,7 @@ struct tda18218_config {
u8 loop_through:1;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18218)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18218)
extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg);
#else
diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h
index 4c418d6..0a84633 100644
--- a/drivers/media/tuners/tda18271.h
+++ b/drivers/media/tuners/tda18271.h
@@ -121,7 +121,7 @@ enum tda18271_mode {
TDA18271_DIGITAL,
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18271)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18271)
extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct i2c_adapter *i2c,
struct tda18271_config *cfg);
diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h
index b642921..abf2e2f 100644
--- a/drivers/media/tuners/tda827x.h
+++ b/drivers/media/tuners/tda827x.h
@@ -51,7 +51,7 @@ struct tda827x_config
* @param cfg optional callback function pointers.
* @return FE pointer on success, NULL on failure.
*/
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA827X)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA827X)
extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
struct tda827x_config *cfg);
diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h
index cf96e58..901b8ca 100644
--- a/drivers/media/tuners/tda8290.h
+++ b/drivers/media/tuners/tda8290.h
@@ -38,7 +38,7 @@ struct tda829x_config {
struct tda18271_std_map *tda18271_std_map;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA8290)
extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h
index 37a4a11..95070ec 100644
--- a/drivers/media/tuners/tda9887.h
+++ b/drivers/media/tuners/tda9887.h
@@ -21,7 +21,7 @@
#include "dvb_frontend.h"
/* ------------------------------------------------------------------------ */
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA9887)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA9887)
extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h
index 933228f..2d624d9 100644
--- a/drivers/media/tuners/tea5761.h
+++ b/drivers/media/tuners/tea5761.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5761)
extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h
index c391011..4f6f6c9 100644
--- a/drivers/media/tuners/tea5767.h
+++ b/drivers/media/tuners/tea5767.h
@@ -39,7 +39,7 @@ struct tea5767_ctrl {
enum tea5767_xtal xtal_freq;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5767)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5767)
extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h
index 26358da..2c3375c 100644
--- a/drivers/media/tuners/tua9001.h
+++ b/drivers/media/tuners/tua9001.h
@@ -51,7 +51,7 @@ struct tua9001_config {
#define TUA9001_CMD_RESETN 1
#define TUA9001_CMD_RXEN 2
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TUA9001)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TUA9001)
extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tua9001_config *cfg);
#else
diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h
index ffd12cf..6399b45 100644
--- a/drivers/media/tuners/tuner-simple.h
+++ b/drivers/media/tuners/tuner-simple.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_SIMPLE)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SIMPLE)
extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h
index 181d087..98e4eff 100644
--- a/drivers/media/tuners/tuner-xc2028.h
+++ b/drivers/media/tuners/tuner-xc2028.h
@@ -56,7 +56,7 @@ struct xc2028_config {
#define XC2028_RESET_CLK 1
#define XC2028_I2C_FLUSH 2
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC2028)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC2028)
extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg);
#else
diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h
index 97c23de..4051786 100644
--- a/drivers/media/tuners/xc4000.h
+++ b/drivers/media/tuners/xc4000.h
@@ -50,7 +50,7 @@ struct xc4000_config {
* it's passed back to a bridge during tuner_callback().
*/
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC4000)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC4000)
extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc4000_config *cfg);
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index 2a039de..e6e5e90 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -1336,7 +1336,10 @@ static int xc5000_release(struct dvb_frontend *fe)
if (priv) {
cancel_delayed_work(&priv->timer_sleep);
- release_firmware(priv->firmware);
+ if (priv->firmware) {
+ release_firmware(priv->firmware);
+ priv->firmware = NULL;
+ }
hybrid_tuner_release_state(priv);
}
diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h
index 6aa534f..00ba29e 100644
--- a/drivers/media/tuners/xc5000.h
+++ b/drivers/media/tuners/xc5000.h
@@ -58,7 +58,7 @@ struct xc5000_config {
* it's passed back to a bridge during tuner_callback().
*/
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC5000)
+#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC5000)
extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct xc5000_config *cfg);
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index a27cb5f..1a362a0 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -299,29 +299,23 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
* Announces that a buffer were filled and request the next
*/
static inline void buffer_filled(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf)
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
{
- /* Advice that buffer was filled */
- au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
+ struct vb2_buffer *vb = &buf->vb;
+ struct vb2_queue *q = vb->vb2_queue;
- buf->vb.v4l2_buf.sequence = dev->frame_count++;
- buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
- v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
-}
-
-static inline void vbi_buffer_filled(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf)
-{
/* Advice that buffer was filled */
au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- buf->vb.v4l2_buf.sequence = dev->vbi_frame_count++;
- buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
- v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ vb->v4l2_buf.sequence = dev->frame_count++;
+ else
+ vb->v4l2_buf.sequence = dev->vbi_frame_count++;
+
+ vb->v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
/*
@@ -574,9 +568,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (fbyte & 0x40) {
/* VBI */
if (vbi_buf != NULL)
- vbi_buffer_filled(dev,
- vbi_dma_q,
- vbi_buf);
+ buffer_filled(dev, vbi_dma_q, vbi_buf);
vbi_get_next_buf(vbi_dma_q, &vbi_buf);
if (vbi_buf == NULL)
vbioutp = NULL;
@@ -899,12 +891,8 @@ void au0828_analog_unregister(struct au0828_dev *dev)
{
dprintk(1, "au0828_analog_unregister called\n");
mutex_lock(&au0828_sysfs_lock);
-
- if (dev->vdev)
- video_unregister_device(dev->vdev);
- if (dev->vbi_dev)
- video_unregister_device(dev->vbi_dev);
-
+ video_unregister_device(&dev->vdev);
+ video_unregister_device(&dev->vbi_dev);
mutex_unlock(&au0828_sysfs_lock);
}
@@ -949,7 +937,7 @@ static void au0828_vbi_buffer_timeout(unsigned long data)
if (buf != NULL) {
vbi_data = vb2_plane_vaddr(&buf->vb, 0);
memset(vbi_data, 0x00, buf->length);
- vbi_buffer_filled(dev, dma_q, buf);
+ buffer_filled(dev, dma_q, buf);
}
vbi_get_next_buf(dma_q, &buf);
@@ -1286,7 +1274,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
input->audioset = 2;
}
- input->std = dev->vdev->tvnorms;
+ input->std = dev->vdev.tvnorms;
return 0;
}
@@ -1704,7 +1692,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
static const struct video_device au0828_video_template = {
.fops = &au0828_v4l_fops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
};
@@ -1814,52 +1802,36 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->std = V4L2_STD_NTSC_M;
au0828_s_input(dev, 0);
- /* allocate and fill v4l2 video struct */
- dev->vdev = video_device_alloc();
- if (NULL == dev->vdev) {
- dprintk(1, "Can't allocate video_device.\n");
- return -ENOMEM;
- }
-
- /* allocate the VBI struct */
- dev->vbi_dev = video_device_alloc();
- if (NULL == dev->vbi_dev) {
- dprintk(1, "Can't allocate vbi_device.\n");
- ret = -ENOMEM;
- goto err_vdev;
- }
-
mutex_init(&dev->vb_queue_lock);
mutex_init(&dev->vb_vbi_queue_lock);
/* Fill the video capture device struct */
- *dev->vdev = au0828_video_template;
- dev->vdev->v4l2_dev = &dev->v4l2_dev;
- dev->vdev->lock = &dev->lock;
- dev->vdev->queue = &dev->vb_vidq;
- dev->vdev->queue->lock = &dev->vb_queue_lock;
- strcpy(dev->vdev->name, "au0828a video");
+ dev->vdev = au0828_video_template;
+ dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ dev->vdev.lock = &dev->lock;
+ dev->vdev.queue = &dev->vb_vidq;
+ dev->vdev.queue->lock = &dev->vb_queue_lock;
+ strcpy(dev->vdev.name, "au0828a video");
/* Setup the VBI device */
- *dev->vbi_dev = au0828_video_template;
- dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
- dev->vbi_dev->lock = &dev->lock;
- dev->vbi_dev->queue = &dev->vb_vbiq;
- dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
- strcpy(dev->vbi_dev->name, "au0828a vbi");
+ dev->vbi_dev = au0828_video_template;
+ dev->vbi_dev.v4l2_dev = &dev->v4l2_dev;
+ dev->vbi_dev.lock = &dev->lock;
+ dev->vbi_dev.queue = &dev->vb_vbiq;
+ dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock;
+ strcpy(dev->vbi_dev.name, "au0828a vbi");
/* initialize videobuf2 stuff */
retval = au0828_vb2_setup(dev);
if (retval != 0) {
dprintk(1, "unable to setup videobuf2 queues (error = %d).\n",
retval);
- ret = -ENODEV;
- goto err_vbi_dev;
+ return -ENODEV;
}
/* Register the v4l2 device */
- video_set_drvdata(dev->vdev, dev);
- retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+ video_set_drvdata(&dev->vdev, dev);
+ retval = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
if (retval != 0) {
dprintk(1, "unable to register video device (error = %d).\n",
retval);
@@ -1868,8 +1840,8 @@ int au0828_analog_register(struct au0828_dev *dev,
}
/* Register the vbi device */
- video_set_drvdata(dev->vbi_dev, dev);
- retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+ video_set_drvdata(&dev->vbi_dev, dev);
+ retval = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, -1);
if (retval != 0) {
dprintk(1, "unable to register vbi device (error = %d).\n",
retval);
@@ -1882,14 +1854,10 @@ int au0828_analog_register(struct au0828_dev *dev,
return 0;
err_reg_vbi_dev:
- video_unregister_device(dev->vdev);
+ video_unregister_device(&dev->vdev);
err_reg_vdev:
vb2_queue_release(&dev->vb_vidq);
vb2_queue_release(&dev->vb_vbiq);
-err_vbi_dev:
- video_device_release(dev->vbi_dev);
-err_vdev:
- video_device_release(dev->vdev);
return ret;
}
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index eb15187..3b48000 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -209,8 +209,8 @@ struct au0828_dev {
struct au0828_rc *ir;
#endif
- struct video_device *vdev;
- struct video_device *vbi_dev;
+ struct video_device vdev;
+ struct video_device vbi_dev;
/* Videobuf2 */
struct vb2_queue vb_vidq;
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
index 173c0e2..0cced3e 100644
--- a/drivers/media/usb/cx231xx/Kconfig
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -47,6 +47,7 @@ config VIDEO_CX231XX_DVB
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 3f295b4..983ea83 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1868,13 +1868,9 @@ void cx231xx_417_unregister(struct cx231xx *dev)
dprintk(1, "%s()\n", __func__);
dprintk(3, "%s()\n", __func__);
- if (dev->v4l_device) {
- if (-1 != dev->v4l_device->minor)
- video_unregister_device(dev->v4l_device);
- else
- video_device_release(dev->v4l_device);
+ if (video_is_registered(&dev->v4l_device)) {
+ video_unregister_device(&dev->v4l_device);
v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
- dev->v4l_device = NULL;
}
}
@@ -1911,25 +1907,21 @@ static struct cx2341x_handler_ops cx231xx_ops = {
.s_video_encoding = cx231xx_s_video_encoding,
};
-static struct video_device *cx231xx_video_dev_alloc(
+static void cx231xx_video_dev_init(
struct cx231xx *dev,
struct usb_device *usbdev,
- struct video_device *template,
- char *type)
+ struct video_device *vfd,
+ const struct video_device *template,
+ const char *type)
{
- struct video_device *vfd;
-
dprintk(1, "%s()\n", __func__);
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
*vfd = *template;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, cx231xx_boards[dev->model].name);
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->lock = &dev->lock;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
video_set_drvdata(vfd, dev);
if (dev->tuner_type == TUNER_ABSENT) {
@@ -1938,9 +1930,6 @@ static struct video_device *cx231xx_video_dev_alloc(
v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
}
-
- return vfd;
-
}
int cx231xx_417_register(struct cx231xx *dev)
@@ -1983,9 +1972,9 @@ int cx231xx_417_register(struct cx231xx *dev)
cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
/* Allocate and initialize V4L video device */
- dev->v4l_device = cx231xx_video_dev_alloc(dev,
- dev->udev, &cx231xx_mpeg_template, "mpeg");
- err = video_register_device(dev->v4l_device,
+ cx231xx_video_dev_init(dev, dev->udev,
+ &dev->v4l_device, &cx231xx_mpeg_template, "mpeg");
+ err = video_register_device(&dev->v4l_device,
VFL_TYPE_GRABBER, -1);
if (err < 0) {
dprintk(3, "%s: can't register mpeg device\n", dev->name);
@@ -1994,7 +1983,7 @@ int cx231xx_417_register(struct cx231xx *dev)
}
dprintk(3, "%s: registered device video%d [mpeg]\n",
- dev->name, dev->v4l_device->num);
+ dev->name, dev->v4l_device.num);
return 0;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index da03733..fe00da1 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -776,6 +776,45 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_HAUPPAUGE_955Q] = {
+ .name = "Hauppauge WinTV-HVR-955Q (111401)",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
+ .has_dvb = 1,
+ .demod_addr = 0x0e,
+ .norm = V4L2_STD_NTSC,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -805,6 +844,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
{USB_DEVICE(0x2040, 0xb120),
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xb123),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q},
{USB_DEVICE(0x2040, 0xb130),
.driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
{USB_DEVICE(0x2040, 0xb131),
@@ -912,9 +953,6 @@ static inline void cx231xx_set_model(struct cx231xx *dev)
*/
void cx231xx_pre_card_setup(struct cx231xx *dev)
{
-
- cx231xx_set_model(dev);
-
dev_info(dev->dev, "Identified as %s (card=%d)\n",
dev->board.name, dev->model);
@@ -1052,6 +1090,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
switch (dev->model) {
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
{
struct tveeprom tvee;
static u8 eeprom[256];
@@ -1092,6 +1131,17 @@ void cx231xx_config_i2c(struct cx231xx *dev)
call_all(dev, video, s_stream, 1);
}
+static void cx231xx_unregister_media_device(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (dev->media_dev) {
+ media_device_unregister(dev->media_dev);
+ kfree(dev->media_dev);
+ dev->media_dev = NULL;
+ }
+#endif
+}
+
/*
* cx231xx_realease_resources()
* unregisters the v4l2,i2c and usb devices
@@ -1099,6 +1149,8 @@ void cx231xx_config_i2c(struct cx231xx *dev)
*/
void cx231xx_release_resources(struct cx231xx *dev)
{
+ cx231xx_unregister_media_device(dev);
+
cx231xx_release_analog_resources(dev);
cx231xx_remove_from_devlist(dev);
@@ -1117,6 +1169,74 @@ void cx231xx_release_resources(struct cx231xx *dev)
clear_bit(dev->devno, &cx231xx_devused);
}
+static void cx231xx_media_device_register(struct cx231xx *dev,
+ struct usb_device *udev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev;
+ int ret;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return;
+
+ mdev->dev = dev->dev;
+ strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strcpy(mdev->bus_info, udev->devpath);
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ ret = media_device_register(mdev);
+ if (ret) {
+ dev_err(dev->dev,
+ "Couldn't create a media device. Error: %d\n",
+ ret);
+ kfree(mdev);
+ return;
+ }
+
+ dev->media_dev = mdev;
+#endif
+}
+
+static void cx231xx_create_media_graph(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *entity;
+ struct media_entity *tuner = NULL, *decoder = NULL;
+
+ if (!mdev)
+ return;
+
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->type) {
+ case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+ tuner = entity;
+ break;
+ case MEDIA_ENT_T_V4L2_SUBDEV_DECODER:
+ decoder = entity;
+ break;
+ }
+ }
+
+ /* Analog setup, using tuner as a link */
+
+ if (!decoder)
+ return;
+
+ if (tuner)
+ media_entity_create_link(tuner, 0, decoder, 0,
+ MEDIA_LNK_FL_ENABLED);
+ media_entity_create_link(decoder, 1, &dev->vdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+ media_entity_create_link(decoder, 2, &dev->vbi_dev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+#endif
+}
+
/*
* cx231xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
@@ -1225,10 +1345,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
}
retval = cx231xx_register_analog_devices(dev);
- if (retval) {
- cx231xx_release_analog_resources(dev);
+ if (retval)
goto err_analog;
- }
cx231xx_ir_init(dev);
@@ -1236,6 +1354,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
return 0;
err_analog:
+ cx231xx_unregister_media_device(dev);
+ cx231xx_release_analog_resources(dev);
cx231xx_remove_from_devlist(dev);
err_dev_init:
cx231xx_dev_uninit(dev);
@@ -1438,6 +1558,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
dev->video_mode.alt = -1;
dev->dev = d;
+ cx231xx_set_model(dev);
+
dev->interface_count++;
/* reset gpio dir and value */
dev->gpio_dir = 0;
@@ -1502,7 +1624,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
+ /* Register the media controller */
+ cx231xx_media_device_register(dev, udev);
+
/* Create v4l2 device */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->v4l2_dev.mdev = dev->media_dev;
+#endif
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
dev_err(d, "v4l2_device_register failed\n");
@@ -1568,6 +1696,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* load other modules required */
request_modules(dev);
+ cx231xx_create_media_graph(dev);
+
return 0;
err_video_alt:
/* cx231xx_uninit_dev: */
@@ -1618,7 +1748,7 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
if (dev->users) {
dev_warn(dev->dev,
"device %s is open! Deregistration and memory deallocation are deferred on close.\n",
- video_device_node_name(dev->vdev));
+ video_device_node_name(&dev->vdev));
/* Even having users, it is safe to remove the RC i2c driver */
cx231xx_ir_exit(dev);
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 4a3f28c..e42bde0 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -176,16 +176,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
saddr_len = req_data->saddr_len;
/* Set wValue */
- if (saddr_len == 1) /* need check saddr_len == 0 */
- ven_req.wValue =
- req_data->
- dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
- _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
- else
- ven_req.wValue =
- req_data->
- dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 |
- _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6;
+ ven_req.wValue = (req_data->dev_addr << 9 | _i2c_period << 4 |
+ saddr_len << 2 | _i2c_nostop << 1 | I2C_SYNC |
+ _i2c_reserve << 6);
/* set channel number */
if (req_data->direction & I2C_M_RD) {
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index dd600b9..610d567 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -34,6 +34,7 @@
#include "si2165.h"
#include "mb86a20s.h"
#include "si2157.h"
+#include "lgdt3306a.h"
MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
@@ -160,6 +161,18 @@ static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = {
.ref_freq_Hz = 24000000,
};
+static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = {
+ .i2c_addr = 0x59,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .mpeg_mode = LGDT3306A_MPEG_SERIAL,
+ .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH,
+ .xtalMHz = 25,
+};
+
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
{
char *errmsg = "Unknown";
@@ -455,6 +468,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
mutex_init(&dvb->lock);
+
/* register adapter */
result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
adapter_nr);
@@ -464,6 +478,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
dev->name, result);
goto fail_adapter;
}
+ dvb_register_media_controller(&dvb->adapter, dev->media_dev);
/* Ensure all frontends negotiate bus access */
dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
@@ -536,6 +551,8 @@ static int register_dvb(struct cx231xx_dvb *dvb,
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ dvb_create_media_graph(&dvb->adapter);
+
return 0;
fail_fe_conn:
@@ -807,7 +824,61 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->i2c_client_tuner = client;
break;
}
+ case CX231XX_BOARD_HAUPPAUGE_955Q:
+ {
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2157_config si2157_config;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
+ &hauppauge_955q_lgdt3306a_config,
+ tuner_i2c
+ );
+
+ if (dev->dvb->frontend == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach LGDT3306A frontend.\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = dev->dvb->frontend;
+ si2157_config.inversion = true;
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+ client = i2c_new_device(
+ tuner_i2c,
+ &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+
+ dev->dvb->i2c_client_tuner = client;
+ break;
+ }
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index ecea76f..c261e16 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -100,6 +100,75 @@ static struct cx231xx_fmt format[] = {
};
+static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *entity, *decoder = NULL, *source;
+ struct media_link *link, *found_link = NULL;
+ int i, ret, active_links = 0;
+
+ if (!mdev)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->type == MEDIA_ENT_T_V4L2_SUBDEV_DECODER) {
+ decoder = entity;
+ break;
+ }
+ }
+ if (!decoder)
+ return 0;
+
+ for (i = 0; i < decoder->num_links; i++) {
+ link = &decoder->links[i];
+ if (link->sink->entity == decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ for (i = 0; i < source->num_links; i++) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ link = &source->links[i];
+ sink = link->sink->entity;
+
+ if (sink == entity)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ dev_err(dev->dev,
+ "Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ } else
+ dev_dbg(dev->dev,
+ "link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
+ }
+#endif
+ return 0;
+}
+
/* ------------------------------------------------------------------
Video buffer and parser functions
------------------------------------------------------------------*/
@@ -667,6 +736,9 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (*count < CX231XX_MIN_BUF)
*count = CX231XX_MIN_BUF;
+
+ cx231xx_enable_analog_tuner(dev);
+
return 0;
}
@@ -756,6 +828,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
}
buf->vb.state = VIDEOBUF_PREPARED;
+
return 0;
fail:
@@ -1056,7 +1129,7 @@ int cx231xx_enum_input(struct file *file, void *priv,
(CX231XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = dev->vdev->tvnorms;
+ i->std = dev->vdev.tvnorms;
/* If they are asking about the active input, read signal status */
if (n == dev->video_input) {
@@ -1451,7 +1524,7 @@ int cx231xx_querycap(struct file *file, void *priv,
cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- if (dev->radio_dev)
+ if (video_is_registered(&dev->radio_dev))
cap->capabilities |= V4L2_CAP_RADIO;
return 0;
@@ -1729,34 +1802,21 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
/*FIXME: I2C IR should be disconnected */
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
- if (dev->vbi_dev) {
+ if (video_is_registered(&dev->radio_dev))
+ video_unregister_device(&dev->radio_dev);
+ if (video_is_registered(&dev->vbi_dev)) {
dev_info(dev->dev, "V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
+ video_device_node_name(&dev->vbi_dev));
+ video_unregister_device(&dev->vbi_dev);
}
- if (dev->vdev) {
+ if (video_is_registered(&dev->vdev)) {
dev_info(dev->dev, "V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
+ video_device_node_name(&dev->vdev));
if (dev->board.has_417)
cx231xx_417_unregister(dev);
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
+ video_unregister_device(&dev->vdev);
}
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
@@ -2013,7 +2073,7 @@ static struct video_device cx231xx_vbi_template;
static const struct video_device cx231xx_video_template = {
.fops = &cx231xx_v4l_fops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
};
@@ -2049,19 +2109,14 @@ static struct video_device cx231xx_radio_template = {
/******************************** usb interface ******************************/
-static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
- const struct video_device
- *template, const char *type_name)
+static void cx231xx_vdev_init(struct cx231xx *dev,
+ struct video_device *vfd,
+ const struct video_device *template,
+ const char *type_name)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
@@ -2073,7 +2128,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
}
- return vfd;
}
int cx231xx_register_analog_devices(struct cx231xx *dev)
@@ -2116,15 +2170,16 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* write code here... */
/* allocate and fill video video_device struct */
- dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
- if (!dev->vdev) {
- dev_err(dev->dev, "cannot allocate video_device.\n");
- return -ENODEV;
- }
-
- dev->vdev->ctrl_handler = &dev->ctrl_handler;
+ cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video");
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&dev->vdev.entity, 1, &dev->video_pad, 0);
+ if (ret < 0)
+ dev_err(dev->dev, "failed to initialize video media entity!\n");
+#endif
+ dev->vdev.ctrl_handler = &dev->ctrl_handler;
/* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
if (ret) {
dev_err(dev->dev,
@@ -2134,22 +2189,24 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
}
dev_info(dev->dev, "Registered video device %s [v4l2]\n",
- video_device_node_name(dev->vdev));
+ video_device_node_name(&dev->vdev));
/* Initialize VBI template */
cx231xx_vbi_template = cx231xx_video_template;
strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
/* Allocate and fill vbi video_device struct */
- dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+ cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi");
- if (!dev->vbi_dev) {
- dev_err(dev->dev, "cannot allocate video_device.\n");
- return -ENODEV;
- }
- dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad, 0);
+ if (ret < 0)
+ dev_err(dev->dev, "failed to initialize vbi media entity!\n");
+#endif
+ dev->vbi_dev.ctrl_handler = &dev->ctrl_handler;
/* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
dev_err(dev->dev, "unable to register vbi device\n");
@@ -2157,18 +2214,13 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
}
dev_info(dev->dev, "Registered VBI device %s\n",
- video_device_node_name(dev->vbi_dev));
+ video_device_node_name(&dev->vbi_dev));
if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
- dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
- dev_err(dev->dev,
- "cannot allocate video_device.\n");
- return -ENODEV;
- }
- dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ cx231xx_vdev_init(dev, &dev->radio_dev,
+ &cx231xx_radio_template, "radio");
+ dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
+ ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
dev_err(dev->dev,
@@ -2176,7 +2228,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
return ret;
}
dev_info(dev->dev, "Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
+ video_device_node_name(&dev->radio_dev));
}
return 0;
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 6d6f3ee..00d3bce 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -76,6 +76,7 @@
#define CX231XX_BOARD_KWORLD_UB445_USB_HYBRID 18
#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx 19
#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20
+#define CX231XX_BOARD_HAUPPAUGE_955Q 21
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -633,7 +634,7 @@ struct cx231xx {
/* video for linux */
int users; /* user count for exclusive use */
- struct video_device *vdev; /* video for linux device struct */
+ struct video_device vdev; /* video for linux device struct */
v4l2_std_id norm; /* selected tv norm */
int ctl_freq; /* selected frequency */
unsigned int ctl_ainput; /* selected audio input */
@@ -655,8 +656,13 @@ struct cx231xx {
struct mutex ctrl_urb_lock; /* protects urb_buf */
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
+ struct video_device vbi_dev;
+ struct video_device radio_dev;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_device *media_dev;
+ struct media_pad video_pad, vbi_pad;
+#endif
unsigned char eedata[256];
@@ -718,7 +724,7 @@ struct cx231xx {
u8 USE_ISO;
struct cx231xx_tvnorm encodernorm;
struct cx231xx_tsport ts1, ts2;
- struct video_device *v4l_device;
+ struct video_device v4l_device;
atomic_t v4l_reader_count;
u32 freq;
unsigned int input;
@@ -972,8 +978,11 @@ extern void cx231xx_417_unregister(struct cx231xx *dev);
int cx231xx_ir_init(struct cx231xx *dev);
void cx231xx_ir_exit(struct cx231xx *dev);
#else
-#define cx231xx_ir_init(dev) (0)
-#define cx231xx_ir_exit(dev) (0)
+static inline int cx231xx_ir_init(struct cx231xx *dev)
+{
+ return 0;
+}
+static inline void cx231xx_ir_exit(struct cx231xx *dev) {}
#endif
static inline unsigned int norm_maxw(struct cx231xx *dev)
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 0982e73..9facc92 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -146,7 +146,7 @@ config DVB_USB_DVBSKY
depends on DVB_USB_V2
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
- select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
select DVB_SP2 if MEDIA_SUBDRV_AUTOSELECT
help
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 41c6363..023d91f 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -25,6 +25,7 @@
#include <linux/usb/input.h>
#include <linux/firmware.h>
#include <media/rc-core.h>
+#include <media/media-device.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 9913e0f..f5df9eaba0 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -400,10 +400,61 @@ skip_feed_stop:
return ret;
}
+static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct media_device *mdev;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct usb_device *udev = d->udev;
+ int ret;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return;
+
+ mdev->dev = &udev->dev;
+ strlcpy(mdev->model, d->name, sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strcpy(mdev->bus_info, udev->devpath);
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ ret = media_device_register(mdev);
+ if (ret) {
+ dev_err(&d->udev->dev,
+ "Couldn't create a media device. Error: %d\n",
+ ret);
+ kfree(mdev);
+ return;
+ }
+
+ dvb_register_media_controller(&adap->dvb_adap, mdev);
+
+ dev_info(&d->udev->dev, "media controller created\n");
+
+#endif
+}
+
+static void dvb_usbv2_media_device_unregister(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+
+ if (!adap->dvb_adap.mdev)
+ return;
+
+ media_device_unregister(adap->dvb_adap.mdev);
+ kfree(adap->dvb_adap.mdev);
+ adap->dvb_adap.mdev = NULL;
+
+#endif
+}
+
static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
{
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
+
dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
@@ -416,6 +467,8 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
adap->dvb_adap.priv = adap;
+ dvb_usbv2_media_device_register(adap);
+
if (d->props->read_mac_address) {
ret = d->props->read_mac_address(adap,
adap->dvb_adap.proposed_mac);
@@ -464,6 +517,7 @@ err_dvb_net_init:
err_dvb_dmxdev_init:
dvb_dmx_release(&adap->demux);
err_dvb_dmx_init:
+ dvb_usbv2_media_device_unregister(adap);
dvb_unregister_adapter(&adap->dvb_adap);
err_dvb_register_adapter:
adap->dvb_adap.priv = NULL;
@@ -480,6 +534,7 @@ static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
dvb_dmx_release(&adap->demux);
+ dvb_usbv2_media_device_unregister(adap);
dvb_unregister_adapter(&adap->dvb_adap);
}
@@ -643,6 +698,8 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
}
}
+ dvb_create_media_graph(&adap->dvb_adap);
+
return 0;
err_dvb_unregister_frontend:
@@ -955,6 +1012,7 @@ void dvb_usbv2_disconnect(struct usb_interface *intf)
struct dvb_usb_device *d = usb_get_intfdata(intf);
const char *name = d->name;
struct device dev = d->udev->dev;
+
dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
intf->cur_altsetting->desc.bInterfaceNumber);
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
index 9b5add4..cdf59bc 100644
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -20,7 +20,7 @@
#include "dvb_usb.h"
#include "m88ds3103.h"
-#include "m88ts2022.h"
+#include "ts2020.h"
#include "sp2.h"
#include "si2168.h"
#include "si2157.h"
@@ -315,9 +315,7 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
struct i2c_adapter *i2c_adapter;
struct i2c_client *client;
struct i2c_board_info info;
- struct m88ts2022_config m88ts2022_config = {
- .clock = 27000000,
- };
+ struct ts2020_config ts2020_config = {};
memset(&info, 0, sizeof(struct i2c_board_info));
/* attach demod */
@@ -332,11 +330,11 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
}
/* attach tuner */
- m88ts2022_config.fe = adap->fe[0];
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ ts2020_config.fe = adap->fe[0];
+ strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
- request_module("m88ts2022");
+ info.platform_data = &ts2020_config;
+ request_module("ts2020");
client = i2c_new_device(i2c_adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
dvb_frontend_detach(adap->fe[0]);
@@ -439,9 +437,7 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
struct i2c_client *client_tuner, *client_ci;
struct i2c_board_info info;
struct sp2_config sp2_config;
- struct m88ts2022_config m88ts2022_config = {
- .clock = 27000000,
- };
+ struct ts2020_config ts2020_config = {};
memset(&info, 0, sizeof(struct i2c_board_info));
/* attach demod */
@@ -456,11 +452,11 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
}
/* attach tuner */
- m88ts2022_config.fe = adap->fe[0];
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ ts2020_config.fe = adap->fe[0];
+ strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
- request_module("m88ts2022");
+ info.platform_data = &ts2020_config;
+ request_module("ts2020");
client_tuner = i2c_new_device(i2c_adapter, &info);
if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
ret = -ENODEV;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 87fc0fe..895441f 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -866,6 +866,8 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
mn88472_config.i2c_wr_max = 22,
strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
mn88472_config.xtal = 20500000;
+ mn88472_config.ts_mode = SERIAL_TS_MODE;
+ mn88472_config.ts_clock = VARIABLE_TS_CLOCK;
info.addr = 0x18;
info.platform_data = &mn88472_config;
request_module(info.type);
@@ -1609,7 +1611,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
rc->allowed_protos = RC_BIT_ALL;
rc->driver_type = RC_DRIVER_IR_RAW;
rc->query = rtl2832u_rc_query;
- rc->interval = 400;
+ rc->interval = 200;
return 0;
}
@@ -1724,6 +1726,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl28xxu_props, "DigitalNow Quad DVB-T Receiver", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID,
&rtl28xxu_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS_PLUS,
+ &rtl28xxu_props, "Leadtek WinFast DTV2000DS Plus", RC_MAP_LEADTEK_Y04G0051) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
&rtl28xxu_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
@@ -1754,6 +1758,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl28xxu_props, "Sveon STV21", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
&rtl28xxu_props, "Sveon STV27", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TURBOX_DTT_2000,
+ &rtl28xxu_props, "TURBO-X Pure TV Tuner DTT-2000", NULL) },
/* RTL2832P devices: */
{ DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 3364200..128eee6 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -278,9 +278,10 @@ config DVB_USB_DW2102
select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
help
- Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
- receivers.
+ Say Y here to support the DvbWorld, TeVii, Prof, TechnoTrend
+ DVB-S/S2 USB2.0 receivers.
config DVB_USB_CINERGY_T2
tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index f327c49..ffc3704 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -1516,28 +1516,95 @@ static void cxusb_disconnect(struct usb_interface *intf)
dvb_usb_device_exit(intf);
}
-static struct usb_device_id cxusb_table [] = {
- { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
- { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
- { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
- { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) },
+enum cxusb_table_index {
+ MEDION_MD95700,
+ DVICO_BLUEBIRD_LG064F_COLD,
+ DVICO_BLUEBIRD_LG064F_WARM,
+ DVICO_BLUEBIRD_DUAL_1_COLD,
+ DVICO_BLUEBIRD_DUAL_1_WARM,
+ DVICO_BLUEBIRD_LGZ201_COLD,
+ DVICO_BLUEBIRD_LGZ201_WARM,
+ DVICO_BLUEBIRD_TH7579_COLD,
+ DVICO_BLUEBIRD_TH7579_WARM,
+ DIGITALNOW_BLUEBIRD_DUAL_1_COLD,
+ DIGITALNOW_BLUEBIRD_DUAL_1_WARM,
+ DVICO_BLUEBIRD_DUAL_2_COLD,
+ DVICO_BLUEBIRD_DUAL_2_WARM,
+ DVICO_BLUEBIRD_DUAL_4,
+ DVICO_BLUEBIRD_DVB_T_NANO_2,
+ DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM,
+ AVERMEDIA_VOLAR_A868R,
+ DVICO_BLUEBIRD_DUAL_4_REV_2,
+ CONEXANT_D680_DMB,
+ MYGICA_D689,
+ MYGICA_T230,
+ NR__cxusb_table_index
+};
+
+static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
+ [MEDION_MD95700] = {
+ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700)
+ },
+ [DVICO_BLUEBIRD_LG064F_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD)
+ },
+ [DVICO_BLUEBIRD_LG064F_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM)
+ },
+ [DVICO_BLUEBIRD_DUAL_1_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD)
+ },
+ [DVICO_BLUEBIRD_DUAL_1_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM)
+ },
+ [DVICO_BLUEBIRD_LGZ201_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD)
+ },
+ [DVICO_BLUEBIRD_LGZ201_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM)
+ },
+ [DVICO_BLUEBIRD_TH7579_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD)
+ },
+ [DVICO_BLUEBIRD_TH7579_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM)
+ },
+ [DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD)
+ },
+ [DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM)
+ },
+ [DVICO_BLUEBIRD_DUAL_2_COLD] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD)
+ },
+ [DVICO_BLUEBIRD_DUAL_2_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM)
+ },
+ [DVICO_BLUEBIRD_DUAL_4] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4)
+ },
+ [DVICO_BLUEBIRD_DVB_T_NANO_2] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2)
+ },
+ [DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM)
+ },
+ [AVERMEDIA_VOLAR_A868R] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R)
+ },
+ [DVICO_BLUEBIRD_DUAL_4_REV_2] = {
+ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2)
+ },
+ [CONEXANT_D680_DMB] = {
+ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB)
+ },
+ [MYGICA_D689] = {
+ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689)
+ },
+ [MYGICA_T230] = {
+ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230)
+ },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1581,7 +1648,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
.devices = {
{ "Medion MD95700 (MDUSBTV-HYBRID)",
{ NULL },
- { &cxusb_table[0], NULL },
+ { &cxusb_table[MEDION_MD95700], NULL },
},
}
};
@@ -1637,8 +1704,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV5 USB Gold",
- { &cxusb_table[1], NULL },
- { &cxusb_table[2], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_LG064F_COLD], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_LG064F_WARM], NULL },
},
}
};
@@ -1693,16 +1760,16 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.num_device_descs = 3,
.devices = {
{ "DViCO FusionHDTV DVB-T Dual USB",
- { &cxusb_table[3], NULL },
- { &cxusb_table[4], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_COLD], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL },
},
{ "DigitalNow DVB-T Dual USB",
- { &cxusb_table[9], NULL },
- { &cxusb_table[10], NULL },
+ { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL },
+ { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL },
},
{ "DViCO FusionHDTV DVB-T Dual Digital 2",
- { &cxusb_table[11], NULL },
- { &cxusb_table[12], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_2_COLD], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_2_WARM], NULL },
},
}
};
@@ -1756,8 +1823,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV DVB-T USB (LGZ201)",
- { &cxusb_table[5], NULL },
- { &cxusb_table[6], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_LGZ201_COLD], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_LGZ201_WARM], NULL },
},
}
};
@@ -1812,8 +1879,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV DVB-T USB (TH7579)",
- { &cxusb_table[7], NULL },
- { &cxusb_table[8], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_TH7579_COLD], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_TH7579_WARM], NULL },
},
}
};
@@ -1865,7 +1932,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
.devices = {
{ "DViCO FusionHDTV DVB-T Dual Digital 4",
{ NULL },
- { &cxusb_table[13], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_4], NULL },
},
}
};
@@ -1918,7 +1985,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
.devices = {
{ "DViCO FusionHDTV DVB-T NANO2",
{ NULL },
- { &cxusb_table[14], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL },
},
}
};
@@ -1972,8 +2039,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
- { &cxusb_table[14], NULL },
- { &cxusb_table[15], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], NULL },
},
}
};
@@ -2017,7 +2084,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
.devices = {
{ "AVerMedia AVerTVHD Volar (A868R)",
{ NULL },
- { &cxusb_table[16], NULL },
+ { &cxusb_table[AVERMEDIA_VOLAR_A868R], NULL },
},
}
};
@@ -2071,7 +2138,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
.devices = {
{ "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
{ NULL },
- { &cxusb_table[17], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DUAL_4_REV_2], NULL },
},
}
};
@@ -2125,7 +2192,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
{
"Conexant DMB-TH Stick",
{ NULL },
- { &cxusb_table[18], NULL },
+ { &cxusb_table[CONEXANT_D680_DMB], NULL },
},
}
};
@@ -2179,7 +2246,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
{
"Mygica D689 DMB-TH",
{ NULL },
- { &cxusb_table[19], NULL },
+ { &cxusb_table[MYGICA_D689], NULL },
},
}
};
@@ -2232,7 +2299,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
{
"Mygica T230 DVB-T/T2/C",
{ NULL },
- { &cxusb_table[20], NULL },
+ { &cxusb_table[MYGICA_T230], NULL },
},
}
};
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 50856db..2b40393 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -651,9 +651,6 @@ out:
return ret;
}
-/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY_V1_20 10
-
/* This is the structure of the RC response packet starting in firmware 1.20 */
struct dib0700_rc_response {
u8 report_id;
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index e1757b8..d7d55a2 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -510,9 +510,6 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
-/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY 6
-
/*
* This function is used only when firmware is < 1.20 version. Newer
* firmwares use bulk mode, with functions implemented at dib0700_core,
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 719413b..8a260c8 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -84,14 +84,61 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
- return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+ deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,
+ dvbdmxfeed->type);
+ return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
}
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
- return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+ return dvb_usb_ctrl_feed(dvbdmxfeed, 0);
+}
+
+static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct media_device *mdev;
+ struct dvb_usb_device *d = adap->dev;
+ struct usb_device *udev = d->udev;
+ int ret;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return;
+
+ mdev->dev = &udev->dev;
+ strlcpy(mdev->model, d->desc->name, sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strcpy(mdev->bus_info, udev->devpath);
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ ret = media_device_register(mdev);
+ if (ret) {
+ dev_err(&d->udev->dev,
+ "Couldn't create a media device. Error: %d\n",
+ ret);
+ kfree(mdev);
+ return;
+ }
+ dvb_register_media_controller(&adap->dvb_adap, mdev);
+
+ dev_info(&d->udev->dev, "media controller created\n");
+#endif
+}
+
+static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (!adap->dvb_adap.mdev)
+ return;
+
+ media_device_unregister(adap->dvb_adap.mdev);
+ kfree(adap->dvb_adap.mdev);
+ adap->dvb_adap.mdev = NULL;
+#endif
}
int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
@@ -107,9 +154,11 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
}
adap->dvb_adap.priv = adap;
+ dvb_usb_media_device_register(adap);
+
if (adap->dev->props.read_mac_address) {
- if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
- info("MAC address: %pM",adap->dvb_adap.proposed_mac);
+ if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0)
+ info("MAC address: %pM", adap->dvb_adap.proposed_mac);
else
err("MAC address reading failed.");
}
@@ -128,7 +177,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
adap->demux.stop_feed = dvb_usb_stop_feed;
adap->demux.write_to_decoder = NULL;
if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
- err("dvb_dmx_init failed: error %d",ret);
+ err("dvb_dmx_init failed: error %d", ret);
goto err_dmx;
}
@@ -136,13 +185,13 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
adap->dmxdev.demux = &adap->demux.dmx;
adap->dmxdev.capabilities = 0;
if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
- err("dvb_dmxdev_init failed: error %d",ret);
+ err("dvb_dmxdev_init failed: error %d", ret);
goto err_dmx_dev;
}
if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
&adap->demux.dmx)) < 0) {
- err("dvb_net_init failed: error %d",ret);
+ err("dvb_net_init failed: error %d", ret);
goto err_net_init;
}
@@ -154,6 +203,7 @@ err_net_init:
err_dmx_dev:
dvb_dmx_release(&adap->demux);
err_dmx:
+ dvb_usb_media_device_unregister(adap);
dvb_unregister_adapter(&adap->dvb_adap);
err:
return ret;
@@ -167,6 +217,7 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
dvb_dmx_release(&adap->demux);
+ dvb_usb_media_device_unregister(adap);
dvb_unregister_adapter(&adap->dvb_adap);
adap->state &= ~DVB_USB_ADAP_STATE_DVB;
}
@@ -268,6 +319,8 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
adap->num_frontends_initialized++;
}
+ dvb_create_media_graph(&adap->dvb_adap);
+
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 1a3df10..f1f357f 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -2,7 +2,8 @@
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
* TeVii S600, S630, S650, S660, S480, S421, S632
* Prof 1100, 7500,
- * Geniatech SU3000, T220 Cards
+ * Geniatech SU3000, T220,
+ * TechnoTrend S2-4600 Cards
* Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
@@ -31,6 +32,8 @@
#include "m88rs2000.h"
#include "tda18271.h"
#include "cxd2820r.h"
+#include "m88ds3103.h"
+#include "ts2020.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
@@ -112,11 +115,9 @@
"Please see linux/Documentation/dvb/ for more details " \
"on firmware-problems."
-struct su3000_state {
+struct dw2102_state {
u8 initialized;
-};
-
-struct s6x0_state {
+ struct i2c_client *i2c_client_tuner;
int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v);
};
@@ -887,7 +888,7 @@ static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
{
- struct su3000_state *state = (struct su3000_state *)d->priv;
+ struct dw2102_state *state = (struct dw2102_state *)d->priv;
u8 obuf[] = {0xde, 0};
info("%s: %d, initialized %d\n", __func__, i, state->initialized);
@@ -973,7 +974,7 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct dvb_usb_adapter *d =
(struct dvb_usb_adapter *)(fe->dvb->priv);
- struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+ struct dw2102_state *st = (struct dw2102_state *)d->dev->priv;
dw210x_set_voltage(fe, voltage);
if (st->old_set_voltage)
@@ -1117,6 +1118,22 @@ static struct tda18271_config tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
};
+static const struct m88ds3103_config tt_s2_4600_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .ts_mode = M88DS3103_TS_CI,
+ .ts_clk = 16000,
+ .ts_clk_pol = 0,
+ .spec_inv = 0,
+ .agc_inv = 0,
+ .clock_out = M88DS3103_CLOCK_OUT_ENABLED,
+ .envelope_mode = 0,
+ .agc = 0x99,
+ .lnb_hv_pol = 1,
+ .lnb_en_pol = 0,
+};
+
static u8 m88rs2000_inittab[] = {
DEMOD_WRITE, 0x9a, 0x30,
DEMOD_WRITE, 0x00, 0x01,
@@ -1295,7 +1312,7 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
{
- struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+ struct dw2102_state *st = d->dev->priv;
u8 obuf[] = {7, 1};
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config,
@@ -1461,6 +1478,84 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
+static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct dw2102_state *state = d->priv;
+ u8 obuf[3] = { 0xe, 0x80, 0 };
+ u8 ibuf[] = { 0 };
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct ts2020_config ts2020_config = {};
+
+ if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x02;
+ obuf[2] = 1;
+
+ if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+ msleep(300);
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x83;
+ obuf[2] = 0;
+
+ if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x83;
+ obuf[2] = 1;
+
+ if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0x51;
+
+ if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 1, 0) < 0)
+ err("command 0x51 transfer failed.");
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ adap->fe_adap[0].fe = dvb_attach(m88ds3103_attach,
+ &tt_s2_4600_m88ds3103_config,
+ &d->i2c_adap,
+ &i2c_adapter);
+ if (adap->fe_adap[0].fe == NULL)
+ return -ENODEV;
+
+ /* attach tuner */
+ ts2020_config.fe = adap->fe_adap[0].fe;
+ strlcpy(info.type, "ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &ts2020_config;
+ request_module("ts2020");
+ client = i2c_new_device(i2c_adapter, &info);
+
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(adap->fe_adap[0].fe);
+ return -ENODEV;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(adap->fe_adap[0].fe);
+ return -ENODEV;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ adap->fe_adap[0].fe->ops.read_signal_strength =
+ adap->fe_adap[0].fe->ops.tuner_ops.get_rf_strength;
+
+ state->i2c_client_tuner = client;
+
+ return 0;
+}
+
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
@@ -1561,6 +1656,7 @@ enum dw2102_table_entry {
TERRATEC_CINERGY_S2_R2,
GOTVIEW_SAT_HD,
GENIATECH_T220,
+ TECHNOTREND_S2_4600,
};
static struct usb_device_id dw2102_table[] = {
@@ -1584,6 +1680,8 @@ static struct usb_device_id dw2102_table[] = {
[TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
[GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
[GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)},
+ [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_S2_4600)},
{ }
};
@@ -1857,7 +1955,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
static struct dvb_usb_device_properties s6x0_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .size_of_priv = sizeof(struct s6x0_state),
+ .size_of_priv = sizeof(struct dw2102_state),
.firmware = S630_FIRMWARE,
.no_reconnect = 1,
@@ -1950,7 +2048,7 @@ static struct dvb_usb_device_description d632 = {
static struct dvb_usb_device_properties su3000_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .size_of_priv = sizeof(struct su3000_state),
+ .size_of_priv = sizeof(struct dw2102_state),
.power_ctrl = su3000_power_ctrl,
.num_adapters = 1,
.identify_state = su3000_identify_state,
@@ -2015,7 +2113,7 @@ static struct dvb_usb_device_properties su3000_properties = {
static struct dvb_usb_device_properties t220_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .size_of_priv = sizeof(struct su3000_state),
+ .size_of_priv = sizeof(struct dw2102_state),
.power_ctrl = su3000_power_ctrl,
.num_adapters = 1,
.identify_state = su3000_identify_state,
@@ -2061,6 +2159,55 @@ static struct dvb_usb_device_properties t220_properties = {
}
};
+static struct dvb_usb_device_properties tt_s2_4600_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .size_of_priv = sizeof(struct dw2102_state),
+ .power_ctrl = su3000_power_ctrl,
+ .num_adapters = 1,
+ .identify_state = su3000_identify_state,
+ .i2c_algo = &su3000_i2c_algo,
+
+ .rc.core = {
+ .rc_interval = 250,
+ .rc_codes = RC_MAP_TT_1500,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_RC5,
+ .rc_query = su3000_rc_query,
+ },
+
+ .read_mac_address = su3000_read_mac_address,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .streaming_ctrl = su3000_streaming_ctrl,
+ .frontend_attach = tt_s2_4600_frontend_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ }
+ } },
+ }
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "TechnoTrend TT-connect S2-4600",
+ { &dw2102_table[TECHNOTREND_S2_4600], NULL },
+ { NULL },
+ },
+ }
+};
+
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -2135,16 +2282,34 @@ static int dw2102_probe(struct usb_interface *intf,
0 == dvb_usb_device_init(intf, &su3000_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &t220_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &tt_s2_4600_properties,
THIS_MODULE, NULL, adapter_nr))
return 0;
return -ENODEV;
}
+static void dw2102_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ struct dw2102_state *st = (struct dw2102_state *)d->priv;
+ struct i2c_client *client;
+
+ /* remove I2C client for tuner */
+ client = st->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ dvb_usb_device_exit(intf);
+}
+
static struct usb_driver dw2102_driver = {
.name = "dw2102",
.probe = dw2102_probe,
- .disconnect = dvb_usb_device_exit,
+ .disconnect = dw2102_disconnect,
.id_table = dw2102_table,
};
@@ -2155,7 +2320,8 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
" TeVii S600, S630, S650, S660, S480, S421, S632"
" Prof 1100, 7500 USB2.0,"
- " Geniatech SU3000, T220 devices");
+ " Geniatech SU3000, T220,"
+ " TechnoTrend S2-4600 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(DW2101_FIRMWARE);
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index f5d7198..e382210 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -55,7 +55,7 @@ config VIDEO_EM28XX_DVB
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
- select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 7be661f..a4b22c2 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -330,7 +330,7 @@ int em28xx_init_camera(struct em28xx *dev)
v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
i2c_adapter_id(adap), client->addr);
- v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
+ v4l2->clk = v4l2_clk_register_fixed(clk_name, -EINVAL);
if (IS_ERR(v4l2->clk))
return PTR_ERR(v4l2->clk);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index d9704e6..3940046 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -1157,6 +1157,15 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
+ [EM2884_BOARD_ELGATO_EYETV_HYBRID_2008] = {
+ .name = "Elgato EyeTV Hybrid 2008 INT",
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+ .tuner_type = TUNER_ABSENT,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
.name = "Hauppauge WinTV HVR 900",
.tda9887_conf = TDA9887_PRESENT,
@@ -2378,8 +2387,10 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
{ USB_DEVICE(0x0ccd, 0x00b2),
.driver_info = EM2884_BOARD_CINERGY_HTC_STICK },
+ { USB_DEVICE(0x0fd9, 0x0018),
+ .driver_info = EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 },
{ USB_DEVICE(0x0fd9, 0x0033),
- .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
+ .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE },
{ USB_DEVICE(0x185b, 0x2870),
.driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
{ USB_DEVICE(0x185b, 0x2041),
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index aee70d4..a5b22c5 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -54,7 +54,7 @@
#include "qt1010.h"
#include "mb86a20s.h"
#include "m88ds3103.h"
-#include "m88ts2022.h"
+#include "ts2020.h"
#include "si2168.h"
#include "si2157.h"
@@ -1380,6 +1380,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
}
}
break;
+ case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008:
case EM2884_BOARD_CINERGY_HTC_STICK:
terratec_htc_stick_init(dev);
@@ -1491,8 +1492,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
struct i2c_adapter *i2c_adapter;
struct i2c_client *client;
struct i2c_board_info info;
- struct m88ts2022_config m88ts2022_config = {
- .clock = 27000000,
+ struct ts2020_config ts2020_config = {
};
memset(&info, 0, sizeof(struct i2c_board_info));
@@ -1507,11 +1507,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
}
/* attach tuner */
- m88ts2022_config.fe = dvb->fe[0];
- strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ ts2020_config.fe = dvb->fe[0];
+ strlcpy(info.type, "ts2022", I2C_NAME_SIZE);
info.addr = 0x60;
- info.platform_data = &m88ts2022_config;
- request_module("m88ts2022");
+ info.platform_data = &ts2020_config;
+ request_module("ts2020");
client = i2c_new_device(i2c_adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
dvb_frontend_detach(dvb->fe[0]);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 9ecf656..14eba9c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1472,7 +1472,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
(EM28XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = dev->v4l2->vdev->tvnorms;
+ i->std = dev->v4l2->vdev.tvnorms;
/* webcams do not have the STD API */
if (dev->board.is_webcam)
i->capabilities = 0;
@@ -1730,9 +1730,9 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- if (v4l2->vbi_dev)
+ if (video_is_registered(&v4l2->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
- if (v4l2->radio_dev)
+ if (video_is_registered(&v4l2->radio_dev))
cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1966,20 +1966,20 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
- if (v4l2->radio_dev) {
+ if (video_is_registered(&v4l2->radio_dev)) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(v4l2->radio_dev));
- video_unregister_device(v4l2->radio_dev);
+ video_device_node_name(&v4l2->radio_dev));
+ video_unregister_device(&v4l2->radio_dev);
}
- if (v4l2->vbi_dev) {
+ if (video_is_registered(&v4l2->vbi_dev)) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(v4l2->vbi_dev));
- video_unregister_device(v4l2->vbi_dev);
+ video_device_node_name(&v4l2->vbi_dev));
+ video_unregister_device(&v4l2->vbi_dev);
}
- if (v4l2->vdev) {
+ if (video_is_registered(&v4l2->vdev)) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(v4l2->vdev));
- video_unregister_device(v4l2->vdev);
+ video_device_node_name(&v4l2->vdev));
+ video_unregister_device(&v4l2->vdev);
}
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
@@ -2127,7 +2127,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
static const struct video_device em28xx_video_template = {
.fops = &em28xx_v4l_fops,
.ioctl_ops = &video_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.tvnorms = V4L2_STD_ALL,
};
@@ -2156,7 +2156,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
static struct video_device em28xx_radio_template = {
.fops = &radio_fops,
.ioctl_ops = &radio_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2179,17 +2179,11 @@ static unsigned short msp3400_addrs[] = {
/******************************** usb interface ******************************/
-static struct video_device
-*em28xx_vdev_init(struct em28xx *dev,
- const struct video_device *template,
- const char *type_name)
+static void em28xx_vdev_init(struct em28xx *dev,
+ struct video_device *vfd,
+ const struct video_device *template,
+ const char *type_name)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->lock = &dev->lock;
@@ -2200,7 +2194,6 @@ static struct video_device
dev->name, type_name);
video_set_drvdata(vfd, dev);
- return vfd;
}
static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr)
@@ -2491,38 +2484,33 @@ static int em28xx_v4l2_init(struct em28xx *dev)
goto unregister_dev;
/* allocate and fill video video_device struct */
- v4l2->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
- if (!v4l2->vdev) {
- em28xx_errdev("cannot allocate video_device.\n");
- ret = -ENODEV;
- goto unregister_dev;
- }
+ em28xx_vdev_init(dev, &v4l2->vdev, &em28xx_video_template, "video");
mutex_init(&v4l2->vb_queue_lock);
mutex_init(&v4l2->vb_vbi_queue_lock);
- v4l2->vdev->queue = &v4l2->vb_vidq;
- v4l2->vdev->queue->lock = &v4l2->vb_queue_lock;
+ v4l2->vdev.queue = &v4l2->vb_vidq;
+ v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
/* disable inapplicable ioctls */
if (dev->board.is_webcam) {
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_QUERYSTD);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_STD);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD);
} else {
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_PARM);
}
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_FREQUENCY);
}
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_AUDIO);
}
/* register v4l2 video video_device */
- ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER,
+ ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
if (ret) {
em28xx_errdev("unable to register video device (error=%i).\n",
@@ -2532,27 +2520,27 @@ static int em28xx_v4l2_init(struct em28xx *dev)
/* Allocate and fill vbi video_device struct */
if (em28xx_vbi_supported(dev) == 1) {
- v4l2->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
- "vbi");
+ em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template,
+ "vbi");
- v4l2->vbi_dev->queue = &v4l2->vb_vbiq;
- v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock;
+ v4l2->vbi_dev.queue = &v4l2->vb_vbiq;
+ v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
/* disable inapplicable ioctls */
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
}
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_AUDIO);
}
/* register v4l2 vbi video_device */
- ret = video_register_device(v4l2->vbi_dev, VFL_TYPE_VBI,
+ ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("unable to register vbi device\n");
@@ -2561,29 +2549,24 @@ static int em28xx_v4l2_init(struct em28xx *dev)
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
- v4l2->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
- "radio");
- if (!v4l2->radio_dev) {
- em28xx_errdev("cannot allocate video_device.\n");
- ret = -ENODEV;
- goto unregister_dev;
- }
- ret = video_register_device(v4l2->radio_dev, VFL_TYPE_RADIO,
+ em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template,
+ "radio");
+ ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("can't register radio device\n");
goto unregister_dev;
}
em28xx_info("Registered radio device as %s\n",
- video_device_node_name(v4l2->radio_dev));
+ video_device_node_name(&v4l2->radio_dev));
}
em28xx_info("V4L2 video device registered as %s\n",
- video_device_node_name(v4l2->vdev));
+ video_device_node_name(&v4l2->vdev));
- if (v4l2->vbi_dev)
+ if (video_is_registered(&v4l2->vbi_dev))
em28xx_info("V4L2 VBI device registered as %s\n",
- video_device_node_name(v4l2->vbi_dev));
+ video_device_node_name(&v4l2->vbi_dev));
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 9c70753..e6559c6 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -143,6 +143,7 @@
#define EM28178_BOARD_PCTV_292E 94
#define EM2861_BOARD_LEADTEK_VC100 95
#define EM28178_BOARD_TERRATEC_T2_STICK_HD 96
+#define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -512,9 +513,9 @@ struct em28xx_v4l2 {
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_clk *clk;
- struct video_device *vdev;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
+ struct video_device vdev;
+ struct video_device vbi_dev;
+ struct video_device radio_dev;
/* Videobuf2 */
struct vb2_queue vb_vidq;
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index a9c866d..146071b 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -816,21 +816,16 @@ static void sethue(struct gspca_dev *gspca_dev, s32 val)
s16 huesin;
s16 huecos;
- /* fixp_sin and fixp_cos accept only positive values, while
- * our val is between -90 and 90
- */
- val += 360;
-
/* According to the datasheet the registers expect HUESIN and
* HUECOS to be the result of the trigonometric functions,
* scaled by 0x80.
*
- * The 0x100 here represents the maximun absolute value
+ * The 0x7fff here represents the maximum absolute value
* returned byt fixp_sin and fixp_cos, so the scaling will
* consider the result like in the interval [-1.0, 1.0].
*/
- huesin = fixp_sin(val) * 0x80 / 0x100;
- huecos = fixp_cos(val) * 0x80 / 0x100;
+ huesin = fixp_sin16(val) * 0x80 / 0x7fff;
+ huecos = fixp_cos16(val) * 0x80 / 0x7fff;
if (huesin < 0) {
sccb_reg_write(gspca_dev, 0xab,
diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index 5fcd1ee..c70ff40 100644
--- a/drivers/media/usb/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
@@ -969,7 +969,9 @@ static void jpeg_set_qual(u8 *jpeg_hdr,
{
int i, sc;
- if (quality < 50)
+ if (quality <= 0)
+ sc = 5000;
+ else if (quality < 50)
sc = 5000 / quality;
else
sc = 200 - quality * 2;
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 42b4cdf..3fc6419 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -69,10 +69,6 @@ MODULE_DEVICE_TABLE(usb, hdpvr_table);
void hdpvr_delete(struct hdpvr_device *dev)
{
hdpvr_free_buffers(dev);
-
- if (dev->video_dev)
- video_device_release(dev->video_dev);
-
usb_put_dev(dev->udev);
}
@@ -397,7 +393,7 @@ static int hdpvr_probe(struct usb_interface *interface,
/* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
- video_device_node_name(dev->video_dev));
+ video_device_node_name(&dev->video_dev));
return 0;
reg_fail:
@@ -420,7 +416,7 @@ static void hdpvr_disconnect(struct usb_interface *interface)
struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
- video_device_node_name(dev->video_dev));
+ video_device_node_name(&dev->video_dev));
/* prevent more I/O from starting and stop any ongoing */
mutex_lock(&dev->io_mutex);
dev->status = STATUS_DISCONNECTED;
@@ -436,7 +432,7 @@ static void hdpvr_disconnect(struct usb_interface *interface)
#if IS_ENABLED(CONFIG_I2C)
i2c_del_adapter(&dev->i2c_adapter);
#endif
- video_unregister_device(dev->video_dev);
+ video_unregister_device(&dev->video_dev);
atomic_dec(&dev_nr);
}
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 59d15fd..d8d8c0f 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -797,7 +797,7 @@ static int vidioc_s_input(struct file *file, void *_fh,
* Comment this out for now, but if the legacy mode can be
* removed in the future, then this code should be enabled
* again.
- dev->video_dev->tvnorms =
+ dev->video_dev.tvnorms =
(index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0;
*/
}
@@ -1228,19 +1228,12 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
}
/* setup and register video device */
- dev->video_dev = video_device_alloc();
- if (!dev->video_dev) {
- v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
- res = -ENOMEM;
- goto error;
- }
-
- *dev->video_dev = hdpvr_video_template;
- strcpy(dev->video_dev->name, "Hauppauge HD PVR");
- dev->video_dev->v4l2_dev = &dev->v4l2_dev;
- video_set_drvdata(dev->video_dev, dev);
+ dev->video_dev = hdpvr_video_template;
+ strcpy(dev->video_dev.name, "Hauppauge HD PVR");
+ dev->video_dev.v4l2_dev = &dev->v4l2_dev;
+ video_set_drvdata(&dev->video_dev, dev);
- res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
+ res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum);
if (res < 0) {
v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
goto error;
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index dc685d4..a319430 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -66,7 +66,7 @@ struct hdpvr_options {
/* Structure to hold all of our device specific stuff */
struct hdpvr_device {
/* the v4l device for this device */
- struct video_device *video_dev;
+ struct video_device video_dev;
/* the control handler for this device */
struct v4l2_ctrl_handler hdl;
/* the usb device for this device */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 35e4ea5..1c5f85b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/version.h>
#include "pvrusb2-context.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2.h"
@@ -32,6 +31,7 @@
#include <linux/module.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -50,14 +50,11 @@ struct pvr2_v4l2_dev {
};
struct pvr2_v4l2_fh {
+ struct v4l2_fh fh;
struct pvr2_channel channel;
struct pvr2_v4l2_dev *pdi;
- enum v4l2_priority prio;
struct pvr2_ioread *rhp;
struct file *file;
- struct pvr2_v4l2 *vhead;
- struct pvr2_v4l2_fh *vnext;
- struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
/* Map contiguous ordinal value to input id */
@@ -67,10 +64,6 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2 {
struct pvr2_channel channel;
- struct pvr2_v4l2_fh *vfirst;
- struct pvr2_v4l2_fh *vlast;
-
- struct v4l2_prio_state prio;
/* streams - Note that these must be separately, individually,
* allocated pointers. This is because the v4l core is going to
@@ -169,23 +162,6 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *
return 0;
}
-static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
-{
- struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_v4l2 *vp = fh->vhead;
-
- *p = v4l2_prio_max(&vp->prio);
- return 0;
-}
-
-static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio)
-{
- struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_v4l2 *vp = fh->vhead;
-
- return v4l2_prio_change(&vp->prio, &fh->prio, prio);
-}
-
static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
struct pvr2_v4l2_fh *fh = file->private_data;
@@ -805,8 +781,6 @@ static int pvr2_log_status(struct file *file, void *priv)
static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
.vidioc_querycap = pvr2_querycap,
- .vidioc_g_priority = pvr2_g_priority,
- .vidioc_s_priority = pvr2_s_priority,
.vidioc_s_audio = pvr2_s_audio,
.vidioc_g_audio = pvr2_g_audio,
.vidioc_enumaudio = pvr2_enumaudio,
@@ -911,7 +885,9 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
if (!vp->channel.mc_head->disconnect_flag) return;
pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
- if (vp->vfirst) return;
+ if (!list_empty(&vp->dev_video->devbase.fh_list) ||
+ !list_empty(&vp->dev_radio->devbase.fh_list))
+ return;
pvr2_v4l2_destroy_no_lock(vp);
}
@@ -921,7 +897,6 @@ static long pvr2_v4l2_ioctl(struct file *file,
{
struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_v4l2 *vp = fh->vhead;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
long ret = -EINVAL;
@@ -934,18 +909,6 @@ static long pvr2_v4l2_ioctl(struct file *file,
return -EFAULT;
}
- /* check priority */
- switch (cmd) {
- case VIDIOC_S_CTRL:
- case VIDIOC_S_STD:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_TUNER:
- case VIDIOC_S_FREQUENCY:
- ret = v4l2_prio_check(&vp->prio, fh->prio);
- if (ret)
- return ret;
- }
-
ret = video_ioctl2(file, cmd, arg);
pvr2_hdw_commit_ctl(hdw);
@@ -970,7 +933,7 @@ static long pvr2_v4l2_ioctl(struct file *file,
static int pvr2_v4l2_release(struct file *file)
{
struct pvr2_v4l2_fh *fhp = file->private_data;
- struct pvr2_v4l2 *vp = fhp->vhead;
+ struct pvr2_v4l2 *vp = fhp->pdi->v4lp;
struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
@@ -984,22 +947,10 @@ static int pvr2_v4l2_release(struct file *file)
fhp->rhp = NULL;
}
- v4l2_prio_close(&vp->prio, fhp->prio);
+ v4l2_fh_del(&fhp->fh);
+ v4l2_fh_exit(&fhp->fh);
file->private_data = NULL;
- if (fhp->vnext) {
- fhp->vnext->vprev = fhp->vprev;
- } else {
- vp->vlast = fhp->vprev;
- }
- if (fhp->vprev) {
- fhp->vprev->vnext = fhp->vnext;
- } else {
- vp->vfirst = fhp->vnext;
- }
- fhp->vnext = NULL;
- fhp->vprev = NULL;
- fhp->vhead = NULL;
pvr2_channel_done(&fhp->channel);
pvr2_trace(PVR2_TRACE_STRUCT,
"Destroying pvr_v4l2_fh id=%p",fhp);
@@ -1008,7 +959,9 @@ static int pvr2_v4l2_release(struct file *file)
fhp->input_map = NULL;
}
kfree(fhp);
- if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+ if (vp->channel.mc_head->disconnect_flag &&
+ list_empty(&vp->dev_video->devbase.fh_list) &&
+ list_empty(&vp->dev_radio->devbase.fh_list)) {
pvr2_v4l2_destroy_no_lock(vp);
}
return 0;
@@ -1043,6 +996,7 @@ static int pvr2_v4l2_open(struct file *file)
return -ENOMEM;
}
+ v4l2_fh_init(&fhp->fh, &dip->devbase);
init_waitqueue_head(&fhp->wait_data);
fhp->pdi = dip;
@@ -1093,21 +1047,11 @@ static int pvr2_v4l2_open(struct file *file)
fhp->input_map[input_cnt++] = idx;
}
- fhp->vnext = NULL;
- fhp->vprev = vp->vlast;
- if (vp->vlast) {
- vp->vlast->vnext = fhp;
- } else {
- vp->vfirst = fhp;
- }
- vp->vlast = fhp;
- fhp->vhead = vp;
-
fhp->file = file;
file->private_data = fhp;
- v4l2_prio_open(&vp->prio, &fhp->prio);
fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
+ v4l2_fh_add(&fhp->fh);
return 0;
}
@@ -1247,7 +1191,7 @@ static const struct v4l2_file_operations vdev_fops = {
.open = pvr2_v4l2_open,
.release = pvr2_v4l2_release,
.read = pvr2_v4l2_read,
- .ioctl = pvr2_v4l2_ioctl,
+ .unlocked_ioctl = pvr2_v4l2_ioctl,
.poll = pvr2_v4l2_poll,
};
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 94e10b1..c945e4c 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************/
+#include "smscoreapi.h"
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/usb.h>
@@ -26,14 +28,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/slab.h>
#include <linux/module.h>
-#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsendian.h"
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
#define USB1_BUFFER_SIZE 0x1000
#define USB2_BUFFER_SIZE 0x2000
@@ -87,7 +84,7 @@ static void smsusb_onresponse(struct urb *urb)
struct smsusb_device_t *dev = surb->dev;
if (urb->status == -ESHUTDOWN) {
- sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
+ pr_err("error, urb status %d (-ESHUTDOWN), %d bytes\n",
urb->status, urb->actual_length);
return;
}
@@ -109,9 +106,7 @@ static void smsusb_onresponse(struct urb *urb)
/* sanity check */
if (((int) phdr->msg_length +
surb->cb->offset) > urb->actual_length) {
- sms_err("invalid response "
- "msglen %d offset %d "
- "size %d",
+ pr_err("invalid response msglen %d offset %d size %d\n",
phdr->msg_length,
surb->cb->offset,
urb->actual_length);
@@ -125,7 +120,7 @@ static void smsusb_onresponse(struct urb *urb)
} else
surb->cb->offset = 0;
- sms_debug("received %s(%d) size: %d",
+ pr_debug("received %s(%d) size: %d\n",
smscore_translate_msg(phdr->msg_type),
phdr->msg_type, phdr->msg_length);
@@ -134,12 +129,11 @@ static void smsusb_onresponse(struct urb *urb)
smscore_onresponse(dev->coredev, surb->cb);
surb->cb = NULL;
} else {
- sms_err("invalid response "
- "msglen %d actual %d",
+ pr_err("invalid response msglen %d actual %d\n",
phdr->msg_length, urb->actual_length);
}
} else
- sms_err("error, urb status %d, %d bytes",
+ pr_err("error, urb status %d, %d bytes\n",
urb->status, urb->actual_length);
@@ -153,7 +147,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
if (!surb->cb) {
surb->cb = smscore_getbuffer(dev->coredev);
if (!surb->cb) {
- sms_err("smscore_getbuffer(...) returned NULL");
+ pr_err("smscore_getbuffer(...) returned NULL\n");
return -ENOMEM;
}
}
@@ -194,7 +188,7 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev)
for (i = 0; i < MAX_URBS; i++) {
rc = smsusb_submit_urb(dev, &dev->surbs[i]);
if (rc < 0) {
- sms_err("smsusb_submit_urb(...) failed");
+ pr_err("smsusb_submit_urb(...) failed\n");
smsusb_stop_streaming(dev);
break;
}
@@ -210,11 +204,11 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
int dummy;
if (dev->state != SMSUSB_ACTIVE) {
- sms_debug("Device not active yet");
+ pr_debug("Device not active yet\n");
return -ENOENT;
}
- sms_debug("sending %s(%d) size: %d",
+ pr_debug("sending %s(%d) size: %d\n",
smscore_translate_msg(phdr->msg_type), phdr->msg_type,
phdr->msg_length);
@@ -249,7 +243,7 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
id = sms_get_board(board_id)->default_mode;
if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
- sms_err("invalid firmware id specified %d", id);
+ pr_err("invalid firmware id specified %d\n", id);
return -EINVAL;
}
@@ -257,13 +251,13 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
rc = request_firmware(&fw, fw_filename, &udev->dev);
if (rc < 0) {
- sms_warn("failed to open \"%s\" mode %d, "
- "trying again with default firmware", fw_filename, id);
+ pr_warn("failed to open '%s' mode %d, trying again with default firmware\n",
+ fw_filename, id);
fw_filename = smsusb1_fw_lkup[id];
rc = request_firmware(&fw, fw_filename, &udev->dev);
if (rc < 0) {
- sms_warn("failed to open \"%s\" mode %d",
+ pr_warn("failed to open '%s' mode %d\n",
fw_filename, id);
return rc;
@@ -277,14 +271,14 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
fw_buffer, fw->size, &dummy, 1000);
- sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc);
+ pr_debug("sent %zu(%d) bytes, rc %d\n", fw->size, dummy, rc);
kfree(fw_buffer);
} else {
- sms_err("failed to allocate firmware buffer");
+ pr_err("failed to allocate firmware buffer\n");
rc = -ENOMEM;
}
- sms_info("read FW %s, size=%zu", fw_filename, fw->size);
+ pr_debug("read FW %s, size=%zu\n", fw_filename, fw->size);
release_firmware(fw);
@@ -300,7 +294,7 @@ static void smsusb1_detectmode(void *context, int *mode)
if (!product_string) {
product_string = "none";
- sms_err("product string not found");
+ pr_err("product string not found\n");
} else if (strstr(product_string, "DVBH"))
*mode = 1;
else if (strstr(product_string, "BDA"))
@@ -310,7 +304,7 @@ static void smsusb1_detectmode(void *context, int *mode)
else if (strstr(product_string, "TDMB"))
*mode = 2;
- sms_info("%d \"%s\"", *mode, product_string);
+ pr_debug("%d \"%s\"\n", *mode, product_string);
}
static int smsusb1_setmode(void *context, int mode)
@@ -319,7 +313,7 @@ static int smsusb1_setmode(void *context, int mode)
sizeof(struct sms_msg_hdr), 0 };
if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
- sms_err("invalid firmware id specified %d", mode);
+ pr_err("invalid firmware id specified %d\n", mode);
return -EINVAL;
}
@@ -339,25 +333,61 @@ static void smsusb_term_device(struct usb_interface *intf)
if (dev->coredev)
smscore_unregister_device(dev->coredev);
- sms_info("device 0x%p destroyed", dev);
+ pr_debug("device 0x%p destroyed\n", dev);
kfree(dev);
}
usb_set_intfdata(intf, NULL);
}
+static void *siano_media_device_register(struct smsusb_device_t *dev,
+ int board_id)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct media_device *mdev;
+ struct usb_device *udev = dev->udev;
+ struct sms_board *board = sms_get_board(board_id);
+ int ret;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return NULL;
+
+ mdev->dev = &udev->dev;
+ strlcpy(mdev->model, board->name, sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strcpy(mdev->bus_info, udev->devpath);
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ ret = media_device_register(mdev);
+ if (ret) {
+ pr_err("Couldn't create a media device. Error: %d\n",
+ ret);
+ kfree(mdev);
+ return NULL;
+ }
+
+ pr_info("media controller created\n");
+
+ return mdev;
+#else
+ return NULL;
+#endif
+}
+
static int smsusb_init_device(struct usb_interface *intf, int board_id)
{
struct smsdevice_params_t params;
struct smsusb_device_t *dev;
+ void *mdev;
int i, rc;
/* create device object */
dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
- if (!dev) {
- sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
+ if (!dev)
return -ENOMEM;
- }
memset(&params, 0, sizeof(params));
usb_set_intfdata(intf, dev);
@@ -374,7 +404,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
params.detectmode_handler = smsusb1_detectmode;
break;
case SMS_UNKNOWN_TYPE:
- sms_err("Unspecified sms device type!");
+ pr_err("Unspecified sms device type!\n");
/* fall-thru */
default:
dev->buffer_size = USB2_BUFFER_SIZE;
@@ -393,7 +423,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
}
- sms_info("in_ep = %02x, out_ep = %02x",
+ pr_debug("in_ep = %02x, out_ep = %02x\n",
dev->in_ep, dev->out_ep);
params.device = &dev->udev->dev;
@@ -403,11 +433,17 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
params.context = dev;
usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
+ mdev = siano_media_device_register(dev, board_id);
+
/* register in smscore */
- rc = smscore_register_device(&params, &dev->coredev);
+ rc = smscore_register_device(&params, &dev->coredev, mdev);
if (rc < 0) {
- sms_err("smscore_register_device(...) failed, rc %d", rc);
+ pr_err("smscore_register_device(...) failed, rc %d\n", rc);
smsusb_term_device(intf);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ media_device_unregister(mdev);
+#endif
+ kfree(mdev);
return rc;
}
@@ -421,10 +457,10 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
usb_init_urb(&dev->surbs[i].urb);
}
- sms_info("smsusb_start_streaming(...).");
+ pr_debug("smsusb_start_streaming(...).\n");
rc = smsusb_start_streaming(dev);
if (rc < 0) {
- sms_err("smsusb_start_streaming(...) failed");
+ pr_err("smsusb_start_streaming(...) failed\n");
smsusb_term_device(intf);
return rc;
}
@@ -433,12 +469,12 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
rc = smscore_start_device(dev->coredev);
if (rc < 0) {
- sms_err("smscore_start_device(...) failed");
+ pr_err("smscore_start_device(...) failed\n");
smsusb_term_device(intf);
return rc;
}
- sms_info("device 0x%p created", dev);
+ pr_debug("device 0x%p created\n", dev);
return rc;
}
@@ -450,13 +486,13 @@ static int smsusb_probe(struct usb_interface *intf,
char devpath[32];
int i, rc;
- sms_info("board id=%lu, interface number %d",
+ pr_info("board id=%lu, interface number %d\n",
id->driver_info,
intf->cur_altsetting->desc.bInterfaceNumber);
if (sms_get_board(id->driver_info)->intf_num !=
intf->cur_altsetting->desc.bInterfaceNumber) {
- sms_debug("interface %d won't be used. Expecting interface %d to popup",
+ pr_debug("interface %d won't be used. Expecting interface %d to popup\n",
intf->cur_altsetting->desc.bInterfaceNumber,
sms_get_board(id->driver_info)->intf_num);
return -ENODEV;
@@ -467,15 +503,15 @@ static int smsusb_probe(struct usb_interface *intf,
intf->cur_altsetting->desc.bInterfaceNumber,
0);
if (rc < 0) {
- sms_err("usb_set_interface failed, rc %d", rc);
+ pr_err("usb_set_interface failed, rc %d\n", rc);
return rc;
}
}
- sms_info("smsusb_probe %d",
+ pr_debug("smsusb_probe %d\n",
intf->cur_altsetting->desc.bInterfaceNumber);
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
- sms_info("endpoint %d %02x %02x %d", i,
+ pr_debug("endpoint %d %02x %02x %d\n", i,
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
@@ -489,7 +525,7 @@ static int smsusb_probe(struct usb_interface *intf,
}
if ((udev->actconfig->desc.bNumInterfaces == 2) &&
(intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
- sms_debug("rom interface 0 is not used");
+ pr_debug("rom interface 0 is not used\n");
return -ENODEV;
}
@@ -498,23 +534,25 @@ static int smsusb_probe(struct usb_interface *intf,
snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
udev->bus->busnum, udev->devpath);
- sms_info("stellar device in cold state was found at %s.", devpath);
+ pr_info("stellar device in cold state was found at %s.\n",
+ devpath);
rc = smsusb1_load_firmware(
udev, smscore_registry_getmode(devpath),
id->driver_info);
/* This device will reset and gain another USB ID */
if (!rc)
- sms_info("stellar device now in warm state");
+ pr_info("stellar device now in warm state\n");
else
- sms_err("Failed to put stellar in warm state. Error: %d", rc);
+ pr_err("Failed to put stellar in warm state. Error: %d\n",
+ rc);
return rc;
} else {
rc = smsusb_init_device(intf, id->driver_info);
}
- sms_info("Device initialized with return code %d", rc);
+ pr_info("Device initialized with return code %d\n", rc);
sms_board_load_modules(id->driver_info);
return rc;
}
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 65a326c..749ad56 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -240,6 +240,11 @@ static int stk1160_stop_streaming(struct stk1160 *dev)
if (mutex_lock_interruptible(&dev->v4l_lock))
return -ERESTARTSYS;
+ /*
+ * Once URBs are cancelled, the URB complete handler
+ * won't be running. This is required to safely release the
+ * current buffer (dev->isoc_ctl.buf).
+ */
stk1160_cancel_isoc(dev);
/*
@@ -620,8 +625,16 @@ void stk1160_clear_queue(struct stk1160 *dev)
stk1160_info("buffer [%p/%d] aborted\n",
buf, buf->vb.v4l2_buf.index);
}
- /* It's important to clear current buffer */
- dev->isoc_ctl.buf = NULL;
+
+ /* It's important to release the current buffer */
+ if (dev->isoc_ctl.buf) {
+ buf = dev->isoc_ctl.buf;
+ dev->isoc_ctl.buf = NULL;
+
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ stk1160_info("buffer [%p/%d] aborted\n",
+ buf, buf->vb.v4l2_buf.index);
+ }
spin_unlock_irqrestore(&dev->buf_lock, flags);
}
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index e08fa58..c21c4c0 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -556,10 +556,8 @@ static int stk_free_sio_buffers(struct stk_camera *dev)
nbufs = dev->n_sbufs;
dev->n_sbufs = 0;
spin_unlock_irqrestore(&dev->spinlock, flags);
- for (i = 0; i < nbufs; i++) {
- if (dev->sio_bufs[i].buffer != NULL)
- vfree(dev->sio_bufs[i].buffer);
- }
+ for (i = 0; i < nbufs; i++)
+ vfree(dev->sio_bufs[i].buffer);
kfree(dev->sio_bufs);
dev->sio_bufs = NULL;
return 0;
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 0f14d3c..77ce9ef 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1576,7 +1576,7 @@ static struct video_device tm6000_template = {
.name = "tm6000",
.fops = &tm6000_fops,
.ioctl_ops = &video_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.tvnorms = TM6000_STD,
};
@@ -1609,25 +1609,19 @@ static struct video_device tm6000_radio_template = {
* ------------------------------------------------------------------
*/
-static struct video_device *vdev_init(struct tm6000_core *dev,
+static void vdev_init(struct tm6000_core *dev,
+ struct video_device *vfd,
const struct video_device
*template, const char *type_name)
{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
+ vfd->release = video_device_release_empty;
vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
video_set_drvdata(vfd, dev);
- return vfd;
}
int tm6000_v4l2_register(struct tm6000_core *dev)
@@ -1658,62 +1652,46 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
if (ret)
goto free_ctrl;
- dev->vfd = vdev_init(dev, &tm6000_template, "video");
+ vdev_init(dev, &dev->vfd, &tm6000_template, "video");
- if (!dev->vfd) {
- printk(KERN_INFO "%s: can't register video device\n",
- dev->name);
- ret = -ENOMEM;
- goto free_ctrl;
- }
- dev->vfd->ctrl_handler = &dev->ctrl_handler;
+ dev->vfd.ctrl_handler = &dev->ctrl_handler;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
- ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
+ ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0) {
printk(KERN_INFO "%s: can't register video device\n",
dev->name);
- video_device_release(dev->vfd);
- dev->vfd = NULL;
goto free_ctrl;
}
printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(dev->vfd));
+ dev->name, video_device_node_name(&dev->vfd));
if (dev->caps.has_radio) {
- dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
+ vdev_init(dev, &dev->radio_dev, &tm6000_radio_template,
"radio");
- if (!dev->radio_dev) {
- printk(KERN_INFO "%s: can't register radio device\n",
- dev->name);
- ret = -ENXIO;
- goto unreg_video;
- }
-
- dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
+ ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr);
if (ret < 0) {
printk(KERN_INFO "%s: can't register radio device\n",
dev->name);
- video_device_release(dev->radio_dev);
goto unreg_video;
}
printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(dev->radio_dev));
+ dev->name, video_device_node_name(&dev->radio_dev));
}
printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
return ret;
unreg_video:
- video_unregister_device(dev->vfd);
+ video_unregister_device(&dev->vfd);
free_ctrl:
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
@@ -1722,19 +1700,12 @@ free_ctrl:
int tm6000_v4l2_unregister(struct tm6000_core *dev)
{
- video_unregister_device(dev->vfd);
+ video_unregister_device(&dev->vfd);
/* if URB buffers are still allocated free them now */
tm6000_free_urb_buffers(dev);
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
-
+ video_unregister_device(&dev->radio_dev);
return 0;
}
diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h
index 08bd074..f212794 100644
--- a/drivers/media/usb/tm6000/tm6000.h
+++ b/drivers/media/usb/tm6000/tm6000.h
@@ -220,8 +220,8 @@ struct tm6000_core {
struct tm6000_fh *resources; /* Points to fh that is streaming */
bool is_res_read;
- struct video_device *vfd;
- struct video_device *radio_dev;
+ struct video_device vfd;
+ struct video_device radio_dev;
struct tm6000_dmaqueue vidq;
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index cd2fbf1..12b403e 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -471,7 +471,7 @@ static int vidioc_g_register(struct file *file, void *priv,
/* NT100x has a 8-bit register space */
err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
if (err_code < 0) {
- dev_err(&usbvision->vdev->dev,
+ dev_err(&usbvision->vdev.dev,
"%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
__func__, err_code);
return err_code;
@@ -490,7 +490,7 @@ static int vidioc_s_register(struct file *file, void *priv,
/* NT100x has a 8-bit register space */
err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
if (err_code < 0) {
- dev_err(&usbvision->vdev->dev,
+ dev_err(&usbvision->vdev.dev,
"%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
__func__, err_code);
return err_code;
@@ -1157,7 +1157,7 @@ static int usbvision_radio_open(struct file *file)
if (mutex_lock_interruptible(&usbvision->v4l2_lock))
return -ERESTARTSYS;
if (usbvision->user) {
- dev_err(&usbvision->rdev->dev,
+ dev_err(&usbvision->rdev.dev,
"%s: Someone tried to open an already opened USBVision Radio!\n",
__func__);
err_code = -EBUSY;
@@ -1280,7 +1280,7 @@ static struct video_device usbvision_video_template = {
.fops = &usbvision_fops,
.ioctl_ops = &usbvision_ioctl_ops,
.name = "usbvision-video",
- .release = video_device_release,
+ .release = video_device_release_empty,
.tvnorms = USBVISION_NORMS,
};
@@ -1312,58 +1312,46 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
static struct video_device usbvision_radio_template = {
.fops = &usbvision_radio_fops,
.name = "usbvision-radio",
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &usbvision_radio_ioctl_ops,
};
-static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
- struct video_device *vdev_template,
- char *name)
+static void usbvision_vdev_init(struct usb_usbvision *usbvision,
+ struct video_device *vdev,
+ const struct video_device *vdev_template,
+ const char *name)
{
struct usb_device *usb_dev = usbvision->dev;
- struct video_device *vdev;
if (usb_dev == NULL) {
dev_err(&usbvision->dev->dev,
"%s: usbvision->dev is not set\n", __func__);
- return NULL;
+ return;
}
- vdev = video_device_alloc();
- if (NULL == vdev)
- return NULL;
*vdev = *vdev_template;
vdev->lock = &usbvision->v4l2_lock;
vdev->v4l2_dev = &usbvision->v4l2_dev;
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
video_set_drvdata(vdev, usbvision);
- return vdev;
}
/* unregister video4linux devices */
static void usbvision_unregister_video(struct usb_usbvision *usbvision)
{
/* Radio Device: */
- if (usbvision->rdev) {
+ if (video_is_registered(&usbvision->rdev)) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
- video_device_node_name(usbvision->rdev));
- if (video_is_registered(usbvision->rdev))
- video_unregister_device(usbvision->rdev);
- else
- video_device_release(usbvision->rdev);
- usbvision->rdev = NULL;
+ video_device_node_name(&usbvision->rdev));
+ video_unregister_device(&usbvision->rdev);
}
/* Video Device: */
- if (usbvision->vdev) {
+ if (video_is_registered(&usbvision->vdev)) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
- video_device_node_name(usbvision->vdev));
- if (video_is_registered(usbvision->vdev))
- video_unregister_device(usbvision->vdev);
- else
- video_device_release(usbvision->vdev);
- usbvision->vdev = NULL;
+ video_device_node_name(&usbvision->vdev));
+ video_unregister_device(&usbvision->vdev);
}
}
@@ -1371,28 +1359,22 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
static int usbvision_register_video(struct usb_usbvision *usbvision)
{
/* Video Device: */
- usbvision->vdev = usbvision_vdev_init(usbvision,
- &usbvision_video_template,
- "USBVision Video");
- if (usbvision->vdev == NULL)
- goto err_exit;
- if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
+ usbvision_vdev_init(usbvision, &usbvision->vdev,
+ &usbvision_video_template, "USBVision Video");
+ if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
goto err_exit;
printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
- usbvision->nr, video_device_node_name(usbvision->vdev));
+ usbvision->nr, video_device_node_name(&usbvision->vdev));
/* Radio Device: */
if (usbvision_device_data[usbvision->dev_model].radio) {
/* usbvision has radio */
- usbvision->rdev = usbvision_vdev_init(usbvision,
- &usbvision_radio_template,
- "USBVision Radio");
- if (usbvision->rdev == NULL)
- goto err_exit;
- if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
+ usbvision_vdev_init(usbvision, &usbvision->rdev,
+ &usbvision_radio_template, "USBVision Radio");
+ if (video_register_device(&usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
goto err_exit;
printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
- usbvision->nr, video_device_node_name(usbvision->rdev));
+ usbvision->nr, video_device_node_name(&usbvision->rdev));
}
/* all done */
return 0;
@@ -1461,7 +1443,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
usbvision->initialized = 0;
- usbvision_remove_sysfs(usbvision->vdev);
+ usbvision_remove_sysfs(&usbvision->vdev);
usbvision_unregister_video(usbvision);
kfree(usbvision->alt_max_pkt_size);
@@ -1525,7 +1507,7 @@ static int usbvision_probe(struct usb_interface *intf,
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
- int model, i;
+ int model, i, ret;
PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor,
@@ -1534,7 +1516,8 @@ static int usbvision_probe(struct usb_interface *intf,
model = devid->driver_info;
if (model < 0 || model >= usbvision_device_data_size) {
PDEBUG(DBG_PROBE, "model out of bounds %d", model);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_usb;
}
printk(KERN_INFO "%s: %s found\n", __func__,
usbvision_device_data[model].model_string);
@@ -1549,18 +1532,21 @@ static int usbvision_probe(struct usb_interface *intf,
__func__, ifnum);
dev_err(&intf->dev, "%s: Endpoint attributes %d",
__func__, endpoint->bmAttributes);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_usb;
}
if (usb_endpoint_dir_out(endpoint)) {
dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n",
__func__, ifnum);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_usb;
}
usbvision = usbvision_alloc(dev, intf);
if (usbvision == NULL) {
dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_usb;
}
if (dev->descriptor.bNumConfigurations > 1)
@@ -1579,8 +1565,8 @@ static int usbvision_probe(struct usb_interface *intf,
usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
if (usbvision->alt_max_pkt_size == NULL) {
dev_err(&intf->dev, "usbvision: out of memory!\n");
- usbvision_release(usbvision);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_pkt;
}
for (i = 0; i < usbvision->num_alt; i++) {
@@ -1611,10 +1597,16 @@ static int usbvision_probe(struct usb_interface *intf,
usbvision_configure_video(usbvision);
usbvision_register_video(usbvision);
- usbvision_create_sysfs(usbvision->vdev);
+ usbvision_create_sysfs(&usbvision->vdev);
PDEBUG(DBG_PROBE, "success");
return 0;
+
+err_pkt:
+ usbvision_release(usbvision);
+err_usb:
+ usb_put_dev(dev);
+ return ret;
}
diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index 77aeb1e..140a1f6 100644
--- a/drivers/media/usb/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
@@ -357,8 +357,8 @@ extern struct usb_device_id usbvision_table[];
struct usb_usbvision {
struct v4l2_device v4l2_dev;
- struct video_device *vdev; /* Video Device */
- struct video_device *rdev; /* Radio Device */
+ struct video_device vdev; /* Video Device */
+ struct video_device rdev; /* Radio Device */
/* i2c Declaration Section*/
struct i2c_adapter i2c_adap;
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index cf27006..5970dd6 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1669,10 +1669,6 @@ static void uvc_delete(struct uvc_device *dev)
#ifdef CONFIG_MEDIA_CONTROLLER
uvc_mc_cleanup_entity(entity);
#endif
- if (entity->vdev) {
- video_device_release(entity->vdev);
- entity->vdev = NULL;
- }
kfree(entity);
}
@@ -1717,11 +1713,10 @@ static void uvc_unregister_video(struct uvc_device *dev)
atomic_inc(&dev->nstreams);
list_for_each_entry(stream, &dev->streams, list) {
- if (stream->vdev == NULL)
+ if (!video_is_registered(&stream->vdev))
continue;
- video_unregister_device(stream->vdev);
- stream->vdev = NULL;
+ video_unregister_device(&stream->vdev);
uvc_debugfs_cleanup_stream(stream);
}
@@ -1736,7 +1731,7 @@ static void uvc_unregister_video(struct uvc_device *dev)
static int uvc_register_video(struct uvc_device *dev,
struct uvc_streaming *stream)
{
- struct video_device *vdev;
+ struct video_device *vdev = &stream->vdev;
int ret;
/* Initialize the video buffers queue. */
@@ -1757,12 +1752,6 @@ static int uvc_register_video(struct uvc_device *dev,
uvc_debugfs_init_stream(stream);
/* Register the device with V4L. */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
- ret);
- return -ENOMEM;
- }
/* We already hold a reference to dev->udev. The video device will be
* unregistered before the reference is released, so we don't need to
@@ -1780,15 +1769,12 @@ static int uvc_register_video(struct uvc_device *dev,
/* Set the driver data before calling video_register_device, otherwise
* uvc_v4l2_open might race us.
*/
- stream->vdev = vdev;
video_set_drvdata(vdev, stream);
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
ret);
- stream->vdev = NULL;
- video_device_release(vdev);
return ret;
}
@@ -1827,7 +1813,7 @@ static int uvc_register_terms(struct uvc_device *dev,
if (ret < 0)
return ret;
- term->vdev = stream->vdev;
+ term->vdev = &stream->vdev;
}
return 0;
@@ -2461,6 +2447,14 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Aveo Technology USB 2.0 Camera (Tasco USB Microscope) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1871,
+ .idProduct = 0x0516,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
/* Ecamm Pico iMage */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 10c554e..87a19f3 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -306,25 +306,14 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_mmap(&queue->queue, vma);
- mutex_unlock(&queue->mutex);
-
- return ret;
+ return vb2_mmap(&queue->queue, vma);
}
#ifndef CONFIG_MMU
unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
unsigned long pgoff)
{
- unsigned long ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
- mutex_unlock(&queue->mutex);
- return ret;
+ return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
}
#endif
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 43e953f..c4b1ac6 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -511,7 +511,7 @@ static int uvc_v4l2_open(struct file *file)
stream->dev->users++;
mutex_unlock(&stream->dev->lock);
- v4l2_fh_init(&handle->vfh, stream->vdev);
+ v4l2_fh_init(&handle->vfh, &stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
handle->stream = stream;
@@ -882,6 +882,35 @@ static int uvc_ioctl_queryctrl(struct file *file, void *fh,
return uvc_query_v4l2_ctrl(chain, qc);
}
+static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
+ struct v4l2_query_ext_ctrl *qec)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ struct v4l2_queryctrl qc = { qec->id };
+ int ret;
+
+ ret = uvc_query_v4l2_ctrl(chain, &qc);
+ if (ret)
+ return ret;
+
+ qec->id = qc.id;
+ qec->type = qc.type;
+ strlcpy(qec->name, qc.name, sizeof(qec->name));
+ qec->minimum = qc.minimum;
+ qec->maximum = qc.maximum;
+ qec->step = qc.step;
+ qec->default_value = qc.default_value;
+ qec->flags = qc.flags;
+ qec->elem_size = 4;
+ qec->elems = 1;
+ qec->nr_of_dims = 0;
+ memset(qec->dims, 0, sizeof(qec->dims));
+ memset(qec->reserved, 0, sizeof(qec->reserved));
+
+ return 0;
+}
+
static int uvc_ioctl_g_ctrl(struct file *file, void *fh,
struct v4l2_control *ctrl)
{
@@ -1018,26 +1047,37 @@ static int uvc_ioctl_querymenu(struct file *file, void *fh,
return uvc_query_v4l2_menu(chain, qm);
}
-static int uvc_ioctl_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *ccap)
+static int uvc_ioctl_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
- if (ccap->type != stream->type)
+ if (sel->type != stream->type)
return -EINVAL;
- ccap->bounds.left = 0;
- ccap->bounds.top = 0;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (stream->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ if (stream->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sel->r.left = 0;
+ sel->r.top = 0;
mutex_lock(&stream->mutex);
- ccap->bounds.width = stream->cur_frame->wWidth;
- ccap->bounds.height = stream->cur_frame->wHeight;
+ sel->r.width = stream->cur_frame->wWidth;
+ sel->r.height = stream->cur_frame->wHeight;
mutex_unlock(&stream->mutex);
- ccap->defrect = ccap->bounds;
-
- ccap->pixelaspect.numerator = 1;
- ccap->pixelaspect.denominator = 1;
return 0;
}
@@ -1133,6 +1173,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
uvc_simplify_fraction(&fival->discrete.numerator,
&fival->discrete.denominator, 8, 333);
} else {
+ if (fival->index)
+ return -EINVAL;
+
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
fival->stepwise.min.numerator = frame->dwFrameInterval[0];
fival->stepwise.min.denominator = 10000000;
@@ -1443,13 +1486,14 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
.vidioc_g_input = uvc_ioctl_g_input,
.vidioc_s_input = uvc_ioctl_s_input,
.vidioc_queryctrl = uvc_ioctl_queryctrl,
+ .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl,
.vidioc_g_ctrl = uvc_ioctl_g_ctrl,
.vidioc_s_ctrl = uvc_ioctl_s_ctrl,
.vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls,
.vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls,
.vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls,
.vidioc_querymenu = uvc_ioctl_querymenu,
- .vidioc_cropcap = uvc_ioctl_cropcap,
+ .vidioc_g_selection = uvc_ioctl_g_selection,
.vidioc_g_parm = uvc_ioctl_g_parm,
.vidioc_s_parm = uvc_ioctl_s_parm,
.vidioc_enum_framesizes = uvc_ioctl_enum_framesizes,
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index c63e5b5..1b594c2 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -443,7 +443,7 @@ struct uvc_stats_stream {
struct uvc_streaming {
struct list_head list;
struct uvc_device *dev;
- struct video_device *vdev;
+ struct video_device vdev;
struct uvc_video_chain *chain;
atomic_t active;
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 559f837..abdcffa 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -134,6 +134,9 @@ struct tuner {
unsigned int type; /* chip type id */
void *config;
const char *name;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_pad pad;
+#endif
};
/*
@@ -434,6 +437,10 @@ static void set_type(struct i2c_client *c, unsigned int type,
t->name = analog_ops->info.name;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ t->sd.entity.name = t->name;
+#endif
+
tuner_dbg("type set to %s\n", t->name);
t->mode_mask = new_mode_mask;
@@ -592,6 +599,9 @@ static int tuner_probe(struct i2c_client *client,
struct tuner *t;
struct tuner *radio;
struct tuner *tv;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int ret;
+#endif
t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
if (NULL == t)
@@ -684,6 +694,18 @@ static int tuner_probe(struct i2c_client *client,
/* Should be just before return */
register_client:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ t->pad.flags = MEDIA_PAD_FL_SOURCE;
+ t->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_TUNER;
+ t->sd.entity.name = t->name;
+
+ ret = media_entity_init(&t->sd.entity, 1, &t->pad, 0);
+ if (ret < 0) {
+ tuner_err("failed to initialize media entity!\n");
+ kfree(t);
+ return -ENODEV;
+ }
+#endif
/* Sets a default mode */
if (t->mode_mask & T_ANALOG_TV)
t->mode = V4L2_TUNER_ANALOG_TV;
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
index e18cc04..34e416a 100644
--- a/drivers/media/v4l2-core/v4l2-clk.c
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -9,6 +9,7 @@
*/
#include <linux/atomic.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/list.h>
@@ -23,17 +24,13 @@
static DEFINE_MUTEX(clk_lock);
static LIST_HEAD(clk_list);
-static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
+static struct v4l2_clk *v4l2_clk_find(const char *dev_id)
{
struct v4l2_clk *clk;
- list_for_each_entry(clk, &clk_list, list) {
- if (strcmp(dev_id, clk->dev_id))
- continue;
-
- if (!id || !clk->id || !strcmp(clk->id, id))
+ list_for_each_entry(clk, &clk_list, list)
+ if (!strcmp(dev_id, clk->dev_id))
return clk;
- }
return ERR_PTR(-ENODEV);
}
@@ -41,9 +38,24 @@ static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
{
struct v4l2_clk *clk;
+ struct clk *ccf_clk = clk_get(dev, id);
+
+ if (PTR_ERR(ccf_clk) == -EPROBE_DEFER)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ if (!IS_ERR_OR_NULL(ccf_clk)) {
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk) {
+ clk_put(ccf_clk);
+ return ERR_PTR(-ENOMEM);
+ }
+ clk->clk = ccf_clk;
+
+ return clk;
+ }
mutex_lock(&clk_lock);
- clk = v4l2_clk_find(dev_name(dev), id);
+ clk = v4l2_clk_find(dev_name(dev));
if (!IS_ERR(clk))
atomic_inc(&clk->use_count);
@@ -60,6 +72,12 @@ void v4l2_clk_put(struct v4l2_clk *clk)
if (IS_ERR(clk))
return;
+ if (clk->clk) {
+ clk_put(clk->clk);
+ kfree(clk);
+ return;
+ }
+
mutex_lock(&clk_lock);
list_for_each_entry(tmp, &clk_list, list)
@@ -97,8 +115,12 @@ static void v4l2_clk_unlock_driver(struct v4l2_clk *clk)
int v4l2_clk_enable(struct v4l2_clk *clk)
{
- int ret = v4l2_clk_lock_driver(clk);
+ int ret;
+
+ if (clk->clk)
+ return clk_prepare_enable(clk->clk);
+ ret = v4l2_clk_lock_driver(clk);
if (ret < 0)
return ret;
@@ -124,11 +146,14 @@ void v4l2_clk_disable(struct v4l2_clk *clk)
{
int enable;
+ if (clk->clk)
+ return clk_disable_unprepare(clk->clk);
+
mutex_lock(&clk->lock);
enable = --clk->enable;
- if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__,
- clk->dev_id, clk->id))
+ if (WARN(enable < 0, "Unbalanced %s() on %s!\n", __func__,
+ clk->dev_id))
clk->enable++;
else if (!enable && clk->ops->disable)
clk->ops->disable(clk);
@@ -141,8 +166,12 @@ EXPORT_SYMBOL(v4l2_clk_disable);
unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk)
{
- int ret = v4l2_clk_lock_driver(clk);
+ int ret;
+
+ if (clk->clk)
+ return clk_get_rate(clk->clk);
+ ret = v4l2_clk_lock_driver(clk);
if (ret < 0)
return ret;
@@ -161,7 +190,16 @@ EXPORT_SYMBOL(v4l2_clk_get_rate);
int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate)
{
- int ret = v4l2_clk_lock_driver(clk);
+ int ret;
+
+ if (clk->clk) {
+ long r = clk_round_rate(clk->clk, rate);
+ if (r < 0)
+ return r;
+ return clk_set_rate(clk->clk, r);
+ }
+
+ ret = v4l2_clk_lock_driver(clk);
if (ret < 0)
return ret;
@@ -181,7 +219,7 @@ EXPORT_SYMBOL(v4l2_clk_set_rate);
struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
const char *dev_id,
- const char *id, void *priv)
+ void *priv)
{
struct v4l2_clk *clk;
int ret;
@@ -193,9 +231,8 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
if (!clk)
return ERR_PTR(-ENOMEM);
- clk->id = kstrdup(id, GFP_KERNEL);
clk->dev_id = kstrdup(dev_id, GFP_KERNEL);
- if ((id && !clk->id) || !clk->dev_id) {
+ if (!clk->dev_id) {
ret = -ENOMEM;
goto ealloc;
}
@@ -205,7 +242,7 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
mutex_init(&clk->lock);
mutex_lock(&clk_lock);
- if (!IS_ERR(v4l2_clk_find(dev_id, id))) {
+ if (!IS_ERR(v4l2_clk_find(dev_id))) {
mutex_unlock(&clk_lock);
ret = -EEXIST;
goto eexist;
@@ -217,7 +254,6 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
eexist:
ealloc:
- kfree(clk->id);
kfree(clk->dev_id);
kfree(clk);
return ERR_PTR(ret);
@@ -227,15 +263,14 @@ EXPORT_SYMBOL(v4l2_clk_register);
void v4l2_clk_unregister(struct v4l2_clk *clk)
{
if (WARN(atomic_read(&clk->use_count),
- "%s(): Refusing to unregister ref-counted %s:%s clock!\n",
- __func__, clk->dev_id, clk->id))
+ "%s(): Refusing to unregister ref-counted %s clock!\n",
+ __func__, clk->dev_id))
return;
mutex_lock(&clk_lock);
list_del(&clk->list);
mutex_unlock(&clk_lock);
- kfree(clk->id);
kfree(clk->dev_id);
kfree(clk);
}
@@ -253,7 +288,7 @@ static unsigned long fixed_get_rate(struct v4l2_clk *clk)
}
struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id,
- const char *id, unsigned long rate, struct module *owner)
+ unsigned long rate, struct module *owner)
{
struct v4l2_clk *clk;
struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -265,7 +300,7 @@ struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id,
priv->ops.get_rate = fixed_get_rate;
priv->ops.owner = owner;
- clk = v4l2_clk_register(&priv->ops, dev_id, id, priv);
+ clk = v4l2_clk_register(&priv->ops, dev_id, priv);
if (IS_ERR(clk))
kfree(priv);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 45c5b47..e3a3468 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -991,7 +991,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_AUTO_FOCUS_START:
case V4L2_CID_AUTO_FOCUS_STOP:
*type = V4L2_CTRL_TYPE_BUTTON;
- *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
*min = *max = *step = *def = 0;
break;
case V4L2_CID_POWER_LINE_FREQUENCY:
@@ -1172,7 +1173,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_FOCUS_RELATIVE:
case V4L2_CID_IRIS_RELATIVE:
case V4L2_CID_ZOOM_RELATIVE:
- *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
break;
case V4L2_CID_FLASH_STROBE_STATUS:
case V4L2_CID_AUTO_FOCUS_STATUS:
@@ -1609,6 +1611,19 @@ static int cluster_changed(struct v4l2_ctrl *master)
if (ctrl == NULL)
continue;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE)
+ changed = ctrl_changed = true;
+
+ /*
+ * Set has_changed to false to avoid generating
+ * the event V4L2_EVENT_CTRL_CH_VALUE
+ */
+ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+ ctrl->has_changed = false;
+ continue;
+ }
+
for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
ctrl->p_cur, ctrl->p_new);
@@ -1974,7 +1989,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
sz_extra = 0;
if (type == V4L2_CTRL_TYPE_BUTTON)
- flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
flags |= V4L2_CTRL_FLAG_READ_ONLY;
else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 86bb93f..71a1b93 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -357,34 +357,6 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (lock)
mutex_unlock(lock);
- } else if (vdev->fops->ioctl) {
- /* This code path is a replacement for the BKL. It is a major
- * hack but it will have to do for those drivers that are not
- * yet converted to use unlocked_ioctl.
- *
- * All drivers implement struct v4l2_device, so we use the
- * lock defined there to serialize the ioctls.
- *
- * However, if the driver sleeps, then it blocks all ioctls
- * since the lock is still held. This is very common for
- * VIDIOC_DQBUF since that normally waits for a frame to arrive.
- * As a result any other ioctl calls will proceed very, very
- * slowly since each call will have to wait for the VIDIOC_QBUF
- * to finish. Things that should take 0.01s may now take 10-20
- * seconds.
- *
- * The workaround is to *not* take the lock for VIDIOC_DQBUF.
- * This actually works OK for videobuf-based drivers, since
- * videobuf will take its own internal lock.
- */
- struct mutex *m = &vdev->v4l2_dev->ioctl_lock;
-
- if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->ioctl(filp, cmd, arg);
- if (cmd != VIDIOC_DQBUF)
- mutex_unlock(m);
} else
ret = -ENOTTY;
@@ -560,10 +532,9 @@ static void determine_valid_ioctls(struct video_device *vdev)
/* vfl_type and vfl_dir independent ioctls */
SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
- if (ops->vidioc_g_priority)
- set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
- if (ops->vidioc_s_priority)
- set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
+
/* Note: the control handler can also be passed through the filehandle,
and that can't be tested here. If the bit for these control ioctls
is set, then the ioctl is valid. But if it is 0, then it can still
@@ -640,6 +611,14 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
+ if (ops->vidioc_g_crop || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
+ if (ops->vidioc_s_crop || ops->vidioc_s_selection)
+ set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
+ SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
+ if (ops->vidioc_cropcap || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
} else if (is_vbi) {
/* vbi specific ioctls */
if ((is_rx && (ops->vidioc_g_fmt_vbi_cap ||
@@ -708,14 +687,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
}
- if (ops->vidioc_g_crop || ops->vidioc_g_selection)
- set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
- if (ops->vidioc_s_crop || ops->vidioc_s_selection)
- set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
- SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
- if (ops->vidioc_cropcap || ops->vidioc_g_selection)
- set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
ops->vidioc_g_std))
set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
@@ -943,8 +914,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->vfl_type != VFL_TYPE_SUBDEV) {
vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
vdev->entity.name = vdev->name;
- vdev->entity.info.v4l.major = VIDEO_MAJOR;
- vdev->entity.info.v4l.minor = vdev->minor;
+ vdev->entity.info.dev.major = VIDEO_MAJOR;
+ vdev->entity.info.dev.minor = vdev->minor;
ret = media_device_register_entity(vdev->v4l2_dev->mdev,
&vdev->entity);
if (ret < 0)
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 015f92a..5b0a30b 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -37,7 +37,6 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
- mutex_init(&v4l2_dev->ioctl_lock);
v4l2_prio_init(&v4l2_dev->prio);
kref_init(&v4l2_dev->ref);
get_device(dev);
@@ -248,8 +247,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
goto clean_up;
}
#if defined(CONFIG_MEDIA_CONTROLLER)
- sd->entity.info.v4l.major = VIDEO_MAJOR;
- sd->entity.info.v4l.minor = vdev->minor;
+ sd->entity.info.dev.major = VIDEO_MAJOR;
+ sd->entity.info.dev.minor = vdev->minor;
#endif
sd->devnode = vdev;
}
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index b1d8dbb..c0e9638 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -282,7 +282,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix,
(bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
bt->vsync, bt->vbackporch);
pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock);
- pr_info("%s: flags (0x%x):%s%s%s%s\n", dev_prefix, bt->flags,
+ pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags,
(bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ?
" REDUCED_BLANKING" : "",
(bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ?
@@ -290,7 +290,9 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix,
(bt->flags & V4L2_DV_FL_REDUCED_FPS) ?
" REDUCED_FPS" : "",
(bt->flags & V4L2_DV_FL_HALF_LINE) ?
- " HALF_LINE" : "");
+ " HALF_LINE" : "",
+ (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ?
+ " CE_VIDEO" : "");
pr_info("%s: standards (0x%x):%s%s%s%s\n", dev_prefix, bt->standards,
(bt->standards & V4L2_DV_BT_STD_CEA861) ? " CEA" : "",
(bt->standards & V4L2_DV_BT_STD_DMT) ? " DMT" : "",
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index b084072..aa407cb 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -257,7 +257,7 @@ static void v4l_print_format(const void *arg, bool write_only)
pr_cont(", width=%u, height=%u, "
"pixelformat=%c%c%c%c, field=%s, "
"bytesperline=%u, sizeimage=%u, colorspace=%d, "
- "flags %x, ycbcr_enc=%u, quantization=%u\n",
+ "flags=0x%x, ycbcr_enc=%u, quantization=%u\n",
pix->width, pix->height,
(pix->pixelformat & 0xff),
(pix->pixelformat >> 8) & 0xff,
@@ -273,7 +273,7 @@ static void v4l_print_format(const void *arg, bool write_only)
mp = &p->fmt.pix_mp;
pr_cont(", width=%u, height=%u, "
"format=%c%c%c%c, field=%s, "
- "colorspace=%d, num_planes=%u, flags=%x, "
+ "colorspace=%d, num_planes=%u, flags=0x%x, "
"ycbcr_enc=%u, quantization=%u\n",
mp->width, mp->height,
(mp->pixelformat & 0xff),
@@ -901,6 +901,8 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
*/
if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
return 0;
+ if (c->ctrl_class == 0)
+ return 1;
/* Check that all controls are from the same control class. */
for (i = 0; i < c->count; i++) {
if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
@@ -1046,8 +1048,6 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops,
struct video_device *vfd;
u32 *p = arg;
- if (ops->vidioc_g_priority)
- return ops->vidioc_g_priority(file, fh, arg);
vfd = video_devdata(file);
*p = v4l2_prio_max(vfd->prio);
return 0;
@@ -1060,9 +1060,9 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,
struct v4l2_fh *vfh;
u32 *p = arg;
- if (ops->vidioc_s_priority)
- return ops->vidioc_s_priority(file, fh, *p);
vfd = video_devdata(file);
+ if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
+ return -ENOTTY;
vfh = file->private_data;
return v4l2_prio_change(vfd->prio, &vfh->prio, *p);
}
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 80c588f..73824a5 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL(v4l2_m2m_get_vq);
*/
void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx)
{
- struct v4l2_m2m_buffer *b = NULL;
+ struct v4l2_m2m_buffer *b;
unsigned long flags;
spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf);
*/
void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx)
{
- struct v4l2_m2m_buffer *b = NULL;
+ struct v4l2_m2m_buffer *b;
unsigned long flags;
spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
index b4ed9a9..83143d3 100644
--- a/drivers/media/v4l2-core/v4l2-of.c
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -19,11 +19,10 @@
#include <media/v4l2-of.h>
-static void v4l2_of_parse_csi_bus(const struct device_node *node,
- struct v4l2_of_endpoint *endpoint)
+static int v4l2_of_parse_csi_bus(const struct device_node *node,
+ struct v4l2_of_endpoint *endpoint)
{
struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2;
- u32 data_lanes[ARRAY_SIZE(bus->data_lanes)];
struct property *prop;
bool have_clk_lane = false;
unsigned int flags = 0;
@@ -32,16 +31,34 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node,
prop = of_find_property(node, "data-lanes", NULL);
if (prop) {
const __be32 *lane = NULL;
- int i;
+ unsigned int i;
- for (i = 0; i < ARRAY_SIZE(data_lanes); i++) {
- lane = of_prop_next_u32(prop, lane, &data_lanes[i]);
+ for (i = 0; i < ARRAY_SIZE(bus->data_lanes); i++) {
+ lane = of_prop_next_u32(prop, lane, &v);
if (!lane)
break;
+ bus->data_lanes[i] = v;
}
bus->num_data_lanes = i;
- while (i--)
- bus->data_lanes[i] = data_lanes[i];
+ }
+
+ prop = of_find_property(node, "lane-polarities", NULL);
+ if (prop) {
+ const __be32 *polarity = NULL;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(bus->lane_polarities); i++) {
+ polarity = of_prop_next_u32(prop, polarity, &v);
+ if (!polarity)
+ break;
+ bus->lane_polarities[i] = v;
+ }
+
+ if (i < 1 + bus->num_data_lanes /* clock + data */) {
+ pr_warn("%s: too few lane-polarities entries (need %u, got %u)\n",
+ node->full_name, 1 + bus->num_data_lanes, i);
+ return -EINVAL;
+ }
}
if (!of_property_read_u32(node, "clock-lanes", &v)) {
@@ -56,6 +73,8 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node,
bus->flags = flags;
endpoint->bus_type = V4L2_MBUS_CSI2;
+
+ return 0;
}
static void v4l2_of_parse_parallel_bus(const struct device_node *node,
@@ -127,11 +146,15 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
int v4l2_of_parse_endpoint(const struct device_node *node,
struct v4l2_of_endpoint *endpoint)
{
+ int rval;
+
of_graph_parse_endpoint(node, &endpoint->base);
endpoint->bus_type = 0;
memset(&endpoint->bus, 0, sizeof(endpoint->bus));
- v4l2_of_parse_csi_bus(node, endpoint);
+ rval = v4l2_of_parse_csi_bus(node, endpoint);
+ if (rval)
+ return rval;
/*
* Parse the parallel video bus properties only if none
* of the MIPI CSI-2 specific properties were found.
@@ -142,3 +165,64 @@ int v4l2_of_parse_endpoint(const struct device_node *node,
return 0;
}
EXPORT_SYMBOL(v4l2_of_parse_endpoint);
+
+/**
+ * v4l2_of_parse_link() - parse a link between two endpoints
+ * @node: pointer to the endpoint at the local end of the link
+ * @link: pointer to the V4L2 OF link data structure
+ *
+ * Fill the link structure with the local and remote nodes and port numbers.
+ * The local_node and remote_node fields are set to point to the local and
+ * remote port's parent nodes respectively (the port parent node being the
+ * parent node of the port node if that node isn't a 'ports' node, or the
+ * grand-parent node of the port node otherwise).
+ *
+ * A reference is taken to both the local and remote nodes, the caller must use
+ * v4l2_of_put_link() to drop the references when done with the link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote endpoint can't be found.
+ */
+int v4l2_of_parse_link(const struct device_node *node,
+ struct v4l2_of_link *link)
+{
+ struct device_node *np;
+
+ memset(link, 0, sizeof(*link));
+
+ np = of_get_parent(node);
+ of_property_read_u32(np, "reg", &link->local_port);
+ np = of_get_next_parent(np);
+ if (of_node_cmp(np->name, "ports") == 0)
+ np = of_get_next_parent(np);
+ link->local_node = np;
+
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np) {
+ of_node_put(link->local_node);
+ return -ENOLINK;
+ }
+
+ np = of_get_parent(np);
+ of_property_read_u32(np, "reg", &link->remote_port);
+ np = of_get_next_parent(np);
+ if (of_node_cmp(np->name, "ports") == 0)
+ np = of_get_next_parent(np);
+ link->remote_node = np;
+
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_of_parse_link);
+
+/**
+ * v4l2_of_put_link() - drop references to nodes in a link
+ * @link: pointer to the V4L2 OF link data structure
+ *
+ * Drop references to the local and remote nodes in the link. This function must
+ * be called on every link parsed with v4l2_of_parse_link().
+ */
+void v4l2_of_put_link(struct v4l2_of_link *link)
+{
+ of_node_put(link->local_node);
+ of_node_put(link->remote_node);
+}
+EXPORT_SYMBOL(v4l2_of_put_link);
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 19a034e..6359606 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -93,8 +93,7 @@ static int subdev_open(struct file *file)
err:
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (entity)
- media_entity_put(entity);
+ media_entity_put(entity);
#endif
v4l2_fh_del(&subdev_fh->vfh);
v4l2_fh_exit(&subdev_fh->vfh);
@@ -262,7 +261,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
- return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format);
+ return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
}
case VIDIOC_SUBDEV_S_FMT: {
@@ -272,7 +271,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
- return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
+ return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
}
case VIDIOC_SUBDEV_G_CROP: {
@@ -289,7 +288,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.target = V4L2_SEL_TGT_CROP;
rval = v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh, &sel);
+ sd, pad, get_selection, subdev_fh->pad, &sel);
crop->rect = sel.r;
@@ -311,7 +310,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.r = crop->rect;
rval = v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh, &sel);
+ sd, pad, set_selection, subdev_fh->pad, &sel);
crop->rect = sel.r;
@@ -321,20 +320,28 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_mbus_code_enum *code = arg;
+ if (code->which != V4L2_SUBDEV_FORMAT_TRY &&
+ code->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (code->pad >= sd->entity.num_pads)
return -EINVAL;
- return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh,
+ return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
code);
}
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
struct v4l2_subdev_frame_size_enum *fse = arg;
+ if (fse->which != V4L2_SUBDEV_FORMAT_TRY &&
+ fse->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fse->pad >= sd->entity.num_pads)
return -EINVAL;
- return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
+ return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
fse);
}
@@ -359,10 +366,14 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval_enum *fie = arg;
+ if (fie->which != V4L2_SUBDEV_FORMAT_TRY &&
+ fie->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fie->pad >= sd->entity.num_pads)
return -EINVAL;
- return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
+ return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
fie);
}
@@ -374,7 +385,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return rval;
return v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh, sel);
+ sd, pad, get_selection, subdev_fh->pad, sel);
}
case VIDIOC_SUBDEV_S_SELECTION: {
@@ -385,7 +396,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return rval;
return v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh, sel);
+ sd, pad, set_selection, subdev_fh->pad, sel);
}
case VIDIOC_G_EDID: {
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index cc16e76..66ada01 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1247,6 +1247,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
{
unsigned int plane;
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ if (WARN_ON_ONCE(b->bytesused == 0)) {
+ pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n");
+ if (vb->vb2_queue->allow_zero_bytesused)
+ pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
+ else
+ pr_warn_once("use the actual size instead.\n");
+ }
+ }
+
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
if (b->memory == V4L2_MEMORY_USERPTR) {
for (plane = 0; plane < vb->num_planes; ++plane) {
@@ -1276,13 +1286,22 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
* userspace clearly never bothered to set it and
* it's a safe assumption that they really meant to
* use the full plane sizes.
+ *
+ * Some drivers, e.g. old codec drivers, use bytesused == 0
+ * as a way to indicate that streaming is finished.
+ * In that case, the driver should use the
+ * allow_zero_bytesused flag to keep old userspace
+ * applications working.
*/
for (plane = 0; plane < vb->num_planes; ++plane) {
struct v4l2_plane *pdst = &v4l2_planes[plane];
struct v4l2_plane *psrc = &b->m.planes[plane];
- pdst->bytesused = psrc->bytesused ?
- psrc->bytesused : pdst->length;
+ if (vb->vb2_queue->allow_zero_bytesused)
+ pdst->bytesused = psrc->bytesused;
+ else
+ pdst->bytesused = psrc->bytesused ?
+ psrc->bytesused : pdst->length;
pdst->data_offset = psrc->data_offset;
}
}
@@ -1295,6 +1314,11 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
*
* If bytesused == 0 for the output buffer, then fall back
* to the full buffer size as that's a sensible default.
+ *
+ * Some drivers, e.g. old codec drivers, use bytesused == 0 as
+ * a way to indicate that streaming is finished. In that case,
+ * the driver should use the allow_zero_bytesused flag to keep
+ * old userspace applications working.
*/
if (b->memory == V4L2_MEMORY_USERPTR) {
v4l2_planes[0].m.userptr = b->m.userptr;
@@ -1306,10 +1330,13 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
v4l2_planes[0].length = b->length;
}
- if (V4L2_TYPE_IS_OUTPUT(b->type))
- v4l2_planes[0].bytesused = b->bytesused ?
- b->bytesused : v4l2_planes[0].length;
- else
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ if (vb->vb2_queue->allow_zero_bytesused)
+ v4l2_planes[0].bytesused = b->bytesused;
+ else
+ v4l2_planes[0].bytesused = b->bytesused ?
+ b->bytesused : v4l2_planes[0].length;
+ } else
v4l2_planes[0].bytesused = 0;
}
@@ -2760,7 +2787,8 @@ struct vb2_fileio_data {
unsigned int initial_index;
unsigned int q_count;
unsigned int dq_count;
- unsigned int flags;
+ unsigned read_once:1;
+ unsigned write_immediately:1;
};
/**
@@ -2798,14 +2826,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
*/
count = 1;
- dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n",
- (read) ? "read" : "write", count, q->io_flags);
+ dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
+ (read) ? "read" : "write", count, q->fileio_read_once,
+ q->fileio_write_immediately);
fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
if (fileio == NULL)
return -ENOMEM;
- fileio->flags = q->io_flags;
+ fileio->read_once = q->fileio_read_once;
+ fileio->write_immediately = q->fileio_write_immediately;
/*
* Request buffers and use MMAP type to force driver
@@ -3028,13 +3058,11 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
/*
* Queue next buffer if required.
*/
- if (buf->pos == buf->size ||
- (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) {
+ if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
/*
* Check if this is the last buffer to read.
*/
- if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
- fileio->dq_count == 1) {
+ if (read && fileio->read_once && fileio->dq_count == 1) {
dprintk(3, "read limit reached\n");
return __vb2_cleanup_fileio(q);
}
@@ -3225,7 +3253,6 @@ EXPORT_SYMBOL_GPL(vb2_thread_start);
int vb2_thread_stop(struct vb2_queue *q)
{
struct vb2_threadio_data *threadio = q->threadio;
- struct vb2_fileio_data *fileio = q->fileio;
int err;
if (threadio == NULL)
@@ -3411,6 +3438,8 @@ ssize_t vb2_fop_write(struct file *file, const char __user *buf,
struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
int err = -EBUSY;
+ if (!(vdev->queue->io_modes & VB2_WRITE))
+ return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
@@ -3433,6 +3462,8 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
int err = -EBUSY;
+ if (!(vdev->queue->io_modes & VB2_READ))
+ return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
OpenPOWER on IntegriCloud