/tools/perf/scripts/python/

tion>
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h3
-rw-r--r--drivers/media/dvb-frontends/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/si2168.c746
-rw-r--r--drivers/media/dvb-frontends/si2168.h39
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h46
-rw-r--r--drivers/media/dvb-frontends/tda10071.c12
-rw-r--r--drivers/media/dvb-frontends/tda10071_priv.h1
-rw-r--r--drivers/media/i2c/ad9389b.c64
-rw-r--r--drivers/media/i2c/adv7180.c2
-rw-r--r--drivers/media/i2c/adv7183.c4
-rw-r--r--drivers/media/i2c/adv7511.c66
-rw-r--r--drivers/media/i2c/adv7604.c1468
-rw-r--r--drivers/media/i2c/adv7842.c28
-rw-r--r--drivers/media/i2c/bt819.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c4
-rw-r--r--drivers/media/i2c/ks0127.c6
-rw-r--r--drivers/media/i2c/m5mols/m5mols_capture.c2
-rw-r--r--drivers/media/i2c/ml86v7667.c2
-rw-r--r--drivers/media/i2c/msp3400-driver.c2
-rw-r--r--drivers/media/i2c/mt9p031.c53
-rw-r--r--drivers/media/i2c/ov7670.c2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c2
-rw-r--r--drivers/media/i2c/saa6752hs.c2
-rw-r--r--drivers/media/i2c/saa7110.c2
-rw-r--r--drivers/media/i2c/saa7115.c2
-rw-r--r--drivers/media/i2c/saa717x.c2
-rw-r--r--drivers/media/i2c/saa7191.c2
-rw-r--r--drivers/media/i2c/smiapp-pll.h2
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c57
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.c55
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.h24
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg-defs.h8
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.c89
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.h19
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c11
-rw-r--r--drivers/media/i2c/sony-btf-mpx.c10
-rw-r--r--drivers/media/i2c/ths8200.c10
-rw-r--r--drivers/media/i2c/tvaudio.c6
-rw-r--r--drivers/media/i2c/tvp514x.c2
-rw-r--r--drivers/media/i2c/tvp5150.c6
-rw-r--r--drivers/media/i2c/tvp7002.c5
-rw-r--r--drivers/media/i2c/tw2804.c2
-rw-r--r--drivers/media/i2c/tw9903.c2
-rw-r--r--drivers/media/i2c/tw9906.c2
-rw-r--r--drivers/media/i2c/vp27smpx.c6
-rw-r--r--drivers/media/i2c/vpx3220.c2
-rw-r--r--drivers/media/media-device.c8
-rw-r--r--drivers/media/media-devnode.c5
-rw-r--r--drivers/media/parport/bw-qcam.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c110
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv.h1
-rw-r--r--drivers/media/pci/bt8xx/dst.c20
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c2
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/pci/cx18/cx18-gpio.c6
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.c6
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c2
-rw-r--r--drivers/media/pci/saa7134/Kconfig4
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c107
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c130
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c50
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c189
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c7
-rw-r--r--drivers/media/pci/saa7134/saa7134-reg.h12
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c191
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c7
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c175
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c697
-rw-r--r--drivers/media/pci/saa7134/saa7134.h108
-rw-r--r--drivers/media/pci/saa7146/mxb.c14
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c7
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c6
-rw-r--r--drivers/media/pci/zoran/zoran_device.c2
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c2
-rw-r--r--drivers/media/platform/Kconfig4
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c14
-rw-r--r--drivers/media/platform/coda.c6
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c71
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c17
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c1148
-rw-r--r--drivers/media/platform/davinci/vpif_capture.h28
-rw-r--r--drivers/media/platform/davinci/vpif_display.c1236
-rw-r--r--drivers/media/platform/davinci/vpif_display.h44
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig3
-rw-r--r--drivers/media/platform/exynos4-is/common.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c7
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c9
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c329
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h2
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c43
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c7
-rw-r--r--drivers/media/platform/mem2mem_testdev.c5
-rw-r--r--drivers/media/platform/mx2_emmaprp.c37
-rw-r--r--drivers/media/platform/omap3isp/Makefile2
-rw-r--r--drivers/media/platform/omap3isp/isp.c108
-rw-r--r--drivers/media/platform/omap3isp/isp.h8
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c107
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.h16
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c4
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c4
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c2
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c2
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c8
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c1161
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h188
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c8
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c197
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h3
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c325
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h29
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c4
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c122
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h6
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v6.h4
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v7.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v8.h124
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c79
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h15
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c62
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h3
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c290
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c96
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h254
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c842
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h7
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c14
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c9
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c11
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c6
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c4
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c12
-rw-r--r--drivers/media/platform/ti-vpe/csc.c6
-rw-r--r--drivers/media/platform/ti-vpe/sc.c4
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c68
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.h17
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c227
-rw-r--r--drivers/media/platform/timblogiw.c10
-rw-r--r--drivers/media/platform/vino.c6
-rw-r--r--drivers/media/platform/vivi.c3
-rw-r--r--drivers/media/platform/vsp1/Makefile2
-rw-r--r--drivers/media/platform/vsp1/vsp1.h3
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c395
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.h39
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c101
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c57
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h24
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c7
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h98
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c7
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h4
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c30
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c13
-rw-r--r--drivers/media/rc/mceusb.c65
-rw-r--r--drivers/media/rc/redrat3.c102
-rw-r--r--drivers/media/rc/streamzap.c9
-rw-r--r--drivers/media/tuners/Kconfig7
-rw-r--r--drivers/media/tuners/Makefile1
-rw-r--r--drivers/media/tuners/fc2580.c6
-rw-r--r--drivers/media/tuners/fc2580_priv.h1
-rw-r--r--drivers/media/tuners/si2157.c260
-rw-r--r--drivers/media/tuners/si2157.h34
-rw-r--r--drivers/media/tuners/si2157_priv.h37
-rw-r--r--drivers/media/tuners/xc5000.c302
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c57
-rw-r--r--drivers/media/usb/au0828/au0828-video.c4
-rw-r--r--drivers/media/usb/au0828/au0828.h2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile1
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c40
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c54
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c7
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c43
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c2
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c28
-rw-r--r--drivers/media/usb/em28xx/Kconfig2
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c39
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c51
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c47
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c89
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h2
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c622
-rw-r--r--drivers/media/usb/em28xx/em28xx.h153
-rw-r--r--drivers/media/usb/gspca/Kconfig10
-rw-r--r--drivers/media/usb/gspca/Makefile2
-rw-r--r--drivers/media/usb/gspca/dtcs033.c441
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-mi2020.c464
-rw-r--r--drivers/media/usb/gspca/pac7302.c1
-rw-r--r--drivers/media/usb/gspca/sonixb.c2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/usb/pwc/pwc-if.c7
-rw-r--r--drivers/media/usb/s2255/s2255drv.c11
-rw-r--r--drivers/media/usb/stk1160/stk1160-core.c10
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c8
-rw-r--r--drivers/media/usb/stk1160/stk1160.h1
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c2
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c9
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/usb/uvc/uvc_video.c36
-rw-r--r--drivers/media/v4l2-core/Kconfig4
-rw-r--r--drivers/media/v4l2-core/Makefile1
-rw-r--r--drivers/media/v4l2-core/tuner-core.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c18
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c15
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c36
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c67
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c2
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c730
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c2
-rw-r--r--drivers/media/v4l2-core/videobuf2-dvb.c336
244 files changed, 9946 insertions, 7520 deletions
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 1bdc0e7e8b7..11d2bea23b0 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -356,11 +356,13 @@
#define USB_PID_ELGATO_EYETV_DTT_2 0x003f
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
#define USB_PID_ELGATO_EYETV_SAT 0x002a
+#define USB_PID_ELGATO_EYETV_SAT_V2 0x0025
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
#define USB_PID_FRIIO_WHITE 0x0001
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
+#define USB_PID_SVEON_STV20_RTL2832U 0xd39d
#define USB_PID_SVEON_STV22 0xe401
#define USB_PID_SVEON_STV22_IT9137 0xe411
#define USB_PID_AZUREWAVE_AZ6027 0x3275
@@ -375,4 +377,5 @@
#define USB_PID_CTVDIGDUAL_V2 0xe410
#define USB_PID_PCTV_2002E 0x025c
#define USB_PID_PCTV_2002E_SE 0x025d
+#define USB_PID_SVEON_STV27 0xd3af
#endif
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 025fc5496bf..1469d44acb2 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -446,6 +446,13 @@ config DVB_RTL2832
help
Say Y when you want to support this frontend.
+config DVB_SI2168
+ tristate "Silicon Labs Si2168"
+ depends on DVB_CORE && I2C && I2C_MUX
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 282aba2fe8d..dda0bee36f2 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_DVB_AF9013) += af9013.o
obj-$(CONFIG_DVB_CX24116) += cx24116.o
obj-$(CONFIG_DVB_CX24117) += cx24117.o
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_SI2168) += si2168.o
obj-$(CONFIG_DVB_STV0288) += stv0288.o
obj-$(CONFIG_DVB_STB6000) += stb6000.o
obj-$(CONFIG_DVB_S921) += s921.o
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
new file mode 100644
index 00000000000..2e3cdcfa0a6
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -0,0 +1,746 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 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.
+ */
+
+#include "si2168_priv.h"
+
+static const struct dvb_frontend_ops si2168_ops;
+
+/* execute firmware command */
+static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
+{
+ int ret;
+ unsigned long timeout;
+
+ mutex_lock(&s->i2c_mutex);
+
+ if (cmd->wlen) {
+ /* write cmd and args for firmware */
+ ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->wlen) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+ }
+
+ if (cmd->rlen) {
+ /* wait cmd execution terminate */
+ #define TIMEOUT 50
+ timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+ while (!time_after(jiffies, timeout)) {
+ ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->rlen) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* firmware ready? */
+ if ((cmd->args[0] >> 7) & 0x01)
+ break;
+ }
+
+ dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
+ __func__,
+ jiffies_to_msecs(jiffies) -
+ (jiffies_to_msecs(timeout) - TIMEOUT));
+
+ if (!((cmd->args[0] >> 7) & 0x01)) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ }
+ }
+
+ ret = 0;
+
+err_mutex_unlock:
+ mutex_unlock(&s->i2c_mutex);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ struct si2168_cmd cmd;
+
+ *status = 0;
+
+ if (!s->active) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ cmd.args[0] = 0xa0;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 13;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ cmd.args[0] = 0x90;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 9;
+ break;
+ case SYS_DVBT2:
+ cmd.args[0] = 0x50;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 14;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /*
+ * Possible values seen, in order from strong signal to weak:
+ * 16 0001 0110 full lock
+ * 1e 0001 1110 partial lock
+ * 1a 0001 1010 partial lock
+ * 18 0001 1000 no lock
+ *
+ * [b3:b1] lock bits
+ * [b4] statistics ready? Set in a few secs after lock is gained.
+ */
+
+ switch ((cmd.args[2] >> 1) & 0x03) {
+ case 0x01:
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ break;
+ case 0x03:
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+ break;
+ }
+
+ s->fe_status = *status;
+
+ dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
+ __func__, *status, cmd.rlen, cmd.args);
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_set_frontend(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ struct si2168_cmd cmd;
+ u8 bandwidth, delivery_system;
+
+ dev_dbg(&s->client->dev,
+ "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
+ __func__, c->delivery_system, c->modulation,
+ c->frequency, c->bandwidth_hz, c->symbol_rate,
+ c->inversion);
+
+ if (!s->active) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ delivery_system = 0x20;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system = 0x30;
+ break;
+ case SYS_DVBT2:
+ delivery_system = 0x70;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (c->bandwidth_hz <= 5000000)
+ bandwidth = 0x05;
+ else if (c->bandwidth_hz <= 6000000)
+ bandwidth = 0x06;
+ else if (c->bandwidth_hz <= 7000000)
+ bandwidth = 0x07;
+ else if (c->bandwidth_hz <= 8000000)
+ bandwidth = 0x08;
+ else if (c->bandwidth_hz <= 9000000)
+ bandwidth = 0x09;
+ else if (c->bandwidth_hz <= 10000000)
+ bandwidth = 0x0a;
+ else
+ bandwidth = 0x0f;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (ret)
+ goto err;
+ }
+
+ memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
+ cmd.wlen = 5;
+ cmd.rlen = 5;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* that has no big effect */
+ if (c->delivery_system == SYS_DVBT)
+ memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6);
+ else if (c->delivery_system == SYS_DVBC_ANNEX_A)
+ memcpy(cmd.args, "\x89\x21\x06\x11\x89\xf0", 6);
+ else if (c->delivery_system == SYS_DVBT2)
+ memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 3;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x51\x03", 2);
+ cmd.wlen = 2;
+ cmd.rlen = 12;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x12\x08\x04", 3);
+ cmd.wlen = 3;
+ cmd.rlen = 3;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
+ cmd.args[4] = delivery_system | bandwidth;
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x85;
+ cmd.wlen = 1;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ s->delivery_system = c->delivery_system;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_init(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ int ret, len, remaining;
+ const struct firmware *fw = NULL;
+ u8 *fw_file = SI2168_FIRMWARE;
+ const unsigned int i2c_wr_max = 8;
+ struct si2168_cmd cmd;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ cmd.args[0] = 0x13;
+ cmd.wlen = 1;
+ cmd.rlen = 0;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0xc0;
+ cmd.args[1] = 0x12;
+ cmd.args[2] = 0x00;
+ cmd.args[3] = 0x0c;
+ cmd.args[4] = 0x00;
+ cmd.args[5] = 0x0d;
+ cmd.args[6] = 0x16;
+ cmd.args[7] = 0x00;
+ cmd.args[8] = 0x00;
+ cmd.args[9] = 0x00;
+ cmd.args[10] = 0x00;
+ cmd.args[11] = 0x00;
+ cmd.args[12] = 0x00;
+ cmd.wlen = 13;
+ cmd.rlen = 0;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0xc0;
+ cmd.args[1] = 0x06;
+ cmd.args[2] = 0x01;
+ cmd.args[3] = 0x0f;
+ cmd.args[4] = 0x00;
+ cmd.args[5] = 0x20;
+ cmd.args[6] = 0x20;
+ cmd.args[7] = 0x01;
+ cmd.wlen = 8;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x02;
+ cmd.wlen = 1;
+ cmd.rlen = 13;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* cold state - try to download firmware */
+ dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
+ KBUILD_MODNAME, si2168_ops.info.name);
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, &s->client->dev);
+ if (ret) {
+ dev_err(&s->client->dev, "%s: firmare file '%s' not found\n",
+ KBUILD_MODNAME, fw_file);
+ goto err;
+ }
+
+ dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
+ KBUILD_MODNAME, fw_file);
+
+ for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
+ len = remaining;
+ if (len > i2c_wr_max)
+ len = i2c_wr_max;
+
+ memcpy(cmd.args, &fw->data[fw->size - remaining], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret) {
+ dev_err(&s->client->dev,
+ "%s: firmware download failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err;
+ }
+ }
+
+ release_firmware(fw);
+ fw = NULL;
+
+ cmd.args[0] = 0x01;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
+ KBUILD_MODNAME, si2168_ops.info.name);
+
+ s->active = true;
+
+ return 0;
+err:
+ if (fw)
+ release_firmware(fw);
+
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_sleep(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ s->active = false;
+
+ return 0;
+}
+
+static int si2168_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 900;
+
+ return 0;
+}
+
+/*
+ * I2C gate logic
+ * We must use unlocked i2c_transfer() here because I2C lock is already taken
+ * by tuner driver.
+ */
+static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+{
+ struct si2168 *s = mux_priv;
+ int ret;
+ struct i2c_msg gate_open_msg = {
+ .addr = s->client->addr,
+ .flags = 0,
+ .len = 3,
+ .buf = "\xc0\x0d\x01",
+ };
+
+ mutex_lock(&s->i2c_mutex);
+
+ /* open tuner I2C gate */
+ ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
+ if (ret != 1) {
+ dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
+ KBUILD_MODNAME, ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+{
+ struct si2168 *s = mux_priv;
+ int ret;
+ struct i2c_msg gate_close_msg = {
+ .addr = s->client->addr,
+ .flags = 0,
+ .len = 3,
+ .buf = "\xc0\x0d\x00",
+ };
+
+ /* close tuner I2C gate */
+ ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
+ if (ret != 1) {
+ dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
+ KBUILD_MODNAME, ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ } else {
+ ret = 0;
+ }
+
+ mutex_unlock(&s->i2c_mutex);
+
+ return ret;
+}
+
+static const struct dvb_frontend_ops si2168_ops = {
+ .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
+ .info = {
+ .name = "Silicon Labs Si2168",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION
+ },
+
+ .get_tune_settings = si2168_get_tune_settings,
+
+ .init = si2168_init,
+ .sleep = si2168_sleep,
+
+ .set_frontend = si2168_set_frontend,
+
+ .read_status = si2168_read_status,
+};
+
+static int si2168_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct si2168_config *config = client->dev.platform_data;
+ struct si2168 *s;
+ int ret;
+ struct si2168_cmd cmd;
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
+ if (!s) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ goto err;
+ }
+
+ s->client = client;
+ mutex_init(&s->i2c_mutex);
+
+ /* check if the demod is there */
+ cmd.wlen = 0;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* create mux i2c adapter for tuner */
+ s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
+ 0, 0, 0, si2168_select, si2168_deselect);
+ if (s->adapter == NULL)
+ goto err;
+
+ /* create dvb_frontend */
+ memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
+ s->fe.demodulator_priv = s;
+
+ *config->i2c_adapter = s->adapter;
+ *config->fe = &s->fe;
+
+ i2c_set_clientdata(client, s);
+
+ dev_info(&s->client->dev,
+ "%s: Silicon Labs Si2168 successfully attached\n",
+ KBUILD_MODNAME);
+ return 0;
+err:
+ kfree(s);
+ dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_remove(struct i2c_client *client)
+{
+ struct si2168 *s = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ i2c_del_mux_adapter(s->adapter);
+
+ s->fe.ops.release = NULL;
+ s->fe.demodulator_priv = NULL;
+
+ kfree(s);
+
+ return 0;
+}
+
+static const struct i2c_device_id si2168_id[] = {
+ {"si2168", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, si2168_id);
+
+static struct i2c_driver si2168_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "si2168",
+ },
+ .probe = si2168_probe,
+ .remove = si2168_remove,
+ .id_table = si2168_id,
+};
+
+module_i2c_driver(si2168_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2168_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
new file mode 100644
index 00000000000..3c5b5ab0179
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -0,0 +1,39 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 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 SI2168_H
+#define SI2168_H
+
+#include <linux/dvb/frontend.h>
+/*
+ * I2C address
+ * 0x64
+ */
+struct si2168_config {
+ /*
+ * frontend
+ * returned by driver
+ */
+ struct dvb_frontend **fe;
+
+ /*
+ * tuner I2C adapter
+ * returned by driver
+ */
+ struct i2c_adapter **i2c_adapter;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
new file mode 100644
index 00000000000..53f7f06ae34
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -0,0 +1,46 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 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 SI2168_PRIV_H
+#define SI2168_PRIV_H
+
+#include "si2168.h"
+#include "dvb_frontend.h"
+#include <linux/firmware.h>
+#include <linux/i2c-mux.h>
+
+#define SI2168_FIRMWARE "dvb-demod-si2168-02.fw"
+
+/* state struct */
+struct si2168 {
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
+ struct mutex i2c_mutex;
+ struct dvb_frontend fe;
+ fe_delivery_system_t delivery_system;
+ fe_status_t fe_status;
+ bool active;
+};
+
+/* firmare command struct */
+#define SI2157_ARGLEN 30
+struct si2168_cmd {
+ u8 args[SI2157_ARGLEN];
+ unsigned wlen;
+ unsigned rlen;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 522fe00f5ee..9619be5d482 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -668,6 +668,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u8 mode, rolloff, pilot, inversion, div;
+ fe_modulation_t modulation;
dev_dbg(&priv->i2c->dev,
"%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
@@ -702,10 +703,13 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
switch (c->delivery_system) {
case SYS_DVBS:
+ modulation = QPSK;
rolloff = 0;
pilot = 2;
break;
case SYS_DVBS2:
+ modulation = c->modulation;
+
switch (c->rolloff) {
case ROLLOFF_20:
rolloff = 2;
@@ -750,7 +754,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) {
if (c->delivery_system == TDA10071_MODCOD[i].delivery_system &&
- c->modulation == TDA10071_MODCOD[i].modulation &&
+ modulation == TDA10071_MODCOD[i].modulation &&
c->fec_inner == TDA10071_MODCOD[i].fec) {
mode = TDA10071_MODCOD[i].val;
dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n",
@@ -834,10 +838,10 @@ static int tda10071_get_frontend(struct dvb_frontend *fe)
switch ((buf[1] >> 0) & 0x01) {
case 0:
- c->inversion = INVERSION_OFF;
+ c->inversion = INVERSION_ON;
break;
case 1:
- c->inversion = INVERSION_ON;
+ c->inversion = INVERSION_OFF;
break;
}
@@ -856,7 +860,7 @@ static int tda10071_get_frontend(struct dvb_frontend *fe)
if (ret)
goto error;
- c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
+ c->symbol_rate = ((buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0)) * 1000;
return ret;
error:
diff --git a/drivers/media/dvb-frontends/tda10071_priv.h b/drivers/media/dvb-frontends/tda10071_priv.h
index 4baf14bfb65..42048619273 100644
--- a/drivers/media/dvb-frontends/tda10071_priv.h
+++ b/drivers/media/dvb-frontends/tda10071_priv.h
@@ -55,6 +55,7 @@ static struct tda10071_modcod {
{ SYS_DVBS2, QPSK, FEC_8_9, 0x0a },
{ SYS_DVBS2, QPSK, FEC_9_10, 0x0b },
/* 8PSK */
+ { SYS_DVBS2, PSK_8, FEC_AUTO, 0x00 },
{ SYS_DVBS2, PSK_8, FEC_3_5, 0x0c },
{ SYS_DVBS2, PSK_8, FEC_2_3, 0x0d },
{ SYS_DVBS2, PSK_8, FEC_3_4, 0x0e },
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 1b7ecfd8867..fada1756620 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -571,35 +571,6 @@ static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
.interrupt_service_routine = ad9389b_isr,
};
-/* ------------------------------ PAD OPS ------------------------------ */
-
-static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- if (edid->pad != 0)
- return -EINVAL;
- if (edid->blocks == 0 || edid->blocks > 256)
- return -EINVAL;
- if (!edid->edid)
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
- }
- if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if (edid->blocks + edid->start_block >= state->edid.segments * 2)
- edid->blocks = state->edid.segments * 2 - edid->start_block;
- memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
- 128 * edid->blocks);
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
- .get_edid = ad9389b_get_edid,
-};
-
/* ------------------------------ VIDEO OPS ------------------------------ */
/* Enable/disable ad9389b output */
@@ -678,6 +649,9 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
NULL, NULL);
}
@@ -685,6 +659,9 @@ static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = ad9389b_timings_cap;
return 0;
}
@@ -693,10 +670,39 @@ static const struct v4l2_subdev_video_ops ad9389b_video_ops = {
.s_stream = ad9389b_s_stream,
.s_dv_timings = ad9389b_s_dv_timings,
.g_dv_timings = ad9389b_g_dv_timings,
+};
+
+/* ------------------------------ PAD OPS ------------------------------ */
+
+static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct ad9389b_state *state = get_ad9389b_state(sd);
+
+ if (edid->pad != 0)
+ return -EINVAL;
+ if (edid->blocks == 0 || edid->blocks > 256)
+ return -EINVAL;
+ if (!state->edid.segments) {
+ v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
+ return -ENODATA;
+ }
+ if (edid->start_block >= state->edid.segments * 2)
+ return -E2BIG;
+ if (edid->blocks + edid->start_block >= state->edid.segments * 2)
+ edid->blocks = state->edid.segments * 2 - edid->start_block;
+ memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
+ 128 * edid->blocks);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
+ .get_edid = ad9389b_get_edid,
.enum_dv_timings = ad9389b_enum_dv_timings,
.dv_timings_cap = ad9389b_dv_timings_cap,
};
+/* ------------------------------ AUDIO OPS ------------------------------ */
+
static int ad9389b_s_audio_stream(struct v4l2_subdev *sd, int enable)
{
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 5e638b15945..ac1cdbe251a 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -461,6 +461,7 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
+ .s_std = adv7180_s_std,
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
@@ -472,7 +473,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .s_std = adv7180_s_std,
.s_power = adv7180_s_power,
};
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index d45e0e3a781..df461b07b2f 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -501,8 +501,6 @@ static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7183_core_ops = {
.log_status = adv7183_log_status,
- .g_std = adv7183_g_std,
- .s_std = adv7183_s_std,
.reset = adv7183_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7183_g_register,
@@ -511,6 +509,8 @@ static const struct v4l2_subdev_core_ops adv7183_core_ops = {
};
static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+ .g_std = adv7183_g_std,
+ .s_std = adv7183_s_std,
.s_routing = adv7183_s_routing,
.querystd = adv7183_querystd,
.g_input_status = adv7183_g_input_status,
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 942ca4b9929..f98acf4aafd 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -597,34 +597,6 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
return 0;
}
-static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
-{
- struct adv7511_state *state = get_adv7511_state(sd);
-
- if (edid->pad != 0)
- return -EINVAL;
- if ((edid->blocks == 0) || (edid->blocks > 256))
- return -EINVAL;
- if (!edid->edid)
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
- }
- if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if ((edid->blocks + edid->start_block) >= state->edid.segments * 2)
- edid->blocks = state->edid.segments * 2 - edid->start_block;
-
- memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
- 128 * edid->blocks);
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
- .get_edid = adv7511_get_edid,
-};
-
static const struct v4l2_subdev_core_ops adv7511_core_ops = {
.log_status = adv7511_log_status,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -700,12 +672,18 @@ static int adv7511_g_dv_timings(struct v4l2_subdev *sd,
static int adv7511_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL);
}
static int adv7511_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = adv7511_timings_cap;
return 0;
}
@@ -714,8 +692,6 @@ static const struct v4l2_subdev_video_ops adv7511_video_ops = {
.s_stream = adv7511_s_stream,
.s_dv_timings = adv7511_s_dv_timings,
.g_dv_timings = adv7511_g_dv_timings,
- .enum_dv_timings = adv7511_enum_dv_timings,
- .dv_timings_cap = adv7511_dv_timings_cap,
};
/* ------------------------------ AUDIO OPS ------------------------------ */
@@ -797,6 +773,36 @@ static const struct v4l2_subdev_audio_ops adv7511_audio_ops = {
.s_routing = adv7511_s_routing,
};
+/* ---------------------------- PAD OPS ------------------------------------- */
+
+static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct adv7511_state *state = get_adv7511_state(sd);
+
+ if (edid->pad != 0)
+ return -EINVAL;
+ if ((edid->blocks == 0) || (edid->blocks > 256))
+ return -EINVAL;
+ if (!state->edid.segments) {
+ v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
+ return -ENODATA;
+ }
+ if (edid->start_block >= state->edid.segments * 2)
+ return -E2BIG;
+ if ((edid->blocks + edid->start_block) >= state->edid.segments * 2)
+ edid->blocks = state->edid.segments * 2 - edid->start_block;
+
+ memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
+ 128 * edid->blocks);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
+ .get_edid = adv7511_get_edid,
+ .enum_dv_timings = adv7511_enum_dv_timings,
+ .dv_timings_cap = adv7511_dv_timings_cap,
+};
+
/* --------------------- SUBDEV OPS --------------------------------------- */
static const struct v4l2_subdev_ops adv7511_ops = {
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 98cc5407f1b..1778d320272 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -27,19 +27,21 @@
* REF_03 - Analog devices, ADV7604, Hardware Manual, Rev. F, August 2010
*/
-
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
+#include <linux/v4l2-dv-timings.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
-#include <linux/v4l2-dv-timings.h>
-#include <media/v4l2-device.h>
+
+#include <media/adv7604.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-dv-timings.h>
-#include <media/adv7604.h>
+#include <media/v4l2-of.h>
static int debug;
module_param(debug, int, 0644);
@@ -53,6 +55,76 @@ MODULE_LICENSE("GPL");
/* ADV7604 system clock frequency */
#define ADV7604_fsc (28636360)
+#define ADV7604_RGB_OUT (1 << 1)
+
+#define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0)
+#define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0)
+#define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0)
+
+#define ADV7604_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 ADV7604_OP_MODE_SEL_DDR_444 (3 << 5)
+#define ADV7604_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 ADV7604_OP_SWAP_CB_CR (1 << 0)
+
+enum adv7604_type {
+ ADV7604,
+ ADV7611,
+};
+
+struct adv7604_reg_seq {
+ unsigned int reg;
+ u8 val;
+};
+
+struct adv7604_format_info {
+ enum v4l2_mbus_pixelcode code;
+ u8 op_ch_sel;
+ bool rgb_out;
+ bool swap_cb_cr;
+ u8 op_format_sel;
+};
+
+struct adv7604_chip_info {
+ enum adv7604_type type;
+
+ bool has_afe;
+ unsigned int max_port;
+ unsigned int num_dv_ports;
+
+ unsigned int edid_enable_reg;
+ unsigned int edid_status_reg;
+ unsigned int lcf_reg;
+
+ unsigned int cable_det_mask;
+ unsigned int tdms_lock_mask;
+ unsigned int fmt_change_digital_mask;
+
+ const struct adv7604_format_info *formats;
+ unsigned int nformats;
+
+ void (*set_termination)(struct v4l2_subdev *sd, bool enable);
+ void (*setup_irqs)(struct v4l2_subdev *sd);
+ unsigned int (*read_hdmi_pixelclock)(struct v4l2_subdev *sd);
+ unsigned int (*read_cable_det)(struct v4l2_subdev *sd);
+
+ /* 0 = AFE, 1 = HDMI */
+ const struct adv7604_reg_seq *recommended_settings[2];
+ unsigned int num_recommended_settings[2];
+
+ unsigned long page_mask;
+};
+
/*
**********************************************************************
*
@@ -60,13 +132,24 @@ MODULE_LICENSE("GPL");
*
**********************************************************************
*/
+
struct adv7604_state {
+ const struct adv7604_chip_info *info;
struct adv7604_platform_data pdata;
+
+ struct gpio_desc *hpd_gpio[4];
+
struct v4l2_subdev sd;
- struct media_pad pad;
+ struct media_pad pads[ADV7604_PAD_MAX];
+ unsigned int source_pad;
+
struct v4l2_ctrl_handler hdl;
- enum adv7604_input_port selected_input;
+
+ enum adv7604_pad selected_input;
+
struct v4l2_dv_timings timings;
+ const struct adv7604_format_info *format;
+
struct {
u8 edid[256];
u32 present;
@@ -80,18 +163,7 @@ struct adv7604_state {
bool restart_stdi_once;
/* i2c clients */
- struct i2c_client *i2c_avlink;
- struct i2c_client *i2c_cec;
- struct i2c_client *i2c_infoframe;
- struct i2c_client *i2c_esdp;
- struct i2c_client *i2c_dpp;
- struct i2c_client *i2c_afe;
- struct i2c_client *i2c_repeater;
- struct i2c_client *i2c_edid;
- struct i2c_client *i2c_hdmi;
- struct i2c_client *i2c_test;
- struct i2c_client *i2c_cp;
- struct i2c_client *i2c_vdp;
+ struct i2c_client *i2c_clients[ADV7604_PAGE_MAX];
/* controls */
struct v4l2_ctrl *detect_tx_5v_ctrl;
@@ -101,6 +173,11 @@ struct adv7604_state {
struct v4l2_ctrl *rgb_quantization_range_ctrl;
};
+static bool adv7604_has_afe(struct adv7604_state *state)
+{
+ return state->info->has_afe;
+}
+
/* Supported CEA and DMT timings */
static const struct v4l2_dv_timings adv7604_timings[] = {
V4L2_DV_BT_CEA_720X480P59_94,
@@ -256,11 +333,6 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct adv7604_state, sd);
}
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct adv7604_state, hdl)->sd;
-}
-
static inline unsigned hblanking(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_BLANKING_WIDTH(t);
@@ -298,14 +370,18 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
return -EIO;
}
-static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command)
+static s32 adv_smbus_read_byte_data(struct adv7604_state *state,
+ enum adv7604_page page, u8 command)
{
- return adv_smbus_read_byte_data_check(client, command, true);
+ return adv_smbus_read_byte_data_check(state->i2c_clients[page],
+ command, true);
}
-static s32 adv_smbus_write_byte_data(struct i2c_client *client,
- u8 command, u8 value)
+static s32 adv_smbus_write_byte_data(struct adv7604_state *state,
+ enum adv7604_page page, u8 command,
+ u8 value)
{
+ struct i2c_client *client = state->i2c_clients[page];
union i2c_smbus_data data;
int err;
int i;
@@ -325,9 +401,11 @@ static s32 adv_smbus_write_byte_data(struct i2c_client *client,
return err;
}
-static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client,
- u8 command, unsigned length, const u8 *values)
+static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state,
+ enum adv7604_page page, u8 command,
+ unsigned length, const u8 *values)
{
+ struct i2c_client *client = state->i2c_clients[page];
union i2c_smbus_data data;
if (length > I2C_SMBUS_BLOCK_MAX)
@@ -343,149 +421,150 @@ static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client,
static inline int io_read(struct v4l2_subdev *sd, u8 reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(client, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg);
}
static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(client, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val);
}
-static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
{
- return io_write(sd, reg, (io_read(sd, reg) & mask) | val);
+ return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val);
}
static inline int avlink_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_avlink, reg);
+ 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);
- return adv_smbus_write_byte_data(state->i2c_avlink, reg, val);
+ 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);
- return adv_smbus_read_byte_data(state->i2c_cec, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg);
}
static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_cec, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val);
}
-static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
{
- return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val);
+ return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val);
}
static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_infoframe, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg);
}
static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME,
+ reg, val);
}
static inline int esdp_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_esdp, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg);
}
static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_esdp, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val);
}
static inline int dpp_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_dpp, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg);
}
static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_dpp, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val);
}
static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_afe, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg);
}
static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_afe, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val);
}
static inline int rep_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_repeater, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg);
}
static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_repeater, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val);
}
-static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
{
- return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val);
+ return rep_write(sd, reg, (rep_read(sd, reg) & ~mask) | val);
}
static inline int edid_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_edid, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg);
}
static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_edid, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val);
}
static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
{
struct adv7604_state *state = to_state(sd);
- struct i2c_client *client = state->i2c_edid;
+ struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID];
u8 msgbuf0[1] = { 0 };
u8 msgbuf1[256];
struct i2c_msg msg[2] = {
@@ -518,11 +597,25 @@ static inline int edid_write_block(struct v4l2_subdev *sd,
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->i2c_edid, i,
- I2C_SMBUS_BLOCK_MAX, val + i);
+ err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID,
+ i, I2C_SMBUS_BLOCK_MAX, val + i);
return err;
}
+static void adv7604_set_hpd(struct adv7604_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;
+
+ gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i));
+ }
+
+ v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd);
+}
+
static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -532,73 +625,210 @@ static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
- v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
+ adv7604_set_hpd(state, state->edid.present);
}
static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_hdmi, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg);
+}
+
+static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
+{
+ return ((hdmi_read(sd, reg) << 8) | hdmi_read(sd, reg + 1)) & mask;
}
static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val);
}
-static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
{
- return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val);
+ return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val);
}
static inline int test_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_test, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg);
}
static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_test, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val);
}
static inline int cp_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_cp, reg);
+ return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg);
+}
+
+static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
+{
+ return ((cp_read(sd, reg) << 8) | cp_read(sd, reg + 1)) & mask;
}
static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_write_byte_data(state->i2c_cp, reg, val);
+ return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val);
}
-static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
{
- return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val);
+ return cp_write(sd, reg, (cp_read(sd, reg) & ~mask) | val);
}
static inline int vdp_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
- return adv_smbus_read_byte_data(state->i2c_vdp, reg);
+ 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);
- return adv_smbus_write_byte_data(state->i2c_vdp, reg, val);
+ 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
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg)
+{
+ struct adv7604_state *state = to_state(sd);
+ unsigned int page = reg >> 8;
+
+ if (!(BIT(page) & state->info->page_mask))
+ return -EINVAL;
+
+ reg &= 0xff;
+
+ return adv_smbus_read_byte_data(state, page, reg);
+}
+#endif
+
+static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val)
+{
+ struct adv7604_state *state = to_state(sd);
+ unsigned int page = reg >> 8;
+
+ if (!(BIT(page) & state->info->page_mask))
+ return -EINVAL;
+
+ reg &= 0xff;
+
+ 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)
+{
+ 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);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
+static const struct adv7604_format_info adv7604_formats[] = {
+ { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
+ ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
+ { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_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 adv7604_format_info adv7611_formats[] = {
+ { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
+ ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
+ { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
+ ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
+ { V4L2_MBUS_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 adv7604_format_info *
+adv7604_format_info(struct adv7604_state *state, enum v4l2_mbus_pixelcode code)
+{
+ unsigned int i;
+
+ for (i = 0; i < state->info->nformats; ++i) {
+ if (state->info->formats[i].code == code)
+ return &state->info->formats[i];
+ }
+
+ return NULL;
}
/* ----------------------------------------------------------------------- */
@@ -607,18 +837,18 @@ static inline bool is_analog_input(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
- return state->selected_input == ADV7604_INPUT_VGA_RGB ||
- state->selected_input == ADV7604_INPUT_VGA_COMP;
+ return state->selected_input == ADV7604_PAD_VGA_RGB ||
+ state->selected_input == ADV7604_PAD_VGA_COMP;
}
static inline bool is_digital_input(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
- return state->selected_input == ADV7604_INPUT_HDMI_PORT_A ||
- state->selected_input == ADV7604_INPUT_HDMI_PORT_B ||
- state->selected_input == ADV7604_INPUT_HDMI_PORT_C ||
- state->selected_input == ADV7604_INPUT_HDMI_PORT_D;
+ return state->selected_input == ADV7604_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;
}
/* ----------------------------------------------------------------------- */
@@ -644,119 +874,61 @@ static void adv7604_inv_register(struct v4l2_subdev *sd)
static int adv7604_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- reg->size = 1;
- switch (reg->reg >> 8) {
- case 0:
- reg->val = io_read(sd, reg->reg & 0xff);
- break;
- case 1:
- reg->val = avlink_read(sd, reg->reg & 0xff);
- break;
- case 2:
- reg->val = cec_read(sd, reg->reg & 0xff);
- break;
- case 3:
- reg->val = infoframe_read(sd, reg->reg & 0xff);
- break;
- case 4:
- reg->val = esdp_read(sd, reg->reg & 0xff);
- break;
- case 5:
- reg->val = dpp_read(sd, reg->reg & 0xff);
- break;
- case 6:
- reg->val = afe_read(sd, reg->reg & 0xff);
- break;
- case 7:
- reg->val = rep_read(sd, reg->reg & 0xff);
- break;
- case 8:
- reg->val = edid_read(sd, reg->reg & 0xff);
- break;
- case 9:
- reg->val = hdmi_read(sd, reg->reg & 0xff);
- break;
- case 0xa:
- reg->val = test_read(sd, reg->reg & 0xff);
- break;
- case 0xb:
- reg->val = cp_read(sd, reg->reg & 0xff);
- break;
- case 0xc:
- reg->val = vdp_read(sd, reg->reg & 0xff);
- break;
- default:
+ int ret;
+
+ ret = adv7604_read_reg(sd, reg->reg);
+ if (ret < 0) {
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
adv7604_inv_register(sd);
- break;
+ return ret;
}
+
+ reg->size = 1;
+ reg->val = ret;
+
return 0;
}
static int adv7604_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- u8 val = reg->val & 0xff;
+ int ret;
- switch (reg->reg >> 8) {
- case 0:
- io_write(sd, reg->reg & 0xff, val);
- break;
- case 1:
- avlink_write(sd, reg->reg & 0xff, val);
- break;
- case 2:
- cec_write(sd, reg->reg & 0xff, val);
- break;
- case 3:
- infoframe_write(sd, reg->reg & 0xff, val);
- break;
- case 4:
- esdp_write(sd, reg->reg & 0xff, val);
- break;
- case 5:
- dpp_write(sd, reg->reg & 0xff, val);
- break;
- case 6:
- afe_write(sd, reg->reg & 0xff, val);
- break;
- case 7:
- rep_write(sd, reg->reg & 0xff, val);
- break;
- case 8:
- edid_write(sd, reg->reg & 0xff, val);
- break;
- case 9:
- hdmi_write(sd, reg->reg & 0xff, val);
- break;
- case 0xa:
- test_write(sd, reg->reg & 0xff, val);
- break;
- case 0xb:
- cp_write(sd, reg->reg & 0xff, val);
- break;
- case 0xc:
- vdp_write(sd, reg->reg & 0xff, val);
- break;
- default:
+ ret = adv7604_write_reg(sd, reg->reg, reg->val);
+ if (ret < 0) {
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
adv7604_inv_register(sd);
- break;
+ return ret;
}
+
return 0;
}
#endif
+static unsigned int adv7604_read_cable_det(struct v4l2_subdev *sd)
+{
+ u8 value = io_read(sd, 0x6f);
+
+ return ((value & 0x10) >> 4)
+ | ((value & 0x08) >> 2)
+ | ((value & 0x04) << 0)
+ | ((value & 0x02) << 2);
+}
+
+static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd)
+{
+ u8 value = io_read(sd, 0x6f);
+
+ return value & 1;
+}
+
static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
- u8 reg_io_6f = io_read(sd, 0x6f);
+ const struct adv7604_chip_info *info = state->info;
return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
- ((reg_io_6f & 0x10) >> 4) |
- ((reg_io_6f & 0x08) >> 2) |
- (reg_io_6f & 0x04) |
- ((reg_io_6f & 0x02) << 2));
+ info->read_cable_det(sd));
}
static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
@@ -787,11 +959,13 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd,
v4l2_dbg(1, debug, sd, "%s", __func__);
- /* reset to default values */
- io_write(sd, 0x16, 0x43);
- io_write(sd, 0x17, 0x5a);
+ if (adv7604_has_afe(state)) {
+ /* reset to default values */
+ io_write(sd, 0x16, 0x43);
+ io_write(sd, 0x17, 0x5a);
+ }
/* disable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x00);
+ cp_write_clr_set(sd, 0x81, 0x10, 0x00);
cp_write(sd, 0x8f, 0x00);
cp_write(sd, 0x90, 0x00);
cp_write(sd, 0xa2, 0x00);
@@ -829,7 +1003,6 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
const struct v4l2_bt_timings *bt)
{
struct adv7604_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
u32 width = htotal(bt);
u32 height = vtotal(bt);
u16 cp_start_sav = bt->hsync + bt->hbackporch - 4;
@@ -850,12 +1023,13 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
io_write(sd, 0x00, 0x07); /* video std */
io_write(sd, 0x01, 0x02); /* prim mode */
/* enable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x10);
+ cp_write_clr_set(sd, 0x81, 0x10, 0x10);
/* 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(client, 0x16, 2, pll))
+ if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO,
+ 0x16, 2, pll))
v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
/* active video - horizontal timing */
@@ -906,7 +1080,8 @@ 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->i2c_cp, 0x77, 4, offset_buf))
+ if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP,
+ 0x77, 4, offset_buf))
v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
}
@@ -935,7 +1110,8 @@ 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->i2c_cp, 0x73, 4, gain_buf))
+ if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP,
+ 0x73, 4, gain_buf))
v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
}
@@ -954,24 +1130,24 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
switch (state->rgb_quantization_range) {
case V4L2_DV_RGB_RANGE_AUTO:
- if (state->selected_input == ADV7604_INPUT_VGA_RGB) {
+ if (state->selected_input == ADV7604_PAD_VGA_RGB) {
/* Receiving analog RGB signal
* Set RGB full range (0-255) */
- io_write_and_or(sd, 0x02, 0x0f, 0x10);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x10);
break;
}
- if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+ if (state->selected_input == ADV7604_PAD_VGA_COMP) {
/* Receiving analog YPbPr signal
* Set automode */
- io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+ io_write_clr_set(sd, 0x02, 0xf0, 0xf0);
break;
}
if (hdmi_signal) {
/* Receiving HDMI signal
* Set automode */
- io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+ io_write_clr_set(sd, 0x02, 0xf0, 0xf0);
break;
}
@@ -980,10 +1156,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
* input format (CE/IT) in automatic mode */
if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
/* RGB limited range (16-235) */
- io_write_and_or(sd, 0x02, 0x0f, 0x00);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x00);
} else {
/* RGB full range (0-255) */
- io_write_and_or(sd, 0x02, 0x0f, 0x10);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x10);
if (is_digital_input(sd) && rgb_output) {
adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
@@ -994,25 +1170,25 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
}
break;
case V4L2_DV_RGB_RANGE_LIMITED:
- if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+ if (state->selected_input == ADV7604_PAD_VGA_COMP) {
/* YCrCb limited range (16-235) */
- io_write_and_or(sd, 0x02, 0x0f, 0x20);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x20);
break;
}
/* RGB limited range (16-235) */
- io_write_and_or(sd, 0x02, 0x0f, 0x00);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x00);
break;
case V4L2_DV_RGB_RANGE_FULL:
- if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+ if (state->selected_input == ADV7604_PAD_VGA_COMP) {
/* YCrCb full range (0-255) */
- io_write_and_or(sd, 0x02, 0x0f, 0x60);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x60);
break;
}
/* RGB full range (0-255) */
- io_write_and_or(sd, 0x02, 0x0f, 0x10);
+ io_write_clr_set(sd, 0x02, 0xf0, 0x10);
if (is_analog_input(sd) || hdmi_signal)
break;
@@ -1030,7 +1206,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct v4l2_subdev *sd = to_sd(ctrl);
+ struct v4l2_subdev *sd =
+ &container_of(ctrl->handler, struct adv7604_state, hdl)->sd;
+
struct adv7604_state *state = to_state(sd);
switch (ctrl->id) {
@@ -1051,6 +1229,8 @@ 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))
+ return -EINVAL;
/* Set the analog sampling phase. This is needed to find the
best sampling phase for analog video: an application or
driver has to try a number of phases and analyze the picture
@@ -1060,7 +1240,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL:
/* Use the default blue color for free running mode,
or supply your own. */
- cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2));
+ cp_write_clr_set(sd, 0xbf, 0x04, ctrl->val << 2);
return 0;
case V4L2_CID_ADV_RX_FREE_RUN_COLOR:
cp_write(sd, 0xc0, (ctrl->val & 0xff0000) >> 16);
@@ -1088,7 +1268,10 @@ static inline bool no_signal_tmds(struct v4l2_subdev *sd)
static inline bool no_lock_tmds(struct v4l2_subdev *sd)
{
- return (io_read(sd, 0x6a) & 0xe0) != 0xe0;
+ struct adv7604_state *state = to_state(sd);
+ const struct adv7604_chip_info *info = state->info;
+
+ return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask;
}
static inline bool is_hdmi(struct v4l2_subdev *sd)
@@ -1098,6 +1281,15 @@ 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);
+
+ /*
+ * Chips without a AFE don't expose registers for the SSPD, so just assume
+ * that we have a lock.
+ */
+ if (adv7604_has_afe(state))
+ return false;
+
/* TODO channel 2 */
return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0);
}
@@ -1127,6 +1319,11 @@ 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);
+
+ if (!adv7604_has_afe(state))
+ return false;
+
/* CP has detected a non standard number of lines on the incoming
video compared to what it is configured to receive by s_dv_timings */
return io_read(sd, 0x12) & 0x01;
@@ -1195,28 +1392,40 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
return -1;
}
+
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;
+ u8 polarity;
+
if (no_lock_stdi(sd) || no_lock_sspd(sd)) {
v4l2_dbg(2, debug, sd, "%s: STDI and/or SSPD not locked\n", __func__);
return -1;
}
/* read STDI */
- stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2);
- stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4);
+ stdi->bl = cp_read16(sd, 0xb1, 0x3fff);
+ stdi->lcf = cp_read16(sd, info->lcf_reg, 0x7ff);
stdi->lcvs = cp_read(sd, 0xb3) >> 3;
stdi->interlaced = io_read(sd, 0x12) & 0x10;
- /* read SSPD */
- if ((cp_read(sd, 0xb5) & 0x03) == 0x01) {
- stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ?
- ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x');
- stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ?
- ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x');
+ if (adv7604_has_afe(state)) {
+ /* read SSPD */
+ polarity = cp_read(sd, 0xb5);
+ if ((polarity & 0x03) == 0x01) {
+ stdi->hs_pol = polarity & 0x10
+ ? (polarity & 0x08 ? '+' : '-') : 'x';
+ stdi->vs_pol = polarity & 0x40
+ ? (polarity & 0x20 ? '+' : '-') : 'x';
+ } else {
+ stdi->hs_pol = 'x';
+ stdi->vs_pol = 'x';
+ }
} else {
- stdi->hs_pol = 'x';
- stdi->vs_pol = 'x';
+ polarity = hdmi_read(sd, 0x05);
+ stdi->hs_pol = polarity & 0x20 ? '+' : '-';
+ stdi->vs_pol = polarity & 0x10 ? '+' : '-';
}
if (no_lock_stdi(sd) || no_lock_sspd(sd)) {
@@ -1243,8 +1452,14 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
static int adv7604_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ struct adv7604_state *state = to_state(sd);
+
if (timings->index >= ARRAY_SIZE(adv7604_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];
return 0;
@@ -1253,14 +1468,30 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd,
static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ struct adv7604_state *state = to_state(sd);
+
+ if (cap->pad >= state->source_pad)
+ return -EINVAL;
+
cap->type = V4L2_DV_BT_656_1120;
cap->bt.max_width = 1920;
cap->bt.max_height = 1200;
cap->bt.min_pixelclock = 25000000;
- if (is_digital_input(sd))
+
+ switch (cap->pad) {
+ case ADV7604_PAD_HDMI_PORT_A:
+ case ADV7604_PAD_HDMI_PORT_B:
+ case ADV7604_PAD_HDMI_PORT_C:
+ case ADV7604_PAD_HDMI_PORT_D:
cap->bt.max_pixelclock = 225000000;
- else
+ break;
+ case ADV7604_PAD_VGA_RGB:
+ case ADV7604_PAD_VGA_COMP:
+ default:
cap->bt.max_pixelclock = 170000000;
+ break;
+ }
+
cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT;
cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
@@ -1284,10 +1515,43 @@ static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
}
}
+static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd)
+{
+ unsigned int freq;
+ int a, b;
+
+ a = hdmi_read(sd, 0x06);
+ b = hdmi_read(sd, 0x3b);
+ if (a < 0 || b < 0)
+ return 0;
+ freq = a * 1000000 + ((b & 0x30) >> 4) * 250000;
+
+ if (is_hdmi(sd)) {
+ /* adjust for deep color mode */
+ unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8;
+
+ freq = freq * 8 / bits_per_channel;
+ }
+
+ return freq;
+}
+
+static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd)
+{
+ int a, b;
+
+ a = hdmi_read(sd, 0x51);
+ b = hdmi_read(sd, 0x52);
+ if (a < 0 || b < 0)
+ return 0;
+ return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128;
+}
+
static int adv7604_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 v4l2_bt_timings *bt = &timings->bt;
struct stdi_readback stdi;
@@ -1311,44 +1575,25 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
if (is_digital_input(sd)) {
- uint32_t freq;
-
timings->type = V4L2_DV_BT_656_1120;
- bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
- bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
- freq = (hdmi_read(sd, 0x06) * 1000000) +
- ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
- if (is_hdmi(sd)) {
- /* adjust for deep color mode */
- unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8;
-
- freq = freq * 8 / bits_per_channel;
- }
- bt->pixelclock = freq;
- bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
- hdmi_read(sd, 0x21);
- bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 +
- hdmi_read(sd, 0x23);
- bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 +
- hdmi_read(sd, 0x25);
- bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 +
- hdmi_read(sd, 0x2b)) / 2;
- bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 +
- hdmi_read(sd, 0x2f)) / 2;
- bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 +
- hdmi_read(sd, 0x33)) / 2;
+ /* FIXME: All masks are incorrect for ADV7611 */
+ bt->width = hdmi_read16(sd, 0x07, 0xfff);
+ bt->height = hdmi_read16(sd, 0x09, 0xfff);
+ bt->pixelclock = info->read_hdmi_pixelclock(sd);
+ bt->hfrontporch = hdmi_read16(sd, 0x20, 0x3ff);
+ bt->hsync = hdmi_read16(sd, 0x22, 0x3ff);
+ bt->hbackporch = hdmi_read16(sd, 0x24, 0x3ff);
+ bt->vfrontporch = hdmi_read16(sd, 0x2a, 0x1fff) / 2;
+ bt->vsync = hdmi_read16(sd, 0x2e, 0x1fff) / 2;
+ bt->vbackporch = hdmi_read16(sd, 0x32, 0x1fff) / 2;
bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) |
((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0);
if (bt->interlaced == V4L2_DV_INTERLACED) {
- bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 +
- hdmi_read(sd, 0x0c);
- bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 +
- hdmi_read(sd, 0x2d)) / 2;
- bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 +
- hdmi_read(sd, 0x31)) / 2;
- bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
- hdmi_read(sd, 0x35)) / 2;
+ bt->height += hdmi_read16(sd, 0x0b, 0xfff);
+ bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2;
+ bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2;
+ bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
}
adv7604_fill_optional_dv_timings_fields(sd, timings);
} else {
@@ -1378,11 +1623,11 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__);
/* TODO restart STDI for Sync Channel 2 */
/* enter one-shot mode */
- cp_write_and_or(sd, 0x86, 0xf9, 0x00);
+ cp_write_clr_set(sd, 0x86, 0x06, 0x00);
/* trigger STDI restart */
- cp_write_and_or(sd, 0x86, 0xf9, 0x04);
+ cp_write_clr_set(sd, 0x86, 0x06, 0x04);
/* reset to continuous mode */
- cp_write_and_or(sd, 0x86, 0xf9, 0x02);
+ cp_write_clr_set(sd, 0x86, 0x06, 0x02);
state->restart_stdi_once = false;
return -ENOLINK;
}
@@ -1441,7 +1686,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
state->timings = *timings;
- cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10);
+ cp_write_clr_set(sd, 0x91, 0x40, bt->interlaced ? 0x40 : 0x00);
/* Use prim_mode and vid_std when available */
err = configure_predefined_video_timings(sd, timings);
@@ -1468,6 +1713,16 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd,
return 0;
}
+static void adv7604_set_termination(struct v4l2_subdev *sd, bool enable)
+{
+ hdmi_write(sd, 0x01, enable ? 0x00 : 0x78);
+}
+
+static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable)
+{
+ hdmi_write(sd, 0x83, enable ? 0xfe : 0xff);
+}
+
static void enable_input(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
@@ -1475,10 +1730,10 @@ static void enable_input(struct v4l2_subdev *sd)
if (is_analog_input(sd)) {
io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */
} else if (is_digital_input(sd)) {
- hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input);
- hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
+ hdmi_write_clr_set(sd, 0x00, 0x03, state->selected_input);
+ state->info->set_termination(sd, true);
io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */
- hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */
+ hdmi_write_clr_set(sd, 0x1a, 0x10, 0x00); /* Unmute audio */
} else {
v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
__func__, state->selected_input);
@@ -1487,67 +1742,36 @@ static void enable_input(struct v4l2_subdev *sd)
static void disable_input(struct v4l2_subdev *sd)
{
- hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */
+ struct adv7604_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] */
io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */
- hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
+ state->info->set_termination(sd, false);
}
static void select_input(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
+ const struct adv7604_chip_info *info = state->info;
if (is_analog_input(sd)) {
- /* reset ADI recommended settings for HDMI: */
- /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
- hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */
- hdmi_write(sd, 0x3d, 0x00); /* DDC bus active pull-up control */
- hdmi_write(sd, 0x3e, 0x74); /* TMDS PLL optimization */
- hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */
- hdmi_write(sd, 0x57, 0x74); /* TMDS PLL optimization */
- hdmi_write(sd, 0x58, 0x63); /* TMDS PLL optimization */
- hdmi_write(sd, 0x8d, 0x18); /* equaliser */
- hdmi_write(sd, 0x8e, 0x34); /* equaliser */
- hdmi_write(sd, 0x93, 0x88); /* equaliser */
- hdmi_write(sd, 0x94, 0x2e); /* equaliser */
- hdmi_write(sd, 0x96, 0x00); /* enable automatic EQ changing */
+ adv7604_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 */
afe_write(sd, 0xc8, 0x00); /* phase control */
-
- /* set ADI recommended settings for digitizer */
- /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
- afe_write(sd, 0x12, 0x7b); /* ADC noise shaping filter controls */
- afe_write(sd, 0x0c, 0x1f); /* CP core gain controls */
- cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */
- cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
- cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */
} else if (is_digital_input(sd)) {
hdmi_write(sd, 0x00, state->selected_input & 0x03);
- /* set ADI recommended settings for HDMI: */
- /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
- hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */
- hdmi_write(sd, 0x3d, 0x10); /* DDC bus active pull-up control */
- hdmi_write(sd, 0x3e, 0x39); /* TMDS PLL optimization */
- hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */
- hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */
- hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */
- hdmi_write(sd, 0x8d, 0x18); /* equaliser */
- hdmi_write(sd, 0x8e, 0x34); /* equaliser */
- hdmi_write(sd, 0x93, 0x8b); /* equaliser */
- hdmi_write(sd, 0x94, 0x2d); /* equaliser */
- hdmi_write(sd, 0x96, 0x01); /* enable automatic EQ changing */
-
- 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 */
-
- /* reset ADI recommended settings for digitizer */
- /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
- afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */
- afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */
+ adv7604_write_reg_seq(sd, info->recommended_settings[1]);
+
+ if (adv7604_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 */
+ }
+
cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */
cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */
@@ -1568,6 +1792,9 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
if (input == state->selected_input)
return 0;
+ if (input > state->info->max_port)
+ return -EINVAL;
+
state->selected_input = input;
disable_input(sd);
@@ -1579,34 +1806,139 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int adv7604_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+static int adv7604_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
{
- if (index)
+ struct adv7604_state *state = to_state(sd);
+
+ if (code->index >= state->info->nformats)
return -EINVAL;
- /* Good enough for now */
- *code = V4L2_MBUS_FMT_FIXED;
+
+ code->code = state->info->formats[code->index].code;
+
return 0;
}
-static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
+static void adv7604_fill_format(struct adv7604_state *state,
+ struct v4l2_mbus_framefmt *format)
{
- struct adv7604_state *state = to_state(sd);
+ memset(format, 0, sizeof(*format));
+
+ format->width = state->timings.bt.width;
+ format->height = state->timings.bt.height;
+ format->field = V4L2_FIELD_NONE;
- fmt->width = state->timings.bt.width;
- fmt->height = state->timings.bt.height;
- fmt->code = V4L2_MBUS_FMT_FIXED;
- fmt->field = V4L2_FIELD_NONE;
- if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
- fmt->colorspace = (state->timings.bt.height <= 576) ?
+ if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861)
+ format->colorspace = (state->timings.bt.height <= 576) ?
V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
+}
+
+/*
+ * Compute the op_ch_sel value required to obtain on the bus the component order
+ * corresponding to the selected format taking into account bus reordering
+ * applied by the board at the output of the device.
+ *
+ * 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).
+ *
+ * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5)
+ * ----------+-------------------------------------------------
+ * RGB (NOP) | GBR GRB BGR RGB BRG RBG
+ * GRB (1-2) | BGR RGB GBR GRB RBG BRG
+ * RBG (2-3) | GRB GBR BRG RBG BGR RGB
+ * BGR (1-3) | RBG BRG RGB BGR GRB GBR
+ * 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)
+{
+#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 }
+#define _BUS(x) [ADV7604_BUS_ORDER_##x]
+
+ static const unsigned int op_ch_sel[6][6] = {
+ _BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG),
+ _BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG),
+ _BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB),
+ _BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR),
+ _BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR),
+ _BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB),
+ };
+
+ return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5];
+}
+
+static void adv7604_setup_format(struct adv7604_state *state)
+{
+ struct v4l2_subdev *sd = &state->sd;
+
+ io_write_clr_set(sd, 0x02, 0x02,
+ state->format->rgb_out ? ADV7604_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, 0x05, 0x01,
+ state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0);
+}
+
+static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7604_state *state = to_state(sd);
+
+ if (format->pad != state->source_pad)
+ return -EINVAL;
+
+ adv7604_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);
+ format->format.code = fmt->code;
+ } else {
+ format->format.code = state->format->code;
}
+
+ return 0;
+}
+
+static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7604_state *state = to_state(sd);
+ const struct adv7604_format_info *info;
+
+ if (format->pad != state->source_pad)
+ return -EINVAL;
+
+ info = adv7604_format_info(state, format->format.code);
+ if (info == NULL)
+ info = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8);
+
+ adv7604_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->code = format->format.code;
+ } else {
+ state->format = info;
+ adv7604_setup_format(state);
+ }
+
return 0;
}
static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
{
+ struct adv7604_state *state = to_state(sd);
+ const struct adv7604_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);
@@ -1625,7 +1957,9 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
/* format change */
fmt_change = irq_reg_0x43 & 0x98;
- fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0;
+ fmt_change_digital = is_digital_input(sd)
+ ? irq_reg_0x6b & info->fmt_change_digital_mask
+ : 0;
if (fmt_change || fmt_change_digital) {
v4l2_dbg(1, debug, sd,
@@ -1647,7 +1981,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
}
/* tx 5v detect */
- tx_5v = io_read(sd, 0x70) & 0x1e;
+ tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
if (tx_5v) {
v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
io_write(sd, 0x71, tx_5v);
@@ -1663,7 +1997,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
struct adv7604_state *state = to_state(sd);
u8 *data = NULL;
- if (edid->pad > ADV7604_EDID_PORT_D)
+ if (edid->pad > ADV7604_PAD_HDMI_PORT_D)
return -EINVAL;
if (edid->blocks == 0)
return -EINVAL;
@@ -1673,17 +2007,15 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return -EINVAL;
if (edid->start_block == 1)
edid->blocks = 1;
- if (!edid->edid)
- return -EINVAL;
if (edid->blocks > state->edid.blocks)
edid->blocks = state->edid.blocks;
switch (edid->pad) {
- case ADV7604_EDID_PORT_A:
- case ADV7604_EDID_PORT_B:
- case ADV7604_EDID_PORT_C:
- case ADV7604_EDID_PORT_D:
+ case ADV7604_PAD_HDMI_PORT_A:
+ case ADV7604_PAD_HDMI_PORT_B:
+ case ADV7604_PAD_HDMI_PORT_C:
+ case ADV7604_PAD_HDMI_PORT_D:
if (state->edid.present & (1 << edid->pad))
data = state->edid.edid;
break;
@@ -1731,20 +2063,20 @@ static int get_edid_spa_location(const u8 *edid)
static int adv7604_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;
int spa_loc;
- int tmp = 0;
int err;
int i;
- if (edid->pad > ADV7604_EDID_PORT_D)
+ if (edid->pad > ADV7604_PAD_HDMI_PORT_D)
return -EINVAL;
if (edid->start_block != 0)
return -EINVAL;
if (edid->blocks == 0) {
/* Disable hotplug and I2C access to EDID RAM from DDC port */
state->edid.present &= ~(1 << edid->pad);
- v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
- rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
+ adv7604_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 */
state->aspect_ratio.numerator = 16;
@@ -1761,43 +2093,47 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
edid->blocks = 2;
return -E2BIG;
}
- if (!edid->edid)
- return -EINVAL;
v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
__func__, edid->pad, state->edid.present);
/* Disable hotplug and I2C access to EDID RAM from DDC port */
cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
- v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp);
- rep_write_and_or(sd, 0x77, 0xf0, 0x00);
+ adv7604_set_hpd(state, 0);
+ rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00);
spa_loc = get_edid_spa_location(edid->edid);
if (spa_loc < 0)
spa_loc = 0xc0; /* Default value [REF_02, p. 116] */
switch (edid->pad) {
- case ADV7604_EDID_PORT_A:
+ case ADV7604_PAD_HDMI_PORT_A:
state->spa_port_a[0] = edid->edid[spa_loc];
state->spa_port_a[1] = edid->edid[spa_loc + 1];
break;
- case ADV7604_EDID_PORT_B:
+ case ADV7604_PAD_HDMI_PORT_B:
rep_write(sd, 0x70, edid->edid[spa_loc]);
rep_write(sd, 0x71, edid->edid[spa_loc + 1]);
break;
- case ADV7604_EDID_PORT_C:
+ case ADV7604_PAD_HDMI_PORT_C:
rep_write(sd, 0x72, edid->edid[spa_loc]);
rep_write(sd, 0x73, edid->edid[spa_loc + 1]);
break;
- case ADV7604_EDID_PORT_D:
+ case ADV7604_PAD_HDMI_PORT_D:
rep_write(sd, 0x74, edid->edid[spa_loc]);
rep_write(sd, 0x75, edid->edid[spa_loc + 1]);
break;
default:
return -EINVAL;
}
- rep_write(sd, 0x76, spa_loc & 0xff);
- rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40);
+
+ if (info->type == ADV7604) {
+ rep_write(sd, 0x76, spa_loc & 0xff);
+ rep_write_clr_set(sd, 0x77, 0x40, (spa_loc & 0x100) >> 2);
+ } else {
+ /* FIXME: Where is the SPA location LSB register ? */
+ rep_write_clr_set(sd, 0x71, 0x01, (spa_loc & 0x100) >> 8);
+ }
edid->edid[spa_loc] = state->spa_port_a[0];
edid->edid[spa_loc + 1] = state->spa_port_a[1];
@@ -1816,10 +2152,10 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
/* adv7604 calculates the checksums and enables I2C access to internal
EDID RAM from DDC port. */
- rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
+ rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present);
for (i = 0; i < 1000; i++) {
- if (rep_read(sd, 0x7d) & state->edid.present)
+ if (rep_read(sd, info->edid_status_reg) & state->edid.present)
break;
mdelay(1);
}
@@ -1882,17 +2218,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
static int adv7604_log_status(struct v4l2_subdev *sd)
{
struct adv7604_state *state = to_state(sd);
+ const struct adv7604_chip_info *info = state->info;
struct v4l2_dv_timings timings;
struct stdi_readback stdi;
u8 reg_io_0x02 = io_read(sd, 0x02);
+ u8 edid_enabled;
+ u8 cable_det;
- char *csc_coeff_sel_rb[16] = {
+ static const char * const csc_coeff_sel_rb[16] = {
"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
"reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709",
"reserved", "reserved", "reserved", "reserved", "manual"
};
- char *input_color_space_txt[16] = {
+ static const char * const input_color_space_txt[16] = {
"RGB limited range (16-235)", "RGB full range (0-255)",
"YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)",
"xvYCC Bt.601", "xvYCC Bt.709",
@@ -1900,12 +2239,12 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
"invalid", "invalid", "invalid", "invalid", "invalid",
"invalid", "invalid", "automatic"
};
- char *rgb_quantization_range_txt[] = {
+ static const char * const rgb_quantization_range_txt[] = {
"Automatic",
"RGB limited range (16-235)",
"RGB full range (0-255)",
};
- char *deep_color_mode_txt[4] = {
+ static const char * const deep_color_mode_txt[4] = {
"8-bits per channel",
"10-bits per channel",
"12-bits per channel",
@@ -1914,20 +2253,22 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "-----Chip status-----\n");
v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on");
+ edid_enabled = rep_read(sd, info->edid_status_reg);
v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n",
- ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"),
- ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"),
- ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"),
- ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No"));
+ ((edid_enabled & 0x01) ? "Yes" : "No"),
+ ((edid_enabled & 0x02) ? "Yes" : "No"),
+ ((edid_enabled & 0x04) ? "Yes" : "No"),
+ ((edid_enabled & 0x08) ? "Yes" : "No"));
v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ?
"enabled" : "disabled");
v4l2_info(sd, "-----Signal status-----\n");
+ cable_det = info->read_cable_det(sd);
v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n",
- ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"),
- ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"),
- ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"),
- ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No"));
+ ((cable_det & 0x01) ? "Yes" : "No"),
+ ((cable_det & 0x02) ? "Yes" : "No"),
+ ((cable_det & 0x04) ? "Yes" : "No"),
+ ((cable_det & 0x08) ? "Yes" : "No"));
v4l2_info(sd, "TMDS signal detected: %s\n",
no_signal_tmds(sd) ? "false" : "true");
v4l2_info(sd, "TMDS signal locked: %s\n",
@@ -2021,13 +2362,6 @@ static const struct v4l2_ctrl_ops adv7604_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7604_core_ops = {
.log_status = adv7604_log_status,
- .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
- .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
- .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
- .queryctrl = v4l2_subdev_queryctrl,
- .querymenu = v4l2_subdev_querymenu,
.interrupt_service_routine = adv7604_isr,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7604_g_register,
@@ -2041,17 +2375,16 @@ static const struct v4l2_subdev_video_ops adv7604_video_ops = {
.s_dv_timings = adv7604_s_dv_timings,
.g_dv_timings = adv7604_g_dv_timings,
.query_dv_timings = adv7604_query_dv_timings,
- .enum_dv_timings = adv7604_enum_dv_timings,
- .dv_timings_cap = adv7604_dv_timings_cap,
- .enum_mbus_fmt = adv7604_enum_mbus_fmt,
- .g_mbus_fmt = adv7604_g_mbus_fmt,
- .try_mbus_fmt = adv7604_g_mbus_fmt,
- .s_mbus_fmt = adv7604_g_mbus_fmt,
};
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_ops adv7604_ops = {
@@ -2100,6 +2433,7 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = {
static int adv7604_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;
hdmi_write(sd, 0x48,
@@ -2108,28 +2442,33 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
disable_input(sd);
+ if (pdata->default_input >= 0 &&
+ pdata->default_input < state->source_pad) {
+ state->selected_input = pdata->default_input;
+ select_input(sd);
+ enable_input(sd);
+ }
+
/* power */
io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */
io_write(sd, 0x0b, 0x44); /* Power down ESDP block */
cp_write(sd, 0xcf, 0x01); /* Power down macrovision */
/* video format */
- io_write_and_or(sd, 0x02, 0xf0,
+ io_write_clr_set(sd, 0x02, 0x0f,
pdata->alt_gamma << 3 |
pdata->op_656_range << 2 |
- pdata->rgb_out << 1 |
pdata->alt_data_sat << 0);
- io_write(sd, 0x03, pdata->op_format_sel);
- io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5);
- io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 |
- pdata->insert_av_codes << 2 |
- pdata->replicate_av_codes << 1 |
- pdata->invert_cbcr << 0);
+ 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);
cp_write(sd, 0x69, 0x30); /* Enable CP CSC */
/* VS, HS polarities */
- io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1);
+ io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 |
+ pdata->inv_hs_pol << 1 | pdata->inv_llc_pol);
/* Adjust drive strength */
io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 |
@@ -2146,52 +2485,46 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
for digital formats */
/* HDMI audio */
- hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */
- hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */
- hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */
+ hdmi_write_clr_set(sd, 0x15, 0x03, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */
+ hdmi_write_clr_set(sd, 0x1a, 0x0e, 0x08); /* Wait 1 s before unmute */
+ hdmi_write_clr_set(sd, 0x68, 0x06, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */
/* TODO from platform data */
afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */
- afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */
- io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4);
+ if (adv7604_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);
+ }
/* interrupts */
- io_write(sd, 0x40, 0xc2); /* Configure INT1 */
- io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
+ io_write(sd, 0x40, 0xc0 | pdata->int1_config); /* Configure INT1 */
io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */
- io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */
- io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */
+ io_write(sd, 0x6e, info->fmt_change_digital_mask); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */
+ io_write(sd, 0x73, info->cable_det_mask); /* Enable cable detection (+5v) interrupts */
+ info->setup_irqs(sd);
return v4l2_ctrl_handler_setup(sd->ctrl_handler);
}
+static void adv7604_setup_irqs(struct v4l2_subdev *sd)
+{
+ io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
+}
+
+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)
{
- if (state->i2c_avlink)
- i2c_unregister_device(state->i2c_avlink);
- if (state->i2c_cec)
- i2c_unregister_device(state->i2c_cec);
- if (state->i2c_infoframe)
- i2c_unregister_device(state->i2c_infoframe);
- if (state->i2c_esdp)
- i2c_unregister_device(state->i2c_esdp);
- if (state->i2c_dpp)
- i2c_unregister_device(state->i2c_dpp);
- if (state->i2c_afe)
- i2c_unregister_device(state->i2c_afe);
- if (state->i2c_repeater)
- i2c_unregister_device(state->i2c_repeater);
- if (state->i2c_edid)
- i2c_unregister_device(state->i2c_edid);
- if (state->i2c_hdmi)
- i2c_unregister_device(state->i2c_hdmi);
- if (state->i2c_test)
- i2c_unregister_device(state->i2c_test);
- if (state->i2c_cp)
- i2c_unregister_device(state->i2c_cp);
- if (state->i2c_vdp)
- i2c_unregister_device(state->i2c_vdp);
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) {
+ if (state->i2c_clients[i])
+ i2c_unregister_device(state->i2c_clients[i]);
+ }
}
static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd,
@@ -2204,15 +2537,219 @@ 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[] = {
+ /* 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 */
+
+ /* 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 */
+
+ { ADV7604_REG_SEQ_TERM, 0 },
+};
+
+static const struct adv7604_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 */
+
+ /* 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 */
+
+ { ADV7604_REG_SEQ_TERM, 0 },
+};
+
+static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = {
+ { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 },
+ { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x0c },
+ { 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 },
+};
+
+static const struct adv7604_chip_info adv7604_chip_info[] = {
+ [ADV7604] = {
+ .type = ADV7604,
+ .has_afe = true,
+ .max_port = ADV7604_PAD_VGA_COMP,
+ .num_dv_ports = 4,
+ .edid_enable_reg = 0x77,
+ .edid_status_reg = 0x7d,
+ .lcf_reg = 0xb3,
+ .tdms_lock_mask = 0xe0,
+ .cable_det_mask = 0x1e,
+ .fmt_change_digital_mask = 0xc1,
+ .formats = adv7604_formats,
+ .nformats = ARRAY_SIZE(adv7604_formats),
+ .set_termination = adv7604_set_termination,
+ .setup_irqs = adv7604_setup_irqs,
+ .read_hdmi_pixelclock = adv7604_read_hdmi_pixelclock,
+ .read_cable_det = adv7604_read_cable_det,
+ .recommended_settings = {
+ [0] = adv7604_recommended_settings_afe,
+ [1] = adv7604_recommended_settings_hdmi,
+ },
+ .num_recommended_settings = {
+ [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) |
+ 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(ADV7604_PAGE_VDP),
+ },
+ [ADV7611] = {
+ .type = ADV7611,
+ .has_afe = false,
+ .max_port = ADV7604_PAD_HDMI_PORT_A,
+ .num_dv_ports = 1,
+ .edid_enable_reg = 0x74,
+ .edid_status_reg = 0x76,
+ .lcf_reg = 0xa3,
+ .tdms_lock_mask = 0x43,
+ .cable_det_mask = 0x01,
+ .fmt_change_digital_mask = 0x03,
+ .formats = adv7611_formats,
+ .nformats = ARRAY_SIZE(adv7611_formats),
+ .set_termination = adv7611_set_termination,
+ .setup_irqs = adv7611_setup_irqs,
+ .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock,
+ .read_cable_det = adv7611_read_cable_det,
+ .recommended_settings = {
+ [1] = adv7611_recommended_settings_hdmi,
+ },
+ .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),
+ },
+};
+
+static struct i2c_device_id adv7604_i2c_id[] = {
+ { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] },
+ { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id);
+
+static struct of_device_id adv7604_of_id[] __maybe_unused = {
+ { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adv7604_of_id);
+
+static int adv7604_parse_dt(struct adv7604_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;
+
+ /* Parse the endpoint. */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ if (!endpoint)
+ return -EINVAL;
+
+ v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+ of_node_put(endpoint);
+
+ flags = bus_cfg.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ state->pdata.inv_hs_pol = 1;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ state->pdata.inv_vs_pol = 1;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ state->pdata.inv_llc_pol = 1;
+
+ if (bus_cfg.bus_type == V4L2_MBUS_BT656) {
+ state->pdata.insert_av_codes = 1;
+ state->pdata.op_656_range = 1;
+ }
+
+ /* Disable the interrupt for now as no DT-based board uses it. */
+ state->pdata.int1_config = ADV7604_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[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[ADV7604_PAGE_VDP] = 0x24;
+
+ /* Hardcode the remaining platform data fields. */
+ state->pdata.disable_pwrdnb = 0;
+ state->pdata.disable_cable_det_rst = 0;
+ state->pdata.default_input = -1;
+ state->pdata.blank_data = 1;
+ state->pdata.alt_data_sat = 1;
+ state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0;
+ state->pdata.bus_order = ADV7604_BUS_ORDER_RGB;
+
+ return 0;
+}
+
static int adv7604_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 adv7604_platform_data *pdata = client->dev.platform_data;
struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
+ unsigned int i;
+ u16 val;
int err;
/* Check if the adapter supports the needed features */
@@ -2227,32 +2764,80 @@ static int adv7604_probe(struct i2c_client *client,
return -ENOMEM;
}
+ state->i2c_clients[ADV7604_PAGE_IO] = client;
+
/* initialize variables */
state->restart_stdi_once = true;
state->selected_input = ~0;
- /* platform data */
- if (!pdata) {
+ 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);
+ state->info = oid->data;
+
+ err = adv7604_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;
+
+ state->info = (const struct adv7604_chip_info *)id->driver_data;
+ state->pdata = *pdata;
+ } else {
v4l_err(client, "No platform data!\n");
return -ENODEV;
}
- state->pdata = *pdata;
+
+ /* Request GPIOs. */
+ for (i = 0; i < state->info->num_dv_ports; ++i) {
+ state->hpd_gpio[i] =
+ devm_gpiod_get_index(&client->dev, "hpd", i);
+ if (IS_ERR(state->hpd_gpio[i]))
+ continue;
+
+ gpiod_direction_output(state->hpd_gpio[i], 0);
+
+ v4l_info(client, "Handling HPD %u GPIO\n", i);
+ }
+
state->timings = cea640x480;
+ state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8);
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7604_ops);
+ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
+ id->name, i2c_adapter_id(client->adapter),
+ client->addr);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- /* i2c access to adv7604? */
- if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
- v4l2_info(sd, "not an adv7604 on address 0x%x\n",
- client->addr << 1);
- return -ENODEV;
+ /*
+ * Verify that the chip is present. On ADV7604 the RD_INFO register only
+ * identifies the revision, while on ADV7611 it identifies the model as
+ * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611.
+ */
+ if (state->info->type == ADV7604) {
+ val = adv_smbus_read_byte_data_check(client, 0xfb, false);
+ if (val != 0x68) {
+ v4l2_info(sd, "not an adv7604 on address 0x%x\n",
+ client->addr << 1);
+ return -ENODEV;
+ }
+ } else {
+ val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8)
+ | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0);
+ if (val != 0x2051) {
+ v4l2_info(sd, "not an adv7611 on address 0x%x\n",
+ client->addr << 1);
+ return -ENODEV;
+ }
}
/* control handlers */
hdl = &state->hdl;
- v4l2_ctrl_handler_init(hdl, 9);
+ v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8);
v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
@@ -2265,15 +2850,17 @@ static int adv7604_probe(struct i2c_client *client,
/* private controls */
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0);
+ 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_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
0, V4L2_DV_RGB_RANGE_AUTO);
/* custom controls */
- state->analog_sampling_phase_ctrl =
- v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL);
+ if (adv7604_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);
state->free_run_color_ctrl =
@@ -2286,7 +2873,8 @@ static int adv7604_probe(struct i2c_client *client,
}
state->detect_tx_5v_ctrl->is_private = true;
state->rgb_quantization_range_ctrl->is_private = true;
- state->analog_sampling_phase_ctrl->is_private = true;
+ if (adv7604_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;
@@ -2295,25 +2883,18 @@ static int adv7604_probe(struct i2c_client *client,
goto err_hdl;
}
- state->i2c_avlink = adv7604_dummy_client(sd, pdata->i2c_avlink, 0xf3);
- state->i2c_cec = adv7604_dummy_client(sd, pdata->i2c_cec, 0xf4);
- state->i2c_infoframe = adv7604_dummy_client(sd, pdata->i2c_infoframe, 0xf5);
- state->i2c_esdp = adv7604_dummy_client(sd, pdata->i2c_esdp, 0xf6);
- state->i2c_dpp = adv7604_dummy_client(sd, pdata->i2c_dpp, 0xf7);
- state->i2c_afe = adv7604_dummy_client(sd, pdata->i2c_afe, 0xf8);
- state->i2c_repeater = adv7604_dummy_client(sd, pdata->i2c_repeater, 0xf9);
- state->i2c_edid = adv7604_dummy_client(sd, pdata->i2c_edid, 0xfa);
- state->i2c_hdmi = adv7604_dummy_client(sd, pdata->i2c_hdmi, 0xfb);
- state->i2c_test = adv7604_dummy_client(sd, pdata->i2c_test, 0xfc);
- state->i2c_cp = adv7604_dummy_client(sd, pdata->i2c_cp, 0xfd);
- state->i2c_vdp = adv7604_dummy_client(sd, pdata->i2c_vdp, 0xfe);
- if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe ||
- !state->i2c_esdp || !state->i2c_dpp || !state->i2c_afe ||
- !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi ||
- !state->i2c_test || !state->i2c_cp || !state->i2c_vdp) {
- err = -ENOMEM;
- v4l2_err(sd, "failed to create all i2c clients\n");
- goto err_i2c;
+ for (i = 1; i < ADV7604_PAGE_MAX; ++i) {
+ if (!(BIT(i) & state->info->page_mask))
+ continue;
+
+ state->i2c_clients[i] =
+ adv7604_dummy_client(sd, state->pdata.i2c_addresses[i],
+ 0xf2 + i);
+ if (state->i2c_clients[i] == NULL) {
+ err = -ENOMEM;
+ v4l2_err(sd, "failed to create i2c client %u\n", i);
+ goto err_i2c;
+ }
}
/* work queues */
@@ -2327,8 +2908,14 @@ static int adv7604_probe(struct i2c_client *client,
INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
adv7604_delayed_work_enable_hotplug);
- state->pad.flags = MEDIA_PAD_FL_SOURCE;
- err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ state->source_pad = state->info->num_dv_ports
+ + (state->info->has_afe ? 2 : 0);
+ for (i = 0; i < state->source_pad; ++i)
+ state->pads[i].flags = MEDIA_PAD_FL_SINK;
+ state->pads[state->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+
+ err = media_entity_init(&sd->entity, state->source_pad + 1,
+ state->pads, 0);
if (err)
goto err_work_queues;
@@ -2337,6 +2924,11 @@ static int adv7604_probe(struct i2c_client *client,
goto err_entity;
v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
client->addr << 1, client->adapter->name);
+
+ err = v4l2_async_register_subdev(sd);
+ if (err)
+ goto err_entity;
+
return 0;
err_entity:
@@ -2360,6 +2952,7 @@ static int adv7604_remove(struct i2c_client *client)
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));
@@ -2369,20 +2962,15 @@ static int adv7604_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static struct i2c_device_id adv7604_id[] = {
- { "adv7604", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, adv7604_id);
-
static struct i2c_driver adv7604_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "adv7604",
+ .of_match_table = of_match_ptr(adv7604_of_id),
},
.probe = adv7604_probe,
.remove = adv7604_remove,
- .id_table = adv7604_id,
+ .id_table = adv7604_i2c_id,
};
module_i2c_driver(adv7604_driver);
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 636ac08925f..0d554919cdd 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1399,6 +1399,9 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
static int adv7842_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings,
adv7842_get_dv_timings_cap(sd), adv7842_check_dv_timings, NULL);
}
@@ -1406,6 +1409,9 @@ static int adv7842_enum_dv_timings(struct v4l2_subdev *sd,
static int adv7842_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = *adv7842_get_dv_timings_cap(sd);
return 0;
}
@@ -2000,6 +2006,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
if (irq_status[5] & 0x08) {
v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__,
(io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI");
+ set_rgb_quantization_range(sd);
if (handled)
*handled = true;
}
@@ -2029,8 +2036,6 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return -EINVAL;
if (edid->start_block == 1)
edid->blocks = 1;
- if (!edid->edid)
- return -EINVAL;
switch (edid->pad) {
case ADV7842_EDID_PORT_A:
@@ -2065,8 +2070,6 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return -EINVAL;
if (e->blocks > 2)
return -E2BIG;
- if (!e->edid)
- return -EINVAL;
/* todo, per edid */
state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15],
@@ -2610,6 +2613,12 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
disable_input(sd);
+ /*
+ * Disable I2C access to internal EDID ram from HDMI DDC ports
+ * Disable auto edid enable when leaving powerdown mode
+ */
+ rep_write_and_or(sd, 0x77, 0xd3, 0x20);
+
/* power */
io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */
io_write(sd, 0x15, 0x80); /* Power up pads */
@@ -2690,9 +2699,6 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
enable_input(sd);
- /* disable I2C access to internal EDID ram from HDMI DDC ports */
- rep_write_and_or(sd, 0x77, 0xf3, 0x00);
-
if (pdata->hpa_auto) {
/* HPA auto, HPA 0.5s after Edid set and Cable detect */
hdmi_write(sd, 0x69, 0x5c);
@@ -2869,8 +2875,6 @@ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7842_core_ops = {
.log_status = adv7842_log_status,
- .g_std = adv7842_g_std,
- .s_std = adv7842_s_std,
.ioctl = adv7842_ioctl,
.interrupt_service_routine = adv7842_isr,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2880,14 +2884,14 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = {
};
static const struct v4l2_subdev_video_ops adv7842_video_ops = {
+ .g_std = adv7842_g_std,
+ .s_std = adv7842_s_std,
.s_routing = adv7842_s_routing,
.querystd = adv7842_querystd,
.g_input_status = adv7842_g_input_status,
.s_dv_timings = adv7842_s_dv_timings,
.g_dv_timings = adv7842_g_dv_timings,
.query_dv_timings = adv7842_query_dv_timings,
- .enum_dv_timings = adv7842_enum_dv_timings,
- .dv_timings_cap = adv7842_dv_timings_cap,
.enum_mbus_fmt = adv7842_enum_mbus_fmt,
.g_mbus_fmt = adv7842_g_mbus_fmt,
.try_mbus_fmt = adv7842_g_mbus_fmt,
@@ -2897,6 +2901,8 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = {
static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {
.get_edid = adv7842_get_edid,
.set_edid = adv7842_set_edid,
+ .enum_dv_timings = adv7842_enum_dv_timings,
+ .dv_timings_cap = adv7842_dv_timings_cap,
};
static const struct v4l2_subdev_ops adv7842_ops = {
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
index 369cf6ff88f..76b334a6a56 100644
--- a/drivers/media/i2c/bt819.c
+++ b/drivers/media/i2c/bt819.c
@@ -387,10 +387,10 @@ static const struct v4l2_subdev_core_ops bt819_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = bt819_s_std,
};
static const struct v4l2_subdev_video_ops bt819_video_ops = {
+ .s_std = bt819_s_std,
.s_routing = bt819_s_routing,
.s_stream = bt819_s_stream,
.querystd = bt819_querystd,
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 2e3771d5735..e453a3ffe7d 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -5041,8 +5041,6 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = cx25840_s_std,
- .g_std = cx25840_g_std,
.reset = cx25840_reset,
.load_fw = cx25840_load_fw,
.s_io_pin_config = common_s_io_pin_config,
@@ -5067,6 +5065,8 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
};
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+ .s_std = cx25840_s_std,
+ .g_std = cx25840_g_std,
.s_routing = cx25840_s_video_routing,
.s_mbus_fmt = cx25840_s_mbus_fmt,
.s_stream = cx25840_s_stream,
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
index c3e94ae82c0..25b81bc58c8 100644
--- a/drivers/media/i2c/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
@@ -648,11 +648,8 @@ static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops ks0127_core_ops = {
- .s_std = ks0127_s_std,
-};
-
static const struct v4l2_subdev_video_ops ks0127_video_ops = {
+ .s_std = ks0127_s_std,
.s_routing = ks0127_s_routing,
.s_stream = ks0127_s_stream,
.querystd = ks0127_querystd,
@@ -660,7 +657,6 @@ static const struct v4l2_subdev_video_ops ks0127_video_ops = {
};
static const struct v4l2_subdev_ops ks0127_ops = {
- .core = &ks0127_core_ops,
.video = &ks0127_video_ops,
};
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
index ab34ccedf31..1a03d02bd4d 100644
--- a/drivers/media/i2c/m5mols/m5mols_capture.c
+++ b/drivers/media/i2c/m5mols/m5mols_capture.c
@@ -26,7 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/m5mols.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "m5mols.h"
#include "m5mols_reg.h"
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index a9110d8bbbc..2cace7313a2 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -276,6 +276,7 @@ static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
};
static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
+ .s_std = ml86v7667_s_std,
.querystd = ml86v7667_querystd,
.g_input_status = ml86v7667_g_input_status,
.enum_mbus_fmt = ml86v7667_enum_mbus_fmt,
@@ -286,7 +287,6 @@ static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
};
static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
- .s_std = ml86v7667_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ml86v7667_g_register,
.s_register = ml86v7667_s_register,
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 8190fec6808..4d9c6bc3426 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -649,10 +649,10 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = msp_s_std,
};
static const struct v4l2_subdev_video_ops msp_video_ops = {
+ .s_std = msp_s_std,
.querystd = msp_querystd,
};
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 33daace8129..e18797ff7fa 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -647,6 +647,28 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
#define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004)
#define V4L2_CID_BLC_DIGITAL_OFFSET (V4L2_CID_USER_BASE | 0x1005)
+static int mt9p031_restore_blc(struct mt9p031 *mt9p031)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ int ret;
+
+ if (mt9p031->blc_auto->cur.val != 0) {
+ ret = mt9p031_set_mode2(mt9p031, 0,
+ MT9P031_READ_MODE_2_ROW_BLC);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (mt9p031->blc_offset->cur.val != 0) {
+ ret = mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
+ mt9p031->blc_offset->cur.val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9p031 *mt9p031 =
@@ -655,6 +677,9 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
u16 data;
int ret;
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
@@ -709,18 +734,20 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
MT9P031_READ_MODE_2_ROW_MIR, 0);
case V4L2_CID_TEST_PATTERN:
+ /* The digital side of the Black Level Calibration function must
+ * be disabled when generating a test pattern to avoid artifacts
+ * in the image. Activate (deactivate) the BLC-related controls
+ * when the test pattern is enabled (disabled).
+ */
+ v4l2_ctrl_activate(mt9p031->blc_auto, ctrl->val == 0);
+ v4l2_ctrl_activate(mt9p031->blc_offset, ctrl->val == 0);
+
if (!ctrl->val) {
- /* Restore the black level compensation settings. */
- if (mt9p031->blc_auto->cur.val != 0) {
- ret = mt9p031_s_ctrl(mt9p031->blc_auto);
- if (ret < 0)
- return ret;
- }
- if (mt9p031->blc_offset->cur.val != 0) {
- ret = mt9p031_s_ctrl(mt9p031->blc_offset);
- if (ret < 0)
- return ret;
- }
+ /* Restore the BLC settings. */
+ ret = mt9p031_restore_blc(mt9p031);
+ if (ret < 0)
+ return ret;
+
return mt9p031_write(client, MT9P031_TEST_PATTERN,
MT9P031_TEST_PATTERN_DISABLE);
}
@@ -735,9 +762,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
if (ret < 0)
return ret;
- /* Disable digital black level compensation when using a test
- * pattern.
- */
+ /* Disable digital BLC when generating a test pattern. */
ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
0);
if (ret < 0)
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index e8a1ce20403..cdd7c1b7259 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1109,7 +1109,7 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
* windows that fall outside that.
*/
for (i = 0; i < n_win_sizes; i++) {
- struct ov7670_win_size *win = &info->devtype->win_sizes[index];
+ struct ov7670_win_size *win = &info->devtype->win_sizes[i];
if (info->min_width && win->width < info->min_width)
continue;
if (info->min_height && win->height < info->min_height)
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index a4459301b5f..ee0f57e01b5 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1616,7 +1616,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
if (ret < 0)
return -EINVAL;
- node_ep = v4l2_of_get_next_endpoint(node, NULL);
+ node_ep = of_graph_get_next_endpoint(node, NULL);
if (!node_ep) {
dev_warn(dev, "no endpoint defined for node: %s\n",
node->full_name);
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 8272c0b9c5b..04e9e55018a 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -643,10 +643,10 @@ static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
.init = saa6752hs_init,
- .s_std = saa6752hs_s_std,
};
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
+ .s_std = saa6752hs_s_std,
.s_mbus_fmt = saa6752hs_s_mbus_fmt,
.try_mbus_fmt = saa6752hs_try_mbus_fmt,
.g_mbus_fmt = saa6752hs_g_mbus_fmt,
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
index ac43e929a1d..99689ee57d7 100644
--- a/drivers/media/i2c/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
@@ -365,10 +365,10 @@ static const struct v4l2_subdev_core_ops saa7110_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = saa7110_s_std,
};
static const struct v4l2_subdev_video_ops saa7110_video_ops = {
+ .s_std = saa7110_s_std,
.s_routing = saa7110_s_routing,
.s_stream = saa7110_s_stream,
.querystd = saa7110_querystd,
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index afdbcb045ce..35a44648150 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -1582,7 +1582,6 @@ static const struct v4l2_subdev_core_ops saa711x_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = saa711x_s_std,
.reset = saa711x_reset,
.s_gpio = saa711x_s_gpio,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1601,6 +1600,7 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
};
static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+ .s_std = saa711x_s_std,
.s_routing = saa711x_s_routing,
.s_crystal_freq = saa711x_s_crystal_freq,
.s_mbus_fmt = saa711x_s_mbus_fmt,
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index 401ca114ab9..6922a9f9a5c 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -1198,7 +1198,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = {
.g_register = saa717x_g_register,
.s_register = saa717x_s_register,
#endif
- .s_std = saa717x_s_std,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1216,6 +1215,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
};
static const struct v4l2_subdev_video_ops saa717x_video_ops = {
+ .s_std = saa717x_s_std,
.s_routing = saa717x_s_video_routing,
.s_mbus_fmt = saa717x_s_mbus_fmt,
.s_stream = saa717x_s_stream,
diff --git a/drivers/media/i2c/saa7191.c b/drivers/media/i2c/saa7191.c
index 606a4baf944..8e9699268a6 100644
--- a/drivers/media/i2c/saa7191.c
+++ b/drivers/media/i2c/saa7191.c
@@ -573,10 +573,10 @@ static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
static const struct v4l2_subdev_core_ops saa7191_core_ops = {
.g_ctrl = saa7191_g_ctrl,
.s_ctrl = saa7191_s_ctrl,
- .s_std = saa7191_s_std,
};
static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+ .s_std = saa7191_s_std,
.s_routing = saa7191_s_routing,
.querystd = saa7191_querystd,
.g_input_status = saa7191_g_input_status,
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
index a4a649834a1..5ce2b61da3c 100644
--- a/drivers/media/i2c/smiapp-pll.h
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -46,7 +46,7 @@ struct smiapp_pll {
uint8_t bus_width;
} parallel;
};
- uint8_t flags;
+ unsigned long flags;
uint8_t binning_horizontal;
uint8_t binning_vertical;
uint8_t scale_m;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 8741cae9c9f..06fb03291d5 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -606,7 +606,7 @@ static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
if (rval)
return rval;
sensor->limits[limit[i]] = val;
- dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+ dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
smiapp_reg_limits[limit[i]].addr,
smiapp_reg_limits[limit[i]].what, val, val);
}
@@ -741,8 +741,8 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
if (rval)
return rval;
- dev_dbg(&client->dev, "bpp %d, compressed %d\n",
- fmt >> 8, (u8)fmt);
+ dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n",
+ i, fmt >> 8, (u8)fmt);
for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
const struct smiapp_csi_data_format *f =
@@ -1128,7 +1128,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
}
usleep_range(1000, 1000);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 1);
sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
@@ -1238,7 +1238,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
return 0;
out_cci_addr_fail:
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
@@ -1264,7 +1264,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
SMIAPP_REG_U8_SOFTWARE_RESET,
SMIAPP_SOFTWARE_RESET);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
@@ -1766,7 +1766,7 @@ static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
unsigned int i;
unsigned int binh = 1, binv = 1;
- unsigned int best = scaling_goodness(
+ int best = scaling_goodness(
subdev,
crops[SMIAPP_PAD_SINK]->width, sel->r.width,
crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
@@ -2355,17 +2355,17 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
unsigned int i;
int rval;
- sensor->vana = devm_regulator_get(&client->dev, "VANA");
+ sensor->vana = devm_regulator_get(&client->dev, "vana");
if (IS_ERR(sensor->vana)) {
dev_err(&client->dev, "could not get regulator for vana\n");
- return -ENODEV;
+ return PTR_ERR(sensor->vana);
}
if (!sensor->platform_data->set_xclk) {
sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk");
if (IS_ERR(sensor->ext_clk)) {
dev_err(&client->dev, "could not get clock\n");
- return -ENODEV;
+ return PTR_ERR(sensor->ext_clk);
}
rval = clk_set_rate(sensor->ext_clk,
@@ -2374,18 +2374,19 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
dev_err(&client->dev,
"unable to set clock freq to %u\n",
sensor->platform_data->ext_clk);
- return -ENODEV;
+ return rval;
}
}
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
- if (devm_gpio_request_one(&client->dev,
- sensor->platform_data->xshutdown, 0,
- "SMIA++ xshutdown") != 0) {
+ if (gpio_is_valid(sensor->platform_data->xshutdown)) {
+ rval = devm_gpio_request_one(
+ &client->dev, sensor->platform_data->xshutdown, 0,
+ "SMIA++ xshutdown");
+ if (rval < 0) {
dev_err(&client->dev,
"unable to acquire reset gpio %d\n",
sensor->platform_data->xshutdown);
- return -ENODEV;
+ return rval;
}
}
@@ -2423,6 +2424,12 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
SMIAPP_IMAGE_ORIENTATION_VFLIP;
+ rval = smiapp_call_quirk(sensor, limits);
+ if (rval) {
+ dev_err(&client->dev, "limits quirks failed\n");
+ goto out_power_off;
+ }
+
rval = smiapp_get_mbus_formats(sensor);
if (rval) {
rval = -ENODEV;
@@ -2483,12 +2490,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
}
- rval = smiapp_call_quirk(sensor, limits);
- if (rval) {
- dev_err(&client->dev, "limits quirks failed\n");
- goto out_nvm_release;
- }
-
/* We consider this as profile 0 sensor if any of these are zero. */
if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
!sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
@@ -2543,8 +2544,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
snprintf(this->sd.name,
- sizeof(this->sd.name), "%s %s",
- sensor->minfo.name, _this->name);
+ sizeof(this->sd.name), "%s %d-%4.4x %s",
+ sensor->minfo.name, i2c_adapter_id(client->adapter),
+ client->addr, _this->name);
this->sink_fmt.width =
sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2616,12 +2618,11 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
pll->csi2.lanes = sensor->platform_data->lanes;
pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+ pll->flags = smiapp_call_quirk(sensor, pll_flags);
+
/* Profile 0 sensors have no separate OP clock branch. */
if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
- if (smiapp_needs_quirk(sensor,
- SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
- pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
rval = smiapp_update_mode(sensor);
@@ -2830,7 +2831,7 @@ static int smiapp_remove(struct i2c_client *client)
unsigned int i;
if (sensor->power_count) {
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
index bb8c506e0e3..e0bee875212 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.c
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -28,7 +28,7 @@
static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
{
- return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+ return smiapp_write(sensor, SMIAPP_REG_MK_U8(reg), val);
}
static int smiapp_write_8s(struct smiapp_sensor *sensor,
@@ -61,52 +61,6 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor,
sensor->limits[limit] = val;
}
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- const struct smia_reg *sreg;
-
- if (!sensor->minfo.quirk)
- return false;
-
- sreg = sensor->minfo.quirk->regs;
-
- if (!sreg)
- return false;
-
- while (sreg->type) {
- u16 type = reg >> 16;
- u16 reg16 = reg;
-
- if (sreg->type != type || sreg->reg != reg16) {
- sreg++;
- continue;
- }
-
- switch ((u8)type) {
- case SMIA_REG_8BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_16BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_32BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
- reg, sreg->val);
- break;
- }
-
- *val = sreg->val;
-
- return true;
- }
-
- return false;
-}
-
static int jt8ew9_limits(struct smiapp_sensor *sensor)
{
if (sensor->minfo.revision_number_major < 0x03)
@@ -266,12 +220,17 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
return smiapp_write_8(sensor, 0x3328, 0x80);
}
+static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor)
+{
+ return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+}
+
const struct smiapp_quirk smiapp_jt8ev1_quirk = {
.limits = jt8ev1_limits,
.post_poweron = jt8ev1_post_poweron,
.pre_streamon = jt8ev1_pre_streamon,
.post_streamoff = jt8ev1_post_streamoff,
- .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+ .pll_flags = jt8ev1_pll_flags,
};
static int tcm8500md_limits(struct smiapp_sensor *sensor)
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h
index 504a6d80ced..46e9ea8bfa0 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.h
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.h
@@ -35,19 +35,30 @@ struct smiapp_sensor;
* @post_poweron: Called always after the sensor has been fully powered on.
* @pre_streamon: Called just before streaming is enabled.
* @post_streamon: Called right after stopping streaming.
+ * @reg_access: Register access quirk. The quirk may divert the access
+ * to another register, or no register at all.
+ *
+ * @write: Is this read (false) or write (true) access?
+ * @reg: Pointer to the register to access
+ * @value: Register value, set by the caller on write, or
+ * by the quirk on read
+ *
+ * @return: 0 on success, -ENOIOCTLCMD if no register
+ * access may be done by the caller (default read
+ * value is zero), else negative error code on error
*/
struct smiapp_quirk {
int (*limits)(struct smiapp_sensor *sensor);
int (*post_poweron)(struct smiapp_sensor *sensor);
int (*pre_streamon)(struct smiapp_sensor *sensor);
int (*post_streamoff)(struct smiapp_sensor *sensor);
- const struct smia_reg *regs;
+ unsigned long (*pll_flags)(struct smiapp_sensor *sensor);
+ int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg,
+ u32 *val);
unsigned long flags;
};
-/* op pix clock is for all lanes in total normally */
-#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
-#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 1)
+#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0)
struct smiapp_reg_8 {
u16 reg;
@@ -56,12 +67,9 @@ struct smiapp_reg_8 {
void smiapp_replace_limit(struct smiapp_sensor *sensor,
u32 limit, u32 val);
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val);
-#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
+#define SMIAPP_MK_QUIRK_REG_8(_reg, _val) \
{ \
- .type = (_reg >> 16), \
.reg = (u16)_reg, \
.val = _val, \
}
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h