diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 02:16:59 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 02:16:59 +0200 |
commit | ef1c4a6fa91bbbe9b09f770d28eba31a9edf770c (patch) | |
tree | 52f5d175031c553160d14890e876ffc5432d2467 | |
parent | Merge tag 'kconfig-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ma... (diff) | |
parent | media: v4l2-ioctl: rename a temp var that stores _IOC_SIZE(cmd) (diff) | |
download | linux-ef1c4a6fa91bbbe9b09f770d28eba31a9edf770c.tar.xz linux-ef1c4a6fa91bbbe9b09f770d28eba31a9edf770c.zip |
Merge tag 'media/v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- new CEC pin injection code for testing purposes
- DVB frontend cxd2099 promoted from staging
- new platform driver for Sony cxd2880 DVB devices
- new sensor drivers: mt9t112, ov2685, ov5695, ov772x, tda1997x,
tw9910.c
- removal of unused cx18 and ivtv alsa mixers
- the reneseas-ceu driver doesn't depend on soc_camera anymore and
moved from staging
- removed the mantis_vp3028 driver, unused since 2009
- s5p-mfc: add support for version 10 of the MSP
- added a decoder for imon protocol
- atomisp: lots of cleanups
- imx074 and mt9t031: don't depend on soc_camera anymore, being
promoted from staging
- added helper functions to better support DVB I2C binding
- lots of driver improvements and cleanups
* tag 'media/v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (438 commits)
media: v4l2-ioctl: rename a temp var that stores _IOC_SIZE(cmd)
media: fimc-capture: get rid of two warnings
media: dvb-usb-v2: fix a missing dependency of I2C_MUX
media: uvc: to the right check at uvc_ioctl_enum_framesizes()
media: cec-core: fix a bug at cec_error_inj_write()
media: tda9840: cleanup a warning
media: tm6000: avoid casting just to print pointer address
media: em28xx-input: improve error handling code
media: zr364xx: avoid casting just to print pointer address
media: vivid-radio-rx: add a cast to avoid a warning
media: saa7134-alsa: don't use casts to print a buffer address
media: solo6x10: get rid of an address space warning
media: zoran: don't cast pointers to print them
media: ir-kbd-i2c: change the if logic to avoid a warning
media: ir-kbd-i2c: improve error handling code
media: saa7134-input: improve error handling
media: s2255drv: fix a casting warning
media: ivtvfb: Cleanup some warnings
media: videobuf-dma-sg: Fix a weird cast
soc_camera: fix a weird cast on printk
...
572 files changed, 37792 insertions, 21327 deletions
diff --git a/Documentation/ABI/testing/debugfs-cec-error-inj b/Documentation/ABI/testing/debugfs-cec-error-inj new file mode 100644 index 000000000000..122b65c5fe62 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-cec-error-inj @@ -0,0 +1,40 @@ +What: /sys/kernel/debug/cec/*/error-inj +Date: March 2018 +Contact: Hans Verkuil <hans.verkuil@cisco.com> +Description: + +The CEC Framework allows for CEC error injection commands through +debugfs. Drivers that support this will create an error-inj file +through which the error injection commands can be given. + +The basic syntax is as follows: + +Leading spaces/tabs are ignored. If the next character is a '#' or the +end of the line was reached, then the whole line is ignored. Otherwise +a command is expected. + +It is up to the driver to decide what commands to implement. The only +exception is that the command 'clear' without any arguments must be +implemented and that it will remove all current error injection +commands. + +This ensures that you can always do 'echo clear >error-inj' to clear any +error injections without having to know the details of the driver-specific +commands. + +Note that the output of 'error-inj' shall be valid as input to 'error-inj'. +So this must work: + + $ cat error-inj >einj.txt + $ cat einj.txt >error-inj + +Other than these basic rules described above this ABI is not considered +stable and may change in the future. + +Drivers that implement this functionality must document the commands as +part of the CEC documentation and must keep that documentation up to date +when changes are made. + +The following CEC error injection implementations exist: + +- Documentation/media/uapi/cec/cec-pin-error-inj.rst diff --git a/Documentation/devicetree/bindings/media/coda.txt b/Documentation/devicetree/bindings/media/coda.txt index 2865d04e4030..90eb74cc1993 100644 --- a/Documentation/devicetree/bindings/media/coda.txt +++ b/Documentation/devicetree/bindings/media/coda.txt @@ -7,8 +7,9 @@ called VPU (Video Processing Unit). Required properties: - compatible : should be "fsl,<chip>-src" for i.MX SoCs: (a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27 - (b) "fsl,imx53-vpu" for CODA7541 present in i.MX53 - (c) "fsl,imx6q-vpu" for CODA960 present in i.MX6q + (b) "fsl,imx51-vpu" for CodaHx4 present in i.MX51 + (c) "fsl,imx53-vpu" for CODA7541 present in i.MX53 + (d) "fsl,imx6q-vpu" for CODA960 present in i.MX6q - reg: should be register base and length as documented in the SoC reference manual - interrupts : Should contain the VPU interrupt. For CODA960, diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index 9cbd92eb5d05..dcf57e7c60eb 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -13,7 +13,11 @@ Required Properties: - "adi,adv7611" for the ADV7611 - "adi,adv7612" for the ADV7612 - - reg: I2C slave address + - reg: I2C slave addresses + The ADV76xx has up to thirteen 256-byte maps that can be accessed via the + main I2C ports. Each map has it own I2C address and acts as a standard + slave device on the I2C bus. The main address is mandatory, others are + optional and revert to defaults if not specified. - hpd-gpios: References to the GPIOs that control the HDMI hot-plug detection pins, one per HDMI input. The active flag indicates the GPIO @@ -35,6 +39,11 @@ Optional Properties: - reset-gpios: Reference to the GPIO connected to the device's reset pin. - default-input: Select which input is selected after reset. + - reg-names : Names of maps with programmable addresses. + It can contain any map needing a non-default address. + Possible maps names are : + "main", "avlink", "cec", "infoframe", "esdp", "dpp", "afe", + "rep", "edid", "hdmi", "test", "cp", "vdp" Optional Endpoint Properties: @@ -52,7 +61,12 @@ Example: hdmi_receiver@4c { compatible = "adi,adv7611"; - reg = <0x4c>; + /* + * The edid page will be accessible @ 0x66 on the I2C bus. All + * other maps will retain their default addresses. + */ + reg = <0x4c>, <0x66>; + reg-names "main", "edid"; reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; diff --git a/Documentation/devicetree/bindings/media/i2c/ov2685.txt b/Documentation/devicetree/bindings/media/i2c/ov2685.txt new file mode 100644 index 000000000000..625c4a8c0d53 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov2685.txt @@ -0,0 +1,41 @@ +* Omnivision OV2685 MIPI CSI-2 sensor + +Required Properties: +- compatible: shall be "ovti,ov2685" +- clocks: reference to the xvclk input clock +- clock-names: shall be "xvclk" +- avdd-supply: Analog voltage supply, 2.8 volts +- dovdd-supply: Digital I/O voltage supply, 1.8 volts +- dvdd-supply: Digital core voltage supply, 1.8 volts +- reset-gpios: Low active reset gpio + +The device node shall contain one 'port' child node with an +'endpoint' subnode for its digital output video port, +in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. +The endpoint optional property 'data-lanes' shall be "<1>". + +Example: +&i2c7 { + ov2685: camera-sensor@3c { + compatible = "ovti,ov2685"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&clk_24m_cam>; + + clocks = <&cru SCLK_TESTCLKOUT1>; + clock-names = "xvclk"; + + avdd-supply = <&pp2800_cam>; + dovdd-supply = <&pp1800>; + dvdd-supply = <&pp1800>; + reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/i2c/ov5695.txt b/Documentation/devicetree/bindings/media/i2c/ov5695.txt new file mode 100644 index 000000000000..640a63717d96 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov5695.txt @@ -0,0 +1,41 @@ +* Omnivision OV5695 MIPI CSI-2 sensor + +Required Properties: +- compatible: shall be "ovti,ov5695" +- clocks: reference to the xvclk input clock +- clock-names: shall be "xvclk" +- avdd-supply: Analog voltage supply, 2.8 volts +- dovdd-supply: Digital I/O voltage supply, 1.8 volts +- dvdd-supply: Digital core voltage supply, 1.2 volts +- reset-gpios: Low active reset gpio + +The device node shall contain one 'port' child node with an +'endpoint' subnode for its digital output video port, +in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. +The endpoint optional property 'data-lanes' shall be "<1 2>". + +Example: +&i2c7 { + ov5695: camera-sensor@36 { + compatible = "ovti,ov5695"; + reg = <0x36>; + pinctrl-names = "default"; + pinctrl-0 = <&clk_24m_cam>; + + clocks = <&cru SCLK_TESTCLKOUT1>; + clock-names = "xvclk"; + + avdd-supply = <&pp2800_cam>; + dovdd-supply = <&pp1800>; + dvdd-supply = <&pp1250_cam>; + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + + port { + wcam_out: endpoint { + remote-endpoint = <&mipi_in_wcam>; + data-lanes = <1 2>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/i2c/ov7670.txt b/Documentation/devicetree/bindings/media/i2c/ov7670.txt index 826b6563b009..2c972a56f3cb 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov7670.txt +++ b/Documentation/devicetree/bindings/media/i2c/ov7670.txt @@ -9,14 +9,21 @@ Required Properties: - clocks: reference to the xclk input clock. - clock-names: should be "xclk". +Required Endpoint Properties: +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + Optional Properties: - reset-gpios: reference to the GPIO connected to the resetb pin, if any. Active is low. - powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any. Active is high. +- ov7670,pclk-hb-disable: a boolean property to suppress pixel clock output + signal during horizontal blankings. -The device node must contain one 'port' child node for its digital output -video port, in accordance with the video interface bindings defined in +The device node must contain one 'port' child node with one 'endpoint' child +sub-node for its digital output video port, in accordance with the video +interface bindings defined in: Documentation/devicetree/bindings/media/video-interfaces.txt. Example: @@ -34,8 +41,13 @@ Example: assigned-clocks = <&pck0>; assigned-clock-rates = <25000000>; + ov7670,pclk-hb-disable; + port { ov7670_0: endpoint { + hsync-active = <0>; + vsync-active = <0>; + remote-endpoint = <&isi_0>; }; }; diff --git a/Documentation/devicetree/bindings/media/i2c/ov9650.txt b/Documentation/devicetree/bindings/media/i2c/ov9650.txt new file mode 100644 index 000000000000..506dfc52872a --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov9650.txt @@ -0,0 +1,36 @@ +* Omnivision OV9650/OV9652 CMOS sensor + +Required Properties: +- compatible: shall be one of + "ovti,ov9650" + "ovti,ov9652" +- clocks: reference to the xvclk input clock. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the resetb pin, if any. + Active is high. +- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any. + Active is high. + +The device node shall contain one 'port' child node with one child 'endpoint' +subnode for its digital output video port, in accordance with the video +interface bindings defined in Documentation/devicetree/bindings/media/ +video-interfaces.txt. + +Example: + +&i2c0 { + ov9650: camera@30 { + compatible = "ovti,ov9650"; + reg = <0x30>; + reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_HIGH>; + clocks = <&xclk>; + + port { + ov9650_0: endpoint { + remote-endpoint = <&vcap1_in0>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/i2c/tda1997x.txt b/Documentation/devicetree/bindings/media/i2c/tda1997x.txt new file mode 100644 index 000000000000..e76167999d76 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/tda1997x.txt @@ -0,0 +1,178 @@ +Device-Tree bindings for the NXP TDA1997x HDMI receiver + +The TDA19971/73 are HDMI video receivers. + +The TDA19971 Video port output pins can be used as follows: + - RGB 8bit per color (24 bits total): R[11:4] B[11:4] G[11:4] + - YUV444 8bit per color (24 bits total): Y[11:4] Cr[11:4] Cb[11:4] + - YUV422 semi-planar 8bit per component (16 bits total): Y[11:4] CbCr[11:4] + - YUV422 semi-planar 10bit per component (20 bits total): Y[11:2] CbCr[11:2] + - YUV422 semi-planar 12bit per component (24 bits total): - Y[11:0] CbCr[11:0] + - YUV422 BT656 8bit per component (8 bits total): YCbCr[11:4] (2-cycles) + - YUV422 BT656 10bit per component (10 bits total): YCbCr[11:2] (2-cycles) + - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles) + +The TDA19973 Video port output pins can be used as follows: + - RGB 12bit per color (36 bits total): R[11:0] B[11:0] G[11:0] + - YUV444 12bit per color (36 bits total): Y[11:0] Cb[11:0] Cr[11:0] + - YUV422 semi-planar 12bit per component (24 bits total): Y[11:0] CbCr[11:0] + - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles) + +The Video port output pins are mapped via 4-bit 'pin groups' allowing +for a variety of connection possibilities including swapping pin order within +pin groups. The video_portcfg device-tree property consists of register mapping +pairs which map a chip-specific VP output register to a 4-bit pin group. If +the pin group needs to be bit-swapped you can use the *_S pin-group defines. + +Required Properties: + - compatible : + - "nxp,tda19971" for the TDA19971 + - "nxp,tda19973" for the TDA19973 + - reg : I2C slave address + - interrupts : The interrupt number + - DOVDD-supply : Digital I/O supply + - DVDD-supply : Digital Core supply + - AVDD-supply : Analog supply + - nxp,vidout-portcfg : array of pairs mapping VP output pins to pin groups. + +Optional Properties: + - nxp,audout-format : DAI bus format: "i2s" or "spdif". + - nxp,audout-width : width of audio output data bus (1-4). + - nxp,audout-layout : data layout (0=AP0 used, 1=AP0/AP1/AP2/AP3 used). + - nxp,audout-mclk-fs : Multiplication factor between stream rate and codec + mclk. + +The port node shall contain one endpoint child node for its digital +output video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Optional Endpoint Properties: + The following three properties are defined in video-interfaces.txt and + are valid for the output parallel bus endpoint: + - hsync-active: Horizontal synchronization polarity. Defaults to active high. + - vsync-active: Vertical synchronization polarity. Defaults to active high. + - data-active: Data polarity. Defaults to active high. + +Examples: + - VP[15:0] connected to IMX6 CSI_DATA[19:4] for 16bit YUV422 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4] + * and Y[11:4] across 16bits in the same pixclk cycle. + */ + nxp,vidout-portcfg = + /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >, + /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >, + /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */ + < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >, + /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */ + < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >; + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; + - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4] + * and Y[11:4] across 16bits in the same pixclk cycle. + */ + nxp,vidout-portcfg = + /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >, + /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >, + /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */ + < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >, + /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */ + < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >; + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; + - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp BT656 mode outputs YCbCr[11:4] across 8bits over + * 2 pixclk cycles. + */ + nxp,vidout-portcfg = + /* YCbCr[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_R_CR_CBCR_11_8 >, + /* YCbCr[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_R_CR_CBCR_7_4 >, + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt index 19357d0bbe65..1ce7ff9449c5 100644 --- a/Documentation/devicetree/bindings/media/rcar_vin.txt +++ b/Documentation/devicetree/bindings/media/rcar_vin.txt @@ -56,7 +56,7 @@ Board setup example (vin1 composite video input) ------------------------------------------------ &i2c2 { - status = "ok"; + status = "okay"; pinctrl-0 = <&i2c2_pins>; pinctrl-names = "default"; @@ -79,7 +79,7 @@ Board setup example (vin1 composite video input) pinctrl-0 = <&vin1_pins>; pinctrl-names = "default"; - status = "ok"; + status = "okay"; port { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/media/renesas,ceu.txt b/Documentation/devicetree/bindings/media/renesas,ceu.txt new file mode 100644 index 000000000000..3fc66dfb192c --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,ceu.txt @@ -0,0 +1,81 @@ +Renesas Capture Engine Unit (CEU) +---------------------------------------------- + +The Capture Engine Unit is the image capture interface found in the Renesas +SH Mobile and RZ SoCs. + +The interface supports a single parallel input with data bus width of 8 or 16 +bits. + +Required properties: +- compatible: Shall be "renesas,r7s72100-ceu" for CEU units found in RZ/A1H + and RZ/A1M SoCs. +- reg: Registers address base and size. +- interrupts: The interrupt specifier. + +The CEU supports a single parallel input and should contain a single 'port' +subnode with a single 'endpoint'. Connection to input devices are modeled +according to the video interfaces OF bindings specified in: +Documentation/devicetree/bindings/media/video-interfaces.txt + +Optional endpoint properties applicable to parallel input bus described in +the above mentioned "video-interfaces.txt" file are supported. + +- hsync-active: Active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. + If property is not present, default is active high. +- vsync-active: Active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + If property is not present, default is active high. + +Example: + +The example describes the connection between the Capture Engine Unit and an +OV7670 image sensor connected to i2c1 interface. + +ceu: ceu@e8210000 { + reg = <0xe8210000 0x209c>; + compatible = "renesas,r7s72100-ceu"; + interrupts = <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&vio_pins>; + + status = "okay"; + + port { + ceu_in: endpoint { + remote-endpoint = <&ov7670_out>; + + hsync-active = <1>; + vsync-active = <0>; + }; + }; +}; + +i2c1: i2c@fcfee400 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + + status = "okay"; + + clock-frequency = <100000>; + + ov7670: camera@21 { + compatible = "ovti,ov7670"; + reg = <0x21>; + + pinctrl-names = "default"; + pinctrl-0 = <&vio_pins>; + + reset-gpios = <&port3 11 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&port3 12 GPIO_ACTIVE_HIGH>; + + port { + ov7670_out: endpoint { + remote-endpoint = <&ceu_in>; + + hsync-active = <1>; + vsync-active = <0>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index d3404b5d4d17..aa54c8159d9f 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -13,6 +13,7 @@ Required properties: (c) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC (d) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC (e) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC + (f) "samsung,mfc-v10" for MFC v10 present in Exynos7880 SoC - reg : Physical base address of the IP registers and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt new file mode 100644 index 000000000000..fc5aa263abe5 --- /dev/null +++ b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt @@ -0,0 +1,14 @@ +Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter + +Required properties: +- compatible: Should be "sony,cxd2880". +- reg: SPI chip select number for the device. +- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz). + +Example: + +cxd2880@0 { + compatible = "sony,cxd2880"; + reg = <0>; /* CE0 */ + spi-max-frequency = <55000000>; /* 55MHz */ +}; diff --git a/Documentation/devicetree/bindings/media/sunxi-ir.txt b/Documentation/devicetree/bindings/media/sunxi-ir.txt index 91648c569b1e..278098987edb 100644 --- a/Documentation/devicetree/bindings/media/sunxi-ir.txt +++ b/Documentation/devicetree/bindings/media/sunxi-ir.txt @@ -11,6 +11,8 @@ Required properties: Optional properties: - linux,rc-map-name: see rc.txt file in the same directory. - resets : phandle + reset specifier pair +- clock-frequency : IR Receiver clock frequency, in Hertz. Defaults to 8 MHz + if missing. Example: @@ -18,6 +20,7 @@ ir0: ir@1c21800 { compatible = "allwinner,sun4i-a10-ir"; clocks = <&apb0_gates 6>, <&ir0_clk>; clock-names = "apb", "ir"; + clock-frequency = <3000000>; resets = <&apb0_rst 1>; interrupts = <0 5 1>; reg = <0x01C21800 0x40>; diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst index 62b9a1448177..a9f53f069a2d 100644 --- a/Documentation/media/kapi/cec-core.rst +++ b/Documentation/media/kapi/cec-core.rst @@ -110,11 +110,14 @@ your driver: void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); void (*adap_free)(struct cec_adapter *adap); + /* Error injection callbacks */ + ... + /* High-level callbacks */ ... }; -The five low-level ops deal with various aspects of controlling the CEC adapter +The seven low-level ops deal with various aspects of controlling the CEC adapter hardware: @@ -286,6 +289,70 @@ handling the receive interrupt. The framework expects to see the cec_transmit_do call before the cec_received_msg call, otherwise it can get confused if the received message was in reply to the transmitted message. +Optional: Implementing Error Injection Support +---------------------------------------------- + +If the CEC adapter supports Error Injection functionality, then that can +be exposed through the Error Injection callbacks: + +.. code-block:: none + + struct cec_adap_ops { + /* Low-level callbacks */ + ... + + /* Error injection callbacks */ + int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); + bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line); + + /* High-level CEC message callback */ + ... + }; + +If both callbacks are set, then an ``error-inj`` file will appear in debugfs. +The basic syntax is as follows: + +Leading spaces/tabs are ignored. If the next character is a ``#`` or the end of the +line was reached, then the whole line is ignored. Otherwise a command is expected. + +This basic parsing is done in the CEC Framework. It is up to the driver to decide +what commands to implement. The only requirement is that the command ``clear`` without +any arguments must be implemented and that it will remove all current error injection +commands. + +This ensures that you can always do ``echo clear >error-inj`` to clear any error +injections without having to know the details of the driver-specific commands. + +Note that the output of ``error-inj`` shall be valid as input to ``error-inj``. +So this must work: + +.. code-block:: none + + $ cat error-inj >einj.txt + $ cat einj.txt >error-inj + +The first callback is called when this file is read and it should show the +the current error injection state: + +.. c:function:: + int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); + +It is recommended that it starts with a comment block with basic usage +information. It returns 0 for success and an error otherwise. + +The second callback will parse commands written to the ``error-inj`` file: + +.. c:function:: + bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line); + +The ``line`` argument points to the start of the command. Any leading +spaces or tabs have already been skipped. It is a single line only (so there +are no embedded newlines) and it is 0-terminated. The callback is free to +modify the contents of the buffer. It is only called for lines containing a +command, so this callback is never called for empty lines or comment lines. + +Return true if the command was valid or false if there were syntax errors. + Implementing the High-Level CEC Adapter --------------------------------------- @@ -298,6 +365,9 @@ CEC protocol driven. The following high-level callbacks are available: /* Low-level callbacks */ ... + /* Error injection callbacks */ + ... + /* High-level CEC message callback */ int (*received)(struct cec_adapter *adap, struct cec_msg *msg); }; diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions index c6e3a35d2c4e..984b61dc3f2e 100644 --- a/Documentation/media/lirc.h.rst.exceptions +++ b/Documentation/media/lirc.h.rst.exceptions @@ -57,6 +57,7 @@ ignore symbol RC_PROTO_RC6_MCE ignore symbol RC_PROTO_SHARP ignore symbol RC_PROTO_XMP ignore symbol RC_PROTO_CEC +ignore symbol RC_PROTO_IMON # Undocumented macros diff --git a/Documentation/media/uapi/cec/cec-api.rst b/Documentation/media/uapi/cec/cec-api.rst index b68ca9c1d2e0..1e2cf498ba30 100644 --- a/Documentation/media/uapi/cec/cec-api.rst +++ b/Documentation/media/uapi/cec/cec-api.rst @@ -23,6 +23,7 @@ This part describes the CEC: Consumer Electronics Control cec-intro cec-funcs + cec-pin-error-inj cec-header diff --git a/Documentation/media/uapi/cec/cec-pin-error-inj.rst b/Documentation/media/uapi/cec/cec-pin-error-inj.rst new file mode 100644 index 000000000000..464b006dbe0a --- /dev/null +++ b/Documentation/media/uapi/cec/cec-pin-error-inj.rst @@ -0,0 +1,325 @@ +CEC Pin Framework Error Injection +================================= + +The CEC Pin Framework is a core CEC framework for CEC hardware that only +has low-level support for the CEC bus. Most hardware today will have +high-level CEC support where the hardware deals with driving the CEC bus, +but some older devices aren't that fancy. However, this framework also +allows you to connect the CEC pin to a GPIO on e.g. a Raspberry Pi and +you have now made a CEC adapter. + +What makes doing this so interesting is that since we have full control +over the bus it is easy to support error injection. This is ideal to +test how well CEC adapters can handle error conditions. + +Currently only the cec-gpio driver (when the CEC line is directly +connected to a pull-up GPIO line) and the AllWinner A10/A20 drm driver +support this framework. + +If ``CONFIG_CEC_PIN_ERROR_INJ`` is enabled, then error injection is available +through debugfs. Specifically, in ``/sys/kernel/debug/cec/cecX/`` there is +now an ``error-inj`` file. + +.. note:: + + The error injection commands are not a stable ABI and may change in the + future. + +With ``cat error-inj`` you can see both the possible commands and the current +error injection status:: + + $ cat /sys/kernel/debug/cec/cec0/error-inj + # Clear error injections: + # clear clear all rx and tx error injections + # rx-clear clear all rx error injections + # tx-clear clear all tx error injections + # <op> clear clear all rx and tx error injections for <op> + # <op> rx-clear clear all rx error injections for <op> + # <op> tx-clear clear all tx error injections for <op> + # + # RX error injection: + # <op>[,<mode>] rx-nack NACK the message instead of sending an ACK + # <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position + # <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message + # <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message + # <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost + # + # TX error injection settings: + # tx-ignore-nack-until-eom ignore early NACKs until EOM + # tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse + # tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse + # tx-custom-pulse transmit the custom pulse once the bus is idle + # + # TX error injection: + # <op>[,<mode>] tx-no-eom don't set the EOM bit + # <op>[,<mode>] tx-early-eom set the EOM bit one byte too soon + # <op>[,<mode>] tx-add-bytes <num> append <num> (1-255) spurious bytes to the message + # <op>[,<mode>] tx-remove-byte drop the last byte from the message + # <op>[,<mode>] tx-short-bit <bit> make this bit shorter than allowed + # <op>[,<mode>] tx-long-bit <bit> make this bit longer than allowed + # <op>[,<mode>] tx-custom-bit <bit> send the custom pulse instead of this bit + # <op>[,<mode>] tx-short-start send a start pulse that's too short + # <op>[,<mode>] tx-long-start send a start pulse that's too long + # <op>[,<mode>] tx-custom-start send the custom pulse instead of the start pulse + # <op>[,<mode>] tx-last-bit <bit> stop sending after this bit + # <op>[,<mode>] tx-low-drive <bit> force a low-drive condition at this bit position + # + # <op> CEC message opcode (0-255) or 'any' + # <mode> 'once' (default), 'always', 'toggle' or 'off' + # <bit> CEC message bit (0-159) + # 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK + # <poll> CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f) + # <usecs> microseconds (0-10000000, default 1000) + + clear + +You can write error injection commands to ``error-inj`` using +``echo 'cmd' >error-inj`` or ``cat cmd.txt >error-inj``. The ``cat error-inj`` +output contains the current error commands. You can save the output to a file +and use it as an input to ``error-inj`` later. + +Basic Syntax +------------ + +Leading spaces/tabs are ignored. If the next character is a ``#`` or the end +of the line was reached, then the whole line is ignored. Otherwise a command +is expected. + +The error injection commands fall in two main groups: those relating to +receiving CEC messages and those relating to transmitting CEC messages. In +addition, there are commands to clear existing error injection commands and +to create custom pulses on the CEC bus. + +Most error injection commands can be executed for specific CEC opcodes or for +all opcodes (``any``). Each command also has a 'mode' which can be ``off`` +(can be used to turn off an existing error injection command), ``once`` +(the default) which will trigger the error injection only once for the next +received or transmitted message, ``always`` to always trigger the error +injection and ``toggle`` to toggle the error injection on or off for every +transmit or receive. + +So '``any rx-nack``' will NACK the next received CEC message, +'``any,always rx-nack``' will NACK all received CEC messages and +'``0x82,toggle rx-nack``' will only NACK if an Active Source message was +received and do that only for every other received message. + +After an error was injected with mode ``once`` the error injection command +is cleared automatically, so ``once`` is a one-time deal. + +All combinations of ``<op>`` and error injection commands can co-exist. So +this is fine:: + + 0x9e tx-add-bytes 1 + 0x9e tx-early-eom + 0x9f tx-add-bytes 2 + any rx-nack + +All four error injection commands will be active simultaneously. + +However, if the same ``<op>`` and command combination is specified, +but with different arguments:: + + 0x9e tx-add-bytes 1 + 0x9e tx-add-bytes 2 + +Then the second will overwrite the first. + +Clear Error Injections +---------------------- + +``clear`` + Clear all error injections. + +``rx-clear`` + Clear all receive error injections + +``tx-clear`` + Clear all transmit error injections + +``<op> clear`` + Clear all error injections for the given opcode. + +``<op> rx-clear`` + Clear all receive error injections for the given opcode. + +``<op> tx-clear`` + Clear all transmit error injections for the given opcode. + +Receive Messages +---------------- + +``<op>[,<mode>] rx-nack`` + NACK broadcast messages and messages directed to this CEC adapter. + Every byte of the message will be NACKed in case the transmitter + keeps transmitting after the first byte was NACKed. + +``<op>[,<mode>] rx-low-drive <bit>`` + Force a Low Drive condition at this bit position. If <op> specifies + a specific CEC opcode then the bit position must be at least 18, + otherwise the opcode hasn't been received yet. This tests if the + transmitter can handle the Low Drive condition correctly and reports + the error correctly. Note that a Low Drive in the first 4 bits can also + be interpreted as an Arbitration Lost condition by the transmitter. + This is implementation dependent. + +``<op>[,<mode>] rx-add-byte`` + Add a spurious 0x55 byte to the received CEC message, provided + the message was 15 bytes long or less. This is useful to test + the high-level protocol since spurious bytes should be ignored. + +``<op>[,<mode>] rx-remove-byte`` + Remove the last byte from the received CEC message, provided it + was at least 2 bytes long. This is useful to test the high-level + protocol since messages that are too short should be ignored. + +``<op>[,<mode>] rx-arb-lost <poll>`` + Generate a POLL message to trigger an Arbitration Lost condition. + This command is only allowed for ``<op>`` values of ``next`` or ``all``. + As soon as a start bit has been received the CEC adapter will switch + to transmit mode and it will transmit a POLL message. By default this is + 0x0f, but it can also be specified explicitly via the ``<poll>`` argument. + + This command can be used to test the Arbitration Lost condition in + the remote CEC transmitter. Arbitration happens when two CEC adapters + start sending a message at the same time. In that case the initiator + with the most leading zeroes wins and the other transmitter has to + stop transmitting ('Arbitration Lost'). This is very hard to test, + except by using this error injection command. + + This does not work if the remote CEC transmitter has logical address + 0 ('TV') since that will always win. + +Transmit Messages +----------------- + +``tx-ignore-nack-until-eom`` + This setting changes the behavior of transmitting CEC messages. Normally + as soon as the receiver NACKs a byte the transmit will stop, but the + specification also allows that the full message is transmitted and only + at the end will the transmitter look at the ACK bit. This is not + recommended behavior since there is no point in keeping the CEC bus busy + for longer than is strictly needed. Especially given how slow the bus is. + + This setting can be used to test how well a receiver deals with + transmitters that ignore NACKs until the very end of the message. + +``<op>[,<mode>] tx-no-eom`` + Don't set the EOM bit. Normally the last byte of the message has the EOM + (End-Of-Message) bit set. With this command the transmit will just stop + without ever sending an EOM. This can be used to test how a receiver + handles this case. Normally receivers have a time-out after which + they will go back to the Idle state. + +``<op>[,<mode>] tx-early-eom`` + Set the EOM bit one byte too soon. This obviously only works for messages + of two bytes or more. The EOM bit will be set for the second-to-last byte + and not for the final byte. The receiver should ignore the last byte in + this case. Since the resulting message is likely to be too short for this + same reason the whole message is typically ignored. The receiver should be + in Idle state after the last byte was transmitted. + +``<op>[,<mode>] tx-add-bytes <num>`` + Append ``<num>`` (1-255) spurious bytes to the message. The extra bytes + have the value of the byte position in the message. So if you transmit a + two byte message (e.g. a Get CEC Version message) and add 2 bytes, then + the full message received by the remote CEC adapter is + ``0x40 0x9f 0x02 0x03``. + + This command can be used to test buffer overflows in the receiver. E.g. + what does it do when it receives more than the maximum message size of 16 + bytes. + +``<op>[,<mode>] tx-remove-byte`` + Drop the last byte from the message, provided the message is at least + two bytes long. The receiver should ignore messages that are too short. + +``<op>[,<mode>] tx-short-bit <bit>`` + Make this bit period shorter than allowed. The bit position cannot be + an Ack bit. If <op> specifies a specific CEC opcode then the bit position + must be at least 18, otherwise the opcode hasn't been received yet. + Normally the period of a data bit is between 2.05 and 2.75 milliseconds. + With this command the period of this bit is 1.8 milliseconds, this is + done by reducing the time the CEC bus is high. This bit period is less + than is allowed and the receiver should respond with a Low Drive + condition. + + This command is ignored for 0 bits in bit positions 0 to 3. This is + because the receiver also looks for an Arbitration Lost condition in + those first four bits and it is undefined what will happen if it + sees a too-short 0 bit. + +``<op>[,<mode>] tx-long-bit <bit>`` + Make this bit period longer than is valid. The bit position cannot be + an Ack bit. If <op> specifies a specific CEC opcode then the bit position + must be at least 18, otherwise the opcode hasn't been received yet. + Normally the period of a data bit is between 2.05 and 2.75 milliseconds. + With this command the period of this bit is 2.9 milliseconds, this is + done by increasing the time the CEC bus is high. + + Even though this bit period is longer than is valid it is undefined what + a receiver will do. It might just accept it, or it might time out and + return to Idle state. Unfortunately the CEC specification is silent about + this. + + This command is ignored for 0 bits in bit positions 0 to 3. This is + because the receiver also looks for an Arbitration Lost condition in + those first four bits and it is undefined what will happen if it + sees a too-long 0 bit. + +``<op>[,<mode>] tx-short-start`` + Make this start bit period shorter than allowed. Normally the period of + a start bit is between 4.3 and 4.7 milliseconds. With this command the + period of the start bit is 4.1 milliseconds, this is done by reducing + the time the CEC bus is high. This start bit period is less than is + allowed and the receiver should return to Idle state when this is detected. + +``<op>[,<mode>] tx-long-start`` + Make this start bit period longer than is valid. Normally the period of + a start bit is between 4.3 and 4.7 milliseconds. With this command the + period of the start bit is 5 milliseconds, this is done by increasing + the time the CEC bus is high. This start bit period is more than is + valid and the receiver should return to Idle state when this is detected. + + Even though this start bit period is longer than is valid it is undefined + what a receiver will do. It might just accept it, or it might time out and + return to Idle state. Unfortunately the CEC specification is silent about + this. + +``<op>[,<mode>] tx-last-bit <bit>`` + Just stop transmitting after this bit. If <op> specifies a specific CEC + opcode then the bit position must be at least 18, otherwise the opcode + hasn't been received yet. This command can be used to test how the receiver + reacts when a message just suddenly stops. It should time out and go back + to Idle state. + +``<op>[,<mode>] tx-low-drive <bit>`` + Force a Low Drive condition at this bit position. If <op> specifies a + specific CEC opcode then the bit position must be at least 18, otherwise + the opcode hasn't been received yet. This can be used to test how the + receiver handles Low Drive conditions. Note that if this happens at bit + positions 0-3 the receiver can interpret this as an Arbitration Lost + condition. This is implementation dependent. + +Custom Pulses +------------- + +``tx-custom-low-usecs <usecs>`` + This defines the duration in microseconds that the custom pulse pulls + the CEC line low. The default is 1000 microseconds. + +``tx-custom-high-usecs <usecs>`` + This defines the duration in microseconds that the custom pulse keeps the + CEC line high (unless another CEC adapter pulls it low in that time). + The default is 1000 microseconds. The total period of the custom pulse is + ``tx-custom-low-usecs + tx-custom-high-usecs``. + +``<op>[,<mode>] tx-custom-bit <bit>`` + Send the custom bit instead of a regular data bit. The bit position cannot + be an Ack bit. If <op> specifies a specific CEC opcode then the bit + position must be at least 18, otherwise the opcode hasn't been received yet. + +``<op>[,<mode>] tx-custom-start`` + Send the custom bit instead of a regular start bit. + +``tx-custom-pulse`` + Transmit a single custom pulse as soon as the CEC bus is idle. diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst index b59ce149efb5..45e76e5bc1ea 100644 --- a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst +++ b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst @@ -144,10 +144,21 @@ id's until they get an error. - .. row 9 - - union + - __u32 + + - ``reserved[4]`` + + - + - + - Reserved for future extensions. Drivers and applications must set + the array to zero. - .. row 10 + - union + + - .. row 11 + - - struct @@ -156,7 +167,7 @@ id's until they get an error. - - Valid for (sub-)devices that create a single device node. - - .. row 11 + - .. row 12 - - @@ -166,7 +177,7 @@ id's until they get an error. - Device node major number. - - .. row 12 + - .. row 13 - - @@ -176,7 +187,7 @@ id's until they get an error. - Device node minor number. - - .. row 13 + - .. row 14 - - __u8 diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst index d05be16ffaf6..256168b3c3be 100644 --- a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst +++ b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst @@ -125,6 +125,15 @@ returned during the enumeration process. - Pad flags, see :ref:`media-pad-flag` for more details. + - .. row 4 + + - __u32 + + - ``reserved[2]`` + + - Reserved for future extensions. Drivers and applications must set + the array to zero. + .. c:type:: media_link_desc @@ -161,6 +170,15 @@ returned during the enumeration process. - Link flags, see :ref:`media-link-flag` for more details. + - .. row 4 + + - __u32 + + - ``reserved[4]`` + + - Reserved for future extensions. Drivers and applications must set + the array to zero. + Return Value ============ diff --git a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst index 997e6b17440d..c8f9ea37db2d 100644 --- a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst +++ b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst @@ -68,7 +68,7 @@ desired arrays with the media graph elements. - .. row 2 - - __u64 + - __u32 - ``num_entities`` @@ -76,6 +76,14 @@ desired arrays with the media graph elements. - .. row 3 + - __u32 + + - ``reserved1`` + + - Applications and drivers shall set this to 0. + + - .. row 4 + - __u64 - ``ptr_entities`` @@ -85,15 +93,23 @@ desired arrays with the media graph elements. the ioctl won't store the entities. It will just update ``num_entities`` - - .. row 4 + - .. row 5 - - __u64 + - __u32 - ``num_interfaces`` - Number of interfaces in the graph - - .. row 5 + - .. row 6 + + - __u32 + + - ``reserved2`` + + - Applications and drivers shall set this to 0. + + - .. row 7 - __u64 @@ -104,15 +120,23 @@ desired arrays with the media graph elements. the ioctl won't store the interfaces. It will just update ``num_interfaces`` - - .. row 6 + - .. row 8 - - __u64 + - __u32 - ``num_pads`` - Total number of pads in the graph - - .. row 7 + - .. row 9 + + - __u32 + + - ``reserved3`` + + - Applications and drivers shall set this to 0. + + - .. row 10 - __u64 @@ -122,15 +146,23 @@ desired arrays with the media graph elements. converted to a 64-bits integer. It can be zero. if zero, the ioctl won't store the pads. It will just update ``num_pads`` - - .. row 8 + - .. row 11 - - __u64 + - __u32 - ``num_links`` - Total number of data and interface links in the graph - - .. row 9 + - .. row 12 + + - __u32 + + - ``reserved4`` + + - Applications and drivers shall set this to 0. + + - .. row 13 - __u64 @@ -334,7 +366,7 @@ desired arrays with the media graph elements. - On pad to pad links: unique ID for the source pad. - On interface to entity links: unique ID for the entity. + On interface to entity links: unique ID for the interface. - .. row 3 diff --git a/Documentation/media/uapi/mediactl/media-types.rst b/Documentation/media/uapi/mediactl/media-types.rst index 8d64b0c06ebc..f92f10b7ffbd 100644 --- a/Documentation/media/uapi/mediactl/media-types.rst +++ b/Documentation/media/uapi/mediactl/media-types.rst @@ -26,7 +26,7 @@ Types and flags used to represent the media graph elements ``MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN`` - Unknown entity. That generally indicates that a driver didn't - initialize properly the entity, with is a Kernel bug + initialize properly the entity, which is a Kernel bug - .. row 2 @@ -293,7 +293,7 @@ Types and flags used to represent the media graph elements - ``MEDIA_ENT_F_PROC_VIDEO_STATISTICS`` - - Video statistics computation (histogram, 3A, ...). An entity + - Video statistics computation (histogram, 3A, etc.). An entity capable of statistics computation must have one sink pad and one source pad. It computes statistics over the frames received on its sink pad and outputs the statistics data on @@ -318,8 +318,19 @@ Types and flags used to represent the media graph elements - Video interface bridge. A video interface bridge entity must have at least one sink pad and at least one source pad. It receives video frames on its sink pad from an input video bus of one type (HDMI, eDP, - MIPI CSI-2, ...), and outputs them on its source pad to an output - video bus of another type (eDP, MIPI CSI-2, parallel, ...). + MIPI CSI-2, etc.), and outputs them on its source pad to an output + video bus of another type (eDP, MIPI CSI-2, parallel, etc.). + + - .. row 31 + + .. _MEDIA-ENT-F-DTV-DECODER: + + - ``MEDIA_ENT_F_DTV_DECODER`` + + - Digital video decoder. The basic function of the video decoder is + to accept digital video from a wide variety of sources + and output it in some digital video standard, with appropriate + timing signals. .. tabularcolumns:: |p{5.5cm}|p{12.0cm}| @@ -337,7 +348,7 @@ Types and flags used to represent the media graph elements - ``MEDIA_ENT_FL_DEFAULT`` - Default entity for its type. Used to discover the default audio, - VBI and video devices, the default camera sensor, ... + VBI and video devices, the default camera sensor, etc. - .. row 2 @@ -345,7 +356,7 @@ Types and flags used to represent the media graph elements - ``MEDIA_ENT_FL_CONNECTOR`` - - The entity represents a data conector + - The entity represents a connector. .. tabularcolumns:: |p{6.5cm}|p{6.0cm}|p{5.0cm}| diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst index 3a74fec66d69..698e4f80270e 100644 --- a/Documentation/media/uapi/rc/lirc-dev-intro.rst +++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst @@ -18,7 +18,6 @@ Example dmesg output upon a driver registering w/LIRC: .. code-block:: none $ dmesg |grep lirc_dev - lirc_dev: IR Remote Control driver registered, major 248 rc rc0: lirc_dev: driver mceusb registered at minor = 0 What you should see for a chardev: diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst index ae6ee73f151c..e2c85ddc990b 100644 --- a/Documentation/media/uapi/v4l/buffer.rst +++ b/Documentation/media/uapi/v4l/buffer.rst @@ -13,7 +13,7 @@ Only pointers to buffers (planes) are exchanged, the data itself is not copied. These pointers, together with meta-information like timestamps or field parity, are stored in a struct :c:type:`v4l2_buffer`, argument to the :ref:`VIDIOC_QUERYBUF`, -:ref:`VIDIOC_QBUF` and +:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. In the multi-planar API, some plane-specific members of struct :c:type:`v4l2_buffer`, such as pointers and sizes for each plane, are stored in struct diff --git a/Documentation/media/uapi/v4l/extended-controls.rst b/Documentation/media/uapi/v4l/extended-controls.rst index dfe49ae57e78..d5f3eb6e674a 100644 --- a/Documentation/media/uapi/v4l/extended-controls.rst +++ b/Documentation/media/uapi/v4l/extended-controls.rst @@ -1960,6 +1960,416 @@ enum v4l2_vp8_golden_frame_sel - 1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3. +High Efficiency Video Coding (HEVC/H.265) Control Reference +----------------------------------------------------------- + +The HEVC/H.265 controls include controls for encoding parameters of HEVC/H.265 +video codec. + + +.. _hevc-control-id: + +HEVC/H.265 Control IDs +^^^^^^^^^^^^^^^^^^^^^^ + +``V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (integer)`` + Minimum quantization parameter for HEVC. + Valid range: from 0 to 51. + +``V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (integer)`` + Maximum quantization parameter for HEVC. + Valid range: from 0 to 51. + +``V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (integer)`` + Quantization parameter for an I frame for HEVC. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (integer)`` + Quantization parameter for a P frame for HEVC. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (integer)`` + Quantization parameter for a B frame for HEVC. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (boolean)`` + HIERARCHICAL_QP allows the host to specify the quantization parameter + values for each temporal layer through HIERARCHICAL_QP_LAYER. This is + valid only if HIERARCHICAL_CODING_LAYER is greater than 1. Setting the + control value to 1 enables setting of the QP values for the layers. + +.. _v4l2-hevc-hier-coding-type: + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE`` + (enum) + +enum v4l2_mpeg_video_hevc_hier_coding_type - + Selects the hierarchical coding type for encoding. Possible values are: + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{9.0cm}|p{8.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B`` + - Use the B frame for hierarchical coding. + * - ``V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P`` + - Use the P frame for hierarchical coding. + +.. raw:: latex + + \normalsize + + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (integer)`` + Selects the hierarchical coding layer. In normal encoding + (non-hierarchial coding), it should be zero. Possible values are [0, 6]. + 0 indicates HIERARCHICAL CODING LAYER 0, 1 indicates HIERARCHICAL CODING + LAYER 1 and so on. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 0. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 1. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 2. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 3. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 4. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 5. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (integer)`` + Indicates quantization parameter for hierarchical coding layer 6. + Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP]. + +.. _v4l2-hevc-profile: + +``V4L2_CID_MPEG_VIDEO_HEVC_PROFILE`` + (enum) + +enum v4l2_mpeg_video_hevc_profile - + Select the desired profile for HEVC encoder. + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{9.0cm}|p{8.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN`` + - Main profile. + * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE`` + - Main still picture profile. + * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10`` + - Main 10 profile. + +.. raw:: latex + + \normalsize + + +.. _v4l2-hevc-level: + +``V4L2_CID_MPEG_VIDEO_HEVC_LEVEL`` + (enum) + +enum v4l2_mpeg_video_hevc_level - + Selects the desired level for HEVC encoder. + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{9.0cm}|p{8.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_1`` + - Level 1.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_2`` + - Level 2.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1`` + - Level 2.1 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_3`` + - Level 3.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1`` + - Level 3.1 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_4`` + - Level 4.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1`` + - Level 4.1 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5`` + - Level 5.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1`` + - Level 5.1 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2`` + - Level 5.2 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6`` + - Level 6.0 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1`` + - Level 6.1 + * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2`` + - Level 6.2 + +.. raw:: latex + + \normalsize + + +``V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (integer)`` + Indicates the number of evenly spaced subintervals, called ticks, within + one second. This is a 16 bit unsigned integer and has a maximum value up to + 0xffff and a minimum value of 1. + +.. _v4l2-hevc-tier: + +``V4L2_CID_MPEG_VIDEO_HEVC_TIER`` + (enum) + +enum v4l2_mpeg_video_hevc_tier - + TIER_FLAG specifies tiers information of the HEVC encoded picture. Tier + were made to deal with applications that differ in terms of maximum bit + rate. Setting the flag to 0 selects HEVC tier as Main tier and setting + this flag to 1 indicates High tier. High tier is for applications requiring + high bit rates. + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{9.0cm}|p{8.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_TIER_MAIN`` + - Main tier. + * - ``V4L2_MPEG_VIDEO_HEVC_TIER_HIGH`` + - High tier. + +.. raw:: latex + + \normalsize + + +``V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (integer)`` + Selects HEVC maximum coding unit depth. + +.. _v4l2-hevc-loop-filter-mode: + +``V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE`` + (enum) + +enum v4l2_mpeg_video_hevc_loop_filter_mode - + Loop filter mode for HEVC encoder. Possible values are: + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{10.7cm}|p{6.3cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED`` + - Loop filter is disabled. + * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED`` + - Loop filter is enabled. + * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY`` + - Loop filter is disabled at the slice boundary. + +.. raw:: latex + + \normalsize + + +``V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (integer)`` + Selects HEVC loop filter beta offset. The valid range is [-6, +6]. + +``V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (integer)`` + Selects HEVC loop filter tc offset. The valid range is [-6, +6]. + +.. _v4l2-hevc-refresh-type: + +``V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE`` + (enum) + +enum v4l2_mpeg_video_hevc_hier_refresh_type - + Selects refresh type for HEVC encoder. + Host has to specify the period into + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD. + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{8.0cm}|p{9.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE`` + - Use the B frame for hierarchical coding. + * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA`` + - Use CRA (Clean Random Access Unit) picture encoding. + * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR`` + - Use IDR (Instantaneous Decoding Refresh) picture encoding. + +.. raw:: latex + + \normalsize + + +``V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (integer)`` + Selects the refresh period for HEVC encoder. + This specifies the number of I pictures between two CRA/IDR pictures. + This is valid only if REFRESH_TYPE is not 0. + +``V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (boolean)`` + Indicates HEVC lossless encoding. Setting it to 0 disables lossless + encoding. Setting it to 1 enables lossless encoding. + +``V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (boolean)`` + Indicates constant intra prediction for HEVC encoder. Specifies the + constrained intra prediction in which intra largest coding unit (LCU) + prediction is performed by using residual data and decoded samples of + neighboring intra LCU only. Setting the value to 1 enables constant intra + prediction and setting the value to 0 disables constant intra prediction. + +``V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (boolean)`` + Indicates wavefront parallel processing for HEVC encoder. Setting it to 0 + disables the feature and setting it to 1 enables the wavefront parallel + processing. + +``V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (boolean)`` + Setting the value to 1 enables combination of P and B frame for HEVC + encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (boolean)`` + Indicates temporal identifier for HEVC encoder which is enabled by + setting the value to 1. + +``V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (boolean)`` + Indicates bi-linear interpolation is conditionally used in the intra + prediction filtering process in the CVS when set to 1. Indicates bi-linear + interpolation is not used in the CVS when set to 0. + +``V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (integer)`` + Indicates maximum number of merge candidate motion vectors. + Values are from 0 to 4. + +``V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (boolean)`` + Indicates temporal motion vector prediction for HEVC encoder. Setting it to + 1 enables the prediction. Setting it to 0 disables the prediction. + +``V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (boolean)`` + Specifies if HEVC generates a stream with a size of the length field + instead of start code pattern. The size of the length field is configurable + through the V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD control. Setting + the value to 0 disables encoding without startcode pattern. Setting the + value to 1 will enables encoding without startcode pattern. + +.. _v4l2-hevc-size-of-length-field: + +``V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD`` +(enum) + +enum v4l2_mpeg_video_hevc_size_of_length_field - + Indicates the size of length field. + This is valid when encoding WITHOUT_STARTCODE_ENABLE is enabled. + +.. raw:: latex + + \footnotesize + +.. tabularcolumns:: |p{6.0cm}|p{11.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_0`` + - Generate start code pattern (Normal). + * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_1`` + - Generate size of length field instead of start code pattern and length is 1. + * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_2`` + - Generate size of length field instead of start code pattern and length is 2. + * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_4`` + - Generate size of length field instead of start code pattern and length is 4. + +.. raw:: latex + + \normalsize + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (integer)`` + Indicates bit rate for hierarchical coding layer 0 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (integer)`` + Indicates bit rate for hierarchical coding layer 1 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (integer)`` + Indicates bit rate for hierarchical coding layer 2 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (integer)`` + Indicates bit rate for hierarchical coding layer 3 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (integer)`` + Indicates bit rate for hierarchical coding layer 4 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (integer)`` + Indicates bit rate for hierarchical coding layer 5 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (integer)`` + Indicates bit rate for hierarchical coding layer 6 for HEVC encoder. + +``V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (integer)`` + Selects number of P reference pictures required for HEVC encoder. + P-Frame can use 1 or 2 frames for reference. + +``V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (integer)`` + Indicates whether to generate SPS and PPS at every IDR. Setting it to 0 + disables generating SPS and PPS at every IDR. Setting it to one enables + generating SPS and PPS at every IDR. + + .. _camera-controls: Camera Control Reference diff --git a/Documentation/media/uapi/v4l/func-poll.rst b/Documentation/media/uapi/v4l/func-poll.rst index d0432dc09b05..360bc6523ae2 100644 --- a/Documentation/media/uapi/v4l/func-poll.rst +++ b/Documentation/media/uapi/v4l/func-poll.rst @@ -39,7 +39,7 @@ When streaming I/O has been negotiated this function waits until a buffer has been filled by the capture device and can be dequeued with the :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. For output devices this function waits until the device is ready to accept a new buffer to be -queued up with the :ref:`VIDIOC_QBUF` ioctl for +queued up with the :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl for display. When buffers are already in the outgoing queue of the driver (capture) or the incoming queue isn't full (display) the function returns immediately. @@ -52,11 +52,11 @@ flags in the ``revents`` field, output devices the ``POLLOUT`` and ``POLLWRNORM`` flags. When the function timed out it returns a value of zero, on failure it returns -1 and the ``errno`` variable is set appropriately. When the application did not call -:ref:`VIDIOC_STREAMON` the :ref:`poll() <func-poll>` +:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` the :ref:`poll() <func-poll>` function succeeds, but sets the ``POLLERR`` flag in the ``revents`` field. When the application has called -:ref:`VIDIOC_STREAMON` for a capture device but -hasn't yet called :ref:`VIDIOC_QBUF`, the +:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` for a capture device but +hasn't yet called :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, the :ref:`poll() <func-poll>` function succeeds and sets the ``POLLERR`` flag in the ``revents`` field. For output devices this same situation will cause :ref:`poll() <func-poll>` to succeed as well, but it sets the ``POLLOUT`` and diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst index 728d7ede10fa..abec03937bb3 100644 --- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst +++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -90,3 +90,8 @@ Compressed Formats - ``V4L2_PIX_FMT_VP9`` - 'VP90' - VP9 video elementary stream. + * .. _V4L2-PIX-FMT-HEVC: + + - ``V4L2_PIX_FMT_HEVC`` + - 'HEVC' + - HEVC/H.265 video elementary stream. diff --git a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst index 2ee164c25637..6622938c1b41 100644 --- a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst +++ b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst @@ -40,7 +40,7 @@ Single-planar format structure RGB formats in :ref:`rgb-formats`, YUV formats in :ref:`yuv-formats`, and reserved codes in :ref:`reserved-formats` - * - enum :c:type::`v4l2_field` + * - enum :c:type:`v4l2_field` - ``field`` - Video images are typically interlaced. Applications can request to capture or output only the top or bottom field, or both fields diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst index b1eea44550e1..9fcabe7f9367 100644 --- a/Documentation/media/uapi/v4l/subdev-formats.rst +++ b/Documentation/media/uapi/v4l/subdev-formats.rst @@ -16,10 +16,14 @@ Media Bus Formats * - __u32 - ``width`` - - Image width, in pixels. + - Image width in pixels. * - __u32 - ``height`` - - Image height, in pixels. + - Image height in pixels. If ``field`` is one of ``V4L2_FIELD_TOP``, + ``V4L2_FIELD_BOTTOM`` or ``V4L2_FIELD_ALTERNATE`` then height + refers to the number of lines in the field, otherwise it refers to + the number of lines in the frame (which is twice the field height + for interlaced formats). * - __u32 - ``code`` - Format code, from enum diff --git a/Documentation/media/uapi/v4l/vidioc-g-parm.rst b/Documentation/media/uapi/v4l/vidioc-g-parm.rst index 616a5ea3f8fa..e831fa5512f0 100644 --- a/Documentation/media/uapi/v4l/vidioc-g-parm.rst +++ b/Documentation/media/uapi/v4l/vidioc-g-parm.rst @@ -66,7 +66,7 @@ union holding separate parameters for input and output devices. - - The buffer (stream) type, same as struct :c:type:`v4l2_format` ``type``, set by the - application. See :c:type:`v4l2_buf_type` + application. See :c:type:`v4l2_buf_type`. * - union - ``parm`` - @@ -75,12 +75,13 @@ union holding separate parameters for input and output devices. - struct :c:type:`v4l2_captureparm` - ``capture`` - Parameters for capture devices, used when ``type`` is - ``V4L2_BUF_TYPE_VIDEO_CAPTURE``. + ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` or + ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``. * - - struct :c:type:`v4l2_outputparm` - ``output`` - Parameters for output devices, used when ``type`` is - ``V4L2_BUF_TYPE_VIDEO_OUTPUT``. + ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` or ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``. * - - __u8 - ``raw_data``\ [200] diff --git a/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst b/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst index 70687a86ae38..49f9f4c181de 100644 --- a/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst +++ b/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst @@ -34,7 +34,7 @@ Description Applications can optionally call the :ref:`VIDIOC_PREPARE_BUF` ioctl to pass ownership of the buffer to the driver before actually enqueuing it, -using the :ref:`VIDIOC_QBUF` ioctl, and to prepare it for future I/O. Such +using the :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl, and to prepare it for future I/O. Such preparations may include cache invalidation or cleaning. Performing them in advance saves time during the actual I/O. In case such cache operations are not required, the application can use one of diff --git a/Documentation/media/v4l-drivers/imx.rst b/Documentation/media/v4l-drivers/imx.rst index 3c4f58bda178..65d3d15eb159 100644 --- a/Documentation/media/v4l-drivers/imx.rst +++ b/Documentation/media/v4l-drivers/imx.rst @@ -109,7 +109,7 @@ imx6-mipi-csi2 This is the MIPI CSI-2 receiver entity. It has one sink pad to receive the MIPI CSI-2 stream (usually from a MIPI CSI-2 camera sensor). It has four source pads, corresponding to the four MIPI CSI-2 demuxed virtual -channel outputs. Multpiple source pads can be enabled to independently +channel outputs. Multiple source pads can be enabled to independently stream from multiple virtual channels. This entity actually consists of two sub-blocks. One is the MIPI CSI-2 @@ -213,9 +213,11 @@ To give an example of crop and /2 downscale, this will crop a 1280x960 input frame to 640x480, and then /2 downscale in both dimensions to 320x240 (assumes ipu1_csi0 is linked to ipu1_csi0_mux): -media-ctl -V "'ipu1_csi0_mux':2[fmt:UYVY2X8/1280x960]" -media-ctl -V "'ipu1_csi0':0[crop:(0,0)/640x480]" -media-ctl -V "'ipu1_csi0':0[compose:(0,0)/320x240]" +.. code-block:: none + + media-ctl -V "'ipu1_csi0_mux':2[fmt:UYVY2X8/1280x960]" + media-ctl -V "'ipu1_csi0':0[crop:(0,0)/640x480]" + media-ctl -V "'ipu1_csi0':0[compose:(0,0)/320x240]" Frame Skipping in ipuX_csiY --------------------------- @@ -229,8 +231,10 @@ at the source pad. The following example reduces an assumed incoming 60 Hz frame rate by half at the IDMAC output source pad: -media-ctl -V "'ipu1_csi0':0[fmt:UYVY2X8/640x480@1/60]" -media-ctl -V "'ipu1_csi0':2[fmt:UYVY2X8/640x480@1/30]" +.. code-block:: none + + media-ctl -V "'ipu1_csi0':0[fmt:UYVY2X8/640x480@1/60]" + media-ctl -V "'ipu1_csi0':2[fmt:UYVY2X8/640x480@1/30]" Frame Interval Monitor in ipuX_csiY ----------------------------------- @@ -422,8 +426,7 @@ This pipeline uses the preprocess encode entity to route frames directly from the CSI to the IC, to carry out scaling up to 1024x1024 resolution, CSC, flipping, and image rotation: --> ipuX_csiY:1 -> 0:ipuX_ic_prp:1 -> 0:ipuX_ic_prpenc:1 -> - ipuX_ic_prpenc capture +-> ipuX_csiY:1 -> 0:ipuX_ic_prp:1 -> 0:ipuX_ic_prpenc:1 -> ipuX_ic_prpenc capture Motion Compensated De-interlace: -------------------------------- @@ -432,8 +435,7 @@ This pipeline routes frames from the CSI direct pad to the VDIC entity to support motion-compensated de-interlacing (high motion mode only), scaling up to 1024x1024, CSC, flip, and rotation: --> ipuX_csiY:1 -> 0:ipuX_vdic:2 -> 0:ipuX_ic_prp:2 -> - 0:ipuX_ic_prpvf:1 -> ipuX_ic_prpvf capture +-> ipuX_csiY:1 -> 0:ipuX_vdic:2 -> 0:ipuX_ic_prp:2 -> 0:ipuX_ic_prpvf:1 -> ipuX_ic_prpvf capture Usage Notes @@ -458,8 +460,8 @@ This platform requires the OmniVision OV5642 module with a parallel camera interface, and the OV5640 module with a MIPI CSI-2 interface. Both modules are available from Boundary Devices: -https://boundarydevices.com/product/nit6x_5mp -https://boundarydevices.com/product/nit6x_5mp_mipi +- https://boundarydevices.com/product/nit6x_5mp +- https://boundarydevices.com/product/nit6x_5mp_mipi Note that if only one camera module is available, the other sensor node can be disabled in the device tree. diff --git a/MAINTAINERS b/MAINTAINERS index f830fc9abe00..2328eed6aea9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3275,6 +3275,7 @@ F: include/media/cec-notifier.h F: include/uapi/linux/cec.h F: include/uapi/linux/cec-funcs.h F: Documentation/devicetree/bindings/media/cec.txt +F: Documentation/ABI/testing/debugfs-cec-error-inj CEC GPIO DRIVER M: Hans Verkuil <hans.verkuil@cisco.com> @@ -6865,6 +6866,13 @@ M: James Hogan <jhogan@kernel.org> S: Maintained F: drivers/media/rc/img-ir/ +IMON SOUNDGRAPH USB IR RECEIVER +M: Sean Young <sean@mess.org> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/rc/imon_raw.c +F: drivers/media/rc/imon.c + IMS TWINTURBO FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan @@ -8604,6 +8612,14 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/dvb-frontends/ascot2e* +MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS +M: Jasmin Jessich <jasmin@anw.at> +L: linux-media@vger.kernel.org +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/cxd2099* + MEDIA DRIVERS FOR CXD2841ER M: Sergey Kozlov <serjk@netup.ru> M: Abylay Ospan <aospan@netup.ru> @@ -8614,6 +8630,15 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/dvb-frontends/cxd2841er* +MEDIA DRIVERS FOR CXD2880 +M: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/cxd2880/* +F: drivers/media/spi/cxd2880* + MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES M: Daniel Scheller <d.scheller.oss@gmail.com> L: linux-media@vger.kernel.org @@ -8681,6 +8706,16 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/pci/netup_unidvb/* +MEDIA DRIVERS FOR RENESAS - CEU +M: Jacopo Mondi <jacopo@jmondi.org> +L: linux-media@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/renesas,ceu.txt +F: drivers/media/platform/renesas-ceu.c +F: include/media/drv-intf/renesas-ceu.h + MEDIA DRIVERS FOR RENESAS - DRIF M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com> L: linux-media@vger.kernel.org @@ -9365,6 +9400,14 @@ S: Maintained F: drivers/media/i2c/mt9t001.c F: include/media/i2c/mt9t001.h +MT9T112 APTINA CAMERA SENSOR +M: Jacopo Mondi <jacopo@jmondi.org> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Odd Fixes +F: drivers/media/i2c/mt9t112.c +F: include/media/i2c/mt9t112.h + MT9V032 APTINA CAMERA SENSOR M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> L: linux-media@vger.kernel.org @@ -10170,6 +10213,13 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/i2c/ov13858.c +OMNIVISION OV2685 SENSOR DRIVER +M: Shunqian Zheng <zhengsq@rock-chips.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov2685.c + OMNIVISION OV5640 SENSOR DRIVER M: Steve Longerbeam <slongerbeam@gmail.com> L: linux-media@vger.kernel.org @@ -10184,6 +10234,13 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/i2c/ov5647.c +OMNIVISION OV5695 SENSOR DRIVER +M: Shunqian Zheng <zhengsq@rock-chips.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov5695.c + OMNIVISION OV7670 SENSOR DRIVER M: Jonathan Corbet <corbet@lwn.net> L: linux-media@vger.kernel.org @@ -10192,6 +10249,14 @@ S: Maintained F: drivers/media/i2c/ov7670.c F: Documentation/devicetree/bindings/media/i2c/ov7670.txt +OMNIVISION OV772x SENSOR DRIVER +M: Jacopo Mondi <jacopo@jmondi.org> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: drivers/media/i2c/ov772x.c +F: include/media/i2c/ov772x.h + OMNIVISION OV7740 SENSOR DRIVER M: Wenyou Yang <wenyou.yang@microchip.com> L: linux-media@vger.kernel.org @@ -10200,6 +10265,16 @@ S: Maintained F: drivers/media/i2c/ov7740.c F: Documentation/devicetree/bindings/media/i2c/ov7740.txt +OMNIVISION OV9650 SENSOR DRIVER +M: Sakari Ailus <sakari.ailus@linux.intel.com> +R: Akinobu Mita <akinobu.mita@gmail.com> +R: Sylwester Nawrocki <s.nawrocki@samsung.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov9650.c +F: Documentation/devicetree/bindings/media/i2c/ov9650.txt + ONENAND FLASH DRIVER M: Kyungmin Park <kyungmin.park@samsung.com> L: linux-mtd@lists.infradead.org @@ -12780,10 +12855,9 @@ S: Maintained F: drivers/net/ethernet/smsc/smsc9420.* SOC-CAMERA V4L2 SUBSYSTEM -M: Guennadi Liakhovetski <g.liakhovetski@gmx.de> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git -S: Maintained +S: Orphan F: include/media/soc* F: drivers/media/i2c/soc_camera/ F: drivers/media/platform/soc_camera/ @@ -13512,6 +13586,14 @@ T: git git://linuxtv.org/mkrufky/tuners.git S: Maintained F: drivers/media/tuners/tda18271* +TDA1997x MEDIA DRIVER +M: Tim Harvey <tharvey@gateworks.com> +L: linux-media@vger.kernel.org +W: https://linuxtv.org +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/i2c/tda1997x.* + TDA827x MEDIA DRIVER M: Michael Krufky <mkrufky@linuxtv.org> L: linux-media@vger.kernel.org @@ -13593,6 +13675,12 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/rc/ttusbir.c +TECHWELL TW9910 VIDEO DECODER +L: linux-media@vger.kernel.org +S: Orphan +F: drivers/media/i2c/tw9910.c +F: include/media/i2c/tw9910.h + TEE SUBSYSTEM M: Jens Wiklander <jens.wiklander@linaro.org> S: Maintained diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 6f929abe0b50..adc61d14172c 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -7,44 +7,47 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ - -#include <linux/init.h> +#include <asm/clock.h> +#include <asm/heartbeat.h> +#include <asm/suspend.h> +#include <cpu/sh7724.h> +#include <linux/delay.h> #include <linux/device.h> -#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/input/sh_keysc.h> +#include <linux/interrupt.h> +#include <linux/memblock.h> +#include <linux/mfd/tmio.h> #include <linux/mmc/host.h> #include <linux/mmc/sh_mmcif.h> #include <linux/mtd/physmap.h> -#include <linux/mfd/tmio.h> #include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/delay.h> +#include <linux/gpio/machine.h> +#include <linux/platform_data/gpio_backlight.h> +#include <linux/platform_data/tsc2007.h> +#include <linux/platform_device.h> #include <linux/regulator/fixed.h> #include <linux/regulator/machine.h> -#include <linux/usb/r8a66597.h> -#include <linux/usb/renesas_usbhs.h> -#include <linux/i2c.h> -#include <linux/platform_data/tsc2007.h> -#include <linux/spi/spi.h> -#include <linux/spi/sh_msiof.h> -#include <linux/spi/mmc_spi.h> -#include <linux/input.h> -#include <linux/input/sh_keysc.h> -#include <linux/platform_data/gpio_backlight.h> #include <linux/sh_eth.h> #include <linux/sh_intc.h> +#include <linux/spi/mmc_spi.h> +#include <linux/spi/sh_msiof.h> +#include <linux/spi/spi.h> +#include <linux/usb/r8a66597.h> +#include <linux/usb/renesas_usbhs.h> #include <linux/videodev2.h> -#include <video/sh_mobile_lcdc.h> + +#include <media/drv-intf/renesas-ceu.h> +#include <media/i2c/mt9t112.h> +#include <media/i2c/tw9910.h> + #include <sound/sh_fsi.h> #include <sound/simple_card.h> -#include <media/drv-intf/sh_mobile_ceu.h> -#include <media/soc_camera.h> -#include <media/i2c/tw9910.h> -#include <media/i2c/mt9t112.h> -#include <asm/heartbeat.h> -#include <asm/clock.h> -#include <asm/suspend.h> -#include <cpu/sh7724.h> + +#include <video/sh_mobile_lcdc.h> /* * Address Interface BusWidth @@ -81,6 +84,10 @@ * amixer set 'Out Mixer Right DAC Right' on */ +#define CEU_BUFFER_MEMORY_SIZE (4 << 20) +static phys_addr_t ceu0_dma_membase; +static phys_addr_t ceu1_dma_membase; + /* Heartbeat */ static unsigned char led_pos[] = { 0, 1, 2, 3 }; @@ -382,8 +389,24 @@ static struct platform_device gpio_backlight_device = { }; /* CEU0 */ -static struct sh_mobile_ceu_info sh_mobile_ceu0_info = { - .flags = SH_CEU_FLAG_USE_8BIT_BUS, +static struct ceu_platform_data ceu0_pdata = { + .num_subdevs = 2, + .subdevs = { + { /* [0] = mt9t112 */ + .flags = 0, + .bus_width = 8, + .bus_shift = 0, + .i2c_adapter_id = 0, + .i2c_address = 0x3c, + }, + { /* [1] = tw9910 */ + .flags = 0, + .bus_width = 8, + .bus_shift = 0, + .i2c_adapter_id = 0, + .i2c_address = 0x45, + }, + }, }; static struct resource ceu0_resources[] = { @@ -397,24 +420,30 @@ static struct resource ceu0_resources[] = { .start = evt2irq(0x880), .flags = IORESOURCE_IRQ, }, - [2] = { - /* place holder for contiguous memory */ - }, }; static struct platform_device ceu0_device = { - .name = "sh_mobile_ceu", - .id = 0, /* "ceu0" clock */ + .name = "renesas-ceu", + .id = 0, /* ceu.0 */ .num_resources = ARRAY_SIZE(ceu0_resources), .resource = ceu0_resources, .dev = { - .platform_data = &sh_mobile_ceu0_info, + .platform_data = &ceu0_pdata, }, }; /* CEU1 */ -static struct sh_mobile_ceu_info sh_mobile_ceu1_info = { - .flags = SH_CEU_FLAG_USE_8BIT_BUS, +static struct ceu_platform_data ceu1_pdata = { + .num_subdevs = 1, + .subdevs = { + { /* [0] = mt9t112 */ + .flags = 0, + .bus_width = 8, + .bus_shift = 0, + .i2c_adapter_id = 1, + .i2c_address = 0x3c, + }, + }, }; static struct resource ceu1_resources[] = { @@ -428,26 +457,71 @@ static struct resource ceu1_resources[] = { .start = evt2irq(0x9e0), .flags = IORESOURCE_IRQ, }, - [2] = { - /* place holder for contiguous memory */ - }, }; static struct platform_device ceu1_device = { - .name = "sh_mobile_ceu", - .id = 1, /* "ceu1" clock */ + .name = "renesas-ceu", + .id = 1, /* ceu.1 */ .num_resources = ARRAY_SIZE(ceu1_resources), .resource = ceu1_resources, .dev = { - .platform_data = &sh_mobile_ceu1_info, + .platform_data = &ceu1_pdata, + }, +}; + +/* Power up/down GPIOs for camera devices and video decoder */ +static struct gpiod_lookup_table tw9910_gpios = { + .dev_id = "0-0045", + .table = { + GPIO_LOOKUP("sh7724_pfc", GPIO_PTU2, "pdn", GPIO_ACTIVE_HIGH), + }, +}; + +static struct gpiod_lookup_table mt9t112_0_gpios = { + .dev_id = "0-003c", + .table = { + GPIO_LOOKUP("sh7724_pfc", GPIO_PTA3, "standby", + GPIO_ACTIVE_HIGH), + }, +}; + +static struct gpiod_lookup_table mt9t112_1_gpios = { + .dev_id = "1-003c", + .table = { + GPIO_LOOKUP("sh7724_pfc", GPIO_PTA4, "standby", + GPIO_ACTIVE_HIGH), }, }; /* I2C device */ +static struct tw9910_video_info tw9910_info = { + .buswidth = 8, + .mpout = TW9910_MPO_FIELD, +}; + +static struct mt9t112_platform_data mt9t112_0_pdata = { + .flags = MT9T112_FLAG_PCLK_RISING_EDGE, + .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */ +}; + +static struct mt9t112_platform_data mt9t112_1_pdata = { + .flags = MT9T112_FLAG_PCLK_RISING_EDGE, + .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */ +}; + static struct i2c_board_info i2c0_devices[] = { { I2C_BOARD_INFO("da7210", 0x1a), }, + { + I2C_BOARD_INFO("tw9910", 0x45), + .platform_data = &tw9910_info, + }, + { + /* 1st camera */ + I2C_BOARD_INFO("mt9t112", 0x3c), + .platform_data = &mt9t112_0_pdata, + }, }; static struct i2c_board_info i2c1_devices[] = { @@ -457,7 +531,12 @@ static struct i2c_board_info i2c1_devices[] = { { I2C_BOARD_INFO("lis3lv02d", 0x1c), .irq = evt2irq(0x620), - } + }, + { + /* 2nd camera */ + I2C_BOARD_INFO("mt9t112", 0x3c), + .platform_data = &mt9t112_1_pdata, + }, }; /* KEYSC */ @@ -724,115 +803,6 @@ static struct platform_device msiof0_device = { #endif -/* I2C Video/Camera */ -static struct i2c_board_info i2c_camera[] = { - { - I2C_BOARD_INFO("tw9910", 0x45), - }, - { - /* 1st camera */ - I2C_BOARD_INFO("mt9t112", 0x3c), - }, - { - /* 2nd camera */ - I2C_BOARD_INFO("mt9t112", 0x3c), - }, -}; - -/* tw9910 */ -static int tw9910_power(struct device *dev, int mode) -{ - int val = mode ? 0 : 1; - - gpio_set_value(GPIO_PTU2, val); - if (mode) - mdelay(100); - - return 0; -} - -static struct tw9910_video_info tw9910_info = { - .buswidth = SOCAM_DATAWIDTH_8, - .mpout = TW9910_MPO_FIELD, -}; - -static struct soc_camera_link tw9910_link = { - .i2c_adapter_id = 0, - .bus_id = 1, - .power = tw9910_power, - .board_info = &i2c_camera[0], - .priv = &tw9910_info, -}; - -/* mt9t112 */ -static int mt9t112_power1(struct device *dev, int mode) -{ - gpio_set_value(GPIO_PTA3, mode); - if (mode) - mdelay(100); - - return 0; -} - -static struct mt9t112_camera_info mt9t112_info1 = { - .flags = MT9T112_FLAG_PCLK_RISING_EDGE | MT9T112_FLAG_DATAWIDTH_8, - .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */ -}; - -static struct soc_camera_link mt9t112_link1 = { - .i2c_adapter_id = 0, - .power = mt9t112_power1, - .bus_id = 0, - .board_info = &i2c_camera[1], - .priv = &mt9t112_info1, -}; - -static int mt9t112_power2(struct device *dev, int mode) -{ - gpio_set_value(GPIO_PTA4, mode); - if (mode) - mdelay(100); - - return 0; -} - -static struct mt9t112_camera_info mt9t112_info2 = { - .flags = MT9T112_FLAG_PCLK_RISING_EDGE | MT9T112_FLAG_DATAWIDTH_8, - .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */ -}; - -static struct soc_camera_link mt9t112_link2 = { - .i2c_adapter_id = 1, - .power = mt9t112_power2, - .bus_id = 1, - .board_info = &i2c_camera[2], - .priv = &mt9t112_info2, -}; - -static struct platform_device camera_devices[] = { - { - .name = "soc-camera-pdrv", - .id = 0, - .dev = { - .platform_data = &tw9910_link, - }, - }, - { - .name = "soc-camera-pdrv", - .id = 1, - .dev = { - .platform_data = &mt9t112_link1, - }, - }, - { - .name = "soc-camera-pdrv", - .id = 2, - .dev = { - .platform_data = &mt9t112_link2, - }, - }, -}; - /* FSI */ static struct resource fsi_resources[] = { [0] = { @@ -979,6 +949,11 @@ static struct platform_device sh_mmcif_device = { }; #endif +static struct platform_device *ecovec_ceu_devices[] __initdata = { + &ceu0_device, + &ceu1_device, +}; + static struct platform_device *ecovec_devices[] __initdata = { &heartbeat_device, &nor_flash_device, @@ -988,8 +963,6 @@ static struct platform_device *ecovec_devices[] __initdata = { &usbhs_device, &lcdc_device, &gpio_backlight_device, - &ceu0_device, - &ceu1_device, &keysc_device, &cn12_power, #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) @@ -1001,9 +974,6 @@ static struct platform_device *ecovec_devices[] __initdata = { #else &msiof0_device, #endif - &camera_devices[0], - &camera_devices[1], - &camera_devices[2], &fsi_device, &fsi_da7210_device, &irda_device, @@ -1240,7 +1210,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_VIO0_CLK, NULL); gpio_request(GPIO_FN_VIO0_FLD, NULL); gpio_request(GPIO_FN_VIO0_HD, NULL); - platform_resource_setup_memory(&ceu0_device, "ceu0", 4 << 20); /* enable CEU1 */ gpio_request(GPIO_FN_VIO1_D7, NULL); @@ -1255,7 +1224,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_VIO1_HD, NULL); gpio_request(GPIO_FN_VIO1_VD, NULL); gpio_request(GPIO_FN_VIO1_CLK, NULL); - platform_resource_setup_memory(&ceu1_device, "ceu1", 4 << 20); /* enable KEYSC */ gpio_request(GPIO_FN_KEYOUT5_IN5, NULL); @@ -1332,16 +1300,6 @@ static int __init arch_setup(void) __raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000, IODRIVEA); - /* enable Video */ - gpio_request(GPIO_PTU2, NULL); - gpio_direction_output(GPIO_PTU2, 1); - - /* enable Camera */ - gpio_request(GPIO_PTA3, NULL); - gpio_request(GPIO_PTA4, NULL); - gpio_direction_output(GPIO_PTA3, 0); - gpio_direction_output(GPIO_PTA4, 0); - /* enable FSI */ gpio_request(GPIO_FN_FSIMCKB, NULL); gpio_request(GPIO_FN_FSIIBSD, NULL); @@ -1390,6 +1348,11 @@ static int __init arch_setup(void) gpio_request(GPIO_PTU5, NULL); gpio_direction_output(GPIO_PTU5, 0); + /* Register gpio lookup tables for cameras and video decoder */ + gpiod_add_lookup_table(&tw9910_gpios); + gpiod_add_lookup_table(&mt9t112_0_gpios); + gpiod_add_lookup_table(&mt9t112_1_gpios); + /* enable I2C device */ i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); @@ -1431,6 +1394,25 @@ static int __init arch_setup(void) gpio_set_value(GPIO_PTG4, 1); #endif + /* Initialize CEU platform devices separately to map memory first */ + device_initialize(&ecovec_ceu_devices[0]->dev); + arch_setup_pdev_archdata(ecovec_ceu_devices[0]); + dma_declare_coherent_memory(&ecovec_ceu_devices[0]->dev, + ceu0_dma_membase, ceu0_dma_membase, + ceu0_dma_membase + + CEU_BUFFER_MEMORY_SIZE - 1, + DMA_MEMORY_EXCLUSIVE); + platform_device_add(ecovec_ceu_devices[0]); + + device_initialize(&ecovec_ceu_devices[1]->dev); + arch_setup_pdev_archdata(ecovec_ceu_devices[1]); + dma_declare_coherent_memory(&ecovec_ceu_devices[1]->dev, + ceu1_dma_membase, ceu1_dma_membase, + ceu1_dma_membase + + CEU_BUFFER_MEMORY_SIZE - 1, + DMA_MEMORY_EXCLUSIVE); + platform_device_add(ecovec_ceu_devices[1]); + return platform_add_devices(ecovec_devices, ARRAY_SIZE(ecovec_devices)); } @@ -1443,6 +1425,24 @@ static int __init devices_setup(void) } device_initcall(devices_setup); +/* Reserve a portion of memory for CEU 0 and CEU 1 buffers */ +static void __init ecovec_mv_mem_reserve(void) +{ + phys_addr_t phys; + phys_addr_t size = CEU_BUFFER_MEMORY_SIZE; + + phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE); + memblock_free(phys, size); + memblock_remove(phys, size); + ceu0_dma_membase = phys; + + phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE); + memblock_free(phys, size); + memblock_remove(phys, size); + ceu1_dma_membase = phys; +} + static struct sh_machine_vector mv_ecovec __initmv = { .mv_name = "R0P7724 (EcoVec)", + .mv_mem_reserve = ecovec_mv_mem_reserve, }; diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 0bcbe58b11e9..271dfc260e82 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -1,17 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas System Solutions Asia Pte. Ltd - Migo-R * * Copyright (C) 2008 Magnus Damm - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. */ +#include <linux/clkdev.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/input/sh_keysc.h> +#include <linux/memblock.h> #include <linux/mmc/host.h> #include <linux/mtd/physmap.h> #include <linux/mfd/tmio.h> @@ -23,10 +22,11 @@ #include <linux/delay.h> #include <linux/clk.h> #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/videodev2.h> #include <linux/sh_intc.h> #include <video/sh_mobile_lcdc.h> -#include <media/drv-intf/sh_mobile_ceu.h> +#include <media/drv-intf/renesas-ceu.h> #include <media/i2c/ov772x.h> #include <media/soc_camera.h> #include <media/i2c/tw9910.h> @@ -45,6 +45,9 @@ * 0x18000000 8GB 8 NAND Flash (K9K8G08U0A) */ +#define CEU_BUFFER_MEMORY_SIZE (4 << 20) +static phys_addr_t ceu_dma_membase; + static struct smc91x_platdata smc91x_info = { .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, }; @@ -301,65 +304,24 @@ static struct platform_device migor_lcdc_device = { }, }; -static struct clk *camera_clk; -static DEFINE_MUTEX(camera_lock); - -static void camera_power_on(int is_tw) -{ - mutex_lock(&camera_lock); - - /* Use 10 MHz VIO_CKO instead of 24 MHz to work - * around signal quality issues on Panel Board V2.1. - */ - camera_clk = clk_get(NULL, "video_clk"); - clk_set_rate(camera_clk, 10000000); - clk_enable(camera_clk); /* start VIO_CKO */ - - /* use VIO_RST to take camera out of reset */ - mdelay(10); - if (is_tw) { - gpio_set_value(GPIO_PTT2, 0); - gpio_set_value(GPIO_PTT0, 0); - } else { - gpio_set_value(GPIO_PTT0, 1); - } - gpio_set_value(GPIO_PTT3, 0); - mdelay(10); - gpio_set_value(GPIO_PTT3, 1); - mdelay(10); /* wait to let chip come out of reset */ -} - -static void camera_power_off(void) -{ - clk_disable(camera_clk); /* stop VIO_CKO */ - clk_put(camera_clk); - - gpio_set_value(GPIO_PTT3, 0); - mutex_unlock(&camera_lock); -} - -static int ov7725_power(struct device *dev, int mode) -{ - if (mode) - camera_power_on(0); - else - camera_power_off(); - - return 0; -} - -static int tw9910_power(struct device *dev, int mode) -{ - if (mode) - camera_power_on(1); - else - camera_power_off(); - - return 0; -} - -static struct sh_mobile_ceu_info sh_mobile_ceu_info = { - .flags = SH_CEU_FLAG_USE_8BIT_BUS, +static struct ceu_platform_data ceu_pdata = { + .num_subdevs = 2, + .subdevs = { + { /* [0] = ov772x */ + .flags = 0, + .bus_width = 8, + .bus_shift = 0, + .i2c_adapter_id = 0, + .i2c_address = 0x21, + }, + { /* [1] = tw9910 */ + .flags = 0, + .bus_width = 8, + .bus_shift = 0, + .i2c_adapter_id = 0, + .i2c_address = 0x45, + }, + }, }; static struct resource migor_ceu_resources[] = { @@ -373,18 +335,32 @@ static struct resource migor_ceu_resources[] = { .start = evt2irq(0x880), .flags = IORESOURCE_IRQ, }, - [2] = { - /* place holder for contiguous memory */ - }, }; static struct platform_device migor_ceu_device = { - .name = "sh_mobile_ceu", - .id = 0, /* "ceu0" clock */ + .name = "renesas-ceu", + .id = 0, /* ceu.0 */ .num_resources = ARRAY_SIZE(migor_ceu_resources), .resource = migor_ceu_resources, .dev = { - .platform_data = &sh_mobile_ceu_info, + .platform_data = &ceu_pdata, + }, +}; + +/* Powerdown/reset gpios for CEU image sensors */ +static struct gpiod_lookup_table ov7725_gpios = { + .dev_id = "0-0021", + .table = { + GPIO_LOOKUP("sh7722_pfc", GPIO_PTT0, "pwdn", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW), + }, +}; + +static struct gpiod_lookup_table tw9910_gpios = { + .dev_id = "0-0045", + .table = { + GPIO_LOOKUP("sh7722_pfc", GPIO_PTT2, "pdn", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW), }, }; @@ -423,6 +399,15 @@ static struct platform_device sdhi_cn9_device = { }, }; +static struct ov772x_camera_info ov7725_info = { + .flags = 0, +}; + +static struct tw9910_video_info tw9910_info = { + .buswidth = 8, + .mpout = TW9910_MPO_FIELD, +}; + static struct i2c_board_info migor_i2c_devices[] = { { I2C_BOARD_INFO("rs5c372b", 0x32), @@ -434,51 +419,13 @@ static struct i2c_board_info migor_i2c_devices[] = { { I2C_BOARD_INFO("wm8978", 0x1a), }, -}; - -static struct i2c_board_info migor_i2c_camera[] = { { I2C_BOARD_INFO("ov772x", 0x21), + .platform_data = &ov7725_info, }, { I2C_BOARD_INFO("tw9910", 0x45), - }, -}; - -static struct ov772x_camera_info ov7725_info; - -static struct soc_camera_link ov7725_link = { - .power = ov7725_power, - .board_info = &migor_i2c_camera[0], - .i2c_adapter_id = 0, - .priv = &ov7725_info, -}; - -static struct tw9910_video_info tw9910_info = { - .buswidth = SOCAM_DATAWIDTH_8, - .mpout = TW9910_MPO_FIELD, -}; - -static struct soc_camera_link tw9910_link = { - .power = tw9910_power, - .board_info = &migor_i2c_camera[1], - .i2c_adapter_id = 0, - .priv = &tw9910_info, -}; - -static struct platform_device migor_camera[] = { - { - .name = "soc-camera-pdrv", - .id = 0, - .dev = { - .platform_data = &ov7725_link, - }, - }, { - .name = "soc-camera-pdrv", - .id = 1, - .dev = { - .platform_data = &tw9910_link, - }, + .platform_data = &tw9910_info, }, }; @@ -486,12 +433,9 @@ static struct platform_device *migor_devices[] __initdata = { &smc91x_eth_device, &sh_keysc_device, &migor_lcdc_device, - &migor_ceu_device, &migor_nor_flash_device, &migor_nand_flash_device, &sdhi_cn9_device, - &migor_camera[0], - &migor_camera[1], }; extern char migor_sdram_enter_start; @@ -501,6 +445,8 @@ extern char migor_sdram_leave_end; static int __init migor_devices_setup(void) { + struct clk *video_clk; + /* register board specific self-refresh code */ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, &migor_sdram_enter_start, @@ -620,20 +566,8 @@ static int __init migor_devices_setup(void) gpio_request(GPIO_FN_VIO_D9, NULL); gpio_request(GPIO_FN_VIO_D8, NULL); - gpio_request(GPIO_PTT3, NULL); /* VIO_RST */ - gpio_direction_output(GPIO_PTT3, 0); - gpio_request(GPIO_PTT2, NULL); /* TV_IN_EN */ - gpio_direction_output(GPIO_PTT2, 1); - gpio_request(GPIO_PTT0, NULL); /* CAM_EN */ -#ifdef CONFIG_SH_MIGOR_RTA_WVGA - gpio_direction_output(GPIO_PTT0, 0); -#else - gpio_direction_output(GPIO_PTT0, 1); -#endif __raw_writew(__raw_readw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */ - platform_resource_setup_memory(&migor_ceu_device, "ceu", 4 << 20); - /* SIU: Port B */ gpio_request(GPIO_FN_SIUBOLR, NULL); gpio_request(GPIO_FN_SIUBOBT, NULL); @@ -647,9 +581,36 @@ static int __init migor_devices_setup(void) */ __raw_writew(__raw_readw(PORT_MSELCRA) | 1, PORT_MSELCRA); + /* + * Use 10 MHz VIO_CKO instead of 24 MHz to work around signal quality + * issues on Panel Board V2.1. + */ + video_clk = clk_get(NULL, "video_clk"); + if (!IS_ERR(video_clk)) { + clk_set_rate(video_clk, clk_round_rate(video_clk, 10000000)); + clk_put(video_clk); + } + + /* Add a clock alias for ov7725 xclk source. */ + clk_add_alias("xclk", "0-0021", "video_clk", NULL); + + /* Register GPIOs for video sources. */ + gpiod_add_lookup_table(&ov7725_gpios); + gpiod_add_lookup_table(&tw9910_gpios); + i2c_register_board_info(0, migor_i2c_devices, ARRAY_SIZE(migor_i2c_devices)); + /* Initialize CEU platform device separately to map memory first */ + device_initialize(&migor_ceu_device.dev); + arch_setup_pdev_archdata(&migor_ceu_device); + dma_declare_coherent_memory(&migor_ceu_device.dev, + ceu_dma_membase, ceu_dma_membase, + ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1, + DMA_MEMORY_EXCLUSIVE); + + platform_device_add(&migor_ceu_device); + return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); } arch_initcall(migor_devices_setup); @@ -665,10 +626,24 @@ static int migor_mode_pins(void) return MODE_PIN0 | MODE_PIN1 | MODE_PIN5; } +/* Reserve a portion of memory for CEU buffers */ +static void __init migor_mv_mem_reserve(void) +{ + phys_addr_t phys; + phys_addr_t size = CEU_BUFFER_MEMORY_SIZE; + + phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE); + memblock_free(phys, size); + memblock_remove(phys, size); + + ceu_dma_membase = phys; +} + /* * The Machine Vector */ static struct sh_machine_vector mv_migor __initmv = { .mv_name = "Migo-R", .mv_mode_pins = migor_mode_pins, + .mv_mem_reserve = migor_mv_mem_reserve, }; diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 8f07a1a38692..d85091ec4b01 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -223,7 +223,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]), CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]), CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]), - CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]), + CLKDEV_DEV_ID("renesas-ceu.0", &mstp_clks[HWBLK_CEU]), CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU]), CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]), CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]), diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index f27c618de527..3194336a3599 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -338,14 +338,14 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]), CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]), CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]), - CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[HWBLK_CEU1]), + CLKDEV_DEV_ID("renesas-ceu.1", &mstp_clks[HWBLK_CEU1]), CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]), CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]), CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]), CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]), CLKDEV_DEV_ID("sh-vou", &mstp_clks[HWBLK_VOU]), CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]), - CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]), + CLKDEV_DEV_ID("renesas-ceu.0", &mstp_clks[HWBLK_CEU0]), CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]), CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]), CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]), diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f16f8358c70a..894843a7ec7b 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -38,6 +38,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-dev.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> #include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-sg.h> @@ -81,7 +82,10 @@ struct sur40_blob { __le32 area; /* size in pixels/pressure (?) */ - u8 padding[32]; + u8 padding[24]; + + __le32 tag_id; /* valid when type == 0x04 (SUR40_TAG) */ + __le32 unknown; } __packed; @@ -146,6 +150,40 @@ struct sur40_image_header { #define SUR40_TOUCH 0x02 #define SUR40_TAG 0x04 +/* video controls */ +#define SUR40_BRIGHTNESS_MAX 0xff +#define SUR40_BRIGHTNESS_MIN 0x00 +#define SUR40_BRIGHTNESS_DEF 0xff + +#define SUR40_CONTRAST_MAX 0x0f +#define SUR40_CONTRAST_MIN 0x00 +#define SUR40_CONTRAST_DEF 0x0a + +#define SUR40_GAIN_MAX 0x09 +#define SUR40_GAIN_MIN 0x00 +#define SUR40_GAIN_DEF 0x08 + +#define SUR40_BACKLIGHT_MAX 0x01 +#define SUR40_BACKLIGHT_MIN 0x00 +#define SUR40_BACKLIGHT_DEF 0x01 + +#define sur40_str(s) #s +#define SUR40_PARAM_RANGE(lo, hi) " (range " sur40_str(lo) "-" sur40_str(hi) ")" + +/* module parameters */ +static uint brightness = SUR40_BRIGHTNESS_DEF; +module_param(brightness, uint, 0644); +MODULE_PARM_DESC(brightness, "set initial brightness" + SUR40_PARAM_RANGE(SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX)); +static uint contrast = SUR40_CONTRAST_DEF; +module_param(contrast, uint, 0644); +MODULE_PARM_DESC(contrast, "set initial contrast" + SUR40_PARAM_RANGE(SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX)); +static uint gain = SUR40_GAIN_DEF; +module_param(gain, uint, 0644); +MODULE_PARM_DESC(gain, "set initial gain" + SUR40_PARAM_RANGE(SUR40_GAIN_MIN, SUR40_GAIN_MAX)); + static const struct v4l2_pix_format sur40_pix_format[] = { { .pixelformat = V4L2_TCH_FMT_TU08, @@ -178,6 +216,7 @@ struct sur40_state { struct video_device vdev; struct mutex lock; struct v4l2_pix_format pix_fmt; + struct v4l2_ctrl_handler hdl; struct vb2_queue queue; struct list_head buf_list; @@ -187,6 +226,7 @@ struct sur40_state { struct sur40_data *bulk_in_buffer; size_t bulk_in_size; u8 bulk_in_epaddr; + u8 vsvideo; char phys[64]; }; @@ -200,6 +240,11 @@ struct sur40_buffer { static const struct video_device sur40_video_device; static const struct vb2_queue sur40_queue; static void sur40_process_video(struct sur40_state *sur40); +static int sur40_s_ctrl(struct v4l2_ctrl *ctrl); + +static const struct v4l2_ctrl_ops sur40_ctrl_ops = { + .s_ctrl = sur40_s_ctrl, +}; /* * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT @@ -220,6 +265,81 @@ static int sur40_command(struct sur40_state *dev, 0x00, index, buffer, size, 1000); } +/* poke a byte in the panel register space */ +static int sur40_poke(struct sur40_state *dev, u8 offset, u8 value) +{ + int result; + u8 index = 0x96; // 0xae for permanent write + + result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), + SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x32, index, NULL, 0, 1000); + if (result < 0) + goto error; + msleep(5); + + result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), + SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x72, offset, NULL, 0, 1000); + if (result < 0) + goto error; + msleep(5); + + result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), + SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0xb2, value, NULL, 0, 1000); + if (result < 0) + goto error; + msleep(5); + +error: + return result; +} + +static int sur40_set_preprocessor(struct sur40_state *dev, u8 value) +{ + u8 setting_07[2] = { 0x01, 0x00 }; + u8 setting_17[2] = { 0x85, 0x80 }; + int result; + + if (value > 1) + return -ERANGE; + + result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), + SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x07, setting_07[value], NULL, 0, 1000); + if (result < 0) + goto error; + msleep(5); + + result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), + SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x17, setting_17[value], NULL, 0, 1000); + if (result < 0) + goto error; + msleep(5); + +error: + return result; +} + +static void sur40_set_vsvideo(struct sur40_state *handle, u8 value) +{ + int i; + + for (i = 0; i < 4; i++) + sur40_poke(handle, 0x1c+i, value); + handle->vsvideo = value; +} + +static void sur40_set_irlevel(struct sur40_state *handle, u8 value) +{ + int i; + + for (i = 0; i < 8; i++) + sur40_poke(handle, 0x08+(2*i), value); +} + /* Initialization routine, called from sur40_open */ static int sur40_init(struct sur40_state *dev) { @@ -631,6 +751,36 @@ static int sur40_probe(struct usb_interface *interface, sur40->vdev.queue = &sur40->queue; video_set_drvdata(&sur40->vdev, sur40); + /* initialize the control handler for 4 controls */ + v4l2_ctrl_handler_init(&sur40->hdl, 4); + sur40->v4l2.ctrl_handler = &sur40->hdl; + sur40->vsvideo = (SUR40_CONTRAST_DEF << 4) | SUR40_GAIN_DEF; + + v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_BRIGHTNESS, + SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX, 1, clamp(brightness, + (uint)SUR40_BRIGHTNESS_MIN, (uint)SUR40_BRIGHTNESS_MAX)); + + v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_CONTRAST, + SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX, 1, clamp(contrast, + (uint)SUR40_CONTRAST_MIN, (uint)SUR40_CONTRAST_MAX)); + + v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_GAIN, + SUR40_GAIN_MIN, SUR40_GAIN_MAX, 1, clamp(gain, + (uint)SUR40_GAIN_MIN, (uint)SUR40_GAIN_MAX)); + + v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, + V4L2_CID_BACKLIGHT_COMPENSATION, SUR40_BACKLIGHT_MIN, + SUR40_BACKLIGHT_MAX, 1, SUR40_BACKLIGHT_DEF); + + v4l2_ctrl_handler_setup(&sur40->hdl); + + if (sur40->hdl.error) { + dev_err(&interface->dev, + "Unable to register video controls."); + v4l2_ctrl_handler_free(&sur40->hdl); + goto err_unreg_v4l2; + } + error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1); if (error) { dev_err(&interface->dev, @@ -663,6 +813,7 @@ static void sur40_disconnect(struct usb_interface *interface) { struct sur40_state *sur40 = usb_get_intfdata(interface); + v4l2_ctrl_handler_free(&sur40->hdl); video_unregister_device(&sur40->vdev); v4l2_device_unregister(&sur40->v4l2); @@ -856,6 +1007,31 @@ static int sur40_vidioc_g_fmt(struct file *file, void *priv, return 0; } +static int sur40_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct sur40_state *sur40 = container_of(ctrl->handler, + struct sur40_state, hdl); + u8 value = sur40->vsvideo; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + sur40_set_irlevel(sur40, ctrl->val); + break; + case V4L2_CID_CONTRAST: + value = (value & 0x0f) | (ctrl->val << 4); + sur40_set_vsvideo(sur40, value); + break; + case V4L2_CID_GAIN: + value = (value & 0xf0) | (ctrl->val); + sur40_set_vsvideo(sur40, value); + break; + case V4L2_CID_BACKLIGHT_COMPENSATION: + sur40_set_preprocessor(sur40, ctrl->val); + break; + } + return 0; +} + static int sur40_ioctl_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 86c1a190d946..37124c3b8c2a 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -141,6 +141,7 @@ config DVB_CORE tristate depends on MEDIA_SUPPORT depends on MEDIA_DIGITAL_TV_SUPPORT + depends on (I2C || I2C=n) default y select CRC32 diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index 43428cec3a01..9c2b108c613a 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -4,3 +4,9 @@ config MEDIA_CEC_RC depends on CEC_CORE=m || RC_CORE=y ---help--- Pass on CEC remote control messages to the RC framework. + +config CEC_PIN_ERROR_INJ + bool "Enable CEC error injection support" + depends on CEC_PIN && DEBUG_FS + ---help--- + This option enables CEC error injection using debugfs. diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile index 41ee3325e1ea..29a2ab9e77c5 100644 --- a/drivers/media/cec/Makefile +++ b/drivers/media/cec/Makefile @@ -9,4 +9,8 @@ ifeq ($(CONFIG_CEC_PIN),y) cec-objs += cec-pin.o endif +ifeq ($(CONFIG_CEC_PIN_ERROR_INJ),y) + cec-objs += cec-pin-error-inj.o +endif + obj-$(CONFIG_CEC_CORE) += cec.o diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 2b1e540587d6..002ed4c90371 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -85,8 +73,8 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { - static const u8 max_events[CEC_NUM_EVENTS] = { - 1, 1, 64, 64, 8, 8, + static const u16 max_events[CEC_NUM_EVENTS] = { + 1, 1, 800, 800, 8, 8, }; struct cec_event_entry *entry; unsigned int ev_idx = new_ev->event - 1; @@ -154,11 +142,13 @@ static void cec_queue_event(struct cec_adapter *adap, } /* Notify userspace that the CEC pin changed state at the given time. */ -void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts) +void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, + bool dropped_events, ktime_t ts) { struct cec_event ev = { .event = is_high ? CEC_EVENT_PIN_CEC_HIGH : CEC_EVENT_PIN_CEC_LOW, + .flags = dropped_events ? CEC_EVENT_FL_DROPPED_EVENTS : 0, }; struct cec_fh *fh; @@ -711,16 +701,31 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, else msg->flags = 0; + if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } + /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { dprintk(1, "%s: invalid length %d\n", __func__, msg->len); return -EINVAL; } + + memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); + + if (msg->timeout) + dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", + __func__, msg->len, msg->msg, msg->reply, + !block ? ", nb" : ""); + else + dprintk(2, "%s: %*ph%s\n", + __func__, msg->len, msg->msg, !block ? " (nb)" : ""); + if (msg->timeout && msg->len == 1) { - dprintk(1, "%s: can't reply for poll msg\n", __func__); + dprintk(1, "%s: can't reply to poll msg\n", __func__); return -EINVAL; } - memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); if (msg->len == 1) { if (cec_msg_destination(msg) == 0xf) { dprintk(1, "%s: invalid poll message\n", __func__); @@ -780,19 +785,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (!msg->sequence) msg->sequence = ++adap->sequence; - if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } - - if (msg->timeout) - dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", - __func__, msg->len, msg->msg, msg->reply, - !block ? ", nb" : ""); - else - dprintk(2, "%s: %*ph%s\n", - __func__, msg->len, msg->msg, !block ? " (nb)" : ""); - data->msg = *msg; data->fh = fh; data->adap = adap; diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 492db12b8c4d..10b67fc40318 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-api.c - HDMI Consumer Electronics Control framework - API * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index a9f9525db9ae..b0c87f9ea08f 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-core.c - HDMI Consumer Electronics Control framework - Core * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -207,6 +195,55 @@ void cec_register_cec_notifier(struct cec_adapter *adap, EXPORT_SYMBOL_GPL(cec_register_cec_notifier); #endif +#ifdef CONFIG_DEBUG_FS +static ssize_t cec_error_inj_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *sf = file->private_data; + struct cec_adapter *adap = sf->private; + char *buf; + char *line; + char *p; + + buf = memdup_user_nul(ubuf, min_t(size_t, PAGE_SIZE, count)); + if (IS_ERR(buf)) + return PTR_ERR(buf); + p = buf; + while (p && *p) { + p = skip_spaces(p); + line = strsep(&p, "\n"); + if (!*line || *line == '#') + continue; + if (!adap->ops->error_inj_parse_line(adap, line)) { + kfree(buf); + return -EINVAL; + } + } + kfree(buf); + return count; +} + +static int cec_error_inj_show(struct seq_file *sf, void *unused) +{ + struct cec_adapter *adap = sf->private; + + return adap->ops->error_inj_show(adap, sf); +} + +static int cec_error_inj_open(struct inode *inode, struct file *file) +{ + return single_open(file, cec_error_inj_show, inode->i_private); +} + +static const struct file_operations cec_error_inj_fops = { + .open = cec_error_inj_open, + .write = cec_error_inj_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, void *priv, const char *name, u32 caps, u8 available_las) @@ -346,7 +383,16 @@ int cec_register_adapter(struct cec_adapter *adap, pr_warn("cec-%s: Failed to create status file\n", adap->name); debugfs_remove_recursive(adap->cec_dir); adap->cec_dir = NULL; + return 0; } + if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line) + return 0; + adap->error_inj_file = debugfs_create_file("error-inj", 0644, + adap->cec_dir, adap, + &cec_error_inj_fops); + if (IS_ERR_OR_NULL(adap->error_inj_file)) + pr_warn("cec-%s: Failed to create error-inj file\n", + adap->name); #endif return 0; } diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c index 38e3fec6152b..ec72ac1c0b91 100644 --- a/drivers/media/cec/cec-edid.c +++ b/drivers/media/cec/cec-edid.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 08b619d0ea1e..16dffa06c913 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-notifier.c - notify CEC drivers of physical address changes * * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk> * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/export.h> diff --git a/drivers/media/cec/cec-pin-error-inj.c b/drivers/media/cec/cec-pin-error-inj.c new file mode 100644 index 000000000000..aaa899a175ce --- /dev/null +++ b/drivers/media/cec/cec-pin-error-inj.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched/types.h> + +#include <media/cec-pin.h> +#include "cec-pin-priv.h" + +struct cec_error_inj_cmd { + unsigned int mode_offset; + int arg_idx; + const char *cmd; +}; + +static const struct cec_error_inj_cmd cec_error_inj_cmds[] = { + { CEC_ERROR_INJ_RX_NACK_OFFSET, -1, "rx-nack" }, + { CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, "rx-low-drive" }, + { CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, "rx-add-byte" }, + { CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, "rx-remove-byte" }, + { CEC_ERROR_INJ_RX_ARB_LOST_OFFSET, + CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, "rx-arb-lost" }, + + { CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, "tx-no-eom" }, + { CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, "tx-early-eom" }, + { CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET, + CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, "tx-add-bytes" }, + { CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, "tx-remove-byte" }, + { CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET, + CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, "tx-short-bit" }, + { CEC_ERROR_INJ_TX_LONG_BIT_OFFSET, + CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, "tx-long-bit" }, + { CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET, + CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, "tx-custom-bit" }, + { CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, "tx-short-start" }, + { CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, "tx-long-start" }, + { CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, -1, "tx-custom-start" }, + { CEC_ERROR_INJ_TX_LAST_BIT_OFFSET, + CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, "tx-last-bit" }, + { CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, "tx-low-drive" }, + { 0, -1, NULL } +}; + +u16 cec_pin_rx_error_inj(struct cec_pin *pin) +{ + u16 cmd = CEC_ERROR_INJ_OP_ANY; + + /* Only when 18 bits have been received do we have a valid cmd */ + if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) && + pin->rx_bit >= 18) + cmd = pin->rx_msg.msg[1]; + return (pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) ? cmd : + CEC_ERROR_INJ_OP_ANY; +} + +u16 cec_pin_tx_error_inj(struct cec_pin *pin) +{ + u16 cmd = CEC_ERROR_INJ_OP_ANY; + + if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) && + pin->tx_msg.len > 1) + cmd = pin->tx_msg.msg[1]; + return (pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) ? cmd : + CEC_ERROR_INJ_OP_ANY; +} + +bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) +{ + static const char *delims = " \t\r"; + struct cec_pin *pin = adap->pin; + unsigned int i; + bool has_pos = false; + char *p = line; + char *token; + char *comma; + u64 *error; + u8 *args; + bool has_op; + u32 op; + u8 mode; + u8 pos; + u8 v; + + p = skip_spaces(p); + token = strsep(&p, delims); + if (!strcmp(token, "clear")) { + memset(pin->error_inj, 0, sizeof(pin->error_inj)); + pin->rx_toggle = pin->tx_toggle = false; + pin->tx_ignore_nack_until_eom = false; + pin->tx_custom_pulse = false; + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + return true; + } + if (!strcmp(token, "rx-clear")) { + for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) + pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; + pin->rx_toggle = false; + return true; + } + if (!strcmp(token, "tx-clear")) { + for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) + pin->error_inj[i] &= ~CEC_ERROR_INJ_TX_MASK; + pin->tx_toggle = false; + pin->tx_ignore_nack_until_eom = false; + pin->tx_custom_pulse = false; + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + return true; + } + if (!strcmp(token, "tx-ignore-nack-until-eom")) { + pin->tx_ignore_nack_until_eom = true; + return true; + } + if (!strcmp(token, "tx-custom-pulse")) { + pin->tx_custom_pulse = true; + cec_pin_start_timer(pin); + return true; + } + if (!p) + return false; + + p = skip_spaces(p); + if (!strcmp(token, "tx-custom-low-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 10000000) + return false; + pin->tx_custom_low_usecs = usecs; + return true; + } + if (!strcmp(token, "tx-custom-high-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 10000000) + return false; + pin->tx_custom_high_usecs = usecs; + return true; + } + + comma = strchr(token, ','); + if (comma) + *comma++ = '\0'; + if (!strcmp(token, "any")) + op = CEC_ERROR_INJ_OP_ANY; + else if (!kstrtou8(token, 0, &v)) + op = v; + else + return false; + mode = CEC_ERROR_INJ_MODE_ONCE; + if (comma) { + if (!strcmp(comma, "off")) + mode = CEC_ERROR_INJ_MODE_OFF; + else if (!strcmp(comma, "once")) + mode = CEC_ERROR_INJ_MODE_ONCE; + else if (!strcmp(comma, "always")) + mode = CEC_ERROR_INJ_MODE_ALWAYS; + else if (!strcmp(comma, "toggle")) + mode = CEC_ERROR_INJ_MODE_TOGGLE; + else + return false; + } + + error = pin->error_inj + op; + args = pin->error_inj_args[op]; + has_op = op <= 0xff; + + token = strsep(&p, delims); + if (p) { + p = skip_spaces(p); + has_pos = !kstrtou8(p, 0, &pos); + } + + if (!strcmp(token, "clear")) { + *error = 0; + return true; + } + if (!strcmp(token, "rx-clear")) { + *error &= ~CEC_ERROR_INJ_RX_MASK; + return true; + } + if (!strcmp(token, "tx-clear")) { + *error &= ~CEC_ERROR_INJ_TX_MASK; + return true; + } + + for (i = 0; cec_error_inj_cmds[i].cmd; i++) { + const char *cmd = cec_error_inj_cmds[i].cmd; + unsigned int mode_offset; + u64 mode_mask; + int arg_idx; + bool is_bit_pos = true; + + if (strcmp(token, cmd)) + continue; + + mode_offset = cec_error_inj_cmds[i].mode_offset; + mode_mask = CEC_ERROR_INJ_MODE_MASK << mode_offset; + arg_idx = cec_error_inj_cmds[i].arg_idx; + + if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET) + is_bit_pos = false; + + if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET) { + if (has_op) + return false; + if (!has_pos) + pos = 0x0f; + } + if (arg_idx >= 0 && is_bit_pos) { + if (!has_pos || pos >= 160) + return false; + if (has_op && pos < 10 + 8) + return false; + /* Invalid bit position may not be the Ack bit */ + if ((mode_offset == CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_LONG_BIT_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET) && + (pos % 10) == 9) + return false; + } + *error &= ~mode_mask; + *error |= (u64)mode << mode_offset; + if (arg_idx >= 0) + args[arg_idx] = pos; + return true; + } + return false; +} + +static void cec_pin_show_cmd(struct seq_file *sf, u32 cmd, u8 mode) +{ + if (cmd == CEC_ERROR_INJ_OP_ANY) + seq_puts(sf, "any,"); + else + seq_printf(sf, "0x%02x,", cmd); + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + seq_puts(sf, "once "); + break; + case CEC_ERROR_INJ_MODE_ALWAYS: + seq_puts(sf, "always "); + break; + case CEC_ERROR_INJ_MODE_TOGGLE: + seq_puts(sf, "toggle "); + break; + default: + seq_puts(sf, "off "); + break; + } +} + +int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) +{ + struct cec_pin *pin = adap->pin; + unsigned int i, j; + + seq_puts(sf, "# Clear error injections:\n"); + seq_puts(sf, "# clear clear all rx and tx error injections\n"); + seq_puts(sf, "# rx-clear clear all rx error injections\n"); + seq_puts(sf, "# tx-clear clear all tx error injections\n"); + seq_puts(sf, "# <op> clear clear all rx and tx error injections for <op>\n"); + seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n"); + seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# RX error injection:\n"); + seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n"); + seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n"); + seq_puts(sf, "# <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message\n"); + seq_puts(sf, "# <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message\n"); + seq_puts(sf, "# <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# TX error injection settings:\n"); + seq_puts(sf, "# tx-ignore-nack-until-eom ignore early NACKs until EOM\n"); + seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n"); + seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n"); + seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# TX error injection:\n"); + seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n"); + seq_puts(sf, "# <op>[,<mode>] tx-early-eom set the EOM bit one byte too soon\n"); + seq_puts(sf, "# <op>[,<mode>] tx-add-bytes <num> append <num> (1-255) spurious bytes to the message\n"); + seq_puts(sf, "# <op>[,<mode>] tx-remove-byte drop the last byte from the message\n"); + seq_puts(sf, "# <op>[,<mode>] tx-short-bit <bit> make this bit shorter than allowed\n"); + seq_puts(sf, "# <op>[,<mode>] tx-long-bit <bit> make this bit longer than allowed\n"); + seq_puts(sf, "# <op>[,<mode>] tx-custom-bit <bit> send the custom pulse instead of this bit\n"); + seq_puts(sf, "# <op>[,<mode>] tx-short-start send a start pulse that's too short\n"); + seq_puts(sf, "# <op>[,<mode>] tx-long-start send a start pulse that's too long\n"); + seq_puts(sf, "# <op>[,<mode>] tx-custom-start send the custom pulse instead of the start pulse\n"); + seq_puts(sf, "# <op>[,<mode>] tx-last-bit <bit> stop sending after this bit\n"); + seq_puts(sf, "# <op>[,<mode>] tx-low-drive <bit> force a low-drive condition at this bit position\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# <op> CEC message opcode (0-255) or 'any'\n"); + seq_puts(sf, "# <mode> 'once' (default), 'always', 'toggle' or 'off'\n"); + seq_puts(sf, "# <bit> CEC message bit (0-159)\n"); + seq_puts(sf, "# 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK\n"); + seq_puts(sf, "# <poll> CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f)\n"); + seq_puts(sf, "# <usecs> microseconds (0-10000000, default 1000)\n"); + + seq_puts(sf, "\nclear\n"); + + for (i = 0; i < ARRAY_SIZE(pin->error_inj); i++) { + u64 e = pin->error_inj[i]; + + for (j = 0; cec_error_inj_cmds[j].cmd; j++) { + const char *cmd = cec_error_inj_cmds[j].cmd; + unsigned int mode; + unsigned int mode_offset; + int arg_idx; + + mode_offset = cec_error_inj_cmds[j].mode_offset; + arg_idx = cec_error_inj_cmds[j].arg_idx; + mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + if (!mode) + continue; + cec_pin_show_cmd(sf, i, mode); + seq_puts(sf, cmd); + if (arg_idx >= 0) + seq_printf(sf, " %u", + pin->error_inj_args[i][arg_idx]); + seq_puts(sf, "\n"); + } + } + + if (pin->tx_ignore_nack_until_eom) + seq_puts(sf, "tx-ignore-nack-until-eom\n"); + if (pin->tx_custom_pulse) + seq_puts(sf, "tx-custom-pulse\n"); + if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT) + seq_printf(sf, "tx-custom-low-usecs %u\n", + pin->tx_custom_low_usecs); + if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) + seq_printf(sf, "tx-custom-high-usecs %u\n", + pin->tx_custom_high_usecs); + return 0; +} diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index 7d0def199762..f423db8855d9 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-pin-priv.h - internal cec-pin header * * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef LINUX_CEC_PIN_PRIV_H @@ -40,14 +28,30 @@ enum cec_pin_state { CEC_ST_TX_START_BIT_LOW, /* Drive CEC high for the start bit */ CEC_ST_TX_START_BIT_HIGH, + /* Generate a start bit period that is too short */ + CEC_ST_TX_START_BIT_HIGH_SHORT, + /* Generate a start bit period that is too long */ + CEC_ST_TX_START_BIT_HIGH_LONG, + /* Drive CEC low for the start bit using the custom timing */ + CEC_ST_TX_START_BIT_LOW_CUSTOM, + /* Drive CEC high for the start bit using the custom timing */ + CEC_ST_TX_START_BIT_HIGH_CUSTOM, /* Drive CEC low for the 0 bit */ CEC_ST_TX_DATA_BIT_0_LOW, /* Drive CEC high for the 0 bit */ CEC_ST_TX_DATA_BIT_0_HIGH, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_0_HIGH_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_0_HIGH_LONG, /* Drive CEC low for the 1 bit */ CEC_ST_TX_DATA_BIT_1_LOW, /* Drive CEC high for the 1 bit */ CEC_ST_TX_DATA_BIT_1_HIGH, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_1_HIGH_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_1_HIGH_LONG, /* * Wait for start of sample time to check for Ack bit or first * four initiator bits to check for Arbitration Lost. @@ -55,6 +59,20 @@ enum cec_pin_state { CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE, /* Wait for end of bit period after sampling */ CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG, + /* Drive CEC low for a data bit using the custom timing */ + CEC_ST_TX_DATA_BIT_LOW_CUSTOM, + /* Drive CEC high for a data bit using the custom timing */ + CEC_ST_TX_DATA_BIT_HIGH_CUSTOM, + /* Drive CEC low for a standalone pulse using the custom timing */ + CEC_ST_TX_PULSE_LOW_CUSTOM, + /* Drive CEC high for a standalone pulse using the custom timing */ + CEC_ST_TX_PULSE_HIGH_CUSTOM, + /* Start low drive */ + CEC_ST_TX_LOW_DRIVE, /* Rx states */ @@ -66,8 +84,8 @@ enum cec_pin_state { CEC_ST_RX_DATA_SAMPLE, /* Wait for earliest end of bit period after sampling */ CEC_ST_RX_DATA_POST_SAMPLE, - /* Wait for CEC to go high (i.e. end of bit period */ - CEC_ST_RX_DATA_HIGH, + /* Wait for CEC to go low (i.e. end of bit period) */ + CEC_ST_RX_DATA_WAIT_FOR_LOW, /* Drive CEC low to send 0 Ack bit */ CEC_ST_RX_ACK_LOW, /* End of 0 Ack time, wait for earliest end of bit period */ @@ -76,9 +94,9 @@ enum cec_pin_state { CEC_ST_RX_ACK_HIGH_POST, /* Wait for earliest end of bit period and end of message */ CEC_ST_RX_ACK_FINISH, - /* Start low drive */ - CEC_ST_LOW_DRIVE, + CEC_ST_RX_LOW_DRIVE, + /* Monitor pin using interrupts */ CEC_ST_RX_IRQ, @@ -86,7 +104,58 @@ enum cec_pin_state { CEC_PIN_STATES }; -#define CEC_NUM_PIN_EVENTS 128 +/* Error Injection */ + +/* Error injection modes */ +#define CEC_ERROR_INJ_MODE_OFF 0 +#define CEC_ERROR_INJ_MODE_ONCE 1 +#define CEC_ERROR_INJ_MODE_ALWAYS 2 +#define CEC_ERROR_INJ_MODE_TOGGLE 3 +#define CEC_ERROR_INJ_MODE_MASK 3ULL + +/* Receive error injection options */ +#define CEC_ERROR_INJ_RX_NACK_OFFSET 0 +#define CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET 2 +#define CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET 4 +#define CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET 6 +#define CEC_ERROR_INJ_RX_ARB_LOST_OFFSET 8 +#define CEC_ERROR_INJ_RX_MASK 0xffffULL + +/* Transmit error injection options */ +#define CEC_ERROR_INJ_TX_NO_EOM_OFFSET 16 +#define CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET 18 +#define CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET 20 +#define CEC_ERROR_INJ_TX_LONG_BIT_OFFSET 22 +#define CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET 24 +#define CEC_ERROR_INJ_TX_SHORT_START_OFFSET 26 +#define CEC_ERROR_INJ_TX_LONG_START_OFFSET 28 +#define CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET 30 +#define CEC_ERROR_INJ_TX_LAST_BIT_OFFSET 32 +#define CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET 34 +#define CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET 36 +#define CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET 38 +#define CEC_ERROR_INJ_TX_MASK 0xffffffffffff0000ULL + +#define CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX 0 +#define CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX 1 + +#define CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX 2 +#define CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX 3 +#define CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX 4 +#define CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX 5 +#define CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX 6 +#define CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX 7 +#define CEC_ERROR_INJ_NUM_ARGS 8 + +/* Special CEC op values */ +#define CEC_ERROR_INJ_OP_ANY 0x00000100 + +/* The default for the low/high time of the custom pulse */ +#define CEC_TIM_CUSTOM_DEFAULT 1000 + +#define CEC_NUM_PIN_EVENTS 128 +#define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) +#define CEC_PIN_EVENT_FL_DROPPED (1 << 1) #define CEC_PIN_IRQ_UNCHANGED 0 #define CEC_PIN_IRQ_DISABLE 1 @@ -110,24 +179,63 @@ struct cec_pin { u32 tx_bit; bool tx_nacked; u32 tx_signal_free_time; + bool tx_toggle; struct cec_msg rx_msg; u32 rx_bit; + bool rx_toggle; + u32 rx_start_bit_low_too_short_cnt; + u64 rx_start_bit_low_too_short_ts; + u32 rx_start_bit_low_too_short_delta; + u32 rx_start_bit_too_short_cnt; + u64 rx_start_bit_too_short_ts; + u32 rx_start_bit_too_short_delta; + u32 rx_start_bit_too_long_cnt; + u32 rx_data_bit_too_short_cnt; + u64 rx_data_bit_too_short_ts; + u32 rx_data_bit_too_short_delta; + u32 rx_data_bit_too_long_cnt; + u32 rx_low_drive_cnt; struct cec_msg work_rx_msg; u8 work_tx_status; ktime_t work_tx_ts; atomic_t work_irq_change; - atomic_t work_pin_events; + atomic_t work_pin_num_events; unsigned int work_pin_events_wr; unsigned int work_pin_events_rd; ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS]; - bool work_pin_is_high[CEC_NUM_PIN_EVENTS]; + u8 work_pin_events[CEC_NUM_PIN_EVENTS]; + bool work_pin_events_dropped; + u32 work_pin_events_dropped_cnt; ktime_t timer_ts; u32 timer_cnt; u32 timer_100ms_overruns; u32 timer_300ms_overruns; u32 timer_max_overrun; u32 timer_sum_overrun; + + u32 tx_custom_low_usecs; + u32 tx_custom_high_usecs; + bool tx_ignore_nack_until_eom; + bool tx_custom_pulse; + bool tx_generated_poll; + bool tx_post_eom; + u8 tx_extra_bytes; + u32 tx_low_drive_cnt; +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u64 error_inj[CEC_ERROR_INJ_OP_ANY + 1]; + u8 error_inj_args[CEC_ERROR_INJ_OP_ANY + 1][CEC_ERROR_INJ_NUM_ARGS]; +#endif }; +void cec_pin_start_timer(struct cec_pin *pin); + +#ifdef CONFIG_CEC_PIN_ERROR_INJ +bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line); +int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf); + +u16 cec_pin_rx_error_inj(struct cec_pin *pin); +u16 cec_pin_tx_error_inj(struct cec_pin *pin); +#endif + #endif diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index b48dfe844118..fafe1ebc8aff 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/delay.h> @@ -51,11 +39,29 @@ #define CEC_TIM_IDLE_SAMPLE 1000 /* when processing the start bit, sample twice per millisecond */ #define CEC_TIM_START_BIT_SAMPLE 500 -/* when polling for a state change, sample once every 50 micoseconds */ +/* when polling for a state change, sample once every 50 microseconds */ #define CEC_TIM_SAMPLE 50 #define CEC_TIM_LOW_DRIVE_ERROR (1.5 * CEC_TIM_DATA_BIT_TOTAL) +/* + * Total data bit time that is too short/long for a valid bit, + * used for error injection. + */ +#define CEC_TIM_DATA_BIT_TOTAL_SHORT 1800 +#define CEC_TIM_DATA_BIT_TOTAL_LONG 2900 + +/* + * Total start bit time that is too short/long for a valid bit, + * used for error injection. + */ +#define CEC_TIM_START_BIT_TOTAL_SHORT 4100 +#define CEC_TIM_START_BIT_TOTAL_LONG 5000 + +/* Data bits are 0-7, EOM is bit 8 and ACK is bit 9 */ +#define EOM_BIT 8 +#define ACK_BIT 9 + struct cec_state { const char * const name; unsigned int usecs; @@ -68,17 +74,32 @@ static const struct cec_state states[CEC_PIN_STATES] = { { "Tx Wait for High", CEC_TIM_IDLE_SAMPLE }, { "Tx Start Bit Low", CEC_TIM_START_BIT_LOW }, { "Tx Start Bit High", CEC_TIM_START_BIT_TOTAL - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit High Short", CEC_TIM_START_BIT_TOTAL_SHORT - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit High Long", CEC_TIM_START_BIT_TOTAL_LONG - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit Low Custom", 0 }, + { "Tx Start Bit High Custom", 0 }, { "Tx Data 0 Low", CEC_TIM_DATA_BIT_0_LOW }, { "Tx Data 0 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 0 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 0 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_0_LOW }, { "Tx Data 1 Low", CEC_TIM_DATA_BIT_1_LOW }, { "Tx Data 1 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_1_LOW }, - { "Tx Data 1 Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW }, - { "Tx Data 1 Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Post Sample Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Post Sample Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data Bit Low Custom", 0 }, + { "Tx Data Bit High Custom", 0 }, + { "Tx Pulse Low Custom", 0 }, + { "Tx Pulse High Custom", 0 }, + { "Tx Low Drive", CEC_TIM_LOW_DRIVE_ERROR }, { "Rx Start Bit Low", CEC_TIM_SAMPLE }, { "Rx Start Bit High", CEC_TIM_SAMPLE }, { "Rx Data Sample", CEC_TIM_DATA_BIT_SAMPLE }, { "Rx Data Post Sample", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_SAMPLE }, - { "Rx Data High", CEC_TIM_SAMPLE }, + { "Rx Data Wait for Low", CEC_TIM_SAMPLE }, { "Rx Ack Low", CEC_TIM_DATA_BIT_0_LOW }, { "Rx Ack Low Post", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_0_LOW }, { "Rx Ack High Post", CEC_TIM_DATA_BIT_HIGH }, @@ -93,12 +114,21 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) return; pin->adap->cec_pin_is_high = v; - if (atomic_read(&pin->work_pin_events) < CEC_NUM_PIN_EVENTS) { - pin->work_pin_is_high[pin->work_pin_events_wr] = v; + if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { + u8 ev = v; + + if (pin->work_pin_events_dropped) { + pin->work_pin_events_dropped = false; + v |= CEC_PIN_EVENT_FL_DROPPED; + } + pin->work_pin_events[pin->work_pin_events_wr] = ev; pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); pin->work_pin_events_wr = (pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS; - atomic_inc(&pin->work_pin_events); + atomic_inc(&pin->work_pin_num_events); + } else { + pin->work_pin_events_dropped = true; + pin->work_pin_events_dropped_cnt++; } wake_up_interruptible(&pin->kthread_waitq); } @@ -123,6 +153,173 @@ static bool cec_pin_high(struct cec_pin *pin) return cec_pin_read(pin); } +static bool rx_error_inj(struct cec_pin *pin, unsigned int mode_offset, + int arg_idx, u8 *arg) +{ +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u16 cmd = cec_pin_rx_error_inj(pin); + u64 e = pin->error_inj[cmd]; + unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + + if (arg_idx >= 0) { + u8 pos = pin->error_inj_args[cmd][arg_idx]; + + if (arg) + *arg = pos; + else if (pos != pin->rx_bit) + return false; + } + + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + pin->error_inj[cmd] &= + ~(CEC_ERROR_INJ_MODE_MASK << mode_offset); + return true; + case CEC_ERROR_INJ_MODE_ALWAYS: + return true; + case CEC_ERROR_INJ_MODE_TOGGLE: + return pin->rx_toggle; + default: + return false; + } +#else + return false; +#endif +} + +static bool rx_nack(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_NACK_OFFSET, -1, NULL); +} + +static bool rx_low_drive(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, NULL); +} + +static bool rx_add_byte(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, NULL); +} + +static bool rx_remove_byte(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, NULL); +} + +static bool rx_arb_lost(struct cec_pin *pin, u8 *poll) +{ + return pin->tx_msg.len == 0 && + rx_error_inj(pin, CEC_ERROR_INJ_RX_ARB_LOST_OFFSET, + CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, poll); +} + +static bool tx_error_inj(struct cec_pin *pin, unsigned int mode_offset, + int arg_idx, u8 *arg) +{ +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u16 cmd = cec_pin_tx_error_inj(pin); + u64 e = pin->error_inj[cmd]; + unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + + if (arg_idx >= 0) { + u8 pos = pin->error_inj_args[cmd][arg_idx]; + + if (arg) + *arg = pos; + else if (pos != pin->tx_bit) + return false; + } + + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + pin->error_inj[cmd] &= + ~(CEC_ERROR_INJ_MODE_MASK << mode_offset); + return true; + case CEC_ERROR_INJ_MODE_ALWAYS: + return true; + case CEC_ERROR_INJ_MODE_TOGGLE: + return pin->tx_toggle; + default: + return false; + } +#else + return false; +#endif +} + +static bool tx_no_eom(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, NULL); +} + +static bool tx_early_eom(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, NULL); +} + +static bool tx_short_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET, + CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, NULL); +} + +static bool tx_long_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_BIT_OFFSET, + CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, NULL); +} + +static bool tx_custom_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET, + CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, NULL); +} + +static bool tx_short_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, NULL); +} + +static bool tx_long_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, NULL); +} + +static bool tx_custom_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, + -1, NULL); +} + +static bool tx_last_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LAST_BIT_OFFSET, + CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, NULL); +} + +static u8 tx_add_bytes(struct cec_pin *pin) +{ + u8 bytes; + + if (tx_error_inj(pin, CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET, + CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, &bytes)) + return bytes; + return 0; +} + +static bool tx_remove_byte(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, NULL); +} + +static bool tx_low_drive(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, NULL); +} + static void cec_pin_to_idle(struct cec_pin *pin) { /* @@ -132,8 +329,16 @@ static void cec_pin_to_idle(struct cec_pin *pin) pin->rx_bit = pin->tx_bit = 0; pin->rx_msg.len = 0; memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); - pin->state = CEC_ST_IDLE; pin->ts = ns_to_ktime(0); + pin->tx_generated_poll = false; + pin->tx_post_eom = false; + if (pin->state >= CEC_ST_TX_WAIT && + pin->state <= CEC_ST_TX_LOW_DRIVE) + pin->tx_toggle ^= 1; + if (pin->state >= CEC_ST_RX_START_BIT_LOW && + pin->state <= CEC_ST_RX_LOW_DRIVE) + pin->rx_toggle ^= 1; + pin->state = CEC_ST_IDLE; } /* @@ -174,42 +379,109 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) break; case CEC_ST_TX_START_BIT_LOW: - pin->state = CEC_ST_TX_START_BIT_HIGH; + if (tx_short_start(pin)) { + /* + * Error Injection: send an invalid (too short) + * start pulse. + */ + pin->state = CEC_ST_TX_START_BIT_HIGH_SHORT; + } else if (tx_long_start(pin)) { + /* + * Error Injection: send an invalid (too long) + * start pulse. + */ + pin->state = CEC_ST_TX_START_BIT_HIGH_LONG; + } else { + pin->state = CEC_ST_TX_START_BIT_HIGH; + } + /* Generate start bit */ + cec_pin_high(pin); + break; + + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + pin->state = CEC_ST_TX_START_BIT_HIGH_CUSTOM; /* Generate start bit */ cec_pin_high(pin); break; case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: - /* If the read value is 1, then all is OK */ - if (!cec_pin_read(pin)) { + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG: + if (pin->tx_nacked) { + cec_pin_to_idle(pin); + pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_NACK; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + /* fall through */ + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_0_HIGH_LONG: + case CEC_ST_TX_DATA_BIT_1_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_LONG: + /* + * If the read value is 1, then all is OK, otherwise we have a + * low drive condition. + * + * Special case: when we generate a poll message due to an + * Arbitration Lost error injection, then ignore this since + * the pin can actually be low in that case. + */ + if (!cec_pin_read(pin) && !pin->tx_generated_poll) { /* * It's 0, so someone detected an error and pulled the * line low for 1.5 times the nominal bit period. */ pin->tx_msg.len = 0; + pin->state = CEC_ST_TX_WAIT_FOR_HIGH; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; - pin->state = CEC_ST_TX_WAIT_FOR_HIGH; + pin->tx_low_drive_cnt++; wake_up_interruptible(&pin->kthread_waitq); break; } - if (pin->tx_nacked) { + /* fall through */ + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + if (tx_last_bit(pin)) { + /* Error Injection: just stop sending after this bit */ cec_pin_to_idle(pin); pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; pin->work_tx_ts = ts; - pin->work_tx_status = CEC_TX_STATUS_NACK; + pin->work_tx_status = CEC_TX_STATUS_OK; wake_up_interruptible(&pin->kthread_waitq); break; } - /* fall through */ - case CEC_ST_TX_DATA_BIT_0_HIGH: - case CEC_ST_TX_DATA_BIT_1_HIGH: pin->tx_bit++; /* fall through */ case CEC_ST_TX_START_BIT_HIGH: - if (pin->tx_bit / 10 >= pin->tx_msg.len) { + case CEC_ST_TX_START_BIT_HIGH_SHORT: + case CEC_ST_TX_START_BIT_HIGH_LONG: + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: + if (tx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_TX_LOW_DRIVE; + pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; + pin->tx_low_drive_cnt++; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + if (pin->tx_bit / 10 >= pin->tx_msg.len + pin->tx_extra_bytes) { cec_pin_to_idle(pin); pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_OK; wake_up_interruptible(&pin->kthread_waitq); @@ -217,39 +489,82 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) } switch (pin->tx_bit % 10) { - default: - v = pin->tx_msg.msg[pin->tx_bit / 10] & - (1 << (7 - (pin->tx_bit % 10))); + default: { + /* + * In the CEC_ERROR_INJ_TX_ADD_BYTES case we transmit + * extra bytes, so pin->tx_bit / 10 can become >= 16. + * Generate bit values for those extra bytes instead + * of reading them from the transmit buffer. + */ + unsigned int idx = (pin->tx_bit / 10); + u8 val = idx; + + if (idx < pin->tx_msg.len) + val = pin->tx_msg.msg[idx]; + v = val & (1 << (7 - (pin->tx_bit % 10))); + pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : - CEC_ST_TX_DATA_BIT_0_LOW; + CEC_ST_TX_DATA_BIT_0_LOW; break; - case 8: - v = pin->tx_bit / 10 == pin->tx_msg.len - 1; + } + case EOM_BIT: { + unsigned int tot_len = pin->tx_msg.len + + pin->tx_extra_bytes; + unsigned int tx_byte_idx = pin->tx_bit / 10; + + v = !pin->tx_post_eom && tx_byte_idx == tot_len - 1; + if (tot_len > 1 && tx_byte_idx == tot_len - 2 && + tx_early_eom(pin)) { + /* Error injection: set EOM one byte early */ + v = true; + pin->tx_post_eom = true; + } else if (v && tx_no_eom(pin)) { + /* Error injection: no EOM */ + v = false; + } pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : - CEC_ST_TX_DATA_BIT_0_LOW; + CEC_ST_TX_DATA_BIT_0_LOW; break; - case 9: + } + case ACK_BIT: pin->state = CEC_ST_TX_DATA_BIT_1_LOW; break; } + if (tx_custom_bit(pin)) + pin->state = CEC_ST_TX_DATA_BIT_LOW_CUSTOM; cec_pin_low(pin); break; case CEC_ST_TX_DATA_BIT_0_LOW: case CEC_ST_TX_DATA_BIT_1_LOW: v = pin->state == CEC_ST_TX_DATA_BIT_1_LOW; - pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH : - CEC_ST_TX_DATA_BIT_0_HIGH; - is_ack_bit = pin->tx_bit % 10 == 9; - if (v && (pin->tx_bit < 4 || is_ack_bit)) + is_ack_bit = pin->tx_bit % 10 == ACK_BIT; + if (v && (pin->tx_bit < 4 || is_ack_bit)) { pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE; + } else if (!is_ack_bit && tx_short_bit(pin)) { + /* Error Injection: send an invalid (too short) bit */ + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_SHORT : + CEC_ST_TX_DATA_BIT_0_HIGH_SHORT; + } else if (!is_ack_bit && tx_long_bit(pin)) { + /* Error Injection: send an invalid (too long) bit */ + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_LONG : + CEC_ST_TX_DATA_BIT_0_HIGH_LONG; + } else { + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH : + CEC_ST_TX_DATA_BIT_0_HIGH; + } + cec_pin_high(pin); + break; + + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + pin->state = CEC_ST_TX_DATA_BIT_HIGH_CUSTOM; cec_pin_high(pin); break; case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: /* Read the CEC value at the sample time */ v = cec_pin_read(pin); - is_ack_bit = pin->tx_bit % 10 == 9; + is_ack_bit = pin->tx_bit % 10 == ACK_BIT; /* * If v == 0 and we're within the first 4 bits * of the initiator, then someone else started @@ -258,7 +573,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) * transmitter has more leading 0 bits in the * initiator). */ - if (!v && !is_ack_bit) { + if (!v && !is_ack_bit && !pin->tx_generated_poll) { pin->tx_msg.len = 0; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_ARB_LOST; @@ -267,18 +582,27 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) pin->tx_bit = 0; memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); pin->rx_msg.msg[0] = pin->tx_msg.msg[0]; - pin->rx_msg.msg[0] &= ~(1 << (7 - pin->rx_bit)); + pin->rx_msg.msg[0] &= (0xff << (8 - pin->rx_bit)); pin->rx_msg.len = 0; + pin->ts = ktime_sub_us(ts, CEC_TIM_DATA_BIT_SAMPLE); pin->state = CEC_ST_RX_DATA_POST_SAMPLE; pin->rx_bit++; break; } pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE; + if (!is_ack_bit && tx_short_bit(pin)) { + /* Error Injection: send an invalid (too short) bit */ + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT; + } else if (!is_ack_bit && tx_long_bit(pin)) { + /* Error Injection: send an invalid (too long) bit */ + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG; + } if (!is_ack_bit) break; /* Was the message ACKed? */ ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v; - if (!ack) { + if (!ack && !pin->tx_ignore_nack_until_eom && + pin->tx_bit / 10 < pin->tx_msg.len && !pin->tx_post_eom) { /* * Note: the CEC spec is ambiguous regarding * what action to take when a NACK appears @@ -295,6 +619,15 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) } break; + case CEC_ST_TX_PULSE_LOW_CUSTOM: + cec_pin_high(pin); + pin->state = CEC_ST_TX_PULSE_HIGH_CUSTOM; + break; + + case CEC_ST_TX_PULSE_HIGH_CUSTOM: + cec_pin_to_idle(pin); + break; + default: break; } @@ -322,6 +655,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) bool ack; bool bcast, for_us; u8 dest; + u8 poll; switch (pin->state) { /* Receive states */ @@ -331,24 +665,54 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) break; pin->state = CEC_ST_RX_START_BIT_HIGH; delta = ktime_us_delta(ts, pin->ts); - pin->ts = ts; /* Start bit low is too short, go back to idle */ - if (delta < CEC_TIM_START_BIT_LOW_MIN - - CEC_TIM_IDLE_SAMPLE) { + if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) { + if (!pin->rx_start_bit_low_too_short_cnt++) { + pin->rx_start_bit_low_too_short_ts = pin->ts; + pin->rx_start_bit_low_too_short_delta = delta; + } cec_pin_to_idle(pin); + break; + } + if (rx_arb_lost(pin, &poll)) { + cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf); + pin->tx_generated_poll = true; + pin->tx_extra_bytes = 0; + pin->state = CEC_ST_TX_START_BIT_HIGH; + pin->ts = ts; } break; case CEC_ST_RX_START_BIT_HIGH: v = cec_pin_read(pin); delta = ktime_us_delta(ts, pin->ts); - if (v && delta > CEC_TIM_START_BIT_TOTAL_MAX - - CEC_TIM_START_BIT_LOW_MIN) { + /* + * Unfortunately the spec does not specify when to give up + * and go to idle. We just pick TOTAL_LONG. + */ + if (v && delta > CEC_TIM_START_BIT_TOTAL_LONG) { + pin->rx_start_bit_too_long_cnt++; cec_pin_to_idle(pin); break; } if (v) break; + /* Start bit is too short, go back to idle */ + if (delta < CEC_TIM_START_BIT_TOTAL_MIN - CEC_TIM_IDLE_SAMPLE) { + if (!pin->rx_start_bit_too_short_cnt++) { + pin->rx_start_bit_too_short_ts = pin->ts; + pin->rx_start_bit_too_short_delta = delta; + } + cec_pin_to_idle(pin); + break; + } + if (rx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; + break; + } pin->state = CEC_ST_RX_DATA_SAMPLE; pin->ts = ts; pin->rx_eom = false; @@ -363,36 +727,55 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) pin->rx_msg.msg[pin->rx_bit / 10] |= v << (7 - (pin->rx_bit % 10)); break; - case 8: + case EOM_BIT: pin->rx_eom = v; pin->rx_msg.len = pin->rx_bit / 10 + 1; break; - case 9: + case ACK_BIT: break; } pin->rx_bit++; break; case CEC_ST_RX_DATA_POST_SAMPLE: - pin->state = CEC_ST_RX_DATA_HIGH; + pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW; break; - case CEC_ST_RX_DATA_HIGH: + case CEC_ST_RX_DATA_WAIT_FOR_LOW: v = cec_pin_read(pin); delta = ktime_us_delta(ts, pin->ts); - if (v && delta > CEC_TIM_DATA_BIT_TOTAL_MAX) { + /* + * Unfortunately the spec does not specify when to give up + * and go to idle. We just pick TOTAL_LONG. + */ + if (v && delta > CEC_TIM_DATA_BIT_TOTAL_LONG) { + pin->rx_data_bit_too_long_cnt++; cec_pin_to_idle(pin); break; } if (v) break; + + if (rx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; + break; + } + /* * Go to low drive state when the total bit time is * too short. */ if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { + if (!pin->rx_data_bit_too_short_cnt++) { + pin->rx_data_bit_too_short_ts = pin->ts; + pin->rx_data_bit_too_short_delta = delta; + } cec_pin_low(pin); - pin->state = CEC_ST_LOW_DRIVE; + pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; break; } pin->ts = ts; @@ -408,6 +791,11 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) /* ACK bit value */ ack = bcast ? 1 : !for_us; + if (for_us && rx_nack(pin)) { + /* Error injection: toggle the ACK bit */ + ack = !ack; + } + if (ack) { /* No need to write to the bus, just wait */ pin->state = CEC_ST_RX_ACK_HIGH_POST; @@ -434,7 +822,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) break; } pin->rx_bit++; - pin->state = CEC_ST_RX_DATA_HIGH; + pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW; break; case CEC_ST_RX_ACK_FINISH: @@ -456,6 +844,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) struct cec_adapter *adap = pin->adap; ktime_t ts; s32 delta; + u32 usecs; ts = ktime_get(); if (ktime_to_ns(pin->timer_ts)) { @@ -503,13 +892,27 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) /* Transmit states */ case CEC_ST_TX_WAIT_FOR_HIGH: case CEC_ST_TX_START_BIT_LOW: - case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: - case CEC_ST_TX_DATA_BIT_0_HIGH: - case CEC_ST_TX_DATA_BIT_1_HIGH: case CEC_ST_TX_START_BIT_HIGH: + case CEC_ST_TX_START_BIT_HIGH_SHORT: + case CEC_ST_TX_START_BIT_HIGH_LONG: + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: case CEC_ST_TX_DATA_BIT_0_LOW: + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_0_HIGH_LONG: case CEC_ST_TX_DATA_BIT_1_LOW: + case CEC_ST_TX_DATA_BIT_1_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_LONG: case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG: + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + case CEC_ST_TX_PULSE_LOW_CUSTOM: + case CEC_ST_TX_PULSE_HIGH_CUSTOM: cec_pin_tx_states(pin, ts); break; @@ -518,7 +921,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) case CEC_ST_RX_START_BIT_HIGH: case CEC_ST_RX_DATA_SAMPLE: case CEC_ST_RX_DATA_POST_SAMPLE: - case CEC_ST_RX_DATA_HIGH: + case CEC_ST_RX_DATA_WAIT_FOR_LOW: case CEC_ST_RX_ACK_LOW: case CEC_ST_RX_ACK_LOW_POST: case CEC_ST_RX_ACK_HIGH_POST: @@ -545,7 +948,10 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (delta / CEC_TIM_DATA_BIT_TOTAL > pin->tx_signal_free_time) { pin->tx_nacked = false; - pin->state = CEC_ST_TX_START_BIT_LOW; + if (tx_custom_start(pin)) + pin->state = CEC_ST_TX_START_BIT_LOW_CUSTOM; + else + pin->state = CEC_ST_TX_START_BIT_LOW; /* Generate start bit */ cec_pin_low(pin); break; @@ -555,6 +961,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) pin->state = CEC_ST_TX_WAIT; break; } + if (pin->tx_custom_pulse && pin->state == CEC_ST_IDLE) { + pin->tx_custom_pulse = false; + /* Generate custom pulse */ + cec_pin_low(pin); + pin->state = CEC_ST_TX_PULSE_LOW_CUSTOM; + break; + } if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL || pin->enable_irq_failed || adap->is_configuring || adap->is_configured || adap->monitor_all_cnt) @@ -565,21 +978,40 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) wake_up_interruptible(&pin->kthread_waitq); return HRTIMER_NORESTART; - case CEC_ST_LOW_DRIVE: + case CEC_ST_TX_LOW_DRIVE: + case CEC_ST_RX_LOW_DRIVE: + cec_pin_high(pin); cec_pin_to_idle(pin); break; default: break; } - if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) { + + switch (pin->state) { + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + case CEC_ST_TX_PULSE_LOW_CUSTOM: + usecs = pin->tx_custom_low_usecs; + break; + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + case CEC_ST_TX_PULSE_HIGH_CUSTOM: + usecs = pin->tx_custom_high_usecs; + break; + default: + usecs = states[pin->state].usecs; + break; + } + + if (!adap->monitor_pin_cnt || usecs <= 150) { pin->wait_usecs = 0; - pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs); + pin->timer_ts = ktime_add_us(ts, usecs); hrtimer_forward_now(timer, - ns_to_ktime(states[pin->state].usecs * 1000)); + ns_to_ktime(usecs * 1000)); return HRTIMER_RESTART; } - pin->wait_usecs = states[pin->state].usecs - 100; + pin->wait_usecs = usecs - 100; pin->timer_ts = ktime_add_us(ts, 100); hrtimer_forward_now(timer, ns_to_ktime(100000)); return HRTIMER_RESTART; @@ -596,12 +1028,25 @@ static int cec_pin_thread_func(void *_adap) pin->work_rx_msg.len || pin->work_tx_status || atomic_read(&pin->work_irq_change) || - atomic_read(&pin->work_pin_events)); + atomic_read(&pin->work_pin_num_events)); if (pin->work_rx_msg.len) { - cec_received_msg_ts(adap, &pin->work_rx_msg, + struct cec_msg *msg = &pin->work_rx_msg; + + if (msg->len > 1 && msg->len < CEC_MAX_MSG_SIZE && + rx_add_byte(pin)) { + /* Error injection: add byte to the message */ + msg->msg[msg->len++] = 0x55; + } + if (msg->len > 2 && rx_remove_byte(pin)) { + /* Error injection: remove byte from message */ + msg->len--; + } + if (msg->len > CEC_MAX_MSG_SIZE) + msg->len = CEC_MAX_MSG_SIZE; + cec_received_msg_ts(adap, msg, ns_to_ktime(pin->work_rx_msg.rx_ts)); - pin->work_rx_msg.len = 0; + msg->len = 0; } if (pin->work_tx_status) { unsigned int tx_status = pin->work_tx_status; @@ -611,14 +1056,16 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } - while (atomic_read(&pin->work_pin_events)) { + while (atomic_read(&pin->work_pin_num_events)) { unsigned int idx = pin->work_pin_events_rd; + u8 v = pin->work_pin_events[idx]; cec_queue_pin_cec_event(adap, - pin->work_pin_is_high[idx], + v & CEC_PIN_EVENT_FL_IS_HIGH, + v & CEC_PIN_EVENT_FL_DROPPED, pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS; - atomic_dec(&pin->work_pin_events); + atomic_dec(&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change, @@ -654,8 +1101,9 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) pin->enabled = enable; if (enable) { - atomic_set(&pin->work_pin_events, 0); + atomic_set(&pin->work_pin_num_events, 0); pin->work_pin_events_rd = pin->work_pin_events_wr = 0; + pin->work_pin_events_dropped = false; cec_pin_read(pin); cec_pin_to_idle(pin); pin->tx_msg.len = 0; @@ -692,23 +1140,37 @@ static int cec_pin_adap_log_addr(struct cec_adapter *adap, u8 log_addr) return 0; } +void cec_pin_start_timer(struct cec_pin *pin) +{ + if (pin->state != CEC_ST_RX_IRQ) + return; + + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); + pin->ops->disable_irq(pin->adap); + cec_pin_high(pin); + cec_pin_to_idle(pin); + hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); +} + static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg) { struct cec_pin *pin = adap->pin; pin->tx_signal_free_time = signal_free_time; + pin->tx_extra_bytes = 0; pin->tx_msg = *msg; + if (msg->len > 1) { + /* Error injection: add byte to the message */ + pin->tx_extra_bytes = tx_add_bytes(pin); + } + if (msg->len > 2 && tx_remove_byte(pin)) { + /* Error injection: remove byte from the message */ + pin->tx_msg.len--; + } pin->work_tx_status = 0; pin->tx_bit = 0; - if (pin->state == CEC_ST_RX_IRQ) { - atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); - pin->ops->disable_irq(adap); - cec_pin_high(pin); - cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, ns_to_ktime(0), - HRTIMER_MODE_REL); - } + cec_pin_start_timer(pin); return 0; } @@ -717,10 +1179,12 @@ static void cec_pin_adap_status(struct cec_adapter *adap, { struct cec_pin *pin = adap->pin; - seq_printf(file, "state: %s\n", states[pin->state].name); - seq_printf(file, "tx_bit: %d\n", pin->tx_bit); - seq_printf(file, "rx_bit: %d\n", pin->rx_bit); + seq_printf(file, "state: %s\n", states[pin->state].name); + seq_printf(file, "tx_bit: %d\n", pin->tx_bit); + seq_printf(file, "rx_bit: %d\n", pin->rx_bit); seq_printf(file, "cec pin: %d\n", pin->ops->read(adap)); + seq_printf(file, "cec pin events dropped: %u\n", + pin->work_pin_events_dropped_cnt); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); if (pin->timer_100ms_overruns) { seq_printf(file, "timer overruns > 100ms: %u of %u\n", @@ -732,11 +1196,45 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "avg timer overrun: %u usecs\n", pin->timer_sum_overrun / pin->timer_100ms_overruns); } + if (pin->rx_start_bit_low_too_short_cnt) + seq_printf(file, + "rx start bit low too short: %u (delta %u, ts %llu)\n", + pin->rx_start_bit_low_too_short_cnt, + pin->rx_start_bit_low_too_short_delta, + pin->rx_start_bit_low_too_short_ts); + if (pin->rx_start_bit_too_short_cnt) + seq_printf(file, + "rx start bit too short: %u (delta %u, ts %llu)\n", + pin->rx_start_bit_too_short_cnt, + pin->rx_start_bit_too_short_delta, + pin->rx_start_bit_too_short_ts); + if (pin->rx_start_bit_too_long_cnt) + seq_printf(file, "rx start bit too long: %u\n", + pin->rx_start_bit_too_long_cnt); + if (pin->rx_data_bit_too_short_cnt) + seq_printf(file, + "rx data bit too short: %u (delta %u, ts %llu)\n", + pin->rx_data_bit_too_short_cnt, + pin->rx_data_bit_too_short_delta, + pin->rx_data_bit_too_short_ts); + if (pin->rx_data_bit_too_long_cnt) + seq_printf(file, "rx data bit too long: %u\n", + pin->rx_data_bit_too_long_cnt); + seq_printf(file, "rx initiated low drive: %u\n", pin->rx_low_drive_cnt); + seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt); + pin->work_pin_events_dropped_cnt = 0; pin->timer_cnt = 0; pin->timer_100ms_overruns = 0; pin->timer_300ms_overruns = 0; pin->timer_max_overrun = 0; pin->timer_sum_overrun = 0; + pin->rx_start_bit_low_too_short_cnt = 0; + pin->rx_start_bit_too_short_cnt = 0; + pin->rx_start_bit_too_long_cnt = 0; + pin->rx_data_bit_too_short_cnt = 0; + pin->rx_data_bit_too_long_cnt = 0; + pin->rx_low_drive_cnt = 0; + pin->tx_low_drive_cnt = 0; if (pin->ops->status) pin->ops->status(adap, file); } @@ -778,6 +1276,10 @@ static const struct cec_adap_ops cec_pin_adap_ops = { .adap_transmit = cec_pin_adap_transmit, .adap_status = cec_pin_adap_status, .adap_free = cec_pin_adap_free, +#ifdef CONFIG_CEC_PIN_ERROR_INJ + .error_inj_parse_line = cec_pin_error_inj_parse_line, + .error_inj_show = cec_pin_error_inj_show, +#endif }; struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, @@ -792,6 +1294,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pin->timer.function = cec_pin_timer; init_waitqueue_head(&pin->kthread_waitq); + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index daf597643af8..804e38f849c7 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-priv.h - HDMI Consumer Electronics Control internal header * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _CEC_PRIV_H diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index c5c827e11b64..b5dcc6d1fe90 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, cb->p = buffer; cb->offset_in_common = buffer - (u8 *) common_buffer; - cb->phys = common_buffer_phys + cb->offset_in_common; + if (common_buffer_phys) + cb->phys = common_buffer_phys + cb->offset_in_common; return cb; } @@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params, /* alloc common buffer */ dev->common_buffer_size = params->buffer_size * params->num_buffers; - dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, - &dev->common_buffer_phys, - GFP_KERNEL | GFP_DMA); - if (!dev->common_buffer) { + if (params->usb_device) + buffer = kzalloc(dev->common_buffer_size, GFP_KERNEL); + else + buffer = dma_alloc_coherent(params->device, + dev->common_buffer_size, + &dev->common_buffer_phys, + GFP_KERNEL | GFP_DMA); + if (!buffer) { smscore_unregister_device(dev); return -ENOMEM; } + dev->common_buffer = buffer; /* prepare dma buffers */ - for (buffer = dev->common_buffer; - dev->num_buffers < params->num_buffers; + for (; dev->num_buffers < params->num_buffers; dev->num_buffers++, buffer += params->buffer_size) { struct smscore_buffer_t *cb; @@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params, dev->board_id = SMS_BOARD_UNKNOWN; dev->context = params->context; dev->device = params->device; + dev->usb_device = params->usb_device; dev->setmode_handler = params->setmode_handler; dev->detectmode_handler = params->detectmode_handler; dev->sendrequest_handler = params->sendrequest_handler; @@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev) pr_debug("freed %d buffers\n", num_buffers); - if (coredev->common_buffer) - dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, coredev->common_buffer_phys); - + if (coredev->common_buffer) { + if (coredev->usb_device) + kfree(coredev->common_buffer); + else + dma_free_coherent(coredev->device, + coredev->common_buffer_size, + coredev->common_buffer, + coredev->common_buffer_phys); + } kfree(coredev->fw_buf); list_del(&coredev->entry); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 4cc39e4a8318..134c69f7ea7b 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -134,6 +134,7 @@ struct smscore_buffer_t { struct smsdevice_params_t { struct device *device; + struct usb_device *usb_device; int buffer_size; int num_buffers; @@ -176,6 +177,7 @@ struct smscore_device_t { void *context; struct device *device; + struct usb_device *usb_device; char devpath[32]; unsigned long device_flags; diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c index 43180204fab2..3a3dc23c560c 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-tpg-colors.c - A table that converts colors to various colorspaces * @@ -20,19 +21,6 @@ * in order to preserve precision. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/videodev2.h> diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 2b3d4ac4dfd4..37632bc524d4 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-tpg-core.c - Test Pattern Generator * @@ -5,19 +6,6 @@ * vivi.c source for the copyright information of those functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> @@ -1155,13 +1143,13 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_NV24: buf[0][offset] = r_y_h; buf[1][2 * offset] = g_u_s; - buf[1][2 * offset + 1] = b_v; + buf[1][(2 * offset + 1) % 8] = b_v; break; case V4L2_PIX_FMT_NV42: buf[0][offset] = r_y_h; buf[1][2 * offset] = b_v; - buf[1][2 * offset + 1] = g_u_s; + buf[1][(2 * offset + 1) %8] = g_u_s; break; case V4L2_PIX_FMT_YUYV: diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index debe35fc66b4..d3f7bb33a54d 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1696,6 +1696,15 @@ static void __vb2_queue_cancel(struct vb2_queue *q) for (i = 0; i < q->num_buffers; ++i) { struct vb2_buffer *vb = q->bufs[i]; + if (vb->state == VB2_BUF_STATE_PREPARED || + vb->state == VB2_BUF_STATE_QUEUED) { + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, finish, + vb->planes[plane].mem_priv); + } + if (vb->state != VB2_BUF_STATE_DEQUEUED) { vb->state = VB2_BUF_STATE_PREPARED; call_void_vb_qop(vb, buf_finish, vb); diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 3a7c80cd1a17..359fb9804d16 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]), size + offset); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 204d0f6c678d..97365a863519 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1254,8 +1254,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, ca->pub->slot_ts_enable(ca->pub, slot); sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); - pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", - ca->dvbdev->adapter->num); + pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + ca->dvbdev->adapter->num); break; case DVB_CA_SLOTSTATE_RUNNING: diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index a7ed16e0841d..21a7d4b47e1a 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2294,7 +2294,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); @@ -2328,7 +2328,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 60e9c2ba26be..787fe06df217 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -24,6 +24,7 @@ #include <linux/string.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/i2c.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> @@ -941,6 +942,55 @@ out: return err; } +#if IS_ENABLED(CONFIG_I2C) +struct i2c_client *dvb_module_probe(const char *module_name, + const char *name, + struct i2c_adapter *adap, + unsigned char addr, + void *platform_data) +{ + struct i2c_client *client; + struct i2c_board_info *board_info; + + board_info = kzalloc(sizeof(*board_info), GFP_KERNEL); + if (!board_info) + return NULL; + + if (name) + strlcpy(board_info->type, name, I2C_NAME_SIZE); + else + strlcpy(board_info->type, module_name, I2C_NAME_SIZE); + + board_info->addr = addr; + board_info->platform_data = platform_data; + request_module(module_name); + client = i2c_new_device(adap, board_info); + if (client == NULL || client->dev.driver == NULL) { + kfree(board_info); + return NULL; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + client = NULL; + } + + kfree(board_info); + return client; +} +EXPORT_SYMBOL_GPL(dvb_module_probe); + +void dvb_module_release(struct i2c_client *client) +{ + if (!client) + return; + + module_put(client->dev.driver->owner); + i2c_unregister_device(client); +} +EXPORT_SYMBOL_GPL(dvb_module_release); +#endif + static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct dvb_device *dvbdev = dev_get_drvdata(dev); diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index d17722eb4456..0712069fd9fe 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -462,7 +462,7 @@ config DVB_TDA10048 config DVB_AF9013 tristate "Afatech AF9013 demodulator" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -546,6 +546,8 @@ config DVB_GP8PSK_FE depends on DVB_CORE default DVB_USB_GP8PSK +source "drivers/media/dvb-frontends/cxd2880/Kconfig" + comment "DVB-C (cable) frontends" depends on DVB_CORE @@ -822,13 +824,6 @@ config DVB_A8293 depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT -config DVB_SP2 - tristate "CIMaX SP2" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - CIMaX SP2/SP2HF Common Interface module. - config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C @@ -904,6 +899,27 @@ config DVB_HELENE help Say Y when you want to support this frontend. +comment "Common Interface (EN50221) controller drivers" + depends on DVB_CORE + +config DVB_CXD2099 + tristate "CXD2099AR Common Interface driver" + depends on DVB_CORE && I2C + select REGMAP_I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A driver for the CI controller currently found mostly on + Digital Devices DuoFlex CI (single) addon modules. + + Say Y when you want to support these devices. + +config DVB_SP2 + tristate "CIMaX SP2" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + CIMaX SP2/SP2HF Common Interface module. + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 4be59fed4536..67a783fd5ed0 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -129,3 +129,5 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o obj-$(CONFIG_DVB_HELENE) += helene.o obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o +obj-$(CONFIG_DVB_CXD2099) += cxd2099.o +obj-$(CONFIG_DVB_CXD2880) += cxd2880/ diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b8f3ebfc3e27..482bce49819a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -23,6 +23,7 @@ struct af9013_state { struct i2c_client *client; struct regmap *regmap; + struct i2c_mux_core *muxc; struct dvb_frontend fe; u32 clk; u8 tuner; @@ -33,20 +34,20 @@ struct af9013_state { u8 api_version[4]; u8 gpio[4]; - /* tuner/demod RF and IF AGC limits used for signal strength calc */ - u8 signal_strength_en, rf_50, rf_80, if_50, if_80; - u16 signal_strength; - u32 ber; - u32 ucblocks; - u16 snr; u32 bandwidth_hz; enum fe_status fe_status; + /* RF and IF AGC limits used for signal strength calc */ + u8 strength_en, rf_agc_50, rf_agc_80, if_agc_50, if_agc_80; unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; + unsigned long strength_jiffies; + unsigned long cnr_jiffies; + unsigned long ber_ucb_jiffies; + u16 dvbv3_snr; + u16 dvbv3_strength; + u32 dvbv3_ber; + u32 dvbv3_ucblocks; bool first_tune; - bool i2c_gate_state; - unsigned int statistics_step:3; - struct delayed_work statistics_work; }; static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) @@ -101,232 +102,6 @@ err: return ret; } -static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* reset and start BER counter */ - ret = regmap_update_bits(state->regmap, 0xd391, 0x10, 0x10); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - unsigned int utmp; - u8 buf[5]; - - dev_dbg(&client->dev, "\n"); - - /* check if error bit count is ready */ - ret = regmap_read(state->regmap, 0xd391, &utmp); - if (ret) - goto err; - - if (!((utmp >> 4) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - ret = regmap_bulk_read(state->regmap, 0xd387, buf, 5); - if (ret) - goto err; - - state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - state->ucblocks += (buf[4] << 8) | buf[3]; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* start SNR meas */ - ret = regmap_update_bits(state->regmap, 0xd2e1, 0x08, 0x08); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, len; - unsigned int utmp; - u8 buf[3]; - u32 snr_val; - const struct af9013_snr *uninitialized_var(snr_lut); - - dev_dbg(&client->dev, "\n"); - - /* check if SNR ready */ - ret = regmap_read(state->regmap, 0xd2e1, &utmp); - if (ret) - goto err; - - if (!((utmp >> 3) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - /* read value */ - ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); - if (ret) - goto err; - - snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - - /* read current modulation */ - ret = regmap_read(state->regmap, 0xd3c1, &utmp); - if (ret) - goto err; - - switch ((utmp >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_lut); - snr_lut = qpsk_snr_lut; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_lut); - snr_lut = qam16_snr_lut; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_lut); - snr_lut = qam64_snr_lut; - break; - default: - goto err; - } - - for (i = 0; i < len; i++) { - utmp = snr_lut[i].snr; - - if (snr_val < snr_lut[i].val) - break; - } - state->snr = utmp * 10; /* dB/10 */ - - c->cnr.stat[0].svalue = 1000 * utmp; - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_signal_strength(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret = 0; - u8 buf[2], rf_gain, if_gain; - int signal_strength; - - dev_dbg(&client->dev, "\n"); - - if (!state->signal_strength_en) - return 0; - - ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); - if (ret) - goto err; - - rf_gain = buf[0]; - if_gain = buf[1]; - - signal_strength = (0xffff / \ - (9 * (state->rf_50 + state->if_50) - \ - 11 * (state->rf_80 + state->if_80))) * \ - (10 * (rf_gain + if_gain) - \ - 11 * (state->rf_80 + state->if_80)); - if (signal_strength < 0) - signal_strength = 0; - else if (signal_strength > 0xffff) - signal_strength = 0xffff; - - state->signal_strength = signal_strength; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static void af9013_statistics_work(struct work_struct *work) -{ - struct af9013_state *state = container_of(work, - struct af9013_state, statistics_work.work); - unsigned int next_msec; - - /* update only signal strength when demod is not locked */ - if (!(state->fe_status & FE_HAS_LOCK)) { - state->statistics_step = 0; - state->ber = 0; - state->snr = 0; - } - - switch (state->statistics_step) { - default: - state->statistics_step = 0; - /* fall-through */ - case 0: - af9013_statistics_signal_strength(&state->fe); - state->statistics_step++; - next_msec = 300; - break; - case 1: - af9013_statistics_snr_start(&state->fe); - state->statistics_step++; - next_msec = 200; - break; - case 2: - af9013_statistics_ber_unc_start(&state->fe); - state->statistics_step++; - next_msec = 1000; - break; - case 3: - af9013_statistics_snr_result(&state->fe); - state->statistics_step++; - next_msec = 400; - break; - case 4: - af9013_statistics_ber_unc_result(&state->fe); - state->statistics_step++; - next_msec = 100; - break; - } - - schedule_delayed_work(&state->statistics_work, - msecs_to_jiffies(next_msec)); -} - static int af9013_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *fesettings) { @@ -751,46 +526,273 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; - int ret; - unsigned int utmp; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, stmp1; + unsigned int utmp, utmp1, utmp2, utmp3, utmp4; + u8 buf[7]; + + dev_dbg(&client->dev, "\n"); /* * Return status from the cache if it is younger than 2000ms with the * exception of last tune is done during 4000ms. */ - if (time_is_after_jiffies( - state->read_status_jiffies + msecs_to_jiffies(2000)) && - time_is_before_jiffies( - state->set_frontend_jiffies + msecs_to_jiffies(4000)) - ) { - *status = state->fe_status; - return 0; + if (time_is_after_jiffies(state->read_status_jiffies + msecs_to_jiffies(2000)) && + time_is_before_jiffies(state->set_frontend_jiffies + msecs_to_jiffies(4000))) { + *status = state->fe_status; } else { - *status = 0; + /* MPEG2 lock */ + ret = regmap_read(state->regmap, 0xd507, &utmp); + if (ret) + goto err; + + if ((utmp >> 6) & 0x01) { + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else { + /* TPS lock */ + ret = regmap_read(state->regmap, 0xd330, &utmp); + if (ret) + goto err; + + if ((utmp >> 3) & 0x01) + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + else + utmp1 = 0; + } + + dev_dbg(&client->dev, "fe_status %02x\n", utmp1); + + state->read_status_jiffies = jiffies; + + state->fe_status = utmp1; + *status = utmp1; } - /* MPEG2 lock */ - ret = regmap_read(state->regmap, 0xd507, &utmp); - if (ret) - goto err; + /* Signal strength */ + switch (state->strength_en) { + case 0: + /* Check if we support signal strength */ + ret = regmap_read(state->regmap, 0x9bee, &utmp); + if (ret) + goto err; - if ((utmp >> 6) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; + if ((utmp >> 0) & 0x01) { + /* Read agc values for signal strength estimation */ + ret = regmap_read(state->regmap, 0x9bbd, &utmp1); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9bd0, &utmp2); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be2, &utmp3); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be4, &utmp4); + if (ret) + goto err; - if (!*status) { - /* TPS lock */ - ret = regmap_read(state->regmap, 0xd330, &utmp); + state->rf_agc_50 = utmp1; + state->rf_agc_80 = utmp2; + state->if_agc_50 = utmp3; + state->if_agc_80 = utmp4; + dev_dbg(&client->dev, + "rf_agc_50 %u, rf_agc_80 %u, if_agc_50 %u, if_agc_80 %u\n", + utmp1, utmp2, utmp3, utmp4); + + state->strength_en = 1; + } else { + /* Signal strength is not supported */ + state->strength_en = 2; + break; + } + /* Fall through */ + case 1: + if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000))) + break; + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); if (ret) goto err; - if ((utmp >> 3) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; + /* + * Construct line equation from tuner dependent -80/-50 dBm agc + * limits and use it to map current agc value to dBm estimate + */ + #define agc_gain (buf[0] + buf[1]) + #define agc_gain_50dbm (state->rf_agc_50 + state->if_agc_50) + #define agc_gain_80dbm (state->rf_agc_80 + state->if_agc_80) + stmp1 = 30000 * (agc_gain - agc_gain_80dbm) / + (agc_gain_50dbm - agc_gain_80dbm) - 80000; + + dev_dbg(&client->dev, + "strength %d, agc_gain %d, agc_gain_50dbm %d, agc_gain_80dbm %d\n", + stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm); + + state->strength_jiffies = jiffies; + /* Convert [-90, -30] dBm to [0x0000, 0xffff] for dvbv3 */ + utmp1 = clamp(stmp1 + 90000, 0, 60000); + state->dvbv3_strength = div_u64((u64)utmp1 * 0xffff, 60000); + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = stmp1; + break; + default: + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; } - state->fe_status = *status; - state->read_status_jiffies = jiffies; + /* CNR */ + switch (state->fe_status & FE_HAS_VITERBI) { + case FE_HAS_VITERBI: + if (time_is_after_jiffies(state->cnr_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if cnr ready */ + ret = regmap_read(state->regmap, 0xd2e1, &utmp); + if (ret) + goto err; + + if (!((utmp >> 3) & 0x01)) { + dev_dbg(&client->dev, "cnr not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); + if (ret) + goto err; + + utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; + + /* Read current modulation */ + ret = regmap_read(state->regmap, 0xd3c1, &utmp); + if (ret) + goto err; + + switch ((utmp >> 6) & 3) { + case 0: + /* + * QPSK + * CNR[dB] 13 * -log10((1690000 - value) / value) + 2.6 + * value [653799, 1689999], 2.6 / 13 = 3355443 + */ + utmp1 = clamp(utmp1, 653799U, 1689999U); + utmp1 = ((u64)(intlog10(utmp1) + - intlog10(1690000 - utmp1) + + 3355443) * 13 * 1000) >> 24; + break; + case 1: + /* + * QAM-16 + * CNR[dB] 6 * log10((value - 370000) / (828000 - value)) + 15.7 + * value [371105, 827999], 15.7 / 6 = 43900382 + */ + utmp1 = clamp(utmp1, 371105U, 827999U); + utmp1 = ((u64)(intlog10(utmp1 - 370000) + - intlog10(828000 - utmp1) + + 43900382) * 6 * 1000) >> 24; + break; + case 2: + /* + * QAM-64 + * CNR[dB] 8 * log10((value - 193000) / (425000 - value)) + 23.8 + * value [193246, 424999], 23.8 / 8 = 49912218 + */ + utmp1 = clamp(utmp1, 193246U, 424999U); + utmp1 = ((u64)(intlog10(utmp1 - 193000) + - intlog10(425000 - utmp1) + + 49912218) * 8 * 1000) >> 24; + break; + default: + dev_dbg(&client->dev, "invalid modulation %u\n", + (utmp >> 6) & 3); + utmp1 = 0; + break; + } + + dev_dbg(&client->dev, "cnr %u\n", utmp1); + + state->cnr_jiffies = jiffies; + state->dvbv3_snr = utmp1 / 100; + + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = utmp1; + break; + default: + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + + /* BER / PER */ + switch (state->fe_status & FE_HAS_SYNC) { + case FE_HAS_SYNC: + if (time_is_after_jiffies(state->ber_ucb_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if ber / ucb is ready */ + ret = regmap_read(state->regmap, 0xd391, &utmp); + if (ret) + goto err; + + if (!((utmp >> 4) & 0x01)) { + dev_dbg(&client->dev, "ber not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd385, buf, 7); + if (ret) + goto err; + + utmp1 = buf[4] << 16 | buf[3] << 8 | buf[2] << 0; + utmp2 = (buf[1] << 8 | buf[0] << 0) * 204 * 8; + utmp3 = buf[6] << 8 | buf[5] << 0; + utmp4 = buf[1] << 8 | buf[0] << 0; + + /* Use 10000 TS packets for measure */ + if (utmp4 != 10000) { + buf[0] = (10000 >> 0) & 0xff; + buf[1] = (10000 >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); + if (ret) + goto err; + } + + /* Reset ber / ucb counter */ + ret = regmap_update_bits(state->regmap, 0xd391, 0x20, 0x20); + if (ret) + goto err; + + dev_dbg(&client->dev, "post_bit_error %u, post_bit_count %u\n", + utmp1, utmp2); + dev_dbg(&client->dev, "block_error %u, block_count %u\n", + utmp3, utmp4); + + state->ber_ucb_jiffies = jiffies; + state->dvbv3_ber = utmp1; + state->dvbv3_ucblocks += utmp3; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += utmp1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += utmp2; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += utmp3; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += utmp4; + break; + default: + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } return 0; err: @@ -801,28 +803,36 @@ err: static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9013_state *state = fe->demodulator_priv; - *snr = state->snr; + + *snr = state->dvbv3_snr; + return 0; } static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct af9013_state *state = fe->demodulator_priv; - *strength = state->signal_strength; + + *strength = state->dvbv3_strength; + return 0; } static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9013_state *state = fe->demodulator_priv; - *ber = state->ber; + + *ber = state->dvbv3_ber; + return 0; } static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct af9013_state *state = fe->demodulator_priv; - *ucblocks = state->ucblocks; + + *ucblocks = state->dvbv3_ucblocks; + return 0; } @@ -833,7 +843,7 @@ static int af9013_init(struct dvb_frontend *fe) int ret, i, len; unsigned int utmp; u8 buf[3]; - const struct af9013_reg_bit *init; + const struct af9013_reg_mask_val *tab; dev_dbg(&client->dev, "\n"); @@ -888,72 +898,66 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* load OFSM settings */ - dev_dbg(&client->dev, "load ofsm settings\n"); - len = ARRAY_SIZE(ofsm_init); - init = ofsm_init; + /* Demod core settings */ + dev_dbg(&client->dev, "load demod core settings\n"); + len = ARRAY_SIZE(demod_init_tab); + tab = demod_init_tab; for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, + tab[i].val); if (ret) goto err; } - /* load tuner specific settings */ + /* Demod tuner specific settings */ dev_dbg(&client->dev, "load tuner specific settings\n"); switch (state->tuner) { case AF9013_TUNER_MXL5003D: - len = ARRAY_SIZE(tuner_init_mxl5003d); - init = tuner_init_mxl5003d; + len = ARRAY_SIZE(tuner_init_tab_mxl5003d); + tab = tuner_init_tab_mxl5003d; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - len = ARRAY_SIZE(tuner_init_mxl5005); - init = tuner_init_mxl5005; + len = ARRAY_SIZE(tuner_init_tab_mxl5005); + tab = tuner_init_tab_mxl5005; break; case AF9013_TUNER_ENV77H11D5: - len = ARRAY_SIZE(tuner_init_env77h11d5); - init = tuner_init_env77h11d5; + len = ARRAY_SIZE(tuner_init_tab_env77h11d5); + tab = tuner_init_tab_env77h11d5; break; case AF9013_TUNER_MT2060: - len = ARRAY_SIZE(tuner_init_mt2060); - init = tuner_init_mt2060; + len = ARRAY_SIZE(tuner_init_tab_mt2060); + tab = tuner_init_tab_mt2060; break; case AF9013_TUNER_MC44S803: - len = ARRAY_SIZE(tuner_init_mc44s803); - init = tuner_init_mc44s803; + len = ARRAY_SIZE(tuner_init_tab_mc44s803); + tab = tuner_init_tab_mc44s803; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - len = ARRAY_SIZE(tuner_init_qt1010); - init = tuner_init_qt1010; + len = ARRAY_SIZE(tuner_init_tab_qt1010); + tab = tuner_init_tab_qt1010; break; case AF9013_TUNER_MT2060_2: - len = ARRAY_SIZE(tuner_init_mt2060_2); - init = tuner_init_mt2060_2; + len = ARRAY_SIZE(tuner_init_tab_mt2060_2); + tab = tuner_init_tab_mt2060_2; break; case AF9013_TUNER_TDA18271: case AF9013_TUNER_TDA18218: - len = ARRAY_SIZE(tuner_init_tda18271); - init = tuner_init_tda18271; + len = ARRAY_SIZE(tuner_init_tab_tda18271); + tab = tuner_init_tab_tda18271; break; case AF9013_TUNER_UNKNOWN: default: - len = ARRAY_SIZE(tuner_init_unknown); - init = tuner_init_unknown; + len = ARRAY_SIZE(tuner_init_tab_unknown); + tab = tuner_init_tab_unknown; break; } for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, + tab[i].val); if (ret) goto err; } @@ -972,50 +976,7 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* check if we support signal strength */ - if (!state->signal_strength_en) { - ret = regmap_read(state->regmap, 0x9bee, &utmp); - if (ret) - goto err; - - state->signal_strength_en = (utmp >> 0) & 0x01; - } - - /* read values needed for signal strength calculation */ - if (state->signal_strength_en && !state->rf_50) { - ret = regmap_bulk_read(state->regmap, 0x9bbd, &state->rf_50, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9bd0, &state->rf_80, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9be2, &state->if_50, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9be4, &state->if_80, 1); - if (ret) - goto err; - } - - /* SNR */ - ret = regmap_write(state->regmap, 0xd2e2, 0x01); - if (ret) - goto err; - - /* BER / UCB */ - buf[0] = (10000 >> 0) & 0xff; - buf[1] = (10000 >> 8) & 0xff; - ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); - if (ret) - goto err; - - /* enable FEC monitor */ - ret = regmap_update_bits(state->regmap, 0xd392, 0x02, 0x02); - if (ret) - goto err; - state->first_tune = true; - schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400)); return 0; err: @@ -1032,9 +993,6 @@ static int af9013_sleep(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); - /* stop statistics polling */ - cancel_delayed_work_sync(&state->statistics_work); - /* disable lock led */ ret = regmap_update_bits(state->regmap, 0xd730, 0x01, 0x00); if (ret) @@ -1072,45 +1030,6 @@ err: return ret; } -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "enable %d\n", enable); - - /* gate already open or close */ - if (state->i2c_gate_state == enable) - return 0; - - if (state->ts_mode == AF9013_TS_MODE_USB) - ret = regmap_update_bits(state->regmap, 0xd417, 0x08, - enable << 3); - else - ret = regmap_update_bits(state->regmap, 0xd607, 0x04, - enable << 2); - if (ret) - goto err; - - state->i2c_gate_state = enable; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "\n"); - - i2c_unregister_device(client); -} - static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) @@ -1213,40 +1132,6 @@ err: return ret; } -/* - * XXX: That is wrapper to af9013_probe() via driver core in order to provide - * proper I2C client for legacy media attach binding. - * New users must use I2C client binding directly! - */ -struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c) -{ - struct i2c_client *client; - struct i2c_board_info board_info; - struct af9013_platform_data pdata; - - pdata.clk = config->clock; - pdata.tuner = config->tuner; - pdata.if_frequency = config->if_frequency; - pdata.ts_mode = config->ts_mode; - pdata.ts_output_pin = 7; - pdata.spec_inv = config->spec_inv; - memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version)); - memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio)); - pdata.attach_in_use = true; - - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "af9013", sizeof(board_info.type)); - board_info.addr = config->i2c_addr; - board_info.platform_data = &pdata; - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) - return NULL; - - return pdata.get_dvb_frontend(client); -} -EXPORT_SYMBOL(af9013_attach); - static const struct dvb_frontend_ops af9013_ops = { .delsys = { SYS_DVBT }, .info = { @@ -1272,8 +1157,6 @@ static const struct dvb_frontend_ops af9013_ops = { FE_CAN_MUTE_TS }, - .release = af9013_release, - .init = af9013_init, .sleep = af9013_sleep, @@ -1286,10 +1169,58 @@ static const struct dvb_frontend_ops af9013_ops = { .read_signal_strength = af9013_read_signal_strength, .read_ber = af9013_read_ber, .read_ucblocks = af9013_read_ucblocks, - - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, }; +static int af9013_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "onoff %d\n", onoff); + + ret = regmap_update_bits(state->regmap, 0xd503, 0x01, onoff); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, + int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + u8 buf[2]; + + dev_dbg(&client->dev, "index %d, pid %04x, onoff %d\n", + index, pid, onoff); + + if (pid > 0x1fff) { + /* 0x2000 is kernel virtual pid for whole ts (all pids) */ + ret = 0; + goto err; + } + + buf[0] = (pid >> 0) & 0xff; + buf[1] = (pid >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd505, buf, 2); + if (ret) + goto err; + ret = regmap_write(state->regmap, 0xd504, onoff << 5 | index << 0); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) { struct af9013_state *state = i2c_get_clientdata(client); @@ -1299,9 +1230,65 @@ static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) return &state->fe; } +static struct i2c_adapter *af9013_get_i2c_adapter(struct i2c_client *client) +{ + struct af9013_state *state = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return state->muxc->adapter[0]; +} + +/* + * XXX: Hackish solution. We use virtual register, reg bit 16, to carry info + * about i2c adapter locking. Own locking is needed because i2c mux call has + * already locked i2c adapter. + */ +static int af9013_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x08); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x04); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x00); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x00); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + /* Own I2C access routines needed for regmap as chip uses extra command byte */ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, - const u8 *val, int len) + const u8 *val, int len, u8 lock) { int ret; u8 buf[21]; @@ -1323,7 +1310,12 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; memcpy(&buf[3], val, len); - ret = i2c_transfer(client->adapter, msg, 1); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 1); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 1) { @@ -1338,7 +1330,7 @@ err: } static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, - u8 *val, int len) + u8 *val, int len, u8 lock) { int ret; u8 buf[3]; @@ -1359,7 +1351,12 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, buf[0] = (reg >> 8) & 0xff; buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; - ret = i2c_transfer(client->adapter, msg, 2); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 2); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 2) { @@ -1379,25 +1376,27 @@ static int af9013_regmap_write(void *context, const void *data, size_t count) struct af9013_state *state = i2c_get_clientdata(client); int ret, i; u8 cmd; - u16 reg = ((u8 *)data)[0] << 8|((u8 *)data)[1] << 0; - u8 *val = &((u8 *)data)[2]; - const unsigned int len = count - 2; + u8 lock = !((u8 *)data)[0]; + u16 reg = ((u8 *)data)[1] << 8 | ((u8 *)data)[2] << 0; + u8 *val = &((u8 *)data)[3]; + const unsigned int len = count - 3; if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0; - ret = af9013_wregs(client, cmd, reg, val, len); + ret = af9013_wregs(client, cmd, reg, val, len, lock); if (ret) goto err; } else if (reg >= 0x5100 && reg < 0x8fff) { /* Firmware download */ cmd = 1 << 7|1 << 6|(len - 1) << 2|1 << 1|1 << 0; - ret = af9013_wregs(client, cmd, reg, val, len); + ret = af9013_wregs(client, cmd, reg, val, len, lock); if (ret) goto err; } else { cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|1 << 0; for (i = 0; i < len; i++) { - ret = af9013_wregs(client, cmd, reg + i, val + i, 1); + ret = af9013_wregs(client, cmd, reg + i, val + i, 1, + lock); if (ret) goto err; } @@ -1416,19 +1415,21 @@ static int af9013_regmap_read(void *context, const void *reg_buf, struct af9013_state *state = i2c_get_clientdata(client); int ret, i; u8 cmd; - u16 reg = ((u8 *)reg_buf)[0] << 8|((u8 *)reg_buf)[1] << 0; + u8 lock = !((u8 *)reg_buf)[0]; + u16 reg = ((u8 *)reg_buf)[1] << 8 | ((u8 *)reg_buf)[2] << 0; u8 *val = &((u8 *)val_buf)[0]; const unsigned int len = val_size; if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0; - ret = af9013_rregs(client, cmd, reg, val_buf, len); + ret = af9013_rregs(client, cmd, reg, val_buf, len, lock); if (ret) goto err; } else { cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|0 << 0; for (i = 0; i < len; i++) { - ret = af9013_rregs(client, cmd, reg + i, val + i, 1); + ret = af9013_rregs(client, cmd, reg + i, val + i, 1, + lock); if (ret) goto err; } @@ -1453,8 +1454,9 @@ static int af9013_probe(struct i2c_client *client, .write = af9013_regmap_write, }; static const struct regmap_config regmap_config = { - .reg_bits = 16, - .val_bits = 8, + /* Actual reg is 16 bits, see i2c adapter lock */ + .reg_bits = 24, + .val_bits = 8, }; state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -1463,6 +1465,8 @@ static int af9013_probe(struct i2c_client *client, goto err; } + dev_dbg(&client->dev, "\n"); + /* Setup the state */ state->client = client; i2c_set_clientdata(client, state); @@ -1474,52 +1478,70 @@ static int af9013_probe(struct i2c_client *client, state->spec_inv = pdata->spec_inv; memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version)); memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio)); - INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work); state->regmap = regmap_init(&client->dev, ®map_bus, client, ®map_config); if (IS_ERR(state->regmap)) { ret = PTR_ERR(state->regmap); goto err_kfree; } + /* Create mux i2c adapter */ + state->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, + af9013_select, af9013_deselect); + if (!state->muxc) { + ret = -ENOMEM; + goto err_regmap_exit; + } + state->muxc->priv = state; + ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + if (ret) + goto err_regmap_exit; /* Download firmware */ if (state->ts_mode != AF9013_TS_MODE_USB) { ret = af9013_download_firmware(state); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; } /* Firmware version */ ret = regmap_bulk_read(state->regmap, 0x5103, firmware_version, sizeof(firmware_version)); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; /* Set GPIOs */ for (i = 0; i < sizeof(state->gpio); i++) { ret = af9013_set_gpio(state, i, state->gpio[i]); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; } /* Create dvb frontend */ memcpy(&state->fe.ops, &af9013_ops, sizeof(state->fe.ops)); - if (!pdata->attach_in_use) - state->fe.ops.release = NULL; state->fe.demodulator_priv = state; /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; + pdata->get_i2c_adapter = af9013_get_i2c_adapter; + pdata->pid_filter = af9013_pid_filter; + pdata->pid_filter_ctrl = af9013_pid_filter_ctrl; /* Init stats to indicate which stats are supported */ c = &state->fe.dtv_property_cache; + c->strength.len = 1; c->cnr.len = 1; + c->post_bit_error.len = 1; + c->post_bit_count.len = 1; + c->block_error.len = 1; + c->block_count.len = 1; dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", firmware_version[0], firmware_version[1], firmware_version[2], firmware_version[3]); return 0; +err_i2c_mux_del_adapters: + i2c_mux_del_adapters(state->muxc); err_regmap_exit: regmap_exit(state->regmap); err_kfree: @@ -1535,8 +1557,7 @@ static int af9013_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - /* Stop statistics polling */ - cancel_delayed_work_sync(&state->statistics_work); + i2c_mux_del_adapters(state->muxc); regmap_exit(state->regmap); diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index a290722c04fd..165ae29ccac4 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -38,13 +38,9 @@ * @api_version: Firmware API version. * @gpio: GPIOs. * @get_dvb_frontend: Get DVB frontend callback. - * - * AF9013/5 GPIOs (mostly guessed): - * * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices - * * demod#1-gpio#1 - xtal setting (?) - * * demod#1-gpio#3 - tuner#1 - * * demod#2-gpio#0 - tuner#2 - * * demod#2-gpio#1 - xtal setting (?) + * @get_i2c_adapter: Get I2C adapter. + * @pid_filter_ctrl: Control PID filter. + * @pid_filter: Set PID to PID filter. */ struct af9013_platform_data { /* @@ -84,36 +80,18 @@ struct af9013_platform_data { u8 gpio[4]; struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); - -/* private: For legacy media attach wrapper. Do not set value. */ - bool attach_in_use; - u8 i2c_addr; - u32 clock; + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + int (*pid_filter_ctrl)(struct dvb_frontend *, int); + int (*pid_filter)(struct dvb_frontend *, u8, u16, int); }; -#define af9013_config af9013_platform_data -#define AF9013_TS_USB AF9013_TS_MODE_USB -#define AF9013_TS_PARALLEL AF9013_TS_MODE_PARALLEL -#define AF9013_TS_SERIAL AF9013_TS_MODE_SERIAL - -#if IS_REACHABLE(CONFIG_DVB_AF9013) -/** - * Attach an af9013 demod - * - * @config: pointer to &struct af9013_config with demod configuration. - * @i2c: i2c adapter to use. - * - * return: FE pointer on success, NULL on failure. +/* + * AF9013/5 GPIOs (mostly guessed) + * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices + * demod#1-gpio#1 - xtal setting (?) + * demod#1-gpio#3 - tuner#1 + * demod#2-gpio#0 - tuner#2 + * demod#2-gpio#1 - xtal setting (?) */ -extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *af9013_attach( -const struct af9013_config *config, struct i2c_adapter *i2c) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_AF9013 */ #endif /* AF9013_H */ diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 688fc3472cf6..3e95de7dba51 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -22,25 +22,21 @@ #define AF9013_PRIV_H #include <media/dvb_frontend.h> +#include <media/dvb_math.h> #include "af9013.h" #include <linux/firmware.h> +#include <linux/i2c-mux.h> #include <linux/math64.h> #include <linux/regmap.h> #define AF9013_FIRMWARE "dvb-fe-af9013.fw" -struct af9013_reg_bit { - u16 addr; - u8 pos:4; - u8 len:4; +struct af9013_reg_mask_val { + u16 reg; + u8 mask; u8 val; }; -struct af9013_snr { - u32 val; - u8 snr; -}; - struct af9013_coeff { u32 clock; u32 bandwidth_hz; @@ -91,817 +87,775 @@ static const struct af9013_coeff coeff_lut[] = { 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, }; -/* QPSK SNR lookup table */ -static const struct af9013_snr qpsk_snr_lut[] = { - { 0x000000, 0 }, - { 0x0b4771, 0 }, - { 0x0c1aed, 1 }, - { 0x0d0d27, 2 }, - { 0x0e4d19, 3 }, - { 0x0e5da8, 4 }, - { 0x107097, 5 }, - { 0x116975, 6 }, - { 0x1252d9, 7 }, - { 0x131fa4, 8 }, - { 0x13d5e1, 9 }, - { 0x148e53, 10 }, - { 0x15358b, 11 }, - { 0x15dd29, 12 }, - { 0x168112, 13 }, - { 0x170b61, 14 }, - { 0xffffff, 15 }, -}; - -/* QAM16 SNR lookup table */ -static const struct af9013_snr qam16_snr_lut[] = { - { 0x000000, 0 }, - { 0x05eb62, 5 }, - { 0x05fecf, 6 }, - { 0x060b80, 7 }, - { 0x062501, 8 }, - { 0x064865, 9 }, - { 0x069604, 10 }, - { 0x06f356, 11 }, - { 0x07706a, 12 }, - { 0x0804d3, 13 }, - { 0x089d1a, 14 }, - { 0x093e3d, 15 }, - { 0x09e35d, 16 }, - { 0x0a7c3c, 17 }, - { 0x0afaf8, 18 }, - { 0x0b719d, 19 }, - { 0xffffff, 20 }, -}; - -/* QAM64 SNR lookup table */ -static const struct af9013_snr qam64_snr_lut[] = { - { 0x000000, 0 }, - { 0x03109b, 12 }, - { 0x0310d4, 13 }, - { 0x031920, 14 }, - { 0x0322d0, 15 }, - { 0x0339fc, 16 }, - { 0x0364a1, 17 }, - { 0x038bcc, 18 }, - { 0x03c7d3, 19 }, - { 0x0408cc, 20 }, - { 0x043bed, 21 }, - { 0x048061, 22 }, - { 0x04be95, 23 }, - { 0x04fa7d, 24 }, - { 0x052405, 25 }, - { 0x05570d, 26 }, - { 0xffffff, 27 }, -}; - -static const struct af9013_reg_bit ofsm_init[] = { - { 0xd73a, 0, 8, 0xa1 }, - { 0xd73b, 0, 8, 0x1f }, - { 0xd73c, 4, 4, 0x0a }, - { 0xd732, 3, 1, 0x00 }, - { 0xd731, 4, 2, 0x03 }, - { 0xd73d, 7, 1, 0x01 }, - { 0xd740, 0, 1, 0x00 }, - { 0xd740, 1, 1, 0x00 }, - { 0xd740, 2, 1, 0x00 }, - { 0xd740, 3, 1, 0x01 }, - { 0xd3c1, 4, 1, 0x01 }, - { 0x9124, 0, 8, 0x58 }, - { 0x9125, 0, 2, 0x02 }, - { 0xd3a2, 0, 8, 0x00 }, - { 0xd3a3, 0, 8, 0x04 }, - { 0xd305, 0, 8, 0x32 }, - { 0xd306, 0, 8, 0x10 }, - { 0xd304, 0, 8, 0x04 }, - { 0x9112, 0, 1, 0x01 }, - { 0x911d, 0, 1, 0x01 }, - { 0x911a, 0, 1, 0x01 }, - { 0x911b, 0, 1, 0x01 }, - { 0x9bce, 0, 4, 0x02 }, - { 0x9116, 0, 1, 0x01 }, - { 0x9122, 0, 8, 0xd0 }, - { 0xd2e0, 0, 8, 0xd0 }, - { 0xd2e9, 0, 4, 0x0d }, - { 0xd38c, 0, 8, 0xfc }, - { 0xd38d, 0, 8, 0x00 }, - { 0xd38e, 0, 8, 0x7e }, - { 0xd38f, 0, 8, 0x00 }, - { 0xd390, 0, 8, 0x2f }, - { 0xd145, 4, 1, 0x01 }, - { 0xd1a9, 4, 1, 0x01 }, - { 0xd158, 5, 3, 0x01 }, - { 0xd159, 0, 6, 0x06 }, - { 0xd167, 0, 8, 0x00 }, - { 0xd168, 0, 4, 0x07 }, - { 0xd1c3, 5, 3, 0x00 }, - { 0xd1c4, 0, 6, 0x00 }, - { 0xd1c5, 0, 7, 0x10 }, - { 0xd1c6, 0, 3, 0x02 }, - { 0xd080, 2, 5, 0x03 }, - { 0xd081, 4, 4, 0x09 }, - { 0xd098, 4, 4, 0x0f }, - { 0xd098, 0, 4, 0x03 }, - { 0xdbc0, 4, 1, 0x01 }, - { 0xdbc7, 0, 8, 0x08 }, - { 0xdbc8, 4, 4, 0x00 }, - { 0xdbc9, 0, 5, 0x01 }, - { 0xd280, 0, 8, 0xe0 }, - { 0xd281, 0, 8, 0xff }, - { 0xd282, 0, 8, 0xff }, - { 0xd283, 0, 8, 0xc3 }, - { 0xd284, 0, 8, 0xff }, - { 0xd285, 0, 4, 0x01 }, - { 0xd0f0, 0, 7, 0x1a }, - { 0xd0f1, 4, 1, 0x01 }, - { 0xd0f2, 0, 8, 0x0c }, - { 0xd101, 5, 3, 0x06 }, - { 0xd103, 0, 4, 0x08 }, - { 0xd0f8, 0, 7, 0x20 }, - { 0xd111, 5, 1, 0x00 }, - { 0xd111, 6, 1, 0x00 }, - { 0x910b, 0, 8, 0x0a }, - { 0x9115, 0, 8, 0x02 }, - { 0x910c, 0, 8, 0x02 }, - { 0x910d, 0, 8, 0x08 }, - { 0x910e, 0, 8, 0x0a }, - { 0x9bf6, 0, 8, 0x06 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf7, 0, 8, 0x05 }, - { 0x9bf9, 0, 8, 0x0f }, - { 0x9bfc, 0, 8, 0x13 }, - { 0x9bd3, 0, 8, 0xff }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, +/* + * Afatech AF9013 demod init + */ +static const struct af9013_reg_mask_val demod_init_tab[] = { + {0xd73a, 0xff, 0xa1}, + {0xd73b, 0xff, 0x1f}, + {0xd73c, 0xf0, 0xa0}, + {0xd732, 0x08, 0x00}, + {0xd731, 0x30, 0x30}, + {0xd73d, 0x80, 0x80}, + {0xd740, 0x01, 0x00}, + {0xd740, 0x02, 0x00}, + {0xd740, 0x04, 0x00}, + {0xd740, 0x08, 0x08}, + {0xd3c1, 0x10, 0x10}, + {0x9124, 0xff, 0x58}, + {0x9125, 0x03, 0x02}, + {0xd3a2, 0xff, 0x00}, + {0xd3a3, 0xff, 0x04}, + {0xd305, 0xff, 0x32}, + {0xd306, 0xff, 0x10}, + {0xd304, 0xff, 0x04}, + {0x9112, 0x01, 0x01}, + {0x911d, 0x01, 0x01}, + {0x911a, 0x01, 0x01}, + {0x911b, 0x01, 0x01}, + {0x9bce, 0x0f, 0x02}, + {0x9116, 0x01, 0x01}, + {0x9122, 0xff, 0xd0}, + {0xd2e0, 0xff, 0xd0}, + {0xd2e9, 0x0f, 0x0d}, + {0xd38c, 0xff, 0xfc}, + {0xd38d, 0xff, 0x00}, + {0xd38e, 0xff, 0x7e}, + {0xd38f, 0xff, 0x00}, + {0xd390, 0xff, 0x2f}, + {0xd145, 0x10, 0x10}, + {0xd1a9, 0x10, 0x10}, + {0xd158, 0xe0, 0x20}, + {0xd159, 0x3f, 0x06}, + {0xd167, 0xff, 0x00}, + {0xd168, 0x0f, 0x07}, + {0xd1c3, 0xe0, 0x00}, + {0xd1c4, 0x3f, 0x00}, + {0xd1c5, 0x7f, 0x10}, + {0xd1c6, 0x07, 0x02}, + {0xd080, 0x7c, 0x0c}, + {0xd081, 0xf0, 0x90}, + {0xd098, 0xf0, 0xf0}, + {0xd098, 0x0f, 0x03}, + {0xdbc0, 0x10, 0x10}, + {0xdbc7, 0xff, 0x08}, + {0xdbc8, 0xf0, 0x00}, + {0xdbc9, 0x1f, 0x01}, + {0xd280, 0xff, 0xe0}, + {0xd281, 0xff, 0xff}, + {0xd282, 0xff, 0xff}, + {0xd283, 0xff, 0xc3}, + {0xd284, 0xff, 0xff}, + {0xd285, 0x0f, 0x01}, + {0xd0f0, 0x7f, 0x1a}, + {0xd0f1, 0x10, 0x10}, + {0xd0f2, 0xff, 0x0c}, + {0xd101, 0xe0, 0xc0}, + {0xd103, 0x0f, 0x08}, + {0xd0f8, 0x7f, 0x20}, + {0xd111, 0x20, 0x00}, + {0xd111, 0x40, 0x00}, + {0x910b, 0xff, 0x0a}, + {0x9115, 0xff, 0x02}, + {0x910c, 0xff, 0x02}, + {0x910d, 0xff, 0x08}, + {0x910e, 0xff, 0x0a}, + {0x9bf6, 0xff, 0x06}, + {0x9bf8, 0xff, 0x02}, + {0x9bf7, 0xff, 0x05}, + {0x9bf9, 0xff, 0x0f}, + {0x9bfc, 0xff, 0x13}, + {0x9bd3, 0xff, 0xff}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, }; -/* Panasonic ENV77H11D5 tuner init - AF9013_TUNER_ENV77H11D5 = 129 */ -static const struct af9013_reg_bit tuner_init_env77h11d5[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x03 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0xd015, 0, 8, 0x50 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xeb }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf4 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xeb }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0x52 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Panasonic ENV77H11D5 tuner init + * AF9013_TUNER_ENV77H11D5 0x81 + */ +static const struct af9013_reg_mask_val tuner_init_tab_env77h11d5[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x03}, + {0x9bbe, 0xff, 0x01}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0xd015, 0xff, 0x50}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0xeb}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf4}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0xeb}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0x52}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060 = 130 */ -static const struct af9013_reg_bit tuner_init_mt2060[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bbe, 0, 1, 0x00 }, - { 0x9bcc, 0, 1, 0x00 }, - { 0x9bb9, 0, 8, 0x75 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x30 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcc }, - { 0x9be4, 0, 8, 0xa0 }, - { 0x9bbd, 0, 8, 0x8e }, - { 0x9be2, 0, 8, 0x4d }, - { 0x9bee, 0, 1, 0x01 }, +/* + * Microtune MT2060 tuner init + * AF9013_TUNER_MT2060 0x82 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mt2060[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x07}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bbe, 0x01, 0x00}, + {0x9bcc, 0x01, 0x00}, + {0x9bb9, 0xff, 0x75}, + {0x9bcd, 0xff, 0x24}, + {0x9bff, 0xff, 0x30}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x32}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x36}, + {0xd00d, 0x03, 0x03}, + {0xd00a, 0xff, 0x35}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x90}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x36}, + {0x9bc6, 0xff, 0x03}, + {0x9bba, 0xff, 0xc9}, + {0x9bc9, 0xff, 0x79}, + {0xd011, 0xff, 0x10}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0x45}, + {0xd014, 0x03, 0x03}, + {0xd040, 0xff, 0x98}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0xcf}, + {0xd043, 0x03, 0x03}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xcc}, + {0x9be4, 0xff, 0xa0}, + {0x9bbd, 0xff, 0x8e}, + {0x9be2, 0xff, 0x4d}, + {0x9bee, 0x01, 0x01}, }; -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060_2 = 147 */ -static const struct af9013_reg_bit tuner_init_mt2060_2[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x96 }, - { 0xd054, 0, 8, 0x46 }, - { 0xd045, 7, 1, 0x00 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Microtune MT2060 tuner init + * AF9013_TUNER_MT2060_2 0x93 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mt2060_2[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x06}, + {0x9bbe, 0xff, 0x01}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x32}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x36}, + {0xd00d, 0x03, 0x03}, + {0xd00a, 0xff, 0x35}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x90}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x36}, + {0x9bc6, 0xff, 0x03}, + {0x9bba, 0xff, 0xc9}, + {0x9bc9, 0xff, 0x79}, + {0xd011, 0xff, 0x10}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0x45}, + {0xd014, 0x03, 0x03}, + {0xd040, 0xff, 0x98}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0xcf}, + {0xd043, 0x03, 0x03}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0xff, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x96}, + {0xd054, 0xff, 0x46}, + {0xd045, 0x80, 0x00}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* MaxLinear MXL5003 tuner init - AF9013_TUNER_MXL5003D = 3 */ -static const struct af9013_reg_bit tuner_init_mxl5003d[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bfc, 0, 8, 0x0f }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0xd015, 0, 8, 0x33 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x6c }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x3d }, - { 0xd00d, 0, 2, 0x00 }, - { 0xd00a, 0, 8, 0x45 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x52 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x3d }, - { 0x9bc6, 0, 8, 0x00 }, - { 0x9bba, 0, 8, 0xa2 }, - { 0x9bc9, 0, 8, 0xa0 }, - { 0xd011, 0, 8, 0x56 }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x50 }, - { 0xd014, 0, 2, 0x00 }, - { 0xd040, 0, 8, 0x56 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x50 }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * MaxLinear MXL5003 tuner init + * AF9013_TUNER_MXL5003D 0x03 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mxl5003d[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x09}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bfc, 0xff, 0x0f}, + {0x9bf6, 0xff, 0x01}, + {0x9bbe, 0x01, 0x01}, + {0xd015, 0xff, 0x33}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x40}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x6c}, + {0xd007, 0x03, 0x00}, + {0xd00c, 0xff, 0x3d}, + {0xd00d, 0x03, 0x00}, + {0xd00a, 0xff, 0x45}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x52}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x3d}, + {0x9bc6, 0xff, 0x00}, + {0x9bba, 0xff, 0xa2}, + {0x9bc9, 0xff, 0xa0}, + {0xd011, 0xff, 0x56}, + {0xd012, 0x03, 0x00}, + {0xd013, 0xff, 0x50}, + {0xd014, 0x03, 0x00}, + {0xd040, 0xff, 0x56}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0x50}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0xff, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* MaxLinear MXL5005S & MXL5007T tuner init - AF9013_TUNER_MXL5005D = 13 - AF9013_TUNER_MXL5005R = 30 - AF9013_TUNER_MXL5007T = 177 */ -static const struct af9013_reg_bit tuner_init_mxl5005[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x40 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x73 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xfa }, - { 0xd00d, 0, 2, 0x01 }, - { 0xd00a, 0, 8, 0xff }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x23 }, - { 0x9bc8, 0, 8, 0x55 }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xfa }, - { 0x9bc6, 0, 8, 0x01 }, - { 0x9bba, 0, 8, 0xff }, - { 0x9bc9, 0, 8, 0xff }, - { 0x9bd3, 0, 8, 0x95 }, - { 0xd011, 0, 8, 0x70 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xfb }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x70 }, - { 0xd041, 0, 2, 0x01 }, - { 0xd042, 0, 8, 0xfb }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x93 }, - { 0x9be4, 0, 8, 0xfe }, - { 0x9bbd, 0, 8, 0x63 }, - { 0x9be2, 0, 8, 0xfe }, - { 0x9bee, 0, 1, 0x01 }, +/* + * MaxLinear MXL5005S & MXL5007T tuner init + * AF9013_TUNER_MXL5005D 0x0d + * AF9013_TUNER_MXL5005R 0x1e + * AF9013_TUNER_MXL5007T 0xb1 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mxl5005[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x07}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x28}, + {0x9bff, 0xff, 0x24}, + {0xd015, 0xff, 0x40}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x40}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x73}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0xfa}, + {0xd00d, 0x03, 0x01}, + {0xd00a, 0xff, 0xff}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x23}, + {0x9bc8, 0xff, 0x55}, + {0x9bc3, 0xff, 0x01}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0xfa}, + {0x9bc6, 0xff, 0x01}, + {0x9bba, 0xff, 0xff}, + {0x9bc9, 0xff, 0xff}, + {0x9bd3, 0xff, 0x95}, + {0xd011, 0xff, 0x70}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xfb}, + {0xd014, 0x03, 0x01}, + {0xd040, 0xff, 0x70}, + {0xd041, 0x03, 0x01}, + {0xd042, 0xff, 0xfb}, + {0xd043, 0x03, 0x01}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0x93}, + {0x9be4, 0xff, 0xfe}, + {0x9bbd, 0xff, 0x63}, + {0x9be2, 0xff, 0xfe}, + {0x9bee, 0x01, 0x01}, }; -/* Quantek QT1010 tuner init - AF9013_TUNER_QT1010 = 134 - AF9013_TUNER_QT1010A = 162 */ -static const struct af9013_reg_bit tuner_init_qt1010[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x20 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x99 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x0f }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0x50 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x00 }, - { 0x9bc8, 0, 8, 0x00 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x0f }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xc5 }, - { 0x9bc9, 0, 8, 0xff }, - { 0xd011, 0, 8, 0x58 }, - { 0xd012, 0, 2, 0x02 }, - { 0xd013, 0, 8, 0x89 }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x58 }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x89 }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcd }, - { 0x9be4, 0, 8, 0xbb }, - { 0x9bbd, 0, 8, 0x93 }, - { 0x9be2, 0, 8, 0x80 }, - { 0x9bee, 0, 1, 0x01 }, +/* + * Quantek QT1010 tuner init + * AF9013_TUNER_QT1010 0x86 + * AF9013_TUNER_QT1010A 0xa2 + */ +static const struct af9013_reg_mask_val tuner_init_tab_qt1010[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x09}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x28}, + {0x9bff, 0xff, 0x20}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x99}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x0f}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0x50}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x00}, + {0x9bc8, 0xff, 0x00}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x0f}, + {0x9bc6, 0xff, 0x02}, + {0x9bba, 0xff, 0xc5}, + {0x9bc9, 0xff, 0xff}, + {0xd011, 0xff, 0x58}, + {0xd012, 0x03, 0x02}, + {0xd013, 0xff, 0x89}, + {0xd014, 0x03, 0x01}, + {0xd040, 0xff, 0x58}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x89}, + {0xd043, 0x03, 0x01}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xcd}, + {0x9be4, 0xff, 0xbb}, + {0x9bbd, 0xff, 0x93}, + {0x9be2, 0xff, 0x80}, + {0x9bee, 0x01, 0x01}, }; -/* Freescale MC44S803 tuner init - AF9013_TUNER_MC44S803 = 133 */ -static const struct af9013_reg_bit tuner_init_mc44s803[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf9, 0, 8, 0x02 }, - { 0x9bfc, 0, 8, 0x1f }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x01 }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x7b }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x7c }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xfe }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x08 }, - { 0x9bc8, 0, 8, 0x9a }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x7c }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xfc }, - { 0x9bc9, 0, 8, 0xaa }, - { 0xd011, 0, 8, 0x6b }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x88 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x6b }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x7c }, - { 0xd043, 0, 2, 0x02 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x9e }, - { 0x9be4, 0, 8, 0xff }, - { 0x9bbd, 0, 8, 0x9e }, - { 0x9be2, 0, 8, 0x25 }, - { 0x9bee, 0, 1, 0x01 }, - { 0xd73b, 3, 1, 0x00 }, +/* + * Freescale MC44S803 tuner init + * AF9013_TUNER_MC44S803 0x85 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mc44s803[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x06}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bf6, 0xff, 0x01}, + {0x9bf8, 0xff, 0x02}, + {0x9bf9, 0xff, 0x02}, + {0x9bfc, 0xff, 0x1f}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x24}, + {0x9bff, 0xff, 0x24}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x01}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x7b}, + {0xd007, 0x03, 0x00}, + {0xd00c, 0xff, 0x7c}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xfe}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x08}, + {0x9bc8, 0xff, 0x9a}, + {0x9bc3, 0xff, 0x01}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x7c}, + {0x9bc6, 0xff, 0x02}, + {0x9bba, 0xff, 0xfc}, + {0x9bc9, 0xff, 0xaa}, + {0xd011, 0xff, 0x6b}, + {0xd012, 0x03, 0x00}, + {0xd013, 0xff, 0x88}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x6b}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0x7c}, + {0xd043, 0x03, 0x02}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0x9e}, + {0x9be4, 0xff, 0xff}, + {0x9bbd, 0xff, 0x9e}, + {0x9be2, 0xff, 0x25}, + {0x9bee, 0x01, 0x01}, + {0xd73b, 0x08, 0x00}, }; -/* unknown, probably for tin can tuner, tuner init - AF9013_TUNER_UNKNOWN = 140 */ -static const struct af9013_reg_bit tuner_init_unknown[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x02 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Unknown, probably for tin can tuner, tuner init + * AF9013_TUNER_UNKNOWN 0x8c + */ +static const struct af9013_reg_mask_val tuner_init_tab_unknown[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x02}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd1a0, 0x02, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x18}, + {0x9bff, 0xff, 0x2c}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x00}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf6}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc8, 0xff, 0xaa}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x00}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0xf0}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* NXP TDA18271 & TDA18218 tuner init - AF9013_TUNER_TDA18271 = 156 - AF9013_TUNER_TDA18218 = 179 */ -static const struct af9013_reg_bit tuner_init_tda18271[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x04 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xa8 }, - { 0x9be4, 0, 8, 0x7f }, - { 0x9bbd, 0, 8, 0xa8 }, - { 0x9be2, 0, 8, 0x20 }, - { 0x9bee, 0, 1, 0x01 }, +/* + * NXP TDA18271 & TDA18218 tuner init + * AF9013_TUNER_TDA18271 0x9c + * AF9013_TUNER_TDA18218 0xb3 + */ +static const struct af9013_reg_mask_val tuner_init_tab_tda18271[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x04}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd1a0, 0x02, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x18}, + {0x9bff, 0xff, 0x2c}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x00}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf6}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc8, 0xff, 0xaa}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x00}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0xf0}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xa8}, + {0x9be4, 0xff, 0x7f}, + {0x9bbd, 0xff, 0xa8}, + {0x9be2, 0xff, 0x20}, + {0x9bee, 0x01, 0x01}, }; #endif /* AF9013_PRIV_H */ diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c index dc9cbd8f2104..c0a5849b76bb 100644 --- a/drivers/staging/media/cxd2099/cxd2099.c +++ b/drivers/media/dvb-frontends/cxd2099.c @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/wait.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -33,8 +34,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); struct cxd { struct dvb_ca_en50221 en; - struct i2c_adapter *i2c; struct cxd2099_cfg cfg; + struct i2c_client *client; + struct regmap *regmap; u8 regs[0x23]; u8 lastaddress; @@ -56,69 +58,12 @@ struct cxd { u8 wbuf[1028]; }; -static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 data) -{ - u8 m[2] = {reg, data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, - "Failed to write to I2C register %02x@%02x!\n", - reg, adr); - return -1; - } - return 0; -} - -static int i2c_write(struct i2c_adapter *adapter, u8 adr, - u8 *data, u16 len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, "Failed to write to I2C!\n"); - return -1; - } - return 0; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *data, u16 n) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = n} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) { int status = 0; if (ci->lastaddress != adr) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr); + status = regmap_write(ci->regmap, 0, adr); if (!status) { ci->lastaddress = adr; @@ -127,7 +72,7 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) len = ci->cfg.max_i2c; - status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len); + status = regmap_raw_read(ci->regmap, 1, data, len); if (status) return status; data += len; @@ -145,64 +90,66 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val) static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) - status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n); + status = regmap_raw_read(ci->regmap, 3, data, n); return status; } static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) { - u8 buf[256] = {3}; + u8 buf[256]; - memcpy(buf + 1, data, n); - status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1); + memcpy(buf, data, n); + status = regmap_raw_write(ci->regmap, 3, buf, n); } return status; } -static int read_io(struct cxd *ci, u16 address, u8 *val) +static int read_io(struct cxd *ci, u16 address, unsigned int *val) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) - status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1); + status = regmap_read(ci->regmap, 3, val); return status; } static int write_io(struct cxd *ci, u16 address, u8 val) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; - u8 buf[2] = {3, val}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) - status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2); + status = regmap_write(ci->regmap, 3, val); return status; } static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) { int status = 0; + unsigned int regval; if (ci->lastaddress != reg) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg); - if (!status && reg >= 6 && reg <= 8 && mask != 0xff) - status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]); + status = regmap_write(ci->regmap, 0, reg); + if (!status && reg >= 6 && reg <= 8 && mask != 0xff) { + status = regmap_read(ci->regmap, 1, ®val); + ci->regs[reg] = regval; + } ci->lastaddress = reg; ci->regs[reg] = (ci->regs[reg] & (~mask)) | val; if (!status) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]); + status = regmap_write(ci->regmap, 1, ci->regs[reg]); if (reg == 0x20) ci->regs[reg] &= 0x7f; return status; @@ -219,19 +166,18 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) u8 *buf = ci->wbuf; if (ci->lastaddress != adr) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr); + status = regmap_write(ci->regmap, 0, adr); if (status) return status; ci->lastaddress = adr; - buf[0] = 1; while (n) { int len = n; if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c)) len = ci->cfg.max_i2c - 1; - memcpy(buf + 1, data, len); - status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1); + memcpy(buf, data, len); + status = regmap_raw_write(ci->regmap, 1, buf, len); if (status) return status; n -= len; @@ -273,7 +219,7 @@ static void cam_mode(struct cxd *ci, int mode) if (!ci->en.read_data) return; ci->write_busy = 0; - dev_info(&ci->i2c->dev, "enable cam buffer mode\n"); + dev_info(&ci->client->dev, "enable cam buffer mode\n"); write_reg(ci, 0x0d, 0x00); write_reg(ci, 0x0e, 0x01); write_regm(ci, 0x08, 0x40, 0x40); @@ -464,7 +410,7 @@ static int read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) { struct cxd *ci = ca->data; - u8 val; + unsigned int val; mutex_lock(&ci->lock); set_mode(ci, 0); @@ -518,7 +464,7 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) { struct cxd *ci = ca->data; - dev_dbg(&ci->i2c->dev, "%s\n", __func__); + dev_dbg(&ci->client->dev, "%s\n", __func__); if (ci->cammode) read_data(ca, slot, ci->rbuf, 0); mutex_lock(&ci->lock); @@ -577,7 +523,7 @@ static int campoll(struct cxd *ci) if (ci->slot_stat) { ci->slot_stat = 0; write_regm(ci, 0x03, 0x00, 0x08); - dev_info(&ci->i2c->dev, "NO CAM\n"); + dev_info(&ci->client->dev, "NO CAM\n"); ci->ready = 0; } } @@ -660,26 +606,41 @@ static struct dvb_ca_en50221 en_templ = { .write_data = write_data, }; -struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, - void *priv, - struct i2c_adapter *i2c) +static int cxd2099_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct cxd *ci; - u8 val; + struct cxd2099_cfg *cfg = client->dev.platform_data; + static const struct regmap_config rm_cfg = { + .reg_bits = 8, + .val_bits = 8, + }; + unsigned int val; + int ret; - if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) { - dev_info(&i2c->dev, "No CXD2099AR detected at 0x%02x\n", - cfg->adr); - return NULL; + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) { + ret = -ENOMEM; + goto err; } - ci = kzalloc(sizeof(*ci), GFP_KERNEL); - if (!ci) - return NULL; + ci->client = client; + memcpy(&ci->cfg, cfg, sizeof(ci->cfg)); + + ci->regmap = regmap_init_i2c(client, &rm_cfg); + if (IS_ERR(ci->regmap)) { + ret = PTR_ERR(ci->regmap); + goto err_kfree; + } + + ret = regmap_read(ci->regmap, 0x00, &val); + if (ret < 0) { + dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n", + client->addr); + goto err_rmexit; + } mutex_init(&ci->lock); - ci->cfg = *cfg; - ci->i2c = i2c; ci->lastaddress = 0xff; ci->clk_reg_b = 0x4a; ci->clk_reg_f = 0x1b; @@ -687,18 +648,56 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, ci->en = en_templ; ci->en.data = ci; init(ci); - dev_info(&i2c->dev, "Attached CXD2099AR at 0x%02x\n", ci->cfg.adr); + dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr); + + *cfg->en = &ci->en; if (!buffermode) { ci->en.read_data = NULL; ci->en.write_data = NULL; } else { - dev_info(&i2c->dev, "Using CXD2099AR buffer mode"); + dev_info(&client->dev, "Using CXD2099AR buffer mode"); } - return &ci->en; + i2c_set_clientdata(client, ci); + + return 0; + +err_rmexit: + regmap_exit(ci->regmap); +err_kfree: + kfree(ci); +err: + + return ret; } -EXPORT_SYMBOL(cxd2099_attach); + +static int cxd2099_remove(struct i2c_client *client) +{ + struct cxd *ci = i2c_get_clientdata(client); + + regmap_exit(ci->regmap); + kfree(ci); + + return 0; +} + +static const struct i2c_device_id cxd2099_id[] = { + {"cxd2099", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cxd2099_id); + +static struct i2c_driver cxd2099_driver = { + .driver = { + .name = "cxd2099", + }, + .probe = cxd2099_probe, + .remove = cxd2099_remove, + .id_table = cxd2099_id, +}; + +module_i2c_driver(cxd2099_driver); MODULE_DESCRIPTION("CXD2099AR Common Interface controller driver"); MODULE_AUTHOR("Ralph Metzler"); diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h index 253e3155a6df..8fa45a4c615a 100644 --- a/drivers/staging/media/cxd2099/cxd2099.h +++ b/drivers/media/dvb-frontends/cxd2099.h @@ -20,26 +20,13 @@ struct cxd2099_cfg { u32 bitrate; - u8 adr; u8 polarity; u8 clock_mode; u32 max_i2c; -}; - -#if defined(CONFIG_DVB_CXD2099) || \ - (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE)) -struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, - void *priv, struct i2c_adapter *i2c); -#else -static inline struct -dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, - struct i2c_adapter *i2c) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif + /* ptr to DVB CA struct */ + struct dvb_ca_en50221 **en; +}; #endif diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig new file mode 100644 index 000000000000..9d989676e800 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +config DVB_CXD2880 + tristate "Sony CXD2880 DVB-T2/T tuner + demodulator" + depends on DVB_CORE && SPI + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Say Y when you want to support this frontend.
\ No newline at end of file diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile new file mode 100644 index 000000000000..c6baa4caba19 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +cxd2880-objs := cxd2880_common.o \ + cxd2880_devio_spi.o \ + cxd2880_integ.o \ + cxd2880_io.o \ + cxd2880_spi_device.o \ + cxd2880_tnrdmd.o \ + cxd2880_tnrdmd_dvbt2.o \ + cxd2880_tnrdmd_dvbt2_mon.o \ + cxd2880_tnrdmd_dvbt.o \ + cxd2880_tnrdmd_dvbt_mon.o\ + cxd2880_tnrdmd_mon.o\ + cxd2880_top.o + +obj-$(CONFIG_DVB_CXD2880) += cxd2880.o + +ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h new file mode 100644 index 000000000000..4ea3510aab66 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_H +#define CXD2880_H + +struct cxd2880_config { + struct spi_device *spi; + struct mutex *spi_mutex; /* For SPI access exclusive control */ +}; + +#if IS_REACHABLE(CONFIG_DVB_CXD2880) +extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg); +#else +static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_CXD2880 */ + +#endif /* CXD2880_H */ diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c new file mode 100644 index 000000000000..d6f5af6609c1 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_common.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_common.h" + +int cxd2880_convert2s_complement(u32 value, u32 bitlen) +{ + if (!bitlen || bitlen >= 32) + return (int)value; + + if (value & (u32)(1 << (bitlen - 1))) + return (int)(GENMASK(31, bitlen) | value); + else + return (int)(GENMASK(bitlen - 1, 0) & value); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h new file mode 100644 index 000000000000..b05bce71ab35 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_common.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_COMMON_H +#define CXD2880_COMMON_H + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/string.h> + +int cxd2880_convert2s_complement(u32 value, u32 bitlen); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c new file mode 100644 index 000000000000..aba59400859e --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_devio_spi.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * I/O interface via SPI + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_devio_spi.h" + +#define BURST_WRITE_MAX 128 + +static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 *data, + u32 size) +{ + int ret = 0; + struct cxd2880_spi *spi = NULL; + u8 send_data[6]; + u8 *read_data_top = data; + + if (!io || !io->if_object || !data) + return -EINVAL; + + if (sub_address + size > 0x100) + return -EINVAL; + + spi = io->if_object; + + if (tgt == CXD2880_IO_TGT_SYS) + send_data[0] = 0x0b; + else + send_data[0] = 0x0a; + + send_data[3] = 0; + send_data[4] = 0; + send_data[5] = 0; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = size; + + ret = + spi->write_read(spi, send_data, sizeof(send_data), + read_data_top, send_data[2]); + if (ret) + return ret; + + sub_address += send_data[2]; + read_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, + const u8 *data, u32 size) +{ + int ret = 0; + struct cxd2880_spi *spi = NULL; + u8 send_data[BURST_WRITE_MAX + 4]; + const u8 *write_data_top = data; + + if (!io || !io->if_object || !data) + return -EINVAL; + + if (size > BURST_WRITE_MAX) + return -EINVAL; + + if (sub_address + size > 0x100) + return -EINVAL; + + spi = io->if_object; + + if (tgt == CXD2880_IO_TGT_SYS) + send_data[0] = 0x0f; + else + send_data[0] = 0x0e; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = size; + + memcpy(&send_data[3], write_data_top, send_data[2]); + + if (tgt == CXD2880_IO_TGT_SYS) { + send_data[3 + send_data[2]] = 0x00; + ret = spi->write(spi, send_data, send_data[2] + 4); + } else { + ret = spi->write(spi, send_data, send_data[2] + 3); + } + if (ret) + return ret; + + sub_address += send_data[2]; + write_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, u8 slave_select) +{ + if (!io || !spi) + return -EINVAL; + + io->read_regs = cxd2880_io_spi_read_reg; + io->write_regs = cxd2880_io_spi_write_reg; + io->write_reg = cxd2880_io_common_write_one_reg; + io->if_object = spi; + io->i2c_address_sys = 0; + io->i2c_address_demod = 0; + io->slave_select = slave_select; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h new file mode 100644 index 000000000000..27f7cb12fad4 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_devio_spi.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * I/O interface via SPI + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DEVIO_SPI_H +#define CXD2880_DEVIO_SPI_H + +#include "cxd2880_common.h" +#include "cxd2880_io.h" +#include "cxd2880_spi.h" + +#include "cxd2880_tnrdmd.h" + +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, + u8 slave_select); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h new file mode 100644 index 000000000000..820f4757a520 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dtv.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DTV related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DTV_H +#define CXD2880_DTV_H + +enum cxd2880_dtv_sys { + CXD2880_DTV_SYS_UNKNOWN, + CXD2880_DTV_SYS_DVBT, + CXD2880_DTV_SYS_DVBT2, + CXD2880_DTV_SYS_ANY +}; + +enum cxd2880_dtv_bandwidth { + CXD2880_DTV_BW_UNKNOWN = 0, + CXD2880_DTV_BW_1_7_MHZ = 1, + CXD2880_DTV_BW_5_MHZ = 5, + CXD2880_DTV_BW_6_MHZ = 6, + CXD2880_DTV_BW_7_MHZ = 7, + CXD2880_DTV_BW_8_MHZ = 8 +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h new file mode 100644 index 000000000000..76a1acc346ef --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dvbt.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DVBT_H +#define CXD2880_DVBT_H + +#include "cxd2880_common.h" + +enum cxd2880_dvbt_constellation { + CXD2880_DVBT_CONSTELLATION_QPSK, + CXD2880_DVBT_CONSTELLATION_16QAM, + CXD2880_DVBT_CONSTELLATION_64QAM, + CXD2880_DVBT_CONSTELLATION_RESERVED_3 +}; + +enum cxd2880_dvbt_hierarchy { + CXD2880_DVBT_HIERARCHY_NON, + CXD2880_DVBT_HIERARCHY_1, + CXD2880_DVBT_HIERARCHY_2, + CXD2880_DVBT_HIERARCHY_4 +}; + +enum cxd2880_dvbt_coderate { + CXD2880_DVBT_CODERATE_1_2, + CXD2880_DVBT_CODERATE_2_3, + CXD2880_DVBT_CODERATE_3_4, + CXD2880_DVBT_CODERATE_5_6, + CXD2880_DVBT_CODERATE_7_8, + CXD2880_DVBT_CODERATE_RESERVED_5, + CXD2880_DVBT_CODERATE_RESERVED_6, + CXD2880_DVBT_CODERATE_RESERVED_7 +}; + +enum cxd2880_dvbt_guard { + CXD2880_DVBT_GUARD_1_32, + CXD2880_DVBT_GUARD_1_16, + CXD2880_DVBT_GUARD_1_8, + CXD2880_DVBT_GUARD_1_4 +}; + +enum cxd2880_dvbt_mode { + CXD2880_DVBT_MODE_2K, + CXD2880_DVBT_MODE_8K, + CXD2880_DVBT_MODE_RESERVED_2, + CXD2880_DVBT_MODE_RESERVED_3 +}; + +enum cxd2880_dvbt_profile { + CXD2880_DVBT_PROFILE_HP = 0, + CXD2880_DVBT_PROFILE_LP +}; + +struct cxd2880_dvbt_tpsinfo { + enum cxd2880_dvbt_constellation constellation; + enum cxd2880_dvbt_hierarchy hierarchy; + enum cxd2880_dvbt_coderate rate_hp; + enum cxd2880_dvbt_coderate rate_lp; + enum cxd2880_dvbt_guard guard; + enum cxd2880_dvbt_mode mode; + u8 fnum; + u8 length_indicator; + u16 cell_id; + u8 cell_id_ok; + u8 reserved_even; + u8 reserved_odd; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h new file mode 100644 index 000000000000..191047b158fe --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h @@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dvbt2.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DVBT2_H +#define CXD2880_DVBT2_H + +#include "cxd2880_common.h" + +enum cxd2880_dvbt2_profile { + CXD2880_DVBT2_PROFILE_BASE, + CXD2880_DVBT2_PROFILE_LITE, + CXD2880_DVBT2_PROFILE_ANY +}; + +enum cxd2880_dvbt2_version { + CXD2880_DVBT2_V111, + CXD2880_DVBT2_V121, + CXD2880_DVBT2_V131 +}; + +enum cxd2880_dvbt2_s1 { + CXD2880_DVBT2_S1_BASE_SISO = 0x00, + CXD2880_DVBT2_S1_BASE_MISO = 0x01, + CXD2880_DVBT2_S1_NON_DVBT2 = 0x02, + CXD2880_DVBT2_S1_LITE_SISO = 0x03, + CXD2880_DVBT2_S1_LITE_MISO = 0x04, + CXD2880_DVBT2_S1_RSVD3 = 0x05, + CXD2880_DVBT2_S1_RSVD4 = 0x06, + CXD2880_DVBT2_S1_RSVD5 = 0x07, + CXD2880_DVBT2_S1_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_base_s2 { + CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00, + CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01, + CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02, + CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03, + CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04, + CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05, + CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06, + CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07, + CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_lite_s2 { + CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00, + CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01, + CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02, + CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03, + CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04, + CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05, + CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06, + CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07, + CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_guard { + CXD2880_DVBT2_G1_32 = 0x00, + CXD2880_DVBT2_G1_16 = 0x01, + CXD2880_DVBT2_G1_8 = 0x02, + CXD2880_DVBT2_G1_4 = 0x03, + CXD2880_DVBT2_G1_128 = 0x04, + CXD2880_DVBT2_G19_128 = 0x05, + CXD2880_DVBT2_G19_256 = 0x06, + CXD2880_DVBT2_G_RSVD1 = 0x07, + CXD2880_DVBT2_G_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_mode { + CXD2880_DVBT2_M2K = 0x00, + CXD2880_DVBT2_M8K = 0x01, + CXD2880_DVBT2_M4K = 0x02, + CXD2880_DVBT2_M1K = 0x03, + CXD2880_DVBT2_M16K = 0x04, + CXD2880_DVBT2_M32K = 0x05, + CXD2880_DVBT2_M_RSVD1 = 0x06, + CXD2880_DVBT2_M_RSVD2 = 0x07 +}; + +enum cxd2880_dvbt2_bw { + CXD2880_DVBT2_BW_8 = 0x00, + CXD2880_DVBT2_BW_7 = 0x01, + CXD2880_DVBT2_BW_6 = 0x02, + CXD2880_DVBT2_BW_5 = 0x03, + CXD2880_DVBT2_BW_10 = 0x04, + CXD2880_DVBT2_BW_1_7 = 0x05, + CXD2880_DVBT2_BW_RSVD1 = 0x06, + CXD2880_DVBT2_BW_RSVD2 = 0x07, + CXD2880_DVBT2_BW_RSVD3 = 0x08, + CXD2880_DVBT2_BW_RSVD4 = 0x09, + CXD2880_DVBT2_BW_RSVD5 = 0x0a, + CXD2880_DVBT2_BW_RSVD6 = 0x0b, + CXD2880_DVBT2_BW_RSVD7 = 0x0c, + CXD2880_DVBT2_BW_RSVD8 = 0x0d, + CXD2880_DVBT2_BW_RSVD9 = 0x0e, + CXD2880_DVBT2_BW_RSVD10 = 0x0f, + CXD2880_DVBT2_BW_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1pre_type { + CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00, + CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01, + CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02, + CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03, + CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_papr { + CXD2880_DVBT2_PAPR_0 = 0x00, + CXD2880_DVBT2_PAPR_1 = 0x01, + CXD2880_DVBT2_PAPR_2 = 0x02, + CXD2880_DVBT2_PAPR_3 = 0x03, + CXD2880_DVBT2_PAPR_RSVD1 = 0x04, + CXD2880_DVBT2_PAPR_RSVD2 = 0x05, + CXD2880_DVBT2_PAPR_RSVD3 = 0x06, + CXD2880_DVBT2_PAPR_RSVD4 = 0x07, + CXD2880_DVBT2_PAPR_RSVD5 = 0x08, + CXD2880_DVBT2_PAPR_RSVD6 = 0x09, + CXD2880_DVBT2_PAPR_RSVD7 = 0x0a, + CXD2880_DVBT2_PAPR_RSVD8 = 0x0b, + CXD2880_DVBT2_PAPR_RSVD9 = 0x0c, + CXD2880_DVBT2_PAPR_RSVD10 = 0x0d, + CXD2880_DVBT2_PAPR_RSVD11 = 0x0e, + CXD2880_DVBT2_PAPR_RSVD12 = 0x0f, + CXD2880_DVBT2_PAPR_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_constell { + CXD2880_DVBT2_L1POST_BPSK = 0x00, + CXD2880_DVBT2_L1POST_QPSK = 0x01, + CXD2880_DVBT2_L1POST_QAM16 = 0x02, + CXD2880_DVBT2_L1POST_QAM64 = 0x03, + CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04, + CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05, + CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06, + CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07, + CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08, + CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09, + CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a, + CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b, + CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c, + CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d, + CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e, + CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f, + CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_cr { + CXD2880_DVBT2_L1POST_R1_2 = 0x00, + CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01, + CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02, + CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03, + CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_fec_type { + CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00, + CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01, + CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02, + CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03, + CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_pp { + CXD2880_DVBT2_PP1 = 0x00, + CXD2880_DVBT2_PP2 = 0x01, + CXD2880_DVBT2_PP3 = 0x02, + CXD2880_DVBT2_PP4 = 0x03, + CXD2880_DVBT2_PP5 = 0x04, + CXD2880_DVBT2_PP6 = 0x05, + CXD2880_DVBT2_PP7 = 0x06, + CXD2880_DVBT2_PP8 = 0x07, + CXD2880_DVBT2_PP_RSVD1 = 0x08, + CXD2880_DVBT2_PP_RSVD2 = 0x09, + CXD2880_DVBT2_PP_RSVD3 = 0x0a, + CXD2880_DVBT2_PP_RSVD4 = 0x0b, + CXD2880_DVBT2_PP_RSVD5 = 0x0c, + CXD2880_DVBT2_PP_RSVD6 = 0x0d, + CXD2880_DVBT2_PP_RSVD7 = 0x0e, + CXD2880_DVBT2_PP_RSVD8 = 0x0f, + CXD2880_DVBT2_PP_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_code_rate { + CXD2880_DVBT2_R1_2 = 0x00, + CXD2880_DVBT2_R3_5 = 0x01, + CXD2880_DVBT2_R2_3 = 0x02, + CXD2880_DVBT2_R3_4 = 0x03, + CXD2880_DVBT2_R4_5 = 0x04, + CXD2880_DVBT2_R5_6 = 0x05, + CXD2880_DVBT2_R1_3 = 0x06, + CXD2880_DVBT2_R2_5 = 0x07, + CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_constell { + CXD2880_DVBT2_QPSK = 0x00, + CXD2880_DVBT2_QAM16 = 0x01, + CXD2880_DVBT2_QAM64 = 0x02, + CXD2880_DVBT2_QAM256 = 0x03, + CXD2880_DVBT2_CON_RSVD1 = 0x04, + CXD2880_DVBT2_CON_RSVD2 = 0x05, + CXD2880_DVBT2_CON_RSVD3 = 0x06, + CXD2880_DVBT2_CON_RSVD4 = 0x07, + CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_type { + CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00, + CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01, + CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02, + CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03, + CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04, + CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05, + CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06, + CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07, + CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_payload { + CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00, + CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01, + CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02, + CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f, + CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_fec { + CXD2880_DVBT2_FEC_LDPC_16K = 0x00, + CXD2880_DVBT2_FEC_LDPC_64K = 0x01, + CXD2880_DVBT2_FEC_RSVD1 = 0x02, + CXD2880_DVBT2_FEC_RSVD2 = 0x03, + CXD2880_DVBT2_FEC_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_mode { + CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00, + CXD2880_DVBT2_PLP_MODE_NM = 0x01, + CXD2880_DVBT2_PLP_MODE_HEM = 0x02, + CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03, + CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_btype { + CXD2880_DVBT2_PLP_COMMON, + CXD2880_DVBT2_PLP_DATA +}; + +enum cxd2880_dvbt2_stream { + CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00, + CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01, + CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02, + CXD2880_DVBT2_STREAM_TRANSPORT = 0x03, + CXD2880_DVBT2_STREAM_UNKNOWN = 0xff +}; + +struct cxd2880_dvbt2_l1pre { + enum cxd2880_dvbt2_l1pre_type type; + u8 bw_ext; + enum cxd2880_dvbt2_s1 s1; + u8 s2; + u8 mixed; + enum cxd2880_dvbt2_mode fft_mode; + u8 l1_rep; + enum cxd2880_dvbt2_guard gi; + enum cxd2880_dvbt2_papr papr; + enum cxd2880_dvbt2_l1post_constell mod; + enum cxd2880_dvbt2_l1post_cr cr; + enum cxd2880_dvbt2_l1post_fec_type fec; + u32 l1_post_size; + u32 l1_post_info_size; + enum cxd2880_dvbt2_pp pp; + u8 tx_id_availability; + u16 cell_id; + u16 network_id; + u16 sys_id; + u8 num_frames; + u16 num_symbols; + u8 regen; + u8 post_ext; + u8 num_rf_freqs; + u8 rf_idx; + enum cxd2880_dvbt2_version t2_version; + u8 l1_post_scrambled; + u8 t2_base_lite; + u32 crc32; +}; + +struct cxd2880_dvbt2_plp { + u8 id; + enum cxd2880_dvbt2_plp_type type; + enum cxd2880_dvbt2_plp_payload payload; + u8 ff; + u8 first_rf_idx; + u8 first_frm_idx; + u8 group_id; + enum cxd2880_dvbt2_plp_constell constell; + enum cxd2880_dvbt2_plp_code_rate plp_cr; + u8 rot; + enum cxd2880_dvbt2_plp_fec fec; + u16 num_blocks_max; + u8 frm_int; + u8 til_len; + u8 til_type; + u8 in_band_a_flag; + u8 in_band_b_flag; + u16 rsvd; + enum cxd2880_dvbt2_plp_mode plp_mode; + u8 static_flag; + u8 static_padding_flag; +}; + +struct cxd2880_dvbt2_l1post { + u16 sub_slices_per_frame; + u8 num_plps; + u8 num_aux; + u8 aux_cfg_rfu; + u8 rf_idx; + u32 freq; + u8 fef_type; + u32 fef_length; + u8 fef_intvl; +}; + +struct cxd2880_dvbt2_ofdm { + u8 mixed; + u8 is_miso; + enum cxd2880_dvbt2_mode mode; + enum cxd2880_dvbt2_guard gi; + enum cxd2880_dvbt2_pp pp; + u8 bw_ext; + enum cxd2880_dvbt2_papr papr; + u16 num_symbols; +}; + +struct cxd2880_dvbt2_bbheader { + enum cxd2880_dvbt2_stream stream_input; + u8 is_single_input_stream; + u8 is_constant_coding_modulation; + u8 issy_indicator; + u8 null_packet_deletion; + u8 ext; + u8 input_stream_identifier; + u16 user_packet_length; + u16 data_field_length; + u8 sync_byte; + u32 issy; + enum cxd2880_dvbt2_plp_mode plp_mode; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c new file mode 100644 index 000000000000..5302ab0964c1 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_integ.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * integration layer common functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include <linux/ktime.h> +#include <linux/errno.h> + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_integ.h" + +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + ktime_t start; + u8 cpu_task_completed = 0; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_tnrdmd_init1(tnr_dmd); + if (ret) + return ret; + + start = ktime_get(); + + while (1) { + ret = + cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (cpu_task_completed) + break; + + if (ktime_to_ms(ktime_sub(ktime_get(), start)) > + CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) + return -ETIMEDOUT; + + usleep_range(CXD2880_TNRDMD_WAIT_INIT_INTVL, + CXD2880_TNRDMD_WAIT_INIT_INTVL + 1000); + } + + return cxd2880_tnrdmd_init2(tnr_dmd); +} + +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 1); + + return 0; +} + +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + if (atomic_read(&tnr_dmd->cancel) != 0) + return -ECANCELED; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h new file mode 100644 index 000000000000..7160225db8b9 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_integ.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * integration layer common interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_INTEG_H +#define CXD2880_INTEG_H + +#include "cxd2880_tnrdmd.h" + +#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT 500 +#define CXD2880_TNRDMD_WAIT_INIT_INTVL 10 + +#define CXD2880_TNRDMD_WAIT_AGC_STABLE 100 + +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd + *tnr_dmd); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c new file mode 100644 index 000000000000..9d932bccfa6c --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_io.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * register I/O interface functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_io.h" + +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data) +{ + if (!io) + return -EINVAL; + + return io->write_regs(io, tgt, sub_address, &data, 1); +} + +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask) +{ + int ret; + + if (!io) + return -EINVAL; + + if (mask == 0x00) + return 0; + + if (mask != 0xff) { + u8 rdata = 0x00; + + ret = io->read_regs(io, tgt, sub_address, &rdata, 1); + if (ret) + return ret; + + data = (data & mask) | (rdata & (mask ^ 0xff)); + } + + return io->write_reg(io, tgt, sub_address, data); +} + +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size) +{ + int ret; + int i; + + if (!io) + return -EINVAL; + + for (i = 0; i < size ; i++) { + ret = io->write_reg(io, tgt, reg_value[i].addr, + reg_value[i].value); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h new file mode 100644 index 000000000000..ba550278881d --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_io.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * register I/O interface definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_IO_H +#define CXD2880_IO_H + +#include "cxd2880_common.h" + +enum cxd2880_io_tgt { + CXD2880_IO_TGT_SYS, + CXD2880_IO_TGT_DMD +}; + +struct cxd2880_reg_value { + u8 addr; + u8 value; +}; + +struct cxd2880_io { + int (*read_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 *data, u32 size); + int (*write_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + const u8 *data, u32 size); + int (*write_reg)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 data); + void *if_object; + u8 i2c_address_sys; + u8 i2c_address_demod; + u8 slave_select; + void *user; +}; + +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data); + +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask); + +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size); +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h new file mode 100644 index 000000000000..2be207461847 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_spi.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_SPI_H +#define CXD2880_SPI_H + +#include "cxd2880_common.h" + +enum cxd2880_spi_mode { + CXD2880_SPI_MODE_0, + CXD2880_SPI_MODE_1, + CXD2880_SPI_MODE_2, + CXD2880_SPI_MODE_3 +}; + +struct cxd2880_spi { + int (*read)(struct cxd2880_spi *spi, u8 *data, + u32 size); + int (*write)(struct cxd2880_spi *spi, const u8 *data, + u32 size); + int (*write_read)(struct cxd2880_spi *spi, + const u8 *tx_data, u32 tx_size, + u8 *rx_data, u32 rx_size); + u32 flags; + void *user; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c new file mode 100644 index 000000000000..b8cbaa8d7aff --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_spi_device.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include <linux/spi/spi.h> + +#include "cxd2880_spi_device.h" + +static int cxd2880_spi_device_write(struct cxd2880_spi *spi, + const u8 *data, u32 size) +{ + struct cxd2880_spi_device *spi_device = NULL; + struct spi_message msg; + struct spi_transfer tx; + int result = 0; + + if (!spi || !spi->user || !data || size == 0) + return -EINVAL; + + spi_device = spi->user; + + memset(&tx, 0, sizeof(tx)); + tx.tx_buf = data; + tx.len = size; + + spi_message_init(&msg); + spi_message_add_tail(&tx, &msg); + result = spi_sync(spi_device->spi, &msg); + + if (result < 0) + return -EIO; + + return 0; +} + +static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi, + const u8 *tx_data, + u32 tx_size, + u8 *rx_data, + u32 rx_size) +{ + struct cxd2880_spi_device *spi_device = NULL; + int result = 0; + + if (!spi || !spi->user || !tx_data || + !tx_size || !rx_data || !rx_size) + return -EINVAL; + + spi_device = spi->user; + + result = spi_write_then_read(spi_device->spi, tx_data, + tx_size, rx_data, rx_size); + if (result < 0) + return -EIO; + + return 0; +} + +int +cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, + enum cxd2880_spi_mode mode, + u32 speed_hz) +{ + int result = 0; + struct spi_device *spi = spi_device->spi; + + switch (mode) { + case CXD2880_SPI_MODE_0: + spi->mode = SPI_MODE_0; + break; + case CXD2880_SPI_MODE_1: + spi->mode = SPI_MODE_1; + break; + case CXD2880_SPI_MODE_2: + spi->mode = SPI_MODE_2; + break; + case CXD2880_SPI_MODE_3: + spi->mode = SPI_MODE_3; + break; + default: + return -EINVAL; + } + + spi->max_speed_hz = speed_hz; + spi->bits_per_word = 8; + result = spi_setup(spi); + if (result != 0) { + pr_err("spi_setup failed %d\n", result); + return -EINVAL; + } + + return 0; +} + +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device) +{ + if (!spi || !spi_device) + return -EINVAL; + + spi->read = NULL; + spi->write = cxd2880_spi_device_write; + spi->write_read = cxd2880_spi_device_write_read; + spi->flags = 0; + spi->user = spi_device; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h new file mode 100644 index 000000000000..05e3a03de3a3 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_spi_device.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_SPI_DEVICE_H +#define CXD2880_SPI_DEVICE_H + +#include "cxd2880_spi.h" + +struct cxd2880_spi_device { + struct spi_device *spi; +}; + +int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, + enum cxd2880_spi_mode mode, + u32 speedHz); + +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device); + +#endif /* CXD2880_SPI_DEVICE_H */ diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c new file mode 100644 index 000000000000..4cf2d7cfd3f5 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -0,0 +1,3519 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common control functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include <media/dvb_frontend.h> +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt2.h" + +static const struct cxd2880_reg_value p_init1_seq[] = { + {0x11, 0x16}, {0x00, 0x10}, +}; + +static const struct cxd2880_reg_value rf_init1_seq1[] = { + {0x4f, 0x18}, {0x61, 0x00}, {0x71, 0x00}, {0x9d, 0x01}, + {0x7d, 0x02}, {0x8f, 0x01}, {0x8b, 0xc6}, {0x9a, 0x03}, + {0x1c, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init1_seq2[] = { + {0xb9, 0x07}, {0x33, 0x01}, {0xc1, 0x01}, {0xc4, 0x1e}, +}; + +static const struct cxd2880_reg_value rf_init1_seq3[] = { + {0x00, 0x10}, {0x51, 0x01}, {0xc5, 0x07}, {0x00, 0x11}, + {0x70, 0xe9}, {0x76, 0x0a}, {0x78, 0x32}, {0x7a, 0x46}, + {0x7c, 0x86}, {0x7e, 0xa4}, {0x00, 0x10}, {0xe1, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq4[] = { + {0x15, 0x00}, {0x00, 0x16} +}; + +static const struct cxd2880_reg_value rf_init1_seq5[] = { + {0x00, 0x00}, {0x25, 0x00} +}; + +static const struct cxd2880_reg_value rf_init1_seq6[] = { + {0x02, 0x00}, {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, + {0x8f, 0x16}, {0x67, 0x60}, {0x6a, 0x0f}, {0x6c, 0x17} +}; + +static const struct cxd2880_reg_value rf_init1_seq7[] = { + {0x00, 0xe2}, {0x41, 0xa0}, {0x4b, 0x68}, {0x00, 0x00}, + {0x21, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq8[] = { + {0x00, 0x10}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq9[] = { + {0x00, 0x10}, {0x14, 0x01}, {0x00, 0x00}, {0x26, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init2_seq1[] = { + {0x00, 0x14}, {0x1b, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init2_seq2[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, {0xd3, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune1_seq1[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune1_seq2[] = { + {0x62, 0x00}, {0x00, 0x15}, +}; + +static const struct cxd2880_reg_value x_tune2_seq1[] = { + {0x00, 0x1a}, {0x29, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq2[] = { + {0x62, 0x01}, {0x00, 0x11}, {0x2d, 0x00}, {0x2f, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune2_seq3[] = { + {0x00, 0x00}, {0x10, 0x00}, {0x21, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq4[] = { + {0x00, 0xe1}, {0x8a, 0x87}, +}; + +static const struct cxd2880_reg_value x_tune2_seq5[] = { + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune3_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0xa0}, + {0x00, 0x00}, {0x21, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune4_seq[] = { + {0x00, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep1_seq[] = { + {0x00, 0x00}, {0x57, 0x03}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq1[] = { + {0x00, 0x2d}, {0xb1, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq2[] = { + {0x00, 0x10}, {0xf4, 0x00}, {0xf3, 0x00}, {0xf2, 0x00}, + {0xf1, 0x00}, {0xf0, 0x00}, {0xef, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep3_seq[] = { + {0x00, 0x00}, {0xfd, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep4_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, + {0x26, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x22, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq4[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq5[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq4[] = { + {0x00, 0x00}, {0x2a, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq5[] = { + {0x00, 0x00}, {0x25, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq6[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq7[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value set_ts_pin_seq[] = { + {0x50, 0x3f}, {0x52, 0x1f}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq1[] = { + {0x00, 0x00}, {0x52, 0x00}, +}; + +static const struct cxd2880_reg_value set_ts_output_seq2[] = { + {0x00, 0x00}, {0xc3, 0x00}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq3[] = { + {0x00, 0x00}, {0xc3, 0x01}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq4[] = { + {0x00, 0x00}, {0x52, 0x1f}, + +}; + +static int p_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_TS: + data = 0x00; + break; + case CXD2880_TNRDMD_TSOUT_IF_SPI: + data = 0x01; + break; + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + data = 0x02; + break; + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + p_init1_seq, + ARRAY_SIZE(p_init1_seq)); + if (ret) + return ret; + + switch (tnr_dmd->chip_id) { + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: + data = 0x1a; + break; + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11: + data = 0x16; + break; + default: + return -ENOTTY; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; + + if (tnr_dmd->create_param.en_internal_ldo) + data = 0x01; + else + data = 0x00; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + switch (tnr_dmd->chip_id) { + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: + data = 0x01; + break; + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11: + data = 0x00; + break; + default: + return -ENOTTY; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x69, data); +} + +static int p_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[6] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = tnr_dmd->create_param.xosc_cap; + data[1] = tnr_dmd->create_param.xosc_i; + switch (tnr_dmd->create_param.xtal_share_type) { + case CXD2880_TNRDMD_XTAL_SHARE_NONE: + data[2] = 0x01; + data[3] = 0x00; + break; + case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: + data[2] = 0x00; + data[3] = 0x00; + break; + case CXD2880_TNRDMD_XTAL_SHARE_MASTER: + data[2] = 0x01; + data[3] = 0x01; + break; + case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: + data[2] = 0x00; + data[3] = 0x01; + break; + default: + return -EINVAL; + } + data[4] = 0x06; + data[5] = 0x00; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 6); +} + +static int p_init3(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + switch (tnr_dmd->diver_mode) { + case CXD2880_TNRDMD_DIVERMODE_SINGLE: + data[0] = 0x00; + break; + case CXD2880_TNRDMD_DIVERMODE_MAIN: + data[0] = 0x03; + break; + case CXD2880_TNRDMD_DIVERMODE_SUB: + data[0] = 0x02; + break; + default: + return -EINVAL; + } + + data[1] = 0x01; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1f, data, 2); +} + +static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[8] = { 0 }; + static const u8 rf_init1_cdata1[40] = { + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x04, 0x04, 0x04 + }; + + static const u8 rf_init1_cdata2[5] = {0xff, 0x00, 0x00, 0x00, 0x00}; + static const u8 rf_init1_cdata3[80] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09, + 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, + 0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0a, 0x03, 0xe0 + }; + + static const u8 rf_init1_cdata4[8] = { + 0x20, 0x20, 0x30, 0x41, 0x50, 0x5f, 0x6f, 0x80 + }; + + static const u8 rf_init1_cdata5[50] = { + 0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, + 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, + 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00, + 0x0e + }; + + u8 addr = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x01; + data[1] = 0x00; + data[2] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x21, data, 3); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + data[0] = 0x01; + data[1] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x17, data, 2); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1a, 0x06); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq1, + ARRAY_SIZE(rf_init1_seq1)); + if (ret) + return ret; + + data[0] = 0x00; + if (tnr_dmd->create_param.is_cxd2881gg && + tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) + data[1] = 0x00; + else + data[1] = 0x1f; + data[2] = 0x0a; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xb5, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq2, + ARRAY_SIZE(rf_init1_seq2)); + if (ret) + return ret; + + if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) { + data[0] = 0x34; + data[1] = 0x2c; + } else { + data[0] = 0x2f; + data[1] = 0x25; + } + data[2] = 0x15; + data[3] = 0x19; + data[4] = 0x1b; + data[5] = 0x15; + data[6] = 0x19; + data[7] = 0x1b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xd9, data, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + data[0] = 0x6c; + data[1] = 0x10; + data[2] = 0xa6; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 3); + if (ret) + return ret; + data[0] = 0x16; + data[1] = 0xa8; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x50, data, 2); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x22; + data[2] = 0x00; + data[3] = 0x88; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x62, data, 4); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x74, 0x75); + if (ret) + return ret; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x7f, rf_init1_cdata1, 40); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x16); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x71; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x23, 0x89); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, rf_init1_cdata2, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3a, rf_init1_cdata3, 80); + if (ret) + return ret; + + data[0] = 0x03; + data[1] = 0xe0; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbc, data, 2); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq3, + ARRAY_SIZE(rf_init1_seq3)); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + data[0] = 0x06; + data[1] = 0x07; + data[2] = 0x1a; + } else { + data[0] = 0x00; + data[1] = 0x08; + data[2] = 0x19; + } + data[3] = 0x0e; + data[4] = 0x09; + data[5] = 0x0e; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x12); + if (ret) + return ret; + for (addr = 0x10; addr < 0x9f; addr += 6) { + if (tnr_dmd->lna_thrs_tbl_air) { + u8 idx = 0; + + idx = (addr - 0x10) / 6; + data[0] = + tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on; + data[1] = + tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; + } + + data[0] = 0x00; + data[1] = 0x08; + if (tnr_dmd->create_param.stationary_use) + data[2] = 0x1a; + else + data[2] = 0x19; + data[3] = 0x0e; + data[4] = 0x09; + data[5] = 0x0e; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x13); + if (ret) + return ret; + for (addr = 0x10; addr < 0xcf; addr += 6) { + if (tnr_dmd->lna_thrs_tbl_cable) { + u8 idx = 0; + + idx = (addr - 0x10) / 6; + data[0] = + tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on; + data[1] = + tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbd, data, 2); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc4, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc9, rf_init1_cdata4, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x14); + if (ret) + return ret; + data[0] = 0x15; + data[1] = 0x18; + data[2] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq4, + ARRAY_SIZE(rf_init1_seq4)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, rf_init1_cdata5, 50); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq5, + ARRAY_SIZE(rf_init1_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq6, + ARRAY_SIZE(rf_init1_seq6)); + if (ret) + return ret; + + data[0] = 0x00; + data[1] = 0xfe; + data[2] = 0xee; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6e, data, 3); + if (ret) + return ret; + data[0] = 0xa1; + data[1] = 0x8b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8d, data, 2); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x77, data, 2); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, 0xaa); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq7, + ARRAY_SIZE(rf_init1_seq7)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq8, + ARRAY_SIZE(rf_init1_seq8)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq9, + ARRAY_SIZE(rf_init1_seq9)); +} + +static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[5] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + data[0] = 0x40; + data[1] = 0x40; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xea, data, 2); + if (ret) + return ret; + + usleep_range(1000, 2000); + + data[0] = 0x00; + if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) + data[1] = 0x00; + else + data[1] = 0x01; + data[2] = 0x01; + data[3] = 0x03; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data, 4); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init2_seq1, + ARRAY_SIZE(rf_init2_seq1)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init2_seq2, + ARRAY_SIZE(rf_init2_seq2)); +} + +static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, u32 freq_khz, + enum cxd2880_dtv_bandwidth bandwidth, + u8 is_cable, int shift_frequency_khz) +{ + u8 data[11] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune1_seq1, + ARRAY_SIZE(x_tune1_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[2] = 0x0e; + data[4] = 0x03; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; + + data[0] = 0x1f; + data[1] = 0x80; + data[2] = 0x18; + data[3] = 0x00; + data[4] = 0x07; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; + + usleep_range(1000, 2000); + + data[0] = 0x72; + data[1] = 0x81; + data[3] = 0x1d; + data[4] = 0x6f; + data[5] = 0x7e; + data[7] = 0x1c; + switch (sys) { + case CXD2880_DTV_SYS_DVBT: + data[2] = 0x94; + data[6] = 0x91; + break; + case CXD2880_DTV_SYS_DVBT2: + data[2] = 0x96; + data[6] = 0x93; + break; + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 8); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune1_seq2, + ARRAY_SIZE(x_tune1_seq2)); + if (ret) + return ret; + + data[0] = 0x03; + data[1] = 0xe2; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1e, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[0] = is_cable ? 0x01 : 0x00; + data[1] = 0x00; + data[2] = 0x6b; + data[3] = 0x4d; + + switch (bandwidth) { + case CXD2880_DTV_BW_1_7_MHZ: + data[4] = 0x03; + break; + case CXD2880_DTV_BW_5_MHZ: + case CXD2880_DTV_BW_6_MHZ: + data[4] = 0x00; + break; + case CXD2880_DTV_BW_7_MHZ: + data[4] = 0x01; + break; + case CXD2880_DTV_BW_8_MHZ: + data[4] = 0x02; + break; + default: + return -EINVAL; + } + + data[5] = 0x00; + + freq_khz += shift_frequency_khz; + + data[6] = (freq_khz >> 16) & 0x0f; + data[7] = (freq_khz >> 8) & 0xff; + data[8] = freq_khz & 0xff; + data[9] = 0xff; + data[10] = 0xfe; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, data, 11); +} + +static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_bandwidth bandwidth, + enum cxd2880_tnrdmd_clockmode clk_mode, + int shift_frequency_khz) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + + data[0] = 0x01; + data[1] = 0x0e; + data[2] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2d, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq1, + ARRAY_SIZE(x_tune2_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2c, data, 1); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x60, data[0]); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq2, + ARRAY_SIZE(x_tune2_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq3, + ARRAY_SIZE(x_tune2_seq3)); + if (ret) + return ret; + + if (shift_frequency_khz != 0) { + int shift_freq = 0; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0xe1); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; + + shift_freq = shift_frequency_khz * 1000; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = (shift_freq + 183 / 2) / 183; + else + shift_freq = (shift_freq - 183 / 2) / 183; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = (shift_freq + 178 / 2) / 178; + else + shift_freq = (shift_freq - 178 / 2) / 178; + break; + } + + shift_freq += + cxd2880_convert2s_complement((data[0] << 8) | data[1], 16); + + if (shift_freq > 32767) + shift_freq = 32767; + else if (shift_freq < -32768) + shift_freq = -32768; + + data[0] = (shift_freq >> 8) & 0xff; + data[1] = shift_freq & 0xff; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data, 1); + if (ret) + return ret; + + shift_freq = -shift_frequency_khz; + + if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 17578 / 2) / 17578; + else + shift_freq = + (shift_freq * 1000 - + 17578 / 2) / 17578; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 17090 / 2) / 17090; + else + shift_freq = + (shift_freq * 1000 - + 17090 / 2) / 17090; + break; + } + } else { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 35156 / 2) / 35156; + else + shift_freq = + (shift_freq * 1000 - + 35156 / 2) / 35156; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 34180 / 2) / 34180; + else + shift_freq = + (shift_freq * 1000 - + 34180 / 2) / 34180; + break; + } + } + + shift_freq += cxd2880_convert2s_complement(data[0], 8); + + if (shift_freq > 127) + shift_freq = 127; + else if (shift_freq < -128) + shift_freq = -128; + + data[0] = shift_freq & 0xff; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data[0]); + if (ret) + return ret; + } + + if (tnr_dmd->create_param.stationary_use) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq4, + ARRAY_SIZE(x_tune2_seq4)); + if (ret) + return ret; + } + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq5, + ARRAY_SIZE(x_tune2_seq5)); +} + +static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) +{ + u8 data[6] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune3_seq, + ARRAY_SIZE(x_tune3_seq)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) + memset(data, 0x01, sizeof(data)); + else + memset(data, 0x00, sizeof(data)); + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xef, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) + data[0] = 0x00; + else + data[0] = 0x01; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, data[0]); +} + +static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x01); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x02); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); +} + +static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep1_seq, + ARRAY_SIZE(x_sleep1_seq)); + if (ret) + return ret; + + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + data[2] = 0x03; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 3); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); +} + +static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep2_seq1, + ARRAY_SIZE(x_sleep2_seq1)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb2, &data, 1); + if (ret) + return ret; + + if ((data & 0x01) == 0x00) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep2_seq2, + ARRAY_SIZE(x_sleep2_seq2)); +} + +static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep3_seq, + ARRAY_SIZE(x_sleep3_seq)); +} + +static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep4_seq, + ARRAY_SIZE(x_sleep4_seq)); +} + +static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_clockmode clockmode) +{ + u8 data[4] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq1, + ARRAY_SIZE(spll_reset_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq2, + ARRAY_SIZE(spll_reset_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq3, + ARRAY_SIZE(spll_reset_seq3)); + if (ret) + return ret; + + switch (clockmode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data[0] = 0x00; + break; + + case CXD2880_TNRDMD_CLOCKMODE_B: + data[0] = 0x01; + break; + + case CXD2880_TNRDMD_CLOCKMODE_C: + data[0] = 0x02; + break; + + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data[0]); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x22, 0x00); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq4, + ARRAY_SIZE(spll_reset_seq4)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq5, + ARRAY_SIZE(spll_reset_seq5)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x26, data, 4); +} + +static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq1, + ARRAY_SIZE(t_power_x_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq2, + ARRAY_SIZE(t_power_x_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq3, + ARRAY_SIZE(t_power_x_seq3)); + if (ret) + return ret; + + if (on) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, 0x01); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq4, + ARRAY_SIZE(t_power_x_seq4)); + if (ret) + return ret; + } else { + data[0] = 0x03; + data[1] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2a, data, 2); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq5, + ARRAY_SIZE(t_power_x_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq6, + ARRAY_SIZE(t_power_x_seq6)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq7, + ARRAY_SIZE(t_power_x_seq7)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, data, 3); +} + +struct cxd2880_tnrdmd_ts_clk_cfg { + u8 srl_clk_mode; + u8 srl_duty_mode; + u8 ts_clk_period; +}; + +static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys) +{ + int ret; + u8 backwards_compatible = 0; + struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg; + u8 ts_rate_ctrl_off = 0; + u8 ts_in_off = 0; + u8 ts_clk_manaul_on = 0; + u8 data = 0; + + static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = { + { + {3, 1, 8,}, + {0, 2, 16,} + }, { + {1, 1, 8,}, + {2, 2, 16,} + } + }; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + if (tnr_dmd->is_ts_backwards_compatible_mode) { + backwards_compatible = 1; + ts_rate_ctrl_off = 1; + ts_in_off = 1; + } else { + backwards_compatible = 0; + ts_rate_ctrl_off = 0; + ts_in_off = 0; + } + + if (tnr_dmd->ts_byte_clk_manual_setting) { + ts_clk_manaul_on = 1; + ts_rate_ctrl_off = 0; + } + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd3, ts_rate_ctrl_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, ts_in_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xda, ts_clk_manaul_on, 0x01); + if (ret) + return ret; + + ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] + [tnr_dmd->srl_ts_clk_frq]; + + if (tnr_dmd->ts_byte_clk_manual_setting) + ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc4, ts_clk_cfg.srl_clk_mode, 0x03); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd1, ts_clk_cfg.srl_duty_mode, 0x03); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, 0xd9, + ts_clk_cfg.ts_clk_period); + if (ret) + return ret; + + data = backwards_compatible ? 0x00 : 0x01; + + if (sys == CXD2880_DTV_SYS_DVBT) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = + cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x66, data, 0x01); + } + + return ret; +} + +static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) +{ + int i; + int ret; + u8 data[65]; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + if (!pid_ftr_cfg) + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, 0x02); + + data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < 32; i++) { + if (pid_ftr_cfg->pid_cfg[i].is_en) { + data[1 + (i * 2)] = (pid_ftr_cfg->pid_cfg[i].pid >> 8) | 0x20; + data[2 + (i * 2)] = pid_ftr_cfg->pid_cfg[i].pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; + } + } + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, data, 65); +} + +static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + u8 i; + + if (!tnr_dmd) + return -EINVAL; + + for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + tnr_dmd->cfg_mem[i].tgt, + 0x00, tnr_dmd->cfg_mem[i].bank); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + tnr_dmd->cfg_mem[i].tgt, + tnr_dmd->cfg_mem[i].address, + tnr_dmd->cfg_mem[i].value, + tnr_dmd->cfg_mem[i].bit_mask); + if (ret) + return ret; + } + + return 0; +} + +static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, u8 value, u8 bit_mask) +{ + u8 i; + u8 value_stored = 0; + + if (!tnr_dmd) + return -EINVAL; + + for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { + if (value_stored == 0 && + tnr_dmd->cfg_mem[i].tgt == tgt && + tnr_dmd->cfg_mem[i].bank == bank && + tnr_dmd->cfg_mem[i].address == address) { + tnr_dmd->cfg_mem[i].value &= ~bit_mask; + tnr_dmd->cfg_mem[i].value |= (value & bit_mask); + + tnr_dmd->cfg_mem[i].bit_mask |= bit_mask; + + value_stored = 1; + } + } + + if (value_stored) + return 0; + + if (tnr_dmd->cfg_mem_last_entry < CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) { + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank = bank; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address = address; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value = (value & bit_mask); + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask = bit_mask; + tnr_dmd->cfg_mem_last_entry++; + } else { + return -ENOMEM; + } + + return 0; +} + +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param) +{ + if (!tnr_dmd || !io || !create_param) + return -EINVAL; + + memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd)); + + tnr_dmd->io = io; + tnr_dmd->create_param = *create_param; + + tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE; + tnr_dmd->diver_sub = NULL; + + tnr_dmd->srl_ts_clk_mod_cnts = 1; + tnr_dmd->en_fef_intmtnt_base = 1; + tnr_dmd->en_fef_intmtnt_lite = 1; + tnr_dmd->rf_lvl_cmpstn = NULL; + tnr_dmd->lna_thrs_tbl_air = NULL; + tnr_dmd->lna_thrs_tbl_cable = NULL; + atomic_set(&tnr_dmd->cancel, 0); + + return 0; +} + +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param) +{ + struct cxd2880_tnrdmd_create_param *main_param, *sub_param; + + if (!tnr_dmd_main || !io_main || !tnr_dmd_sub || !io_sub || + !create_param) + return -EINVAL; + + memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); + memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd)); + + main_param = &tnr_dmd_main->create_param; + sub_param = &tnr_dmd_sub->create_param; + + tnr_dmd_main->io = io_main; + tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN; + tnr_dmd_main->diver_sub = tnr_dmd_sub; + tnr_dmd_main->create_param.en_internal_ldo = + create_param->en_internal_ldo; + + main_param->ts_output_if = create_param->ts_output_if; + main_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_MASTER; + main_param->xosc_cap = create_param->xosc_cap_main; + main_param->xosc_i = create_param->xosc_i_main; + main_param->is_cxd2881gg = create_param->is_cxd2881gg; + main_param->stationary_use = create_param->stationary_use; + + tnr_dmd_sub->io = io_sub; + tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB; + tnr_dmd_sub->diver_sub = NULL; + + sub_param->en_internal_ldo = create_param->en_internal_ldo; + sub_param->ts_output_if = create_param->ts_output_if; + sub_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_SLAVE; + sub_param->xosc_cap = 0; + sub_param->xosc_i = create_param->xosc_i_sub; + sub_param->is_cxd2881gg = create_param->is_cxd2881gg; + sub_param->stationary_use = create_param->stationary_use; + + tnr_dmd_main->srl_ts_clk_mod_cnts = 1; + tnr_dmd_main->en_fef_intmtnt_base = 1; + tnr_dmd_main->en_fef_intmtnt_lite = 1; + tnr_dmd_main->rf_lvl_cmpstn = NULL; + tnr_dmd_main->lna_thrs_tbl_air = NULL; + tnr_dmd_main->lna_thrs_tbl_cable = NULL; + + tnr_dmd_sub->srl_ts_clk_mod_cnts = 1; + tnr_dmd_sub->en_fef_intmtnt_base = 1; + tnr_dmd_sub->en_fef_intmtnt_lite = 1; + tnr_dmd_sub->rf_lvl_cmpstn = NULL; + tnr_dmd_sub->lna_thrs_tbl_air = NULL; + tnr_dmd_sub->lna_thrs_tbl_cable = NULL; + + return 0; +} + +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd || tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN; + tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN; + tnr_dmd->frequency_khz = 0; + tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; + tnr_dmd->scan_mode = 0; + atomic_set(&tnr_dmd->cancel, 0); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN; + tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN; + tnr_dmd->diver_sub->frequency_khz = 0; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; + tnr_dmd->diver_sub->scan_mode = 0; + atomic_set(&tnr_dmd->diver_sub->cancel, 0); + } + + ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id); + if (ret) + return ret; + + if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id)) + return -ENOTTY; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub, + &tnr_dmd->diver_sub->chip_id); + if (ret) + return ret; + + if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id)) + return -ENOTTY; + } + + ret = p_init1(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init1(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + usleep_range(1000, 2000); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = p_init2(tnr_dmd); + if (ret) + return ret; + + usleep_range(5000, 6000); + + ret = p_init3(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init3(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = rf_init1(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = rf_init1(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 cpu_task_completed; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + ret = cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (!cpu_task_completed) + return -EINVAL; + + ret = rf_init2(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = rf_init2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = load_cfg_mem(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = load_cfg_mem(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; + + return ret; +} + +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed) +{ + u16 cpu_status = 0; + int ret; + + if (!tnr_dmd || !task_completed) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (cpu_status == 0) + *task_completed = 1; + else + *task_completed = 0; + + return ret; + } + if (cpu_status != 0) { + *task_completed = 0; + return ret; + } + + ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status); + if (ret) + return ret; + + if (cpu_status == 0) + *task_completed = 1; + else + *task_completed = 0; + + return ret; +} + +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir) +{ + u8 data; + enum cxd2880_tnrdmd_clockmode new_clk_mode = + CXD2880_TNRDMD_CLOCKMODE_A; + int shift_frequency_khz; + u8 cpu_task_completed; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (frequency_khz < 4000) + return -EINVAL; + + ret = cxd2880_tnrdmd_sleep(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, + 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, + &data, + 1); + if (ret) + return ret; + + switch (sys) { + case CXD2880_DTV_SYS_DVBT: + if (data == 0x00) { + ret = t_power_x(tnr_dmd, 1); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 1); + if (ret) + return ret; + } + } + break; + + case CXD2880_DTV_SYS_DVBT2: + if (data == 0x01) { + ret = t_power_x(tnr_dmd, 0); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 0); + if (ret) + return ret; + } + } + break; + + default: + return -EINVAL; + } + + ret = spll_reset(tnr_dmd, new_clk_mode); + if (ret) + return ret; + + tnr_dmd->clk_mode = new_clk_mode; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode); + if (ret) + return ret; + + tnr_dmd->diver_sub->clk_mode = new_clk_mode; + } + + ret = load_cfg_mem(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = load_cfg_mem(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + if (one_seg_opt) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 350; + } else { + if (one_seg_opt_shft_dir) + shift_frequency_khz = 350; + else + shift_frequency_khz = -350; + + if (tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) + shift_frequency_khz *= -1; + } + } else { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 150; + } else { + switch (tnr_dmd->create_param.xtal_share_type) { + case CXD2880_TNRDMD_XTAL_SHARE_NONE: + case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: + default: + shift_frequency_khz = 0; + break; + case CXD2880_TNRDMD_XTAL_SHARE_MASTER: + shift_frequency_khz = 150; + break; + case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: + shift_frequency_khz = -150; + break; + } + } + } + + ret = + x_tune1(tnr_dmd, sys, frequency_khz, bandwidth, + tnr_dmd->is_cable_input, shift_frequency_khz); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune1(tnr_dmd->diver_sub, sys, frequency_khz, + bandwidth, tnr_dmd->is_cable_input, + -shift_frequency_khz); + if (ret) + return ret; + } + + usleep_range(10000, 11000); + + ret = + cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (!cpu_task_completed) + return -EINVAL; + + ret = + x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, + shift_frequency_khz); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune2(tnr_dmd->diver_sub, bandwidth, + tnr_dmd->diver_sub->clk_mode, + -shift_frequency_khz); + if (ret) + return ret; + } + + if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) { + ret = set_ts_clk_mode_and_freq(tnr_dmd, sys); + } else { + struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg; + + if (tnr_dmd->pid_ftr_cfg_en) + pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg; + else + pid_ftr_cfg = NULL; + + ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg); + } + + return ret; +} + +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl); + if (ret) + return ret; + ret = x_tune4(tnr_dmd); + if (ret) + return ret; + } + + return cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); +} + +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) + return 0; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep1(tnr_dmd); + if (ret) + return ret; + } + + ret = x_sleep2(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + switch (tnr_dmd->sys) { + case CXD2880_DTV_SYS_DVBT: + ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; + + case CXD2880_DTV_SYS_DVBT2: + ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + ret = x_sleep3(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep3(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = x_sleep4(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep4(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->frequency_khz = 0; + tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->diver_sub->frequency_khz = 0; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; + } + + return 0; +} + +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value) +{ + int ret = 0; + u8 data[2] = { 0 }; + u8 need_sub_setting = 0; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (id) { + case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc4, + value ? 0x00 : 0x10, + 0x10); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x00 : 0x02, + 0x02); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x00 : 0x04, + 0x04); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xcb, + value ? 0x00 : 0x01, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_CONT: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc6, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSVALID_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc8, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc9, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x91, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_CURRENT: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x51, value, + 0x3f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x50, + value ? 0x80 : 0x00, + 0x80); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_PULLUP: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x50, value, + 0x3f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_FREQ: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 1) + return -EINVAL; + + tnr_dmd->srl_ts_clk_frq = + (enum cxd2880_tnrdmd_serial_ts_clk)value; + break; + + case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0xff) + return -EINVAL; + + tnr_dmd->ts_byte_clk_manual_setting = value; + + break; + + case CXD2880_TNRDMD_CFG_TS_PACKET_GAP: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 7) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xd6, value, + 0x07); + if (ret) + return ret; + + break; + + case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0; + + break; + + case CXD2880_TNRDMD_CFG_PWM_VALUE: + if (value < 0 || value > 0x1000) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x22, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + + data[0] = (value >> 8) & 0x1f; + data[1] = value & 0xff; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x23, + data[0], 0x1f); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x24, + data[1], 0xff); + if (ret) + return ret; + + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT: + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x48, data[0], + 0xff); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x49, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL: + data[0] = value & 0x07; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x4a, data[0], + 0x07); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL: + data[0] = (value & 0x07) << 3; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x4a, data[0], + 0x38); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE: + if (value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN || + value > CXD2880_TNRDMD_CLOCKMODE_C) + return -EINVAL; + tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value; + break; + + case CXD2880_TNRDMD_CFG_CABLE_INPUT: + tnr_dmd->is_cable_input = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE: + tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE: + tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x99, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9a, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9b, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9c, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9d, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9e, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST: + tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD: + if (value < 0 || value > 31) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x60, + value & 0x1f, 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD: + if (value < 0 || value > 7) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x6f, + value & 0x07, 0x07); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x20, 0x72, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x20, 0x6f, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT_PER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x5c, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_PER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x24, 0xdc, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + if (need_sub_setting && + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value); + + return ret; +} + +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x40 + id, mode, + 0x0f); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x43, + open_drain ? (1 << id) : 0, + 1 << id); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x44, + invert ? (1 << id) : 0, + 1 << id); + if (ret) + return ret; + + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x45, + en ? 0 : (1 << id), + 1 << id); +} + +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, u8 invert) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, + open_drain, invert); +} + +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd || !value) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x20, &data, 1); + if (ret) + return ret; + + *value = (data >> id) & 0x01; + + return 0; +} + +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); +} + +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x46, + value ? (1 << id) : 0, + 1 << id); +} + +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); +} + +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd || !value) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; + + *value = (data[0] << 8) | data[1]; + + return 0; +} + +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3c, data, 2); +} + +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + data[0] = clear_overflow_flag ? 0x02 : 0x00; + data[0] |= clear_underflow_flag ? 0x01 : 0x00; + data[1] = clear_buf ? 0x01 : 0x00; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9f, data, 2); +} + +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id) +{ + int ret; + u8 data = 0; + + if (!tnr_dmd || !chip_id) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xfd, &data, 1); + if (ret) + return ret; + + *chip_id = (enum cxd2880_tnrdmd_chip_id)data; + + return 0; +} + +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + tgt, address, value, bit_mask); + if (ret) + return ret; + + return set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); +} + +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + tnr_dmd->scan_mode = scan_mode_end; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + return cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, + scan_mode_end); + else + return 0; +} + +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) + return -ENOTTY; + + if (pid_ftr_cfg) { + tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg; + tnr_dmd->pid_ftr_cfg_en = 1; + } else { + tnr_dmd->pid_ftr_cfg_en = 0; + } + + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) + return pid_ftr_setting(tnr_dmd, pid_ftr_cfg); + else + return 0; +} + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) +{ + if (!tnr_dmd) + return -EINVAL; + + tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn; + + return 0; +} + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, + rf_lvl_cmpstn); +} + +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) +{ + if (!tnr_dmd) + return -EINVAL; + + tnr_dmd->lna_thrs_tbl_air = tbl_air; + tnr_dmd->lna_thrs_tbl_cable = tbl_cable; + + return 0; +} + +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, + tbl_air, tbl_cable); +} + +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS) + return -ENOTTY; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + if (en) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x50, ((value & 0x1f) | 0x80)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, (value & 0x1f)); + } else { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_pin_seq, + ARRAY_SIZE(set_ts_pin_seq)); + if (ret) + return ret; + + ret = load_cfg_mem(tnr_dmd); + } + + return ret; +} + +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_TS: + if (en) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq1, + ARRAY_SIZE(set_ts_output_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq2, + ARRAY_SIZE(set_ts_output_seq2)); + if (ret) + return ret; + } else { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq3, + ARRAY_SIZE(set_ts_output_seq3)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq4, + ARRAY_SIZE(set_ts_output_seq4)); + if (ret) + return ret; + } + break; + + case CXD2880_TNRDMD_TSOUT_IF_SPI: + break; + + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + break; + + default: + return -EINVAL; + } + + return 0; +} + +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_SPI: + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, &data, 1); + if (ret) + return ret; + + break; + case CXD2880_TNRDMD_TSOUT_IF_TS: + default: + break; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x01, 0x01); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h new file mode 100644 index 000000000000..9d809a251fc7 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h @@ -0,0 +1,365 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common control interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_H +#define CXD2880_TNRDMD_H + +#include <linux/atomic.h> + +#include "cxd2880_common.h" +#include "cxd2880_io.h" +#include "cxd2880_dtv.h" +#include "cxd2880_dvbt.h" +#include "cxd2880_dvbt2.h" + +#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100 + +#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\ +((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00))) + +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW 0x0001 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW 0x0002 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY 0x0004 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL 0x0008 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY 0x0010 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND 0x0020 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS 0x0040 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR 0x0100 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK 0x0200 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK 0x0400 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM 0x0800 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS 0x1000 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW 0x2000 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL 0x4000 + +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK 0x01 +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK 0x02 +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK 0x04 + +enum cxd2880_tnrdmd_chip_id { + CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00, + CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62, + CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a +}; + +#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \ + (((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \ + ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) + +enum cxd2880_tnrdmd_state { + CXD2880_TNRDMD_STATE_UNKNOWN, + CXD2880_TNRDMD_STATE_SLEEP, + CXD2880_TNRDMD_STATE_ACTIVE, + CXD2880_TNRDMD_STATE_INVALID +}; + +enum cxd2880_tnrdmd_divermode { + CXD2880_TNRDMD_DIVERMODE_SINGLE, + CXD2880_TNRDMD_DIVERMODE_MAIN, + CXD2880_TNRDMD_DIVERMODE_SUB +}; + +enum cxd2880_tnrdmd_clockmode { + CXD2880_TNRDMD_CLOCKMODE_UNKNOWN, + CXD2880_TNRDMD_CLOCKMODE_A, + CXD2880_TNRDMD_CLOCKMODE_B, + CXD2880_TNRDMD_CLOCKMODE_C +}; + +enum cxd2880_tnrdmd_tsout_if { + CXD2880_TNRDMD_TSOUT_IF_TS, + CXD2880_TNRDMD_TSOUT_IF_SPI, + CXD2880_TNRDMD_TSOUT_IF_SDIO +}; + +enum cxd2880_tnrdmd_xtal_share { + CXD2880_TNRDMD_XTAL_SHARE_NONE, + CXD2880_TNRDMD_XTAL_SHARE_EXTREF, + CXD2880_TNRDMD_XTAL_SHARE_MASTER, + CXD2880_TNRDMD_XTAL_SHARE_SLAVE +}; + +enum cxd2880_tnrdmd_spectrum_sense { + CXD2880_TNRDMD_SPECTRUM_NORMAL, + CXD2880_TNRDMD_SPECTRUM_INV +}; + +enum cxd2880_tnrdmd_cfg_id { + CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB, + CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI, + CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI, + CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI, + CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE, + CXD2880_TNRDMD_CFG_TSCLK_CONT, + CXD2880_TNRDMD_CFG_TSCLK_MASK, + CXD2880_TNRDMD_CFG_TSVALID_MASK, + CXD2880_TNRDMD_CFG_TSERR_MASK, + CXD2880_TNRDMD_CFG_TSERR_VALID_DIS, + CXD2880_TNRDMD_CFG_TSPIN_CURRENT, + CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL, + CXD2880_TNRDMD_CFG_TSPIN_PULLUP, + CXD2880_TNRDMD_CFG_TSCLK_FREQ, + CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL, + CXD2880_TNRDMD_CFG_TS_PACKET_GAP, + CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE, + CXD2880_TNRDMD_CFG_PWM_VALUE, + CXD2880_TNRDMD_CFG_INTERRUPT, + CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL, + CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL, + CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS, + CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS, + CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS, + CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE, + CXD2880_TNRDMD_CFG_CABLE_INPUT, + CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE, + CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE, + CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST, + CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, + CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, + CXD2880_TNRDMD_CFG_DVBT_PER_MES, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, +}; + +enum cxd2880_tnrdmd_lock_result { + CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT, + CXD2880_TNRDMD_LOCK_RESULT_LOCKED, + CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED +}; + +enum cxd2880_tnrdmd_gpio_mode { + CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00, + CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01, + CXD2880_TNRDMD_GPIO_MODE_INT = 0x02, + CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03, + CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04, + CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05, + CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06 +}; + +enum cxd2880_tnrdmd_serial_ts_clk { + CXD2880_TNRDMD_SERIAL_TS_CLK_FULL, + CXD2880_TNRDMD_SERIAL_TS_CLK_HALF +}; + +struct cxd2880_tnrdmd_cfg_mem { + enum cxd2880_io_tgt tgt; + u8 bank; + u8 address; + u8 value; + u8 bit_mask; +}; + +struct cxd2880_tnrdmd_pid_cfg { + u8 is_en; + u16 pid; +}; + +struct cxd2880_tnrdmd_pid_ftr_cfg { + u8 is_negative; + struct cxd2880_tnrdmd_pid_cfg pid_cfg[32]; +}; + +struct cxd2880_tnrdmd_lna_thrs { + u8 off_on; + u8 on_off; +}; + +struct cxd2880_tnrdmd_lna_thrs_tbl_air { + struct cxd2880_tnrdmd_lna_thrs thrs[24]; +}; + +struct cxd2880_tnrdmd_lna_thrs_tbl_cable { + struct cxd2880_tnrdmd_lna_thrs thrs[32]; +}; + +struct cxd2880_tnrdmd_create_param { + enum cxd2880_tnrdmd_tsout_if ts_output_if; + u8 en_internal_ldo; + enum cxd2880_tnrdmd_xtal_share xtal_share_type; + u8 xosc_cap; + u8 xosc_i; + u8 is_cxd2881gg; + u8 stationary_use; +}; + +struct cxd2880_tnrdmd_diver_create_param { + enum cxd2880_tnrdmd_tsout_if ts_output_if; + u8 en_internal_ldo; + u8 xosc_cap_main; + u8 xosc_i_main; + u8 xosc_i_sub; + u8 is_cxd2881gg; + u8 stationary_use; +}; + +struct cxd2880_tnrdmd { + struct cxd2880_tnrdmd *diver_sub; + struct cxd2880_io *io; + struct cxd2880_tnrdmd_create_param create_param; + enum cxd2880_tnrdmd_divermode diver_mode; + enum cxd2880_tnrdmd_clockmode fixed_clk_mode; + u8 is_cable_input; + u8 en_fef_intmtnt_base; + u8 en_fef_intmtnt_lite; + u8 blind_tune_dvbt2_first; + int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air; + struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable; + u8 srl_ts_clk_mod_cnts; + enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq; + u8 ts_byte_clk_manual_setting; + u8 is_ts_backwards_compatible_mode; + struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT]; + u8 cfg_mem_last_entry; + struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg; + u8 pid_ftr_cfg_en; + void *user; + enum cxd2880_tnrdmd_chip_id chip_id; + enum cxd2880_tnrdmd_state state; + enum cxd2880_tnrdmd_clockmode clk_mode; + u32 frequency_khz; + enum cxd2880_dtv_sys sys; + enum cxd2880_dtv_bandwidth bandwidth; + u8 scan_mode; + atomic_t cancel; +}; + +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param); + +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param); + +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed); + +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir); + +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl); + +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value); + +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert); + +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, + u8 invert); + +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value); + +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value); + +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf); + +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id); + +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask); + +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end); + +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value); + +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en); + +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h new file mode 100644 index 000000000000..fab55038b37b --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_driver_version.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * version information + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.4" + +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-01-17" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c new file mode 100644 index 000000000000..fe3c6f8b1b3e --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -0,0 +1,919 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control functions for DVB-T + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include <media/dvb_frontend.h> + +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" + +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x01}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03}, + {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = { + {0x00, 0x12}, {0x44, 0x00}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = { + {0x00, 0x11}, {0x87, 0xd2}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = { + {0x00, 0x00}, {0xfd, 0x01}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = { + {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = { + {0x00, 0x11}, {0x87, 0x04}, +}; + +static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) +{ + static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 }; + static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 }; + static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 }; + static const u8 ratectl_margin[2] = { 0x01, 0xf0 }; + static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 }; + static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa }; + static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 }; + + static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa}; + static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 }; + static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 }; + static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 }; + static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 }; + static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 }; + static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 }; + static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 }; + + static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55}; + static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c }; + static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 }; + static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 }; + static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 }; + static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa }; + static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 }; + + static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38}; + static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 }; + static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 }; + static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c }; + static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 }; + static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff }; + static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 }; + + static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99}; + static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa}; + static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d }; + static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 }; + static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 }; + static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 }; + static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 }; + static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc }; + static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 }; + const u8 *data = NULL; + u8 sst_data; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_ckffrq_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_ckffrq_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_ckffrq_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x65, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5d, 0x07); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + u8 data[2] = { 0x01, 0x01 }; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, data, 2); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, ratectl_margin, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq3, + ARRAY_SIZE(tune_dmd_setting_seq3)); + if (ret) + return ret; + } + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq4, + ARRAY_SIZE(tune_dmd_setting_seq4)); + if (ret) + return ret; + } + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = maxclkcnt_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = maxclkcnt_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = maxclkcnt_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x68, data, 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (bandwidth) { + case CXD2880_DTV_BW_8_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x35; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x34; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw8_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw8_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_7_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2f; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x2e; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw7_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw7_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_6_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x29; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2a; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw6_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw6_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_5_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x24; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x23; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw5_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw5_notch[2], 2); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq5, + ARRAY_SIZE(tune_dmd_setting_seq5)); +} + +static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq1, + ARRAY_SIZE(sleep_dmd_setting_seq1)); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq2, + ARRAY_SIZE(sleep_dmd_setting_seq2)); + + return ret; +} + +static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt_profile profile) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x67, + (profile == CXD2880_DVBT_PROFILE_HP) + ? 0x00 : 0x01); +} + +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT, + tune_param->center_freq_khz, + tune_param->bandwidth, 0, 0); + if (ret) + return ret; + + ret = + x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth, + tnr_dmd->clk_mode); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune_dvbt_demod_setting(tnr_dmd->diver_sub, + tune_param->bandwidth, + tnr_dmd->diver_sub->clk_mode); + if (ret) + return ret; + } + + return dvbt_set_profile(tnr_dmd, tune_param->profile); +} + +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT, + 0); + if (ret) + return ret; + + tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->sys = CXD2880_DTV_SYS_DVBT; + tnr_dmd->bandwidth = tune_param->bandwidth; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT; + tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_sleep_dvbt_demod_setting(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (sync_stat == 6) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (ts_lock) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (ts_lock) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } else if (!unlock_detected) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h new file mode 100644 index 000000000000..35d81ccc732b --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control interface for DVB-T + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT_H +#define CXD2880_TNRDMD_DVBT_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +struct cxd2880_dvbt_tune_param { + u32 center_freq_khz; + enum cxd2880_dtv_bandwidth bandwidth; + enum cxd2880_dvbt_profile profile; +}; + +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c new file mode 100644 index 000000000000..dd32004a12d8 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -0,0 +1,1217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt2.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control functions for DVB-T2 + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include <media/dvb_frontend.h> + +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" + +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x02}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5d, 0x0b}, +}; + +static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) +{ + static const u8 tsif_settings[2] = { 0x01, 0x01 }; + static const u8 init_settings[14] = { + 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, + 0x09, 0x9c, 0x0e, 0x4c + }; + static const u8 clk_mode_settings_a1[9] = { + 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c + }; + + static const u8 clk_mode_settings_b1[9] = { + 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d + }; + + static const u8 clk_mode_settings_c1[9] = { + 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e + }; + + static const u8 clk_mode_settings_a2[13] = { + 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49, + 0xcd, 0xcd, 0x1f, 0x5b + }; + + static const u8 clk_mode_settings_b2[13] = { + 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea, + 0xc8, 0xc8, 0x23, 0x91 + }; + + static const u8 clk_mode_settings_c2[13] = { + 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00, + 0xcd, 0xcd, 0x24, 0x95 + }; + + static const u8 clk_mode_settings_a3[5] = { + 0x0b, 0x6a, 0xc9, 0x03, 0x33 + }; + static const u8 clk_mode_settings_b3[5] = { + 0x01, 0x02, 0xe4, 0x03, 0x39 + }; + static const u8 clk_mode_settings_c3[5] = { + 0x01, 0x02, 0xeb, 0x03, 0x3b + }; + + static const u8 gtdofst[2] = { 0x3f, 0xff }; + + static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 }; + static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw8_sst_a[2] = { 0x06, 0x2a }; + static const u8 bw8_sst_b[2] = { 0x06, 0x29 }; + static const u8 bw8_sst_c[2] = { 0x06, 0x28 }; + static const u8 bw8_mrc_a[9] = { + 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x00 + }; + static const u8 bw8_mrc_b[9] = { + 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x55 + }; + static const u8 bw8_mrc_c[9] = { + 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x00 + }; + + static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 }; + static const u8 bw7_sst_a[2] = { 0x06, 0x23 }; + static const u8 bw7_sst_b[2] = { 0x06, 0x22 }; + static const u8 bw7_sst_c[2] = { 0x06, 0x21 }; + static const u8 bw7_mrc_a[9] = { + 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x92 + }; + static const u8 bw7_mrc_b[9] = { + 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa + }; + static const u8 bw7_mrc_c[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + + static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 }; + static const u8 bw6_sst_a[2] = { 0x06, 0x1c }; + static const u8 bw6_sst_b[2] = { 0x06, 0x1b }; + static const u8 bw6_sst_c[2] = { 0x06, 0x1a }; + static const u8 bw6_mrc_a[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + static const u8 bw6_mrc_b[9] = { + 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7 + }; + static const u8 bw6_mrc_c[9] = { + 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff + }; + + static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 }; + static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw5_sst_a[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_b[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_c[2] = { 0x06, 0x14 }; + static const u8 bw5_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66 + }; + static const u8 bw5_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55 + }; + static const u8 bw5_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc + }; + + static const u8 bw1_7_nomi_a[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_c[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_b[6] = { + 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03 + }; + static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b }; + static const u8 bw1_7_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f + }; + static const u8 bw1_7_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d + }; + static const u8 bw1_7_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d + }; + + const u8 *data = NULL; + const u8 *data2 = NULL; + const u8 *data3 = NULL; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, tsif_settings, 2); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8a, init_settings[0]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x90, init_settings[1]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, &init_settings[2], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2a); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, init_settings[4]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, init_settings[5]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x73, &init_settings[6], 4); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8f, &init_settings[10], 4); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_settings_a1; + data2 = clk_mode_settings_a2; + data3 = clk_mode_settings_a3; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_settings_b1; + data2 = clk_mode_settings_b2; + data3 = clk_mode_settings_b3; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_settings_c1; + data2 = clk_mode_settings_c2; + data3 = clk_mode_settings_c3; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, &data[0], 3); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, data[3]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x24, data[4]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, data[5]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, &data[6], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2d, data[8]); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2e, &data2[0], 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x35, &data2[6], 7); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, &data3[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x56, &data3[2], 3); + if (ret) + return ret; + + switch (bandwidth) { + case CXD2880_DTV_BW_8_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = gtdofst; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_7_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_6_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_5_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_1_7_MHZ: + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_nomi_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_nomi_c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x03); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xfd, 0x01); +} + +static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + static const u8 difint_clip[] = { + 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32 + }; + int ret = 0; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, difint_clip, 12); + } + + return ret; +} + +static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_profile profile) +{ + u8 t2_mode_tune_mode = 0; + u8 seq_not2_dtime = 0; + u8 dtime1 = 0; + u8 dtime2 = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + switch (tnr_dmd->clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + dtime1 = 0x27; + dtime2 = 0x0c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + dtime1 = 0x2c; + dtime2 = 0x0d; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + dtime1 = 0x2e; + dtime2 = 0x0e; + break; + default: + return -EINVAL; + } + + switch (profile) { + case CXD2880_DVBT2_PROFILE_BASE: + t2_mode_tune_mode = 0x01; + seq_not2_dtime = dtime2; + break; + + case CXD2880_DVBT2_PROFILE_LITE: + t2_mode_tune_mode = 0x05; + seq_not2_dtime = dtime1; + break; + + case CXD2880_DVBT2_PROFILE_ANY: + t2_mode_tune_mode = 0x00; + seq_not2_dtime = dtime1; + break; + + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2e); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, t2_mode_tune_mode); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2c, seq_not2_dtime); +} + +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN && + tune_param->profile == CXD2880_DVBT2_PROFILE_ANY) + return -ENOTTY; + + ret = + cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2, + tune_param->center_freq_khz, + tune_param->bandwidth, 0, 0); + if (ret) + return ret; + + ret = + x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth, + tnr_dmd->clk_mode); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub, + tune_param->bandwidth, + tnr_dmd->diver_sub->clk_mode); + if (ret) + return ret; + } + + ret = dvbt2_set_profile(tnr_dmd, tune_param->profile); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile); + if (ret) + return ret; + } + + if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) + ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0); + else + ret = + cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0, + (u8)(tune_param->data_plp_id)); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + u8 en_fef_intmtnt_ctrl = 1; + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (tune_param->profile) { + case CXD2880_DVBT2_PROFILE_BASE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base; + break; + case CXD2880_DVBT2_PROFILE_LITE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite; + break; + case CXD2880_DVBT2_PROFILE_ANY: + if (tnr_dmd->en_fef_intmtnt_base && + tnr_dmd->en_fef_intmtnt_lite) + en_fef_intmtnt_ctrl = 1; + else + en_fef_intmtnt_ctrl = 0; + break; + default: + return -EINVAL; + } + + ret = + cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, + CXD2880_DTV_SYS_DVBT2, + en_fef_intmtnt_ctrl); + if (ret) + return ret; + + tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2; + tnr_dmd->bandwidth = tune_param->bandwidth; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2; + tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_sleep_dvbt2_demod_setting(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (sync_stat == 6) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (ts_lock) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (ts_lock) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } else if (!unlock_detected) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x23); + if (ret) + return ret; + + if (!auto_plp) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xaf, plp_id); + if (ret) + return ret; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xad, auto_plp ? 0x00 : 0x01); +} + +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + struct cxd2880_dvbt2_ofdm ofdm; + static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0}; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) + return 0; + + ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); + if (ret) + return ret; + + if (!ofdm.mixed) + return 0; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, data, 12); +} + +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid) +{ + int ret; + + u8 data; + + if (!tnr_dmd || !l1_post_valid) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) + return ret; + + *l1_post_valid = data & 0x01; + + return ret; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h new file mode 100644 index 000000000000..7108e3540093 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt2.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control interface for DVB-T2 + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT2_H +#define CXD2880_TNRDMD_DVBT2_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +enum cxd2880_tnrdmd_dvbt2_tune_info { + CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK, + CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID +}; + +struct cxd2880_dvbt2_tune_param { + u32 center_freq_khz; + enum cxd2880_dtv_bandwidth bandwidth; + u16 data_plp_id; + enum cxd2880_dvbt2_profile profile; + enum cxd2880_tnrdmd_dvbt2_tune_info tune_info; +}; + +#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xffff + +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id); + +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c new file mode 100644 index 000000000000..604580bf7cf7 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -0,0 +1,1878 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt2_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" + +#include <media/dvb_math.h> + +static const int ref_dbm_1000[4][8] = { + {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, + {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000}, + {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000}, + {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000}, +}; + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) +{ + u8 data; + int ret; + + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &data, sizeof(data)); + if (ret) + return ret; + + *sync_stat = data & 0x07; + *ts_lock_stat = ((data & 0x20) ? 1 : 0); + *unlock_detected = ((data & 0x10) ? 1 : 0); + + if (*sync_stat == 0x07) + return -EAGAIN; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected) +{ + u8 ts_lock_stat = 0; + + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); +} + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) +{ + u8 data[4]; + u32 ctl_val = 0; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x30, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ctl_val = + ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8) + | (data[3]); + *offset = cxd2880_convert2s_complement(ctl_val, 28); + + switch (tnr_dmd->bandwidth) { + case CXD2880_DTV_BW_1_7_MHZ: + *offset = -1 * ((*offset) / 582); + break; + case CXD2880_DTV_BW_5_MHZ: + case CXD2880_DTV_BW_6_MHZ: + case CXD2880_DTV_BW_7_MHZ: + case CXD2880_DTV_BW_8_MHZ: + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940); + break; + default: + return -EINVAL; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) +{ + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, + offset); +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre) +{ + u8 data[37]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 version = 0; + enum cxd2880_dvbt2_profile profile; + int ret; + + if (!tnr_dmd || !l1_pre) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x61, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + slvt_unfreeze_reg(tnr_dmd); + + l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0]; + l1_pre->bw_ext = data[1] & 0x01; + l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07); + l1_pre->s2 = data[3] & 0x0f; + l1_pre->l1_rep = data[4] & 0x01; + l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07); + l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f); + l1_pre->mod = + (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f); + l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03); + l1_pre->fec = + (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03); + l1_pre->l1_post_size = (data[10] & 0x03) << 16; + l1_pre->l1_post_size |= (data[11]) << 8; + l1_pre->l1_post_size |= (data[12]); + l1_pre->l1_post_info_size = (data[13] & 0x03) << 16; + l1_pre->l1_post_info_size |= (data[14]) << 8; + l1_pre->l1_post_info_size |= (data[15]); + l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f); + l1_pre->tx_id_availability = data[17]; + l1_pre->cell_id = (data[18] << 8); + l1_pre->cell_id |= (data[19]); + l1_pre->network_id = (data[20] << 8); + l1_pre->network_id |= (data[21]); + l1_pre->sys_id = (data[22] << 8); + l1_pre->sys_id |= (data[23]); + l1_pre->num_frames = data[24]; + l1_pre->num_symbols = (data[25] & 0x0f) << 8; + l1_pre->num_symbols |= data[26]; + l1_pre->regen = data[27] & 0x07; + l1_pre->post_ext = data[28] & 0x01; + l1_pre->num_rf_freqs = data[29] & 0x07; + l1_pre->rf_idx = data[30] & 0x07; + version = (data[31] & 0x03) << 2; + version |= (data[32] & 0xc0) >> 6; + l1_pre->t2_version = (enum cxd2880_dvbt2_version)version; + l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5; + l1_pre->t2_base_lite = (data[32] & 0x10) >> 4; + l1_pre->crc32 = (data[33] << 24); + l1_pre->crc32 |= (data[34] << 16); + l1_pre->crc32 |= (data[35] << 8); + l1_pre->crc32 |= data[36]; + + if (profile == CXD2880_DVBT2_PROFILE_BASE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_BASE_S2_M1K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M1K; + break; + case CXD2880_DVBT2_BASE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_BASE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_BASE_S2_M16K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M32K; + break; + default: + return -EAGAIN; + } + } else if (profile == CXD2880_DVBT2_PROFILE_LITE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_LITE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_LITE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + default: + return -EAGAIN; + } + } else { + return -EAGAIN; + } + + l1_pre->mixed = l1_pre->s2 & 0x01; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver) +{ + u8 data[2]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 version = 0; + int ret; + + if (!tnr_dmd || !ver) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + version = ((data[0] & 0x03) << 2); + version |= ((data[1] & 0xc0) >> 6); + *ver = (enum cxd2880_dvbt2_version)version; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm) +{ + u8 data[5]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !ofdm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + + ret = -EAGAIN; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub, + ofdm); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ofdm->mixed = ((data[0] & 0x20) ? 1 : 0); + ofdm->is_miso = ((data[0] & 0x10) >> 4); + ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07); + ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4); + ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07); + ofdm->bw_ext = (data[2] & 0x10) >> 4; + ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f); + ofdm->num_symbols = (data[3] << 8) | data[4]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps) +{ + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !num_plps) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc1, num_plps, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (*num_plps == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EINVAL; + } + + if (!plp_ids) { + slvt_unfreeze_reg(tnr_dmd); + return 0; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc2, + plp_ids, + ((*num_plps > 62) ? + 62 : *num_plps)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (*num_plps > 62) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0c); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, plp_ids + 62, + *num_plps - 62); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info) +{ + u8 data[20]; + u8 addr = 0; + u8 index = 0; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !plp_info) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!l1_post_ok) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa9; + else + addr = 0x96; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + if (type == CXD2880_DVBT2_PLP_COMMON && !data[13]) + return -EAGAIN; + + plp_info->id = data[index++]; + plp_info->type = + (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07); + plp_info->payload = + (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f); + plp_info->ff = data[index++] & 0x01; + plp_info->first_rf_idx = data[index++] & 0x07; + plp_info->first_frm_idx = data[index++]; + plp_info->group_id = data[index++]; + plp_info->plp_cr = + (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07); + plp_info->constell = + (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07); + plp_info->rot = data[index++] & 0x01; + plp_info->fec = + (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03); + plp_info->num_blocks_max = (data[index++] & 0x03) << 8; + plp_info->num_blocks_max |= data[index++]; + plp_info->frm_int = data[index++]; + plp_info->til_len = data[index++]; + plp_info->til_type = data[index++] & 0x01; + + plp_info->in_band_a_flag = data[index++] & 0x01; + plp_info->rsvd = data[index++] << 8; + plp_info->rsvd |= data[index++]; + + plp_info->in_band_b_flag = + (plp_info->rsvd & 0x8000) >> 15; + plp_info->plp_mode = + (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2); + plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1; + plp_info->static_padding_flag = plp_info->rsvd & 0x0001; + plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error) +{ + u8 data; + int ret; + + if (!tnr_dmd || !plp_error) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if ((data & 0x01) == 0x00) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc0, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *plp_error = data & 0x01; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change) +{ + u8 data; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !l1_change) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + *l1_change = data & 0x01; + if (*l1_change) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x22); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x16, 0x01); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + slvt_unfreeze_reg(tnr_dmd); + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post) +{ + u8 data[16]; + int ret; + + if (!tnr_dmd || !l1_post) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, data, sizeof(data)); + if (ret) + return ret; + + if (!(data[0] & 0x01)) + return -EAGAIN; + + l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8; + l1_post->sub_slices_per_frame |= data[2]; + l1_post->num_plps = data[3]; + l1_post->num_aux = data[4] & 0x0f; + l1_post->aux_cfg_rfu = data[5]; + l1_post->rf_idx = data[6] & 0x07; + l1_post->freq = data[7] << 24; + l1_post->freq |= data[8] << 16; + l1_post->freq |= data[9] << 8; + l1_post->freq |= data[10]; + l1_post->fef_type = data[11] & 0x0f; + l1_post->fef_length = data[12] << 16; + l1_post->fef_length |= data[13] << 8; + l1_post->fef_length |= data[14]; + l1_post->fef_intvl = data[15]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 data[14]; + u8 addr = 0; + int ret; + + if (!tnr_dmd || !bbheader) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!ts_lock) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + u8 l1_post_ok; + u8 data; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0x51; + else + addr = 0x42; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + bbheader->stream_input = + (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); + bbheader->is_single_input_stream = (data[0] >> 5) & 0x01; + bbheader->is_constant_coding_modulation = + (data[0] >> 4) & 0x01; + bbheader->issy_indicator = (data[0] >> 3) & 0x01; + bbheader->null_packet_deletion = (data[0] >> 2) & 0x01; + bbheader->ext = data[0] & 0x03; + + bbheader->input_stream_identifier = data[1]; + bbheader->plp_mode = + (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM : + CXD2880_DVBT2_PLP_MODE_NM; + bbheader->data_field_length = (data[4] << 8) | data[5]; + + if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + bbheader->user_packet_length = + (data[6] << 8) | data[7]; + bbheader->sync_byte = data[8]; + bbheader->issy = 0; + } else { + bbheader->user_packet_length = 0; + bbheader->sync_byte = 0; + bbheader->issy = + (data[11] << 16) | (data[12] << 8) | data[13]; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 l1_post_ok = 0; + u8 data[4]; + u8 addr = 0; + + int ret; + + if (!tnr_dmd || !ts_rate_bps) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!ts_lock) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xba; + else + addr = 0xa7; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if ((data[0] & 0x80) == 0x00) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa6; + else + addr = 0xaa; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 4); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) | + (data[2] << 8) | data[3]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 early_unlock = 0; + u8 data = 0; + int ret; + + if (!tnr_dmd || !sense) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, + &early_unlock); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + + ret = -EAGAIN; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *sense = + (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : + CXD2880_TNRDMD_SPECTRUM_NORMAL; + + return 0; +} + +static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 data[2]; + int ret; + + if (!tnr_dmd || !reg_value) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *reg_value = (data[0] << 8) | data[1]; + + return ret; +} + +static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) +{ + if (!tnr_dmd || !snr) + return -EINVAL; + + if (reg_value == 0) + return -EAGAIN; + + if (reg_value > 10876) + reg_value = 10876; + + *snr = intlog10(reg_value) - intlog10(12600 - reg_value); + *snr = (*snr + 839) / 1678 + 32000; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) +{ + u16 reg_value = 0; + int ret; + + if (!tnr_dmd || !snr) + return -EINVAL; + + *snr = -1000 * 1000; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (ret) + return ret; + + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); + } else { + int snr_main = 0; + int snr_sub = 0; + + ret = + cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main, + &snr_sub); + } + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) +{ + u16 reg_value = 0; + u32 reg_value_sum = 0; + int ret; + + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; + + *snr = -1000 * 1000; + *snr_main = -1000 * 1000; + *snr_sub = -1000 * 1000; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); +} + +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) +{ + int ret; + u8 data[3]; + + if (!tnr_dmd || !pen) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x39, data, sizeof(data)); + if (ret) + return ret; + + if (!(data[0] & 0x01)) + return -EAGAIN; + + *pen = ((data[1] << 8) | data[2]); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + int ret; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + s8 diff_upper = 0; + + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x34, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); + else + num = (int)(trl_ctl_val - trcg_nominal_rate); + + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; + + den >>= 1; + + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm) +{ + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, + ppm); +} + +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell *qam) +{ + u8 data; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !qam) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } else { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9e, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate) +{ + u8 data; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !code_rate) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb0, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } else { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile) +{ + u8 data; + int ret; + + if (!tnr_dmd || !profile) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, &data, sizeof(data)); + if (ret) + return ret; + + if (data & 0x02) { + if (data & 0x01) + *profile = CXD2880_DVBT2_PROFILE_LITE; + else + *profile = CXD2880_DVBT2_PROFILE_BASE; + } else { + ret = -EAGAIN; + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub, + profile); + + return ret; + } + + return 0; +} + +static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) +{ + enum cxd2880_dvbt2_plp_constell qam; + enum cxd2880_dvbt2_plp_code_rate code_rate; + int prel; + int temp_ssi = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, + &code_rate); + if (ret) + return ret; + + if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256) + return -EINVAL; + + prel = rf_lvl - ref_dbm_1000[qam][code_rate]; + + if (prel < -15000) + temp_ssi = 0; + else if (prel < 0) + temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; + else if (prel < 20000) + temp_ssi = (((4 * prel) + 500) / 1000) + 10; + else if (prel < 35000) + temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; + else + temp_ssi = 100; + + *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); + if (ret) + return ret; + + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); + if (ret) + return ret; + + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h new file mode 100644 index 000000000000..5b7adaceff22 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt2_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT2_MON_H +#define CXD2880_TNRDMD_DVBT2_MON_H + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_dvbt2.h" + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre); + +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver); + +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm); + +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps); + +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info); + +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error); + +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change); + +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post); + +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader); + +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps); + +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); + +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); + +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, + int *snr_sub); + +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen); + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); + +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell + *qam); + +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate); + +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile); + +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c new file mode 100644 index 000000000000..fedc3b4a2fa0 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" + +#include <media/dvb_math.h> + +static const int ref_dbm_1000[3][5] = { + {-93000, -91000, -90000, -89000, -88000}, + {-87000, -85000, -84000, -83000, -82000}, + {-82000, -80000, -78000, -77000, -76000}, +}; + +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) +{ + u8 rdata = 0x00; + int ret; + + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &rdata, 1); + if (ret) + return ret; + + *unlock_detected = (rdata & 0x10) ? 1 : 0; + *sync_stat = rdata & 0x07; + *ts_lock_stat = (rdata & 0x20) ? 1 : 0; + + if (*sync_stat == 0x07) + return -EAGAIN; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected) +{ + u8 ts_lock_stat = 0; + + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); +} + +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard) +{ + u8 rdata = 0x00; + int ret; + + if (!tnr_dmd || !mode || !guard) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub, + mode, guard); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, &rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03); + *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) +{ + u8 rdata[4]; + u32 ctl_val = 0; + int ret; + + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, rdata, 4); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ctl_val = + ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) | + (rdata[3]); + *offset = cxd2880_convert2s_complement(ctl_val, 29); + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) +{ + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, + offset); +} + +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info) +{ + u8 rdata[7]; + u8 cell_id_ok = 0; + int ret; + + if (!tnr_dmd || !info) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub, + info); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, rdata, 7); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x11); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd5, &cell_id_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + info->constellation = + (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03); + info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07); + info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07); + info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07); + info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03); + info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03); + info->fnum = (rdata[2] >> 6) & 0x03; + info->length_indicator = rdata[2] & 0x3f; + info->cell_id = (rdata[3] << 8) | rdata[4]; + info->reserved_even = rdata[5] & 0x3f; + info->reserved_odd = rdata[6] & 0x3f; + + info->cell_id_ok = cell_id_ok & 0x01; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) +{ + u8 rdata[3]; + int ret; + + if (!tnr_dmd || !pen) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, rdata, 3); + if (ret) + return ret; + + if (!(rdata[0] & 0x01)) + return -EAGAIN; + + *pen = (rdata[1] << 8) | rdata[2]; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd || !sense) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1c, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *sense = + (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : + CXD2880_TNRDMD_SPECTRUM_NORMAL; + + return ret; +} + +static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) +{ + u8 rdata[2]; + int ret; + + if (!tnr_dmd || !reg_value) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, rdata, 2); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *reg_value = (rdata[0] << 8) | rdata[1]; + + return ret; +} + +static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) +{ + if (!tnr_dmd || !snr) + return -EINVAL; + + if (reg_value == 0) + return -EAGAIN; + + if (reg_value > 4996) + reg_value = 4996; + + *snr = intlog10(reg_value) - intlog10(5350 - reg_value); + *snr = (*snr + 839) / 1678 + 28500; + + return 0; +} + +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) +{ + u16 reg_value = 0; + int ret; + + if (!tnr_dmd || !snr) + return -EINVAL; + + *snr = -1000 * 1000; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + ret = dvbt_read_snr_reg(tnr_dmd, ®_value); + if (ret) + return ret; + + ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); + } else { + int snr_main = 0; + int snr_sub = 0; + + ret = + cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main, + &snr_sub); + } + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) +{ + u16 reg_value = 0; + u32 reg_value_sum = 0; + int ret; + + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; + + *snr = -1000 * 1000; + *snr_main = -1000 * 1000; + *snr_sub = -1000 * 1000; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = dvbt_read_snr_reg(tnr_dmd, ®_value); + if (!ret) { + ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); + if (!ret) { + ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); +} + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + s8 diff_upper = 0; + int ret; + + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x21, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); + else + num = (int)(trl_ctl_val - trcg_nominal_rate); + + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; + + den >>= 1; + + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); +} + +static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) +{ + struct cxd2880_dvbt_tpsinfo tps; + int prel; + int temp_ssi = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); + if (ret) + return ret; + + if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 || + tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) + return -EINVAL; + + prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp]; + + if (prel < -15000) + temp_ssi = 0; + else if (prel < 0) + temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; + else if (prel < 20000) + temp_ssi = (((4 * prel) + 500) / 1000) + 10; + else if (prel < 35000) + temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; + else + temp_ssi = 100; + + *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); + if (ret) + return ret; + + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); + if (ret) + return ret; + + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 sync = 0; + u8 tslock = 0; + u8 early_unlock = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, + &early_unlock); + if (ret) + return ret; + + if (sync != 6) + return -EAGAIN; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h new file mode 100644 index 000000000000..f4c31725fa48 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT_MON_H +#define CXD2880_TNRDMD_DVBT_MON_H + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_dvbt.h" + +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info); + +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen); + +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); + +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); + +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub); + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); + +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c new file mode 100644 index 000000000000..3d8012c18e3f --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd_mon.h" + +static const u8 rf_lvl_seq[2] = { + 0x80, 0x00, +}; + +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) +{ + u8 rdata[2]; + int ret; + + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x01); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x5b, rf_lvl_seq, 2); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, rdata, 2); + if (ret) + return ret; + + if (rdata[0] || rdata[1]) + return -EINVAL; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, rdata, 2); + if (ret) + return ret; + + *rf_lvl_db = + cxd2880_convert2s_complement((rdata[0] << 3) | + ((rdata[1] & 0xe0) >> 5), 11); + + *rf_lvl_db *= 125; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x00); + if (ret) + return ret; + + if (tnr_dmd->rf_lvl_cmpstn) + ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db); + + return ret; +} + +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) +{ + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); +} + +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd || !status) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; + + *status = (data[0] << 8) | data[1]; + + return 0; +} + +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status) +{ + if (!tnr_dmd || !status) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, + status); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h new file mode 100644 index 000000000000..570360925f87 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_MON_H +#define CXD2880_TNRDMD_MON_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status); + +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status); +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c new file mode 100644 index 000000000000..d474dc1b05da --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -0,0 +1,1947 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_top.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include <linux/spi/spi.h> + +#include <media/dvb_frontend.h> +#include <media/dvb_math.h> + +#include "cxd2880.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" +#include "cxd2880_integ.h" +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_devio_spi.h" +#include "cxd2880_spi_device.h" +#include "cxd2880_tnrdmd_driver_version.h" + +struct cxd2880_priv { + struct cxd2880_tnrdmd tnrdmd; + struct spi_device *spi; + struct cxd2880_io regio; + struct cxd2880_spi_device spi_device; + struct cxd2880_spi cxd2880_spi; + struct cxd2880_dvbt_tune_param dvbt_tune_param; + struct cxd2880_dvbt2_tune_param dvbt2_tune_param; + struct mutex *spi_mutex; /* For SPI access exclusive control */ + unsigned long pre_ber_update; + unsigned long pre_ber_interval; + unsigned long post_ber_update; + unsigned long post_ber_interval; + unsigned long ucblock_update; + unsigned long ucblock_interval; + enum fe_status s; +}; + +static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, u32 *pre_bit_count) +{ + u8 rdata[2]; + int ret; + + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x39, rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if ((rdata[0] & 0x01) == 0) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x22, rdata, 2); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + *pre_bit_err = (rdata[0] << 8) | rdata[1]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + slvt_unfreeze_reg(tnrdmd); + + *pre_bit_count = ((rdata[0] & 0x07) == 0) ? + 256 : (0x1000 << (rdata[0] & 0x07)); + + return 0; +} + +static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, + u32 *pre_bit_count) +{ + u32 period_exp = 0; + u32 n_ldpc = 0; + u8 data[5]; + int ret; + + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (!(data[0] & 0x01)) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + *pre_bit_err = + ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == + CXD2880_DVBT2_FEC_LDPC_16K) + n_ldpc = 16200; + else + n_ldpc = 64800; + slvt_unfreeze_reg(tnrdmd); + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, data, 1); + if (ret) + return ret; + + period_exp = data[0] & 0x0f; + + *pre_bit_count = (1U << period_exp) * n_ldpc; + + return 0; +} + +static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) +{ + u8 rdata[3]; + u32 bit_error = 0; + u32 period_exp = 0; + int ret; + + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x40) == 0) + return -EAGAIN; + + *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x60, rdata, 1); + if (ret) + return ret; + + period_exp = (rdata[0] & 0x1f); + + if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8)) + return -EAGAIN; + + *post_bit_count = (1U << period_exp) * 204 * 8; + + return 0; +} + +static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) +{ + u32 period_exp = 0; + u32 n_bch = 0; + u8 data[3]; + enum cxd2880_dvbt2_plp_fec plp_fec_type = + CXD2880_DVBT2_FEC_LDPC_16K; + enum cxd2880_dvbt2_plp_code_rate plp_code_rate = + CXD2880_DVBT2_R1_2; + int ret; + static const u16 n_bch_bits_lookup[2][8] = { + {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, + {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} + }; + + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, data, 3); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (!(data[0] & 0x40)) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + + *post_bit_err = + ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + plp_code_rate = + (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); + + slvt_unfreeze_reg(tnrdmd); + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x72, data, 1); + if (ret) + return ret; + + period_exp = data[0] & 0x0f; + + if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K || + plp_code_rate > CXD2880_DVBT2_R2_5) + return -EAGAIN; + + n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; + + if (*post_bit_err > ((1U << period_exp) * n_bch)) + return -EAGAIN; + + *post_bit_count = (1U << period_exp) * n_bch; + + return 0; +} + +static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) +{ + u8 rdata[3]; + int ret; + + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x01) == 0) + return -EAGAIN; + + *block_err = (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x5c, rdata, 1); + if (ret) + return ret; + + *block_count = 1U << (rdata[0] & 0x0f); + + if ((*block_count == 0) || (*block_err > *block_count)) + return -EAGAIN; + + return 0; +} + +static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) +{ + u8 rdata[3]; + int ret; + + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x01) == 0) + return -EAGAIN; + + *block_err = (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x24); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, rdata, 1); + if (ret) + return ret; + + *block_count = 1U << (rdata[0] & 0x0f); + + if ((*block_count == 0) || (*block_err > *block_count)) + return -EAGAIN; + + return 0; +} + +static void cxd2880_release(struct dvb_frontend *fe) +{ + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg.\n"); + return; + } + priv = fe->demodulator_priv; + kfree(priv); +} + +static int cxd2880_init(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct cxd2880_tnrdmd_create_param create_param; + + if (!fe) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI; + create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE; + create_param.en_internal_ldo = 1; + create_param.xosc_cap = 18; + create_param.xosc_i = 8; + create_param.stationary_use = 1; + + mutex_lock(priv->spi_mutex); + if (priv->tnrdmd.io != &priv->regio) { + ret = cxd2880_tnrdmd_create(&priv->tnrdmd, + &priv->regio, &create_param); + if (ret) { + mutex_unlock(priv->spi_mutex); + pr_info("cxd2880 tnrdmd create failed %d\n", ret); + return ret; + } + } + ret = cxd2880_integ_init(&priv->tnrdmd); + if (ret) { + mutex_unlock(priv->spi_mutex); + pr_err("cxd2880 integ init failed %d\n", ret); + return ret; + } + mutex_unlock(priv->spi_mutex); + + pr_debug("OK.\n"); + + return ret; +} + +static int cxd2880_sleep(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); + mutex_unlock(priv->spi_mutex); + + pr_debug("tnrdmd_sleep ret %d\n", ret); + + return ret; +} + +static int cxd2880_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + int level = 0; + + if (!fe || !strength) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT || + c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level); + } else { + pr_debug("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + level /= 125; + /* + * level should be between -105dBm and -30dBm. + * E.g. they should be between: + * -105000/125 = -840 and -30000/125 = -240 + */ + level = clamp(level, -840, -240); + /* scale value to 0x0000-0xffff */ + *strength = ((level + 840) * 0xffff) / (-240 + 840); + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int ret; + int snrvalue = 0; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !snr) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd, + &snrvalue); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd, + &snrvalue); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + if (snrvalue < 0) + snrvalue = 0; + *snr = snrvalue; + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !ucblocks) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd, + ucblocks); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd, + ucblocks); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + +static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv; + struct cxd2880_dvbt_tpsinfo info; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125}; + static const int denominator_tbl[4] = {125664, 129472, 137088, 152320}; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + bw = priv->dvbt_tune_param.bandwidth; + + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, + &info); + if (ret) { + pr_err("tps monitor error ret = %d\n", ret); + info.hierarchy = CXD2880_DVBT_HIERARCHY_NON; + info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK; + info.guard = CXD2880_DVBT_GUARD_1_4; + info.rate_hp = CXD2880_DVBT_CODERATE_1_2; + info.rate_lp = CXD2880_DVBT_CODERATE_1_2; + } + + if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) { + pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = 875 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + } else { + u8 data = 0; + struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (!ret) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x67, &data, 1); + if (ret) + data = 0x00; + } else { + data = 0x00; + } + + if (data & 0x01) { /* Low priority */ + pre_ber_rate = + 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_lp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] * + bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + } else { /* High priority */ + pre_ber_rate = + 63000000 * bw * 2 / denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] * + bw * 2 / denominator_tbl[info.guard]; + } + } + + mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, + mes_exp == 8 ? 0 : mes_exp - 12); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, + mes_exp); + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_PER_MES, + mes_exp); + + return 0; +} + +static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv; + struct cxd2880_dvbt2_l1pre l1pre; + struct cxd2880_dvbt2_l1post l1post; + struct cxd2880_dvbt2_plp plp; + struct cxd2880_dvbt2_bbheader bbheader; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + u32 term_a = 0; + u32 term_b = 0; + u32 denominator = 0; + static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76}; + static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1}; + static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32}; + static const u32 kbch_tbl[2][8] = { + {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232}, + {32128, 38608, 42960, 48328, 51568, 53760, 0, 0} + }; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + bw = priv->dvbt2_tune_param.bandwidth; + + ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); + if (ret) { + pr_info("l1 pre error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, &plp); + if (ret) { + pr_info("plp info error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post); + if (ret) { + pr_info("l1 post error\n"); + goto error_ber_setting; + } + + term_a = + (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) * + (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048; + + if (l1pre.mixed && l1post.fef_intvl) { + term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) / + l1post.fef_intvl; + } else { + term_b = 0; + } + + switch (bw) { + case CXD2880_DTV_BW_1_7_MHZ: + denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131; + break; + case CXD2880_DTV_BW_5_MHZ: + denominator = ((term_a + term_b) * 7 + 20) / 40; + break; + case CXD2880_DTV_BW_6_MHZ: + denominator = ((term_a + term_b) * 7 + 24) / 48; + break; + case CXD2880_DTV_BW_7_MHZ: + denominator = ((term_a + term_b) + 4) / 8; + break; + case CXD2880_DTV_BW_8_MHZ: + default: + denominator = ((term_a + term_b) * 7 + 32) / 64; + break; + } + + if (plp.til_type && plp.til_len) { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) / + plp.til_len; + } else { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + } + + post_ber_rate = pre_ber_rate; + + mes_exp = intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, + mes_exp); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, + mes_exp); + + ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &bbheader); + if (ret) { + pr_info("bb header error\n"); + goto error_ucblock_setting; + } + + if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + if (!bbheader.issy_indicator) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 752) / 1504; + } else { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 764) / 1528; + } + } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) / + 1496; + } else { + pr_info("plp mode is not Normal or HEM\n"); + goto error_ucblock_setting; + } + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, + mes_exp); + + return 0; + +error_ber_setting: + priv->pre_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0); + + priv->post_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0); + +error_ucblock_setting: + priv->ucblock_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8); + + return 0; +} + +static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); +} + +static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE && + tune_param->profile != CXD2880_DVBT2_PROFILE_LITE) + return -EINVAL; + + ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); +} + +static int cxd2880_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct dtv_frontend_properties *c; + struct cxd2880_priv *priv; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[0].uvalue = 0; + c->pre_bit_error.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[0].uvalue = 0; + c->pre_bit_count.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_error.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_count.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].uvalue = 0; + c->block_error.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].uvalue = 0; + c->block_count.len = 1; + + switch (c->bandwidth_hz) { + case 1712000: + bw = CXD2880_DTV_BW_1_7_MHZ; + break; + case 5000000: + bw = CXD2880_DTV_BW_5_MHZ; + break; + case 6000000: + bw = CXD2880_DTV_BW_6_MHZ; + break; + case 7000000: + bw = CXD2880_DTV_BW_7_MHZ; + break; + case 8000000: + bw = CXD2880_DTV_BW_8_MHZ; + break; + default: + return -EINVAL; + } + + priv->s = 0; + + pr_info("sys:%d freq:%d bw:%d\n", + c->delivery_system, c->frequency, bw); + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT; + priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000; + priv->dvbt_tune_param.bandwidth = bw; + priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP; + ret = cxd2880_dvbt_tune(&priv->tnrdmd, + &priv->dvbt_tune_param); + } else if (c->delivery_system == SYS_DVBT2) { + priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2; + priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000; + priv->dvbt2_tune_param.bandwidth = bw; + priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id; + priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE; + ret = cxd2880_dvbt2_tune(&priv->tnrdmd, + &priv->dvbt2_tune_param); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + pr_info("tune result %d\n", ret); + + return ret; +} + +static int cxd2880_get_stats(struct dvb_frontend *fe, + enum fe_status status) +{ + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + u32 pre_bit_err = 0, pre_bit_count = 0; + u32 post_bit_err = 0, post_bit_count = 0; + u32 block_err = 0, block_count = 0; + int ret; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + if (!(status & FE_HAS_LOCK)) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + return 0; + } + + if (time_after(jiffies, priv->pre_ber_update)) { + priv->pre_ber_update = + jiffies + msecs_to_jiffies(priv->pre_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += pre_bit_err; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += pre_bit_count; + } else { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("pre_bit_error_t failed %d\n", ret); + } + } + + if (time_after(jiffies, priv->post_ber_update)) { + priv->post_ber_update = + jiffies + msecs_to_jiffies(priv->post_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += post_bit_err; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += post_bit_count; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + pr_debug("post_bit_err_t %d\n", ret); + } + } + + if (time_after(jiffies, priv->ucblock_update)) { + priv->ucblock_update = + jiffies + msecs_to_jiffies(priv->ucblock_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t2(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + if (!ret) { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += block_err; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += block_count; + } else { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_block_err_t %d\n", ret); + } + } + + return 0; +} + +static int cxd2880_check_l1post_plp(struct dvb_frontend *fe) +{ + u8 valid = 0; + u8 plp_not_found; + int ret; + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd, + &valid); + if (ret) + return ret; + + if (!valid) + return -EAGAIN; + + ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd, + &plp_not_found); + if (ret) + return ret; + + if (plp_not_found) { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; + } else { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; + } + + return 0; +} + +static int cxd2880_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + int ret; + u8 sync = 0; + u8 lock = 0; + u8 unlock = 0; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !status) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + *status = 0; + + if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) { + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); + } else { + pr_err("invalid system"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + + mutex_unlock(priv->spi_mutex); + if (ret) { + pr_err("failed. sys = %d\n", priv->tnrdmd.sys); + return ret; + } + + if (sync == 6) { + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER; + } + if (lock) + *status |= FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + } + + pr_debug("status %d\n", *status); + + if (priv->s == 0 && (*status & FE_HAS_LOCK)) { + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_set_ber_per_period_t(fe); + priv->s = *status; + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_check_l1post_plp(fe); + if (!ret) { + ret = cxd2880_set_ber_per_period_t2(fe); + priv->s = *status; + } + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + } + + cxd2880_get_stats(fe, *status); + return 0; +} + +static int cxd2880_tune(struct dvb_frontend *fe, + bool retune, + unsigned int mode_flags, + unsigned int *delay, + enum fe_status *status) +{ + int ret; + + if (!fe || !delay || !status) { + pr_err("invalid arg."); + return -EINVAL; + } + + if (retune) { + ret = cxd2880_set_frontend(fe); + if (ret) { + pr_err("cxd2880_set_frontend failed %d\n", ret); + return ret; + } + } + + *delay = HZ / 5; + + return cxd2880_read_status(fe, status); +} + +static int cxd2880_get_frontend_t(struct dvb_frontend *fe, + struct dtv_frontend_properties *c) +{ + int ret; + struct cxd2880_priv *priv = NULL; + enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K; + enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32; + struct cxd2880_dvbt_tpsinfo tps; + enum cxd2880_tnrdmd_spectrum_sense sense; + u16 snr = 0; + int strength = 0; + + if (!fe || !c) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd, + &mode, &guard); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (mode) { + case CXD2880_DVBT_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case CXD2880_DVBT_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + c->transmission_mode = TRANSMISSION_MODE_2K; + pr_debug("transmission mode is invalid %d\n", mode); + break; + } + switch (guard) { + case CXD2880_DVBT_GUARD_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case CXD2880_DVBT_GUARD_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case CXD2880_DVBT_GUARD_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case CXD2880_DVBT_GUARD_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("guard interval is invalid %d\n", + guard); + break; + } + } else { + c->transmission_mode = TRANSMISSION_MODE_2K; + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("ModeGuard err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (tps.hierarchy) { + case CXD2880_DVBT_HIERARCHY_NON: + c->hierarchy = HIERARCHY_NONE; + break; + case CXD2880_DVBT_HIERARCHY_1: + c->hierarchy = HIERARCHY_1; + break; + case CXD2880_DVBT_HIERARCHY_2: + c->hierarchy = HIERARCHY_2; + break; + case CXD2880_DVBT_HIERARCHY_4: + c->hierarchy = HIERARCHY_4; + break; + default: + c->hierarchy = HIERARCHY_NONE; + pr_debug("TPSInfo hierarchy is invalid %d\n", + tps.hierarchy); + break; + } + + switch (tps.rate_hp) { + case CXD2880_DVBT_CODERATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CXD2880_DVBT_CODERATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CXD2880_DVBT_CODERATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CXD2880_DVBT_CODERATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CXD2880_DVBT_CODERATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + default: + c->code_rate_HP = FEC_NONE; + pr_debug("TPSInfo rateHP is invalid %d\n", + tps.rate_hp); + break; + } + switch (tps.rate_lp) { + case CXD2880_DVBT_CODERATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CXD2880_DVBT_CODERATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CXD2880_DVBT_CODERATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CXD2880_DVBT_CODERATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CXD2880_DVBT_CODERATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + default: + c->code_rate_LP = FEC_NONE; + pr_debug("TPSInfo rateLP is invalid %d\n", + tps.rate_lp); + break; + } + switch (tps.constellation) { + case CXD2880_DVBT_CONSTELLATION_QPSK: + c->modulation = QPSK; + break; + case CXD2880_DVBT_CONSTELLATION_16QAM: + c->modulation = QAM_16; + break; + case CXD2880_DVBT_CONSTELLATION_64QAM: + c->modulation = QAM_64; + break; + default: + c->modulation = QPSK; + pr_debug("TPSInfo constellation is invalid %d\n", + tps.constellation); + break; + } + } else { + c->hierarchy = HIERARCHY_NONE; + c->code_rate_HP = FEC_NONE; + c->code_rate_LP = FEC_NONE; + c->modulation = QPSK; + pr_debug("TPS info err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (sense) { + case CXD2880_TNRDMD_SPECTRUM_NORMAL: + c->inversion = INVERSION_OFF; + break; + case CXD2880_TNRDMD_SPECTRUM_INV: + c->inversion = INVERSION_ON; + break; + default: + c->inversion = INVERSION_OFF; + pr_debug("spectrum sense is invalid %d\n", sense); + break; + } + } else { + c->inversion = INVERSION_OFF; + pr_debug("spectrum_sense %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); + mutex_unlock(priv->spi_mutex); + if (!ret) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("mon_rf_lvl %d\n", ret); + } + + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = snr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_snr %d\n", ret); + } + + return 0; +} + +static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, + struct dtv_frontend_properties *c) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct cxd2880_dvbt2_l1pre l1pre; + enum cxd2880_dvbt2_plp_code_rate coderate; + enum cxd2880_dvbt2_plp_constell qam; + enum cxd2880_tnrdmd_spectrum_sense sense; + u16 snr = 0; + int strength = 0; + + if (!fe || !c) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (l1pre.fft_mode) { + case CXD2880_DVBT2_M2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case CXD2880_DVBT2_M8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + case CXD2880_DVBT2_M4K: + c->transmission_mode = TRANSMISSION_MODE_4K; + break; + case CXD2880_DVBT2_M1K: + c->transmission_mode = TRANSMISSION_MODE_1K; + break; + case CXD2880_DVBT2_M16K: + c->transmission_mode = TRANSMISSION_MODE_16K; + break; + case CXD2880_DVBT2_M32K: + c->transmission_mode = TRANSMISSION_MODE_32K; + break; + default: + c->transmission_mode = TRANSMISSION_MODE_2K; + pr_debug("L1Pre fft_mode is invalid %d\n", + l1pre.fft_mode); + break; + } + switch (l1pre.gi) { + case CXD2880_DVBT2_G1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case CXD2880_DVBT2_G1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case CXD2880_DVBT2_G1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case CXD2880_DVBT2_G1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + case CXD2880_DVBT2_G1_128: + c->guard_interval = GUARD_INTERVAL_1_128; + break; + case CXD2880_DVBT2_G19_128: + c->guard_interval = GUARD_INTERVAL_19_128; + break; + case CXD2880_DVBT2_G19_256: + c->guard_interval = GUARD_INTERVAL_19_256; + break; + default: + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("L1Pre guard interval is invalid %d\n", + l1pre.gi); + break; + } + } else { + c->transmission_mode = TRANSMISSION_MODE_2K; + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("L1Pre err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &coderate); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (coderate) { + case CXD2880_DVBT2_R1_2: + c->fec_inner = FEC_1_2; + break; + case CXD2880_DVBT2_R3_5: + c->fec_inner = FEC_3_5; + break; + case CXD2880_DVBT2_R2_3: + c->fec_inner = FEC_2_3; + break; + case CXD2880_DVBT2_R3_4: + c->fec_inner = FEC_3_4; + break; + case CXD2880_DVBT2_R4_5: + c->fec_inner = FEC_4_5; + break; + case CXD2880_DVBT2_R5_6: + c->fec_inner = FEC_5_6; + break; + default: + c->fec_inner = FEC_NONE; + pr_debug("CodeRate is invalid %d\n", coderate); + break; + } + } else { + c->fec_inner = FEC_NONE; + pr_debug("CodeRate %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &qam); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (qam) { + case CXD2880_DVBT2_QPSK: + c->modulation = QPSK; + break; + case CXD2880_DVBT2_QAM16: + c->modulation = QAM_16; + break; + case CXD2880_DVBT2_QAM64: + c->modulation = QAM_64; + break; + case CXD2880_DVBT2_QAM256: + c->modulation = QAM_256; + break; + default: + c->modulation = QPSK; + pr_debug("QAM is invalid %d\n", qam); + break; + } + } else { + c->modulation = QPSK; + pr_debug("QAM %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (sense) { + case CXD2880_TNRDMD_SPECTRUM_NORMAL: + c->inversion = INVERSION_OFF; + break; + case CXD2880_TNRDMD_SPECTRUM_INV: + c->inversion = INVERSION_ON; + break; + default: + c->inversion = INVERSION_OFF; + pr_debug("spectrum sense is invalid %d\n", sense); + break; + } + } else { + c->inversion = INVERSION_OFF; + pr_debug("SpectrumSense %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); + mutex_unlock(priv->spi_mutex); + if (!ret) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("mon_rf_lvl %d\n", ret); + } + + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = snr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_snr %d\n", ret); + } + + return 0; +} + +static int cxd2880_get_frontend(struct dvb_frontend *fe, + struct dtv_frontend_properties *props) +{ + int ret; + + if (!fe || !props) { + pr_err("invalid arg."); + return -EINVAL; + } + + pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2880_get_frontend_t(fe, props); + break; + case SYS_DVBT2: + ret = cxd2880_get_frontend_t2(fe, props); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { + .info = { + .name = "Sony CXD2880", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + 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_2G_MODULATION | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS, + }, + .delsys = { SYS_DVBT, SYS_DVBT2 }, + + .release = cxd2880_release, + .init = cxd2880_init, + .sleep = cxd2880_sleep, + .tune = cxd2880_tune, + .set_frontend = cxd2880_set_frontend, + .get_frontend = cxd2880_get_frontend, + .read_status = cxd2880_read_status, + .read_ber = cxd2880_read_ber, + .read_signal_strength = cxd2880_read_signal_strength, + .read_snr = cxd2880_read_snr, + .read_ucblocks = cxd2880_read_ucblocks, + .get_frontend_algo = cxd2880_get_frontend_algo, +}; + +struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg) +{ + int ret; + enum cxd2880_tnrdmd_chip_id chipid = + CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + static struct cxd2880_priv *priv; + u8 data = 0; + + if (!fe) { + pr_err("invalid arg.\n"); + return NULL; + } + + priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL); + if (!priv) + return NULL; + + priv->spi = cfg->spi; + priv->spi_mutex = cfg->spi_mutex; + priv->spi_device.spi = cfg->spi; + + memcpy(&fe->ops, &cxd2880_dvbt_t2_ops, + sizeof(struct dvb_frontend_ops)); + + ret = cxd2880_spi_device_initialize(&priv->spi_device, + CXD2880_SPI_MODE_0, + 55000000); + if (ret) { + pr_err("spi_device_initialize failed. %d\n", ret); + kfree(priv); + return NULL; + } + + ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, + &priv->spi_device); + if (ret) { + pr_err("spi_device_create_spi failed. %d\n", ret); + kfree(priv); + return NULL; + } + + ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); + if (ret) { + pr_err("io_spi_create failed. %d\n", ret); + kfree(priv); + return NULL; + } + ret = priv->regio.write_reg(&priv->regio, + CXD2880_IO_TGT_SYS, 0x00, 0x00); + if (ret) { + pr_err("set bank to 0x00 failed.\n"); + kfree(priv); + return NULL; + } + ret = priv->regio.read_regs(&priv->regio, + CXD2880_IO_TGT_SYS, 0xfd, &data, 1); + if (ret) { + pr_err("read chip id failed.\n"); + kfree(priv); + return NULL; + } + + chipid = (enum cxd2880_tnrdmd_chip_id)data; + if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X && + chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) { + pr_err("chip id invalid.\n"); + kfree(priv); + return NULL; + } + + fe->demodulator_priv = priv; + pr_info("CXD2880 driver version: Ver %s\n", + CXD2880_TNRDMD_DRIVER_VERSION); + + return fe; +} +EXPORT_SYMBOL(cxd2880_attach); + +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver"); +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 64f49c8eb1fb..ee7af34979ed 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -1285,7 +1285,7 @@ int dib0090_gain_control(struct dvb_frontend *fe) #endif if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ - if (ABS(adc_error) < 50 || state->agc_step++ > 5) { + if (abs(adc_error) < 50 || state->agc_step++ > 5) { #ifdef CONFIG_STANDARD_DAB if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { @@ -1754,7 +1754,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front *tune_state = CT_TUNER_STEP_1; } else { /* the minimum was what we have seen in the step before */ - if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { + if (abs(state->adc_diff) > abs(state->min_adc_diff)) { dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff); state->step--; } diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 90ace707a80d..902af482448e 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -809,7 +809,7 @@ static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) { u32 internal = dib7000p_get_internal_freq(state); s32 unit_khz_dds_val; - u32 abs_offset_khz = ABS(offset_khz); + u32 abs_offset_khz = abs(offset_khz); u32 dds = state->cfg.bw->ifreq & 0x1ffffff; u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); if (internal == 0) { diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index e64014f338fb..6f35173d2968 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2677,7 +2677,7 @@ static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) { s16 unit_khz_dds_val; - u32 abs_offset_khz = ABS(offset_khz); + u32 abs_offset_khz = abs(offset_khz); u32 dds = state->cfg.pll->ifreq & 0x1ffffff; u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); u8 ratio; diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c index d981233e458f..70119c79ac2b 100644 --- a/drivers/media/dvb-frontends/dibx000_common.c +++ b/drivers/media/dvb-frontends/dibx000_common.c @@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) { - strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); + strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->algo = algo; i2c_adap->algo_data = NULL; i2c_set_adapdata(i2c_adap, mst); diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h index 8784af962eba..12b58f5c677d 100644 --- a/drivers/media/dvb-frontends/dibx000_common.h +++ b/drivers/media/dvb-frontends/dibx000_common.h @@ -223,8 +223,6 @@ struct dvb_frontend_parametersContext { #define FE_CALLBACK_TIME_NEVER 0xffffffff -#define ABS(x) ((x < 0) ? (-x) : (x)) - #define DATA_BUS_ACCESS_MODE_8BIT 0x01 #define DATA_BUS_ACCESS_MODE_16BIT 0x02 #define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10 diff --git a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h b/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h deleted file mode 100644 index 2b3af247a1f1..000000000000 --- a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - I2C API, implementation depends on board specifics - - Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Trident Microsystems nor Hauppauge Computer Works - nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - This module encapsulates I2C access.In some applications several devices - share one I2C bus. If these devices have the same I2C address some kind - off "switch" must be implemented to ensure error free communication with - one device. In case such a "switch" is used, the device ID can be used - to implement control over this "switch". -*/ - -#ifndef __BSPI2C_H__ -#define __BSPI2C_H__ - -#include "bsp_types.h" - -/* - * This structure contains the I2C address, the device ID and a user_data pointer. - * The user_data pointer can be used for application specific purposes. - */ -struct i2c_device_addr { - u16 i2c_addr; /* The I2C address of the device. */ - u16 i2c_dev_id; /* The device identifier. */ - void *user_data; /* User data pointer */ -}; - - -/* -* \def IS_I2C_10BIT( addr ) -* \brief Determine if I2C address 'addr' is a 10 bits address or not. -* \param addr The I2C address. -* \return int. -* \retval 0 if address is not a 10 bits I2C address. -* \retval 1 if address is a 10 bits I2C address. -*/ -#define IS_I2C_10BIT(addr) \ - (((addr) & 0xF8) == 0xF0) - -/*------------------------------------------------------------------------------ -Exported FUNCTIONS -------------------------------------------------------------------------------*/ - -/* -* \fn drxbsp_i2c_init() -* \brief Initialize I2C communication module. -* \return drx_status_t Return status. -* \retval 0 Initialization successful. -* \retval -EIO Initialization failed. -*/ - drx_status_t drxbsp_i2c_init(void); - -/* -* \fn drxbsp_i2c_term() -* \brief Terminate I2C communication module. -* \return drx_status_t Return status. -* \retval 0 Termination successful. -* \retval -EIO Termination failed. -*/ - drx_status_t drxbsp_i2c_term(void); - -/* -* \fn drx_status_t drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr, -* u16 w_count, -* u8 *wData, -* struct i2c_device_addr *r_dev_addr, -* u16 r_count, -* u8 *r_data) -* \brief Read and/or write count bytes from I2C bus, store them in data[]. -* \param w_dev_addr The device i2c address and the device ID to write to -* \param w_count The number of bytes to write -* \param wData The array to write the data to -* \param r_dev_addr The device i2c address and the device ID to read from -* \param r_count The number of bytes to read -* \param r_data The array to read the data from -* \return drx_status_t Return status. -* \retval 0 Succes. -* \retval -EIO Failure. -* \retval -EINVAL Parameter 'wcount' is not zero but parameter -* 'wdata' contains NULL. -* Idem for 'rcount' and 'rdata'. -* Both w_dev_addr and r_dev_addr are NULL. -* -* This function must implement an atomic write and/or read action on the I2C bus -* No other process may use the I2C bus when this function is executing. -* The critical section of this function runs from and including the I2C -* write, up to and including the I2C read action. -* -* The device ID can be useful if several devices share an I2C address. -* It can be used to control a "switch" on the I2C bus to the correct device. -*/ - drx_status_t drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr, - u16 w_count, - u8 *w_data, - struct i2c_device_addr *r_dev_addr, - u16 r_count, u8 *r_data); - -/* -* \fn drxbsp_i2c_error_text() -* \brief Returns a human readable error. -* Counter part of numerical drx_i2c_error_g. -* -* \return char* Pointer to human readable error text. -*/ - char *drxbsp_i2c_error_text(void); - -/* -* \var drx_i2c_error_g; -* \brief I2C specific error codes, platform dependent. -*/ - extern int drx_i2c_error_g; - -#endif /* __BSPI2C_H__ */ diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 6356815cf3e1..7eb4e1469d20 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -30,6 +30,17 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); +/* + * Older drivers treated QAM64 and QAM256 the same; that is the HW always + * used "Auto" mode during detection. Setting "forced_manual"=1 allows + * the user to treat these modes as separate. For backwards compatibility, + * it's off by default. QAM_AUTO can now be specified to achive that + * effect even if "forced_manual"=1 + */ +static int forced_manual; +module_param(forced_manual, int, 0644); +MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified"); + #define DBG_INFO 1 #define DBG_REG 2 #define DBG_DUMP 4 /* FGR - comment out to remove dump code */ @@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) /* 3. : 64QAM/256QAM detection(manual, auto) */ ret = lgdt3306a_read_reg(state, 0x0009, &val); val &= 0xfc; - val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */ + /* Check for forced Manual modulation modes; otherwise always "auto" */ + if(forced_manual && (modulation != QAM_AUTO)){ + val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */ + } else { + val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */ + } ret = lgdt3306a_write_reg(state, 0x0009, val); if (lg_chkerr(ret)) goto fail; @@ -598,6 +614,28 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) if (lg_chkerr(ret)) goto fail; + /* 5.1 V0.36 SRDCHKALWAYS : For better QAM detection */ + ret = lgdt3306a_read_reg(state, 0x000a, &val); + val &= 0xfd; + val |= 0x02; + ret = lgdt3306a_write_reg(state, 0x000a, val); + if (lg_chkerr(ret)) + goto fail; + + /* 5.2 V0.36 Control of "no signal" detector function */ + ret = lgdt3306a_read_reg(state, 0x2849, &val); + val &= 0xdf; + ret = lgdt3306a_write_reg(state, 0x2849, val); + if (lg_chkerr(ret)) + goto fail; + + /* 5.3 Fix for Blonder Tongue HDE-2H-QAM and AQM modulators */ + ret = lgdt3306a_read_reg(state, 0x302b, &val); + val &= 0x7f; /* SELFSYNCFINDEN_CQS=0; disable auto reset */ + ret = lgdt3306a_write_reg(state, 0x302b, val); + if (lg_chkerr(ret)) + goto fail; + /* 6. Reset */ ret = lgdt3306a_soft_reset(state); if (lg_chkerr(ret)) @@ -620,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state, ret = lgdt3306a_set_vsb(state); break; case QAM_64: - ret = lgdt3306a_set_qam(state, QAM_64); - break; case QAM_256: - ret = lgdt3306a_set_qam(state, QAM_256); + case QAM_AUTO: + ret = lgdt3306a_set_qam(state, p->modulation); break; default: return -EINVAL; @@ -650,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: break; default: return -EINVAL; @@ -704,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: /* Auto ok for QAM */ ret = lgdt3306a_set_inversion_auto(state, 1); break; @@ -727,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: if_freq_khz = state->cfg->qam_if_khz; break; default: @@ -1585,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe, switch (state->current_modulation) { case QAM_256: case QAM_64: + case QAM_AUTO: if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) { *status |= FE_HAS_VITERBI; *status |= FE_HAS_SYNC; @@ -1628,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, * Calculate some sort of "strength" from SNR */ struct lgdt3306a_state *state = fe->demodulator_priv; + u8 val; u16 snr; /* snr_x10 */ int ret; u32 ref_snr; /* snr*100 */ @@ -1640,11 +1682,15 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, ref_snr = 1600; /* 16dB */ break; case QAM_64: - ref_snr = 2200; /* 22dB */ - break; case QAM_256: - ref_snr = 2800; /* 28dB */ - break; + case QAM_AUTO: + /* need to know actual modulation to set proper SNR baseline */ + lgdt3306a_read_reg(state, 0x00a6, &val); + if(val & 0x04) + ref_snr = 2800; /* QAM-256 28dB */ + else + ref_snr = 2200; /* QAM-64 22dB */ + break; default: return -EINVAL; } @@ -2114,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + .caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB }, .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl, .init = lgdt3306a_init, @@ -2177,6 +2223,7 @@ static int lgdt3306a_probe(struct i2c_client *client, i2c_set_clientdata(client, fe->demodulator_priv); state = fe->demodulator_priv; + state->frontend.ops.release = NULL; /* create mux i2c adapter for tuner */ state->muxc = i2c_mux_alloc(client->adapter, &client->dev, @@ -2196,6 +2243,8 @@ static int lgdt3306a_probe(struct i2c_client *client, *config->i2c_adapter = state->muxc->adapter[0]; *config->fe = fe; + dev_info(&client->dev, "LG Electronics LGDT3306A successfully identified\n"); + return 0; err_kfree: @@ -2203,7 +2252,7 @@ err_kfree: err_fe: kfree(config); fail: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 2969ba6ed9e1..377cd984b069 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -31,8 +31,6 @@ static unsigned int verbose = 5; module_param(verbose, int, 0644); -#define ABS(x) ((x) < 0 ? (-x) : (x)) - struct mb86a16_state { struct i2c_adapter *i2c_adap; const struct mb86a16_config *config; @@ -1202,12 +1200,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state) signal_dupl = 0; for (j = 0; j < prev_freq_num; j++) { - if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { + if ((abs(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { signal_dupl = 1; dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j); } } - if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { + if ((signal_dupl == 0) && (swp_freq > 0) && (abs(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate); prev_swp_freq[prev_freq_num] = swp_freq; prev_freq_num++; @@ -1381,7 +1379,7 @@ static int mb86a16_set_fe(struct mb86a16_state *state) dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq); swp_freq += delta_freq; dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq); - if (ABS(state->frequency * 1000 - swp_freq) > 3800) { + if (abs(state->frequency * 1000 - swp_freq) > 3800) { dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !"); } else { diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c index e899821018a0..483ee7d6198e 100644 --- a/drivers/media/dvb-frontends/mxl5xx.c +++ b/drivers/media/dvb-frontends/mxl5xx.c @@ -380,6 +380,38 @@ static int get_algo(struct dvb_frontend *fe) return DVBFE_ALGO_HW; } +static u32 gold2root(u32 gold) +{ + u32 x, g, tmp = gold; + + if (tmp >= 0x3ffff) + tmp = 0; + for (g = 0, x = 1; g < tmp; g++) + x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1); + return x; +} + +static int cfg_scrambler(struct mxl *state, u32 gold) +{ + u32 root; + u8 buf[26] = { + MXL_HYDRA_PLID_CMD_WRITE, 24, + 0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0, + state->demod, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + }; + + root = gold2root(gold); + + buf[25] = (root >> 24) & 0xff; + buf[24] = (root >> 16) & 0xff; + buf[23] = (root >> 8) & 0xff; + buf[22] = root & 0xff; + + return send_command(state, sizeof(buf), buf); +} + static int cfg_demod_abort_tune(struct mxl *state) { struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd; @@ -437,7 +469,7 @@ static int set_parameters(struct dvb_frontend *fe) demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO; demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO; - /* cfg_scrambler(state); */ + cfg_scrambler(state, p->scrambling_sequence_index); break; default: return -EINVAL; diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 94bf5b7d6f3f..fa3b8169c1a5 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -498,7 +498,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) * / ConstWithBandwidthMode) */ - num = dev->pdata->clk * 7; + num = dev->pdata->clk * 7ULL; num *= 0x400000; num = div_u64(num, bw_mode); resamp_ratio = num & 0x3ffffff; @@ -511,7 +511,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * / (CrystalFreqHz * 7)) */ num = bw_mode << 20; - num2 = dev->pdata->clk * 7; + num2 = dev->pdata->clk * 7ULL; num = div_u64(num, num2); num = -num; cfreq_off_ratio = num & 0xfffff; diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index aced6a956ec5..a23ba8727218 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -682,17 +682,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) val = s5h1409_readreg(state, 0xac) & 0xcfff; switch (mode) { - case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK: val |= 0x0000; break; - case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK: dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); val |= 0x1000; break; - case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK: val |= 0x2000; break; - case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK: val |= 0x3000; break; default: diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index b38557c451b9..87de58ffc822 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -52,10 +52,10 @@ struct s5h1409_config { u8 status_mode; /* MPEG signal timing */ -#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* HVR-1600 optimizations (to better work with MXL5005s) diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index c4b1e9725f3e..af5962807f2c 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -433,17 +433,17 @@ static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode) val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff; switch (mode) { - case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK: val |= 0x0000; break; - case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK: dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); val |= 0x1000; break; - case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK: val |= 0x2000; break; - case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK: val |= 0x3000; break; default: diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index 791bab0e16e9..850ee713d64c 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -40,10 +40,10 @@ struct s5h1411_config { u8 gpio; /* MPEG signal timing */ -#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* IF Freq for QAM and VSB in KHz */ diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h index af3a157b5e77..646dda36262b 100644 --- a/drivers/media/dvb-frontends/s5h1432.h +++ b/drivers/media/dvb-frontends/s5h1432.h @@ -42,10 +42,10 @@ struct s5h1432_config { u8 gpio; /* MPEG signal timing */ -#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1432_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1432_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1432_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* IF Freq for QAM and VSB in KHz */ diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 539399dac551..324493e05f9f 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -82,6 +82,30 @@ err_mutex_unlock: return ret; } +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + struct si2168_cmd cmd; + int ret = 0; + + dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + + /* set TS_MODE property */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + if (acquire) + cmd.args[4] |= dev->ts_mode; + else + cmd.args[4] |= SI2168_TS_TRISTATE; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + + return ret; +} + static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; @@ -339,6 +363,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; + if (dev->spectral_inversion) + cmd.args[5] |= 1; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); @@ -403,6 +429,11 @@ static int si2168_set_frontend(struct dvb_frontend *fe) dev->delivery_system = c->delivery_system; + /* enable ts bus */ + ret = si2168_ts_bus_ctrl(fe, 1); + if (ret) + goto err; + return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); @@ -541,13 +572,7 @@ static int si2168_init(struct dvb_frontend *fe) dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); /* set ts mode */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - cmd.args[4] |= dev->ts_mode; - if (dev->ts_clock_gapped) - cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); + ret = si2168_ts_bus_ctrl(fe, 1); if (ret) goto err; @@ -584,7 +609,12 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; - /* Firmware B 4.0-11 or later loses warm state during sleep */ + /* tri-state data bus */ + ret = si2168_ts_bus_ctrl(fe, 0); + if (ret) + goto err; + + /* Firmware later than B 4.0-11 loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; @@ -776,6 +806,7 @@ static int si2168_probe(struct i2c_client *client, dev->ts_mode = config->ts_mode; dev->ts_clock_inv = config->ts_clock_inv; dev->ts_clock_gapped = config->ts_clock_gapped; + dev->spectral_inversion = config->spectral_inversion; dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n", dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, @@ -788,7 +819,7 @@ static int si2168_probe(struct i2c_client *client, err_kfree: kfree(dev); err: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3225d0cc93c7..d519edd26c21 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -38,6 +38,7 @@ struct si2168_config { /* TS mode */ #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 +#define SI2168_TS_TRISTATE 0x00 u8 ts_mode; /* TS clock inverted */ @@ -45,6 +46,9 @@ struct si2168_config { /* TS clock gapped */ bool ts_clock_gapped; + + /* Inverted spectrum */ + bool spectral_inversion; }; #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 3c8746a20038..2d362e162ade 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -48,6 +48,7 @@ struct si2168_dev { u8 ts_mode; bool ts_clock_inv; bool ts_clock_gapped; + bool spectral_inversion; }; /* firmware command struct */ diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index 572a297811fe..f39d566d7d1d 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -136,7 +136,7 @@ static void sp887x_setup_agc (struct sp887x_state* state) static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) { struct sp887x_state* state = fe->demodulator_priv; - u8 buf [BLOCKSIZE+2]; + u8 buf [BLOCKSIZE + 2]; int i; int fw_size = fw->size; const unsigned char *mem = fw->data; @@ -144,7 +144,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware dprintk("%s\n", __func__); /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */ - if (fw_size < FW_SIZE+10) + if (fw_size < FW_SIZE + 10) return -ENODEV; mem = fw->data + 10; @@ -167,7 +167,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware int c = BLOCKSIZE; int err; - if (i+c > FW_SIZE) + if (c > FW_SIZE - i) c = FW_SIZE - i; /* bit 0x8000 in address is set to enable 13bit mode */ diff --git a/drivers/media/dvb-frontends/stb0899_reg.h b/drivers/media/dvb-frontends/stb0899_reg.h index ba1ed56304a0..f564269249a6 100644 --- a/drivers/media/dvb-frontends/stb0899_reg.h +++ b/drivers/media/dvb-frontends/stb0899_reg.h @@ -374,22 +374,22 @@ #define STB0899_OFF0_IF_AGC_GAIN 0xf30c #define STB0899_BASE_IF_AGC_GAIN 0x00000000 -#define STB0899_IF_AGC_GAIN (0x3fff < 0) +#define STB0899_IF_AGC_GAIN (0x3fff << 0) #define STB0899_OFFST_IF_AGC_GAIN 0 #define STB0899_WIDTH_IF_AGC_GAIN 14 #define STB0899_OFF0_BB_AGC_GAIN 0xf310 #define STB0899_BASE_BB_AGC_GAIN 0x00000000 -#define STB0899_BB_AGC_GAIN (0x3fff < 0) +#define STB0899_BB_AGC_GAIN (0x3fff << 0) #define STB0899_OFFST_BB_AGC_GAIN 0 #define STB0899_WIDTH_BB_AGC_GAIN 14 #define STB0899_OFF0_DC_OFFSET 0xf314 #define STB0899_BASE_DC_OFFSET 0x00000000 -#define STB0899_I (0xff < 8) +#define STB0899_I (0xff << 8) #define STB0899_OFFST_I 8 #define STB0899_WIDTH_I 8 -#define STB0899_Q (0xff < 0) +#define STB0899_Q (0xff << 0) #define STB0899_OFFST_Q 8 #define STB0899_WIDTH_Q 8 diff --git a/drivers/media/dvb-frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h index 8abc451dd524..460066a391b7 100644 --- a/drivers/media/dvb-frontends/stv0367_priv.h +++ b/drivers/media/dvb-frontends/stv0367_priv.h @@ -35,7 +35,6 @@ #endif /* MACRO definitions */ -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) #define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) #define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) #define INRANGE(X, Y, Z) \ diff --git a/drivers/media/dvb-frontends/stv0900_priv.h b/drivers/media/dvb-frontends/stv0900_priv.h index d1fc06ff27d3..09a46477eae4 100644 --- a/drivers/media/dvb-frontends/stv0900_priv.h +++ b/drivers/media/dvb-frontends/stv0900_priv.h @@ -24,7 +24,6 @@ #include <linux/i2c.h> -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) #define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \ || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index c97a39120ea5..d406c83e4744 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1255,14 +1255,14 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe) else intp->freq[d] = stv0900_get_tuner_freq(fe); - if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) range = STV0900_RANGEOK; - else if (ABS(offsetFreq) <= + else if (abs(offsetFreq) <= (stv0900_carrier_width(result->symbol_rate, result->rolloff) / 2000)) range = STV0900_RANGEOK; - } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + } else if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) range = STV0900_RANGEOK; dprintk("%s: range %d\n", __func__, range); diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index a2f7c0c1587f..52355c14fd64 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1673,15 +1673,15 @@ static int send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; int i; - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); + SET_FIELD(DIS_PRECHARGE, 1); for (i = 0; i < cmd->msg_len; i++) { wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]); + SET_REG(DISTXFIFO, cmd->msg[i]); } - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; } @@ -1689,19 +1689,20 @@ static int send_master_cmd(struct dvb_frontend *fe, static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; u8 value; if (burst == SEC_MINI_A) { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F); + SET_FIELD(DISEQC_MODE, 3); value = 0x00; } else { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); value = 0xFF; } + + SET_FIELD(DIS_PRECHARGE, 1); wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value); - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_REG(DISTXFIFO, value); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c index 1d8979289915..17600989f121 100644 --- a/drivers/media/dvb-frontends/ves1820.c +++ b/drivers/media/dvb-frontends/ves1820.c @@ -137,7 +137,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) NDEC = 3; /* yeuch! */ - fpxin = state->config->xin * 10; + fpxin = state->config->xin * 10ULL; fptmp = fpxin; do_div(fptmp, 123); if (symbolrate < fptmp) SFIL = 1; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 9f18cd296841..541f0d28afd8 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -56,6 +56,17 @@ config VIDEO_TDA9840 To compile this driver as a module, choose M here: the module will be called tda9840. +config VIDEO_TDA1997X + tristate "NXP TDA1997x HDMI receiver" + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on SND_SOC + select SND_PCM + ---help--- + V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. + + To compile this driver as a module, choose M here: the + module will be called tda1997x. + config VIDEO_TEA6415C tristate "Philips TEA6415C audio processor" depends on I2C @@ -423,6 +434,15 @@ config VIDEO_TW9906 To compile this driver as a module, choose M here: the module will be called tw9906. +config VIDEO_TW9910 + tristate "Techwell TW9910 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. + + To compile this driver as a module, choose M here: the + module will be called tw9910. + config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C @@ -586,6 +606,18 @@ config VIDEO_OV2659 To compile this driver as a module, choose M here: the module will be called ov2659. +config VIDEO_OV2685 + tristate "OmniVision OV2685 sensor support" + depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV2685 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2685. + config VIDEO_OV5640 tristate "OmniVision OV5640 sensor support" depends on OF @@ -645,6 +677,28 @@ config VIDEO_OV5670 To compile this driver as a module, choose M here: the module will be called ov5670. +config VIDEO_OV5695 + tristate "OmniVision OV5695 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV5695 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5695. + +config VIDEO_OV772X + tristate "OmniVision OV772x sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV772x camera. + + To compile this driver as a module, choose M here: the + module will be called ov772x. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 @@ -660,6 +714,7 @@ config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE ---help--- This is a Video4Linux2 sensor-level driver for the OmniVision OV7670 VGA camera. It currently only works with the M88ALP01 @@ -733,6 +788,17 @@ config VIDEO_MT9T001 This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt0t001 3 Mpixel camera. +config VIDEO_MT9T112 + tristate "Aptina MT9T111/MT9T112 support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the Aptina + (Micron) MT9T111 and MT9T112 3 Mpixel camera. + + To compile this driver as a module, choose M here: the + module will be called mt9t112. + config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index c0f94cd8d56d..ea34aee1a85a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o +obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o @@ -48,6 +49,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o obj-$(CONFIG_VIDEO_TW2804) += tw2804.o obj-$(CONFIG_VIDEO_TW9903) += tw9903.o obj-$(CONFIG_VIDEO_TW9906) += tw9906.o +obj-$(CONFIG_VIDEO_TW9910) += tw9910.o obj-$(CONFIG_VIDEO_CS3308) += cs3308.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o @@ -61,13 +63,16 @@ obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_OV2640) += ov2640.o +obj-$(CONFIG_VIDEO_OV2685) += ov2685.o obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o @@ -75,6 +80,7 @@ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o +obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index a056d6cdaaaa..91ff06088572 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices AD9389B/AD9889B video encoder driver * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index fd92c9e4b519..6ca88daa0ecd 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -35,96 +35,28 @@ * Register manipulation */ -static const struct regmap_config adv748x_regmap_cnf[] = { - { - .name = "io", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "dpll", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "cp", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "hdmi", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "edid", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "repeater", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "infoframe", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "cec", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "sdp", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - - { - .name = "txb", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "txa", - .reg_bits = 8, - .val_bits = 8, +#define ADV748X_REGMAP_CONF(n) \ +{ \ + .name = n, \ + .reg_bits = 8, \ + .val_bits = 8, \ + .max_register = 0xff, \ + .cache_type = REGCACHE_NONE, \ +} - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, +static const struct regmap_config adv748x_regmap_cnf[] = { + ADV748X_REGMAP_CONF("io"), + ADV748X_REGMAP_CONF("dpll"), + ADV748X_REGMAP_CONF("cp"), + ADV748X_REGMAP_CONF("hdmi"), + ADV748X_REGMAP_CONF("edid"), + ADV748X_REGMAP_CONF("repeater"), + ADV748X_REGMAP_CONF("infoframe"), + ADV748X_REGMAP_CONF("cbus"), + ADV748X_REGMAP_CONF("cec"), + ADV748X_REGMAP_CONF("sdp"), + ADV748X_REGMAP_CONF("txa"), + ADV748X_REGMAP_CONF("txb"), }; static int adv748x_configure_regmap(struct adv748x_state *state, int region) @@ -148,20 +80,24 @@ static int adv748x_configure_regmap(struct adv748x_state *state, int region) return 0; } +struct adv748x_register_map { + const char *name; + u8 default_addr; +}; -/* Default addresses for the I2C pages */ -static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = { - ADV748X_I2C_IO, - ADV748X_I2C_DPLL, - ADV748X_I2C_CP, - ADV748X_I2C_HDMI, - ADV748X_I2C_EDID, - ADV748X_I2C_REPEATER, - ADV748X_I2C_INFOFRAME, - ADV748X_I2C_CEC, - ADV748X_I2C_SDP, - ADV748X_I2C_TXB, - ADV748X_I2C_TXA, +static const struct adv748x_register_map adv748x_default_addresses[] = { + [ADV748X_PAGE_IO] = { "main", 0x70 }, + [ADV748X_PAGE_DPLL] = { "dpll", 0x26 }, + [ADV748X_PAGE_CP] = { "cp", 0x22 }, + [ADV748X_PAGE_HDMI] = { "hdmi", 0x34 }, + [ADV748X_PAGE_EDID] = { "edid", 0x36 }, + [ADV748X_PAGE_REPEATER] = { "repeater", 0x32 }, + [ADV748X_PAGE_INFOFRAME] = { "infoframe", 0x31 }, + [ADV748X_PAGE_CBUS] = { "cbus", 0x30 }, + [ADV748X_PAGE_CEC] = { "cec", 0x41 }, + [ADV748X_PAGE_SDP] = { "sdp", 0x79 }, + [ADV748X_PAGE_TXB] = { "txb", 0x48 }, + [ADV748X_PAGE_TXA] = { "txa", 0x4a }, }; static int adv748x_read_check(struct adv748x_state *state, @@ -210,15 +146,20 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, return regmap_raw_write(regmap, init_reg, val, val_len); } -static struct i2c_client *adv748x_dummy_client(struct adv748x_state *state, - u8 addr, u8 io_reg) +static int adv748x_set_slave_addresses(struct adv748x_state *state) { - struct i2c_client *client = state->client; + struct i2c_client *client; + unsigned int i; + u8 io_reg; - if (addr) - io_write(state, io_reg, addr << 1); + for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { + io_reg = ADV748X_IO_SLAVE_ADDR_BASE + i; + client = state->i2c_clients[i]; + + io_write(state, io_reg, client->addr << 1); + } - return i2c_new_dummy(client->adapter, io_read(state, io_reg) >> 1); + return 0; } static void adv748x_unregister_clients(struct adv748x_state *state) @@ -231,13 +172,15 @@ static void adv748x_unregister_clients(struct adv748x_state *state) static int adv748x_initialise_clients(struct adv748x_state *state) { - int i; + unsigned int i; int ret; for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { - state->i2c_clients[i] = - adv748x_dummy_client(state, adv748x_i2c_addresses[i], - ADV748X_IO_SLAVE_ADDR_BASE + i); + state->i2c_clients[i] = i2c_new_secondary_device( + state->client, + adv748x_default_addresses[i].name, + adv748x_default_addresses[i].default_addr); + if (state->i2c_clients[i] == NULL) { adv_err(state, "failed to create i2c client %u\n", i); return -ENOMEM; @@ -248,7 +191,7 @@ static int adv748x_initialise_clients(struct adv748x_state *state) return ret; } - return 0; + return adv748x_set_slave_addresses(state); } /** @@ -414,20 +357,6 @@ static const struct adv748x_reg_value adv748x_sw_reset[] = { {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; -static const struct adv748x_reg_value adv748x_set_slave_address[] = { - {ADV748X_PAGE_IO, 0xf3, ADV748X_I2C_DPLL << 1}, - {ADV748X_PAGE_IO, 0xf4, ADV748X_I2C_CP << 1}, - {ADV748X_PAGE_IO, 0xf5, ADV748X_I2C_HDMI << 1}, - {ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1}, - {ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1}, - {ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1}, - {ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1}, - {ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1}, - {ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1}, - {ADV748X_PAGE_IO, 0xfd, ADV748X_I2C_TXA << 1}, - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; - /* Supported Formats For Script Below */ /* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { @@ -558,7 +487,7 @@ static int adv748x_reset(struct adv748x_state *state) if (ret < 0) return ret; - ret = adv748x_write_regs(state, adv748x_set_slave_address); + ret = adv748x_set_slave_addresses(state); if (ret < 0) return ret; @@ -715,7 +644,7 @@ static int adv748x_probe(struct i2c_client *client, ret = adv748x_identify_chip(state); if (ret) { adv_err(state, "Failed to identify chip"); - goto err_cleanup_clients; + goto err_cleanup_dt; } /* Configure remaining pages as I2C clients with regmap access */ diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index 4da4253553fc..10d229a4f088 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -105,6 +105,9 @@ static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi, fmt->width = hdmi->timings.bt.width; fmt->height = hdmi->timings.bt.height; + + if (fmt->field == V4L2_FIELD_ALTERNATE) + fmt->height /= 2; } static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings) diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 6789e2f3bc8c..65f83741277e 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -27,19 +27,6 @@ #ifndef _ADV748X_H_ #define _ADV748X_H_ -/* I2C slave addresses */ -#define ADV748X_I2C_IO 0x70 /* IO Map */ -#define ADV748X_I2C_DPLL 0x26 /* DPLL Map */ -#define ADV748X_I2C_CP 0x22 /* CP Map */ -#define ADV748X_I2C_HDMI 0x34 /* HDMI Map */ -#define ADV748X_I2C_EDID 0x36 /* EDID Map */ -#define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */ -#define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */ -#define ADV748X_I2C_CEC 0x41 /* CEC Map */ -#define ADV748X_I2C_SDP 0x79 /* SDP Map */ -#define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */ -#define ADV748X_I2C_TXA 0x4a /* CSI-TXA Map */ - enum adv748x_page { ADV748X_PAGE_IO, ADV748X_PAGE_DPLL, @@ -48,6 +35,7 @@ enum adv748x_page { ADV748X_PAGE_EDID, ADV748X_PAGE_REPEATER, ADV748X_PAGE_INFOFRAME, + ADV748X_PAGE_CBUS, ADV748X_PAGE_CEC, ADV748X_PAGE_SDP, ADV748X_PAGE_TXB, diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 2817bafc67bf..d23505a411ee 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices ADV7511 HDMI Transmitter Device Driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 1544920ec52d..cac2081e876e 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adv7604 - Analog Devices ADV7604 video decoder driver * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* @@ -2734,6 +2722,27 @@ static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = { /* ----------------------------------------------------------------------- */ +struct adv76xx_register_map { + const char *name; + u8 default_addr; +}; + +static const struct adv76xx_register_map adv76xx_default_addresses[] = { + [ADV76XX_PAGE_IO] = { "main", 0x4c }, + [ADV7604_PAGE_AVLINK] = { "avlink", 0x42 }, + [ADV76XX_PAGE_CEC] = { "cec", 0x40 }, + [ADV76XX_PAGE_INFOFRAME] = { "infoframe", 0x3e }, + [ADV7604_PAGE_ESDP] = { "esdp", 0x38 }, + [ADV7604_PAGE_DPP] = { "dpp", 0x3c }, + [ADV76XX_PAGE_AFE] = { "afe", 0x26 }, + [ADV76XX_PAGE_REP] = { "rep", 0x32 }, + [ADV76XX_PAGE_EDID] = { "edid", 0x36 }, + [ADV76XX_PAGE_HDMI] = { "hdmi", 0x34 }, + [ADV76XX_PAGE_TEST] = { "test", 0x30 }, + [ADV76XX_PAGE_CP] = { "cp", 0x22 }, + [ADV7604_PAGE_VDP] = { "vdp", 0x24 }, +}; + static int adv76xx_core_init(struct v4l2_subdev *sd) { struct adv76xx_state *state = to_state(sd); @@ -2834,13 +2843,26 @@ static void adv76xx_unregister_clients(struct adv76xx_state *state) } static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd, - u8 addr, u8 io_reg) + unsigned int page) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv76xx_state *state = to_state(sd); + struct adv76xx_platform_data *pdata = &state->pdata; + unsigned int io_reg = 0xf2 + page; + struct i2c_client *new_client; + + if (pdata && pdata->i2c_addresses[page]) + new_client = i2c_new_dummy(client->adapter, + pdata->i2c_addresses[page]); + else + new_client = i2c_new_secondary_device(client, + adv76xx_default_addresses[page].name, + adv76xx_default_addresses[page].default_addr); + + if (new_client) + io_write(sd, io_reg, new_client->addr << 1); - if (addr) - io_write(sd, io_reg, addr << 1); - return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); + return new_client; } static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = { @@ -3115,20 +3137,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) /* Disable the interrupt for now as no DT-based board uses it. */ state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; - /* Use the default I2C addresses. */ - state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; - state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40; - state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e; - state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; - state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; - state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26; - state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32; - state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36; - state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34; - state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30; - state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22; - state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; - /* Hardcode the remaining platform data fields. */ state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; @@ -3478,11 +3486,9 @@ static int adv76xx_probe(struct i2c_client *client, if (!(BIT(i) & state->info->page_mask)) continue; - state->i2c_clients[i] = - adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], - 0xf2 + i); + state->i2c_clients[i] = adv76xx_dummy_client(sd, i); if (!state->i2c_clients[i]) { - err = -ENOMEM; + err = -EINVAL; v4l2_err(sd, "failed to create i2c client %u\n", i); goto err_i2c; } diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 136aa80a834b..fddac32e5051 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adv7842 - Analog Devices ADV7842 video decoder driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 98be63ae8590..b168bf3635b6 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -463,8 +463,13 @@ static void cx23885_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u32 clk_freq = 0; struct workqueue_struct *q; + /* cx23885 sets hostdata to clk_freq pointer */ + if (v4l2_get_subdev_hostdata(&state->sd)) + clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd)); + /* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from @@ -500,8 +505,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - /* HVR1850 or 50MHz xtal */ - cx25840_write(client, 0x2, 0x71); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25Mhz xtal */ + ; /* nothing to do */ + } else { + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + } cx25840_write4(client, 0x11c, 0x01d1744c); cx25840_write4(client, 0x118, 0x00000416); cx25840_write4(client, 0x404, 0x0010253e); @@ -544,9 +554,15 @@ static void cx23885_initialize(struct i2c_client *client) /* HVR1850 */ switch (state->id) { case CX23888_AV: - /* 888/HVR1250 specific */ - cx25840_write4(client, 0x10c, 0x13333333); - cx25840_write4(client, 0x108, 0x00000515); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25MHz xtal */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + cx25840_write4(client, 0x108, 0x00000512); + } else { + /* 888/HVR1250 or 50MHz xtal */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + } break; default: cx25840_write4(client, 0x10c, 0x002be2c9); @@ -576,7 +592,7 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - /* HVR1850 or 50MHz xtal */ + /* HVR1850 or 50MHz xtal or 25MHz xtal */ cx25840_write4(client, 0x114, 0x017dbf48); cx25840_write4(client, 0x110, 0x000a030e); break; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 193020d64e51..a7e23bcf845c 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -168,11 +168,15 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -185,11 +189,15 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char buf[4]; /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, buf, 4)) { + rc = i2c_master_recv(ir->c, buf, 4); + if (rc != 4) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -209,11 +217,15 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -571,7 +583,7 @@ static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf, /* first copy any leading non-repeating */ int leading = c - rep * 3; - if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) { + if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) { dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); return -EINVAL; } diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 2f1966bdc473..87cba15b2977 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -643,7 +643,7 @@ static int max2175_set_nco_freq(struct max2175 *ctx, s32 nco_freq) if (abs_nco_freq < clock_rate / 2) { nco_val_desired = 2 * nco_freq; } else { - nco_val_desired = 2 * (clock_rate - abs_nco_freq); + nco_val_desired = 2LL * (clock_rate - abs_nco_freq); if (nco_freq < 0) nco_val_desired = -nco_val_desired; } diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c new file mode 100644 index 000000000000..af8cca984215 --- /dev/null +++ b/drivers/media/i2c/mt9t112.c @@ -0,0 +1,1140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt9t112 Camera Driver + * + * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ov772x driver, mt9m111 driver, + * + * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> + * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + * + * TODO: This driver lacks support for frame rate control due to missing + * register level documentation and suitable hardware for testing. + * v4l-utils compliance tools will report errors. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> + +#include <media/i2c/mt9t112.h> +#include <media/v4l2-common.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-subdev.h> + +/* you can check PLL/clock info */ +/* #define EXT_CLOCK 24000000 */ + +/************************************************************************ + * macro + ***********************************************************************/ +/* + * frame size + */ +#define MAX_WIDTH 2048 +#define MAX_HEIGHT 1536 + +/* + * macro of read/write + */ +#define ECHECKER(ret, x) \ + do { \ + (ret) = (x); \ + if ((ret) < 0) \ + return (ret); \ + } while (0) + +#define mt9t112_reg_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_reg_write(client, a, b)) +#define mt9t112_mcu_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) + +#define mt9t112_reg_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) +#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) + +#define mt9t112_reg_read(ret, client, a) \ + ECHECKER(ret, __mt9t112_reg_read(client, a)) + +/* + * Logical address + */ +#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) +#define VAR(id, offset) _VAR(id, offset, 0x0000) +#define VAR8(id, offset) _VAR(id, offset, 0x8000) + +/************************************************************************ + * struct + ***********************************************************************/ +struct mt9t112_format { + u32 code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +struct mt9t112_priv { + struct v4l2_subdev subdev; + struct mt9t112_platform_data *info; + struct i2c_client *client; + struct v4l2_rect frame; + struct clk *clk; + struct gpio_desc *standby_gpio; + const struct mt9t112_format *format; + int num_formats; + bool init_done; +}; + +/************************************************************************ + * supported format + ***********************************************************************/ + +static const struct mt9t112_format mt9t112_cfmts[] = { + { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 0, + }, { + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 1, + }, { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 2, + }, { + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 3, + }, { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 8, + .order = 2, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 4, + .order = 2, + }, +}; + +/************************************************************************ + * general function + ***********************************************************************/ +static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), + struct mt9t112_priv, + subdev); +} + +static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + command = swab16(command); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = (u8 *)&command; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = buf; + + /* + * If return value of this function is < 0, it means error, else, + * below 16bit is valid data. + */ + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + + memcpy(&ret, buf, 2); + + return swab16(ret); +} + +static int __mt9t112_reg_write(const struct i2c_client *client, + u16 command, u16 data) +{ + struct i2c_msg msg; + u8 buf[4]; + int ret; + + command = swab16(command); + data = swab16(data); + + memcpy(buf + 0, &command, 2); + memcpy(buf + 2, &data, 2); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 4; + msg.buf = buf; + + /* + * i2c_transfer return message length, but this function should + * return 0 if correct case. + */ + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret >= 0 ? 0 : ret; +} + +static int __mt9t112_reg_mask_set(const struct i2c_client *client, + u16 command, u16 mask, u16 set) +{ + int val = __mt9t112_reg_read(client, command); + + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_reg_write(client, command, val); +} + +/* mcu access */ +static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_read(client, 0x0990); +} + +static int __mt9t112_mcu_write(const struct i2c_client *client, + u16 command, u16 data) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_write(client, 0x0990, data); +} + +static int __mt9t112_mcu_mask_set(const struct i2c_client *client, + u16 command, u16 mask, u16 set) +{ + int val = __mt9t112_mcu_read(client, command); + + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_mcu_write(client, command, val); +} + +static int mt9t112_reset(const struct i2c_client *client) +{ + int ret; + + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); + usleep_range(1000, 5000); + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); + + return ret; +} + +#ifndef EXT_CLOCK +#define CLOCK_INFO(a, b) +#else +#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) +static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) +{ + int m, n, p1, p2, p3, p4, p5, p6, p7; + u32 vco, clk; + char *enable; + + ext /= 1000; /* kbyte order */ + + mt9t112_reg_read(n, client, 0x0012); + p1 = n & 0x000f; + n = n >> 4; + p2 = n & 0x000f; + n = n >> 4; + p3 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002a); + p4 = n & 0x000f; + n = n >> 4; + p5 = n & 0x000f; + n = n >> 4; + p6 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002c); + p7 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x0010); + m = n & 0x00ff; + n = (n >> 8) & 0x003f; + + enable = ((ext < 6000) || (ext > 54000)) ? "X" : ""; + dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + + vco = 2 * m * ext / (n + 1); + enable = ((vco < 384000) || (vco > 768000)) ? "X" : ""; + dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); + + clk = vco / (p1 + 1) / (p2 + 1); + enable = (clk > 96000) ? "X" : ""; + dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + + clk = vco / (p3 + 1); + enable = (clk > 768000) ? "X" : ""; + dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + + clk = vco / (p6 + 1); + enable = (clk > 96000) ? "X" : ""; + dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + + clk = vco / (p5 + 1); + enable = (clk > 54000) ? "X" : ""; + dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + + clk = vco / (p4 + 1); + enable = (clk > 70000) ? "X" : ""; + dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + + clk = vco / (p7 + 1); + dev_dbg(&client->dev, "External sensor : %10u K\n", clk); + + clk = ext / (n + 1); + enable = ((clk < 2000) || (clk > 24000)) ? "X" : ""; + dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); + + return 0; +} +#endif + +static int mt9t112_set_a_frame_size(const struct i2c_client *client, + u16 width, u16 height) +{ + int ret; + u16 wstart = (MAX_WIDTH - width) / 2; + u16 hstart = (MAX_HEIGHT - height) / 2; + + /* (Context A) Image Width/Height. */ + mt9t112_mcu_write(ret, client, VAR(26, 0), width); + mt9t112_mcu_write(ret, client, VAR(26, 2), height); + + /* (Context A) Output Width/Height. */ + mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); + mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); + + /* (Context A) Start Row/Column. */ + mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); + + /* (Context A) End Row/Column. */ + mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + return ret; +} + +static int mt9t112_set_pll_dividers(const struct i2c_client *client, + u8 m, u8 n, u8 p1, u8 p2, u8 p3, u8 p4, + u8 p5, u8 p6, u8 p7) +{ + int ret; + u16 val; + + /* N/M */ + val = (n << 8) | (m << 0); + mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); + + /* P1/P2/P3 */ + val = ((p3 & 0x0F) << 8) | ((p2 & 0x0F) << 4) | ((p1 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); + + /* P4/P5/P6 */ + val = (0x7 << 12) | ((p6 & 0x0F) << 8) | ((p5 & 0x0F) << 4) | + ((p4 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); + + /* P7 */ + val = (0x1 << 12) | ((p7 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); + + return ret; +} + +static int mt9t112_init_pll(const struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int data, i, ret; + + mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); + + /* PLL control: BYPASS PLL = 8517. */ + mt9t112_reg_write(ret, client, 0x0014, 0x2145); + + /* Replace these registers when new timing parameters are generated. */ + mt9t112_set_pll_dividers(client, + priv->info->divider.m, priv->info->divider.n, + priv->info->divider.p1, priv->info->divider.p2, + priv->info->divider.p3, priv->info->divider.p4, + priv->info->divider.p5, priv->info->divider.p6, + priv->info->divider.p7); + + /* + * TEST_BYPASS on + * PLL_ENABLE on + * SEL_LOCK_DET on + * TEST_BYPASS off + */ + mt9t112_reg_write(ret, client, 0x0014, 0x2525); + mt9t112_reg_write(ret, client, 0x0014, 0x2527); + mt9t112_reg_write(ret, client, 0x0014, 0x3427); + mt9t112_reg_write(ret, client, 0x0014, 0x3027); + + mdelay(10); + + /* + * PLL_BYPASS off + * Reference clock count + * I2C Master Clock Divider + */ + mt9t112_reg_write(ret, client, 0x0014, 0x3046); + /* JPEG initialization workaround */ + mt9t112_reg_write(ret, client, 0x0016, 0x0400); + mt9t112_reg_write(ret, client, 0x0022, 0x0190); + mt9t112_reg_write(ret, client, 0x3B84, 0x0212); + + /* External sensor clock is PLL bypass. */ + mt9t112_reg_write(ret, client, 0x002E, 0x0500); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); + mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); + + /* MCU disabled. */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); + + /* Out of standby. */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); + + mdelay(50); + + /* + * Standby Workaround + * Disable Secondary I2C Pads + */ + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + + /* Poll to verify out of standby. Must Poll this bit. */ + for (i = 0; i < 100; i++) { + mt9t112_reg_read(data, client, 0x0018); + if (!(data & 0x4000)) + break; + + mdelay(10); + } + + return ret; +} + +static int mt9t112_init_setting(const struct i2c_client *client) +{ + int ret; + + /* Adaptive Output Clock (A) */ + mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); + + /* Read Mode (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); + + /* Fine Correction (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); + + /* Fine IT Min (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); + + /* Fine IT Max Margin (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); + + /* Base Frame Lines (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); + + /* Min Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); + + /* Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); + + /* Adaptive Output Clock (B) */ + mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); + + /* Row Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); + + /* Column Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); + + /* Row End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); + + /* Column End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); + + /* Fine Correction (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); + + /* Fine IT Min (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); + + /* Fine IT Max Margin (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); + + /* Base Frame Lines (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); + + /* Min Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); + + /* Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); + + /* + * Flicker Dectection registers. + * This section should be replaced whenever new timing file is + * generated. All the following registers need to be replaced. + * Following registers are generated from Register Wizard but user can + * modify them. For detail see auto flicker detection tuning. + */ + + /* FD_FDPERIOD_SELECT */ + mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); + + /* PRI_B_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); + + /* PRI_A_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); + + /* + * AFD range detection tuning registers. + */ + + /* Search_f1_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); + + /* Search_f2_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); + + /* Search_f1_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); + + /* Search_f2_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); + + /* Period_50Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); + + /* Secret register by Aptina. */ + /* Period_50Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); + + /* Period_60Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); + + /* Secret register by Aptina. */ + /* Period_60Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); + + /* Period_50Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); + + /* Secret register by Aptina. */ + /* Period_50Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); + + /* Period_60Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); + + /* Secret register by Aptina. */ + /* Period_60Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); + + /* FD Mode */ + mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); + + /* Stat_min */ + mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); + + /* Stat_max */ + mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); + + /* Min_amplitude */ + mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); + + /* RX FIFO Watermark (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); + + /* RX FIFO Watermark (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); + + /* MCLK: 16MHz + * PCLK: 73MHz + * CorePixCLK: 36.5 MHz + */ + mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); + mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); + + mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); + + return ret; +} + +static int mt9t112_auto_focus_setting(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); + mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_reg_write(ret, client, 0x0614, 0x0000); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); + mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); + mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); + mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); + mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); + mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + + return ret; +} + +static int mt9t112_auto_focus_trigger(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); + + return ret; +} + +static int mt9t112_init_camera(const struct i2c_client *client) +{ + int ret; + + ECHECKER(ret, mt9t112_reset(client)); + ECHECKER(ret, mt9t112_init_pll(client)); + ECHECKER(ret, mt9t112_init_setting(client)); + ECHECKER(ret, mt9t112_auto_focus_setting(client)); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); + + /* Analog setting B.*/ + mt9t112_reg_write(ret, client, 0x3084, 0x2409); + mt9t112_reg_write(ret, client, 0x3092, 0x0A49); + mt9t112_reg_write(ret, client, 0x3094, 0x4949); + mt9t112_reg_write(ret, client, 0x3096, 0x4950); + + /* + * Disable adaptive clock. + * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); + mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); + + /* + * Configure Status in Status_before_length Format and enable header. + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); + + /* + * Enable JPEG in context B. + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); + + /* Disable Dac_TXLO. */ + mt9t112_reg_write(ret, client, 0x316C, 0x350F); + + /* Set max slew rates. */ + mt9t112_reg_write(ret, client, 0x1E, 0x777); + + return ret; +} + +/************************************************************************ + * v4l2_subdev_core_ops + ***********************************************************************/ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9t112_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 2; + mt9t112_reg_read(ret, client, reg->reg); + + reg->val = (__u64)ret; + + return 0; +} + +static int mt9t112_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mt9t112_reg_write(ret, client, reg->reg, reg->val); + + return ret; +} +#endif + +static int mt9t112_power_on(struct mt9t112_priv *priv) +{ + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + if (priv->standby_gpio) { + gpiod_set_value(priv->standby_gpio, 0); + msleep(100); + } + + return 0; +} + +static int mt9t112_power_off(struct mt9t112_priv *priv) +{ + clk_disable_unprepare(priv->clk); + if (priv->standby_gpio) { + gpiod_set_value(priv->standby_gpio, 1); + msleep(100); + } + + return 0; +} + +static int mt9t112_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + return on ? mt9t112_power_on(priv) : + mt9t112_power_off(priv); +} + +static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9t112_g_register, + .s_register = mt9t112_s_register, +#endif + .s_power = mt9t112_s_power, +}; + +/************************************************************************ + * v4l2_subdev_video_ops + **********************************************************************/ +static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + int ret = 0; + + if (!enable) { + /* FIXME + * + * If user selected large output size, and used it long time, + * mt9t112 camera will be very warm. + * + * But current driver can not stop mt9t112 camera. + * So, set small size here to solve this problem. + */ + mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); + return ret; + } + + if (!priv->init_done) { + u16 param = MT9T112_FLAG_PCLK_RISING_EDGE & priv->info->flags ? + 0x0001 : 0x0000; + + ECHECKER(ret, mt9t112_init_camera(client)); + + /* Invert PCLK (Data sampled on falling edge of pixclk). */ + mt9t112_reg_write(ret, client, 0x3C20, param); + + mdelay(5); + + priv->init_done = true; + } + + mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); + mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_set_a_frame_size(client, priv->frame.width, priv->frame.height); + + ECHECKER(ret, mt9t112_auto_focus_trigger(client)); + + dev_dbg(&client->dev, "format : %d\n", priv->format->code); + dev_dbg(&client->dev, "size : %d x %d\n", + priv->frame.width, + priv->frame.height); + + CLOCK_INFO(client, EXT_CLOCK); + + return ret; +} + +static int mt9t112_set_params(struct mt9t112_priv *priv, + const struct v4l2_rect *rect, + u32 code) +{ + int i; + + /* + * get color format + */ + for (i = 0; i < priv->num_formats; i++) + if (mt9t112_cfmts[i].code == code) + break; + + if (i == priv->num_formats) + return -EINVAL; + + priv->frame = *rect; + + /* + * frame size check + */ + v4l_bound_align_image(&priv->frame.width, 0, MAX_WIDTH, 0, + &priv->frame.height, 0, MAX_HEIGHT, 0, 0); + + priv->format = mt9t112_cfmts + i; + + return 0; +} + +static int mt9t112_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = MAX_WIDTH; + sel->r.height = MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = VGA_WIDTH; + sel->r.height = VGA_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->frame; + return 0; + default: + return -EINVAL; + } +} + +static int mt9t112_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + const struct v4l2_rect *rect = &sel->r; + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || + sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + return mt9t112_set_params(priv, rect, priv->format->code); +} + +static int mt9t112_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (format->pad) + return -EINVAL; + + mf->width = priv->frame.width; + mf->height = priv->frame.height; + mf->colorspace = priv->format->colorspace; + mf->code = priv->format->code; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + struct v4l2_rect rect = { + .width = mf->width, + .height = mf->height, + .left = priv->frame.left, + .top = priv->frame.top, + }; + int ret; + + ret = mt9t112_set_params(priv, &rect, mf->code); + + if (!ret) + mf->colorspace = priv->format->colorspace; + + return ret; +} + +static int mt9t112_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &format->format; + struct mt9t112_priv *priv = to_mt9t112(client); + int i; + + if (format->pad) + return -EINVAL; + + for (i = 0; i < priv->num_formats; i++) + if (mt9t112_cfmts[i].code == mf->code) + break; + + if (i == priv->num_formats) { + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_JPEG; + } else { + mf->colorspace = mt9t112_cfmts[i].colorspace; + } + + v4l_bound_align_image(&mf->width, 0, MAX_WIDTH, 0, + &mf->height, 0, MAX_HEIGHT, 0, 0); + + mf->field = V4L2_FIELD_NONE; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9t112_s_fmt(sd, mf); + cfg->try_fmt = *mf; + + return 0; +} + +static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (code->pad || code->index >= priv->num_formats) + return -EINVAL; + + code->code = mt9t112_cfmts[code->index].code; + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { + .s_stream = mt9t112_s_stream, +}; + +static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { + .enum_mbus_code = mt9t112_enum_mbus_code, + .get_selection = mt9t112_get_selection, + .set_selection = mt9t112_set_selection, + .get_fmt = mt9t112_get_fmt, + .set_fmt = mt9t112_set_fmt, +}; + +/************************************************************************ + * i2c driver + ***********************************************************************/ +static const struct v4l2_subdev_ops mt9t112_subdev_ops = { + .core = &mt9t112_subdev_core_ops, + .video = &mt9t112_subdev_video_ops, + .pad = &mt9t112_subdev_pad_ops, +}; + +static int mt9t112_camera_probe(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + const char *devname; + int chipid; + int ret; + + ret = mt9t112_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* Check and show chip ID. */ + mt9t112_reg_read(chipid, client, 0x0000); + + switch (chipid) { + case 0x2680: + devname = "mt9t111"; + priv->num_formats = 1; + break; + case 0x2682: + devname = "mt9t112"; + priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); + break; + default: + dev_err(&client->dev, "Product ID error %04x\n", chipid); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); + +done: + mt9t112_s_power(&priv->subdev, 0); + + return ret; +} + +static int mt9t112_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t112_priv *priv; + int ret; + + if (!client->dev.platform_data) { + dev_err(&client->dev, "mt9t112: missing platform data!\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = client->dev.platform_data; + priv->init_done = false; + + v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); + + priv->clk = devm_clk_get(&client->dev, "extclk"); + if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = NULL; + } else if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); + return PTR_ERR(priv->clk); + } + + priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->standby_gpio)) { + dev_err(&client->dev, "Unable to get gpio \"standby\"\n"); + return PTR_ERR(priv->standby_gpio); + } + + ret = mt9t112_camera_probe(client); + if (ret) + return ret; + + return v4l2_async_register_subdev(&priv->subdev); +} + +static int mt9t112_remove(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + + clk_disable_unprepare(priv->clk); + v4l2_async_unregister_subdev(&priv->subdev); + + return 0; +} + +static const struct i2c_device_id mt9t112_id[] = { + { "mt9t112", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t112_id); + +static struct i2c_driver mt9t112_i2c_driver = { + .driver = { + .name = "mt9t112", + }, + .probe = mt9t112_probe, + .remove = mt9t112_remove, + .id_table = mt9t112_id, +}; + +module_i2c_driver(mt9t112_i2c_driver); + +MODULE_DESCRIPTION("V4L2 driver for MT9T111/MT9T112 camera sensor"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 5e29064fae91..46ef74a2ca36 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -364,33 +364,22 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int mt9v011_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; calc_fps(sd, - &cp->timeperframe.numerator, - &cp->timeperframe.denominator); + &ival->interval.numerator, + &ival->interval.denominator); return 0; } -static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int mt9v011_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; u16 speed; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; - speed = calc_speed(sd, tpf->numerator, tpf->denominator); mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); @@ -469,8 +458,8 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .g_parm = mt9v011_g_parm, - .s_parm = mt9v011_s_parm, + .g_frame_interval = mt9v011_g_frame_interval, + .s_frame_interval = mt9v011_s_frame_interval, }; static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = { diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index bf7d06f3f21a..30ee9f71bf0d 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -194,6 +194,7 @@ static const struct ov13858_reg mode_4224x3136_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x12}, {0x3664, 0x73}, @@ -384,6 +385,7 @@ static const struct ov13858_reg mode_2112x1568_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x10}, {0x3664, 0x73}, @@ -574,6 +576,7 @@ static const struct ov13858_reg mode_2112x1188_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x10}, {0x3664, 0x73}, @@ -764,6 +767,7 @@ static const struct ov13858_reg mode_1056x784_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x08}, {0x3664, 0x73}, @@ -1057,14 +1061,15 @@ struct ov13858 { #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) /* Read registers up to 4 at a time */ -static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val) +static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct i2c_msg msgs[2]; u8 *data_be_p; int ret; - u32 data_be = 0; - u16 reg_addr_be = cpu_to_be16(reg); + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); if (len > 4) return -EINVAL; @@ -1092,11 +1097,13 @@ static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val) } /* Write registers up to 4 at a time */ -static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val) +static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 __val) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int buf_i, val_i; u8 buf[6], *val_p; + __be32 val; if (len > 4) return -EINVAL; @@ -1104,7 +1111,7 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val) buf[0] = reg >> 8; buf[1] = reg & 0xff; - val = cpu_to_be32(val); + val = cpu_to_be32(__val); val_p = (u8 *)&val; buf_i = 2; val_i = 4 - len; @@ -1348,39 +1355,6 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd, return ret; } -/* - * Calculate resolution distance - */ -static int -ov13858_get_resolution_dist(const struct ov13858_mode *mode, - struct v4l2_mbus_framefmt *framefmt) -{ - return abs(mode->width - framefmt->width) + - abs(mode->height - framefmt->height); -} - -/* - * Find the closest supported resolution to the requested resolution - */ -static const struct ov13858_mode * -ov13858_find_best_fit(struct ov13858 *ov13858, - struct v4l2_subdev_format *fmt) -{ - int i, dist, cur_best_fit = 0, cur_best_fit_dist = -1; - struct v4l2_mbus_framefmt *framefmt = &fmt->format; - - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = ov13858_get_resolution_dist(&supported_modes[i], - framefmt); - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { - cur_best_fit_dist = dist; - cur_best_fit = i; - } - } - - return &supported_modes[cur_best_fit]; -} - static int ov13858_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, @@ -1401,7 +1375,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10) fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - mode = ov13858_find_best_fit(ov13858, fmt); + mode = v4l2_find_nearest_size(supported_modes, width, height, + fmt->format.width, fmt->format.height); ov13858_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); @@ -1565,7 +1540,7 @@ static int __maybe_unused ov13858_resume(struct device *dev) error: ov13858_stop_streaming(ov13858); - ov13858->streaming = 0; + ov13858->streaming = false; return ret; } diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c new file mode 100644 index 000000000000..83c55e8288e7 --- /dev/null +++ b/drivers/media/i2c/ov2685.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ov2685 driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/sysfs.h> +#include <media/media-entity.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> + +#define CHIP_ID 0x2685 +#define OV2685_REG_CHIP_ID 0x300a + +#define OV2685_XVCLK_FREQ 24000000 + +#define REG_SC_CTRL_MODE 0x0100 +#define SC_CTRL_MODE_STANDBY 0x0 +#define SC_CTRL_MODE_STREAMING BIT(0) + +#define OV2685_REG_EXPOSURE 0x3500 +#define OV2685_EXPOSURE_MIN 4 +#define OV2685_EXPOSURE_STEP 1 + +#define OV2685_REG_VTS 0x380e +#define OV2685_VTS_MAX 0x7fff + +#define OV2685_REG_GAIN 0x350a +#define OV2685_GAIN_MIN 0 +#define OV2685_GAIN_MAX 0x07ff +#define OV2685_GAIN_STEP 0x1 +#define OV2685_GAIN_DEFAULT 0x0036 + +#define OV2685_REG_TEST_PATTERN 0x5080 +#define OV2685_TEST_PATTERN_DISABLED 0x00 +#define OV2685_TEST_PATTERN_COLOR_BAR 0x80 +#define OV2685_TEST_PATTERN_RANDOM 0x81 +#define OV2685_TEST_PATTERN_COLOR_BAR_FADE 0x88 +#define OV2685_TEST_PATTERN_BW_SQUARE 0x92 +#define OV2685_TEST_PATTERN_COLOR_SQUARE 0x82 + +#define REG_NULL 0xFFFF + +#define OV2685_REG_VALUE_08BIT 1 +#define OV2685_REG_VALUE_16BIT 2 +#define OV2685_REG_VALUE_24BIT 3 + +#define OV2685_LANES 1 +#define OV2685_BITS_PER_SAMPLE 10 + +static const char * const ov2685_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names) + +struct regval { + u16 addr; + u8 val; +}; + +struct ov2685_mode { + u32 width; + u32 height; + u32 exp_def; + u32 hts_def; + u32 vts_def; + const struct regval *reg_list; +}; + +struct ov2685 { + struct i2c_client *client; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES]; + + bool streaming; + struct mutex mutex; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_ctrl *anal_gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl_handler ctrl_handler; + + const struct ov2685_mode *cur_mode; +}; + +#define to_ov2685(sd) container_of(sd, struct ov2685, subdev) + +/* PLL settings bases on 24M xvclk */ +static struct regval ov2685_1600x1200_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x3002, 0x00}, + {0x3016, 0x1c}, + {0x3018, 0x44}, + {0x301d, 0xf0}, + {0x3020, 0x00}, + {0x3082, 0x37}, + {0x3083, 0x03}, + {0x3084, 0x09}, + {0x3085, 0x04}, + {0x3086, 0x00}, + {0x3087, 0x00}, + {0x3501, 0x4e}, + {0x3502, 0xe0}, + {0x3503, 0x27}, + {0x350b, 0x36}, + {0x3600, 0xb4}, + {0x3603, 0x35}, + {0x3604, 0x24}, + {0x3605, 0x00}, + {0x3620, 0x24}, + {0x3621, 0x34}, + {0x3622, 0x03}, + {0x3628, 0x10}, + {0x3705, 0x3c}, + {0x370a, 0x21}, + {0x370c, 0x50}, + {0x370d, 0xc0}, + {0x3717, 0x58}, + {0x3718, 0x80}, + {0x3720, 0x00}, + {0x3721, 0x09}, + {0x3722, 0x06}, + {0x3723, 0x59}, + {0x3738, 0x99}, + {0x3781, 0x80}, + {0x3784, 0x0c}, + {0x3789, 0x60}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x06}, + {0x3805, 0x4f}, + {0x3806, 0x04}, + {0x3807, 0xbf}, + {0x3808, 0x06}, + {0x3809, 0x40}, + {0x380a, 0x04}, + {0x380b, 0xb0}, + {0x380c, 0x06}, + {0x380d, 0xa4}, + {0x380e, 0x05}, + {0x380f, 0x0e}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3819, 0x04}, + {0x3820, 0xc0}, + {0x3821, 0x00}, + {0x3a06, 0x01}, + {0x3a07, 0x84}, + {0x3a08, 0x01}, + {0x3a09, 0x43}, + {0x3a0a, 0x24}, + {0x3a0b, 0x60}, + {0x3a0c, 0x28}, + {0x3a0d, 0x60}, + {0x3a0e, 0x04}, + {0x3a0f, 0x8c}, + {0x3a10, 0x05}, + {0x3a11, 0x0c}, + {0x4000, 0x81}, + {0x4001, 0x40}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x4300, 0x00}, + {0x430e, 0x00}, + {0x4602, 0x02}, + {0x481b, 0x40}, + {0x481f, 0x40}, + {0x4837, 0x18}, + {0x5000, 0x1f}, + {0x5001, 0x05}, + {0x5002, 0x30}, + {0x5003, 0x04}, + {0x5004, 0x00}, + {0x5005, 0x0c}, + {0x5280, 0x15}, + {0x5281, 0x06}, + {0x5282, 0x06}, + {0x5283, 0x08}, + {0x5284, 0x1c}, + {0x5285, 0x1c}, + {0x5286, 0x20}, + {0x5287, 0x10}, + {REG_NULL, 0x00} +}; + +#define OV2685_LINK_FREQ_330MHZ 330000000 +static const s64 link_freq_menu_items[] = { + OV2685_LINK_FREQ_330MHZ +}; + +static const char * const ov2685_test_pattern_menu[] = { + "Disabled", + "Color Bar", + "Color Bar FADE", + "Random Data", + "Black White Square", + "Color Square" +}; + +static const int ov2685_test_pattern_val[] = { + OV2685_TEST_PATTERN_DISABLED, + OV2685_TEST_PATTERN_COLOR_BAR, + OV2685_TEST_PATTERN_COLOR_BAR_FADE, + OV2685_TEST_PATTERN_RANDOM, + OV2685_TEST_PATTERN_BW_SQUARE, + OV2685_TEST_PATTERN_COLOR_SQUARE, +}; + +static const struct ov2685_mode supported_modes[] = { + { + .width = 1600, + .height = 1200, + .exp_def = 0x04ee, + .hts_def = 0x06a4, + .vts_def = 0x050e, + .reg_list = ov2685_1600x1200_regs, + }, +}; + +/* Write registers up to 4 at a time */ +static int ov2685_write_reg(struct i2c_client *client, u16 reg, + u32 len, u32 val) +{ + u32 val_i, buf_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val_be = cpu_to_be32(val); + val_p = (u8 *)&val_be; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov2685_write_array(struct i2c_client *client, + const struct regval *regs) +{ + int ret = 0; + u32 i; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) + ret = ov2685_write_reg(client, regs[i].addr, + OV2685_REG_VALUE_08BIT, regs[i].val); + + return ret; +} + +/* Read registers up to 4 at a time */ +static int ov2685_read_reg(struct i2c_client *client, u16 reg, + u32 len, u32 *val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +static void ov2685_fill_fmt(const struct ov2685_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov2685_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + + /* only one mode supported for now */ + ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt); + + return 0; +} + +static int ov2685_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + + ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt); + + return 0; +} + +static int ov2685_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + fse->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + fse->min_width = supported_modes[index].width; + fse->max_width = supported_modes[index].width; + fse->max_height = supported_modes[index].height; + fse->min_height = supported_modes[index].height; + + return 0; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 ov2685_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000); +} + +static int __ov2685_power_on(struct ov2685 *ov2685) +{ + int ret; + u32 delay_us; + struct device *dev = &ov2685->client->dev; + + ret = clk_prepare_enable(ov2685->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + gpiod_set_value_cansleep(ov2685->reset_gpio, 1); + + ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + /* The minimum delay between power supplies and reset rising can be 0 */ + gpiod_set_value_cansleep(ov2685->reset_gpio, 0); + /* 8192 xvclk cycles prior to the first SCCB transaction */ + delay_us = ov2685_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); + + /* HACK: ov2685 would output messy data after reset(R0103), + * writing register before .s_stream() as a workaround + */ + ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list); + if (ret) + goto disable_supplies; + + return 0; + +disable_supplies: + regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies); +disable_clk: + clk_disable_unprepare(ov2685->xvclk); + + return ret; +} + +static void __ov2685_power_off(struct ov2685 *ov2685) +{ + /* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */ + u32 delay_us = ov2685_cal_delay(512); + + usleep_range(delay_us, delay_us * 2); + clk_disable_unprepare(ov2685->xvclk); + gpiod_set_value_cansleep(ov2685->reset_gpio, 1); + regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies); +} + +static int ov2685_s_stream(struct v4l2_subdev *sd, int on) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct i2c_client *client = ov2685->client; + int ret = 0; + + mutex_lock(&ov2685->mutex); + + on = !!on; + if (on == ov2685->streaming) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&ov2685->client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler); + if (ret) { + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + ret = ov2685_write_reg(client, REG_SC_CTRL_MODE, + OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING); + if (ret) { + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + } else { + ov2685_write_reg(client, REG_SC_CTRL_MODE, + OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY); + pm_runtime_put(&ov2685->client->dev); + } + + ov2685->streaming = on; + +unlock_and_return: + mutex_unlock(&ov2685->mutex); + + return ret; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *try_fmt; + + mutex_lock(&ov2685->mutex); + + try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0); + /* Initialize try_fmt */ + ov2685_fill_fmt(&supported_modes[0], try_fmt); + + mutex_unlock(&ov2685->mutex); + + return 0; +} +#endif + +static int __maybe_unused ov2685_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + return __ov2685_power_on(ov2685); +} + +static int __maybe_unused ov2685_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + __ov2685_power_off(ov2685); + + return 0; +} + +static const struct dev_pm_ops ov2685_pm_ops = { + SET_RUNTIME_PM_OPS(ov2685_runtime_suspend, + ov2685_runtime_resume, NULL) +}; + +static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2685 *ov2685 = container_of(ctrl->handler, + struct ov2685, ctrl_handler); + struct i2c_client *client = ov2685->client; + s64 max_expo; + int ret; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max_expo = ov2685->cur_mode->height + ctrl->val - 4; + __v4l2_ctrl_modify_range(ov2685->exposure, + ov2685->exposure->minimum, max_expo, + ov2685->exposure->step, + ov2685->exposure->default_value); + break; + } + + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE, + OV2685_REG_VALUE_24BIT, ctrl->val << 4); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN, + OV2685_REG_VALUE_16BIT, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS, + OV2685_REG_VALUE_16BIT, + ctrl->val + ov2685->cur_mode->height); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN, + OV2685_REG_VALUE_08BIT, + ov2685_test_pattern_val[ctrl->val]); + break; + default: + dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + ret = -EINVAL; + break; + }; + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops ov2685_video_ops = { + .s_stream = ov2685_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov2685_pad_ops = { + .enum_mbus_code = ov2685_enum_mbus_code, + .enum_frame_size = ov2685_enum_frame_sizes, + .get_fmt = ov2685_get_fmt, + .set_fmt = ov2685_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2685_subdev_ops = { + .video = &ov2685_video_ops, + .pad = &ov2685_pad_ops, +}; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops ov2685_internal_ops = { + .open = ov2685_open, +}; +#endif + +static const struct v4l2_ctrl_ops ov2685_ctrl_ops = { + .s_ctrl = ov2685_set_ctrl, +}; + +static int ov2685_initialize_controls(struct ov2685 *ov2685) +{ + const struct ov2685_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + u64 exposure_max; + u32 pixel_rate, h_blank; + int ret; + + handler = &ov2685->ctrl_handler; + mode = ov2685->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 8); + if (ret) + return ret; + handler->lock = &ov2685->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = (link_freq_menu_items[0] * 2 * OV2685_LANES) / + OV2685_BITS_PER_SAMPLE; + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts_def - mode->width; + ov2685->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov2685->hblank) + ov2685->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov2685->vblank = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_VBLANK, mode->vts_def - mode->height, + OV2685_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + + exposure_max = mode->vts_def - 4; + ov2685->exposure = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_EXPOSURE, OV2685_EXPOSURE_MIN, + exposure_max, OV2685_EXPOSURE_STEP, + mode->exp_def); + + ov2685->anal_gain = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, OV2685_GAIN_MIN, + OV2685_GAIN_MAX, OV2685_GAIN_STEP, + OV2685_GAIN_DEFAULT); + + ov2685->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &ov2685_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2685_test_pattern_menu) - 1, + 0, 0, ov2685_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_err(&ov2685->client->dev, + "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ov2685->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov2685_check_sensor_id(struct ov2685 *ov2685, + struct i2c_client *client) +{ + struct device *dev = &ov2685->client->dev; + int ret; + u32 id = 0; + + ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID, + OV2685_REG_VALUE_16BIT, &id); + if (id != CHIP_ID) { + dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret); + return ret; + } + + dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID); + + return 0; +} + +static int ov2685_configure_regulators(struct ov2685 *ov2685) +{ + int i; + + for (i = 0; i < OV2685_NUM_SUPPLIES; i++) + ov2685->supplies[i].supply = ov2685_supply_names[i]; + + return devm_regulator_bulk_get(&ov2685->client->dev, + OV2685_NUM_SUPPLIES, + ov2685->supplies); +} + +static int ov2685_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ov2685 *ov2685; + int ret; + + ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL); + if (!ov2685) + return -ENOMEM; + + ov2685->client = client; + ov2685->cur_mode = &supported_modes[0]; + + ov2685->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov2685->xvclk)) { + dev_err(dev, "Failed to get xvclk\n"); + return -EINVAL; + } + ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ); + if (ret < 0) { + dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); + return ret; + } + if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov2685->reset_gpio)) { + dev_err(dev, "Failed to get reset-gpios\n"); + return -EINVAL; + } + + ret = ov2685_configure_regulators(ov2685); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + + mutex_init(&ov2685->mutex); + v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops); + ret = ov2685_initialize_controls(ov2685); + if (ret) + goto err_destroy_mutex; + + ret = __ov2685_power_on(ov2685); + if (ret) + goto err_free_handler; + + ret = ov2685_check_sensor_id(ov2685, client); + if (ret) + goto err_power_off; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + ov2685->subdev.internal_ops = &ov2685_internal_ops; + ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif +#if defined(CONFIG_MEDIA_CONTROLLER) + ov2685->pad.flags = MEDIA_PAD_FL_SOURCE; + ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad); + if (ret < 0) + goto err_power_off; +#endif + + ret = v4l2_async_register_subdev(&ov2685->subdev); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +err_clean_entity: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&ov2685->subdev.entity); +#endif +err_power_off: + __ov2685_power_off(ov2685); +err_free_handler: + v4l2_ctrl_handler_free(&ov2685->ctrl_handler); +err_destroy_mutex: + mutex_destroy(&ov2685->mutex); + + return ret; +} + +static int ov2685_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + v4l2_ctrl_handler_free(&ov2685->ctrl_handler); + mutex_destroy(&ov2685->mutex); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + __ov2685_power_off(ov2685); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2685_of_match[] = { + { .compatible = "ovti,ov2685" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov2685_of_match); +#endif + +static struct i2c_driver ov2685_i2c_driver = { + .driver = { + .name = "ov2685", + .owner = THIS_MODULE, + .pm = &ov2685_pm_ops, + .of_match_table = of_match_ptr(ov2685_of_match), + }, + .probe = &ov2685_probe, + .remove = &ov2685_remove, +}; + +module_i2c_driver(ov2685_i2c_driver); + +MODULE_DESCRIPTION("OmniVision ov2685 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index e2dd352224c7..03940f0cdfa6 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -14,14 +14,14 @@ #include <linux/ctype.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/gpio/consumer.h> -#include <linux/regulator/consumer.h> #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -34,6 +34,8 @@ #define OV5640_DEFAULT_SLAVE_ID 0x3c +#define OV5640_REG_SYS_RESET02 0x3002 +#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 #define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_CHIP_ID 0x300a #define OV5640_REG_IO_MIPI_CTRL00 0x300e @@ -114,6 +116,7 @@ struct ov5640_pixfmt { }; static const struct ov5640_pixfmt ov5640_formats[] = { + { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, @@ -125,7 +128,7 @@ static const struct ov5640_pixfmt ov5640_formats[] = { * to set the MIPI CSI-2 virtual channel. */ static unsigned int virtual_channel; -module_param(virtual_channel, int, 0); +module_param(virtual_channel, uint, 0444); MODULE_PARM_DESC(virtual_channel, "MIPI CSI-2 virtual channel (0..3), default 0"); @@ -136,7 +139,7 @@ static const int ov5640_framerates[] = { /* regulator supplies */ static const char * const ov5640_supply_name[] = { - "DOVDD", /* Digital I/O (1.8V) suppply */ + "DOVDD", /* Digital I/O (1.8V) supply */ "DVDD", /* Digital Core (1.5V) supply */ "AVDD", /* Analog (2.8V) supply */ }; @@ -242,7 +245,6 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) */ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { - {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, @@ -331,7 +333,6 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { }; static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = { - {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, @@ -374,7 +375,6 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = { }; static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { - {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, @@ -481,6 +481,7 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; + static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, @@ -836,7 +837,7 @@ static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) ret = i2c_transfer(client->adapter, &msg, 1); if (ret < 0) { - v4l2_err(&sensor->sd, "%s: error: reg=%x, val=%x\n", + dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", __func__, reg, val); return ret; } @@ -865,8 +866,11 @@ static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) msg[1].len = 1; ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) + if (ret < 0) { + dev_err(&client->dev, "%s: error: reg=%x\n", + __func__, reg); return ret; + } *val = buf[0]; return 0; @@ -880,7 +884,7 @@ static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) ret = ov5640_read_reg(sensor, reg, &hi); if (ret) return ret; - ret = ov5640_read_reg(sensor, reg+1, &lo); + ret = ov5640_read_reg(sensor, reg + 1, &lo); if (ret) return ret; @@ -941,7 +945,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, break; if (delay_ms) - usleep_range(1000*delay_ms, 1000*delay_ms+100); + usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } return ret; @@ -1283,7 +1287,6 @@ static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) return ret; prev_vts = ret; - /* calculate banding filter */ /* 60Hz */ band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; @@ -1355,11 +1358,16 @@ static int ov5640_binning_on(struct ov5640_dev *sensor) static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) { + struct i2c_client *client = sensor->i2c_client; u8 temp, channel = virtual_channel; int ret; - if (channel > 3) + if (channel > 3) { + dev_err(&client->dev, + "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", + __func__, channel); return -EINVAL; + } ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); if (ret) @@ -1399,8 +1407,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, * sensor changes between scaling and subsampling, go through * exposure calculation */ -static int ov5640_set_mode_exposure_calc( - struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) +static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) { u32 prev_shutter, prev_gain16; u32 cap_shutter, cap_gain16; @@ -1410,7 +1418,7 @@ static int ov5640_set_mode_exposure_calc( u8 average; int ret; - if (mode->reg_data == NULL) + if (!mode->reg_data) return -EINVAL; /* read preview shutter */ @@ -1564,7 +1572,7 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, { int ret; - if (mode->reg_data == NULL) + if (!mode->reg_data) return -EINVAL; /* Write capture setting */ @@ -1915,6 +1923,7 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, { int ret = 0; bool is_rgb = false; + bool is_jpeg = false; u8 val; switch (format->code) { @@ -1936,6 +1945,11 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, val = 0x61; is_rgb = true; break; + case MEDIA_BUS_FMT_JPEG_1X8: + /* YUV422, YUYV */ + val = 0x30; + is_jpeg = true; + break; default: return -EINVAL; } @@ -1946,8 +1960,40 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - return ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, - is_rgb ? 0x01 : 0x00); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, + is_rgb ? 0x01 : 0x00); + if (ret) + return ret; + + /* + * TIMING TC REG21: + * - [5]: JPEG enable + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, + BIT(5), is_jpeg ? BIT(5) : 0); + if (ret) + return ret; + + /* + * SYSTEM RESET02: + * - [4]: Reset JFIFO + * - [3]: Reset SFIFO + * - [2]: Reset JPEG + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, + BIT(4) | BIT(3) | BIT(2), + is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); + if (ret) + return ret; + + /* + * CLOCK ENABLE02: + * - [5]: Enable JPEG 2x clock + * - [3]: Enable JPEG clock + */ + return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, + BIT(5) | BIT(3), + is_jpeg ? (BIT(5) | BIT(3)) : 0); } /* @@ -2073,7 +2119,8 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, int auto_gain) if (ctrls->auto_gain->is_new) { ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, - BIT(1), ctrls->auto_gain->val ? 0 : BIT(1)); + BIT(1), + ctrls->auto_gain->val ? 0 : BIT(1)); if (ret) return ret; } @@ -2253,10 +2300,12 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= OV5640_NUM_MODES) return -EINVAL; - fse->min_width = fse->max_width = + fse->min_width = ov5640_mode_data[0][fse->index].width; - fse->min_height = fse->max_height = + fse->max_width = fse->min_width; + fse->min_height = ov5640_mode_data[0][fse->index].height; + fse->max_height = fse->min_height; return 0; } @@ -2325,6 +2374,8 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, sensor->current_fr = frame_rate; sensor->frame_interval = fi->interval; + sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->width, + mode->height, true); sensor->pending_mode_change = true; out: mutex_unlock(&sensor->lock); @@ -2332,8 +2383,8 @@ out: } static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { if (code->pad != 0) return -EINVAL; diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 9f9196568eb8..d2db480da1b9 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1853,8 +1853,8 @@ static int ov5670_read_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); struct i2c_msg msgs[2]; u8 *data_be_p; - u32 data_be = 0; - u16 reg_addr_be = cpu_to_be16(reg); + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); int ret; if (len > 4) @@ -1891,6 +1891,7 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, int val_i; u8 buf[6]; u8 *val_p; + __be32 tmp; if (len > 4) return -EINVAL; @@ -1898,8 +1899,8 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, buf[0] = reg >> 8; buf[1] = reg & 0xff; - val = cpu_to_be32(val); - val_p = (u8 *)&val; + tmp = cpu_to_be32(val); + val_p = (u8 *)&tmp; buf_i = 2; val_i = 4 - len; @@ -2180,36 +2181,6 @@ static int ov5670_enum_frame_size(struct v4l2_subdev *sd, return 0; } -/* Calculate resolution distance */ -static int ov5670_get_reso_dist(const struct ov5670_mode *mode, - struct v4l2_mbus_framefmt *framefmt) -{ - return abs(mode->width - framefmt->width) + - abs(mode->height - framefmt->height); -} - -/* Find the closest supported resolution to the requested resolution */ -static const struct ov5670_mode *ov5670_find_best_fit( - struct ov5670 *ov5670, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *framefmt = &fmt->format; - int dist; - int cur_best_fit = 0; - int cur_best_fit_dist = -1; - int i; - - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = ov5670_get_reso_dist(&supported_modes[i], framefmt); - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { - cur_best_fit_dist = dist; - cur_best_fit = i; - } - } - - return &supported_modes[cur_best_fit]; -} - static void ov5670_update_pad_format(const struct ov5670_mode *mode, struct v4l2_subdev_format *fmt) { @@ -2259,7 +2230,8 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd, fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - mode = ov5670_find_best_fit(ov5670, fmt); + mode = v4l2_find_nearest_size(supported_modes, width, height, + fmt->format.width, fmt->format.height); ov5670_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c new file mode 100644 index 000000000000..9be38a0a2046 --- /dev/null +++ b/drivers/media/i2c/ov5695.c @@ -0,0 +1,1399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ov5695 driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/sysfs.h> +#include <media/media-entity.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> + +#ifndef V4L2_CID_DIGITAL_GAIN +#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN +#endif + +/* 45Mhz * 4 Binning */ +#define OV5695_PIXEL_RATE (45 * 1000 * 1000 * 4) +#define OV5695_XVCLK_FREQ 24000000 + +#define CHIP_ID 0x005695 +#define OV5695_REG_CHIP_ID 0x300a + +#define OV5695_REG_CTRL_MODE 0x0100 +#define OV5695_MODE_SW_STANDBY 0x0 +#define OV5695_MODE_STREAMING BIT(0) + +#define OV5695_REG_EXPOSURE 0x3500 +#define OV5695_EXPOSURE_MIN 4 +#define OV5695_EXPOSURE_STEP 1 +#define OV5695_VTS_MAX 0x7fff + +#define OV5695_REG_ANALOG_GAIN 0x3509 +#define ANALOG_GAIN_MIN 0x10 +#define ANALOG_GAIN_MAX 0xf8 +#define ANALOG_GAIN_STEP 1 +#define ANALOG_GAIN_DEFAULT 0xf8 + +#define OV5695_REG_DIGI_GAIN_H 0x350a +#define OV5695_REG_DIGI_GAIN_L 0x350b +#define OV5695_DIGI_GAIN_L_MASK 0x3f +#define OV5695_DIGI_GAIN_H_SHIFT 6 +#define OV5695_DIGI_GAIN_MIN 0 +#define OV5695_DIGI_GAIN_MAX (0x4000 - 1) +#define OV5695_DIGI_GAIN_STEP 1 +#define OV5695_DIGI_GAIN_DEFAULT 1024 + +#define OV5695_REG_TEST_PATTERN 0x4503 +#define OV5695_TEST_PATTERN_ENABLE 0x80 +#define OV5695_TEST_PATTERN_DISABLE 0x0 + +#define OV5695_REG_VTS 0x380e + +#define REG_NULL 0xFFFF + +#define OV5695_REG_VALUE_08BIT 1 +#define OV5695_REG_VALUE_16BIT 2 +#define OV5695_REG_VALUE_24BIT 3 + +#define OV5695_LANES 2 +#define OV5695_BITS_PER_SAMPLE 10 + +static const char * const ov5695_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV5695_NUM_SUPPLIES ARRAY_SIZE(ov5695_supply_names) + +struct regval { + u16 addr; + u8 val; +}; + +struct ov5695_mode { + u32 width; + u32 height; + u32 max_fps; + u32 hts_def; + u32 vts_def; + u32 exp_def; + const struct regval *reg_list; +}; + +struct ov5695 { + struct i2c_client *client; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV5695_NUM_SUPPLIES]; + + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *anal_gain; + struct v4l2_ctrl *digi_gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + struct mutex mutex; + bool streaming; + const struct ov5695_mode *cur_mode; +}; + +#define to_ov5695(sd) container_of(sd, struct ov5695, subdev) + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1296 + * grabwindow_height 972 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_global_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0301, 0x00}, + {0x0302, 0x69}, + {0x0303, 0x00}, + {0x0304, 0x00}, + {0x0305, 0x01}, + {0x0307, 0x00}, + {0x030b, 0x00}, + {0x030c, 0x00}, + {0x030d, 0x1e}, + {0x030e, 0x04}, + {0x030f, 0x03}, + {0x0312, 0x01}, + {0x3000, 0x00}, + {0x3002, 0xa1}, + {0x3008, 0x00}, + {0x3010, 0x00}, + {0x3022, 0x51}, + {0x3106, 0x15}, + {0x3107, 0x01}, + {0x3108, 0x05}, + {0x3500, 0x00}, + {0x3501, 0x45}, + {0x3502, 0x00}, + {0x3503, 0x08}, + {0x3504, 0x03}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0x55}, + {0x3602, 0x58}, + {0x3614, 0x30}, + {0x3615, 0x77}, + {0x3621, 0x08}, + {0x3624, 0x40}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3638, 0x00}, + {0x3639, 0x00}, + {0x363a, 0x00}, + {0x363b, 0x00}, + {0x363c, 0xff}, + {0x363d, 0xfa}, + {0x3650, 0x44}, + {0x3651, 0x44}, + {0x3652, 0x44}, + {0x3653, 0x44}, + {0x3654, 0x44}, + {0x3655, 0x44}, + {0x3656, 0x44}, + {0x3657, 0x44}, + {0x3660, 0x00}, + {0x3661, 0x00}, + {0x3662, 0x00}, + {0x366a, 0x00}, + {0x366e, 0x0c}, + {0x3673, 0x04}, + {0x3700, 0x14}, + {0x3703, 0x0c}, + {0x3715, 0x01}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x373f, 0xa0}, + {0x3765, 0x20}, + {0x37a1, 0x1d}, + {0x37a8, 0x26}, + {0x37ab, 0x14}, + {0x37c2, 0x04}, + {0x37cb, 0x09}, + {0x37cc, 0x13}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3810, 0x00}, + {0x3811, 0x06}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x381a, 0x00}, + {0x381b, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3c80, 0x08}, + {0x3c82, 0x00}, + {0x3c83, 0x00}, + {0x3c88, 0x00}, + {0x3d85, 0x14}, + {0x3f02, 0x08}, + {0x3f03, 0x10}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x404e, 0x20}, + {0x4501, 0x00}, + {0x4502, 0x10}, + {0x4800, 0x00}, + {0x481f, 0x2a}, + {0x4837, 0x13}, + {0x5000, 0x17}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5b00, 0x00}, + {0x5b01, 0x1c}, + {0x5b02, 0x00}, + {0x5b03, 0x7f}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x4010, 0xf1}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0xf8}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 740(0x2e4) + * framelength 2024(0x7e8) + * grabwindow_width 2592 + * grabwindow_height 1944 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_2592x1944_regs[] = { + {0x3501, 0x7e}, + {0x366e, 0x18}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xab}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x02}, + {0x380d, 0xe4}, + {0x380e, 0x07}, + {0x380f, 0xe8}, + {0x3811, 0x06}, + {0x3813, 0x08}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x3820, 0x88}, + {0x3821, 0x00}, + {0x4501, 0x00}, + {0x4008, 0x04}, + {0x4009, 0x13}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1920 + * grabwindow_height 1080 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1920x1080_regs[] = { + {0x3501, 0x45}, + {0x366e, 0x18}, + {0x3800, 0x01}, + {0x3801, 0x50}, + {0x3802, 0x01}, + {0x3803, 0xb8}, + {0x3804, 0x08}, + {0x3805, 0xef}, + {0x3806, 0x05}, + {0x3807, 0xf7}, + {0x3808, 0x07}, + {0x3809, 0x80}, + {0x380a, 0x04}, + {0x380b, 0x38}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3811, 0x06}, + {0x3813, 0x04}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x3820, 0x88}, + {0x3821, 0x00}, + {0x4501, 0x00}, + {0x4008, 0x04}, + {0x4009, 0x13}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 740(0x02e4) + * framelength 1012(0x03f4) + * grabwindow_width 1296 + * grabwindow_height 972 + * max_framerate 60fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1296x972_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0301, 0x00}, + {0x0302, 0x69}, + {0x0303, 0x00}, + {0x0304, 0x00}, + {0x0305, 0x01}, + {0x0307, 0x00}, + {0x030b, 0x00}, + {0x030c, 0x00}, + {0x030d, 0x1e}, + {0x030e, 0x04}, + {0x030f, 0x03}, + {0x0312, 0x01}, + {0x3000, 0x00}, + {0x3002, 0xa1}, + {0x3008, 0x00}, + {0x3010, 0x00}, + {0x3016, 0x32}, + {0x3022, 0x51}, + {0x3106, 0x15}, + {0x3107, 0x01}, + {0x3108, 0x05}, + {0x3500, 0x00}, + {0x3501, 0x3e}, + {0x3502, 0x00}, + {0x3503, 0x08}, + {0x3504, 0x03}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0x55}, + {0x3602, 0x58}, + {0x3611, 0x58}, + {0x3614, 0x30}, + {0x3615, 0x77}, + {0x3621, 0x08}, + {0x3624, 0x40}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3638, 0x00}, + {0x3639, 0x00}, + {0x363a, 0x00}, + {0x363b, 0x00}, + {0x363c, 0xff}, + {0x363d, 0xfa}, + {0x3650, 0x44}, + {0x3651, 0x44}, + {0x3652, 0x44}, + {0x3653, 0x44}, + {0x3654, 0x44}, + {0x3655, 0x44}, + {0x3656, 0x44}, + {0x3657, 0x44}, + {0x3660, 0x00}, + {0x3661, 0x00}, + {0x3662, 0x00}, + {0x366a, 0x00}, + {0x366e, 0x0c}, + {0x3673, 0x04}, + {0x3700, 0x14}, + {0x3703, 0x0c}, + {0x3706, 0x24}, + {0x3714, 0x27}, + {0x3715, 0x01}, + {0x3716, 0x00}, + {0x3717, 0x02}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x373f, 0xa0}, + {0x3765, 0x20}, + {0x37a1, 0x1d}, + {0x37a8, 0x26}, + {0x37ab, 0x14}, + {0x37c2, 0x04}, + {0x37c3, 0xf0}, + {0x37cb, 0x09}, + {0x37cc, 0x13}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, + {0x380c, 0x02}, + {0x380d, 0xe4}, + {0x380e, 0x03}, + {0x380f, 0xf4}, + {0x3810, 0x00}, + {0x3811, 0x00}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x381a, 0x00}, + {0x381b, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3c80, 0x08}, + {0x3c82, 0x00}, + {0x3c83, 0x00}, + {0x3c88, 0x00}, + {0x3d85, 0x14}, + {0x3f02, 0x08}, + {0x3f03, 0x10}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x404e, 0x20}, + {0x4501, 0x00}, + {0x4502, 0x10}, + {0x4800, 0x00}, + {0x481f, 0x2a}, + {0x4837, 0x13}, + {0x5000, 0x13}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5b00, 0x00}, + {0x5b01, 0x1c}, + {0x5b02, 0x00}, + {0x5b03, 0x7f}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x4010, 0xf1}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0xf8}, + {0x0100, 0x01}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1280 + * grabwindow_height 720 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1280x720_regs[] = { + {0x3501, 0x45}, + {0x366e, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x01}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x06}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3811, 0x06}, + {0x3813, 0x02}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x4501, 0x00}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 558(0x22e) + * grabwindow_width 640 + * grabwindow_height 480 + * max_framerate 120fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_640x480_regs[] = { + {0x3501, 0x22}, + {0x366e, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xa7}, + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0xe0}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x02}, + {0x380f, 0x2e}, + {0x3811, 0x06}, + {0x3813, 0x04}, + {0x3814, 0x07}, + {0x3816, 0x05}, + {0x3817, 0x03}, + {0x3820, 0x8d}, + {0x3821, 0x01}, + {0x4501, 0x00}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {REG_NULL, 0x00} +}; + +static const struct ov5695_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02e4 * 4, + .vts_def = 0x07e8, + .reg_list = ov5695_2592x1944_regs, + }, + { + .width = 1920, + .height = 1080, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x08b8, + .reg_list = ov5695_1920x1080_regs, + }, + { + .width = 1296, + .height = 972, + .max_fps = 60, + .exp_def = 0x03e0, + .hts_def = 0x02e4 * 4, + .vts_def = 0x03f4, + .reg_list = ov5695_1296x972_regs, + }, + { + .width = 1280, + .height = 720, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x08b8, + .reg_list = ov5695_1280x720_regs, + }, + { + .width = 640, + .height = 480, + .max_fps = 120, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x022e, + .reg_list = ov5695_640x480_regs, + }, +}; + +#define OV5695_LINK_FREQ_420MHZ 420000000 +static const s64 link_freq_menu_items[] = { + OV5695_LINK_FREQ_420MHZ +}; + +static const char * const ov5695_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +/* Write registers up to 4 at a time */ +static int ov5695_write_reg(struct i2c_client *client, u16 reg, + u32 len, u32 val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val_be = cpu_to_be32(val); + val_p = (u8 *)&val_be; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov5695_write_array(struct i2c_client *client, + const struct regval *regs) +{ + u32 i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) + ret = ov5695_write_reg(client, regs[i].addr, + OV5695_REG_VALUE_08BIT, regs[i].val); + + return ret; +} + +/* Read registers up to 4 at a time */ +static int ov5695_read_reg(struct i2c_client *client, u16 reg, unsigned int len, + u32 *val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +static int ov5695_get_reso_dist(const struct ov5695_mode *mode, + struct v4l2_mbus_framefmt *framefmt) +{ + return abs(mode->width - framefmt->width) + + abs(mode->height - framefmt->height); +} + +static const struct ov5695_mode * +ov5695_find_best_fit(struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt = &fmt->format; + int dist; + int cur_best_fit = 0; + int cur_best_fit_dist = -1; + int i; + + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + dist = ov5695_get_reso_dist(&supported_modes[i], framefmt); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + cur_best_fit = i; + } + } + + return &supported_modes[cur_best_fit]; +} + +static int ov5695_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + const struct ov5695_mode *mode; + s64 h_blank, vblank_def; + + mutex_lock(&ov5695->mutex); + + mode = ov5695_find_best_fit(fmt); + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; +#else + mutex_unlock(&ov5695->mutex); + return -ENOTTY; +#endif + } else { + ov5695->cur_mode = mode; + h_blank = mode->hts_def - mode->width; + __v4l2_ctrl_modify_range(ov5695->hblank, h_blank, + h_blank, 1, h_blank); + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov5695->vblank, vblank_def, + OV5695_VTS_MAX - mode->height, + 1, vblank_def); + } + + mutex_unlock(&ov5695->mutex); + + return 0; +} + +static int ov5695_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + const struct ov5695_mode *mode = ov5695->cur_mode; + + mutex_lock(&ov5695->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); +#else + mutex_unlock(&ov5695->mutex); + return -ENOTTY; +#endif + } else { + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.field = V4L2_FIELD_NONE; + } + mutex_unlock(&ov5695->mutex); + + return 0; +} + +static int ov5695_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = supported_modes[fse->index].width; + fse->max_height = supported_modes[fse->index].height; + fse->min_height = supported_modes[fse->index].height; + + return 0; +} + +static int ov5695_enable_test_pattern(struct ov5695 *ov5695, u32 pattern) +{ + u32 val; + + if (pattern) + val = (pattern - 1) | OV5695_TEST_PATTERN_ENABLE; + else + val = OV5695_TEST_PATTERN_DISABLE; + + return ov5695_write_reg(ov5695->client, OV5695_REG_TEST_PATTERN, + OV5695_REG_VALUE_08BIT, val); +} + +static int __ov5695_start_stream(struct ov5695 *ov5695) +{ + int ret; + + ret = ov5695_write_array(ov5695->client, ov5695_global_regs); + if (ret) + return ret; + ret = ov5695_write_array(ov5695->client, ov5695->cur_mode->reg_list); + if (ret) + return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&ov5695->ctrl_handler); + if (ret) + return ret; + + return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE, + OV5695_REG_VALUE_08BIT, OV5695_MODE_STREAMING); +} + +static int __ov5695_stop_stream(struct ov5695 *ov5695) +{ + return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE, + OV5695_REG_VALUE_08BIT, OV5695_MODE_SW_STANDBY); +} + +static int ov5695_s_stream(struct v4l2_subdev *sd, int on) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + struct i2c_client *client = ov5695->client; + int ret = 0; + + mutex_lock(&ov5695->mutex); + on = !!on; + if (on == ov5695->streaming) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = __ov5695_start_stream(ov5695); + if (ret) { + v4l2_err(sd, "start stream failed while write regs\n"); + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + } else { + __ov5695_stop_stream(ov5695); + pm_runtime_put(&client->dev); + } + + ov5695->streaming = on; + +unlock_and_return: + mutex_unlock(&ov5695->mutex); + + return ret; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 ov5695_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000); +} + +static int __ov5695_power_on(struct ov5695 *ov5695) +{ + int ret; + u32 delay_us; + struct device *dev = &ov5695->client->dev; + + ret = clk_prepare_enable(ov5695->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + gpiod_set_value_cansleep(ov5695->reset_gpio, 1); + + ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + gpiod_set_value_cansleep(ov5695->reset_gpio, 0); + + /* 8192 cycles prior to first SCCB transaction */ + delay_us = ov5695_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); + + return 0; + +disable_clk: + clk_disable_unprepare(ov5695->xvclk); + + return ret; +} + +static void __ov5695_power_off(struct ov5695 *ov5695) +{ + clk_disable_unprepare(ov5695->xvclk); + gpiod_set_value_cansleep(ov5695->reset_gpio, 1); + regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies); +} + +static int __maybe_unused ov5695_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + return __ov5695_power_on(ov5695); +} + +static int __maybe_unused ov5695_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + __ov5695_power_off(ov5695); + + return 0; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + const struct ov5695_mode *def_mode = &supported_modes[0]; + + mutex_lock(&ov5695->mutex); + /* Initialize try_fmt */ + try_fmt->width = def_mode->width; + try_fmt->height = def_mode->height; + try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + try_fmt->field = V4L2_FIELD_NONE; + + mutex_unlock(&ov5695->mutex); + /* No crop or compose */ + + return 0; +} +#endif + +static const struct dev_pm_ops ov5695_pm_ops = { + SET_RUNTIME_PM_OPS(ov5695_runtime_suspend, + ov5695_runtime_resume, NULL) +}; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops ov5695_internal_ops = { + .open = ov5695_open, +}; +#endif + +static const struct v4l2_subdev_video_ops ov5695_video_ops = { + .s_stream = ov5695_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov5695_pad_ops = { + .enum_mbus_code = ov5695_enum_mbus_code, + .enum_frame_size = ov5695_enum_frame_sizes, + .get_fmt = ov5695_get_fmt, + .set_fmt = ov5695_set_fmt, +}; + +static const struct v4l2_subdev_ops ov5695_subdev_ops = { + .video = &ov5695_video_ops, + .pad = &ov5695_pad_ops, +}; + +static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5695 *ov5695 = container_of(ctrl->handler, + struct ov5695, ctrl_handler); + struct i2c_client *client = ov5695->client; + s64 max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = ov5695->cur_mode->height + ctrl->val - 4; + __v4l2_ctrl_modify_range(ov5695->exposure, + ov5695->exposure->minimum, max, + ov5695->exposure->step, + ov5695->exposure->default_value); + break; + } + + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of expsoure are fractional part */ + ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE, + OV5695_REG_VALUE_24BIT, ctrl->val << 4); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_ANALOG_GAIN, + OV5695_REG_VALUE_08BIT, ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_L, + OV5695_REG_VALUE_08BIT, + ctrl->val & OV5695_DIGI_GAIN_L_MASK); + ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H, + OV5695_REG_VALUE_08BIT, + ctrl->val >> OV5695_DIGI_GAIN_H_SHIFT); + break; + case V4L2_CID_VBLANK: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_VTS, + OV5695_REG_VALUE_16BIT, + ctrl->val + ov5695->cur_mode->height); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov5695_enable_test_pattern(ov5695, ctrl->val); + break; + default: + dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + }; + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov5695_ctrl_ops = { + .s_ctrl = ov5695_set_ctrl, +}; + +static int ov5695_initialize_controls(struct ov5695 *ov5695) +{ + const struct ov5695_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + s64 exposure_max, vblank_def; + u32 h_blank; + int ret; + + handler = &ov5695->ctrl_handler; + mode = ov5695->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 8); + if (ret) + return ret; + handler->lock = &ov5695->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, OV5695_PIXEL_RATE, 1, OV5695_PIXEL_RATE); + + h_blank = mode->hts_def - mode->width; + ov5695->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov5695->hblank) + ov5695->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_def = mode->vts_def - mode->height; + ov5695->vblank = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV5695_VTS_MAX - mode->height, + 1, vblank_def); + + exposure_max = mode->vts_def - 4; + ov5695->exposure = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_EXPOSURE, OV5695_EXPOSURE_MIN, + exposure_max, OV5695_EXPOSURE_STEP, + mode->exp_def); + + ov5695->anal_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, ANALOG_GAIN_MIN, + ANALOG_GAIN_MAX, ANALOG_GAIN_STEP, + ANALOG_GAIN_DEFAULT); + + /* Digital gain */ + ov5695->digi_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, OV5695_DIGI_GAIN_MIN, + OV5695_DIGI_GAIN_MAX, OV5695_DIGI_GAIN_STEP, + OV5695_DIGI_GAIN_DEFAULT); + + ov5695->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &ov5695_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5695_test_pattern_menu) - 1, + 0, 0, ov5695_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_err(&ov5695->client->dev, + "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ov5695->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov5695_check_sensor_id(struct ov5695 *ov5695, + struct i2c_client *client) +{ + struct device *dev = &ov5695->client->dev; + u32 id = 0; + int ret; + + ret = ov5695_read_reg(client, OV5695_REG_CHIP_ID, + OV5695_REG_VALUE_24BIT, &id); + if (id != CHIP_ID) { + dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret); + return ret; + } + + dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); + + return 0; +} + +static int ov5695_configure_regulators(struct ov5695 *ov5695) +{ + int i; + + for (i = 0; i < OV5695_NUM_SUPPLIES; i++) + ov5695->supplies[i].supply = ov5695_supply_names[i]; + + return devm_regulator_bulk_get(&ov5695->client->dev, + OV5695_NUM_SUPPLIES, + ov5695->supplies); +} + +static int ov5695_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ov5695 *ov5695; + struct v4l2_subdev *sd; + int ret; + + ov5695 = devm_kzalloc(dev, sizeof(*ov5695), GFP_KERNEL); + if (!ov5695) + return -ENOMEM; + + ov5695->client = client; + ov5695->cur_mode = &supported_modes[0]; + + ov5695->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov5695->xvclk)) { + dev_err(dev, "Failed to get xvclk\n"); + return -EINVAL; + } + ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ); + if (ret < 0) { + dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); + return ret; + } + if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov5695->reset_gpio)) { + dev_err(dev, "Failed to get reset-gpios\n"); + return -EINVAL; + } + + ret = ov5695_configure_regulators(ov5695); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + + mutex_init(&ov5695->mutex); + + sd = &ov5695->subdev; + v4l2_i2c_subdev_init(sd, client, &ov5695_subdev_ops); + ret = ov5695_initialize_controls(ov5695); + if (ret) + goto err_destroy_mutex; + + ret = __ov5695_power_on(ov5695); + if (ret) + goto err_free_handler; + + ret = ov5695_check_sensor_id(ov5695, client); + if (ret) + goto err_power_off; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sd->internal_ops = &ov5695_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif +#if defined(CONFIG_MEDIA_CONTROLLER) + ov5695->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad); + if (ret < 0) + goto err_power_off; +#endif + + ret = v4l2_async_register_subdev(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +err_clean_entity: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif +err_power_off: + __ov5695_power_off(ov5695); +err_free_handler: + v4l2_ctrl_handler_free(&ov5695->ctrl_handler); +err_destroy_mutex: + mutex_destroy(&ov5695->mutex); + + return ret; +} + +static int ov5695_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + v4l2_ctrl_handler_free(&ov5695->ctrl_handler); + mutex_destroy(&ov5695->mutex); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + __ov5695_power_off(ov5695); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov5695_of_match[] = { + { .compatible = "ovti,ov5695" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov5695_of_match); +#endif + +static struct i2c_driver ov5695_i2c_driver = { + .driver = { + .name = "ov5695", + .owner = THIS_MODULE, + .pm = &ov5695_pm_ops, + .of_match_table = of_match_ptr(ov5695_of_match), + }, + .probe = &ov5695_probe, + .remove = &ov5695_remove, +}; + +module_i2c_driver(ov5695_i2c_driver); + +MODULE_DESCRIPTION("OmniVision ov5695 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 8975d16b2b24..17a34b4a819d 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -201,7 +201,7 @@ struct ov6650 { struct v4l2_rect rect; /* sensor cropping window */ unsigned long pclk_limit; /* from host */ unsigned long pclk_max; /* from resolution and format */ - struct v4l2_fract tpf; /* as requested with s_parm */ + struct v4l2_fract tpf; /* as requested with s_frame_interval */ u32 code; enum v4l2_colorspace colorspace; }; @@ -723,42 +723,31 @@ static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov6650_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(*cp)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, + ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max)); - cp->timeperframe.denominator = FRAME_RATE_MAX; + ival->interval.denominator = FRAME_RATE_MAX; dev_dbg(&client->dev, "Frame interval: %u/%u s\n", - cp->timeperframe.numerator, cp->timeperframe.denominator); + ival->interval.numerator, ival->interval.denominator); return 0; } -static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov6650_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; int div, ret; u8 clkrc; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cp->extendedmode != 0) - return -EINVAL; - if (tpf->numerator == 0 || tpf->denominator == 0) div = 1; /* Reset to full rate */ else @@ -921,8 +910,8 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, - .g_parm = ov6650_g_parm, - .s_parm = ov6650_s_parm, + .g_frame_interval = ov6650_g_frame_interval, + .s_frame_interval = ov6650_s_frame_interval, .g_mbus_config = ov6650_g_mbus_config, .s_mbus_config = ov6650_s_mbus_config, }; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 28571de1c2f6..3474ef832c1e 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -21,6 +21,7 @@ #include <linux/gpio/consumer.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-image-sizes.h> #include <media/i2c/ov7670.h> @@ -242,6 +243,7 @@ struct ov7670_info { struct clk *clk; struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; + unsigned int mbus_config; /* Media bus configuration flags */ int min_width; /* Filter out smaller sizes */ int min_height; /* Filter out smaller sizes */ int clock_speed; /* External clock speed (MHz) */ @@ -1014,7 +1016,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; #endif - unsigned char com7; + unsigned char com7, com10 = 0; int ret; if (format->pad) @@ -1034,7 +1036,6 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, } ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); - if (ret) return ret; /* @@ -1045,16 +1046,41 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, */ com7 = ovfmt->regs[0].value; com7 |= wsize->com7_bit; - ov7670_write(sd, REG_COM7, com7); + ret = ov7670_write(sd, REG_COM7, com7); + if (ret) + return ret; + + /* + * Configure the media bus through COM10 register + */ + if (info->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW) + com10 |= COM10_VS_NEG; + if (info->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW) + com10 |= COM10_HREF_REV; + if (info->pclk_hb_disable) + com10 |= COM10_PCLK_HB; + ret = ov7670_write(sd, REG_COM10, com10); + if (ret) + return ret; + /* * Now write the rest of the array. Also store start/stops */ - ov7670_write_array(sd, ovfmt->regs + 1); - ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, - wsize->vstop); - ret = 0; - if (wsize->regs) + ret = ov7670_write_array(sd, ovfmt->regs + 1); + if (ret) + return ret; + + ret = ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, + wsize->vstop); + if (ret) + return ret; + + if (wsize->regs) { ret = ov7670_write_array(sd, wsize->regs); + if (ret) + return ret; + } + info->fmt = ovfmt; /* @@ -1067,8 +1093,10 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, * to write it unconditionally, and that will make the frame * rate persistent too. */ - if (ret == 0) - ret = ov7670_write(sd, REG_CLKRC, info->clkrc); + ret = ov7670_write(sd, REG_CLKRC, info->clkrc); + if (ret) + return ret; + return 0; } @@ -1100,30 +1128,24 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, * Implement G/S_PARM. There is a "high quality" mode we could try * to do someday; for now, we just do the frame rate tweak. */ -static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov7670_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; struct ov7670_info *info = to_state(sd); - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cp->capability = V4L2_CAP_TIMEPERFRAME; - info->devtype->get_framerate(sd, &cp->timeperframe); + info->devtype->get_framerate(sd, &ival->interval); return 0; } -static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov7670_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; struct ov7670_info *info = to_state(sd); - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cp->capability = V4L2_CAP_TIMEPERFRAME; return info->devtype->set_framerate(sd, tpf); } @@ -1636,8 +1658,8 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { }; static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .s_parm = ov7670_s_parm, - .g_parm = ov7670_g_parm, + .s_frame_interval = ov7670_s_frame_interval, + .g_frame_interval = ov7670_g_frame_interval, }; static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { @@ -1698,6 +1720,45 @@ static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info) return 0; } +/* + * ov7670_parse_dt() - Parse device tree to collect mbus configuration + * properties + */ +static int ov7670_parse_dt(struct device *dev, + struct ov7670_info *info) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg; + struct fwnode_handle *ep; + int ret; + + if (!fwnode) + return -EINVAL; + + info->pclk_hb_disable = false; + if (fwnode_property_present(fwnode, "ov7670,pclk-hb-disable")) + info->pclk_hb_disable = true; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_parse(ep, &bus_cfg); + if (ret) { + fwnode_handle_put(ep); + return ret; + } + + if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) { + dev_err(dev, "Unsupported media bus type\n"); + fwnode_handle_put(ep); + return ret; + } + info->mbus_config = bus_cfg.bus.parallel.flags; + + return 0; +} + static int ov7670_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1718,7 +1779,13 @@ static int ov7670_probe(struct i2c_client *client, #endif info->clock_speed = 30; /* default: a guess */ - if (client->dev.platform_data) { + + if (dev_fwnode(&client->dev)) { + ret = ov7670_parse_dt(&client->dev, info); + if (ret) + return ret; + + } else if (client->dev.platform_data) { struct ov7670_config *config = client->dev.platform_data; /* @@ -1785,9 +1852,6 @@ static int ov7670_probe(struct i2c_client *client, tpf.denominator = 30; info->devtype->set_framerate(sd, &tpf); - if (info->pclk_hb_disable) - ov7670_write(sd, REG_COM10, COM10_PCLK_HB); - v4l2_ctrl_handler_init(&info->hdl, 10); v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c new file mode 100644 index 000000000000..b62860c89439 --- /dev/null +++ b/drivers/media/i2c/ov772x.c @@ -0,0 +1,1356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ov772x Camera Driver + * + * Copyright (C) 2017 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ov7670 and soc_camera_platform driver, + * + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> + +#include <media/i2c/ov772x.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-subdev.h> + +/* + * register offset + */ +#define GAIN 0x00 /* AGC - Gain control gain setting */ +#define BLUE 0x01 /* AWB - Blue channel gain setting */ +#define RED 0x02 /* AWB - Red channel gain setting */ +#define GREEN 0x03 /* AWB - Green channel gain setting */ +#define COM1 0x04 /* Common control 1 */ +#define BAVG 0x05 /* U/B Average Level */ +#define GAVG 0x06 /* Y/Gb Average Level */ +#define RAVG 0x07 /* V/R Average Level */ +#define AECH 0x08 /* Exposure Value - AEC MSBs */ +#define COM2 0x09 /* Common control 2 */ +#define PID 0x0A /* Product ID Number MSB */ +#define VER 0x0B /* Product ID Number LSB */ +#define COM3 0x0C /* Common control 3 */ +#define COM4 0x0D /* Common control 4 */ +#define COM5 0x0E /* Common control 5 */ +#define COM6 0x0F /* Common control 6 */ +#define AEC 0x10 /* Exposure Value */ +#define CLKRC 0x11 /* Internal clock */ +#define COM7 0x12 /* Common control 7 */ +#define COM8 0x13 /* Common control 8 */ +#define COM9 0x14 /* Common control 9 */ +#define COM10 0x15 /* Common control 10 */ +#define REG16 0x16 /* Register 16 */ +#define HSTART 0x17 /* Horizontal sensor size */ +#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ +#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ +#define VSIZE 0x1A /* Vertical sensor size */ +#define PSHFT 0x1B /* Data format - pixel delay select */ +#define MIDH 0x1C /* Manufacturer ID byte - high */ +#define MIDL 0x1D /* Manufacturer ID byte - low */ +#define LAEC 0x1F /* Fine AEC value */ +#define COM11 0x20 /* Common control 11 */ +#define BDBASE 0x22 /* Banding filter Minimum AEC value */ +#define DBSTEP 0x23 /* Banding filter Maximum Setp */ +#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ +#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ +#define VPT 0x26 /* AGC/AEC Fast mode operating region */ +#define REG28 0x28 /* Register 28 */ +#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ +#define EXHCH 0x2A /* Dummy pixel insert MSB */ +#define EXHCL 0x2B /* Dummy pixel insert LSB */ +#define VOUTSIZE 0x2C /* Vertical data output size MSBs */ +#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ +#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */ +#define YAVE 0x2F /* Y/G Channel Average value */ +#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */ +#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */ +#define HREF 0x32 /* Image start and size control */ +#define DM_LNL 0x33 /* Dummy line low 8 bits */ +#define DM_LNH 0x34 /* Dummy line high 8 bits */ +#define ADOFF_B 0x35 /* AD offset compensation value for B channel */ +#define ADOFF_R 0x36 /* AD offset compensation value for R channel */ +#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */ +#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */ +#define OFF_B 0x39 /* Analog process B channel offset value */ +#define OFF_R 0x3A /* Analog process R channel offset value */ +#define OFF_GB 0x3B /* Analog process Gb channel offset value */ +#define OFF_GR 0x3C /* Analog process Gr channel offset value */ +#define COM12 0x3D /* Common control 12 */ +#define COM13 0x3E /* Common control 13 */ +#define COM14 0x3F /* Common control 14 */ +#define COM15 0x40 /* Common control 15*/ +#define COM16 0x41 /* Common control 16 */ +#define TGT_B 0x42 /* BLC blue channel target value */ +#define TGT_R 0x43 /* BLC red channel target value */ +#define TGT_GB 0x44 /* BLC Gb channel target value */ +#define TGT_GR 0x45 /* BLC Gr channel target value */ +/* for ov7720 */ +#define LCC0 0x46 /* Lens correction control 0 */ +#define LCC1 0x47 /* Lens correction option 1 - X coordinate */ +#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ +#define LCC3 0x49 /* Lens correction option 3 */ +#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ +#define LCC5 0x4B /* Lens correction option 5 */ +#define LCC6 0x4C /* Lens correction option 6 */ +/* for ov7725 */ +#define LC_CTR 0x46 /* Lens correction control */ +#define LC_XC 0x47 /* X coordinate of lens correction center relative */ +#define LC_YC 0x48 /* Y coordinate of lens correction center relative */ +#define LC_COEF 0x49 /* Lens correction coefficient */ +#define LC_RADI 0x4A /* Lens correction radius */ +#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */ +#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */ + +#define FIXGAIN 0x4D /* Analog fix gain amplifer */ +#define AREF0 0x4E /* Sensor reference control */ +#define AREF1 0x4F /* Sensor reference current control */ +#define AREF2 0x50 /* Analog reference control */ +#define AREF3 0x51 /* ADC reference control */ +#define AREF4 0x52 /* ADC reference control */ +#define AREF5 0x53 /* ADC reference control */ +#define AREF6 0x54 /* Analog reference control */ +#define AREF7 0x55 /* Analog reference control */ +#define UFIX 0x60 /* U channel fixed value output */ +#define VFIX 0x61 /* V channel fixed value output */ +#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ +#define AWB_CTRL0 0x63 /* AWB control byte 0 */ +#define DSP_CTRL1 0x64 /* DSP control byte 1 */ +#define DSP_CTRL2 0x65 /* DSP control byte 2 */ +#define DSP_CTRL3 0x66 /* DSP control byte 3 */ +#define DSP_CTRL4 0x67 /* DSP control byte 4 */ +#define AWB_BIAS 0x68 /* AWB BLC level clip */ +#define AWB_CTRL1 0x69 /* AWB control 1 */ +#define AWB_CTRL2 0x6A /* AWB control 2 */ +#define AWB_CTRL3 0x6B /* AWB control 3 */ +#define AWB_CTRL4 0x6C /* AWB control 4 */ +#define AWB_CTRL5 0x6D /* AWB control 5 */ +#define AWB_CTRL6 0x6E /* AWB control 6 */ +#define AWB_CTRL7 0x6F /* AWB control 7 */ +#define AWB_CTRL8 0x70 /* AWB control 8 */ +#define AWB_CTRL9 0x71 /* AWB control 9 */ +#define AWB_CTRL10 0x72 /* AWB control 10 */ +#define AWB_CTRL11 0x73 /* AWB control 11 */ +#define AWB_CTRL12 0x74 /* AWB control 12 */ +#define AWB_CTRL13 0x75 /* AWB control 13 */ +#define AWB_CTRL14 0x76 /* AWB control 14 */ +#define AWB_CTRL15 0x77 /* AWB control 15 */ +#define AWB_CTRL16 0x78 /* AWB control 16 */ +#define AWB_CTRL17 0x79 /* AWB control 17 */ +#define AWB_CTRL18 0x7A /* AWB control 18 */ +#define AWB_CTRL19 0x7B /* AWB control 19 */ +#define AWB_CTRL20 0x7C /* AWB control 20 */ +#define AWB_CTRL21 0x7D /* AWB control 21 */ +#define GAM1 0x7E /* Gamma Curve 1st segment input end point */ +#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ +#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ +#define GAM4 0x81 /* Gamma Curve 4th segment input end point */ +#define GAM5 0x82 /* Gamma Curve 5th segment input end point */ +#define GAM6 0x83 /* Gamma Curve 6th segment input end point */ +#define GAM7 0x84 /* Gamma Curve 7th segment input end point */ +#define GAM8 0x85 /* Gamma Curve 8th segment input end point */ +#define GAM9 0x86 /* Gamma Curve 9th segment input end point */ +#define GAM10 0x87 /* Gamma Curve 10th segment input end point */ +#define GAM11 0x88 /* Gamma Curve 11th segment input end point */ +#define GAM12 0x89 /* Gamma Curve 12th segment input end point */ +#define GAM13 0x8A /* Gamma Curve 13th segment input end point */ +#define GAM14 0x8B /* Gamma Curve 14th segment input end point */ +#define GAM15 0x8C /* Gamma Curve 15th segment input end point */ +#define SLOP 0x8D /* Gamma curve highest segment slope */ +#define DNSTH 0x8E /* De-noise threshold */ +#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */ +#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */ +#define DNSOFF 0x91 /* Auto De-noise threshold control */ +#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */ +#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */ +#define MTX1 0x94 /* Matrix coefficient 1 */ +#define MTX2 0x95 /* Matrix coefficient 2 */ +#define MTX3 0x96 /* Matrix coefficient 3 */ +#define MTX4 0x97 /* Matrix coefficient 4 */ +#define MTX5 0x98 /* Matrix coefficient 5 */ +#define MTX6 0x99 /* Matrix coefficient 6 */ +#define MTX_CTRL 0x9A /* Matrix control */ +#define BRIGHT 0x9B /* Brightness control */ +#define CNTRST 0x9C /* Contrast contrast */ +#define CNTRST_CTRL 0x9D /* Contrast contrast center */ +#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */ +#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */ +#define SCAL0 0xA0 /* Scaling control 0 */ +#define SCAL1 0xA1 /* Scaling control 1 */ +#define SCAL2 0xA2 /* Scaling control 2 */ +#define FIFODLYM 0xA3 /* FIFO manual mode delay control */ +#define FIFODLYA 0xA4 /* FIFO auto mode delay control */ +#define SDE 0xA6 /* Special digital effect control */ +#define USAT 0xA7 /* U component saturation control */ +#define VSAT 0xA8 /* V component saturation control */ +/* for ov7720 */ +#define HUE0 0xA9 /* Hue control 0 */ +#define HUE1 0xAA /* Hue control 1 */ +/* for ov7725 */ +#define HUECOS 0xA9 /* Cosine value */ +#define HUESIN 0xAA /* Sine value */ + +#define SIGN 0xAB /* Sign bit for Hue and contrast */ +#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ + +/* + * register detail + */ + +/* COM2 */ +#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ + /* Output drive capability */ +#define OCAP_1x 0x00 /* 1x */ +#define OCAP_2x 0x01 /* 2x */ +#define OCAP_3x 0x02 /* 3x */ +#define OCAP_4x 0x03 /* 4x */ + +/* COM3 */ +#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) +#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) + +#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ +#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ +#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ +#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ +#define SWAP_ML 0x08 /* Swap output MSB/LSB */ + /* Tri-state option for output clock */ +#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ + /* Tri-state option for output data */ +#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ +#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */ + +/* COM4 */ + /* PLL frequency control */ +#define PLL_BYPASS 0x00 /* 00: Bypass PLL */ +#define PLL_4x 0x40 /* 01: PLL 4x */ +#define PLL_6x 0x80 /* 10: PLL 6x */ +#define PLL_8x 0xc0 /* 11: PLL 8x */ + /* AEC evaluate window */ +#define AEC_FULL 0x00 /* 00: Full window */ +#define AEC_1p2 0x10 /* 01: 1/2 window */ +#define AEC_1p4 0x20 /* 10: 1/4 window */ +#define AEC_2p3 0x30 /* 11: Low 2/3 window */ +#define COM4_RESERVED 0x01 /* Reserved bit */ + +/* COM5 */ +#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ +#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */ + /* Auto frame rate max rate control */ +#define AFR_NO_RATE 0x00 /* No reduction of frame rate */ +#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */ +#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */ +#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */ + /* Auto frame rate active point control */ +#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */ +#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */ +#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ +#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ + /* AEC max step control */ +#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ + /* 1 : No limit to AEC increase step */ +/* CLKRC */ + /* Input clock divider register */ +#define CLKRC_RESERVED 0x80 /* Reserved bit */ +#define CLKRC_DIV(n) ((n) - 1) + +/* COM7 */ + /* SCCB Register Reset */ +#define SCCB_RESET 0x80 /* 0 : No change */ + /* 1 : Resets all registers to default */ + /* Resolution selection */ +#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */ +#define SLCT_VGA 0x00 /* 0 : VGA */ +#define SLCT_QVGA 0x40 /* 1 : QVGA */ +#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ +#define SENSOR_RAW 0x10 /* Sensor RAW */ + /* RGB output format control */ +#define FMT_MASK 0x0c /* Mask of color format */ +#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ +#define FMT_RGB565 0x04 /* 01 : RGB 565 */ +#define FMT_RGB555 0x08 /* 10 : RGB 555 */ +#define FMT_RGB444 0x0c /* 11 : RGB 444 */ + /* Output format control */ +#define OFMT_MASK 0x03 /* Mask of output format */ +#define OFMT_YUV 0x00 /* 00 : YUV */ +#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ +#define OFMT_RGB 0x02 /* 10 : RGB */ +#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */ + +/* COM8 */ +#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */ + /* AEC Setp size limit */ +#define UNLMT_STEP 0x40 /* 0 : Step size is limited */ + /* 1 : Unlimited step size */ +#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */ +#define AEC_BND 0x10 /* Enable AEC below banding value */ +#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */ +#define AGC_ON 0x04 /* AGC Enable */ +#define AWB_ON 0x02 /* AWB Enable */ +#define AEC_ON 0x01 /* AEC Enable */ + +/* COM9 */ +#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */ + /* Automatic gain ceiling - maximum AGC value */ +#define GAIN_2x 0x00 /* 000 : 2x */ +#define GAIN_4x 0x10 /* 001 : 4x */ +#define GAIN_8x 0x20 /* 010 : 8x */ +#define GAIN_16x 0x30 /* 011 : 16x */ +#define GAIN_32x 0x40 /* 100 : 32x */ +#define GAIN_64x 0x50 /* 101 : 64x */ +#define GAIN_128x 0x60 /* 110 : 128x */ +#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ +#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ + +/* COM11 */ +#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */ +#define SGLF_TRIG 0x01 /* Single frame transfer trigger */ + +/* HREF */ +#define HREF_VSTART_SHIFT 6 /* VSTART LSB */ +#define HREF_HSTART_SHIFT 4 /* HSTART 2 LSBs */ +#define HREF_VSIZE_SHIFT 2 /* VSIZE LSB */ +#define HREF_HSIZE_SHIFT 0 /* HSIZE 2 LSBs */ + +/* EXHCH */ +#define EXHCH_VSIZE_SHIFT 2 /* VOUTSIZE LSB */ +#define EXHCH_HSIZE_SHIFT 0 /* HOUTSIZE 2 LSBs */ + +/* DSP_CTRL1 */ +#define FIFO_ON 0x80 /* FIFO enable/disable selection */ +#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */ +#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */ +#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */ +#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */ +#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */ +#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */ +#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */ + +/* DSP_CTRL3 */ +#define UV_MASK 0x80 /* UV output sequence option */ +#define UV_ON 0x80 /* ON */ +#define UV_OFF 0x00 /* OFF */ +#define CBAR_MASK 0x20 /* DSP Color bar mask */ +#define CBAR_ON 0x20 /* ON */ +#define CBAR_OFF 0x00 /* OFF */ + +/* DSP_CTRL4 */ +#define DSP_OFMT_YUV 0x00 +#define DSP_OFMT_RGB 0x00 +#define DSP_OFMT_RAW8 0x02 +#define DSP_OFMT_RAW10 0x03 + +/* DSPAUTO (DSP Auto Function ON/OFF Control) */ +#define AWB_ACTRL 0x80 /* AWB auto threshold control */ +#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */ +#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */ +#define UV_ACTRL 0x10 /* UV adjust auto slope control */ +#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ +#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ + +#define OV772X_MAX_WIDTH VGA_WIDTH +#define OV772X_MAX_HEIGHT VGA_HEIGHT + +/* + * ID + */ +#define OV7720 0x7720 +#define OV7725 0x7721 +#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) + +/* + * PLL multipliers + */ +static struct { + unsigned int mult; + u8 com4; +} ov772x_pll[] = { + { 1, PLL_BYPASS, }, + { 4, PLL_4x, }, + { 6, PLL_6x, }, + { 8, PLL_8x, }, +}; + +/* + * struct + */ + +struct ov772x_color_format { + u32 code; + enum v4l2_colorspace colorspace; + u8 dsp3; + u8 dsp4; + u8 com3; + u8 com7; +}; + +struct ov772x_win_size { + char *name; + unsigned char com7_bit; + unsigned int sizeimage; + struct v4l2_rect rect; +}; + +struct ov772x_priv { + struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct clk *clk; + struct ov772x_camera_info *info; + struct gpio_desc *pwdn_gpio; + struct gpio_desc *rstb_gpio; + const struct ov772x_color_format *cfmt; + const struct ov772x_win_size *win; + unsigned short flag_vflip:1; + unsigned short flag_hflip:1; + /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ + unsigned short band_filter; + unsigned int fps; +}; + +/* + * supported color format list + */ +static const struct ov772x_color_format ov772x_cfmts[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = UV_ON, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_RGB, + .com7 = FMT_RGB555 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = FMT_RGB555 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_RGB, + .com7 = FMT_RGB565 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = FMT_RGB565 | OFMT_RGB, + }, + { + /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output, + * regardless of the COM7 value. We can thus only support 10-bit + * Bayer until someone figures it out. + */ + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_RAW10, + .com3 = 0x0, + .com7 = SENSOR_RAW | OFMT_BRAW, + }, +}; + +/* + * window size list + */ + +static const struct ov772x_win_size ov772x_win_sizes[] = { + { + .name = "VGA", + .com7_bit = SLCT_VGA, + .sizeimage = 510 * 748, + .rect = { + .left = 140, + .top = 14, + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + }, + }, { + .name = "QVGA", + .com7_bit = SLCT_QVGA, + .sizeimage = 278 * 576, + .rect = { + .left = 252, + .top = 6, + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, + }, + }, +}; + +/* + * frame rate settings lists + */ +static const unsigned int ov772x_frame_intervals[] = { 5, 10, 15, 20, 30, 60 }; + +/* + * general function + */ + +static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov772x_priv, subdev); +} + +static inline int ov772x_read(struct i2c_client *client, u8 addr) +{ + return i2c_smbus_read_byte_data(client, addr); +} + +static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value) +{ + return i2c_smbus_write_byte_data(client, addr, value); +} + +static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask, + u8 set) +{ + s32 val = ov772x_read(client, command); + + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return ov772x_write(client, command, val); +} + +static int ov772x_reset(struct i2c_client *client) +{ + int ret; + + ret = ov772x_write(client, COM7, SCCB_RESET); + if (ret < 0) + return ret; + + usleep_range(1000, 5000); + + return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); +} + +/* + * subdev ops + */ + +static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov772x_priv *priv = to_ov772x(sd); + + if (!enable) { + ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); + return 0; + } + + ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); + + dev_dbg(&client->dev, "format %d, win %s\n", + priv->cfmt->code, priv->win->name); + + return 0; +} + +static int ov772x_set_frame_rate(struct ov772x_priv *priv, + struct v4l2_fract *tpf, + const struct ov772x_color_format *cfmt, + const struct ov772x_win_size *win) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + unsigned long fin = clk_get_rate(priv->clk); + unsigned int fps = tpf->numerator ? + tpf->denominator / tpf->numerator : + tpf->denominator; + unsigned int best_diff; + unsigned int fsize; + unsigned int pclk; + unsigned int diff; + unsigned int idx; + unsigned int i; + u8 clkrc = 0; + u8 com4 = 0; + int ret; + + /* Approximate to the closest supported frame interval. */ + best_diff = ~0L; + for (i = 0, idx = 0; i < ARRAY_SIZE(ov772x_frame_intervals); i++) { + diff = abs(fps - ov772x_frame_intervals[i]); + if (diff < best_diff) { + idx = i; + best_diff = diff; + } + } + fps = ov772x_frame_intervals[idx]; + + /* Use image size (with blankings) to calculate desired pixel clock. */ + switch (cfmt->com7 & OFMT_MASK) { + case OFMT_BRAW: + fsize = win->sizeimage; + break; + case OFMT_RGB: + case OFMT_YUV: + default: + fsize = win->sizeimage * 2; + break; + } + + pclk = fps * fsize; + + /* + * Pixel clock generation circuit is pretty simple: + * + * Fin -> [ / CLKRC_div] -> [ * PLL_mult] -> pclk + * + * Try to approximate the desired pixel clock testing all available + * PLL multipliers (1x, 4x, 6x, 8x) and calculate corresponding + * divisor with: + * + * div = PLL_mult * Fin / pclk + * + * and re-calculate the pixel clock using it: + * + * pclk = Fin * PLL_mult / CLKRC_div + * + * Choose the PLL_mult and CLKRC_div pair that gives a pixel clock + * closer to the desired one. + * + * The desired pixel clock is calculated using a known frame size + * (blanking included) and FPS. + */ + best_diff = ~0L; + for (i = 0; i < ARRAY_SIZE(ov772x_pll); i++) { + unsigned int pll_mult = ov772x_pll[i].mult; + unsigned int pll_out = pll_mult * fin; + unsigned int t_pclk; + unsigned int div; + + if (pll_out < pclk) + continue; + + div = DIV_ROUND_CLOSEST(pll_out, pclk); + t_pclk = DIV_ROUND_CLOSEST(fin * pll_mult, div); + diff = abs(pclk - t_pclk); + if (diff < best_diff) { + best_diff = diff; + clkrc = CLKRC_DIV(div); + com4 = ov772x_pll[i].com4; + } + } + + ret = ov772x_write(client, COM4, com4 | COM4_RESERVED); + if (ret < 0) + return ret; + + ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED); + if (ret < 0) + return ret; + + tpf->numerator = 1; + tpf->denominator = fps; + priv->fps = tpf->denominator; + + return 0; +} + +static int ov772x_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_fract *tpf = &ival->interval; + + tpf->numerator = 1; + tpf->denominator = priv->fps; + + return 0; +} + +static int ov772x_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_fract *tpf = &ival->interval; + + return ov772x_set_frame_rate(priv, tpf, priv->cfmt, priv->win); +} + +static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov772x_priv *priv = container_of(ctrl->handler, + struct ov772x_priv, hdl); + struct v4l2_subdev *sd = &priv->subdev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + u8 val; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + val = ctrl->val ? VFLIP_IMG : 0x00; + priv->flag_vflip = ctrl->val; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val ^= VFLIP_IMG; + return ov772x_mask_set(client, COM3, VFLIP_IMG, val); + case V4L2_CID_HFLIP: + val = ctrl->val ? HFLIP_IMG : 0x00; + priv->flag_hflip = ctrl->val; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val ^= HFLIP_IMG; + return ov772x_mask_set(client, COM3, HFLIP_IMG, val); + case V4L2_CID_BAND_STOP_FILTER: + if (!ctrl->val) { + /* Switch the filter off, it is on now */ + ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); + if (!ret) + ret = ov772x_mask_set(client, COM8, + BNDF_ON_OFF, 0); + } else { + /* Switch the filter on, set AEC low limit */ + val = 256 - ctrl->val; + ret = ov772x_mask_set(client, COM8, + BNDF_ON_OFF, BNDF_ON_OFF); + if (!ret) + ret = ov772x_mask_set(client, BDBASE, + 0xff, val); + } + if (!ret) + priv->band_filter = ctrl->val; + return ret; + } + + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov772x_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 1; + if (reg->reg > 0xff) + return -EINVAL; + + ret = ov772x_read(client, reg->reg); + if (ret < 0) + return ret; + + reg->val = (__u64)ret; + + return 0; +} + +static int ov772x_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return ov772x_write(client, reg->reg, reg->val); +} +#endif + +static int ov772x_power_on(struct ov772x_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + int ret; + + if (priv->clk) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + if (priv->pwdn_gpio) { + gpiod_set_value(priv->pwdn_gpio, 1); + usleep_range(500, 1000); + } + + /* + * FIXME: The reset signal is connected to a shared GPIO on some + * platforms (namely the SuperH Migo-R). Until a framework becomes + * available to handle this cleanly, request the GPIO temporarily + * to avoid conflicts. + */ + priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb", + GPIOD_OUT_LOW); + if (IS_ERR(priv->rstb_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + return PTR_ERR(priv->rstb_gpio); + } + + if (priv->rstb_gpio) { + gpiod_set_value(priv->rstb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(priv->rstb_gpio, 0); + usleep_range(500, 1000); + + gpiod_put(priv->rstb_gpio); + } + + return 0; +} + +static int ov772x_power_off(struct ov772x_priv *priv) +{ + clk_disable_unprepare(priv->clk); + + if (priv->pwdn_gpio) { + gpiod_set_value(priv->pwdn_gpio, 0); + usleep_range(500, 1000); + } + + return 0; +} + +static int ov772x_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov772x_priv *priv = to_ov772x(sd); + + return on ? ov772x_power_on(priv) : + ov772x_power_off(priv); +} + +static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) +{ + const struct ov772x_win_size *win = &ov772x_win_sizes[0]; + u32 best_diff = UINT_MAX; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) { + u32 diff = abs(width - ov772x_win_sizes[i].rect.width) + + abs(height - ov772x_win_sizes[i].rect.height); + if (diff < best_diff) { + best_diff = diff; + win = &ov772x_win_sizes[i]; + } + } + + return win; +} + +static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf, + const struct ov772x_color_format **cfmt, + const struct ov772x_win_size **win) +{ + unsigned int i; + + /* Select a format. */ + *cfmt = &ov772x_cfmts[0]; + + for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { + if (mf->code == ov772x_cfmts[i].code) { + *cfmt = &ov772x_cfmts[i]; + break; + } + } + + /* Select a window size. */ + *win = ov772x_select_win(mf->width, mf->height); +} + +static int ov772x_set_params(struct ov772x_priv *priv, + const struct ov772x_color_format *cfmt, + const struct ov772x_win_size *win) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + struct v4l2_fract tpf; + int ret; + u8 val; + + /* Reset hardware. */ + ov772x_reset(client); + + /* Edge Ctrl. */ + if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { + /* + * Manual Edge Control Mode. + * + * Edge auto strength bit is set by default. + * Remove it when manual mode. + */ + + ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, + priv->info->edgectrl.threshold); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, + priv->info->edgectrl.strength); + if (ret < 0) + goto ov772x_set_fmt_error; + + } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) { + /* + * Auto Edge Control Mode. + * + * Set upper and lower limit. + */ + ret = ov772x_mask_set(client, + EDGE_UPPER, OV772X_EDGE_UPPER_MASK, + priv->info->edgectrl.upper); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_LOWER, OV772X_EDGE_LOWER_MASK, + priv->info->edgectrl.lower); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* Format and window size. */ + ret = ov772x_write(client, HSTART, win->rect.left >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HSIZE, win->rect.width >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VSTART, win->rect.top >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VSIZE, win->rect.height >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HREF, + ((win->rect.top & 1) << HREF_VSTART_SHIFT) | + ((win->rect.left & 3) << HREF_HSTART_SHIFT) | + ((win->rect.height & 1) << HREF_VSIZE_SHIFT) | + ((win->rect.width & 3) << HREF_HSIZE_SHIFT)); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, EXHCH, + ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) | + ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT)); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* Set DSP_CTRL3. */ + val = cfmt->dsp3; + if (val) { + ret = ov772x_mask_set(client, + DSP_CTRL3, UV_MASK, val); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* DSP_CTRL4: AEC reference point and DSP output format. */ + if (cfmt->dsp4) { + ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* Set COM3. */ + val = cfmt->com3; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val |= VFLIP_IMG; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val |= HFLIP_IMG; + if (priv->flag_vflip) + val ^= VFLIP_IMG; + if (priv->flag_hflip) + val ^= HFLIP_IMG; + + ret = ov772x_mask_set(client, + COM3, SWAP_MASK | IMG_MASK, val); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* COM7: Sensor resolution and output format control. */ + ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* COM4, CLKRC: Set pixel clock and framerate. */ + tpf.numerator = 1; + tpf.denominator = priv->fps; + ret = ov772x_set_frame_rate(priv, &tpf, cfmt, win); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* Set COM8. */ + if (priv->band_filter) { + ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); + if (!ret) + ret = ov772x_mask_set(client, BDBASE, + 0xff, 256 - priv->band_filter); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + return ret; + +ov772x_set_fmt_error: + + ov772x_reset(client); + + return ret; +} + +static int ov772x_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ov772x_priv *priv = to_ov772x(sd); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + sel->r.width = priv->win->rect.width; + sel->r.height = priv->win->rect.height; + return 0; + default: + return -EINVAL; + } +} + +static int ov772x_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct ov772x_priv *priv = to_ov772x(sd); + + if (format->pad) + return -EINVAL; + + mf->width = priv->win->rect.width; + mf->height = priv->win->rect.height; + mf->code = priv->cfmt->code; + mf->colorspace = priv->cfmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov772x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_mbus_framefmt *mf = &format->format; + const struct ov772x_color_format *cfmt; + const struct ov772x_win_size *win; + int ret; + + if (format->pad) + return -EINVAL; + + ov772x_select_params(mf, &cfmt, &win); + + mf->code = cfmt->code; + mf->width = win->rect.width; + mf->height = win->rect.height; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = cfmt->colorspace; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + + ret = ov772x_set_params(priv, cfmt, win); + if (ret < 0) + return ret; + + priv->win = win; + priv->cfmt = cfmt; + + return 0; +} + +static int ov772x_video_probe(struct ov772x_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + u8 pid, ver; + const char *devname; + int ret; + + ret = ov772x_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* Check and show product ID and manufacturer ID. */ + pid = ov772x_read(client, PID); + ver = ov772x_read(client, VER); + + switch (VERSION(pid, ver)) { + case OV7720: + devname = "ov7720"; + break; + case OV7725: + devname = "ov7725"; + break; + default: + dev_err(&client->dev, + "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, + "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, + pid, + ver, + ov772x_read(client, MIDH), + ov772x_read(client, MIDL)); + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov772x_s_power(&priv->subdev, 0); + + return ret; +} + +static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { + .s_ctrl = ov772x_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov772x_g_register, + .s_register = ov772x_s_register, +#endif + .s_power = ov772x_s_power, +}; + +static int ov772x_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + if (fie->pad || fie->index >= ARRAY_SIZE(ov772x_frame_intervals)) + return -EINVAL; + + if (fie->width != VGA_WIDTH && fie->width != QVGA_WIDTH) + return -EINVAL; + if (fie->height != VGA_HEIGHT && fie->height != QVGA_HEIGHT) + return -EINVAL; + + fie->interval.numerator = 1; + fie->interval.denominator = ov772x_frame_intervals[fie->index]; + + return 0; +} + +static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) + return -EINVAL; + + code->code = ov772x_cfmts[code->index].code; + + return 0; +} + +static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { + .s_stream = ov772x_s_stream, + .s_frame_interval = ov772x_s_frame_interval, + .g_frame_interval = ov772x_g_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { + .enum_frame_interval = ov772x_enum_frame_interval, + .enum_mbus_code = ov772x_enum_mbus_code, + .get_selection = ov772x_get_selection, + .get_fmt = ov772x_get_fmt, + .set_fmt = ov772x_set_fmt, +}; + +static const struct v4l2_subdev_ops ov772x_subdev_ops = { + .core = &ov772x_subdev_core_ops, + .video = &ov772x_subdev_video_ops, + .pad = &ov772x_subdev_pad_ops, +}; + +/* + * i2c_driver function + */ + +static int ov772x_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov772x_priv *priv; + struct i2c_adapter *adapter = client->adapter; + int ret; + + if (!client->dev.platform_data) { + dev_err(&client->dev, "Missing ov772x platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_PROTOCOL_MANGLING)) { + dev_err(&adapter->dev, + "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n"); + return -EIO; + } + client->flags |= I2C_CLIENT_SCCB; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = client->dev.platform_data; + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 3); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) + return priv->hdl.error; + + priv->clk = clk_get(&client->dev, "xclk"); + if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get xclk clock\n"); + ret = PTR_ERR(priv->clk); + goto error_ctrl_free; + } + + priv->pwdn_gpio = gpiod_get_optional(&client->dev, "pwdn", + GPIOD_OUT_LOW); + if (IS_ERR(priv->pwdn_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"pwdn\""); + ret = PTR_ERR(priv->pwdn_gpio); + goto error_clk_put; + } + + ret = ov772x_video_probe(priv); + if (ret < 0) + goto error_gpio_put; + + priv->cfmt = &ov772x_cfmts[0]; + priv->win = &ov772x_win_sizes[0]; + priv->fps = 15; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto error_gpio_put; + + return 0; + +error_gpio_put: + if (priv->pwdn_gpio) + gpiod_put(priv->pwdn_gpio); +error_clk_put: + clk_put(priv->clk); +error_ctrl_free: + v4l2_ctrl_handler_free(&priv->hdl); + + return ret; +} + +static int ov772x_remove(struct i2c_client *client) +{ + struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client)); + + clk_put(priv->clk); + if (priv->pwdn_gpio) + gpiod_put(priv->pwdn_gpio); + v4l2_async_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); + + return 0; +} + +static const struct i2c_device_id ov772x_id[] = { + { "ov772x", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov772x_id); + +static struct i2c_driver ov772x_i2c_driver = { + .driver = { + .name = "ov772x", + }, + .probe = ov772x_probe, + .remove = ov772x_remove, + .id_table = ov772x_id, +}; + +module_i2c_driver(ov772x_i2c_driver); + +MODULE_DESCRIPTION("V4L2 driver for OV772x image sensor"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index fc9dbbcae56e..01f578785e79 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -279,7 +279,7 @@ static int ov7740_get_register(struct v4l2_subdev *sd, reg->val = val; reg->size = 1; - return 0; + return ret; } static int ov7740_set_register(struct v4l2_subdev *sd, @@ -624,17 +624,11 @@ err_unlock: return ret; } -static int ov7740_get_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *parms) +static int ov7740_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + struct v4l2_fract *tpf = &ival->interval; - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; tpf->numerator = 1; tpf->denominator = 60; @@ -642,18 +636,11 @@ static int ov7740_get_parm(struct v4l2_subdev *sd, return 0; } -static int ov7740_set_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *parms) +static int ov7740_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; + struct v4l2_fract *tpf = &ival->interval; - cp->capability = V4L2_CAP_TIMEPERFRAME; tpf->numerator = 1; tpf->denominator = 60; @@ -663,8 +650,8 @@ static int ov7740_set_parm(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { .s_stream = ov7740_set_stream, - .s_parm = ov7740_set_parm, - .g_parm = ov7740_get_parm, + .s_frame_interval = ov7740_s_frame_interval, + .g_frame_interval = ov7740_g_frame_interval, }; static const struct reg_sequence ov7740_format_yuyv[] = { diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index e519f278d5f9..5bea31cd41aa 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -11,8 +11,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/media.h> @@ -249,9 +251,10 @@ struct ov965x { struct v4l2_subdev sd; struct media_pad pad; enum v4l2_mbus_type bus_type; - int gpios[NUM_GPIOS]; + struct gpio_desc *gpios[NUM_GPIOS]; /* External master clock frequency */ unsigned long mclk_frequency; + struct clk *clk; /* Protects the struct fields below */ struct mutex lock; @@ -513,24 +516,27 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x) return 0; } -static void ov965x_gpio_set(int gpio, int val) -{ - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, val); -} - -static void __ov965x_set_power(struct ov965x *ov965x, int on) +static int __ov965x_set_power(struct ov965x *ov965x, int on) { if (on) { - ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 0); - ov965x_gpio_set(ov965x->gpios[GPIO_RST], 0); + int ret = clk_prepare_enable(ov965x->clk); + + if (ret) + return ret; + + gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 0); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 0); msleep(25); } else { - ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1); - ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 1); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 1); + + clk_disable_unprepare(ov965x->clk); } ov965x->streaming = 0; + + return 0; } static int ov965x_s_power(struct v4l2_subdev *sd, int on) @@ -543,8 +549,8 @@ static int ov965x_s_power(struct v4l2_subdev *sd, int on) mutex_lock(&ov965x->lock); if (ov965x->power == !on) { - __ov965x_set_power(ov965x, on); - if (on) { + ret = __ov965x_set_power(ov965x, on); + if (!ret && on) { ret = ov965x_write_array(client, ov965x_init_regs); ov965x->apply_frame_fmt = 1; @@ -1130,8 +1136,8 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x, if (fi->interval.denominator == 0) return -EINVAL; - req_int = (u64)(fi->interval.numerator * 10000) / - fi->interval.denominator; + req_int = (u64)fi->interval.numerator * 10000; + do_div(req_int, fi->interval.denominator); for (i = 0; i < ARRAY_SIZE(ov965x_intervals); i++) { const struct ov965x_interval *iv = &ov965x_intervals[i]; @@ -1410,16 +1416,17 @@ static const struct v4l2_subdev_ops ov965x_subdev_ops = { /* * Reset and power down GPIOs configuration */ -static int ov965x_configure_gpios(struct ov965x *ov965x, - const struct ov9650_platform_data *pdata) +static int ov965x_configure_gpios_pdata(struct ov965x *ov965x, + const struct ov9650_platform_data *pdata) { int ret, i; + int gpios[NUM_GPIOS]; - ov965x->gpios[GPIO_PWDN] = pdata->gpio_pwdn; - ov965x->gpios[GPIO_RST] = pdata->gpio_reset; + gpios[GPIO_PWDN] = pdata->gpio_pwdn; + gpios[GPIO_RST] = pdata->gpio_reset; for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) { - int gpio = ov965x->gpios[i]; + int gpio = gpios[i]; if (!gpio_is_valid(gpio)) continue; @@ -1429,9 +1436,30 @@ static int ov965x_configure_gpios(struct ov965x *ov965x, return ret; v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio); - gpio_set_value(gpio, 1); + gpio_set_value_cansleep(gpio, 1); gpio_export(gpio, 0); - ov965x->gpios[i] = gpio; + ov965x->gpios[i] = gpio_to_desc(gpio); + } + + return 0; +} + +static int ov965x_configure_gpios(struct ov965x *ov965x) +{ + struct device *dev = &ov965x->client->dev; + + ov965x->gpios[GPIO_PWDN] = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov965x->gpios[GPIO_PWDN])) { + dev_info(dev, "can't get %s GPIO\n", "powerdown"); + return PTR_ERR(ov965x->gpios[GPIO_PWDN]); + } + + ov965x->gpios[GPIO_RST] = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov965x->gpios[GPIO_RST])) { + dev_info(dev, "can't get %s GPIO\n", "reset"); + return PTR_ERR(ov965x->gpios[GPIO_RST]); } return 0; @@ -1445,7 +1473,10 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) int ret; mutex_lock(&ov965x->lock); - __ov965x_set_power(ov965x, 1); + ret = __ov965x_set_power(ov965x, 1); + if (ret) + goto out; + msleep(25); /* Check sensor revision */ @@ -1465,6 +1496,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) ret = -ENODEV; } } +out: mutex_unlock(&ov965x->lock); return ret; @@ -1478,23 +1510,39 @@ static int ov965x_probe(struct i2c_client *client, struct ov965x *ov965x; int ret; - if (!pdata) { - dev_err(&client->dev, "platform data not specified\n"); - return -EINVAL; - } - - if (pdata->mclk_frequency == 0) { - dev_err(&client->dev, "MCLK frequency not specified\n"); - return -EINVAL; - } - ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL); if (!ov965x) return -ENOMEM; - mutex_init(&ov965x->lock); ov965x->client = client; - ov965x->mclk_frequency = pdata->mclk_frequency; + + if (pdata) { + if (pdata->mclk_frequency == 0) { + dev_err(&client->dev, "MCLK frequency not specified\n"); + return -EINVAL; + } + ov965x->mclk_frequency = pdata->mclk_frequency; + + ret = ov965x_configure_gpios_pdata(ov965x, pdata); + if (ret < 0) + return ret; + } else if (dev_fwnode(&client->dev)) { + ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL); + if (IS_ERR(ov965x->clk)) + return PTR_ERR(ov965x->clk); + ov965x->mclk_frequency = clk_get_rate(ov965x->clk); + + ret = ov965x_configure_gpios(ov965x); + if (ret < 0) + return ret; + } else { + dev_err(&client->dev, + "Neither platform data nor device property specified\n"); + + return -EINVAL; + } + + mutex_init(&ov965x->lock); sd = &ov965x->sd; v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops); @@ -1504,10 +1552,6 @@ static int ov965x_probe(struct i2c_client *client, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - ret = ov965x_configure_gpios(ov965x, pdata); - if (ret < 0) - goto err_mutex; - ov965x->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad); @@ -1563,9 +1607,19 @@ static const struct i2c_device_id ov965x_id[] = { }; MODULE_DEVICE_TABLE(i2c, ov965x_id); +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov965x_of_match[] = { + { .compatible = "ovti,ov9650", }, + { .compatible = "ovti,ov9652", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov965x_of_match); +#endif + static struct i2c_driver ov965x_i2c_driver = { .driver = { .name = DRIVER_NAME, + .of_match_table = of_match_ptr(ov965x_of_match), }, .probe = ov965x_probe, .remove = ov965x_remove, diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index cdc4f2392ef9..ce196b60f917 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -248,17 +248,17 @@ static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value) { unsigned long start = jiffies; unsigned long end = start + msecs_to_jiffies(2000); - int ret = 0; + int ret; u16 status; int count = 0; - while (time_is_after_jiffies(end)) { + do { ret = s5c73m3_read(state, REG_STATUS, &status); if (ret < 0 || status == value) break; usleep_range(500, 1000); ++count; - } + } while (time_is_after_jiffies(end)); if (count > 0) v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 72b369895b37..7c2aabc8a3f6 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -1,11 +1,5 @@ comment "soc_camera sensor drivers" -config SOC_CAMERA_IMX074 - tristate "imx074 support" - depends on SOC_CAMERA && I2C - help - This driver supports IMX074 cameras from Sony - config SOC_CAMERA_MT9M001 tristate "mt9m001 support" depends on SOC_CAMERA && I2C @@ -23,12 +17,6 @@ config SOC_CAMERA_MT9M111 This is the legacy configuration which shouldn't be used anymore, while VIDEO_MT9M111 should be used instead. -config SOC_CAMERA_MT9T031 - tristate "mt9t031 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T031 cameras from Micron. - config SOC_CAMERA_MT9T112 tristate "mt9t112 support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index faa2df8901d2..8c7770f62997 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 297d22ebcb18..b53c36dfa469 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -85,7 +85,7 @@ struct mt9t112_format { struct mt9t112_priv { struct v4l2_subdev subdev; - struct mt9t112_camera_info *info; + struct mt9t112_platform_data *info; struct i2c_client *client; struct v4l2_rect frame; struct v4l2_clk *clk; diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index 0bf031b7e4fa..2a4882cddc51 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -511,13 +511,16 @@ static int sr030pc30_get_fmt(struct v4l2_subdev *sd, static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - int i = ARRAY_SIZE(sr030pc30_formats); + int i; sr030pc30_try_frame_size(mf); - while (i--) + for (i = 0; i < ARRAY_SIZE(sr030pc30_formats); i++) { if (mf->code == sr030pc30_formats[i].code) break; + } + if (i == ARRAY_SIZE(sr030pc30_formats)) + i = 0; mf->code = sr030pc30_formats[i].code; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 2b8181469b93..393bbbbbaad7 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tc358743 - Toshiba HDMI to CSI-2 bridge * * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights * reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h index 227b46471793..2495878dc358 100644 --- a/drivers/media/i2c/tc358743_regs.h +++ b/drivers/media/i2c/tc358743_regs.h @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks * * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights * reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c new file mode 100644 index 000000000000..3021913c28fa --- /dev/null +++ b/drivers/media/i2c/tda1997x.c @@ -0,0 +1,2820 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Gateworks Corporation + */ +#include <linux/delay.h> +#include <linux/hdmi.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/v4l2-dv-timings.h> +#include <linux/videodev2.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> +#include <media/i2c/tda1997x.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <dt-bindings/media/tda1997x.h> + +#include "tda1997x_regs.h" + +#define TDA1997X_MBUS_CODES 5 + +/* debug level */ +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +/* Audio formats */ +static const char * const audtype_names[] = { + "PCM", /* PCM Samples */ + "HBR", /* High Bit Rate Audio */ + "OBA", /* One-Bit Audio */ + "DST" /* Direct Stream Transfer */ +}; + +/* Audio output port formats */ +enum audfmt_types { + AUDFMT_TYPE_DISABLED = 0, + AUDFMT_TYPE_I2S, + AUDFMT_TYPE_SPDIF, +}; +static const char * const audfmt_names[] = { + "Disabled", + "I2S", + "SPDIF", +}; + +/* Video input formats */ +static const char * const hdmi_colorspace_names[] = { + "RGB", "YUV422", "YUV444", "YUV420", "", "", "", "", +}; +static const char * const hdmi_colorimetry_names[] = { + "", "ITU601", "ITU709", "Extended", +}; +static const char * const v4l2_quantization_names[] = { + "Default", + "Full Range (0-255)", + "Limited Range (16-235)", +}; + +/* Video output port formats */ +static const char * const vidfmt_names[] = { + "RGB444/YUV444", /* RGB/YUV444 16bit data bus, 8bpp */ + "YUV422 semi-planar", /* YUV422 16bit data base, 8bpp */ + "YUV422 CCIR656", /* BT656 (YUV 8bpp 2 clock per pixel) */ + "Invalid", +}; + +/* + * Colorspace conversion matrices + */ +struct color_matrix_coefs { + const char *name; + /* Input offsets */ + s16 offint1; + s16 offint2; + s16 offint3; + /* Coeficients */ + s16 p11coef; + s16 p12coef; + s16 p13coef; + s16 p21coef; + s16 p22coef; + s16 p23coef; + s16 p31coef; + s16 p32coef; + s16 p33coef; + /* Output offsets */ + s16 offout1; + s16 offout2; + s16 offout3; +}; + +enum { + ITU709_RGBFULL, + ITU601_RGBFULL, + RGBLIMITED_RGBFULL, + RGBLIMITED_ITU601, + RGBLIMITED_ITU709, + RGBFULL_ITU601, + RGBFULL_ITU709, +}; + +/* NB: 4096 is 1.0 using fixed point numbers */ +static const struct color_matrix_coefs conv_matrix[] = { + { + "YUV709 -> RGB full", + -256, -2048, -2048, + 4769, -2183, -873, + 4769, 7343, 0, + 4769, 0, 8652, + 0, 0, 0, + }, + { + "YUV601 -> RGB full", + -256, -2048, -2048, + 4769, -3330, -1602, + 4769, 6538, 0, + 4769, 0, 8264, + 256, 256, 256, + }, + { + "RGB limited -> RGB full", + -256, -256, -256, + 0, 4769, 0, + 0, 0, 4769, + 4769, 0, 0, + 0, 0, 0, + }, + { + "RGB limited -> ITU601", + -256, -256, -256, + 2404, 1225, 467, + -1754, 2095, -341, + -1388, -707, 2095, + 256, 2048, 2048, + }, + { + "RGB limited -> ITU709", + -256, -256, -256, + 2918, 867, 295, + -1894, 2087, -190, + -1607, -477, 2087, + 256, 2048, 2048, + }, + { + "RGB full -> ITU601", + 0, 0, 0, + 2065, 1052, 401, + -1506, 1799, -293, + -1192, -607, 1799, + 256, 2048, 2048, + }, + { + "RGB full -> ITU709", + 0, 0, 0, + 2506, 745, 253, + -1627, 1792, -163, + -1380, -410, 1792, + 256, 2048, 2048, + }, +}; + +static const struct v4l2_dv_timings_cap tda1997x_dv_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + + V4L2_INIT_BT_TIMINGS( + 640, 1920, /* min/max width */ + 350, 1200, /* min/max height */ + 13000000, 165000000, /* min/max pixelclock */ + /* standards */ + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, + /* capabilities */ + V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM + ) +}; + +/* regulator supplies */ +static const char * const tda1997x_supply_name[] = { + "DOVDD", /* Digital I/O supply */ + "DVDD", /* Digital Core supply */ + "AVDD", /* Analog supply */ +}; + +#define TDA1997X_NUM_SUPPLIES ARRAY_SIZE(tda1997x_supply_name) + +enum tda1997x_type { + TDA19971, + TDA19973, +}; + +enum tda1997x_hdmi_pads { + TDA1997X_PAD_SOURCE, + TDA1997X_NUM_PADS, +}; + +struct tda1997x_chip_info { + enum tda1997x_type type; + const char *name; +}; + +struct tda1997x_state { + const struct tda1997x_chip_info *info; + struct tda1997x_platform_data pdata; + struct i2c_client *client; + struct i2c_client *client_cec; + struct v4l2_subdev sd; + struct regulator_bulk_data supplies[TDA1997X_NUM_SUPPLIES]; + struct media_pad pads[TDA1997X_NUM_PADS]; + struct mutex lock; + struct mutex page_lock; + char page; + + /* detected info from chip */ + int chip_revision; + char port_30bit; + char output_2p5; + char tmdsb_clk; + char tmdsb_soc; + + /* status info */ + char hdmi_status; + char mptrw_in_progress; + char activity_status; + char input_detect[2]; + + /* video */ + struct hdmi_avi_infoframe avi_infoframe; + struct v4l2_hdmi_colorimetry colorimetry; + u32 rgb_quantization_range; + struct v4l2_dv_timings timings; + int fps; + const struct color_matrix_coefs *conv; + u32 mbus_codes[TDA1997X_MBUS_CODES]; /* available modes */ + u32 mbus_code; /* current mode */ + u8 vid_fmt; + + /* controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *detect_tx_5v_ctrl; + struct v4l2_ctrl *rgb_quantization_range_ctrl; + + /* audio */ + u8 audio_ch_alloc; + int audio_samplerate; + int audio_channels; + int audio_samplesize; + int audio_type; + struct mutex audio_lock; + struct snd_pcm_substream *audio_stream; + + /* EDID */ + struct { + u8 edid[256]; + u32 present; + unsigned int blocks; + } edid; + struct delayed_work delayed_work_enable_hpd; +}; + +static const struct v4l2_event tda1997x_ev_fmt = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, +}; + +static const struct tda1997x_chip_info tda1997x_chip_info[] = { + [TDA19971] = { + .type = TDA19971, + .name = "tda19971", + }, + [TDA19973] = { + .type = TDA19973, + .name = "tda19973", + }, +}; + +static inline struct tda1997x_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tda1997x_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tda1997x_state, hdl)->sd; +} + +static int tda1997x_cec_read(struct v4l2_subdev *sd, u8 reg) +{ + struct tda1997x_state *state = to_state(sd); + int val; + + val = i2c_smbus_read_byte_data(state->client_cec, reg); + if (val < 0) { + v4l_err(state->client, "read reg error: reg=%2x\n", reg); + val = -1; + } + + return val; +} + +static int tda1997x_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct tda1997x_state *state = to_state(sd); + int ret = 0; + + ret = i2c_smbus_write_byte_data(state->client_cec, reg, val); + if (ret < 0) { + v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n", + reg, val); + ret = -1; + } + + return ret; +} + +/* ----------------------------------------------------------------------------- + * I2C transfer + */ + +static int tda1997x_setpage(struct v4l2_subdev *sd, u8 page) +{ + struct tda1997x_state *state = to_state(sd); + int ret; + + if (state->page != page) { + ret = i2c_smbus_write_byte_data(state->client, + REG_CURPAGE_00H, page); + if (ret < 0) { + v4l_err(state->client, + "write reg error:reg=%2x,val=%2x\n", + REG_CURPAGE_00H, page); + return ret; + } + state->page = page; + } + return 0; +} + +static inline int io_read(struct v4l2_subdev *sd, u16 reg) +{ + struct tda1997x_state *state = to_state(sd); + int val; + + mutex_lock(&state->page_lock); + if (tda1997x_setpage(sd, reg >> 8)) { + val = -1; + goto out; + } + + val = i2c_smbus_read_byte_data(state->client, reg&0xff); + if (val < 0) { + v4l_err(state->client, "read reg error: reg=%2x\n", reg & 0xff); + val = -1; + goto out; + } + +out: + mutex_unlock(&state->page_lock); + return val; +} + +static inline long io_read16(struct v4l2_subdev *sd, u16 reg) +{ + int val; + long lval = 0; + + val = io_read(sd, reg); + if (val < 0) + return val; + lval |= (val << 8); + val = io_read(sd, reg + 1); + if (val < 0) + return val; + lval |= val; + + return lval; +} + +static inline long io_read24(struct v4l2_subdev *sd, u16 reg) +{ + int val; + long lval = 0; + + val = io_read(sd, reg); + if (val < 0) + return val; + lval |= (val << 16); + val = io_read(sd, reg + 1); + if (val < 0) + return val; + lval |= (val << 8); + val = io_read(sd, reg + 2); + if (val < 0) + return val; + lval |= val; + + return lval; +} + +static unsigned int io_readn(struct v4l2_subdev *sd, u16 reg, u8 len, u8 *data) +{ + int i; + int sz = 0; + int val; + + for (i = 0; i < len; i++) { + val = io_read(sd, reg + i); + if (val < 0) + break; + data[i] = val; + sz++; + } + + return sz; +} + +static int io_write(struct v4l2_subdev *sd, u16 reg, u8 val) +{ + struct tda1997x_state *state = to_state(sd); + s32 ret = 0; + + mutex_lock(&state->page_lock); + if (tda1997x_setpage(sd, reg >> 8)) { + ret = -1; + goto out; + } + + ret = i2c_smbus_write_byte_data(state->client, reg & 0xff, val); + if (ret < 0) { + v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n", + reg&0xff, val); + ret = -1; + goto out; + } + +out: + mutex_unlock(&state->page_lock); + return ret; +} + +static int io_write16(struct v4l2_subdev *sd, u16 reg, u16 val) +{ + int ret; + + ret = io_write(sd, reg, (val >> 8) & 0xff); + if (ret < 0) + return ret; + ret = io_write(sd, reg + 1, val & 0xff); + if (ret < 0) + return ret; + return 0; +} + +static int io_write24(struct v4l2_subdev *sd, u16 reg, u32 val) +{ + int ret; + + ret = io_write(sd, reg, (val >> 16) & 0xff); + if (ret < 0) + return ret; + ret = io_write(sd, reg + 1, (val >> 8) & 0xff); + if (ret < 0) + return ret; + ret = io_write(sd, reg + 2, val & 0xff); + if (ret < 0) + return ret; + return 0; +} + +/* ----------------------------------------------------------------------------- + * Hotplug + */ + +enum hpd_mode { + HPD_LOW_BP, /* HPD low and pulse of at least 100ms */ + HPD_LOW_OTHER, /* HPD low and pulse of at least 100ms */ + HPD_HIGH_BP, /* HIGH */ + HPD_HIGH_OTHER, + HPD_PULSE, /* HPD low pulse */ +}; + +/* manual HPD (Hot Plug Detect) control */ +static int tda1997x_manual_hpd(struct v4l2_subdev *sd, enum hpd_mode mode) +{ + u8 hpd_auto, hpd_pwr, hpd_man; + + hpd_auto = io_read(sd, REG_HPD_AUTO_CTRL); + hpd_pwr = io_read(sd, REG_HPD_POWER); + hpd_man = io_read(sd, REG_HPD_MAN_CTRL); + + /* mask out unused bits */ + hpd_man &= (HPD_MAN_CTRL_HPD_PULSE | + HPD_MAN_CTRL_5VEN | + HPD_MAN_CTRL_HPD_B | + HPD_MAN_CTRL_HPD_A); + + switch (mode) { + /* HPD low and pulse of at least 100ms */ + case HPD_LOW_BP: + /* hpd_bp=0 */ + hpd_pwr &= ~HPD_POWER_BP_MASK; + /* disable HPD_A and HPD_B */ + hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B); + io_write(sd, REG_HPD_POWER, hpd_pwr); + io_write(sd, REG_HPD_MAN_CTRL, hpd_man); + break; + /* HPD high */ + case HPD_HIGH_BP: + /* hpd_bp=1 */ + hpd_pwr &= ~HPD_POWER_BP_MASK; + hpd_pwr |= 1 << HPD_POWER_BP_SHIFT; + io_write(sd, REG_HPD_POWER, hpd_pwr); + break; + /* HPD low and pulse of at least 100ms */ + case HPD_LOW_OTHER: + /* disable HPD_A and HPD_B */ + hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B); + /* hp_other=0 */ + hpd_auto &= ~HPD_AUTO_HP_OTHER; + io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto); + io_write(sd, REG_HPD_MAN_CTRL, hpd_man); + break; + /* HPD high */ + case HPD_HIGH_OTHER: + hpd_auto |= HPD_AUTO_HP_OTHER; + io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto); + break; + /* HPD low pulse */ + case HPD_PULSE: + /* disable HPD_A and HPD_B */ + hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B); + io_write(sd, REG_HPD_MAN_CTRL, hpd_man); + break; + } + + return 0; +} + +static void tda1997x_delayed_work_enable_hpd(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tda1997x_state *state = container_of(dwork, + struct tda1997x_state, + delayed_work_enable_hpd); + struct v4l2_subdev *sd = &state->sd; + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + /* Set HPD high */ + tda1997x_manual_hpd(sd, HPD_HIGH_OTHER); + tda1997x_manual_hpd(sd, HPD_HIGH_BP); + + state->edid.present = 1; +} + +static void tda1997x_disable_edid(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + + v4l2_dbg(1, debug, sd, "%s\n", __func__); + cancel_delayed_work_sync(&state->delayed_work_enable_hpd); + + /* Set HPD low */ + tda1997x_manual_hpd(sd, HPD_LOW_BP); +} + +static void tda1997x_enable_edid(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + + v4l2_dbg(1, debug, sd, "%s\n", __func__); + + /* Enable hotplug after 100ms */ + schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10); +} + +/* ----------------------------------------------------------------------------- + * Signal Control + */ + +/* + * configure vid_fmt based on mbus_code + */ +static int +tda1997x_setup_format(struct tda1997x_state *state, u32 code) +{ + v4l_dbg(1, debug, state->client, "%s code=0x%x\n", __func__, code); + switch (code) { + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_YUV8_1X24: + state->vid_fmt = OF_FMT_444; + break; + case MEDIA_BUS_FMT_UYVY12_1X24: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_UYVY8_1X16: + state->vid_fmt = OF_FMT_422_SMPT; + break; + case MEDIA_BUS_FMT_UYVY12_2X12: + case MEDIA_BUS_FMT_UYVY10_2X10: + case MEDIA_BUS_FMT_UYVY8_2X8: + state->vid_fmt = OF_FMT_422_CCIR; + break; + default: + v4l_err(state->client, "incompatible format (0x%x)\n", code); + return -EINVAL; + } + v4l_dbg(1, debug, state->client, "%s code=0x%x fmt=%s\n", __func__, + code, vidfmt_names[state->vid_fmt]); + state->mbus_code = code; + + return 0; +} + +/* + * The color conversion matrix will convert between the colorimetry of the + * HDMI input to the desired output format RGB|YUV. RGB output is to be + * full-range and YUV is to be limited range. + * + * RGB full-range uses values from 0 to 255 which is recommended on a monitor + * and RGB Limited uses values from 16 to 236 (16=black, 235=white) which is + * typically recommended on a TV. + */ +static void +tda1997x_configure_csc(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + struct hdmi_avi_infoframe *avi = &state->avi_infoframe; + struct v4l2_hdmi_colorimetry *c = &state->colorimetry; + /* Blanking code values depend on output colorspace (RGB or YUV) */ + struct blanking_codes { + s16 code_gy; + s16 code_bu; + s16 code_rv; + }; + static const struct blanking_codes rgb_blanking = { 64, 64, 64 }; + static const struct blanking_codes yuv_blanking = { 64, 512, 512 }; + const struct blanking_codes *blanking_codes = NULL; + u8 reg; + + v4l_dbg(1, debug, state->client, "input:%s quant:%s output:%s\n", + hdmi_colorspace_names[avi->colorspace], + v4l2_quantization_names[c->quantization], + vidfmt_names[state->vid_fmt]); + state->conv = NULL; + switch (state->vid_fmt) { + /* RGB output */ + case OF_FMT_444: + blanking_codes = &rgb_blanking; + if (c->colorspace == V4L2_COLORSPACE_SRGB) { + if (c->quantization == V4L2_QUANTIZATION_LIM_RANGE) + state->conv = &conv_matrix[RGBLIMITED_RGBFULL]; + } else { + if (c->colorspace == V4L2_COLORSPACE_REC709) + state->conv = &conv_matrix[ITU709_RGBFULL]; + else if (c->colorspace == V4L2_COLORSPACE_SMPTE170M) + state->conv = &conv_matrix[ITU601_RGBFULL]; + } + break; + + /* YUV output */ + case OF_FMT_422_SMPT: /* semi-planar */ + case OF_FMT_422_CCIR: /* CCIR656 */ + blanking_codes = &yuv_blanking; + if ((c->colorspace == V4L2_COLORSPACE_SRGB) && + (c->quantization == V4L2_QUANTIZATION_FULL_RANGE)) { + if (state->timings.bt.height <= 576) + state->conv = &conv_matrix[RGBFULL_ITU601]; + else + state->conv = &conv_matrix[RGBFULL_ITU709]; + } else if ((c->colorspace == V4L2_COLORSPACE_SRGB) && + (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)) { + if (state->timings.bt.height <= 576) + state->conv = &conv_matrix[RGBLIMITED_ITU601]; + else + state->conv = &conv_matrix[RGBLIMITED_ITU709]; + } + break; + } + + if (state->conv) { + v4l_dbg(1, debug, state->client, "%s\n", + state->conv->name); + /* enable matrix conversion */ + reg = io_read(sd, REG_VDP_CTRL); + reg &= ~VDP_CTRL_MATRIX_BP; + io_write(sd, REG_VDP_CTRL, reg); + /* offset inputs */ + io_write16(sd, REG_VDP_MATRIX + 0, state->conv->offint1); + io_write16(sd, REG_VDP_MATRIX + 2, state->conv->offint2); + io_write16(sd, REG_VDP_MATRIX + 4, state->conv->offint3); + /* coefficients */ + io_write16(sd, REG_VDP_MATRIX + 6, state->conv->p11coef); + io_write16(sd, REG_VDP_MATRIX + 8, state->conv->p12coef); + io_write16(sd, REG_VDP_MATRIX + 10, state->conv->p13coef); + io_write16(sd, REG_VDP_MATRIX + 12, state->conv->p21coef); + io_write16(sd, REG_VDP_MATRIX + 14, state->conv->p22coef); + io_write16(sd, REG_VDP_MATRIX + 16, state->conv->p23coef); + io_write16(sd, REG_VDP_MATRIX + 18, state->conv->p31coef); + io_write16(sd, REG_VDP_MATRIX + 20, state->conv->p32coef); + io_write16(sd, REG_VDP_MATRIX + 22, state->conv->p33coef); + /* offset outputs */ + io_write16(sd, REG_VDP_MATRIX + 24, state->conv->offout1); + io_write16(sd, REG_VDP_MATRIX + 26, state->conv->offout2); + io_write16(sd, REG_VDP_MATRIX + 28, state->conv->offout3); + } else { + /* disable matrix conversion */ + reg = io_read(sd, REG_VDP_CTRL); + reg |= VDP_CTRL_MATRIX_BP; + io_write(sd, REG_VDP_CTRL, reg); + } + + /* SetBlankingCodes */ + if (blanking_codes) { + io_write16(sd, REG_BLK_GY, blanking_codes->code_gy); + io_write16(sd, REG_BLK_BU, blanking_codes->code_bu); + io_write16(sd, REG_BLK_RV, blanking_codes->code_rv); + } +} + +/* Configure frame detection window and VHREF timing generator */ +static void +tda1997x_configure_vhref(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + const struct v4l2_bt_timings *bt = &state->timings.bt; + int width, lines; + u16 href_start, href_end; + u16 vref_f1_start, vref_f2_start; + u8 vref_f1_width, vref_f2_width; + u8 field_polarity; + u16 fieldref_f1_start, fieldref_f2_start; + u8 reg; + + href_start = bt->hbackporch + bt->hsync + 1; + href_end = href_start + bt->width; + vref_f1_start = bt->height + bt->vbackporch + bt->vsync + + bt->il_vbackporch + bt->il_vsync + + bt->il_vfrontporch; + vref_f1_width = bt->vbackporch + bt->vsync + bt->vfrontporch; + vref_f2_start = 0; + vref_f2_width = 0; + fieldref_f1_start = 0; + fieldref_f2_start = 0; + if (bt->interlaced) { + vref_f2_start = (bt->height / 2) + + (bt->il_vbackporch + bt->il_vsync - 1); + vref_f2_width = bt->il_vbackporch + bt->il_vsync + + bt->il_vfrontporch; + fieldref_f2_start = vref_f2_start + bt->il_vfrontporch + + fieldref_f1_start; + } + field_polarity = 0; + + width = V4L2_DV_BT_FRAME_WIDTH(bt); + lines = V4L2_DV_BT_FRAME_HEIGHT(bt); + + /* + * Configure Frame Detection Window: + * horiz area where the VHREF module consider a VSYNC a new frame + */ + io_write16(sd, REG_FDW_S, 0x2ef); /* start position */ + io_write16(sd, REG_FDW_E, 0x141); /* end position */ + + /* Set Pixel And Line Counters */ + if (state->chip_revision == 0) + io_write16(sd, REG_PXCNT_PR, 4); + else + io_write16(sd, REG_PXCNT_PR, 1); + io_write16(sd, REG_PXCNT_NPIX, width & MASK_VHREF); + io_write16(sd, REG_LCNT_PR, 1); + io_write16(sd, REG_LCNT_NLIN, lines & MASK_VHREF); + + /* + * Configure the VHRef timing generator responsible for rebuilding all + * horiz and vert synch and ref signals from its input allowing auto + * detection algorithms and forcing predefined modes (480i & 576i) + */ + reg = VHREF_STD_DET_OFF << VHREF_STD_DET_SHIFT; + io_write(sd, REG_VHREF_CTRL, reg); + + /* + * Configure the VHRef timing values. In case the VHREF generator has + * been configured in manual mode, this will allow to manually set all + * horiz and vert ref values (non-active pixel areas) of the generator + * and allows setting the frame reference params. + */ + /* horizontal reference start/end */ + io_write16(sd, REG_HREF_S, href_start & MASK_VHREF); + io_write16(sd, REG_HREF_E, href_end & MASK_VHREF); + /* vertical reference f1 start/end */ + io_write16(sd, REG_VREF_F1_S, vref_f1_start & MASK_VHREF); + io_write(sd, REG_VREF_F1_WIDTH, vref_f1_width); + /* vertical reference f2 start/end */ + io_write16(sd, REG_VREF_F2_S, vref_f2_start & MASK_VHREF); + io_write(sd, REG_VREF_F2_WIDTH, vref_f2_width); + + /* F1/F2 FREF, field polarity */ + reg = fieldref_f1_start & MASK_VHREF; + reg |= field_polarity << 8; + io_write16(sd, REG_FREF_F1_S, reg); + reg = fieldref_f2_start & MASK_VHREF; + io_write16(sd, REG_FREF_F2_S, reg); +} + +/* Configure Video Output port signals */ +static int +tda1997x_configure_vidout(struct tda1997x_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + struct tda1997x_platform_data *pdata = &state->pdata; + u8 prefilter; + u8 reg; + + /* Configure pixel clock generator: delay, polarity, rate */ + reg = (state->vid_fmt == OF_FMT_422_CCIR) ? + PCLK_SEL_X2 : PCLK_SEL_X1; + reg |= pdata->vidout_delay_pclk << PCLK_DELAY_SHIFT; + reg |= pdata->vidout_inv_pclk << PCLK_INV_SHIFT; + io_write(sd, REG_PCLK, reg); + + /* Configure pre-filter */ + prefilter = 0; /* filters off */ + /* YUV422 mode requires conversion */ + if ((state->vid_fmt == OF_FMT_422_SMPT) || + (state->vid_fmt == OF_FMT_422_CCIR)) { + /* 2/7 taps for Rv and Bu */ + prefilter = FILTERS_CTRL_2_7TAP << FILTERS_CTRL_BU_SHIFT | + FILTERS_CTRL_2_7TAP << FILTERS_CTRL_RV_SHIFT; + } + io_write(sd, REG_FILTERS_CTRL, prefilter); + + /* Configure video port */ + reg = state->vid_fmt & OF_FMT_MASK; + if (state->vid_fmt == OF_FMT_422_CCIR) + reg |= (OF_BLK | OF_TRC); + reg |= OF_VP_ENABLE; + io_write(sd, REG_OF, reg); + + /* Configure formatter and conversions */ + reg = io_read(sd, REG_VDP_CTRL); + /* pre-filter is needed unless (REG_FILTERS_CTRL == 0) */ + if (!prefilter) + reg |= VDP_CTRL_PREFILTER_BP; + else + reg &= ~VDP_CTRL_PREFILTER_BP; + /* formatter is needed for YUV422 and for trc/blc codes */ + if (state->vid_fmt == OF_FMT_444) + reg |= VDP_CTRL_FORMATTER_BP; + /* formatter and compdel needed for timing/blanking codes */ + else + reg &= ~(VDP_CTRL_FORMATTER_BP | VDP_CTRL_COMPDEL_BP); + /* activate compdel for small sync delays */ + if ((pdata->vidout_delay_vs < 4) || (pdata->vidout_delay_hs < 4)) + reg &= ~VDP_CTRL_COMPDEL_BP; + io_write(sd, REG_VDP_CTRL, reg); + + /* Configure DE output signal: delay, polarity, and source */ + reg = pdata->vidout_delay_de << DE_FREF_DELAY_SHIFT | + pdata->vidout_inv_de << DE_FREF_INV_SHIFT | + pdata->vidout_sel_de << DE_FREF_SEL_SHIFT; + io_write(sd, REG_DE_FREF, reg); + + /* Configure HS/HREF output signal: delay, polarity, and source */ + if (state->vid_fmt != OF_FMT_422_CCIR) { + reg = pdata->vidout_delay_hs << HS_HREF_DELAY_SHIFT | + pdata->vidout_inv_hs << HS_HREF_INV_SHIFT | + pdata->vidout_sel_hs << HS_HREF_SEL_SHIFT; + } else + reg = HS_HREF_SEL_NONE << HS_HREF_SEL_SHIFT; + io_write(sd, REG_HS_HREF, reg); + + /* Configure VS/VREF output signal: delay, polarity, and source */ + if (state->vid_fmt != OF_FMT_422_CCIR) { + reg = pdata->vidout_delay_vs << VS_VREF_DELAY_SHIFT | + pdata->vidout_inv_vs << VS_VREF_INV_SHIFT | + pdata->vidout_sel_vs << VS_VREF_SEL_SHIFT; + } else + reg = VS_VREF_SEL_NONE << VS_VREF_SEL_SHIFT; + io_write(sd, REG_VS_VREF, reg); + + return 0; +} + +/* Configure Audio output port signals */ +static int +tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment) +{ + struct tda1997x_state *state = to_state(sd); + struct tda1997x_platform_data *pdata = &state->pdata; + bool sp_used_by_fifo = 1; + u8 reg; + + if (!pdata->audout_format) + return 0; + + /* channel assignment (CEA-861-D Table 20) */ + io_write(sd, REG_AUDIO_PATH, channel_assignment); + + /* Audio output configuration */ + reg = 0; + switch (pdata->audout_format) { + case AUDFMT_TYPE_I2S: + reg |= AUDCFG_BUS_I2S << AUDCFG_BUS_SHIFT; + break; + case AUDFMT_TYPE_SPDIF: + reg |= AUDCFG_BUS_SPDIF << AUDCFG_BUS_SHIFT; + break; + } + switch (state->audio_type) { + case AUDCFG_TYPE_PCM: + reg |= AUDCFG_TYPE_PCM << AUDCFG_TYPE_SHIFT; + break; + case AUDCFG_TYPE_OBA: + reg |= AUDCFG_TYPE_OBA << AUDCFG_TYPE_SHIFT; + break; + case AUDCFG_TYPE_DST: + reg |= AUDCFG_TYPE_DST << AUDCFG_TYPE_SHIFT; + sp_used_by_fifo = 0; + break; + case AUDCFG_TYPE_HBR: + reg |= AUDCFG_TYPE_HBR << AUDCFG_TYPE_SHIFT; + if (pdata->audout_layout == 1) { + /* demuxed via AP0:AP3 */ + reg |= AUDCFG_HBR_DEMUX << AUDCFG_HBR_SHIFT; + if (pdata->audout_format == AUDFMT_TYPE_SPDIF) + sp_used_by_fifo = 0; + } else { + /* straight via AP0 */ + reg |= AUDCFG_HBR_STRAIGHT << AUDCFG_HBR_SHIFT; + } + break; + } + if (pdata->audout_width == 32) + reg |= AUDCFG_I2SW_32 << AUDCFG_I2SW_SHIFT; + else + reg |= AUDCFG_I2SW_16 << AUDCFG_I2SW_SHIFT; + + /* automatic hardware mute */ + if (pdata->audio_auto_mute) + reg |= AUDCFG_AUTO_MUTE_EN; + /* clock polarity */ + if (pdata->audout_invert_clk) + reg |= AUDCFG_CLK_INVERT; + io_write(sd, REG_AUDCFG, reg); + + /* audio layout */ + reg = (pdata->audout_layout) ? AUDIO_LAYOUT_LAYOUT1 : 0; + if (!pdata->audout_layoutauto) + reg |= AUDIO_LAYOUT_MANUAL; + if (sp_used_by_fifo) + reg |= AUDIO_LAYOUT_SP_FLAG; + io_write(sd, REG_AUDIO_LAYOUT, reg); + + /* FIFO Latency value */ + io_write(sd, REG_FIFO_LATENCY_VAL, 0x80); + + /* Audio output port config */ + if (sp_used_by_fifo) { + reg = AUDIO_OUT_ENABLE_AP0; + if (channel_assignment >= 0x01) + reg |= AUDIO_OUT_ENABLE_AP1; + if (channel_assignment >= 0x04) + reg |= AUDIO_OUT_ENABLE_AP2; + if (channel_assignment >= 0x0c) + reg |= AUDIO_OUT_ENABLE_AP3; + /* specific cases where AP1 is not used */ + if ((channel_assignment == 0x04) + || (channel_assignment == 0x08) + || (channel_assignment == 0x0c) + || (channel_assignment == 0x10) + || (channel_assignment == 0x14) + || (channel_assignment == 0x18) + || (channel_assignment == 0x1c)) + reg &= ~AUDIO_OUT_ENABLE_AP1; + /* specific cases where AP2 is not used */ + if ((channel_assignment >= 0x14) + && (channel_assignment <= 0x17)) + reg &= ~AUDIO_OUT_ENABLE_AP2; + } else { + reg = AUDIO_OUT_ENABLE_AP3 | + AUDIO_OUT_ENABLE_AP2 | + AUDIO_OUT_ENABLE_AP1 | + AUDIO_OUT_ENABLE_AP0; + } + if (pdata->audout_format == AUDFMT_TYPE_I2S) + reg |= (AUDIO_OUT_ENABLE_ACLK | AUDIO_OUT_ENABLE_WS); + io_write(sd, REG_AUDIO_OUT_ENABLE, reg); + + /* reset test mode to normal audio freq auto selection */ + io_write(sd, REG_TEST_MODE, 0x00); + + return 0; +} + +/* Soft Reset of specific hdmi info */ +static int +tda1997x_hdmi_info_reset(struct v4l2_subdev *sd, u8 info_rst, bool reset_sus) +{ + u8 reg; + + /* reset infoframe engine packets */ + reg = io_read(sd, REG_HDMI_INFO_RST); + io_write(sd, REG_HDMI_INFO_RST, info_rst); + + /* if infoframe engine has been reset clear INT_FLG_MODE */ + if (reg & RESET_IF) { + reg = io_read(sd, REG_INT_FLG_CLR_MODE); + io_write(sd, REG_INT_FLG_CLR_MODE, reg); + } + + /* Disable REFTIM to restart start-up-sequencer (SUS) */ + reg = io_read(sd, REG_RATE_CTRL); + reg &= ~RATE_REFTIM_ENABLE; + if (!reset_sus) + reg |= RATE_REFTIM_ENABLE; + reg = io_write(sd, REG_RATE_CTRL, reg); + + return 0; +} + +static void +tda1997x_power_mode(struct tda1997x_state *state, bool enable) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg; + + if (enable) { + /* Automatic control of TMDS */ + io_write(sd, REG_PON_OVR_EN, PON_DIS); + /* Enable current bias unit */ + io_write(sd, REG_CFG1, PON_EN); + /* Enable deep color PLL */ + io_write(sd, REG_DEEP_PLL7_BYP, PON_DIS); + /* Output buffers active */ + reg = io_read(sd, REG_OF); + reg &= ~OF_VP_ENABLE; + io_write(sd, REG_OF, reg); + } else { + /* Power down EDID mode sequence */ + /* Output buffers in HiZ */ + reg = io_read(sd, REG_OF); + reg |= OF_VP_ENABLE; + io_write(sd, REG_OF, reg); + /* Disable deep color PLL */ + io_write(sd, REG_DEEP_PLL7_BYP, PON_EN); + /* Disable current bias unit */ + io_write(sd, REG_CFG1, PON_DIS); + /* Manual control of TMDS */ + io_write(sd, REG_PON_OVR_EN, PON_EN); + } +} + +static bool +tda1997x_detect_tx_5v(struct v4l2_subdev *sd) +{ + u8 reg = io_read(sd, REG_DETECT_5V); + + return ((reg & DETECT_5V_SEL) ? 1 : 0); +} + +static bool +tda1997x_detect_tx_hpd(struct v4l2_subdev *sd) +{ + u8 reg = io_read(sd, REG_DETECT_5V); + + return ((reg & DETECT_HPD) ? 1 : 0); +} + +static int +tda1997x_detect_std(struct tda1997x_state *state, + struct v4l2_dv_timings *timings) +{ + struct v4l2_subdev *sd = &state->sd; + u32 vper; + u16 hper; + u16 hsper; + int i; + + /* + * Read the FMT registers + * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) cycles + * REG_H_PER: Period of a line in MCLK(27MHz) cycles + * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles + */ + vper = io_read24(sd, REG_V_PER) & MASK_VPER; + hper = io_read16(sd, REG_H_PER) & MASK_HPER; + hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; + v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper); + if (!vper || !hper || !hsper) + return -ENOLINK; + + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { + const struct v4l2_bt_timings *bt; + u32 lines, width, _hper, _hsper; + u32 vmin, vmax, hmin, hmax, hsmin, hsmax; + bool vmatch, hmatch, hsmatch; + + bt = &v4l2_dv_timings_presets[i].bt; + width = V4L2_DV_BT_FRAME_WIDTH(bt); + lines = V4L2_DV_BT_FRAME_HEIGHT(bt); + _hper = (u32)bt->pixelclock / width; + if (bt->interlaced) + lines /= 2; + /* vper +/- 0.7% */ + vmin = ((27000000 / 1000) * 993) / _hper * lines; + vmax = ((27000000 / 1000) * 1007) / _hper * lines; + /* hper +/- 1.0% */ + hmin = ((27000000 / 100) * 99) / _hper; + hmax = ((27000000 / 100) * 101) / _hper; + /* hsper +/- 2 (take care to avoid 32bit overflow) */ + _hsper = 27000 * bt->hsync / ((u32)bt->pixelclock/1000); + hsmin = _hsper - 2; + hsmax = _hsper + 2; + + /* vmatch matches the framerate */ + vmatch = ((vper <= vmax) && (vper >= vmin)) ? 1 : 0; + /* hmatch matches the width */ + hmatch = ((hper <= hmax) && (hper >= hmin)) ? 1 : 0; + /* hsmatch matches the hswidth */ + hsmatch = ((hsper <= hsmax) && (hsper >= hsmin)) ? 1 : 0; + if (hmatch && vmatch && hsmatch) { + v4l2_print_dv_timings(sd->name, "Detected format: ", + &v4l2_dv_timings_presets[i], + false); + if (timings) + *timings = v4l2_dv_timings_presets[i]; + return 0; + } + } + + v4l_err(state->client, "no resolution match for timings: %d/%d/%d\n", + vper, hper, hsper); + return -ERANGE; +} + +/* some sort of errata workaround for chip revision 0 (N1) */ +static void tda1997x_reset_n1(struct tda1997x_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg; + + /* clear HDMI mode flag in BCAPS */ + io_write(sd, REG_CLK_CFG, CLK_CFG_SEL_ACLK_EN | CLK_CFG_SEL_ACLK); + io_write(sd, REG_PON_OVR_EN, PON_EN); + io_write(sd, REG_PON_CBIAS, PON_EN); + io_write(sd, REG_PON_PLL, PON_EN); + + reg = io_read(sd, REG_MODE_REC_CFG1); + reg &= ~0x06; + reg |= 0x02; + io_write(sd, REG_MODE_REC_CFG1, reg); + io_write(sd, REG_CLK_CFG, CLK_CFG_DIS); + io_write(sd, REG_PON_OVR_EN, PON_DIS); + reg = io_read(sd, REG_MODE_REC_CFG1); + reg &= ~0x06; + io_write(sd, REG_MODE_REC_CFG1, reg); +} + +/* + * Activity detection must only be notified when stable_clk_x AND active_x + * bits are set to 1. If only stable_clk_x bit is set to 1 but not + * active_x, it means that the TMDS clock is not in the defined range + * and activity detection must not be notified. + */ +static u8 +tda1997x_read_activity_status_regs(struct v4l2_subdev *sd) +{ + u8 reg, status = 0; + + /* Read CLK_A_STATUS register */ + reg = io_read(sd, REG_CLK_A_STATUS); + /* ignore if not active */ + if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE)) + reg &= ~MASK_CLK_STABLE; + status |= ((reg & MASK_CLK_STABLE) >> 2); + + /* Read CLK_B_STATUS register */ + reg = io_read(sd, REG_CLK_B_STATUS); + /* ignore if not active */ + if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE)) + reg &= ~MASK_CLK_STABLE; + status |= ((reg & MASK_CLK_STABLE) >> 1); + + /* Read the SUS_STATUS register */ + reg = io_read(sd, REG_SUS_STATUS); + + /* If state = 5 => TMDS is locked */ + if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED) + status |= MASK_SUS_STATE; + else + status &= ~MASK_SUS_STATE; + + return status; +} + +static void +set_rgb_quantization_range(struct tda1997x_state *state) +{ + struct v4l2_hdmi_colorimetry *c = &state->colorimetry; + + state->colorimetry = v4l2_hdmi_rx_colorimetry(&state->avi_infoframe, + NULL, + state->timings.bt.height); + /* If ycbcr_enc is V4L2_YCBCR_ENC_DEFAULT, we receive RGB */ + if (c->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) { + switch (state->rgb_quantization_range) { + case V4L2_DV_RGB_RANGE_LIMITED: + c->quantization = V4L2_QUANTIZATION_FULL_RANGE; + break; + case V4L2_DV_RGB_RANGE_FULL: + c->quantization = V4L2_QUANTIZATION_LIM_RANGE; + break; + } + } + v4l_dbg(1, debug, state->client, + "colorspace=%d/%d colorimetry=%d range=%s content=%d\n", + state->avi_infoframe.colorspace, c->colorspace, + state->avi_infoframe.colorimetry, + v4l2_quantization_names[c->quantization], + state->avi_infoframe.content_type); +} + +/* parse an infoframe and do some sanity checks on it */ +static unsigned int +tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr) +{ + struct v4l2_subdev *sd = &state->sd; + union hdmi_infoframe frame; + u8 buffer[40]; + u8 reg; + int len, err; + + /* read data */ + len = io_readn(sd, addr, sizeof(buffer), buffer); + err = hdmi_infoframe_unpack(&frame, buffer); + if (err) { + v4l_err(state->client, + "failed parsing %d byte infoframe: 0x%04x/0x%02x\n", + len, addr, buffer[0]); + return err; + } + hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame); + switch (frame.any.type) { + /* Audio InfoFrame: see HDMI spec 8.2.2 */ + case HDMI_INFOFRAME_TYPE_AUDIO: + /* sample rate */ + switch (frame.audio.sample_frequency) { + case HDMI_AUDIO_SAMPLE_FREQUENCY_32000: + state->audio_samplerate = 32000; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_44100: + state->audio_samplerate = 44100; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_48000: + state->audio_samplerate = 48000; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_88200: + state->audio_samplerate = 88200; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_96000: + state->audio_samplerate = 96000; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_176400: + state->audio_samplerate = 176400; + break; + case HDMI_AUDIO_SAMPLE_FREQUENCY_192000: + state->audio_samplerate = 192000; + break; + default: + case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM: + break; + } + + /* sample size */ + switch (frame.audio.sample_size) { + case HDMI_AUDIO_SAMPLE_SIZE_16: + state->audio_samplesize = 16; + break; + case HDMI_AUDIO_SAMPLE_SIZE_20: + state->audio_samplesize = 20; + break; + case HDMI_AUDIO_SAMPLE_SIZE_24: + state->audio_samplesize = 24; + break; + case HDMI_AUDIO_SAMPLE_SIZE_STREAM: + default: + break; + } + + /* Channel Count */ + state->audio_channels = frame.audio.channels; + if (frame.audio.channel_allocation && + frame.audio.channel_allocation != state->audio_ch_alloc) { + /* use the channel assignment from the infoframe */ + state->audio_ch_alloc = frame.audio.channel_allocation; + tda1997x_configure_audout(sd, state->audio_ch_alloc); + /* reset the audio FIFO */ + tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false); + } + break; + + /* Auxiliary Video information (AVI) InfoFrame: see HDMI spec 8.2.1 */ + case HDMI_INFOFRAME_TYPE_AVI: + state->avi_infoframe = frame.avi; + set_rgb_quantization_range(state); + + /* configure upsampler: 0=bypass 1=repeatchroma 2=interpolate */ + reg = io_read(sd, REG_PIX_REPEAT); + reg &= ~PIX_REPEAT_MASK_UP_SEL; + if (frame.avi.colorspace == HDMI_COLORSPACE_YUV422) + reg |= (PIX_REPEAT_CHROMA << PIX_REPEAT_SHIFT); + io_write(sd, REG_PIX_REPEAT, reg); + + /* ConfigurePixelRepeater: repeat n-times each pixel */ + reg = io_read(sd, REG_PIX_REPEAT); + reg &= ~PIX_REPEAT_MASK_REP; + reg |= frame.avi.pixel_repeat; + io_write(sd, REG_PIX_REPEAT, reg); + + /* configure the receiver with the new colorspace */ + tda1997x_configure_csc(sd); + break; + default: + break; + } + return 0; +} + +static void tda1997x_irq_sus(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg, source; + + source = io_read(sd, REG_INT_FLG_CLR_SUS); + io_write(sd, REG_INT_FLG_CLR_SUS, source); + + if (source & MASK_MPT) { + /* reset MTP in use flag if set */ + if (state->mptrw_in_progress) + state->mptrw_in_progress = 0; + } + + if (source & MASK_SUS_END) { + /* reset audio FIFO */ + reg = io_read(sd, REG_HDMI_INFO_RST); + reg |= MASK_SR_FIFO_FIFO_CTRL; + io_write(sd, REG_HDMI_INFO_RST, reg); + reg &= ~MASK_SR_FIFO_FIFO_CTRL; + io_write(sd, REG_HDMI_INFO_RST, reg); + + /* reset HDMI flags */ + state->hdmi_status = 0; + } + + /* filter FMT interrupt based on SUS state */ + reg = io_read(sd, REG_SUS_STATUS); + if (((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED) + || (source & MASK_MPT)) { + source &= ~MASK_FMT; + } + + if (source & (MASK_FMT | MASK_SUS_END)) { + reg = io_read(sd, REG_SUS_STATUS); + if ((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED) { + v4l_err(state->client, "BAD SUS STATUS\n"); + return; + } + if (debug) + tda1997x_detect_std(state, NULL); + /* notify user of change in resolution */ + v4l2_subdev_notify_event(&state->sd, &tda1997x_ev_fmt); + } +} + +static void tda1997x_irq_ddc(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 source; + + source = io_read(sd, REG_INT_FLG_CLR_DDC); + io_write(sd, REG_INT_FLG_CLR_DDC, source); + if (source & MASK_EDID_MTP) { + /* reset MTP in use flag if set */ + if (state->mptrw_in_progress) + state->mptrw_in_progress = 0; + } + + /* Detection of +5V */ + if (source & MASK_DET_5V) { + v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, + tda1997x_detect_tx_5v(sd)); + } +} + +static void tda1997x_irq_rate(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg, source; + + u8 irq_status; + + source = io_read(sd, REG_INT_FLG_CLR_RATE); + io_write(sd, REG_INT_FLG_CLR_RATE, source); + + /* read status regs */ + irq_status = tda1997x_read_activity_status_regs(sd); + + /* + * read clock status reg until INT_FLG_CLR_RATE is still 0 + * after the read to make sure its the last one + */ + reg = source; + while (reg != 0) { + irq_status = tda1997x_read_activity_status_regs(sd); + reg = io_read(sd, REG_INT_FLG_CLR_RATE); + io_write(sd, REG_INT_FLG_CLR_RATE, reg); + source |= reg; + } + + /* we only pay attention to stability change events */ + if (source & (MASK_RATE_A_ST | MASK_RATE_B_ST)) { + int input = (source & MASK_RATE_A_ST)?0:1; + u8 mask = 1<<input; + + /* state change */ + if ((irq_status & mask) != (state->activity_status & mask)) { + /* activity lost */ + if ((irq_status & mask) == 0) { + v4l_info(state->client, + "HDMI-%c: Digital Activity Lost\n", + input+'A'); + + /* bypass up/down sampler and pixel repeater */ + reg = io_read(sd, REG_PIX_REPEAT); + reg &= ~PIX_REPEAT_MASK_UP_SEL; + reg &= ~PIX_REPEAT_MASK_REP; + io_write(sd, REG_PIX_REPEAT, reg); + + if (state->chip_revision == 0) + tda1997x_reset_n1(state); + + state->input_detect[input] = 0; + v4l2_subdev_notify_event(sd, &tda1997x_ev_fmt); + } + + /* activity detected */ + else { + v4l_info(state->client, + "HDMI-%c: Digital Activity Detected\n", + input+'A'); + state->input_detect[input] = 1; + } + + /* hold onto current state */ + state->activity_status = (irq_status & mask); + } + } +} + +static void tda1997x_irq_info(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 source; + + source = io_read(sd, REG_INT_FLG_CLR_INFO); + io_write(sd, REG_INT_FLG_CLR_INFO, source); + + /* Audio infoframe */ + if (source & MASK_AUD_IF) { + tda1997x_parse_infoframe(state, AUD_IF); + source &= ~MASK_AUD_IF; + } + + /* Source Product Descriptor infoframe change */ + if (source & MASK_SPD_IF) { + tda1997x_parse_infoframe(state, SPD_IF); + source &= ~MASK_SPD_IF; + } + + /* Auxiliary Video Information infoframe */ + if (source & MASK_AVI_IF) { + tda1997x_parse_infoframe(state, AVI_IF); + source &= ~MASK_AVI_IF; + } +} + +static void tda1997x_irq_audio(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg, source; + + source = io_read(sd, REG_INT_FLG_CLR_AUDIO); + io_write(sd, REG_INT_FLG_CLR_AUDIO, source); + + /* reset audio FIFO on FIFO pointer error or audio mute */ + if (source & MASK_ERROR_FIFO_PT || + source & MASK_MUTE_FLG) { + /* audio reset audio FIFO */ + reg = io_read(sd, REG_SUS_STATUS); + if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED) { + reg = io_read(sd, REG_HDMI_INFO_RST); + reg |= MASK_SR_FIFO_FIFO_CTRL; + io_write(sd, REG_HDMI_INFO_RST, reg); + reg &= ~MASK_SR_FIFO_FIFO_CTRL; + io_write(sd, REG_HDMI_INFO_RST, reg); + /* reset channel status IT if present */ + source &= ~(MASK_CH_STATE); + } + } + if (source & MASK_AUDIO_FREQ_FLG) { + static const int freq[] = { + 0, 32000, 44100, 48000, 88200, 96000, 176400, 192000 + }; + + reg = io_read(sd, REG_AUDIO_FREQ); + state->audio_samplerate = freq[reg & 7]; + v4l_info(state->client, "Audio Frequency Change: %dHz\n", + state->audio_samplerate); + } + if (source & MASK_AUDIO_FLG) { + reg = io_read(sd, REG_AUDIO_FLAGS); + if (reg & BIT(AUDCFG_TYPE_DST)) + state->audio_type = AUDCFG_TYPE_DST; + if (reg & BIT(AUDCFG_TYPE_OBA)) + state->audio_type = AUDCFG_TYPE_OBA; + if (reg & BIT(AUDCFG_TYPE_HBR)) + state->audio_type = AUDCFG_TYPE_HBR; + if (reg & BIT(AUDCFG_TYPE_PCM)) + state->audio_type = AUDCFG_TYPE_PCM; + v4l_info(state->client, "Audio Type: %s\n", + audtype_names[state->audio_type]); + } +} + +static void tda1997x_irq_hdcp(struct tda1997x_state *state, u8 *flags) +{ + struct v4l2_subdev *sd = &state->sd; + u8 reg, source; + + source = io_read(sd, REG_INT_FLG_CLR_HDCP); + io_write(sd, REG_INT_FLG_CLR_HDCP, source); + + /* reset MTP in use flag if set */ + if (source & MASK_HDCP_MTP) + state->mptrw_in_progress = 0; + if (source & MASK_STATE_C5) { + /* REPEATER: mask AUDIO and IF irqs to avoid IF during auth */ + reg = io_read(sd, REG_INT_MASK_TOP); + reg &= ~(INTERRUPT_AUDIO | INTERRUPT_INFO); + io_write(sd, REG_INT_MASK_TOP, reg); + *flags &= (INTERRUPT_AUDIO | INTERRUPT_INFO); + } +} + +static irqreturn_t tda1997x_isr_thread(int irq, void *d) +{ + struct tda1997x_state *state = d; + struct v4l2_subdev *sd = &state->sd; + u8 flags; + + mutex_lock(&state->lock); + do { + /* read interrupt flags */ + flags = io_read(sd, REG_INT_FLG_CLR_TOP); + if (flags == 0) + break; + + /* SUS interrupt source (Input activity events) */ + if (flags & INTERRUPT_SUS) + tda1997x_irq_sus(state, &flags); + /* DDC interrupt source (Display Data Channel) */ + else if (flags & INTERRUPT_DDC) + tda1997x_irq_ddc(state, &flags); + /* RATE interrupt source (Digital Input activity) */ + else if (flags & INTERRUPT_RATE) + tda1997x_irq_rate(state, &flags); + /* Infoframe change interrupt */ + else if (flags & INTERRUPT_INFO) + tda1997x_irq_info(state, &flags); + /* Audio interrupt source: + * freq change, DST,OBA,HBR,ASP flags, mute, FIFO err + */ + else if (flags & INTERRUPT_AUDIO) + tda1997x_irq_audio(state, &flags); + /* HDCP interrupt source (content protection) */ + if (flags & INTERRUPT_HDCP) + tda1997x_irq_hdcp(state, &flags); + } while (flags != 0); + mutex_unlock(&state->lock); + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_video_ops + */ + +static int +tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct tda1997x_state *state = to_state(sd); + u32 vper; + u16 hper; + u16 hsper; + + mutex_lock(&state->lock); + vper = io_read24(sd, REG_V_PER) & MASK_VPER; + hper = io_read16(sd, REG_H_PER) & MASK_HPER; + hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; + /* + * The tda1997x supports A/B inputs but only a single output. + * The irq handler monitors for timing changes on both inputs and + * sets the input_detect array to 0|1 depending on signal presence. + * I believe selection of A vs B is automatic. + * + * The vper/hper/hsper registers provide the frame period, line period + * and horiz sync period (units of MCLK clock cycles (27MHz)) and + * testing shows these values to be random if no signal is present + * or locked. + */ + v4l2_dbg(1, debug, sd, "inputs:%d/%d timings:%d/%d/%d\n", + state->input_detect[0], state->input_detect[1], + vper, hper, hsper); + if (!state->input_detect[0] && !state->input_detect[1]) + *status = V4L2_IN_ST_NO_SIGNAL; + else if (!vper || !hper || !hsper) + *status = V4L2_IN_ST_NO_SYNC; + else + *status = 0; + mutex_unlock(&state->lock); + + return 0; +}; + +static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s\n", __func__); + + if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) + return 0; /* no changes */ + + if (!v4l2_valid_dv_timings(timings, &tda1997x_dv_timings_cap, + NULL, NULL)) + return -ERANGE; + + mutex_lock(&state->lock); + state->timings = *timings; + /* setup frame detection window and VHREF timing generator */ + tda1997x_configure_vhref(sd); + /* configure colorspace conversion */ + tda1997x_configure_csc(sd); + mutex_unlock(&state->lock); + + return 0; +} + +static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s\n", __func__); + mutex_lock(&state->lock); + *timings = state->timings; + mutex_unlock(&state->lock); + + return 0; +} + +static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s\n", __func__); + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + mutex_lock(&state->lock); + tda1997x_detect_std(state, timings); + mutex_unlock(&state->lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops tda1997x_video_ops = { + .g_input_status = tda1997x_g_input_status, + .s_dv_timings = tda1997x_s_dv_timings, + .g_dv_timings = tda1997x_g_dv_timings, + .query_dv_timings = tda1997x_query_dv_timings, +}; + + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_pad_ops + */ + +static int tda1997x_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct tda1997x_state *state = to_state(sd); + struct v4l2_mbus_framefmt *mf; + + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + mf->code = state->mbus_codes[0]; + + return 0; +} + +static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s %d\n", __func__, code->index); + if (code->index >= ARRAY_SIZE(state->mbus_codes)) + return -EINVAL; + + if (!state->mbus_codes[code->index]) + return -EINVAL; + + code->code = state->mbus_codes[code->index]; + + return 0; +} + +static void tda1997x_fill_format(struct tda1997x_state *state, + struct v4l2_mbus_framefmt *format) +{ + const struct v4l2_bt_timings *bt; + + memset(format, 0, sizeof(*format)); + bt = &state->timings.bt; + format->width = bt->width; + format->height = bt->height; + format->colorspace = state->colorimetry.colorspace; + format->field = (bt->interlaced) ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_NONE; +} + +static int tda1997x_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s pad=%d which=%d\n", + __func__, format->pad, format->which); + + tda1997x_fill_format(state, &format->format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + format->format.code = fmt->code; + } else + format->format.code = state->mbus_code; + + return 0; +} + +static int tda1997x_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tda1997x_state *state = to_state(sd); + u32 code = 0; + int i; + + v4l_dbg(1, debug, state->client, "%s pad=%d which=%d fmt=0x%x\n", + __func__, format->pad, format->which, format->format.code); + + for (i = 0; i < ARRAY_SIZE(state->mbus_codes); i++) { + if (format->format.code == state->mbus_codes[i]) { + code = state->mbus_codes[i]; + break; + } + } + if (!code) + code = state->mbus_codes[0]; + + tda1997x_fill_format(state, &format->format); + format->format.code = code; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + *fmt = format->format; + } else { + int ret = tda1997x_setup_format(state, format->format.code); + + if (ret) + return ret; + /* mbus_code has changed - re-configure csc/vidout */ + tda1997x_configure_csc(sd); + tda1997x_configure_vidout(state); + } + + return 0; +} + +static int tda1997x_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct tda1997x_state *state = to_state(sd); + + v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad); + memset(edid->reserved, 0, sizeof(edid->reserved)); + + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = state->edid.blocks; + return 0; + } + + if (!state->edid.present) + return -ENODATA; + + if (edid->start_block >= state->edid.blocks) + return -EINVAL; + + if (edid->start_block + edid->blocks > state->edid.blocks) + edid->blocks = state->edid.blocks - edid->start_block; + + memcpy(edid->edid, state->edid.edid + edid->start_block * 128, + edid->blocks * 128); + + return 0; +} + +static int tda1997x_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct tda1997x_state *state = to_state(sd); + int i; + + v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad); + memset(edid->reserved, 0, sizeof(edid->reserved)); + + if (edid->start_block != 0) + return -EINVAL; + + if (edid->blocks == 0) { + state->edid.blocks = 0; + state->edid.present = 0; + tda1997x_disable_edid(sd); + return 0; + } + + if (edid->blocks > 2) { + edid->blocks = 2; + return -E2BIG; + } + + tda1997x_disable_edid(sd); + + /* write base EDID */ + for (i = 0; i < 128; i++) + io_write(sd, REG_EDID_IN_BYTE0 + i, edid->edid[i]); + + /* write CEA Extension */ + for (i = 0; i < 128; i++) + io_write(sd, REG_EDID_IN_BYTE128 + i, edid->edid[i+128]); + + tda1997x_enable_edid(sd); + + return 0; +} + +static int tda1997x_get_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + *cap = tda1997x_dv_timings_cap; + return 0; +} + +static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &tda1997x_dv_timings_cap, + NULL, NULL); +} + +static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = { + .init_cfg = tda1997x_init_cfg, + .enum_mbus_code = tda1997x_enum_mbus_code, + .get_fmt = tda1997x_get_format, + .set_fmt = tda1997x_set_format, + .get_edid = tda1997x_get_edid, + .set_edid = tda1997x_set_edid, + .dv_timings_cap = tda1997x_get_dv_timings_cap, + .enum_dv_timings = tda1997x_enum_dv_timings, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_core_ops + */ + +static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr) +{ + struct tda1997x_state *state = to_state(sd); + union hdmi_infoframe frame; + u8 buffer[40]; + int len, err; + + /* read data */ + len = io_readn(sd, addr, sizeof(buffer), buffer); + v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len); + err = hdmi_infoframe_unpack(&frame, buffer); + if (err) { + v4l_err(state->client, + "failed parsing %d byte infoframe: 0x%04x/0x%02x\n", + len, addr, buffer[0]); + return err; + } + hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame); + + return 0; +} + +static int tda1997x_log_status(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + struct v4l2_dv_timings timings; + struct hdmi_avi_infoframe *avi = &state->avi_infoframe; + + v4l2_info(sd, "-----Chip status-----\n"); + v4l2_info(sd, "Chip: %s N%d\n", state->info->name, + state->chip_revision + 1); + v4l2_info(sd, "EDID Enabled: %s\n", state->edid.present ? "yes" : "no"); + + v4l2_info(sd, "-----Signal status-----\n"); + v4l2_info(sd, "Cable detected (+5V power): %s\n", + tda1997x_detect_tx_5v(sd) ? "yes" : "no"); + v4l2_info(sd, "HPD detected: %s\n", + tda1997x_detect_tx_hpd(sd) ? "yes" : "no"); + + v4l2_info(sd, "-----Video Timings-----\n"); + switch (tda1997x_detect_std(state, &timings)) { + case -ENOLINK: + v4l2_info(sd, "No video detected\n"); + break; + case -ERANGE: + v4l2_info(sd, "Invalid signal detected\n"); + break; + } + v4l2_print_dv_timings(sd->name, "Configured format: ", + &state->timings, true); + + v4l2_info(sd, "-----Color space-----\n"); + v4l2_info(sd, "Input color space: %s %s %s", + hdmi_colorspace_names[avi->colorspace], + (avi->colorspace == HDMI_COLORSPACE_RGB) ? "" : + hdmi_colorimetry_names[avi->colorimetry], + v4l2_quantization_names[state->colorimetry.quantization]); + v4l2_info(sd, "Output color space: %s", + vidfmt_names[state->vid_fmt]); + v4l2_info(sd, "Color space conversion: %s", state->conv ? + state->conv->name : "None"); + + v4l2_info(sd, "-----Audio-----\n"); + if (state->audio_channels) { + v4l2_info(sd, "audio: %dch %dHz\n", state->audio_channels, + state->audio_samplerate); + } else { + v4l2_info(sd, "audio: none\n"); + } + + v4l2_info(sd, "-----Infoframes-----\n"); + tda1997x_log_infoframe(sd, AUD_IF); + tda1997x_log_infoframe(sd, SPD_IF); + tda1997x_log_infoframe(sd, AVI_IF); + + return 0; +} + +static int tda1997x_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + +static const struct v4l2_subdev_core_ops tda1997x_core_ops = { + .log_status = tda1997x_log_status, + .subscribe_event = tda1997x_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_ops + */ + +static const struct v4l2_subdev_ops tda1997x_subdev_ops = { + .core = &tda1997x_core_ops, + .video = &tda1997x_video_ops, + .pad = &tda1997x_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_controls + */ + +static int tda1997x_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct tda1997x_state *state = to_state(sd); + + switch (ctrl->id) { + /* allow overriding the default RGB quantization range */ + case V4L2_CID_DV_RX_RGB_RANGE: + state->rgb_quantization_range = ctrl->val; + set_rgb_quantization_range(state); + tda1997x_configure_csc(sd); + return 0; + } + + return -EINVAL; +}; + +static int tda1997x_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct tda1997x_state *state = to_state(sd); + + if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) { + ctrl->val = state->avi_infoframe.content_type; + return 0; + } + return -EINVAL; +}; + +static const struct v4l2_ctrl_ops tda1997x_ctrl_ops = { + .s_ctrl = tda1997x_s_ctrl, + .g_volatile_ctrl = tda1997x_g_volatile_ctrl, +}; + +static int tda1997x_core_init(struct v4l2_subdev *sd) +{ + struct tda1997x_state *state = to_state(sd); + struct tda1997x_platform_data *pdata = &state->pdata; + u8 reg; + int i; + + /* disable HPD */ + io_write(sd, REG_HPD_AUTO_CTRL, HPD_AUTO_HPD_UNSEL); + if (state->chip_revision == 0) { + io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_DIS_HDCP | MAN_RST_HDCP); + io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT); + } + + /* reset infoframe at end of start-up-sequencer */ + io_write(sd, REG_SUS_SET_RGB2, 0x06); + io_write(sd, REG_SUS_SET_RGB3, 0x06); + + /* Enable TMDS pull-ups */ + io_write(sd, REG_RT_MAN_CTRL, RT_MAN_CTRL_RT | + RT_MAN_CTRL_RT_B | RT_MAN_CTRL_RT_A); + + /* enable sync measurement timing */ + tda1997x_cec_write(sd, REG_PWR_CONTROL & 0xff, 0x04); + /* adjust CEC clock divider */ + tda1997x_cec_write(sd, REG_OSC_DIVIDER & 0xff, 0x03); + tda1997x_cec_write(sd, REG_EN_OSC_PERIOD_LSB & 0xff, 0xa0); + io_write(sd, REG_TIMER_D, 0x54); + /* enable power switch */ + reg = tda1997x_cec_read(sd, REG_CONTROL & 0xff); + reg |= 0x20; + tda1997x_cec_write(sd, REG_CONTROL & 0xff, reg); + mdelay(50); + + /* read the chip version */ + reg = io_read(sd, REG_VERSION); + /* get the chip configuration */ + reg = io_read(sd, REG_CMTP_REG10); + + /* enable interrupts we care about */ + io_write(sd, REG_INT_MASK_TOP, + INTERRUPT_HDCP | INTERRUPT_AUDIO | INTERRUPT_INFO | + INTERRUPT_RATE | INTERRUPT_SUS); + /* config_mtp,fmt,sus_end,sus_st */ + io_write(sd, REG_INT_MASK_SUS, MASK_MPT | MASK_FMT | MASK_SUS_END); + /* rate stability change for inputs A/B */ + io_write(sd, REG_INT_MASK_RATE, MASK_RATE_B_ST | MASK_RATE_A_ST); + /* aud,spd,avi*/ + io_write(sd, REG_INT_MASK_INFO, + MASK_AUD_IF | MASK_SPD_IF | MASK_AVI_IF); + /* audio_freq,audio_flg,mute_flg,fifo_err */ + io_write(sd, REG_INT_MASK_AUDIO, + MASK_AUDIO_FREQ_FLG | MASK_AUDIO_FLG | MASK_MUTE_FLG | + MASK_ERROR_FIFO_PT); + /* HDCP C5 state reached */ + io_write(sd, REG_INT_MASK_HDCP, MASK_STATE_C5); + /* 5V detect and HDP pulse end */ + io_write(sd, REG_INT_MASK_DDC, MASK_DET_5V); + /* don't care about AFE/MODE */ + io_write(sd, REG_INT_MASK_AFE, 0); + io_write(sd, REG_INT_MASK_MODE, 0); + + /* clear all interrupts */ + io_write(sd, REG_INT_FLG_CLR_TOP, 0xff); + io_write(sd, REG_INT_FLG_CLR_SUS, 0xff); + io_write(sd, REG_INT_FLG_CLR_DDC, 0xff); + io_write(sd, REG_INT_FLG_CLR_RATE, 0xff); + io_write(sd, REG_INT_FLG_CLR_MODE, 0xff); + io_write(sd, REG_INT_FLG_CLR_INFO, 0xff); + io_write(sd, REG_INT_FLG_CLR_AUDIO, 0xff); + io_write(sd, REG_INT_FLG_CLR_HDCP, 0xff); + io_write(sd, REG_INT_FLG_CLR_AFE, 0xff); + + /* init TMDS equalizer */ + if (state->chip_revision == 0) + io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT); + io_write24(sd, REG_CLK_MIN_RATE, CLK_MIN_RATE); + io_write24(sd, REG_CLK_MAX_RATE, CLK_MAX_RATE); + if (state->chip_revision == 0) + io_write(sd, REG_WDL_CFG, WDL_CFG_VAL); + /* DC filter */ + io_write(sd, REG_DEEP_COLOR_CTRL, DC_FILTER_VAL); + /* disable test pattern */ + io_write(sd, REG_SVC_MODE, 0x00); + /* update HDMI INFO CTRL */ + io_write(sd, REG_INFO_CTRL, 0xff); + /* write HDMI INFO EXCEED value */ + io_write(sd, REG_INFO_EXCEED, 3); + + if (state->chip_revision == 0) + tda1997x_reset_n1(state); + + /* + * No HDCP acknowledge when HDCP is disabled + * and reset SUS to force format detection + */ + tda1997x_hdmi_info_reset(sd, NACK_HDCP, true); + + /* Set HPD low */ + tda1997x_manual_hpd(sd, HPD_LOW_BP); + + /* Configure receiver capabilities */ + io_write(sd, REG_HDCP_BCAPS, HDCP_HDMI | HDCP_FAST_REAUTH); + + /* Configure HDMI: Auto HDCP mode, packet controlled mute */ + reg = HDMI_CTRL_MUTE_AUTO << HDMI_CTRL_MUTE_SHIFT; + reg |= HDMI_CTRL_HDCP_AUTO << HDMI_CTRL_HDCP_SHIFT; + io_write(sd, REG_HDMI_CTRL, reg); + + /* reset start-up-sequencer to force format detection */ + tda1997x_hdmi_info_reset(sd, 0, true); + + /* disable matrix conversion */ + reg = io_read(sd, REG_VDP_CTRL); + reg |= VDP_CTRL_MATRIX_BP; + io_write(sd, REG_VDP_CTRL, reg); + + /* set video output mode */ + tda1997x_configure_vidout(state); + + /* configure video output port */ + for (i = 0; i < 9; i++) { + v4l_dbg(1, debug, state->client, "vidout_cfg[%d]=0x%02x\n", i, + pdata->vidout_port_cfg[i]); + io_write(sd, REG_VP35_32_CTRL + i, pdata->vidout_port_cfg[i]); + } + + /* configure audio output port */ + tda1997x_configure_audout(sd, 0); + + /* configure audio clock freq */ + switch (pdata->audout_mclk_fs) { + case 512: + reg = AUDIO_CLOCK_SEL_512FS; + break; + case 256: + reg = AUDIO_CLOCK_SEL_256FS; + break; + case 128: + reg = AUDIO_CLOCK_SEL_128FS; + break; + case 64: + reg = AUDIO_CLOCK_SEL_64FS; + break; + case 32: + reg = AUDIO_CLOCK_SEL_32FS; + break; + default: + reg = AUDIO_CLOCK_SEL_16FS; + break; + } + io_write(sd, REG_AUDIO_CLOCK, reg); + + /* reset advanced infoframes (ISRC1/ISRC2/ACP) */ + tda1997x_hdmi_info_reset(sd, RESET_AI, false); + /* reset infoframe */ + tda1997x_hdmi_info_reset(sd, RESET_IF, false); + /* reset audio infoframes */ + tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false); + /* reset gamut */ + tda1997x_hdmi_info_reset(sd, RESET_GAMUT, false); + + /* get initial HDMI status */ + state->hdmi_status = io_read(sd, REG_HDMI_FLAGS); + + return 0; +} + +static int tda1997x_set_power(struct tda1997x_state *state, bool on) +{ + int ret = 0; + + if (on) { + ret = regulator_bulk_enable(TDA1997X_NUM_SUPPLIES, + state->supplies); + msleep(300); + } else { + ret = regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, + state->supplies); + } + + return ret; +} + +static const struct i2c_device_id tda1997x_i2c_id[] = { + {"tda19971", (kernel_ulong_t)&tda1997x_chip_info[TDA19971]}, + {"tda19973", (kernel_ulong_t)&tda1997x_chip_info[TDA19973]}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, tda1997x_i2c_id); + +static const struct of_device_id tda1997x_of_id[] __maybe_unused = { + { .compatible = "nxp,tda19971", .data = &tda1997x_chip_info[TDA19971] }, + { .compatible = "nxp,tda19973", .data = &tda1997x_chip_info[TDA19973] }, + { }, +}; +MODULE_DEVICE_TABLE(of, tda1997x_of_id); + +static int tda1997x_parse_dt(struct tda1997x_state *state) +{ + struct tda1997x_platform_data *pdata = &state->pdata; + struct v4l2_fwnode_endpoint bus_cfg; + struct device_node *ep; + struct device_node *np; + unsigned int flags; + const char *str; + int ret; + u32 v; + + /* + * setup default values: + * - HREF: active high from start to end of row + * - VS: Vertical Sync active high at beginning of frame + * - DE: Active high when data valid + * - A_CLK: 128*Fs + */ + pdata->vidout_sel_hs = HS_HREF_SEL_HREF_VHREF; + pdata->vidout_sel_vs = VS_VREF_SEL_VREF_HDMI; + pdata->vidout_sel_de = DE_FREF_SEL_DE_VHREF; + + np = state->client->dev.of_node; + ep = of_graph_get_next_endpoint(np, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); + if (ret) { + of_node_put(ep); + return ret; + } + of_node_put(ep); + pdata->vidout_bus_type = bus_cfg.bus_type; + + /* polarity of HS/VS/DE */ + flags = bus_cfg.bus.parallel.flags; + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + pdata->vidout_inv_hs = 1; + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + pdata->vidout_inv_vs = 1; + if (flags & V4L2_MBUS_DATA_ACTIVE_LOW) + pdata->vidout_inv_de = 1; + pdata->vidout_bus_width = bus_cfg.bus.parallel.bus_width; + + /* video output port config */ + ret = of_property_count_u32_elems(np, "nxp,vidout-portcfg"); + if (ret > 0) { + u32 reg, val, i; + + for (i = 0; i < ret / 2 && i < 9; i++) { + of_property_read_u32_index(np, "nxp,vidout-portcfg", + i * 2, ®); + of_property_read_u32_index(np, "nxp,vidout-portcfg", + i * 2 + 1, &val); + if (reg < 9) + pdata->vidout_port_cfg[reg] = val; + } + } else { + v4l_err(state->client, "nxp,vidout-portcfg missing\n"); + return -EINVAL; + } + + /* default to channel layout dictated by packet header */ + pdata->audout_layoutauto = true; + + pdata->audout_format = AUDFMT_TYPE_DISABLED; + if (!of_property_read_string(np, "nxp,audout-format", &str)) { + if (strcmp(str, "i2s") == 0) + pdata->audout_format = AUDFMT_TYPE_I2S; + else if (strcmp(str, "spdif") == 0) + pdata->audout_format = AUDFMT_TYPE_SPDIF; + else { + v4l_err(state->client, "nxp,audout-format invalid\n"); + return -EINVAL; + } + if (!of_property_read_u32(np, "nxp,audout-layout", &v)) { + switch (v) { + case 0: + case 1: + break; + default: + v4l_err(state->client, + "nxp,audout-layout invalid\n"); + return -EINVAL; + } + pdata->audout_layout = v; + } + if (!of_property_read_u32(np, "nxp,audout-width", &v)) { + switch (v) { + case 16: + case 32: + break; + default: + v4l_err(state->client, + "nxp,audout-width invalid\n"); + return -EINVAL; + } + pdata->audout_width = v; + } + if (!of_property_read_u32(np, "nxp,audout-mclk-fs", &v)) { + switch (v) { + case 512: + case 256: + case 128: + case 64: + case 32: + case 16: + break; + default: + v4l_err(state->client, + "nxp,audout-mclk-fs invalid\n"); + return -EINVAL; + } + pdata->audout_mclk_fs = v; + } + } + + return 0; +} + +static int tda1997x_get_regulators(struct tda1997x_state *state) +{ + int i; + + for (i = 0; i < TDA1997X_NUM_SUPPLIES; i++) + state->supplies[i].supply = tda1997x_supply_name[i]; + + return devm_regulator_bulk_get(&state->client->dev, + TDA1997X_NUM_SUPPLIES, + state->supplies); +} + +static int tda1997x_identify_module(struct tda1997x_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + enum tda1997x_type type; + u8 reg; + + /* Read chip configuration*/ + reg = io_read(sd, REG_CMTP_REG10); + state->tmdsb_clk = (reg >> 6) & 0x01; /* use tmds clock B_inv for B */ + state->tmdsb_soc = (reg >> 5) & 0x01; /* tmds of input B */ + state->port_30bit = (reg >> 2) & 0x03; /* 30bit vs 24bit */ + state->output_2p5 = (reg >> 1) & 0x01; /* output supply 2.5v */ + switch ((reg >> 4) & 0x03) { + case 0x00: + type = TDA19971; + break; + case 0x02: + case 0x03: + type = TDA19973; + break; + default: + dev_err(&state->client->dev, "unsupported chip ID\n"); + return -EIO; + } + if (state->info->type != type) { + dev_err(&state->client->dev, "chip id mismatch\n"); + return -EIO; + } + + /* read chip revision */ + state->chip_revision = io_read(sd, REG_CMTP_REG11); + + return 0; +} + +static const struct media_entity_operations tda1997x_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + + +/* ----------------------------------------------------------------------------- + * HDMI Audio Codec + */ + +/* refine sample-rate based on HDMI source */ +static int tda1997x_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tda1997x_state *state = snd_soc_dai_get_drvdata(dai); + struct snd_soc_codec *codec = dai->codec; + struct snd_pcm_runtime *rtd = substream->runtime; + int rate, err; + + rate = state->audio_samplerate; + err = snd_pcm_hw_constraint_minmax(rtd, SNDRV_PCM_HW_PARAM_RATE, + rate, rate); + if (err < 0) { + dev_err(codec->dev, "failed to constrain samplerate to %dHz\n", + rate); + return err; + } + dev_info(codec->dev, "set samplerate constraint to %dHz\n", rate); + + return 0; +} + +static const struct snd_soc_dai_ops tda1997x_dai_ops = { + .startup = tda1997x_pcm_startup, +}; + +static struct snd_soc_dai_driver tda1997x_audio_dai = { + .name = "tda1997x", + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + }, + .ops = &tda1997x_dai_ops, +}; + +static int tda1997x_codec_probe(struct snd_soc_codec *codec) +{ + return 0; +} + +static int tda1997x_codec_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static struct snd_soc_codec_driver tda1997x_codec_driver = { + .probe = tda1997x_codec_probe, + .remove = tda1997x_codec_remove, + .reg_word_size = sizeof(u16), +}; + +static int tda1997x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tda1997x_state *state; + struct tda1997x_platform_data *pdata; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *hdl; + struct v4l2_ctrl *ctrl; + static const struct v4l2_dv_timings cea1920x1080 = + V4L2_DV_BT_CEA_1920X1080P60; + u32 *mbus_codes; + int i, ret; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + state = kzalloc(sizeof(struct tda1997x_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->client = client; + pdata = &state->pdata; + if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) { + const struct of_device_id *oid; + + oid = of_match_node(tda1997x_of_id, client->dev.of_node); + state->info = oid->data; + + ret = tda1997x_parse_dt(state); + if (ret < 0) { + v4l_err(client, "DT parsing error\n"); + goto err_free_state; + } + } else if (client->dev.platform_data) { + struct tda1997x_platform_data *pdata = + client->dev.platform_data; + state->info = + (const struct tda1997x_chip_info *)id->driver_data; + state->pdata = *pdata; + } else { + v4l_err(client, "No platform data\n"); + ret = -ENODEV; + goto err_free_state; + } + + ret = tda1997x_get_regulators(state); + if (ret) + goto err_free_state; + + ret = tda1997x_set_power(state, 1); + if (ret) + goto err_free_state; + + mutex_init(&state->page_lock); + mutex_init(&state->lock); + state->page = 0xff; + + INIT_DELAYED_WORK(&state->delayed_work_enable_hpd, + tda1997x_delayed_work_enable_hpd); + + /* set video format based on chip and bus width */ + ret = tda1997x_identify_module(state); + if (ret) + goto err_free_mutex; + + /* initialize subdev */ + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_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 | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.function = MEDIA_ENT_F_DTV_DECODER; + sd->entity.ops = &tda1997x_media_ops; + + /* set allowed mbus modes based on chip, bus-type, and bus-width */ + i = 0; + mbus_codes = state->mbus_codes; + switch (state->info->type) { + case TDA19973: + switch (pdata->vidout_bus_type) { + case V4L2_MBUS_PARALLEL: + switch (pdata->vidout_bus_width) { + case 36: + mbus_codes[i++] = MEDIA_BUS_FMT_RGB121212_1X36; + mbus_codes[i++] = MEDIA_BUS_FMT_YUV12_1X36; + /* fall-through */ + case 24: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24; + break; + } + break; + case V4L2_MBUS_BT656: + switch (pdata->vidout_bus_width) { + case 36: + case 24: + case 12: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12; + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10; + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8; + break; + } + break; + default: + break; + } + break; + case TDA19971: + switch (pdata->vidout_bus_type) { + case V4L2_MBUS_PARALLEL: + switch (pdata->vidout_bus_width) { + case 24: + mbus_codes[i++] = MEDIA_BUS_FMT_RGB888_1X24; + mbus_codes[i++] = MEDIA_BUS_FMT_YUV8_1X24; + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24; + /* fall through */ + case 20: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_1X20; + /* fall through */ + case 16: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_1X16; + break; + } + break; + case V4L2_MBUS_BT656: + switch (pdata->vidout_bus_width) { + case 24: + case 20: + case 16: + case 12: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12; + /* fall through */ + case 10: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10; + /* fall through */ + case 8: + mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8; + break; + } + break; + default: + break; + } + break; + } + if (WARN_ON(i > ARRAY_SIZE(state->mbus_codes))) { + ret = -EINVAL; + goto err_free_mutex; + } + + /* default format */ + tda1997x_setup_format(state, state->mbus_codes[0]); + state->timings = cea1920x1080; + + /* + * default to SRGB full range quantization + * (in case we don't get an infoframe such as DVI signal + */ + state->colorimetry.colorspace = V4L2_COLORSPACE_SRGB; + state->colorimetry.quantization = V4L2_QUANTIZATION_FULL_RANGE; + + /* disable/reset HDCP to get correct I2C access to Rx HDMI */ + io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_RST_HDCP | MAN_DIS_HDCP); + + /* + * if N2 version, reset compdel_bp as it may generate some small pixel + * shifts in case of embedded sync/or delay lower than 4 + */ + if (state->chip_revision != 0) { + io_write(sd, REG_MAN_SUS_HDMI_SEL, 0x00); + io_write(sd, REG_VDP_CTRL, 0x1f); + } + + v4l_info(client, "NXP %s N%d detected\n", state->info->name, + state->chip_revision + 1); + v4l_info(client, "video: %dbit %s %d formats available\n", + pdata->vidout_bus_width, + (pdata->vidout_bus_type == V4L2_MBUS_PARALLEL) ? + "parallel" : "BT656", + i); + if (pdata->audout_format) { + v4l_info(client, "audio: %dch %s layout%d sysclk=%d*fs\n", + pdata->audout_layout ? 2 : 8, + audfmt_names[pdata->audout_format], + pdata->audout_layout, + pdata->audout_mclk_fs); + } + + ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03); + state->client_cec = i2c_new_dummy(client->adapter, ret); + v4l_info(client, "CEC slave address 0x%02x\n", ret); + + ret = tda1997x_core_init(sd); + if (ret) + goto err_free_mutex; + + /* control handlers */ + hdl = &state->hdl; + v4l2_ctrl_handler_init(hdl, 3); + ctrl = v4l2_ctrl_new_std_menu(hdl, &tda1997x_ctrl_ops, + V4L2_CID_DV_RX_IT_CONTENT_TYPE, + V4L2_DV_IT_CONTENT_TYPE_NO_ITC, 0, + V4L2_DV_IT_CONTENT_TYPE_NO_ITC); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + /* custom controls */ + state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); + state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl, + &tda1997x_ctrl_ops, + V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, + V4L2_DV_RGB_RANGE_AUTO); + state->sd.ctrl_handler = hdl; + if (hdl->error) { + ret = hdl->error; + goto err_free_handler; + } + v4l2_ctrl_handler_setup(hdl); + + /* initialize source pads */ + state->pads[TDA1997X_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, TDA1997X_NUM_PADS, + state->pads); + if (ret) { + v4l_err(client, "failed entity_init: %d", ret); + goto err_free_mutex; + } + + ret = v4l2_async_register_subdev(sd); + if (ret) + goto err_free_media; + + /* register audio DAI */ + if (pdata->audout_format) { + u64 formats; + + if (pdata->audout_width == 32) + formats = SNDRV_PCM_FMTBIT_S32_LE; + else + formats = SNDRV_PCM_FMTBIT_S16_LE; + tda1997x_audio_dai.capture.formats = formats; + ret = snd_soc_register_codec(&state->client->dev, + &tda1997x_codec_driver, + &tda1997x_audio_dai, 1); + if (ret) { + dev_err(&client->dev, "register audio codec failed\n"); + goto err_free_media; + } + dev_set_drvdata(&state->client->dev, state); + v4l_info(state->client, "registered audio codec\n"); + } + + /* request irq */ + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, tda1997x_isr_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + KBUILD_MODNAME, state); + if (ret) { + v4l_err(client, "irq%d reg failed: %d\n", client->irq, ret); + goto err_free_media; + } + + return 0; + +err_free_media: + media_entity_cleanup(&sd->entity); +err_free_handler: + v4l2_ctrl_handler_free(&state->hdl); +err_free_mutex: + cancel_delayed_work(&state->delayed_work_enable_hpd); + mutex_destroy(&state->page_lock); + mutex_destroy(&state->lock); +err_free_state: + kfree(state); + dev_err(&client->dev, "%s failed: %d\n", __func__, ret); + + return ret; +} + +static int tda1997x_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tda1997x_state *state = to_state(sd); + struct tda1997x_platform_data *pdata = &state->pdata; + + if (pdata->audout_format) { + snd_soc_unregister_codec(&client->dev); + mutex_destroy(&state->audio_lock); + } + + disable_irq(state->client->irq); + tda1997x_power_mode(state, 0); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&state->hdl); + regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies); + i2c_unregister_device(state->client_cec); + cancel_delayed_work(&state->delayed_work_enable_hpd); + mutex_destroy(&state->page_lock); + mutex_destroy(&state->lock); + + kfree(state); + + return 0; +} + +static struct i2c_driver tda1997x_i2c_driver = { + .driver = { + .name = "tda1997x", + .of_match_table = of_match_ptr(tda1997x_of_id), + }, + .probe = tda1997x_probe, + .remove = tda1997x_remove, + .id_table = tda1997x_i2c_id, +}; + +module_i2c_driver(tda1997x_i2c_driver); + +MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>"); +MODULE_DESCRIPTION("TDA1997X HDMI Receiver driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h new file mode 100644 index 000000000000..f55dfc423a86 --- /dev/null +++ b/drivers/media/i2c/tda1997x_regs.h @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Gateworks Corporation + */ + +/* Page 0x00 - General Control */ +#define REG_VERSION 0x0000 +#define REG_INPUT_SEL 0x0001 +#define REG_SVC_MODE 0x0002 +#define REG_HPD_MAN_CTRL 0x0003 +#define REG_RT_MAN_CTRL 0x0004 +#define REG_STANDBY_SOFT_RST 0x000A +#define REG_HDMI_SOFT_RST 0x000B +#define REG_HDMI_INFO_RST 0x000C +#define REG_INT_FLG_CLR_TOP 0x000E +#define REG_INT_FLG_CLR_SUS 0x000F +#define REG_INT_FLG_CLR_DDC 0x0010 +#define REG_INT_FLG_CLR_RATE 0x0011 +#define REG_INT_FLG_CLR_MODE 0x0012 +#define REG_INT_FLG_CLR_INFO 0x0013 +#define REG_INT_FLG_CLR_AUDIO 0x0014 +#define REG_INT_FLG_CLR_HDCP 0x0015 +#define REG_INT_FLG_CLR_AFE 0x0016 +#define REG_INT_MASK_TOP 0x0017 +#define REG_INT_MASK_SUS 0x0018 +#define REG_INT_MASK_DDC 0x0019 +#define REG_INT_MASK_RATE 0x001A +#define REG_INT_MASK_MODE 0x001B +#define REG_INT_MASK_INFO 0x001C +#define REG_INT_MASK_AUDIO 0x001D +#define REG_INT_MASK_HDCP 0x001E +#define REG_INT_MASK_AFE 0x001F +#define REG_DETECT_5V 0x0020 +#define REG_SUS_STATUS 0x0021 +#define REG_V_PER 0x0022 +#define REG_H_PER 0x0025 +#define REG_HS_WIDTH 0x0027 +#define REG_FMT_H_TOT 0x0029 +#define REG_FMT_H_ACT 0x002b +#define REG_FMT_H_FRONT 0x002d +#define REG_FMT_H_SYNC 0x002f +#define REG_FMT_H_BACK 0x0031 +#define REG_FMT_V_TOT 0x0033 +#define REG_FMT_V_ACT 0x0035 +#define REG_FMT_V_FRONT_F1 0x0037 +#define REG_FMT_V_FRONT_F2 0x0038 +#define REG_FMT_V_SYNC 0x0039 +#define REG_FMT_V_BACK_F1 0x003a +#define REG_FMT_V_BACK_F2 0x003b +#define REG_FMT_DE_ACT 0x003c +#define REG_RATE_CTRL 0x0040 +#define REG_CLK_MIN_RATE 0x0043 +#define REG_CLK_MAX_RATE 0x0046 +#define REG_CLK_A_STATUS 0x0049 +#define REG_CLK_A_RATE 0x004A +#define REG_DRIFT_CLK_A_REG 0x004D +#define REG_CLK_B_STATUS 0x004E +#define REG_CLK_B_RATE 0x004F +#define REG_DRIFT_CLK_B_REG 0x0052 +#define REG_HDCP_CTRL 0x0060 +#define REG_HDCP_KDS 0x0061 +#define REG_HDCP_BCAPS 0x0063 +#define REG_HDCP_KEY_CTRL 0x0064 +#define REG_INFO_CTRL 0x0076 +#define REG_INFO_EXCEED 0x0077 +#define REG_PIX_REPEAT 0x007B +#define REG_AUDIO_PATH 0x007C +#define REG_AUDCFG 0x007D +#define REG_AUDIO_OUT_ENABLE 0x007E +#define REG_AUDIO_OUT_HIZ 0x007F +#define REG_VDP_CTRL 0x0080 +#define REG_VDP_MATRIX 0x0081 +#define REG_VHREF_CTRL 0x00A0 +#define REG_PXCNT_PR 0x00A2 +#define REG_PXCNT_NPIX 0x00A4 +#define REG_LCNT_PR 0x00A6 +#define REG_LCNT_NLIN 0x00A8 +#define REG_HREF_S 0x00AA +#define REG_HREF_E 0x00AC +#define REG_HS_S 0x00AE +#define REG_HS_E 0x00B0 +#define REG_VREF_F1_S 0x00B2 +#define REG_VREF_F1_WIDTH 0x00B4 +#define REG_VREF_F2_S 0x00B5 +#define REG_VREF_F2_WIDTH 0x00B7 +#define REG_VS_F1_LINE_S 0x00B8 +#define REG_VS_F1_LINE_WIDTH 0x00BA +#define REG_VS_F2_LINE_S 0x00BB +#define REG_VS_F2_LINE_WIDTH 0x00BD +#define REG_VS_F1_PIX_S 0x00BE +#define REG_VS_F1_PIX_E 0x00C0 +#define REG_VS_F2_PIX_S 0x00C2 +#define REG_VS_F2_PIX_E 0x00C4 +#define REG_FREF_F1_S 0x00C6 +#define REG_FREF_F2_S 0x00C8 +#define REG_FDW_S 0x00ca +#define REG_FDW_E 0x00cc +#define REG_BLK_GY 0x00da +#define REG_BLK_BU 0x00dc +#define REG_BLK_RV 0x00de +#define REG_FILTERS_CTRL 0x00e0 +#define REG_DITHERING_CTRL 0x00E9 +#define REG_OF 0x00EA +#define REG_PCLK 0x00EB +#define REG_HS_HREF 0x00EC +#define REG_VS_VREF 0x00ED +#define REG_DE_FREF 0x00EE +#define REG_VP35_32_CTRL 0x00EF +#define REG_VP31_28_CTRL 0x00F0 +#define REG_VP27_24_CTRL 0x00F1 +#define REG_VP23_20_CTRL 0x00F2 +#define REG_VP19_16_CTRL 0x00F3 +#define REG_VP15_12_CTRL 0x00F4 +#define REG_VP11_08_CTRL 0x00F5 +#define REG_VP07_04_CTRL 0x00F6 +#define REG_VP03_00_CTRL 0x00F7 +#define REG_CURPAGE_00H 0xFF + +#define MASK_VPER 0x3fffff +#define MASK_VHREF 0x3fff +#define MASK_HPER 0x0fff +#define MASK_HSWIDTH 0x03ff + +/* HPD Detection */ +#define DETECT_UTIL BIT(7) /* utility of HDMI level */ +#define DETECT_HPD BIT(6) /* HPD of HDMI level */ +#define DETECT_5V_SEL BIT(2) /* 5V present on selected input */ +#define DETECT_5V_B BIT(1) /* 5V present on input B */ +#define DETECT_5V_A BIT(0) /* 5V present on input A */ + +/* Input Select */ +#define INPUT_SEL_RST_FMT BIT(7) /* 1=reset format measurement */ +#define INPUT_SEL_RST_VDP BIT(2) /* 1=reset video data path */ +#define INPUT_SEL_OUT_MODE BIT(1) /* 0=loop 1=bypass */ +#define INPUT_SEL_B BIT(0) /* 0=inputA 1=inputB */ + +/* Service Mode */ +#define SVC_MODE_CLK2_MASK 0xc0 +#define SVC_MODE_CLK2_SHIFT 6 +#define SVC_MODE_CLK2_XTL 0L +#define SVC_MODE_CLK2_XTLDIV2 1L +#define SVC_MODE_CLK2_HDMIX2 3L +#define SVC_MODE_CLK1_MASK 0x30 +#define SVC_MODE_CLK1_SHIFT 4 +#define SVC_MODE_CLK1_XTAL 0L +#define SVC_MODE_CLK1_XTLDIV2 1L +#define SVC_MODE_CLK1_HDMI 3L +#define SVC_MODE_RAMP BIT(3) /* 0=colorbar 1=ramp */ +#define SVC_MODE_PAL BIT(2) /* 0=NTSC(480i/p) 1=PAL(576i/p) */ +#define SVC_MODE_INT_PROG BIT(1) /* 0=interlaced 1=progressive */ +#define SVC_MODE_SM_ON BIT(0) /* Enable color bars and tone gen */ + +/* HDP Manual Control */ +#define HPD_MAN_CTRL_HPD_PULSE BIT(7) /* HPD Pulse low 110ms */ +#define HPD_MAN_CTRL_5VEN BIT(2) /* Output 5V */ +#define HPD_MAN_CTRL_HPD_B BIT(1) /* Assert HPD High for Input A */ +#define HPD_MAN_CTRL_HPD_A BIT(0) /* Assert HPD High for Input A */ + +/* RT_MAN_CTRL */ +#define RT_MAN_CTRL_RT_AUTO BIT(7) +#define RT_MAN_CTRL_RT BIT(6) +#define RT_MAN_CTRL_RT_B BIT(1) /* enable TMDS pull-up on Input B */ +#define RT_MAN_CTRL_RT_A BIT(0) /* enable TMDS pull-up on Input A */ + +/* VDP_CTRL */ +#define VDP_CTRL_COMPDEL_BP BIT(5) /* bypass compdel */ +#define VDP_CTRL_FORMATTER_BP BIT(4) /* bypass formatter */ +#define VDP_CTRL_PREFILTER_BP BIT(1) /* bypass prefilter */ +#define VDP_CTRL_MATRIX_BP BIT(0) /* bypass matrix conversion */ + +/* REG_VHREF_CTRL */ +#define VHREF_INT_DET BIT(7) /* interlace detect: 1=alt 0=frame */ +#define VHREF_VSYNC_MASK 0x60 +#define VHREF_VSYNC_SHIFT 6 +#define VHREF_VSYNC_AUTO 0L +#define VHREF_VSYNC_FDW 1L +#define VHREF_VSYNC_EVEN 2L +#define VHREF_VSYNC_ODD 3L +#define VHREF_STD_DET_MASK 0x18 +#define VHREF_STD_DET_SHIFT 3 +#define VHREF_STD_DET_PAL 0L +#define VHREF_STD_DET_NTSC 1L +#define VHREF_STD_DET_AUTO 2L +#define VHREF_STD_DET_OFF 3L +#define VHREF_VREF_SRC_STD BIT(2) /* 1=from standard 0=manual */ +#define VHREF_HREF_SRC_STD BIT(1) /* 1=from standard 0=manual */ +#define VHREF_HSYNC_SEL_HS BIT(0) /* 1=HS 0=VS */ + +/* AUDIO_OUT_ENABLE */ +#define AUDIO_OUT_ENABLE_ACLK BIT(5) +#define AUDIO_OUT_ENABLE_WS BIT(4) +#define AUDIO_OUT_ENABLE_AP3 BIT(3) +#define AUDIO_OUT_ENABLE_AP2 BIT(2) +#define AUDIO_OUT_ENABLE_AP1 BIT(1) +#define AUDIO_OUT_ENABLE_AP0 BIT(0) + +/* Prefilter Control */ +#define FILTERS_CTRL_BU_MASK 0x0c +#define FILTERS_CTRL_BU_SHIFT 2 +#define FILTERS_CTRL_RV_MASK 0x03 +#define FILTERS_CTRL_RV_SHIFT 0 +#define FILTERS_CTRL_OFF 0L /* off */ +#define FILTERS_CTRL_2TAP 1L /* 2 Taps */ +#define FILTERS_CTRL_7TAP 2L /* 7 Taps */ +#define FILTERS_CTRL_2_7TAP 3L /* 2/7 Taps */ + +/* PCLK Configuration */ +#define PCLK_DELAY_MASK 0x70 +#define PCLK_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define PCLK_INV_SHIFT 2 +#define PCLK_SEL_MASK 0x03 /* clock scaler */ +#define PCLK_SEL_SHIFT 0 +#define PCLK_SEL_X1 0L +#define PCLK_SEL_X2 1L +#define PCLK_SEL_DIV2 2L +#define PCLK_SEL_DIV4 3L + +/* Pixel Repeater */ +#define PIX_REPEAT_MASK_UP_SEL 0x30 +#define PIX_REPEAT_MASK_REP 0x0f +#define PIX_REPEAT_SHIFT 4 +#define PIX_REPEAT_CHROMA 1 + +/* Page 0x01 - HDMI info and packets */ +#define REG_HDMI_FLAGS 0x0100 +#define REG_DEEP_COLOR_MODE 0x0101 +#define REG_AUDIO_FLAGS 0x0108 +#define REG_AUDIO_FREQ 0x0109 +#define REG_ACP_PACKET_TYPE 0x0141 +#define REG_ISRC1_PACKET_TYPE 0x0161 +#define REG_ISRC2_PACKET_TYPE 0x0181 +#define REG_GBD_PACKET_TYPE 0x01a1 + +/* HDMI_FLAGS */ +#define HDMI_FLAGS_AUDIO BIT(7) /* Audio packet in last videoframe */ +#define HDMI_FLAGS_HDMI BIT(6) /* HDMI detected */ +#define HDMI_FLAGS_EESS BIT(5) /* EESS detected */ +#define HDMI_FLAGS_HDCP BIT(4) /* HDCP detected */ +#define HDMI_FLAGS_AVMUTE BIT(3) /* AVMUTE */ +#define HDMI_FLAGS_AUD_LAYOUT BIT(2) /* Layout status Audio sample packet */ +#define HDMI_FLAGS_AUD_FIFO_OF BIT(1) /* FIFO read/write pointers crossed */ +#define HDMI_FLAGS_AUD_FIFO_LOW BIT(0) /* FIFO read ptr within 2 of write */ + +/* Page 0x12 - HDMI Extra control and debug */ +#define REG_CLK_CFG 0x1200 +#define REG_CLK_OUT_CFG 0x1201 +#define REG_CFG1 0x1202 +#define REG_CFG2 0x1203 +#define REG_WDL_CFG 0x1210 +#define REG_DELOCK_DELAY 0x1212 +#define REG_PON_OVR_EN 0x12A0 +#define REG_PON_CBIAS 0x12A1 +#define REG_PON_RESCAL 0x12A2 +#define REG_PON_RES 0x12A3 +#define REG_PON_CLK 0x12A4 +#define REG_PON_PLL 0x12A5 +#define REG_PON_EQ 0x12A6 +#define REG_PON_DES 0x12A7 +#define REG_PON_OUT 0x12A8 +#define REG_PON_MUX 0x12A9 +#define REG_MODE_REC_CFG1 0x12F8 +#define REG_MODE_REC_CFG2 0x12F9 +#define REG_MODE_REC_STS 0x12FA +#define REG_AUDIO_LAYOUT 0x12D0 + +#define PON_EN 1 +#define PON_DIS 0 + +/* CLK CFG */ +#define CLK_CFG_INV_OUT_CLK BIT(7) +#define CLK_CFG_INV_BUS_CLK BIT(6) +#define CLK_CFG_SEL_ACLK_EN BIT(1) +#define CLK_CFG_SEL_ACLK BIT(0) +#define CLK_CFG_DIS 0 + +/* Page 0x13 - HDMI Extra control and debug */ +#define REG_DEEP_COLOR_CTRL 0x1300 +#define REG_CGU_DBG_SEL 0x1305 +#define REG_HDCP_DDC_ADDR 0x1310 +#define REG_HDCP_KIDX 0x1316 +#define REG_DEEP_PLL7_BYP 0x1347 +#define REG_HDCP_DE_CTRL 0x1370 +#define REG_HDCP_EP_FILT_CTRL 0x1371 +#define REG_HDMI_CTRL 0x1377 +#define REG_HMTP_CTRL 0x137a +#define REG_TIMER_D 0x13CF +#define REG_SUS_SET_RGB0 0x13E1 +#define REG_SUS_SET_RGB1 0x13E2 +#define REG_SUS_SET_RGB2 0x13E3 +#define REG_SUS_SET_RGB3 0x13E4 +#define REG_SUS_SET_RGB4 0x13E5 +#define REG_MAN_SUS_HDMI_SEL 0x13E8 +#define REG_MAN_HDMI_SET 0x13E9 +#define REG_SUS_CLOCK_GOOD 0x13EF + +/* HDCP DE Control */ +#define HDCP_DE_MODE_MASK 0xc0 /* DE Measurement mode */ +#define HDCP_DE_MODE_SHIFT 6 +#define HDCP_DE_REGEN_EN BIT(5) /* enable regen mode */ +#define HDCP_DE_FILTER_MASK 0x18 /* DE filter sensitivity */ +#define HDCP_DE_FILTER_SHIFT 3 +#define HDCP_DE_COMP_MASK 0x07 /* DE Composition mode */ +#define HDCP_DE_COMP_MIXED 6L +#define HDCP_DE_COMP_OR 5L +#define HDCP_DE_COMP_AND 4L +#define HDCP_DE_COMP_CH3 3L +#define HDCP_DE_COMP_CH2 2L +#define HDCP_DE_COMP_CH1 1L +#define HDCP_DE_COMP_CH0 0L + +/* HDCP EP Filter Control */ +#define HDCP_EP_FIL_CTL_MASK 0x30 +#define HDCP_EP_FIL_CTL_SHIFT 4 +#define HDCP_EP_FIL_VS_MASK 0x0c +#define HDCP_EP_FIL_VS_SHIFT 2 +#define HDCP_EP_FIL_HS_MASK 0x03 +#define HDCP_EP_FIL_HS_SHIFT 0 + +/* HDMI_CTRL */ +#define HDMI_CTRL_MUTE_MASK 0x0c +#define HDMI_CTRL_MUTE_SHIFT 2 +#define HDMI_CTRL_MUTE_AUTO 0L +#define HDMI_CTRL_MUTE_OFF 1L +#define HDMI_CTRL_MUTE_ON 2L +#define HDMI_CTRL_HDCP_MASK 0x03 +#define HDMI_CTRL_HDCP_SHIFT 0 +#define HDMI_CTRL_HDCP_EESS 2L +#define HDMI_CTRL_HDCP_OESS 1L +#define HDMI_CTRL_HDCP_AUTO 0L + +/* CGU_DBG_SEL bits */ +#define CGU_DBG_CLK_SEL_MASK 0x18 +#define CGU_DBG_CLK_SEL_SHIFT 3 +#define CGU_DBG_XO_FRO_SEL BIT(2) +#define CGU_DBG_VDP_CLK_SEL BIT(1) +#define CGU_DBG_PIX_CLK_SEL BIT(0) + +/* REG_MAN_SUS_HDMI_SEL / REG_MAN_HDMI_SET bits */ +#define MAN_DIS_OUT_BUF BIT(7) +#define MAN_DIS_ANA_PATH BIT(6) +#define MAN_DIS_HDCP BIT(5) +#define MAN_DIS_TMDS_ENC BIT(4) +#define MAN_DIS_TMDS_FLOW BIT(3) +#define MAN_RST_HDCP BIT(2) +#define MAN_RST_TMDS_ENC BIT(1) +#define MAN_RST_TMDS_FLOW BIT(0) + +/* Page 0x14 - Audio Extra control and debug */ +#define REG_FIFO_LATENCY_VAL 0x1403 +#define REG_AUDIO_CLOCK 0x1411 +#define REG_TEST_NCTS_CTRL 0x1415 +#define REG_TEST_AUDIO_FREQ 0x1426 +#define REG_TEST_MODE 0x1437 + +/* Audio Clock Configuration */ +#define AUDIO_CLOCK_PLL_PD BIT(7) /* powerdown PLL */ +#define AUDIO_CLOCK_SEL_MASK 0x7f +#define AUDIO_CLOCK_SEL_16FS 0L /* 16*fs */ +#define AUDIO_CLOCK_SEL_32FS 1L /* 32*fs */ +#define AUDIO_CLOCK_SEL_64FS 2L /* 64*fs */ +#define AUDIO_CLOCK_SEL_128FS 3L /* 128*fs */ +#define AUDIO_CLOCK_SEL_256FS 4L /* 256*fs */ +#define AUDIO_CLOCK_SEL_512FS 5L /* 512*fs */ + +/* Page 0x20: EDID and Hotplug Detect */ +#define REG_EDID_IN_BYTE0 0x2000 /* EDID base */ +#define REG_EDID_IN_VERSION 0x2080 +#define REG_EDID_ENABLE 0x2081 +#define REG_HPD_POWER 0x2084 +#define REG_HPD_AUTO_CTRL 0x2085 +#define REG_HPD_DURATION 0x2086 +#define REG_RX_HPD_HEAC 0x2087 + +/* EDID_ENABLE */ +#define EDID_ENABLE_NACK_OFF BIT(7) +#define EDID_ENABLE_EDID_ONLY BIT(6) +#define EDID_ENABLE_B_EN BIT(1) +#define EDID_ENABLE_A_EN BIT(0) + +/* HPD Power */ +#define HPD_POWER_BP_MASK 0x0c +#define HPD_POWER_BP_SHIFT 2 +#define HPD_POWER_BP_LOW 0L +#define HPD_POWER_BP_HIGH 1L +#define HPD_POWER_EDID_ONLY BIT(1) + +/* HPD Auto control */ +#define HPD_AUTO_READ_EDID BIT(7) +#define HPD_AUTO_HPD_F3TECH BIT(5) +#define HPD_AUTO_HP_OTHER BIT(4) +#define HPD_AUTO_HPD_UNSEL BIT(3) +#define HPD_AUTO_HPD_ALL_CH BIT(2) +#define HPD_AUTO_HPD_PRV_CH BIT(1) +#define HPD_AUTO_HPD_NEW_CH BIT(0) + +/* Page 0x21 - EDID content */ +#define REG_EDID_IN_BYTE128 0x2100 /* CEA Extension block */ +#define REG_EDID_IN_SPA_SUB 0x2180 +#define REG_EDID_IN_SPA_AB_A 0x2181 +#define REG_EDID_IN_SPA_CD_A 0x2182 +#define REG_EDID_IN_CKSUM_A 0x2183 +#define REG_EDID_IN_SPA_AB_B 0x2184 +#define REG_EDID_IN_SPA_CD_B 0x2185 +#define REG_EDID_IN_CKSUM_B 0x2186 + +/* Page 0x30 - NV Configuration */ +#define REG_RT_AUTO_CTRL 0x3000 +#define REG_EQ_MAN_CTRL0 0x3001 +#define REG_EQ_MAN_CTRL1 0x3002 +#define REG_OUTPUT_CFG 0x3003 +#define REG_MUTE_CTRL 0x3004 +#define REG_SLAVE_ADDR 0x3005 +#define REG_CMTP_REG6 0x3006 +#define REG_CMTP_REG7 0x3007 +#define REG_CMTP_REG8 0x3008 +#define REG_CMTP_REG9 0x3009 +#define REG_CMTP_REGA 0x300A +#define REG_CMTP_REGB 0x300B +#define REG_CMTP_REGC 0x300C +#define REG_CMTP_REGD 0x300D +#define REG_CMTP_REGE 0x300E +#define REG_CMTP_REGF 0x300F +#define REG_CMTP_REG10 0x3010 +#define REG_CMTP_REG11 0x3011 + +/* Page 0x80 - CEC */ +#define REG_PWR_CONTROL 0x80F4 +#define REG_OSC_DIVIDER 0x80F5 +#define REG_EN_OSC_PERIOD_LSB 0x80F8 +#define REG_CONTROL 0x80FF + +/* global interrupt flags (INT_FLG_CRL_TOP) */ +#define INTERRUPT_AFE BIT(7) /* AFE module */ +#define INTERRUPT_HDCP BIT(6) /* HDCP module */ +#define INTERRUPT_AUDIO BIT(5) /* Audio module */ +#define INTERRUPT_INFO BIT(4) /* Infoframe module */ +#define INTERRUPT_MODE BIT(3) /* HDMI mode module */ +#define INTERRUPT_RATE BIT(2) /* rate module */ +#define INTERRUPT_DDC BIT(1) /* DDC module */ +#define INTERRUPT_SUS BIT(0) /* SUS module */ + +/* INT_FLG_CLR_HDCP bits */ +#define MASK_HDCP_MTP BIT(7) /* HDCP MTP busy */ +#define MASK_HDCP_DLMTP BIT(4) /* HDCP end download MTP to SRAM */ +#define MASK_HDCP_DLRAM BIT(3) /* HDCP end download keys from SRAM */ +#define MASK_HDCP_ENC BIT(2) /* HDCP ENC */ +#define MASK_STATE_C5 BIT(1) /* HDCP State C5 reached */ +#define MASK_AKSV BIT(0) /* AKSV received (start of auth) */ + +/* INT_FLG_CLR_RATE bits */ +#define MASK_RATE_B_DRIFT BIT(7) /* Rate measurement drifted */ +#define MASK_RATE_B_ST BIT(6) /* Rate measurement stability change */ +#define MASK_RATE_B_ACT BIT(5) /* Rate measurement activity change */ +#define MASK_RATE_B_PST BIT(4) /* Rate measreument presence change */ +#define MASK_RATE_A_DRIFT BIT(3) /* Rate measurement drifted */ +#define MASK_RATE_A_ST BIT(2) /* Rate measurement stability change */ +#define MASK_RATE_A_ACT BIT(1) /* Rate measurement presence change */ +#define MASK_RATE_A_PST BIT(0) /* Rate measreument presence change */ + +/* INT_FLG_CLR_SUS (Start Up Sequencer) bits */ +#define MASK_MPT BIT(7) /* Config MTP end of process */ +#define MASK_FMT BIT(5) /* Video format changed */ +#define MASK_RT_PULSE BIT(4) /* End of termination resistance pulse */ +#define MASK_SUS_END BIT(3) /* SUS last state reached */ +#define MASK_SUS_ACT BIT(2) /* Activity of selected input changed */ +#define MASK_SUS_CH BIT(1) /* Selected input changed */ +#define MASK_SUS_ST BIT(0) /* SUS state changed */ + +/* INT_FLG_CLR_DDC bits */ +#define MASK_EDID_MTP BIT(7) /* EDID MTP end of process */ +#define MASK_DDC_ERR BIT(6) /* master DDC error */ +#define MASK_DDC_CMD_DONE BIT(5) /* master DDC cmd send correct */ +#define MASK_READ_DONE BIT(4) /* End of down EDID read */ +#define MASK_RX_DDC_SW BIT(3) /* Output DDC switching finished */ +#define MASK_HDCP_DDC_SW BIT(2) /* HDCP DDC switching finished */ +#define MASK_HDP_PULSE_END BIT(1) /* End of Hot Plug Detect pulse */ +#define MASK_DET_5V BIT(0) /* Detection of +5V */ + +/* INT_FLG_CLR_MODE bits */ +#define MASK_HDMI_FLG BIT(7) /* HDMI mode/avmute/encrypt/FIFO fail */ +#define MASK_GAMUT BIT(6) /* Gamut packet */ +#define MASK_ISRC2 BIT(5) /* ISRC2 packet */ +#define MASK_ISRC1 BIT(4) /* ISRC1 packet */ +#define MASK_ACP BIT(3) /* Audio Content Protection packet */ +#define MASK_DC_NO_GCP BIT(2) /* GCP not received in 5 frames */ +#define MASK_DC_PHASE BIT(1) /* deepcolor pixel phase needs update */ +#define MASK_DC_MODE BIT(0) /* deepcolor color depth changed */ + +/* INT_FLG_CLR_INFO bits (Infoframe Change Status) */ +#define MASK_MPS_IF BIT(6) /* MPEG Source Product */ +#define MASK_AUD_IF BIT(5) /* Audio */ +#define MASK_SPD_IF BIT(4) /* Source Product Descriptor */ +#define MASK_AVI_IF BIT(3) /* Auxiliary Video IF */ +#define MASK_VS_IF_OTHER_BK2 BIT(2) /* Vendor Specific (bank2) */ +#define MASK_VS_IF_OTHER_BK1 BIT(1) /* Vendor Specific (bank1) */ +#define MASK_VS_IF_HDMI BIT(0) /* Vendor Specific (w/ HDMI LLC code) */ + +/* INT_FLG_CLR_AUDIO bits */ +#define MASK_AUDIO_FREQ_FLG BIT(5) /* Audio freq change */ +#define MASK_AUDIO_FLG BIT(4) /* DST, OBA, HBR, ASP change */ +#define MASK_MUTE_FLG BIT(3) /* Audio Mute */ +#define MASK_CH_STATE BIT(2) /* Channel status */ +#define MASK_UNMUTE_FIFO BIT(1) /* Audio Unmute */ +#define MASK_ERROR_FIFO_PT BIT(0) /* Audio FIFO pointer error */ + +/* INT_FLG_CLR_AFE bits */ +#define MASK_AFE_WDL_UNLOCKED BIT(7) /* Wordlocker was unlocked */ +#define MASK_AFE_GAIN_DONE BIT(6) /* Gain calibration done */ +#define MASK_AFE_OFFSET_DONE BIT(5) /* Offset calibration done */ +#define MASK_AFE_ACTIVITY_DET BIT(4) /* Activity detected on data */ +#define MASK_AFE_PLL_LOCK BIT(3) /* TMDS PLL is locked */ +#define MASK_AFE_TRMCAL_DONE BIT(2) /* Termination calibration done */ +#define MASK_AFE_ASU_STATE BIT(1) /* ASU state is reached */ +#define MASK_AFE_ASU_READY BIT(0) /* AFE calibration done: TMDS ready */ + +/* Audio Output */ +#define AUDCFG_CLK_INVERT BIT(7) /* invert A_CLK polarity */ +#define AUDCFG_TEST_TONE BIT(6) /* enable test tone generator */ +#define AUDCFG_BUS_SHIFT 5 +#define AUDCFG_BUS_I2S 0L +#define AUDCFG_BUS_SPDIF 1L +#define AUDCFG_I2SW_SHIFT 4 +#define AUDCFG_I2SW_16 0L +#define AUDCFG_I2SW_32 1L +#define AUDCFG_AUTO_MUTE_EN BIT(3) /* Enable Automatic audio mute */ +#define AUDCFG_HBR_SHIFT 2 +#define AUDCFG_HBR_STRAIGHT 0L /* straight via AP0 */ +#define AUDCFG_HBR_DEMUX 1L /* demuxed via AP0:AP3 */ +#define AUDCFG_TYPE_MASK 0x03 +#define AUDCFG_TYPE_SHIFT 0 +#define AUDCFG_TYPE_DST 3L /* Direct Stream Transfer (DST) */ +#define AUDCFG_TYPE_OBA 2L /* One Bit Audio (OBA) */ +#define AUDCFG_TYPE_HBR 1L /* High Bit Rate (HBR) */ +#define AUDCFG_TYPE_PCM 0L /* Audio samples */ + +/* Video Formatter */ +#define OF_VP_ENABLE BIT(7) /* VP[35:0]/HS/VS/DE/CLK */ +#define OF_BLK BIT(4) /* blanking codes */ +#define OF_TRC BIT(3) /* timing codes (SAV/EAV) */ +#define OF_FMT_MASK 0x3 +#define OF_FMT_444 0L /* RGB444/YUV444 */ +#define OF_FMT_422_SMPT 1L /* YUV422 semi-planar */ +#define OF_FMT_422_CCIR 2L /* YUV422 CCIR656 */ + +/* HS/HREF output control */ +#define HS_HREF_DELAY_MASK 0xf0 +#define HS_HREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define HS_HREF_PXQ_SHIFT 3 /* Timing codes from HREF */ +#define HS_HREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define HS_HREF_SEL_MASK 0x03 +#define HS_HREF_SEL_SHIFT 0 +#define HS_HREF_SEL_HS_VHREF 0L /* HS from VHREF */ +#define HS_HREF_SEL_HREF_VHREF 1L /* HREF from VHREF */ +#define HS_HREF_SEL_HREF_HDMI 2L /* HREF from HDMI */ +#define HS_HREF_SEL_NONE 3L /* not generated */ + +/* VS output control */ +#define VS_VREF_DELAY_MASK 0xf0 +#define VS_VREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define VS_VREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define VS_VREF_SEL_MASK 0x03 +#define VS_VREF_SEL_SHIFT 0 +#define VS_VREF_SEL_VS_VHREF 0L /* VS from VHREF */ +#define VS_VREF_SEL_VREF_VHREF 1L /* VREF from VHREF */ +#define VS_VREF_SEL_VREF_HDMI 2L /* VREF from HDMI */ +#define VS_VREF_SEL_NONE 3L /* not generated */ + +/* DE/FREF output control */ +#define DE_FREF_DELAY_MASK 0xf0 +#define DE_FREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define DE_FREF_DE_PXQ_SHIFT 3 /* Timing codes from DE */ +#define DE_FREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define DE_FREF_SEL_MASK 0x03 +#define DE_FREF_SEL_SHIFT 0 +#define DE_FREF_SEL_DE_VHREF 0L /* DE from VHREF (HREF and not(VREF) */ +#define DE_FREF_SEL_FREF_VHREF 1L /* FREF from VHREF */ +#define DE_FREF_SEL_FREF_HDMI 2L /* FREF from HDMI */ +#define DE_FREF_SEL_NONE 3L /* not generated */ + +/* HDMI_SOFT_RST bits */ +#define RESET_DC BIT(7) /* Reset deep color module */ +#define RESET_HDCP BIT(6) /* Reset HDCP module */ +#define RESET_KSV BIT(5) /* Reset KSV-FIFO */ +#define RESET_SCFG BIT(4) /* Reset HDCP and repeater function */ +#define RESET_HCFG BIT(3) /* Reset HDCP DDC part */ +#define RESET_PA BIT(2) /* Reset polarity adjust */ +#define RESET_EP BIT(1) /* Reset Error protection */ +#define RESET_TMDS BIT(0) /* Reset TMDS (calib, encoding, flow) */ + +/* HDMI_INFO_RST bits */ +#define NACK_HDCP BIT(7) /* No ACK on HDCP request */ +#define RESET_FIFO BIT(4) /* Reset Audio FIFO control */ +#define RESET_GAMUT BIT(3) /* Clear Gamut packet */ +#define RESET_AI BIT(2) /* Clear ACP and ISRC packets */ +#define RESET_IF BIT(1) /* Clear all Audio infoframe packets */ +#define RESET_AUDIO BIT(0) /* Reset Audio FIFO control */ + +/* HDCP_BCAPS bits */ +#define HDCP_HDMI BIT(7) /* HDCP suports HDMI (vs DVI only) */ +#define HDCP_REPEATER BIT(6) /* HDCP supports repeater function */ +#define HDCP_READY BIT(5) /* set by repeater function */ +#define HDCP_FAST BIT(4) /* Up to 400kHz */ +#define HDCP_11 BIT(1) /* HDCP 1.1 supported */ +#define HDCP_FAST_REAUTH BIT(0) /* fast reauthentication supported */ + +/* Audio output formatter */ +#define AUDIO_LAYOUT_SP_FLAG BIT(2) /* sp flag used by FIFO */ +#define AUDIO_LAYOUT_MANUAL BIT(1) /* manual layout (vs per pkt) */ +#define AUDIO_LAYOUT_LAYOUT1 BIT(0) /* Layout1: AP0-3 vs Layout0:AP0 */ + +/* masks for interrupt status registers */ +#define MASK_SUS_STATUS 0x1F +#define LAST_STATE_REACHED 0x1B +#define MASK_CLK_STABLE 0x04 +#define MASK_CLK_ACTIVE 0x02 +#define MASK_SUS_STATE 0x10 +#define MASK_SR_FIFO_FIFO_CTRL 0x30 +#define MASK_AUDIO_FLAG 0x10 + +/* Rate measurement */ +#define RATE_REFTIM_ENABLE 0x01 +#define CLK_MIN_RATE 0x0057e4 +#define CLK_MAX_RATE 0x0395f8 +#define WDL_CFG_VAL 0x82 +#define DC_FILTER_VAL 0x31 + +/* Infoframe */ +#define VS_HDMI_IF_UPDATE 0x0200 +#define VS_HDMI_IF 0x0201 +#define VS_BK1_IF_UPDATE 0x0220 +#define VS_BK1_IF 0x0221 +#define VS_BK2_IF_UPDATE 0x0240 +#define VS_BK2_IF 0x0241 +#define AVI_IF_UPDATE 0x0260 +#define AVI_IF 0x0261 +#define SPD_IF_UPDATE 0x0280 +#define SPD_IF 0x0281 +#define AUD_IF_UPDATE 0x02a0 +#define AUD_IF 0x02a1 +#define MPS_IF_UPDATE 0x02c0 +#define MPS_IF 0x02c1 diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index f31e659588ac..0dd6ff3e6201 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -68,11 +68,15 @@ static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val) static int tda9840_status(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); + int rc; u8 byte; - if (1 != i2c_master_recv(client, &byte, 1)) { + rc = i2c_master_recv(client, &byte, 1); + if (rc != 1) { v4l2_dbg(1, debug, sd, "i2c_master_recv() failed\n"); + if (rc < 0) + return rc; return -EIO; } diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 772164b848ef..5919214a56bf 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -156,14 +156,18 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); unsigned char buffer[2]; + int rc; if (subaddr < 0) { v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(c, buffer, 1)) { + rc = i2c_master_send(c, buffer, 1); + if (rc != 1) { v4l2_warn(sd, "I/O error (write 0x%x)\n", val); - return -1; + if (rc < 0) + return rc; + return -EIO; } } else { if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { @@ -178,10 +182,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(c, buffer, 2)) { + rc = i2c_master_send(c, buffer, 2); + if (rc != 2) { v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n", subaddr, val); - return -1; + if (rc < 0) + return rc; + return -EIO; } } return 0; @@ -214,10 +221,14 @@ static int chip_read(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); unsigned char buffer; + int rc; - if (1 != i2c_master_recv(c, &buffer, 1)) { + rc = i2c_master_recv(c, &buffer, 1); + if (rc != 1) { v4l2_warn(sd, "I/O error (read)\n"); - return -1; + if (rc < 0) + return rc; + return -EIO; } v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer); return buffer; @@ -227,6 +238,7 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) { struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); + int rc; unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { @@ -245,9 +257,12 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) write[0] = subaddr; - if (2 != i2c_transfer(c->adapter, msgs, 2)) { + rc = i2c_transfer(c->adapter, msgs, 2); + if (rc != 2) { v4l2_warn(sd, "I/O error (read2)\n"); - return -1; + if (rc < 0) + return rc; + return -EIO; } v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n", subaddr, read[0]); @@ -258,7 +273,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) { struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); - int i; + int i, rc; if (0 == cmd->count) return 0; @@ -284,9 +299,12 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk(KERN_CONT "\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) { + rc = i2c_master_send(c, cmd->bytes, cmd->count); + if (rc != cmd->count) { v4l2_warn(sd, "I/O error (%s)\n", name); - return -1; + if (rc < 0) + return rc; + return -EIO; } return 0; } @@ -400,8 +418,12 @@ static int tda9840_getrxsubchans(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int val, mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA9840_DS_DUAL) mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; if (val & TDA9840_ST_STEREO) @@ -445,7 +467,12 @@ static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode) static int tda9840_checkit(struct CHIPSTATE *chip) { int rc; + rc = chip_read(chip); + if (rc < 0) + return 0; + + /* lower 5 bits should be 0 */ return ((rc & 0x1f) == 0) ? 1 : 0; } @@ -563,6 +590,9 @@ static int tda985x_getrxsubchans(struct CHIPSTATE *chip) /* Allows forced mono */ mode = V4L2_TUNER_SUB_MONO; val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA985x_STP) mode = V4L2_TUNER_SUB_STEREO; if (val & TDA985x_SAPP) @@ -720,8 +750,12 @@ static int tda9873_getrxsubchans(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int val,mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA9873_STEREO) mode = V4L2_TUNER_SUB_STEREO; if (val & TDA9873_DUAL) @@ -780,7 +814,8 @@ static int tda9873_checkit(struct CHIPSTATE *chip) { int rc; - if (-1 == (rc = chip_read2(chip,254))) + rc = chip_read2(chip, 254); + if (rc < 0) return 0; return (rc & ~0x1f) == 0x80; } @@ -926,11 +961,14 @@ static int tda9874a_getrxsubchans(struct CHIPSTATE *chip) mode = V4L2_TUNER_SUB_MONO; - if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) + dsr = chip_read2(chip, TDA9874A_DSR); + if (dsr < 0) return mode; - if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR))) + nsr = chip_read2(chip, TDA9874A_NSR); + if (nsr < 0) return mode; - if(-1 == (necr = chip_read2(chip,TDA9874A_NECR))) + necr = chip_read2(chip, TDA9874A_NECR); + if (necr < 0) return mode; /* need to store dsr/nsr somewhere */ @@ -1059,9 +1097,11 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int dic,sic; /* device id. and software id. codes */ - if(-1 == (dic = chip_read2(chip,TDA9874A_DIC))) + dic = chip_read2(chip, TDA9874A_DIC); + if (dic < 0) return 0; - if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) + sic = chip_read2(chip, TDA9874A_SIC); + if (sic < 0) return 0; v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); @@ -1201,7 +1241,11 @@ static int tda9875_checkit(struct CHIPSTATE *chip) int dic, rev; dic = chip_read2(chip, 254); + if (dic < 0) + return 0; rev = chip_read2(chip, 255); + if (rev < 0) + return 0; if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */ v4l2_info(sd, "found tda9875%s rev. %d.\n", @@ -1377,8 +1421,12 @@ static int ta8874z_getrxsubchans(struct CHIPSTATE *chip) { int val, mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TA8874Z_B1){ mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; }else if (!(val & TA8874Z_B0)){ @@ -1431,7 +1479,11 @@ static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode) static int ta8874z_checkit(struct CHIPSTATE *chip) { int rc; + rc = chip_read(chip); + if (rc < 0) + return rc; + return ((rc & 0x1f) == 0x1f) ? 1 : 0; } diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 8b0aa9297bde..6a9890531d01 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -747,60 +747,47 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) } /** - * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm + * tvp514x_g_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * @ival: pointer to a v4l2_subdev_frame_interval structure * * Returns the decoder's video CAPTURE parameters. */ static int -tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +tvp514x_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_captureparm *cparm; enum tvp514x_std current_std; - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; /* get the current standard */ current_std = decoder->current_std; - cparm = &a->parm.capture; - cparm->capability = V4L2_CAP_TIMEPERFRAME; - cparm->timeperframe = + ival->interval = decoder->std_list[current_std].standard.frameperiod; return 0; } /** - * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm + * tvp514x_s_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * @ival: pointer to a v4l2_subdev_frame_interval structure * * Configures the decoder to use the input parameters, if possible. If * not possible, returns the appropriate error code. */ static int -tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +tvp514x_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct tvp514x_decoder *decoder = to_decoder(sd); struct v4l2_fract *timeperframe; enum tvp514x_std current_std; - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - timeperframe = &a->parm.capture.timeperframe; + timeperframe = &ival->interval; /* get the current standard */ current_std = decoder->current_std; @@ -961,8 +948,8 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, - .g_parm = tvp514x_g_parm, - .s_parm = tvp514x_s_parm, + .g_frame_interval = tvp514x_g_frame_interval, + .s_frame_interval = tvp514x_s_frame_interval, .s_stream = tvp514x_s_stream, }; diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c new file mode 100644 index 000000000000..a54548cc4285 --- /dev/null +++ b/drivers/media/i2c/tw9910.c @@ -0,0 +1,1027 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * tw9910 Video Driver + * + * Copyright (C) 2017 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ov772x driver, + * + * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> + +#include <media/i2c/tw9910.h> +#include <media/v4l2-subdev.h> + +#define GET_ID(val) ((val & 0xF8) >> 3) +#define GET_REV(val) (val & 0x07) + +/* + * register offset + */ +#define ID 0x00 /* Product ID Code Register */ +#define STATUS1 0x01 /* Chip Status Register I */ +#define INFORM 0x02 /* Input Format */ +#define OPFORM 0x03 /* Output Format Control Register */ +#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */ +#define OUTCTR1 0x05 /* Output Control I */ +#define ACNTL1 0x06 /* Analog Control Register 1 */ +#define CROP_HI 0x07 /* Cropping Register, High */ +#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */ +#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */ +#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */ +#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */ +#define CNTRL1 0x0C /* Control Register I */ +#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */ +#define SCALE_HI 0x0E /* Scaling Register, High */ +#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */ +#define BRIGHT 0x10 /* BRIGHTNESS Control Register */ +#define CONTRAST 0x11 /* CONTRAST Control Register */ +#define SHARPNESS 0x12 /* SHARPNESS Control Register I */ +#define SAT_U 0x13 /* Chroma (U) Gain Register */ +#define SAT_V 0x14 /* Chroma (V) Gain Register */ +#define HUE 0x15 /* Hue Control Register */ +#define CORING1 0x17 +#define CORING2 0x18 /* Coring and IF compensation */ +#define VBICNTL 0x19 /* VBI Control Register */ +#define ACNTL2 0x1A /* Analog Control 2 */ +#define OUTCTR2 0x1B /* Output Control 2 */ +#define SDT 0x1C /* Standard Selection */ +#define SDTR 0x1D /* Standard Recognition */ +#define TEST 0x1F /* Test Control Register */ +#define CLMPG 0x20 /* Clamping Gain */ +#define IAGC 0x21 /* Individual AGC Gain */ +#define AGCGAIN 0x22 /* AGC Gain */ +#define PEAKWT 0x23 /* White Peak Threshold */ +#define CLMPL 0x24 /* Clamp level */ +#define SYNCT 0x25 /* Sync Amplitude */ +#define MISSCNT 0x26 /* Sync Miss Count Register */ +#define PCLAMP 0x27 /* Clamp Position Register */ +#define VCNTL1 0x28 /* Vertical Control I */ +#define VCNTL2 0x29 /* Vertical Control II */ +#define CKILL 0x2A /* Color Killer Level Control */ +#define COMB 0x2B /* Comb Filter Control */ +#define LDLY 0x2C /* Luma Delay and H Filter Control */ +#define MISC1 0x2D /* Miscellaneous Control I */ +#define LOOP 0x2E /* LOOP Control Register */ +#define MISC2 0x2F /* Miscellaneous Control II */ +#define MVSN 0x30 /* Macrovision Detection */ +#define STATUS2 0x31 /* Chip STATUS II */ +#define HFREF 0x32 /* H monitor */ +#define CLMD 0x33 /* CLAMP MODE */ +#define IDCNTL 0x34 /* ID Detection Control */ +#define CLCNTL1 0x35 /* Clamp Control I */ +#define ANAPLLCTL 0x4C +#define VBIMIN 0x4D +#define HSLOWCTL 0x4E +#define WSS3 0x4F +#define FILLDATA 0x50 +#define SDID 0x51 +#define DID 0x52 +#define WSS1 0x53 +#define WSS2 0x54 +#define VVBI 0x55 +#define LCTL6 0x56 +#define LCTL7 0x57 +#define LCTL8 0x58 +#define LCTL9 0x59 +#define LCTL10 0x5A +#define LCTL11 0x5B +#define LCTL12 0x5C +#define LCTL13 0x5D +#define LCTL14 0x5E +#define LCTL15 0x5F +#define LCTL16 0x60 +#define LCTL17 0x61 +#define LCTL18 0x62 +#define LCTL19 0x63 +#define LCTL20 0x64 +#define LCTL21 0x65 +#define LCTL22 0x66 +#define LCTL23 0x67 +#define LCTL24 0x68 +#define LCTL25 0x69 +#define LCTL26 0x6A +#define HSBEGIN 0x6B +#define HSEND 0x6C +#define OVSDLY 0x6D +#define OVSEND 0x6E +#define VBIDELAY 0x6F + +/* + * register detail + */ + +/* INFORM */ +#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */ +#define FC27_FF 0x00 /* 0 : Square pixel mode. */ + /* Must use 24.54MHz for 60Hz field rate */ + /* source or 29.5MHz for 50Hz field rate */ +#define IFSEL_S 0x10 /* 01 : S-video decoding */ +#define IFSEL_C 0x00 /* 00 : Composite video decoding */ + /* Y input video selection */ +#define YSEL_M0 0x00 /* 00 : Mux0 selected */ +#define YSEL_M1 0x04 /* 01 : Mux1 selected */ +#define YSEL_M2 0x08 /* 10 : Mux2 selected */ +#define YSEL_M3 0x10 /* 11 : Mux3 selected */ + +/* OPFORM */ +#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */ + /* 1 : ITU-R-656 compatible data sequence format */ +#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */ + /* 1 : 16-bit YCrCb 4:2:2 output format.*/ +#define LLCMODE 0x20 /* 1 : LLC output mode. */ + /* 0 : free-run output mode */ +#define AINC 0x10 /* Serial interface auto-indexing control */ + /* 0 : auto-increment */ + /* 1 : non-auto */ +#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ + /* 0 : Vertical out ctrl by HACTIVE and DVALID */ +#define OEN_TRI_SEL_MASK 0x07 +#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ +#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ +#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ + +/* OUTCTR1 */ +#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ +#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */ + /* VS pin output control */ +#define VSSL_VSYNC 0x00 /* 0 : VSYNC */ +#define VSSL_VACT 0x10 /* 1 : VACT */ +#define VSSL_FIELD 0x20 /* 2 : FIELD */ +#define VSSL_VVALID 0x30 /* 3 : VVALID */ +#define VSSL_ZERO 0x70 /* 7 : 0 */ +#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */ +#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/ + /* HS pin output control */ +#define HSSL_HACT 0x00 /* 0 : HACT */ +#define HSSL_HSYNC 0x01 /* 1 : HSYNC */ +#define HSSL_DVALID 0x02 /* 2 : DVALID */ +#define HSSL_HLOCK 0x03 /* 3 : HLOCK */ +#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */ +#define HSSL_ZERO 0x07 /* 7 : 0 */ + +/* ACNTL1 */ +#define SRESET 0x80 /* resets the device to its default state + * but all register content remain unchanged. + * This bit is self-resetting. + */ +#define ACNTL1_PDN_MASK 0x0e +#define CLK_PDN 0x08 /* system clock power down */ +#define Y_PDN 0x04 /* Luma ADC power down */ +#define C_PDN 0x02 /* Chroma ADC power down */ + +/* ACNTL2 */ +#define ACNTL2_PDN_MASK 0x40 +#define PLL_PDN 0x40 /* PLL power down */ + +/* VBICNTL */ + +/* RTSEL : control the real time signal output from the MPOUT pin */ +#define RTSEL_MASK 0x07 +#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ +#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ +#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */ +#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */ +#define RTSEL_MONO 0x04 /* 0100 = MONO */ +#define RTSEL_DET50 0x05 /* 0101 = DET50 */ +#define RTSEL_FIELD 0x06 /* 0110 = FIELD */ +#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ + +/* HSYNC start and end are constant for now */ +#define HSYNC_START 0x0260 +#define HSYNC_END 0x0300 + +/* + * structure + */ + +struct regval_list { + unsigned char reg_num; + unsigned char value; +}; + +struct tw9910_scale_ctrl { + char *name; + unsigned short width; + unsigned short height; + u16 hscale; + u16 vscale; +}; + +struct tw9910_priv { + struct v4l2_subdev subdev; + struct clk *clk; + struct tw9910_video_info *info; + struct gpio_desc *pdn_gpio; + struct gpio_desc *rstb_gpio; + const struct tw9910_scale_ctrl *scale; + v4l2_std_id norm; + u32 revision; +}; + +static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { + { + .name = "NTSC SQ", + .width = 640, + .height = 480, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "NTSC CCIR601", + .width = 720, + .height = 480, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "NTSC SQ (CIF)", + .width = 320, + .height = 240, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "NTSC CCIR601 (CIF)", + .width = 360, + .height = 240, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "NTSC SQ (QCIF)", + .width = 160, + .height = 120, + .hscale = 0x0400, + .vscale = 0x0400, + }, + { + .name = "NTSC CCIR601 (QCIF)", + .width = 180, + .height = 120, + .hscale = 0x0400, + .vscale = 0x0400, + }, +}; + +static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { + { + .name = "PAL SQ", + .width = 768, + .height = 576, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "PAL CCIR601", + .width = 720, + .height = 576, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "PAL SQ (CIF)", + .width = 384, + .height = 288, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "PAL CCIR601 (CIF)", + .width = 360, + .height = 288, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "PAL SQ (QCIF)", + .width = 192, + .height = 144, + .hscale = 0x0400, + .vscale = 0x0400, + }, + { + .name = "PAL CCIR601 (QCIF)", + .width = 180, + .height = 144, + .hscale = 0x0400, + .vscale = 0x0400, + }, +}; + +/* + * general function + */ +static struct tw9910_priv *to_tw9910(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct tw9910_priv, + subdev); +} + +static int tw9910_mask_set(struct i2c_client *client, u8 command, + u8 mask, u8 set) +{ + s32 val = i2c_smbus_read_byte_data(client, command); + + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return i2c_smbus_write_byte_data(client, command, val); +} + +static int tw9910_set_scale(struct i2c_client *client, + const struct tw9910_scale_ctrl *scale) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, SCALE_HI, + (scale->vscale & 0x0F00) >> 4 | + (scale->hscale & 0x0F00) >> 8); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, HSCALE_LO, + scale->hscale & 0x00FF); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, VSCALE_LO, + scale->vscale & 0x00FF); + + return ret; +} + +static int tw9910_set_hsync(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + int ret; + + /* bit 10 - 3 */ + ret = i2c_smbus_write_byte_data(client, HSBEGIN, + (HSYNC_START & 0x07F8) >> 3); + if (ret < 0) + return ret; + + /* bit 10 - 3 */ + ret = i2c_smbus_write_byte_data(client, HSEND, + (HSYNC_END & 0x07F8) >> 3); + if (ret < 0) + return ret; + + /* So far only revisions 0 and 1 have been seen. */ + /* bit 2 - 0 */ + if (priv->revision == 1) + ret = tw9910_mask_set(client, HSLOWCTL, 0x77, + (HSYNC_START & 0x0007) << 4 | + (HSYNC_END & 0x0007)); + + return ret; +} + +static void tw9910_reset(struct i2c_client *client) +{ + tw9910_mask_set(client, ACNTL1, SRESET, SRESET); + usleep_range(1000, 5000); +} + +static int tw9910_power(struct i2c_client *client, int enable) +{ + int ret; + u8 acntl1; + u8 acntl2; + + if (enable) { + acntl1 = 0; + acntl2 = 0; + } else { + acntl1 = CLK_PDN | Y_PDN | C_PDN; + acntl2 = PLL_PDN; + } + + ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); + if (ret < 0) + return ret; + + return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); +} + +static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, + u32 width, u32 height) +{ + const struct tw9910_scale_ctrl *scale; + const struct tw9910_scale_ctrl *ret = NULL; + __u32 diff = 0xffffffff, tmp; + int size, i; + + if (norm & V4L2_STD_NTSC) { + scale = tw9910_ntsc_scales; + size = ARRAY_SIZE(tw9910_ntsc_scales); + } else if (norm & V4L2_STD_PAL) { + scale = tw9910_pal_scales; + size = ARRAY_SIZE(tw9910_pal_scales); + } else { + return NULL; + } + + for (i = 0; i < size; i++) { + tmp = abs(width - scale[i].width) + + abs(height - scale[i].height); + if (tmp < diff) { + diff = tmp; + ret = scale + i; + } + } + + return ret; +} + +/* + * subdevice operations + */ +static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + u8 val; + int ret; + + if (!enable) { + switch (priv->revision) { + case 0: + val = OEN_TRI_SEL_ALL_OFF_r0; + break; + case 1: + val = OEN_TRI_SEL_ALL_OFF_r1; + break; + default: + dev_err(&client->dev, "un-supported revision\n"); + return -EINVAL; + } + } else { + val = OEN_TRI_SEL_ALL_ON; + + if (!priv->scale) { + dev_err(&client->dev, "norm select error\n"); + return -EPERM; + } + + dev_dbg(&client->dev, "%s %dx%d\n", + priv->scale->name, + priv->scale->width, + priv->scale->height); + } + + ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); + if (ret < 0) + return ret; + + return tw9910_power(client, enable); +} + +static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + *norm = priv->norm; + + return 0; +} + +static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + const unsigned int hact = 720; + const unsigned int hdelay = 15; + unsigned int vact; + unsigned int vdelay; + int ret; + + if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) + return -EINVAL; + + priv->norm = norm; + if (norm & V4L2_STD_525_60) { + vact = 240; + vdelay = 18; + ret = tw9910_mask_set(client, VVBI, 0x10, 0x10); + } else { + vact = 288; + vdelay = 24; + ret = tw9910_mask_set(client, VVBI, 0x10, 0x00); + } + if (!ret) + ret = i2c_smbus_write_byte_data(client, CROP_HI, + ((vdelay >> 2) & 0xc0) | + ((vact >> 4) & 0x30) | + ((hdelay >> 6) & 0x0c) | + ((hact >> 8) & 0x03)); + if (!ret) + ret = i2c_smbus_write_byte_data(client, VDELAY_LO, + vdelay & 0xff); + if (!ret) + ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, + vact & 0xff); + + return ret; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int tw9910_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (reg->reg > 0xff) + return -EINVAL; + + reg->size = 1; + ret = i2c_smbus_read_byte_data(client, reg->reg); + if (ret < 0) + return ret; + + /* + * ret = int + * reg->val = __u64 + */ + reg->val = (__u64)ret; + + return 0; +} + +static int tw9910_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(client, reg->reg, reg->val); +} +#endif + +static int tw9910_power_on(struct tw9910_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + int ret; + + if (priv->clk) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + if (priv->pdn_gpio) { + gpiod_set_value(priv->pdn_gpio, 0); + usleep_range(500, 1000); + } + + /* + * FIXME: The reset signal is connected to a shared GPIO on some + * platforms (namely the SuperH Migo-R). Until a framework becomes + * available to handle this cleanly, request the GPIO temporarily + * to avoid conflicts. + */ + priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb", + GPIOD_OUT_LOW); + if (IS_ERR(priv->rstb_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + return PTR_ERR(priv->rstb_gpio); + } + + if (priv->rstb_gpio) { + gpiod_set_value(priv->rstb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(priv->rstb_gpio, 0); + usleep_range(500, 1000); + + gpiod_put(priv->rstb_gpio); + } + + return 0; +} + +static int tw9910_power_off(struct tw9910_priv *priv) +{ + clk_disable_unprepare(priv->clk); + + if (priv->pdn_gpio) { + gpiod_set_value(priv->pdn_gpio, 1); + usleep_range(500, 1000); + } + + return 0; +} + +static int tw9910_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + return on ? tw9910_power_on(priv) : tw9910_power_off(priv); +} + +static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + int ret = -EINVAL; + u8 val; + + /* Select suitable norm. */ + priv->scale = tw9910_select_norm(priv->norm, *width, *height); + if (!priv->scale) + goto tw9910_set_fmt_error; + + /* Reset hardware. */ + tw9910_reset(client); + + /* Set bus width. */ + val = 0x00; + if (priv->info->buswidth == 16) + val = LEN; + + ret = tw9910_mask_set(client, OPFORM, LEN, val); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* Select MPOUT behavior. */ + switch (priv->info->mpout) { + case TW9910_MPO_VLOSS: + val = RTSEL_VLOSS; break; + case TW9910_MPO_HLOCK: + val = RTSEL_HLOCK; break; + case TW9910_MPO_SLOCK: + val = RTSEL_SLOCK; break; + case TW9910_MPO_VLOCK: + val = RTSEL_VLOCK; break; + case TW9910_MPO_MONO: + val = RTSEL_MONO; break; + case TW9910_MPO_DET50: + val = RTSEL_DET50; break; + case TW9910_MPO_FIELD: + val = RTSEL_FIELD; break; + case TW9910_MPO_RTCO: + val = RTSEL_RTCO; break; + default: + val = 0; + } + + ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* Set scale. */ + ret = tw9910_set_scale(client, priv->scale); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* Set hsync. */ + ret = tw9910_set_hsync(client); + if (ret < 0) + goto tw9910_set_fmt_error; + + *width = priv->scale->width; + *height = priv->scale->height; + + return ret; + +tw9910_set_fmt_error: + + tw9910_reset(client); + priv->scale = NULL; + + return ret; +} + +static int tw9910_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported. */ + if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + if (priv->norm & V4L2_STD_NTSC) { + sel->r.width = 640; + sel->r.height = 480; + } else { + sel->r.width = 768; + sel->r.height = 576; + } + + return 0; +} + +static int tw9910_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + if (format->pad) + return -EINVAL; + + if (!priv->scale) { + priv->scale = tw9910_select_norm(priv->norm, 640, 480); + if (!priv->scale) + return -EINVAL; + } + + mf->width = priv->scale->width; + mf->height = priv->scale->height; + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->field = V4L2_FIELD_INTERLACED_BT; + + return 0; +} + +static int tw9910_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u32 width = mf->width, height = mf->height; + int ret; + + WARN_ON(mf->field != V4L2_FIELD_ANY && + mf->field != V4L2_FIELD_INTERLACED_BT); + + /* Check color format. */ + if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8) + return -EINVAL; + + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = tw9910_set_frame(sd, &width, &height); + if (ret) + return ret; + + mf->width = width; + mf->height = height; + + return 0; +} + +static int tw9910_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + const struct tw9910_scale_ctrl *scale; + + if (format->pad) + return -EINVAL; + + if (mf->field == V4L2_FIELD_ANY) { + mf->field = V4L2_FIELD_INTERLACED_BT; + } else if (mf->field != V4L2_FIELD_INTERLACED_BT) { + dev_err(&client->dev, "Field type %d invalid\n", mf->field); + return -EINVAL; + } + + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + /* Select suitable norm. */ + scale = tw9910_select_norm(priv->norm, mf->width, mf->height); + if (!scale) + return -EINVAL; + + mf->width = scale->width; + mf->height = scale->height; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return tw9910_s_fmt(sd, mf); + + cfg->try_fmt = *mf; + + return 0; +} + +static int tw9910_video_probe(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + s32 id; + int ret; + + /* TW9910 only use 8 or 16 bit bus width. */ + if (priv->info->buswidth != 16 && priv->info->buswidth != 8) { + dev_err(&client->dev, "bus width error\n"); + return -ENODEV; + } + + ret = tw9910_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * Check and show Product ID. + * So far only revisions 0 and 1 have been seen. + */ + id = i2c_smbus_read_byte_data(client, ID); + priv->revision = GET_REV(id); + id = GET_ID(id); + + if (id != 0x0b || priv->revision > 0x01) { + dev_err(&client->dev, "Product ID error %x:%x\n", + id, priv->revision); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, "tw9910 Product ID %0x:%0x\n", + id, priv->revision); + + priv->norm = V4L2_STD_NTSC; + priv->scale = &tw9910_ntsc_scales[0]; + +done: + tw9910_s_power(&priv->subdev, 0); + + return ret; +} + +static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tw9910_g_register, + .s_register = tw9910_s_register, +#endif + .s_power = tw9910_s_power, +}; + +static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_UYVY8_2X8; + + return 0; +} + +static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + *norm = V4L2_STD_NTSC | V4L2_STD_PAL; + + return 0; +} + +static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { + .s_std = tw9910_s_std, + .g_std = tw9910_g_std, + .s_stream = tw9910_s_stream, + .g_tvnorms = tw9910_g_tvnorms, +}; + +static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { + .enum_mbus_code = tw9910_enum_mbus_code, + .get_selection = tw9910_get_selection, + .get_fmt = tw9910_get_fmt, + .set_fmt = tw9910_set_fmt, +}; + +static const struct v4l2_subdev_ops tw9910_subdev_ops = { + .core = &tw9910_subdev_core_ops, + .video = &tw9910_subdev_video_ops, + .pad = &tw9910_subdev_pad_ops, +}; + +/* + * i2c_driver function + */ + +static int tw9910_probe(struct i2c_client *client, + const struct i2c_device_id *did) + +{ + struct tw9910_priv *priv; + struct tw9910_video_info *info; + struct i2c_adapter *adapter = + to_i2c_adapter(client->dev.parent); + int ret; + + if (!client->dev.platform_data) { + dev_err(&client->dev, "TW9910: missing platform data!\n"); + return -EINVAL; + } + + info = client->dev.platform_data; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); + return -EIO; + } + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = info; + + v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); + + priv->clk = clk_get(&client->dev, "xti"); + if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = NULL; + } else if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get xti clock\n"); + return PTR_ERR(priv->clk); + } + + priv->pdn_gpio = gpiod_get_optional(&client->dev, "pdn", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->pdn_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"pdn\""); + ret = PTR_ERR(priv->pdn_gpio); + goto error_clk_put; + } + + ret = tw9910_video_probe(client); + if (ret < 0) + goto error_gpio_put; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto error_gpio_put; + + return ret; + +error_gpio_put: + if (priv->pdn_gpio) + gpiod_put(priv->pdn_gpio); +error_clk_put: + clk_put(priv->clk); + + return ret; +} + +static int tw9910_remove(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + + if (priv->pdn_gpio) + gpiod_put(priv->pdn_gpio); + clk_put(priv->clk); + v4l2_device_unregister_subdev(&priv->subdev); + + return 0; +} + +static const struct i2c_device_id tw9910_id[] = { + { "tw9910", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tw9910_id); + +static struct i2c_driver tw9910_i2c_driver = { + .driver = { + .name = "tw9910", + }, + .probe = tw9910_probe, + .remove = tw9910_remove, + .id_table = tw9910_id, +}; + +module_i2c_driver(tw9910_i2c_driver); + +MODULE_DESCRIPTION("V4L2 driver for TW9910 video decoder"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 560738213c00..1658816a9844 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -657,31 +657,22 @@ static int vs6624_get_fmt(struct v4l2_subdev *sd, return 0; } -static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int vs6624_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct vs6624 *sensor = to_vs6624(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(*cp)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = sensor->frame_rate.denominator; - cp->timeperframe.denominator = sensor->frame_rate.numerator; + ival->interval.numerator = sensor->frame_rate.denominator; + ival->interval.denominator = sensor->frame_rate.numerator; return 0; } -static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int vs6624_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct vs6624 *sensor = to_vs6624(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; if (tpf->numerator == 0 || tpf->denominator == 0 || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) { @@ -738,8 +729,8 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { }; static const struct v4l2_subdev_video_ops vs6624_video_ops = { - .s_parm = vs6624_s_parm, - .g_parm = vs6624_g_parm, + .s_frame_interval = vs6624_s_frame_interval, + .g_frame_interval = vs6624_g_frame_interval, .s_stream = vs6624_s_stream, }; diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index e79f72b8b858..35e81f7c0d2f 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -190,6 +190,7 @@ static long media_device_enum_links(struct media_device *mdev, ulink_desc++; } } + memset(links->reserved, 0, sizeof(links->reserved)); return 0; } @@ -218,6 +219,8 @@ static long media_device_setup_link(struct media_device *mdev, if (link == NULL) return -EINVAL; + memset(linkd->reserved, 0, sizeof(linkd->reserved)); + /* Setup the link on both entities. */ return __media_entity_setup_link(link, linkd->flags); } @@ -255,7 +258,7 @@ static long media_device_get_topology(struct media_device *mdev, memset(&kentity, 0, sizeof(kentity)); kentity.id = entity->graph_obj.id; kentity.function = entity->function; - strncpy(kentity.name, entity->name, + strlcpy(kentity.name, entity->name, sizeof(kentity.name)); if (copy_to_user(uentity, &kentity, sizeof(kentity))) @@ -263,6 +266,7 @@ static long media_device_get_topology(struct media_device *mdev, uentity++; } topo->num_entities = i; + topo->reserved1 = 0; /* Get interfaces and number of interfaces */ i = 0; @@ -298,6 +302,7 @@ static long media_device_get_topology(struct media_device *mdev, uintf++; } topo->num_interfaces = i; + topo->reserved2 = 0; /* Get pads and number of pads */ i = 0; @@ -324,6 +329,7 @@ static long media_device_get_topology(struct media_device *mdev, upad++; } topo->num_pads = i; + topo->reserved3 = 0; /* Get links and number of links */ i = 0; @@ -355,6 +361,7 @@ static long media_device_get_topology(struct media_device *mdev, ulink++; } topo->num_links = i; + topo->reserved4 = 0; return ret; } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index f7c6d64e6031..3498551e618e 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -64,22 +64,6 @@ static inline const char *intf_type(struct media_interface *intf) return "v4l-swradio"; case MEDIA_INTF_T_V4L_TOUCH: return "v4l-touch"; - case MEDIA_INTF_T_ALSA_PCM_CAPTURE: - return "alsa-pcm-capture"; - case MEDIA_INTF_T_ALSA_PCM_PLAYBACK: - return "alsa-pcm-playback"; - case MEDIA_INTF_T_ALSA_CONTROL: - return "alsa-control"; - case MEDIA_INTF_T_ALSA_COMPRESS: - return "alsa-compress"; - case MEDIA_INTF_T_ALSA_RAWMIDI: - return "alsa-rawmidi"; - case MEDIA_INTF_T_ALSA_HWDEP: - return "alsa-hwdep"; - case MEDIA_INTF_T_ALSA_SEQUENCER: - return "alsa-sequencer"; - case MEDIA_INTF_T_ALSA_TIMER: - return "alsa-timer"; default: return "unknown-intf"; } diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index da49c5567db5..08266b23826e 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -332,11 +332,15 @@ static void bttv_ir_stop(struct bttv *btv) static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dprintk("read error\n"); + if (rc < 0) + return rc; return -EIO; } diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile index b328955abbd2..29eddff2f35f 100644 --- a/drivers/media/pci/cobalt/Makefile +++ b/drivers/media/pci/cobalt/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 cobalt-objs := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \ cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \ cobalt-alsa-main.o cobalt-alsa-pcm.o diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c index 720e3ad93a9e..e5022b620856 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-main.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/init.h> diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c index b69b258d39b9..f6a7df13cd04 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ALSA PCM device for the * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/init.h> diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h index 513fb1f71794..0e2e9c63a23e 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ALSA PCM device for the * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc); diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h index 08db699ced37..bb7f156ad3e7 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa.h +++ b/drivers/media/pci/cobalt/cobalt-alsa.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ struct snd_card; diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c index bfcecef659e3..3d8026483ac3 100644 --- a/drivers/media/pci/cobalt/cobalt-cpld.c +++ b/drivers/media/pci/cobalt/cobalt-cpld.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cobalt CPLD functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/delay.h> diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h index 0fc88fd5fa7b..8c880ed14cda 100644 --- a/drivers/media/pci/cobalt/cobalt-cpld.h +++ b/drivers/media/pci/cobalt/cobalt-cpld.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Cobalt CPLD functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_CPLD_H diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 3f16cf3f6d74..c8b1a6206c65 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt driver initialization and card probing * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/delay.h> diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h index 00f773ec359a..429bee4ef79c 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.h +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt driver internal defines and structures * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_DRIVER_H diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c index 04dcaf9198d2..ef96e0f956d2 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.c +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cobalt NOR flash functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/mtd/mtd.h> diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h index 8077daea51cd..605ce3d37ca3 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.h +++ b/drivers/media/pci/cobalt/cobalt-flash.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Cobalt NOR flash functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_FLASH_H diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c index 1a5c55673ea8..c374dae78bf7 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.c +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt I2C functions * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include "cobalt-driver.h" diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h index a4c1cfaacf95..7a9057c8bff6 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.h +++ b/drivers/media/pci/cobalt/cobalt-i2c.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt I2C functions * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* init + register i2c algo-bit adapter */ diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index b190d4f81c6e..04783e78cc12 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt interrupt handling * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <media/i2c/adv7604.h> diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h index 5119484a24d9..0b4078ce6555 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.h +++ b/drivers/media/pci/cobalt/cobalt-irq.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt interrupt handling * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/interrupt.h> diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c index a28a8482c1d4..4c137453e679 100644 --- a/drivers/media/pci/cobalt/cobalt-omnitek.c +++ b/drivers/media/pci/cobalt/cobalt-omnitek.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Omnitek Scatter-Gather DMA Controller * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/string.h> diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h index e5c6d032c6f2..129c5fccbe39 100644 --- a/drivers/media/pci/cobalt/cobalt-omnitek.h +++ b/drivers/media/pci/cobalt/cobalt-omnitek.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Omnitek Scatter-Gather DMA Controller * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_OMNITEK_H diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index def4a3b37084..e2a4c705d353 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt V4L2 API * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/dma-mapping.h> diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h index 62be553cd8e2..dc43974b2d86 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.h +++ b/drivers/media/pci/cobalt/cobalt-v4l2.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt V4L2 API * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ int cobalt_nodes_register(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h index 9bc9ef1fd3a8..4c6ad1cee87e 100644 --- a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h +++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h index a480529f561e..6cc1ad7d98c9 100644 --- a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h +++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h index 602419e589d3..f0c6fe304247 100644 --- a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h +++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00389_CVI_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h index 95471c995067..27f05aca632f 100644 --- a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h +++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00460_EVCNT_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h index 384a3e156301..8a5bf008750a 100644 --- a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h +++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h index 2a029026bf82..18bd4fcd2db8 100644 --- a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h +++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h index bdef2df5d689..86da49033cd8 100644 --- a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h +++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index 2531e4b81b60..93443d1457c5 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -32,7 +32,6 @@ #include "cx18-driver.h" #include "cx18-version.h" #include "cx18-alsa.h" -#include "cx18-alsa-mixer.h" #include "cx18-alsa-pcm.h" int cx18_alsa_debug; diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c deleted file mode 100644 index cb04c3d820e2..000000000000 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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 <linux/init.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/spinlock.h> -#include <linux/videodev2.h> - -#include <media/v4l2-device.h> - -#include <sound/core.h> -#include <sound/control.h> -#include <sound/tlv.h> - -#include "cx18-alsa.h" -#include "cx18-driver.h" - -/* - * Note the cx18-av-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx18_av_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx18_av_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); - snd_cx18_unlock(cxsc); - - if (!ret) - uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - - /* Fetch current state */ - ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); - - if (ret || - (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - ret = v4l2_s_ctrl(cx->sd_av->ctrl_handler, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_cx18_unlock(cxsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_cx18_mixer_tv_volume_info, - .get = snd_cx18_mixer_tv_volume_get, - .put = snd_cx18_mixer_tv_volume_put, - .tlv.p = snd_cx18_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add CS5345 I2S volume for HVR-1600 */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) -{ - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct snd_card *sc = cxsc->sc; - int ret; - - strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(&snd_cx18_mixer_tv_vol, cxsc)); - if (ret) { - CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_cx18_mixer_tv_vol.name, ret); - } - return ret; -} diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.h b/drivers/media/pci/cx18/cx18-alsa-mixer.h deleted file mode 100644 index 3aed123955dd..000000000000 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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. - */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc); diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c index 53f4d6bf81fb..010f39eafce1 100644 --- a/drivers/media/pci/cx18/cx18-dvb.c +++ b/drivers/media/pci/cx18/cx18-dvb.c @@ -72,7 +72,7 @@ static struct s5h1409_config hauppauge_hvr1600_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE }; @@ -86,7 +86,7 @@ static struct s5h1411_config hcw_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda18271_std_map hauppauge_tda18271_std_map = { diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index d8c3637e492e..20b3cb17f97f 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -89,9 +89,8 @@ static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) return -ENOMEM; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)buf->vaddr, - nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + buf->vaddr, nr_pages << PAGE_SHIFT); memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 3622521431f5..3a1c55187b2a 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -771,11 +771,46 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885] = { + .name = "Hauppauge WinTV-QuadHD-DVB(885)", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = { .name = "Hauppauge WinTV-QuadHD-ATSC", .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885] = { + .name = "Hauppauge WinTV-QuadHD-ATSC(885)", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = { + .name = "Hauppauge WinTV-HVR-1265(161111)", + .porta = CX23885_ANALOG_VIDEO, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, + }, + [CX23885_BOARD_HAUPPAUGE_STARBURST2] = { + .name = "Hauppauge WinTV-Starburst2", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -1028,6 +1063,10 @@ struct cx23885_subid cx23885_subids[] = { .subdevice = 0x7133, .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE, }, { + .subvendor = 0x0070, + .subdevice = 0x7137, + .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE, + }, { .subvendor = 0x18ac, .subdevice = 0xdb98, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2, @@ -1087,6 +1126,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x6b18, .card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 2 */ + }, { + .subvendor = 0x0070, + .subdevice = 0x2a18, + .card = CX23885_BOARD_HAUPPAUGE_HVR1265_K4, /* Hauppauge WinTV HVR-1265 (Model 161xx1, Hybrid ATSC/QAM-B) */ + }, { + .subvendor = 0x0070, + .subdevice = 0xf02a, + .card = CX23885_BOARD_HAUPPAUGE_STARBURST2, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1287,25 +1334,28 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 150329: /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; - case 166100: + case 161111: + /* WinTV-HVR-1265 K4 (PCIe, Analog/ATSC/QAM-B) */ + break; + case 166100: /* 888 version, hybrid */ + case 166200: /* 885 version, DVB only */ /* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height, DVB-T/T2/C, DVB-T/T2/C */ break; - case 166101: + case 166101: /* 888 version, hybrid */ + case 166201: /* 885 version, DVB only */ /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, DVB-T/T2/C, DVB-T/T2/C */ break; - case 165100: - /* - * WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height, - * ATSC, ATSC - */ + case 165100: /* 888 version, hybrid */ + case 165200: /* 885 version, digital only */ + /* WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height, + * ATSC/QAM-B, ATSC/QAM-B */ break; - case 165101: - /* - * WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, - * ATSC, ATSC - */ + case 165101: /* 888 version, hybrid */ + case 165201: /* 885 version, digital only */ + /* WinTV-QuadHD (ATSC) Tuner Pair 2 (PCIe, IR, half height, + * ATSC/QAM-B, ATSC/QAM-B */ break; default: pr_warn("%s: warning: unknown hauppauge model #%d\n", @@ -1778,8 +1828,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx23885_gpio_set(dev, GPIO_2); break; case CX23885_BOARD_HAUPPAUGE_HVR5525: - case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: - case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: /* * HVR5525 GPIO Details: * GPIO-00 IR_WIDE @@ -1809,6 +1858,22 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) * card does not have any GPIO's connected to subcomponents. */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: + /* + * GPIO-08 TER1_RESN + * GPIO-09 TER2_RESN + */ + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); + cx23885_gpio_clear(dev, GPIO_8 | GPIO_9); + msleep(100); + cx23885_gpio_set(dev, GPIO_8 | GPIO_9); + msleep(100); + break; } } @@ -2054,8 +2119,12 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_STARBURST: case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: case CX23885_BOARD_HAUPPAUGE_HVR5525: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -2194,6 +2263,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR5525: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: ts1->gen_ctrl_val = 0x5; /* Parallel */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -2201,8 +2271,11 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -2259,6 +2332,9 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: @@ -2286,6 +2362,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { + /* set host data for clk_freq configuration */ + v4l2_set_subdev_hostdata(dev->sd_cx25840, + &dev->clk_freq); + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8f63df1cb418..019fac49db5b 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -839,10 +839,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* Configure the internal memory */ if (dev->pci->device == 0x8880) { - /* Could be 887 or 888, assume a default */ - dev->bridge = CX23885_BRIDGE_887; + /* Could be 887 or 888, assume an 888 default */ + dev->bridge = CX23885_BRIDGE_888; /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 25000000; + dev->clk_freq = 50000000; dev->sram_channels = cx23887_sram_channels; } else if (dev->pci->device == 0x8852) { @@ -869,10 +869,28 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } + if (dev->pci->device == 0x8852) { + /* no DIF on cx23885, so no analog tuner support possible */ + if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) + dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885; + else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) + dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885; + } + /* If the user specific a clk freq override, apply it */ if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; + if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE && + dev->pci->subsystem_device == 0x7137) { + /* Hauppauge ImpactVCBe device ID 0x7137 is populated + * with an 888, and a 25Mhz crystal, instead of the + * usual third overtone 50Mhz. The default clock rate must + * be overridden so the cx25840 is properly configured + */ + dev->clk_freq = 25000000; + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); @@ -965,7 +983,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_card_setup(dev); - call_all(dev, core, s_power, 0); + call_all(dev, tuner, standby); cx23885_ir_init(dev); if (dev->board == CX23885_BOARD_VIEWCAST_460E) { diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 700422b538c0..114d9bcbe4f4 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -193,7 +193,7 @@ static struct s5h1409_config hauppauge_generic_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda10048_config hauppauge_hvr1200_config = { @@ -225,7 +225,7 @@ static struct s5h1409_config hauppauge_ezqam_config = { .qam_if = 4000, .inversion = S5H1409_INVERSION_ON, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1800lp_config = { @@ -235,7 +235,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1500_config = { @@ -244,7 +244,7 @@ static struct s5h1409_config hauppauge_hvr1500_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -264,7 +264,7 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config dvico_s5h1409_config = { @@ -274,7 +274,7 @@ static struct s5h1409_config dvico_s5h1409_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config dvico_s5h1411_config = { @@ -284,7 +284,7 @@ static struct s5h1411_config dvico_s5h1411_config = { .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config hcw_s5h1411_config = { @@ -294,7 +294,7 @@ static struct s5h1411_config hcw_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { @@ -930,6 +930,18 @@ static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = { .agc = 0x99, }; +static struct lgdt3306a_config hauppauge_hvr1265k4_config = { + .i2c_addr = 0x59, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -1194,6 +1206,8 @@ static int dvb_register(struct cx23885_tsport *port) struct si2157_config si2157_config; struct ts2020_config ts2020_config; struct m88ds3103_platform_data m88ds3103_pdata; + struct m88rs6000t_config m88rs6000t_config = {}; + struct a8293_platform_data a8293_pdata = {}; struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client_demod = NULL, *client_tuner = NULL; @@ -2217,9 +2231,10 @@ static int dvb_register(struct cx23885_tsport *port) } port->i2c_client_tuner = client_tuner; break; - case CX23885_BOARD_HAUPPAUGE_HVR5525: { - struct m88rs6000t_config m88rs6000t_config; - struct a8293_platform_data a8293_pdata = {}; + case CX23885_BOARD_HAUPPAUGE_STARBURST2: + case CX23885_BOARD_HAUPPAUGE_HVR5525: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; switch (port->nr) { @@ -2228,7 +2243,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach frontend */ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, &hauppauge_hvr5525_m88ds3103_config, - &dev->i2c_bus[0].i2c_adap, &adapter); + &i2c_bus->i2c_adap, &adapter); if (fe0->dvb.frontend == NULL) break; @@ -2239,7 +2254,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x0b; info.platform_data = &a8293_pdata; request_module("a8293"); - client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); if (!client_sec || !client_sec->dev.driver) goto frontend_detach; if (!try_module_get(client_sec->dev.driver->owner)) { @@ -2281,7 +2296,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x64; info.platform_data = &si2168_config; request_module("%s", info.type); - client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); if (!client_demod || !client_demod->dev.driver) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { @@ -2299,7 +2314,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x60; info.platform_data = &si2157_config; request_module("%s", info.type); - client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + client_tuner = i2c_new_device(&i2c_bus2->i2c_adap, &info); if (!client_tuner || !client_tuner->dev.driver) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); @@ -2317,8 +2332,10 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - } case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: + pr_info("%s(): board=%d port=%d\n", __func__, + dev->board, port->nr); switch (port->nr) { /* port b - Terrestrial/cable */ case 1: @@ -2416,6 +2433,9 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: + pr_info("%s(): board=%d port=%d\n", __func__, + dev->board, port->nr); switch (port->nr) { /* port b - Terrestrial/cable */ case 1: @@ -2490,7 +2510,41 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + switch (port->nr) { + /* port c - Terrestrial/cable */ + case 2: + /* attach frontend */ + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr1265k4_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend == NULL) + break; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; + si2157_config.inversion = 1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!client_tuner || !client_tuner->dev.driver) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + client_tuner = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: pr_info("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); @@ -2514,8 +2568,8 @@ static int dvb_register(struct cx23885_tsport *port) fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; #endif - /* Put the analog decoder in standby to keep it quiet */ - call_all(dev, core, s_power, 0); + /* Put the tuner in standby to keep it quiet */ + call_all(dev, tuner, standby); if (fe0->dvb.frontend->ops.analog_ops.standby) fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 0f4e54294bb7..be49589a61d2 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -94,6 +94,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) case CX23885_BOARD_DVBSKY_S950: case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* * The only boards we handle right now. However other boards * using the CX2388x integrated IR controller should be similar @@ -153,6 +154,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) case CX23885_BOARD_DVBSKY_S950: case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* * The IR controller on this board only returns pulse widths. * Any other mode setting will fail to set up the device. @@ -283,6 +285,7 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* Integrated CX2388[58] IR controller */ allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Hauppauge RC-5 remote */ diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index a03dcb662953..f8a3deadc77a 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -263,6 +263,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || (dev->board == CX23885_BOARD_MYGICA_X8507) || (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) || @@ -993,7 +994,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111)) + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4)) fe = &dev->ts1.analog_fe; if (fe && fe->ops.tuner_ops.set_analog_params) { @@ -1022,6 +1024,7 @@ int cx23885_set_frequency(struct file *file, void *priv, switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_HVR1850: ret = cx23885_set_freq_via_ops(dev, f); break; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 2a17209eb4f6..d54c7ee1ab21 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -107,6 +107,10 @@ #define CX23885_BOARD_VIEWCAST_460E 55 #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57 +#define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58 +#define CX23885_BOARD_HAUPPAUGE_STARBURST2 59 +#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885 60 +#define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885 61 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 04aa4a68a0ae..040c6c251d3a 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -867,6 +867,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); + if (dev->nr >= ARRAY_SIZE(card)) { + CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card)); + return -ENODEV; + } if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -882,9 +886,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->channels[i].sram_channels = &cx25821_sram_channels[i]; } - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - /* board config */ dev->board = 1; /* card[dev->nr]; */ dev->_max_num_decoders = MAX_DECODERS; diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 9740326bc93f..ab09bb55cf45 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -292,8 +292,8 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) return -ENOMEM; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)buf->vaddr, nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + buf->vaddr, nr_pages << PAGE_SHIFT); memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; @@ -656,8 +656,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, { struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - int left = value->value.integer.value[0]; - int right = value->value.integer.value[1]; + u16 left = value->value.integer.value[0]; + u16 right = value->value.integer.value[1]; int v, b; /* Pass volume & balance onto any WM8775 */ diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 6df21b29ea17..4c92d2388c26 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -3592,7 +3592,7 @@ static void cx88_card_setup(struct cx88_core *core) ctl.fname); call_all(core, tuner, s_config, &xc2028_cfg); } - call_all(core, core, s_power, 0); + call_all(core, tuner, standby); } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 49a335f4603e..2f886140dd2e 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -558,7 +558,7 @@ static const struct s5h1409_config pinnacle_pctv_hd_800i_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK, }; static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { @@ -567,7 +567,7 @@ static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static const struct s5h1409_config kworld_atsc_120_config = { @@ -576,7 +576,7 @@ static const struct s5h1409_config kworld_atsc_120_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { @@ -599,7 +599,7 @@ static const struct zl10353_config cx88_geniatech_x8000_mt = { static const struct s5h1411_config dvico_fusionhdtv7_config = { .output_mode = S5H1411_SERIAL_OUTPUT, .gpio = S5H1411_GPIO_ON, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, .qam_if = S5H1411_IF_44000, .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, @@ -1631,8 +1631,8 @@ static int dvb_register(struct cx8802_dev *dev) if (fe1) fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; - /* Put the analog decoder in standby to keep it quiet */ - call_all(core, core, s_power, 0); + /* Put the tuner in standby to keep it quiet */ + call_all(core, tuner, standby); /* register everything */ res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 4e9953e61a12..6f4e6923a91a 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -180,7 +180,7 @@ static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); cx88_ir_handle_key(ir); - missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000); + missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000LL); if (missed > 1) ir_dprintk("Missed ticks %ld\n", missed - 1); @@ -200,7 +200,7 @@ static int __cx88_ir_start(void *priv) if (ir->polling) { hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ir->timer.function = cx88_ir_work; - hrtimer_start(&ir->timer, ir->polling * 1000000, + hrtimer_start(&ir->timer, ir->polling * 1000000LL, HRTIMER_MODE_REL); } if (ir->sampling) { diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index f43d0b83fc0c..a422dde2f34a 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -13,6 +13,7 @@ config DVB_DDBRIDGE select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index f58fdec50eab..745b37d07558 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -10,6 +10,3 @@ obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o ccflags-y += -Idrivers/media/dvb-frontends/ ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 5828111487b0..a9dbc4ebf94f 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port) memcpy(&ci->en, &en_templ, sizeof(en_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; } @@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port) memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; ci->port->creg = 0; @@ -311,38 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port) write_creg(ci, 0x08, 0x08); } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 72000, - .adr = 0x40, .polarity = 1, .clock_mode = 1, .max_i2c = 512, }; +static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) +{ + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + + cxd_cfg.bitrate = bitrate; + cxd_cfg.en = &port->en; + + client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap, + 0x40, &cxd_cfg); + if (!client) + goto err; + + port->dvb[0].i2c_client[0] = client; + port->en_freedata = 0; + return 0; + +err: + dev_err(port->dev->dev, "CXD2099AR attach failed\n"); + return -ENODEV; +} + int ddb_ci_attach(struct ddb_port *port, u32 bitrate) { + int ret; + switch (port->type) { case DDB_CI_EXTERNAL_SONY: - cxd_cfg.bitrate = bitrate; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) + ret = ci_cxd2099_attach(port, bitrate); + if (ret) return -ENODEV; break; - case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); - if (!port->en) - return -ENODEV; break; - case DDB_CI_INTERNAL: ci_attach(port); - if (!port->en) - return -ENODEV; break; + default: + return -ENODEV; } + if (!port->en) + return -ENODEV; dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); return 0; } @@ -353,7 +375,14 @@ void ddb_ci_detach(struct ddb_port *port) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - kfree(port->en->data); + + dvb_module_release(port->dvb[0].i2c_client[0]); + port->dvb[0].i2c_client[0] = NULL; + + /* free alloc'ed memory if needed */ + if (port->en_freedata) + kfree(port->en->data); + port->en = NULL; } } diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index f9bee36f1cad..90687eff5909 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -999,37 +999,21 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (input->nr & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (input->nr & 1) ? 0x63 : 0x60; /* due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when * cold started, or it very likely will fail. */ if (porttype == DDB_TUNER_DVBCT_ST) - tuner_tda18212_ping(input, board_info.addr); - - request_module(board_info.type); - - /* perform tuner init/attach */ - client = i2c_new_device(adapter, &board_info); - if (!client || !client->dev.driver) - goto err; + tuner_tda18212_ping(input, addr); - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, adapter, addr, &config); + if (!client) goto err; - } dvb->i2c_client[0] = client; - return 0; err: dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); @@ -1253,7 +1237,6 @@ static void dvb_input_detach(struct ddb_input *input) { struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; struct dvb_demux *dvbdemux = &dvb->demux; - struct i2c_client *client; switch (dvb->attached) { case 0x31: @@ -1263,13 +1246,8 @@ static void dvb_input_detach(struct ddb_input *input) dvb_unregister_frontend(dvb->fe); /* fallthrough */ case 0x30: - client = dvb->i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - dvb->i2c_client[0] = NULL; - client = NULL; - } + dvb_module_release(dvb->i2c_client[0]); + dvb->i2c_client[0] = NULL; if (dvb->fe2) dvb_frontend_detach(dvb->fe2); diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 095457737bc1..f223dc6c9963 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -276,6 +276,7 @@ struct ddb_port { struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + u8 en_freedata; struct ddb_dvb dvb[2]; u32 gap; u32 obr; diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 6c4444b31f4b..7d768ec0f824 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2017 Intel Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2017 Intel Corporation * * Based partially on Intel IPU4 driver written by * Sakari Ailus <sakari.ailus@linux.intel.com> @@ -526,6 +518,8 @@ static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q) unsigned int i, maxloops = 1000; /* Disable CSI receiver and MIPI backend devices */ + writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_MASK); + writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_ENABLE); writel(0, q->csi_rx_base + CIO2_REG_CSIRX_ENABLE); writel(0, q->csi_rx_base + CIO2_REG_MIPIBE_ENABLE); @@ -1035,6 +1029,7 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq) "failed to stop sensor streaming\n"); cio2_hw_exit(cio2, q); + synchronize_irq(cio2->pci_dev->irq); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR); media_pipeline_stop(&q->vdev.entity); pm_runtime_put(&cio2->pci_dev->dev); @@ -1976,6 +1971,7 @@ static int __maybe_unused cio2_suspend(struct device *dev) /* Stop stream */ cio2_hw_exit(cio2, q); + synchronize_irq(pci_dev->irq); pm_runtime_force_suspend(dev); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 78a5799f08e7..240635be7a31 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2017 Intel Corporation */ #ifndef __IPU3_CIO2_H #define __IPU3_CIO2_H diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 029f52733f70..c1856f609d2c 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -20,7 +20,6 @@ #include "ivtv-driver.h" #include "ivtv-version.h" #include "ivtv-alsa.h" -#include "ivtv-alsa-mixer.h" #include "ivtv-alsa-pcm.h" #include <sound/core.h> @@ -160,15 +159,7 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev) /* (4) Set the driver ID and name strings */ snd_ivtv_card_set_names(itvsc); - /* (5) Create other components: mixer, PCM, & proc files */ -#if 0 - ret = snd_ivtv_mixer_create(itvsc); - if (ret) { - IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d: proceeding anyway\n", - __func__, ret); - } -#endif - + /* (5) Create other components: PCM, & proc files */ ret = snd_ivtv_pcm_create(itvsc); if (ret) { IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n", diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c deleted file mode 100644 index aee453fcff37..000000000000 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to ivtv PCM capture streams - * - * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net> - * - * 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 "ivtv-alsa.h" -#include "ivtv-alsa-mixer.h" -#include "ivtv-driver.h" - -#include <linux/videodev2.h> - -#include <sound/core.h> -#include <sound/control.h> -#include <sound/tlv.h> - -/* - * Note the cx25840-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx25840_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx25840_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_ivtv_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_ivtv_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl); - struct ivtv *itv = to_ivtv(itvsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - - snd_ivtv_lock(itvsc); - ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - snd_ivtv_unlock(itvsc); - - if (!ret) - uctl->value.integer.value[0] = cx25840_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl); - struct ivtv *itv = to_ivtv(itvsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - - snd_ivtv_lock(itvsc); - - /* Fetch current state */ - ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - - if (ret || - (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - ret = v4l2_s_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_ivtv_unlock(itvsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_ivtv_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_ivtv_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_ivtv_mixer_tv_volume_info, - .get = snd_ivtv_mixer_tv_volume_get, - .put = snd_ivtv_mixer_tv_volume_put, - .tlv.p = snd_ivtv_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add I2S volume */ - -int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc) -{ - struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; - struct snd_card *sc = itvsc->sc; - int ret; - - strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(&snd_ivtv_mixer_tv_vol, itvsc)); - if (ret) { - IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_ivtv_mixer_tv_vol.name, ret); - } - return ret; -} diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h b/drivers/media/pci/ivtv/ivtv-alsa-mixer.h deleted file mode 100644 index 382bc36bc529..000000000000 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to ivtv PCM capture streams - * - * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net> - * - * 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. - */ - -int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc); diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 621b2f613d81..8e62b8be6529 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -346,8 +346,8 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", - (unsigned long)source); + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (%p)\n", + source); if (dest_offset & 3) IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); @@ -357,12 +357,10 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", - (unsigned long)source); + IVTVFB_WARN("Invalid userspace pointer %p\n", source); - IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", - dest_offset, (unsigned long)source, - count); + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source %p count %d\n", + dest_offset, source, count); return -EINVAL; } diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c deleted file mode 100644 index 4155c838a18a..000000000000 --- a/drivers/media/pci/mantis/mantis_vp3028.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_vp3028.h" - -struct zl10353_config mantis_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -struct mantis_hwconfig vp3028_mantis_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, -}; diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h deleted file mode 100644 index 34130d29e0aa..000000000000 --- a/drivers/media/pci/mantis/mantis_vp3028.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include <media/dvb_frontend.h> -#include "mantis_common.h" -#include "zl10353.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct zl10353_config mantis_vp3028_config; -extern struct mantis_hwconfig vp3028_mantis_config; - -#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 637d506b23c5..e06d019996f3 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -8,6 +8,13 @@ config DVB_NGENE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile index e4208f5ed215..ec450ad19281 100644 --- a/drivers/media/pci/ngene/Makefile +++ b/drivers/media/pci/ngene/Makefile @@ -9,6 +9,3 @@ obj-$(CONFIG_DVB_NGENE) += ngene.o ccflags-y += -Idrivers/media/dvb-frontends/ ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index bb49620540c5..65fc8f23ad86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -23,6 +23,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -40,22 +42,101 @@ #include "drxk.h" #include "drxd.h" #include "dvb-pll.h" +#include "stv0367.h" +#include "stv0367_priv.h" +#include "tda18212.h" +#include "cxd2841er.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" + +/****************************************************************************/ +/* I2C transfer functions used for demod/tuner probing***********************/ +/****************************************************************************/ + +static int i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + {.addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, + u8 reg, u8 val) +{ + u8 msg[2] = {reg, val}; + + return i2c_write(adap, adr, msg, 2); +} + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} +static int i2c_read_regs(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len} }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} /****************************************************************************/ /* Demod/tuner attachment ***************************************************/ /****************************************************************************/ +static struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan) +{ + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + return &chan->dev->channel[0].i2c_adapter; + + return &chan->dev->channel[1].i2c_adapter; +} + static int tuner_attach_stv6110(struct ngene_channel *chan) { - struct i2c_adapter *i2c; + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; struct stv6110x_config *tunerconf = (struct stv6110x_config *) chan->dev->card_info->tuner_config[chan->number]; const struct stv6110x_devctl *ctl; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ if (chan->number < 2) i2c = &chan->dev->channel[0].i2c_adapter; else @@ -63,7 +144,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + dev_err(pdev, "No STV6110X found!\n"); return -ENODEV; } @@ -82,6 +163,23 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } +static int tuner_attach_stv6111(struct ngene_channel *chan) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); + struct dvb_frontend *fe; + u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); + + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); + if (!fe) { + dev_err(pdev, "stv6111_attach() failed!\n"); + return -ENODEV; + } + } + return 0; +} static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { @@ -100,35 +198,109 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { - struct i2c_adapter *i2c; + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; - i2c = &chan->dev->channel[0].i2c_adapter; if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + dev_err(pdev, "No TDA18271 found!\n"); return -ENODEV; } return 0; } +static int tuner_tda18212_ping(struct ngene_channel *chan, + struct i2c_adapter *i2c, + unsigned short adr) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 tda_id[2]; + u8 subaddr = 0x00; + + dev_dbg(pdev, "stv0367-tda18212 tuner ping\n"); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + + if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) + dev_dbg(pdev, "tda18212 ping 1 fail\n"); + if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) + dev_warn(pdev, "tda18212 ping failed, expect problems\n"); + + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); + + return 0; +} + +static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); + struct i2c_client *client; + struct tda18212_config config = { + .fe = chan->fe, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, + }; + u8 addr = (chan->number & 1) ? 0x63 : 0x60; + + /* + * due to a hardware quirk with the I2C gate on the stv0367+tda18212 + * combo, the tda18212 must be probed by reading it's id _twice_ when + * cold started, or it very likely will fail. + */ + if (dmdtype == DEMOD_TYPE_STV0367) + tuner_tda18212_ping(chan, i2c, addr); + + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, i2c, addr, &config); + if (!client) + goto err; + + chan->i2c_client[0] = client; + chan->i2c_client_fe = 1; + + return 0; +err: + dev_err(pdev, "TDA18212 tuner not found. Device is not fully operational.\n"); + return -ENODEV; +} + static int tuner_attach_probe(struct ngene_channel *chan) { - if (chan->demod_type == 0) + switch (chan->demod_type) { + case DEMOD_TYPE_STV090X: return tuner_attach_stv6110(chan); - if (chan->demod_type == 1) + case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); + case DEMOD_TYPE_STV0367: + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: + return tuner_attach_tda18212(chan, chan->demod_type); + case DEMOD_TYPE_STV0910: + return tuner_attach_stv6111(chan); + } + return -EINVAL; } static int demod_attach_stv0900(struct ngene_channel *chan) { - struct i2c_adapter *i2c; + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -144,7 +316,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 : STV090x_DEMODULATOR_1); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + dev_err(pdev, "No STV0900 found!\n"); return -ENODEV; } @@ -154,7 +326,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dev_err(pdev, "No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); chan->fe = NULL; return -ENODEV; @@ -163,6 +335,119 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 30000000, +}; + +static struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1)); + if (!chan->fe) { + cfg.adr = 0x6c; + chan->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (chan->number & 1)); + } + if (!chan->fe) { + dev_err(pdev, "stv0910_attach() failed!\n"); + return -ENODEV; + } + + /* + * attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit + * i2c addresses + */ + lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + dev_err(pdev, "lnbh25_attach() failed!\n"); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + return -ENODEV; + } + } + + return 0; +} + +static struct stv0367_config ddb_stv0367_config[] = { + { + .demod_address = 0x1f, + .xtal = 27000000, + .if_khz = 0, + .if_iq_mode = FE_TER_NORMAL_IF_TUNER, + .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, + .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, + }, { + .demod_address = 0x1e, + .xtal = 27000000, + .if_khz = 0, + .if_iq_mode = FE_TER_NORMAL_IF_TUNER, + .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, + .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, + }, +}; + +static int demod_attach_stv0367(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + + chan->fe = dvb_attach(stv0367ddb_attach, + &ddb_stv0367_config[(chan->number & 1)], i2c); + + if (!chan->fe) { + dev_err(pdev, "stv0367ddb_attach() failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + +static int demod_attach_cxd28xx(struct ngene_channel *chan, + struct i2c_adapter *i2c, int osc24) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct cxd2841er_config cfg; + + /* the cxd2841er driver expects 8bit/shifted I2C addresses */ + cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1; + + cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500; + cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE | + CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG | + CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL; + + /* attach frontend */ + chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + + if (!chan->fe) { + dev_err(pdev, "CXD28XX attach failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) { struct ngene_channel *chan = fe->analog_demod_priv; @@ -173,44 +458,61 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) up(&chan->dev->pll_mutex); } -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +static int port_has_stv0900(struct i2c_adapter *i2c, int port) { - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; + u8 val; + if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) + return 0; + return 1; } -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) +static int port_has_drxk(struct i2c_adapter *i2c, int port) { - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; + u8 val; + + if (i2c_read(i2c, 0x29+port, &val) < 0) + return 0; + return 1; } -static int port_has_stv0900(struct i2c_adapter *i2c, int port) +static int port_has_stv0367(struct i2c_adapter *i2c) { u8 val; - if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) + + if (i2c_read_reg16(i2c, 0x1e, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + if (i2c_read_reg16(i2c, 0x1f, 0xf000, &val) < 0) + return 0; + if (val != 0x60) return 0; return 1; } -static int port_has_drxk(struct i2c_adapter *i2c, int port) +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type) { u8 val; - - if (i2c_read(i2c, 0x29+port, &val) < 0) + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(i2c, msgs, 2); + if (val != 2) return 0; + + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; return 1; } static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxk_config config; memset(&config, 0, sizeof(config)); @@ -220,7 +522,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { - printk(KERN_ERR "No DRXK found!\n"); + dev_err(pdev, "No DRXK found!\n"); return -ENODEV; } chan->fe->sec_priv = chan; @@ -229,22 +531,153 @@ static int demod_attach_drxk(struct ngene_channel *chan, return 0; } +/****************************************************************************/ +/* XO2 related lists and functions ******************************************/ +/****************************************************************************/ + +static char *xo2names[] = { + "DUAL DVB-S2", + "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", + "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", + "DUAL DVB-C/C2/T/T2/I", +}; + +static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 addr = 0x10; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, addr, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number); + return -1; + } + + i2c_read_reg(i2c, addr, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, addr, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, addr, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, addr, 0x08, 0x07); + + /* + * speed: 0=55,1=75,2=90,3=104 MBit/s + * Note: The ngene hardware must be run at 75 MBit/s compared + * to more modern ddbridge hardware which runs at 90 MBit/s, + * else there will be issues with the data transport and non- + * working secondary/slave demods/tuners. + */ + i2c_write_reg(i2c, addr, 0x09, 1); + + i2c_write_reg(i2c, addr, 0x0a, 0x01); + i2c_write_reg(i2c, addr, 0x0b, 0x01); + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, addr, 0x08, 0x87); + + return 0; +} + +static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + u8 addr = 0x10; + + *type = NGENE_XO2_TYPE_NONE; + + if (i2c_io(i2c, addr, probe, 1, data, 4)) + return 0; + if (data[0] == 'D' && data[1] == 'F') { + *id = data[2]; + *type = NGENE_XO2_TYPE_DUOFLEX; + return 1; + } + if (data[0] == 'C' && data[1] == 'I') { + *id = data[2]; + *type = NGENE_XO2_TYPE_CI; + return 1; + } + return 0; +} + +/****************************************************************************/ +/* Probing and port/channel handling ****************************************/ +/****************************************************************************/ + static int cineS2_probe(struct ngene_channel *chan) { - struct i2c_adapter *i2c; + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *fe_conf; u8 buf[3]; + u8 xo2_type, xo2_id, xo2_demodtype; + u8 sony_osc24 = 0; struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - if (port_has_stv0900(i2c, chan->number)) { - chan->demod_type = 0; + if (port_has_xo2(i2c, &xo2_type, &xo2_id)) { + xo2_id >>= 2; + dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n", + chan->number, xo2_type, xo2_id); + + switch (xo2_type) { + case NGENE_XO2_TYPE_DUOFLEX: + if (chan->number & 1) + dev_dbg(pdev, + "skipping XO2 init on odd channel %d", + chan->number); + else + init_xo2(chan, i2c); + + xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id; + + switch (xo2_demodtype) { + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: + dev_info(pdev, "%s (XO2) on channel %d\n", + xo2names[xo2_id], chan->number); + chan->demod_type = xo2_demodtype; + if (xo2_demodtype == DEMOD_TYPE_SONY_C2T2I) + sony_osc24 = 1; + + demod_attach_cxd28xx(chan, i2c, sony_osc24); + break; + case DEMOD_TYPE_STV0910: + dev_info(pdev, "%s (XO2) on channel %d\n", + xo2names[xo2_id], chan->number); + chan->demod_type = xo2_demodtype; + demod_attach_stv0910(chan, i2c); + break; + default: + dev_warn(pdev, + "Unsupported XO2 module on channel %d\n", + chan->number); + return -ENODEV; + } + break; + case NGENE_XO2_TYPE_CI: + dev_info(pdev, "DuoFlex CI modules not supported\n"); + return -ENODEV; + default: + dev_info(pdev, "Unsupported XO2 module type\n"); + return -ENODEV; + } + } else if (port_has_stv0900(i2c, chan->number)) { + chan->demod_type = DEMOD_TYPE_STV090X; fe_conf = chan->dev->card_info->fe_config[chan->number]; /* demod found, attach it */ rc = demod_attach_stv0900(chan); @@ -269,14 +702,18 @@ static int cineS2_probe(struct ngene_channel *chan) } rc = i2c_transfer(i2c, &i2c_msg, 1); if (rc != 1) { - printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + dev_err(pdev, "Could not setup DPNx\n"); return -EIO; } } else if (port_has_drxk(i2c, chan->number^2)) { - chan->demod_type = 1; + chan->demod_type = DEMOD_TYPE_DRXK; demod_attach_drxk(chan, i2c); + } else if (port_has_stv0367(i2c)) { + chan->demod_type = DEMOD_TYPE_STV0367; + dev_info(pdev, "STV0367 on channel %d\n", chan->number); + demod_attach_stv0367(chan, i2c); } else { - printk(KERN_ERR "No demod found on chan %d\n", chan->number); + dev_info(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; } return 0; @@ -299,9 +736,11 @@ static struct mt2131_config m780_tunerconfig = { */ static int demod_attach_lg330x(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); + dev_err(pdev, "No LGDT330x found!\n"); return -ENODEV; } @@ -313,6 +752,7 @@ static int demod_attach_lg330x(struct ngene_channel *chan) static int demod_attach_drxd(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxd_config *feconf; feconf = chan->dev->card_info->fe_config[chan->number]; @@ -320,7 +760,7 @@ static int demod_attach_drxd(struct ngene_channel *chan) chan->fe = dvb_attach(drxd_attach, feconf, chan, &chan->i2c_adapter, &chan->dev->pci_dev->dev); if (!chan->fe) { - pr_err("No DRXD found!\n"); + dev_err(pdev, "No DRXD found!\n"); return -ENODEV; } return 0; @@ -328,6 +768,7 @@ static int demod_attach_drxd(struct ngene_channel *chan) static int tuner_attach_dtt7520x(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxd_config *feconf; feconf = chan->dev->card_info->fe_config[chan->number]; @@ -335,7 +776,7 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan) if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, &chan->i2c_adapter, feconf->pll_type)) { - pr_err("No pll(%d) found!\n", feconf->pll_type); + dev_err(pdev, "No pll(%d) found!\n", feconf->pll_type); return -ENODEV; } return 0; @@ -371,12 +812,13 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan) static int i2c_write_eeprom(struct i2c_adapter *adapter, u8 adr, u16 reg, u8 data) { + struct device *pdev = adapter->dev.parent; u8 m[3] = {(reg >> 8), (reg & 0xff), data}; struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = sizeof(m)}; if (i2c_transfer(adapter, &msg, 1) != 1) { - pr_err(DEVICE_NAME ": Error writing EEPROM!\n"); + dev_err(pdev, "Error writing EEPROM!\n"); return -EIO; } return 0; @@ -385,6 +827,7 @@ static int i2c_write_eeprom(struct i2c_adapter *adapter, static int i2c_read_eeprom(struct i2c_adapter *adapter, u8 adr, u16 reg, u8 *data, int len) { + struct device *pdev = adapter->dev.parent; u8 msg[2] = {(reg >> 8), (reg & 0xff)}; struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, .buf = msg, .len = 2 }, @@ -392,7 +835,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter, .buf = data, .len = len} }; if (i2c_transfer(adapter, msgs, 2) != 2) { - pr_err(DEVICE_NAME ": Error reading EEPROM\n"); + dev_err(pdev, "Error reading EEPROM\n"); return -EIO; } return 0; @@ -401,6 +844,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter, static int ReadEEProm(struct i2c_adapter *adapter, u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) { + struct device *pdev = adapter->dev.parent; int status = 0; u16 Addr = MICNG_EE_START, Length, tag = 0; u8 EETag[3]; @@ -416,9 +860,8 @@ static int ReadEEProm(struct i2c_adapter *adapter, Addr += sizeof(u16) + 1 + EETag[2]; } if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); + dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); return -1; } Length = EETag[2]; @@ -441,6 +884,7 @@ static int ReadEEProm(struct i2c_adapter *adapter, static int WriteEEProm(struct i2c_adapter *adapter, u16 Tag, u32 Length, u8 *data) { + struct device *pdev = adapter->dev.parent; int status = 0; u16 Addr = MICNG_EE_START; u8 EETag[3]; @@ -458,9 +902,8 @@ static int WriteEEProm(struct i2c_adapter *adapter, Addr += sizeof(u16) + 1 + EETag[2]; } if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); + dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); return -1; } @@ -487,13 +930,11 @@ static int WriteEEProm(struct i2c_adapter *adapter, if (status) break; if (Tmp != data[i]) - pr_err(DEVICE_NAME - "eeprom write error\n"); + dev_err(pdev, "eeprom write error\n"); retry -= 1; } if (status) { - pr_err(DEVICE_NAME - ": Timeout polling eeprom\n"); + dev_err(pdev, "Timeout polling eeprom\n"); break; } } @@ -532,19 +973,20 @@ static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) static s16 osc_deviation(void *priv, s16 deviation, int flag) { struct ngene_channel *chan = priv; + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *adap = &chan->i2c_adapter; u16 data = 0; if (flag) { data = (u16) deviation; - pr_info(DEVICE_NAME ": write deviation %d\n", - deviation); + dev_info(pdev, "write deviation %d\n", + deviation); eeprom_write_ushort(adap, 0x1000 + chan->number, data); } else { if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) data = 0; - pr_info(DEVICE_NAME ": read deviation %d\n", - (s16) data); + dev_info(pdev, "read deviation %d\n", + (s16)data); } return (s16) data; @@ -749,6 +1191,8 @@ static const struct ngene_info ngene_info_terratec = { /****************************************************************************/ static const struct pci_device_id ngene_id_tbl[] = { + NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5), NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), @@ -769,7 +1213,7 @@ MODULE_DEVICE_TABLE(pci, ngene_id_tbl); static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, enum pci_channel_state state) { - printk(KERN_ERR DEVICE_NAME ": PCI error\n"); + dev_err(&dev->dev, "PCI error\n"); if (state == pci_channel_io_perm_failure) return PCI_ERS_RESULT_DISCONNECT; if (state == pci_channel_io_frozen) @@ -779,13 +1223,13 @@ static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) { - printk(KERN_INFO DEVICE_NAME ": slot reset\n"); + dev_info(&dev->dev, "slot reset\n"); return 0; } static void ngene_resume(struct pci_dev *dev) { - printk(KERN_INFO DEVICE_NAME ": resume\n"); + dev_info(&dev->dev, "resume\n"); } static const struct pci_error_handlers ngene_errors = { @@ -805,8 +1249,9 @@ static struct pci_driver ngene_pci_driver = { static __init int module_init_ngene(void) { - printk(KERN_INFO - "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + /* pr_*() since we don't have a device to use with dev_*() yet */ + pr_info("nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + return pci_register_driver(&ngene_pci_driver); } diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 8c92cb7f7e72..25f16833a475 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -51,8 +51,6 @@ MODULE_PARM_DESC(debug, "Print debugging information."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk if (debug) printk - #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) #define ngwritel(dat, adr) writel((dat), dev->iomem + (adr)) #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) @@ -86,6 +84,7 @@ static void event_tasklet(unsigned long data) static void demux_tasklet(unsigned long data) { struct ngene_channel *chan = (struct ngene_channel *)data; + struct device *pdev = &chan->dev->pci_dev->dev; struct SBufferHeader *Cur = chan->nextBuffer; spin_lock_irq(&chan->state_lock); @@ -124,16 +123,15 @@ static void demux_tasklet(unsigned long data) chan->HWState = HWSTATE_RUN; } } else { - printk(KERN_ERR DEVICE_NAME ": OOPS\n"); + dev_err(pdev, "OOPS\n"); if (chan->HWState == HWSTATE_RUN) { Cur->ngeneBuffer.SR.Flags &= ~0x40; break; /* Stop processing stream */ } } if (chan->AudioDTOUpdated) { - printk(KERN_INFO DEVICE_NAME - ": Update AudioDTO = %d\n", - chan->AudioDTOValue); + dev_info(pdev, "Update AudioDTO = %d\n", + chan->AudioDTOValue); Cur->ngeneBuffer.SR.DTOUpdate = chan->AudioDTOValue; chan->AudioDTOUpdated = 0; @@ -173,6 +171,7 @@ static void demux_tasklet(unsigned long data) static irqreturn_t irq_handler(int irq, void *dev_id) { struct ngene *dev = (struct ngene *)dev_id; + struct device *pdev = &dev->pci_dev->dev; u32 icounts = 0; irqreturn_t rc = IRQ_NONE; u32 i = MAX_STREAM; @@ -213,7 +212,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id) *(dev->EventBuffer); dev->EventQueueWriteIndex = nextWriteIndex; } else { - printk(KERN_ERR DEVICE_NAME ": event overflow\n"); + dev_err(pdev, "event overflow\n"); dev->EventQueueOverflowCount += 1; dev->EventQueueOverflowFlag = 1; } @@ -249,23 +248,25 @@ static irqreturn_t irq_handler(int irq, void *dev_id) static void dump_command_io(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; u8 buf[8], *b; ngcpyfrom(buf, HOST_TO_NGENE, 8); - printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); + dev_err(pdev, "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); ngcpyfrom(buf, NGENE_TO_HOST, 8); - printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); + dev_err(pdev, "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); b = dev->hosttongene; - printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); + dev_err(pdev, "dev->hosttongene (%p): %*ph\n", b, 8, b); b = dev->ngenetohost; - printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); + dev_err(pdev, "dev->ngenetohost (%p): %*ph\n", b, 8, b); } static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) { + struct device *pdev = &dev->pci_dev->dev; int ret; u8 *tmpCmdDoneByte; @@ -313,9 +314,8 @@ static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) if (!ret) { /*ngwritel(0, FORCE_NMI);*/ - printk(KERN_ERR DEVICE_NAME - ": Command timeout cmd=%02x prev=%02x\n", - com->cmd.hdr.Opcode, dev->prev_cmd); + dev_err(pdev, "Command timeout cmd=%02x prev=%02x\n", + com->cmd.hdr.Opcode, dev->prev_cmd); dump_command_io(dev); return -1; } @@ -553,6 +553,7 @@ static void clear_buffers(struct ngene_channel *chan) static int ngene_command_stream_control(struct ngene *dev, u8 stream, u8 control, u8 mode, u8 flags) { + struct device *pdev = &dev->pci_dev->dev; struct ngene_channel *chan = &dev->channel[stream]; struct ngene_command com; u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); @@ -572,8 +573,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, com.in_len = sizeof(struct FW_STREAM_CONTROL); com.out_len = 0; - dprintk(KERN_INFO DEVICE_NAME - ": Stream=%02x, Control=%02x, Mode=%02x\n", + dev_dbg(pdev, "Stream=%02x, Control=%02x, Mode=%02x\n", com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, com.cmd.StreamControl.Mode); @@ -695,23 +695,24 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, void set_transfer(struct ngene_channel *chan, int state) { + struct device *pdev = &chan->dev->pci_dev->dev; u8 control = 0, mode = 0, flags = 0; struct ngene *dev = chan->dev; int ret; /* - printk(KERN_INFO DEVICE_NAME ": st %d\n", state); + dev_info(pdev, "st %d\n", state); msleep(100); */ if (state) { if (chan->running) { - printk(KERN_INFO DEVICE_NAME ": already running\n"); + dev_info(pdev, "already running\n"); return; } } else { if (!chan->running) { - printk(KERN_INFO DEVICE_NAME ": already stopped\n"); + dev_info(pdev, "already stopped\n"); return; } } @@ -722,7 +723,7 @@ void set_transfer(struct ngene_channel *chan, int state) if (state) { spin_lock_irq(&chan->state_lock); - /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + /* dev_info(pdev, "lock=%08x\n", ngreadl(0x9310)); */ dvb_ringbuffer_flush(&dev->tsout_rbuf); control = 0x80; @@ -740,7 +741,7 @@ void set_transfer(struct ngene_channel *chan, int state) chan->pBufferExchange = tsin_exchange; spin_unlock_irq(&chan->state_lock); } - /* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + /* else dev_info(pdev, "lock=%08x\n", ngreadl(0x9310)); */ mutex_lock(&dev->stream_mutex); @@ -751,8 +752,7 @@ void set_transfer(struct ngene_channel *chan, int state) if (!ret) chan->running = state; else - printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", - state); + dev_err(pdev, "%s %d failed\n", __func__, state); if (!state) { spin_lock_irq(&chan->state_lock); chan->pBufferExchange = NULL; @@ -1195,6 +1195,7 @@ static int ngene_get_buffers(struct ngene *dev) static void ngene_init(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; int i; tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); @@ -1214,12 +1215,12 @@ static void ngene_init(struct ngene *dev) dev->icounts = ngreadl(NGENE_INT_COUNTS); dev->device_version = ngreadl(DEV_VER) & 0x0f; - printk(KERN_INFO DEVICE_NAME ": Device version %d\n", - dev->device_version); + dev_info(pdev, "Device version %d\n", dev->device_version); } static int ngene_load_firm(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; u32 size; const struct firmware *fw = NULL; u8 *ngene_fw; @@ -1253,21 +1254,18 @@ static int ngene_load_firm(struct ngene *dev) } if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { - printk(KERN_ERR DEVICE_NAME - ": Could not load firmware file %s.\n", fw_name); - printk(KERN_INFO DEVICE_NAME - ": Copy %s to your hotplug directory!\n", fw_name); + dev_err(pdev, "Could not load firmware file %s.\n", fw_name); + dev_info(pdev, "Copy %s to your hotplug directory!\n", + fw_name); return -1; } if (size == 0) size = fw->size; if (size != fw->size) { - printk(KERN_ERR DEVICE_NAME - ": Firmware %s has invalid size!", fw_name); + dev_err(pdev, "Firmware %s has invalid size!", fw_name); err = -1; } else { - printk(KERN_INFO DEVICE_NAME - ": Loading firmware file %s.\n", fw_name); + dev_info(pdev, "Loading firmware file %s.\n", fw_name); ngene_fw = (u8 *) fw->data; err = ngene_command_load_firmware(dev, ngene_fw, size); } @@ -1360,14 +1358,14 @@ static int ngene_start(struct ngene *dev) #ifdef CONFIG_PCI_MSI /* enable MSI if kernel and card support it */ if (pci_msi_enabled() && dev->card_info->msi_supported) { + struct device *pdev = &dev->pci_dev->dev; unsigned long flags; ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); stat = pci_enable_msi(dev->pci_dev); if (stat) { - printk(KERN_INFO DEVICE_NAME - ": MSI not available\n"); + dev_info(pdev, "MSI not available\n"); flags = IRQF_SHARED; } else { flags = 0; @@ -1426,6 +1424,13 @@ static void release_channel(struct ngene_channel *chan) if (chan->fe) { dvb_unregister_frontend(chan->fe); + + /* release I2C client (tuner) if needed */ + if (chan->i2c_client_fe) { + dvb_module_release(chan->i2c_client[0]); + chan->i2c_client[0] = NULL; + } + dvb_frontend_detach(chan->fe); chan->fe = NULL; } @@ -1461,6 +1466,7 @@ static int init_channel(struct ngene_channel *chan) chan->users = 0; chan->type = io; chan->mode = chan->type; /* for now only one mode */ + chan->i2c_client_fe = 0; /* be sure this is set to zero */ if (io & NGENE_IO_TSIN) { chan->fe = NULL; @@ -1562,19 +1568,46 @@ static int init_channels(struct ngene *dev) return 0; } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 62000, - .adr = 0x40, .polarity = 0, .clock_mode = 0, }; static void cxd_attach(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; struct ngene_ci *ci = &dev->ci; + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + int ret; + u8 type; + + /* check for CXD2099AR presence before attaching */ + ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type); + if (!ret) { + dev_dbg(pdev, "No CXD2099AR found\n"); + return; + } + + if (type != 1) { + dev_warn(pdev, "CXD2099AR is uninitialized!\n"); + return; + } + + cxd_cfg.en = &ci->en; + client = dvb_module_probe("cxd2099", NULL, + &dev->channel[0].i2c_adapter, + 0x40, &cxd_cfg); + if (!client) + goto err; - ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); ci->dev = dev; + dev->channel[0].i2c_client[0] = client; + return; + +err: + dev_err(pdev, "CXD2099AR attach failed\n"); return; } @@ -1583,7 +1616,9 @@ static void cxd_detach(struct ngene *dev) struct ngene_ci *ci = &dev->ci; dvb_ca_en50221_release(ci->en); - kfree(ci->en); + + dvb_module_release(dev->channel[0].i2c_client[0]); + dev->channel[0].i2c_client[0] = NULL; ci->en = NULL; } @@ -1615,7 +1650,7 @@ void ngene_shutdown(struct pci_dev *pdev) if (!dev || !shutdown_workaround) return; - printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + dev_info(&pdev->dev, "shutdown workaround...\n"); ngene_unlink(dev); pci_disable_device(pdev); } @@ -1655,7 +1690,7 @@ int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) dev->pci_dev = pci_dev; dev->card_info = (struct ngene_info *)id->driver_data; - printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); + dev_info(&pci_dev->dev, "Found %s\n", dev->card_info->name); pci_set_drvdata(pci_dev, dev); diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 03fc218a45e9..fee89b9ed9c1 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #include "ngene.h" +static int ci_tsfix = 1; +module_param(ci_tsfix, int, 0444); +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); /****************************************************************************/ /* COMMAND API interface ****************************************************/ @@ -84,18 +87,41 @@ static ssize_t ts_read(struct file *file, char __user *buf, return count; } +static __poll_t ts_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf; + struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf; + __poll_t mask = 0; + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= EPOLLIN | EPOLLRDNORM; + if (dvb_ringbuffer_free(wbuf) >= 188) + mask |= EPOLLOUT | EPOLLWRNORM; + + return mask; +} + static const struct file_operations ci_fops = { .owner = THIS_MODULE, .read = ts_read, .write = ts_write, .open = dvb_generic_open, .release = dvb_generic_release, + .poll = ts_poll, + .mmap = NULL, }; struct dvb_device ngene_dvbdev_ci = { - .readers = -1, - .writers = -1, - .users = -1, + .priv = NULL, + .readers = 1, + .writers = 1, + .users = 2, .fops = &ci_fops, }; @@ -116,47 +142,118 @@ static void swap_buffer(u32 *p, u32 len) /* start of filler packet */ static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; -/* #define DEBUG_CI_XFER */ -#ifdef DEBUG_CI_XFER -static u32 ok; -static u32 overflow; -static u32 stripped; -#endif +static int tsin_find_offset(void *buf, u32 len) +{ + int i, l; + + l = len - sizeof(fill_ts); + if (l <= 0) + return -1; + + for (i = 0; i < l; i++) { + if (((char *)buf)[i] == 0x47) { + if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) + return i % 188; + } + } + + return -1; +} + +static inline void tsin_copy_stripped(struct ngene *dev, void *buf) +{ + if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); + } + } +} void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; struct ngene *dev = chan->dev; - + int tsoff; if (flags & DF_SWAP32) swap_buffer(buf, len); if (dev->ci.en && chan->number == 2) { + /* blindly copy buffers if ci_tsfix is disabled */ + if (!ci_tsfix) { + while (len >= 188) { + tsin_copy_stripped(dev, buf); + + buf += 188; + len -= 188; + } + return NULL; + } + + /* ci_tsfix = 1 */ + + /* + * since the remainder of the TS packet which got cut off + * in the previous tsin_exchange() run is at the beginning + * of the new TS buffer, append this to the temp buffer and + * send it to the DVB ringbuffer afterwards. + */ + if (chan->tsin_offset) { + memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)], + buf, chan->tsin_offset); + tsin_copy_stripped(dev, &chan->tsin_buffer); + + buf += chan->tsin_offset; + len -= chan->tsin_offset; + } + + /* + * copy TS packets to the DVB ringbuffer and detect new offset + * shifts by checking for a valid TS SYNC byte + */ while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif + if (*((char *)buf) != 0x47) { + /* + * no SYNC header, find new offset shift + * (max. 188 bytes, tsoff will be mod 188) + */ + tsoff = tsin_find_offset(buf, len); + if (tsoff > 0) { + chan->tsin_offset += tsoff; + chan->tsin_offset %= 188; + + buf += tsoff; + len -= tsoff; + + dev_info(&dev->pci_dev->dev, + "%s(): tsin_offset shift by %d on channel %d\n", + __func__, tsoff, + chan->number); + + /* + * offset corrected. re-check remaining + * len for a full TS frame, break and + * skip to fragment handling if < 188. + */ + if (len < 188) + break; } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif } -#ifdef DEBUG_CI_XFER - else - stripped++; - if (ok % 100 == 0 && overflow) - printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); -#endif + tsin_copy_stripped(dev, buf); + buf += 188; len -= 188; } + + /* + * if a fragment is left, copy to temp buffer. The remainder + * will be appended in the next tsin_exchange() iteration. + */ + if (len > 0 && len < 188) + memcpy(&chan->tsin_buffer, buf, len); + return NULL; } diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index 3004947f300b..092d46c2a3a9 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -147,7 +147,7 @@ done: static u32 ngene_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm ngene_i2c_algo = { diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 02dbd18f92d0..01d9f1b58fcb 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -51,6 +51,22 @@ #define VIDEO_CAP_MPEG4 512 #endif +#define DEMOD_TYPE_STV090X 0 +#define DEMOD_TYPE_DRXK 1 +#define DEMOD_TYPE_STV0367 2 + +#define DEMOD_TYPE_XO2 32 +#define DEMOD_TYPE_STV0910 (DEMOD_TYPE_XO2 + 0) +#define DEMOD_TYPE_SONY_CT2 (DEMOD_TYPE_XO2 + 1) +#define DEMOD_TYPE_SONY_ISDBT (DEMOD_TYPE_XO2 + 2) +#define DEMOD_TYPE_SONY_C2T2 (DEMOD_TYPE_XO2 + 3) +#define DEMOD_TYPE_ST_ATSC (DEMOD_TYPE_XO2 + 4) +#define DEMOD_TYPE_SONY_C2T2I (DEMOD_TYPE_XO2 + 5) + +#define NGENE_XO2_TYPE_NONE 0 +#define NGENE_XO2_TYPE_DUOFLEX 1 +#define NGENE_XO2_TYPE_CI 2 + enum STREAM { STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ STREAM_VIDEOIN2, @@ -630,6 +646,8 @@ struct ngene_vopen { struct ngene_channel { struct device device; struct i2c_adapter i2c_adapter; + struct i2c_client *i2c_client[1]; + int i2c_client_fe; struct ngene *dev; int number; @@ -714,6 +732,9 @@ struct ngene_channel { #endif int running; + + int tsin_offset; + u8 tsin_buffer[188]; }; @@ -891,6 +912,9 @@ int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); void set_transfer(struct ngene_channel *chan, int state); void FillTSBuffer(void *Buffer, int Length, u32 Flags); +/* Provided by ngene-cards.c */ +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type); + /* Provided by ngene-i2c.c */ int ngene_i2c_init(struct ngene *dev, int dev_nr); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index c59b69f1af9d..72311445d13d 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -273,9 +273,8 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages) return -ENOMEM; } - pr_debug("vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vaddr, - nr_pages << PAGE_SHIFT); + pr_debug("vmalloc is at addr %p, size=%d\n", + dma->vaddr, nr_pages << PAGE_SHIFT); memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index a7a63d608dde..3025d38ddb2b 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1195,7 +1195,7 @@ static struct s5h1411_config kworld_s5h1411_config = { .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, .mpeg_timing = - S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 33ee8322895e..0e28c5021ac4 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -115,7 +115,7 @@ static int build_key(struct saa7134_dev *dev) static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { - int gpio; + int gpio, rc; int attempt = 0; unsigned char b; @@ -153,8 +153,11 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, attempt); return -EIO; } - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -169,7 +172,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *scancode, u8 *toggle) { unsigned char b; - int gpio; + int gpio, rc; /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; @@ -193,8 +196,11 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -218,6 +224,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, { unsigned char b; unsigned int gpio; + int rc; /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; @@ -241,8 +248,11 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -263,11 +273,15 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -288,11 +302,17 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char buf[5]; /* poll IR chip */ - if (5 != i2c_master_recv(ir->c, buf, 5)) + rc = i2c_master_recv(ir->c, buf, 5); + if (rc != 5) { + ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; + } /* Check if some key were pressed */ if (!(buf[0] & 0x80)) @@ -319,6 +339,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char data[12]; u32 gpio; @@ -335,8 +356,11 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, ir->c->addr = 0x5a >> 1; - if (12 != i2c_master_recv(ir->c, data, 12)) { + rc = i2c_master_recv(ir->c, data, 12); + if (rc != 12) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -356,12 +380,16 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle, int parity_offset, int marker, int code_modulo) { + int rc; unsigned char b[4]; unsigned int start = 0,parity = 0,code = 0; /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, b, 4)) { + rc = i2c_master_recv(ir->c, b, 4); + if (rc != 4) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1ca6a32ad10e..4f1091a11e91 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1200,7 +1200,7 @@ static int video_release(struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - saa_call_all(dev, core, s_power, 0); + saa_call_all(dev, tuner, standby); if (vdev->vfl_type == VFL_TYPE_RADIO) saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd); mutex_unlock(&dev->lock); diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index e76d3bafe2ce..4f9f03c3b252 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -78,7 +78,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = { .vsb_if = S5H1411_IF_3250, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct lgdt3306a_config hauppauge_hvr2255a_config = { diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 81be1b8df758..2ac33b5cc454 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) return idx * G723_FRAMES_PER_PAGE; } -static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, - unsigned long pos, void *dst, - unsigned long count, bool in_kernel) +static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void __user *dst, + unsigned long count) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo_dev *solo_dev = solo_pcm->solo_dev; @@ -242,10 +242,7 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, if (err) return err; - if (in_kernel) - memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); - else if (copy_to_user((void __user *)dst, - solo_pcm->g723_buf, G723_PERIOD_BYTES)) + if (copy_to_user(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES)) return -EFAULT; dst += G723_PERIOD_BYTES; } @@ -253,18 +250,30 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, return 0; } -static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, - unsigned long pos, void __user *dst, - unsigned long count) -{ - return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false); -} - static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel, unsigned long pos, void *dst, unsigned long count) { - return __snd_solo_pcm_copy(ss, pos, dst, count, true); + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + struct solo_dev *solo_dev = solo_pcm->solo_dev; + int err, i; + + for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { + int page = (pos / G723_FRAMES_PER_PAGE) + i; + + err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, + SOLO_G723_EXT_ADDR(solo_dev) + + (page * G723_PERIOD_BLOCK) + + (ss->number * G723_PERIOD_BYTES), + G723_PERIOD_BYTES, 0, 0); + if (err) + return err; + + memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); + dst += G723_PERIOD_BYTES; + } + + return 0; } static const struct snd_pcm_ops snd_solo_pcm_ops = { diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c index 8c8484674d2f..46c30430e30b 100644 --- a/drivers/media/pci/solo6x10/solo6x10-p2m.c +++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c @@ -69,14 +69,11 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev, unsigned int timeout; unsigned int config = 0; int ret = 0; - int p2m_id = 0; + unsigned int p2m_id = 0; /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ - if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { + if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; - if (p2m_id < 0) - p2m_id = -p2m_id; - } p2m_dev = &solo_dev->p2m_dev[p2m_id]; diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 9534f29c1ffd..78c7a6589be5 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -138,7 +138,7 @@ static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encode int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) { - int ret, i; + int ret; u8 encodedMAC[20]; u8 decodedMAC[6]; @@ -153,11 +153,8 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) ret = getmac_tt(decodedMAC, encodedMAC); if( ret != 0 ) { dprintk("adapter failed MAC signature check\n"); - dprintk("encoded MAC from EEPROM was " ); - for(i=0; i<19; i++) { - dprintk( "%.2x:", encodedMAC[i]); - } - dprintk("%.2x\n", encodedMAC[19]); + dprintk("encoded MAC from EEPROM was %*phC", + (int)sizeof(encodedMAC), &encodedMAC); eth_zero_addr(proposed_mac); return ret; } diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 8d4e7d930a66..14f9c0e26a1c 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -241,8 +241,8 @@ static int v4l_fbuffer_alloc(struct zoran_fh *fh) SetPageReserved(virt_to_page(mem + off)); dprintk(4, KERN_INFO - "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n", - ZR_DEVNAME(zr), __func__, i, (unsigned long) mem, + "%s: %s - V4L frame %d mem %p (bus: 0x%llx)\n", + ZR_DEVNAME(zr), __func__, i, mem, (unsigned long long)virt_to_bus(mem)); } diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6df9ec377482..c7a1cf8a1b01 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -122,6 +122,15 @@ config VIDEO_STM32_DCMI To compile this driver as a module, choose M here: the module will be called stm32-dcmi. +config VIDEO_RENESAS_CEU + tristate "Renesas Capture Engine Unit (CEU) driver" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + ---help--- + This is a v4l2 driver for the Renesas CEU Interface + source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/am437x/Kconfig" @@ -560,7 +569,7 @@ config CEC_GPIO config VIDEO_SAMSUNG_S5P_CEC tristate "Samsung S5P CEC driver" - depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on ARCH_EXYNOS || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER ---help--- diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index db96a3cb18dd..932515df4477 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o +obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 34676409ca08..d89e14524d42 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -335,7 +335,7 @@ static struct isc_format formats_list[] = { }, }; -struct fmt_config fmt_configs_list[] = { +static struct fmt_config fmt_configs_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, @@ -1417,20 +1417,14 @@ static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 9958918e2449..e5be21a31640 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -689,22 +689,14 @@ static int isi_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index 5debdf08fbe7..f1f28cf5c751 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9fe113cb901f..68ed2a564ad1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -68,8 +68,9 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd) { struct coda_dev *dev = ctx->dev; - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_960) { /* Restore context related registers to CODA */ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -506,7 +507,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, goto err; } - if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) { + if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541)) { ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); if (ret < 0) @@ -594,6 +596,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) int dbk_bits; int bit_bits; int ip_bits; + int me_bits; memset(iram_info, 0, sizeof(*iram_info)); iram_info->next_paddr = dev->iram.paddr; @@ -603,15 +606,23 @@ static void coda_setup_iram(struct coda_ctx *ctx) return; switch (dev->devtype->product) { + case CODA_HX4: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE; + break; case CODA_7541: dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; break; case CODA_960: dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = 0; break; default: /* CODA_DX6 */ return; @@ -626,7 +637,8 @@ static void coda_setup_iram(struct coda_ctx *ctx) w64 = mb_width * 64; /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { iram_info->search_ram_size = round_up(mb_width * 16 * 36 + 2048, 1024); iram_info->search_ram_paddr = coda_iram_alloc(iram_info, @@ -635,8 +647,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) pr_err("IRAM is smaller than the search ram size\n"); goto out; } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; + iram_info->axi_sram_use |= me_bits; } /* Only H.264BP and H.263P3 are considered */ @@ -688,7 +699,8 @@ out: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "IRAM smaller than needed\n"); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { /* TODO - Enabling these causes picture errors on CODA7541 */ if (ctx->inst_type == CODA_INST_DECODER) { /* fw 1.4.50 */ @@ -706,6 +718,7 @@ out: static u32 coda_supported_firmwares[] = { CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), @@ -890,6 +903,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) case CODA_960: coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); /* fallthrough */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); @@ -919,6 +933,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; + case CODA_HX4: case CODA_7541: if (dst_fourcc == V4L2_PIX_FMT_H264) { value = (round_up(q_data_src->width, 16) & @@ -1086,6 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = FMO_SLICE_SAVE_BUF_SIZE << 7; coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); break; + case CODA_HX4: case CODA_7541: coda_write(dev, ctx->iram_info.search_ram_paddr, CODA7_CMD_ENC_SEQ_SEARCH_BASE); @@ -1131,7 +1147,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, q_data_src->bytesperline, CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); } @@ -1570,7 +1587,8 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; int profile, level; - if (dev->devtype->product != CODA_7541 && + if (dev->devtype->product != CODA_HX4 && + dev->devtype->product != CODA_7541 && dev->devtype->product != CODA_960) return false; @@ -1664,7 +1682,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); } if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, ctx->psbuf.paddr, CODA_CMD_DEC_SEQ_PS_BB_START); coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), @@ -1791,7 +1810,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_SET_FRAME_SLICE_BB_SIZE); } - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { int max_mb_x = 1920 / 16; int max_mb_y = 1088 / 16; int max_mb_num = max_mb_x * max_mb_y; @@ -1909,6 +1929,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) switch (dev->devtype->product) { case CODA_DX6: /* TBD */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); break; @@ -2049,7 +2070,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "errors in %d macroblocks\n", err_mb); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); if (val == 0) { /* not enough bitstream data */ diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index e8a7554a61d2..04e35d70ce2e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -128,7 +128,8 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, /* * Arrays of codecs supported by each given version of Coda: * i.MX27 -> codadx6 - * i.MX5x -> coda7 + * i.MX51 -> codahx4 + * i.MX53 -> coda7 * i.MX6 -> coda960 * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants */ @@ -137,6 +138,13 @@ static const struct coda_codec codadx6_codecs[] = { CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), }; +static const struct coda_codec codahx4_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), +}; + static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), @@ -234,6 +242,11 @@ static const struct coda_video_device *codadx6_video_devices[] = { &coda_bit_encoder, }; +static const struct coda_video_device *codahx4_video_devices[] = { + &coda_bit_encoder, + &coda_bit_decoder, +}; + static const struct coda_video_device *coda7_video_devices[] = { &coda_bit_jpeg_encoder, &coda_bit_jpeg_decoder, @@ -332,6 +345,8 @@ const char *coda_product_name(int product) switch (product) { case CODA_DX6: return "CodaDx6"; + case CODA_HX4: + return "CodaHx4"; case CODA_7541: return "CODA7541"; case CODA_960: @@ -1775,7 +1790,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); - if (ctx->dev->devtype->product == CODA_7541) { + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_3_1, @@ -1803,7 +1819,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); - if (ctx->dev->devtype->product == CODA_7541 || + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541 || ctx->dev->devtype->product == CODA_960) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, @@ -2004,6 +2021,7 @@ static int coda_open(struct file *file) if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; /* fallthrough */ + case CODA_HX4: case CODA_7541: ctx->reg_idx = 0; break; @@ -2182,7 +2200,8 @@ static int coda_hw_init(struct coda_dev *dev) /* Tell the BIT where to find everything it needs */ if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_HX4) { coda_write(dev, dev->tempbuf.paddr, CODA_REG_BIT_TEMP_BUF_ADDR); coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -2387,6 +2406,7 @@ put_pm: enum coda_platform { CODA_IMX27, + CODA_IMX51, CODA_IMX53, CODA_IMX6Q, CODA_IMX6DL, @@ -2407,6 +2427,21 @@ static const struct coda_devtype coda_devdata[] = { .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, .iram_size = 0xb000, }, + [CODA_IMX51] = { + .firmware = { + "vpu_fw_imx51.bin", + "vpu/vpu_fw_imx51.bin", + "v4l-codahx4-imx51.bin" + }, + .product = CODA_HX4, + .codecs = codahx4_codecs, + .num_codecs = ARRAY_SIZE(codahx4_codecs), + .vdevs = codahx4_video_devices, + .num_vdevs = ARRAY_SIZE(codahx4_video_devices), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, [CODA_IMX53] = { .firmware = { "vpu_fw_imx53.bin", @@ -2463,6 +2498,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids); #ifdef CONFIG_OF static const struct of_device_id coda_dt_ids[] = { { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, + { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c5f504d8cf67..c70cfab2433f 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -28,7 +28,7 @@ #include "coda_regs.h" -#define CODA_MAX_FRAMEBUFFERS 17 +#define CODA_MAX_FRAMEBUFFERS 19 #define FMO_SLICE_SAVE_BUF_SIZE (32) enum { @@ -43,6 +43,7 @@ enum coda_inst_type { enum coda_product { CODA_DX6 = 0xf001, + CODA_HX4 = 0xf00a, CODA_7541 = 0xf012, CODA_960 = 0xf020, }; diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index b73886519f4f..19cf6853411e 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -116,7 +116,7 @@ struct vpss_hw_ops { struct vpss_oper_config { __iomem void *vpss_regs_base0; __iomem void *vpss_regs_base1; - resource_size_t *vpss_regs_base2; + __iomem void *vpss_regs_base2; enum vpss_platform_type platform; spinlock_t vpss_lock; struct vpss_hw_ops hw_ops; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index ed9302caa004..a3cdac188190 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -670,10 +670,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, return; } if (target == V4L2_SEL_TGT_COMPOSE) { + u32 tmp_min_h = ffs(sink->width) - 3; + u32 tmp_min_v = ffs(sink->height) - 1; + if (ctx->rotation != 90 && ctx->rotation != 270) align_h = 1; - max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); - max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); + max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h); + max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v); min_sz = var->min_out_pixsize; } else { u32 depth = fimc_get_format_depth(sink->fmt); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index cfe4406a83ff..e0e291066037 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -159,7 +159,7 @@ void fimc_is_hw_load_setfile(struct fimc_is *is) int fimc_is_hw_change_mode(struct fimc_is *is) { - const u8 cmd[] = { + static const u8 cmd[] = { HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO, HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, }; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 7b7250b1cff8..80670eeee142 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1443,24 +1443,24 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) * the level which controls the number of read buffers. */ static int mcam_vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, g_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } static int mcam_vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, s_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 843510979ad8..86f0a7134365 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1224,6 +1224,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) ctx->dpb_size = dpbsize; ctx->state = MTK_STATE_HEADER; mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); + + mtk_vdec_queue_res_chg_event(ctx); } static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 123c2b26a933..1d8508237220 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -236,7 +236,6 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct dma_async_tx_descriptor *tx; enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_chan *chan = vout->vrfb_dma_tx.chan; - struct dma_device *dmadev = chan->device; struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt; dma_cookie_t cookie; enum dma_status status; @@ -271,7 +270,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, xt->dst_sgl = true; xt->dst_inc = true; - tx = dmadev->device_prep_interleaved_dma(chan, xt, flags); + tx = dmaengine_prep_interleaved_dma(chan, xt, flags); if (tx == NULL) { pr_err("%s: DMA interleaved prep error\n", __func__); return -EINVAL; diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index a681ae5381d6..90c93d9603dc 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -659,10 +659,10 @@ static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst, prop->buffer_type == HFI_BUFFER_OUTPUT2) { switch (prop->data[i]) { case HFI_BUFFER_MODE_STATIC: - inst->cap_bufs_mode_static = 1; + inst->cap_bufs_mode_static = true; break; case HFI_BUFFER_MODE_DYNAMIC: - inst->cap_bufs_mode_dynamic = 1; + inst->cap_bufs_mode_dynamic = true; break; default: break; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 23fdff7a7370..4a40e6ad1be7 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -168,12 +168,8 @@ static int rvin_setup(struct rvin_dev *vin) break; case V4L2_FIELD_ALTERNATE: case V4L2_FIELD_NONE: - if (vin->continuous) { - vnmc = VNMC_IM_ODD_EVEN; - progressive = true; - } else { - vnmc = VNMC_IM_ODD; - } + vnmc = VNMC_IM_ODD_EVEN; + progressive = true; break; default: vnmc = VNMC_IM_ODD; @@ -298,14 +294,6 @@ static bool rvin_capture_active(struct rvin_dev *vin) return rvin_read(vin, VNMS_REG) & VNMS_CA; } -static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms) -{ - if (vin->continuous) - return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; - - return 0; -} - static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) { if (vin->format.field == V4L2_FIELD_ALTERNATE) { @@ -344,76 +332,47 @@ static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) rvin_write(vin, offset, VNMB_REG(slot)); } -/* Moves a buffer from the queue to the HW slots */ -static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot) +/* + * Moves a buffer from the queue to the HW slot. If no buffer is + * available use the scratch buffer. The scratch buffer is never + * returned to userspace, its only function is to enable the capture + * loop to keep running. + */ +static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) { struct rvin_buffer *buf; struct vb2_v4l2_buffer *vbuf; - dma_addr_t phys_addr_top; - - if (vin->queue_buf[slot] != NULL) - return true; + dma_addr_t phys_addr; - if (list_empty(&vin->buf_list)) - return false; + /* A already populated slot shall never be overwritten. */ + if (WARN_ON(vin->queue_buf[slot] != NULL)) + return; vin_dbg(vin, "Filling HW slot: %d\n", slot); - /* Keep track of buffer we give to HW */ - buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); - vbuf = &buf->vb; - list_del_init(to_buf_list(vbuf)); - vin->queue_buf[slot] = vbuf; - - /* Setup DMA */ - phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); - rvin_set_slot_addr(vin, slot, phys_addr_top); - - return true; -} - -static bool rvin_fill_hw(struct rvin_dev *vin) -{ - int slot, limit; - - limit = vin->continuous ? HW_BUFFER_NUM : 1; - - for (slot = 0; slot < limit; slot++) - if (!rvin_fill_hw_slot(vin, slot)) - return false; - return true; -} - -static void rvin_capture_on(struct rvin_dev *vin) -{ - vin_dbg(vin, "Capture on in %s mode\n", - vin->continuous ? "continuous" : "single"); + if (list_empty(&vin->buf_list)) { + vin->queue_buf[slot] = NULL; + phys_addr = vin->scratch_phys; + } else { + /* Keep track of buffer we give to HW */ + buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); + vbuf = &buf->vb; + list_del_init(to_buf_list(vbuf)); + vin->queue_buf[slot] = vbuf; + + /* Setup DMA */ + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + } - if (vin->continuous) - /* Continuous Frame Capture Mode */ - rvin_write(vin, VNFC_C_FRAME, VNFC_REG); - else - /* Single Frame Capture Mode */ - rvin_write(vin, VNFC_S_FRAME, VNFC_REG); + rvin_set_slot_addr(vin, slot, phys_addr); } static int rvin_capture_start(struct rvin_dev *vin) { - struct rvin_buffer *buf, *node; - int bufs, ret; - - /* Count number of free buffers */ - bufs = 0; - list_for_each_entry_safe(buf, node, &vin->buf_list, list) - bufs++; + int slot, ret; - /* Continuous capture requires more buffers then there are HW slots */ - vin->continuous = bufs > HW_BUFFER_NUM; - - if (!rvin_fill_hw(vin)) { - vin_err(vin, "HW not ready to start, not enough buffers available\n"); - return -EINVAL; - } + for (slot = 0; slot < HW_BUFFER_NUM; slot++) + rvin_fill_hw_slot(vin, slot); rvin_crop_scale_comp(vin); @@ -421,7 +380,10 @@ static int rvin_capture_start(struct rvin_dev *vin) if (ret) return ret; - rvin_capture_on(vin); + vin_dbg(vin, "Starting to capture\n"); + + /* Continuous Frame Capture Mode */ + rvin_write(vin, VNFC_C_FRAME, VNFC_REG); vin->state = RUNNING; @@ -904,7 +866,7 @@ static irqreturn_t rvin_irq(int irq, void *data) struct rvin_dev *vin = data; u32 int_status, vnms; int slot; - unsigned int i, sequence, handled = 0; + unsigned int handled = 0; unsigned long flags; spin_lock_irqsave(&vin->qlock, flags); @@ -930,65 +892,25 @@ static irqreturn_t rvin_irq(int irq, void *data) /* Prepare for capture and update state */ vnms = rvin_read(vin, VNMS_REG); - slot = rvin_get_active_slot(vin, vnms); - sequence = vin->sequence++; - - vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", - sequence, slot, - slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0', - slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0', - slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0', - !list_empty(&vin->buf_list)); - - /* HW have written to a slot that is not prepared we are in trouble */ - if (WARN_ON((vin->queue_buf[slot] == NULL))) - goto done; + slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; /* Capture frame */ - vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); - vin->queue_buf[slot]->sequence = sequence; - vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); - vin->queue_buf[slot] = NULL; - - /* Prepare for next frame */ - if (!rvin_fill_hw(vin)) { - - /* - * Can't supply HW with new buffers fast enough. Halt - * capture until more buffers are available. - */ - vin->state = STALLED; - - /* - * The continuous capturing requires an explicit stop - * operation when there is no buffer to be set into - * the VnMBm registers. - */ - if (vin->continuous) { - rvin_capture_stop(vin); - vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence); - - /* Maybe we can continue in single capture mode */ - for (i = 0; i < HW_BUFFER_NUM; i++) { - if (vin->queue_buf[i]) { - list_add(to_buf_list(vin->queue_buf[i]), - &vin->buf_list); - vin->queue_buf[i] = NULL; - } - } - - if (!list_empty(&vin->buf_list)) - rvin_capture_start(vin); - } + if (vin->queue_buf[slot]) { + vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); + vin->queue_buf[slot]->sequence = vin->sequence; + vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); + vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, + VB2_BUF_STATE_DONE); + vin->queue_buf[slot] = NULL; } else { - /* - * The single capturing requires an explicit capture - * operation to fetch the next frame. - */ - if (!vin->continuous) - rvin_capture_on(vin); + /* Scratch buffer was used, dropping frame. */ + vin_dbg(vin, "Dropping frame %u\n", vin->sequence); } + + vin->sequence++; + + /* Prepare for next frame */ + rvin_fill_hw_slot(vin, slot); done: spin_unlock_irqrestore(&vin->qlock, flags); @@ -1059,13 +981,6 @@ static void rvin_buffer_queue(struct vb2_buffer *vb) list_add_tail(to_buf_list(vbuf), &vin->buf_list); - /* - * If capture is stalled add buffer to HW and restart - * capturing if HW is ready to continue. - */ - if (vin->state == STALLED) - rvin_capture_start(vin); - spin_unlock_irqrestore(&vin->qlock, flags); } @@ -1076,6 +991,17 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; + /* Allocate scratch buffer. */ + vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, + &vin->scratch_phys, GFP_KERNEL); + if (!vin->scratch) { + spin_lock_irqsave(&vin->qlock, flags); + return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + spin_unlock_irqrestore(&vin->qlock, flags); + vin_err(vin, "Failed to allocate scratch buffer\n"); + return -ENOMEM; + } + sd = vin_to_source(vin); v4l2_subdev_call(sd, video, s_stream, 1); @@ -1091,6 +1017,10 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) spin_unlock_irqrestore(&vin->qlock, flags); + if (ret) + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); + return ret; } @@ -1141,6 +1071,10 @@ static void rvin_stop_streaming(struct vb2_queue *vq) /* disable interrupts */ rvin_disable_interrupts(vin); + + /* Free scratch buffer. */ + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); } static const struct vb2_ops rvin_qops = { @@ -1189,7 +1123,7 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq) q->ops = &rvin_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_buffers_needed = 4; q->dev = vin->dev; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 5382078143fb..95897127cc41 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -38,13 +38,11 @@ enum chip_id { /** * STOPPED - No operation in progress * RUNNING - Operation in progress have buffers - * STALLED - No operation in progress have no buffers * STOPPING - Stopping operation */ enum rvin_dma_state { STOPPED = 0, RUNNING, - STALLED, STOPPING, }; @@ -102,12 +100,13 @@ struct rvin_graph_entity { * * @lock: protects @queue * @queue: vb2 buffers queue + * @scratch: cpu address for scratch buffer + * @scratch_phys: physical address of the scratch buffer * - * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence + * @qlock: protects @queue_buf, @buf_list, @sequence * @state * @queue_buf: Keeps track of buffers given to HW slot * @buf_list: list of queued buffers - * @continuous: tracks if active operation is continuous or single mode * @sequence: V4L2 buffers sequence number * @state: keeps track of operation state * @@ -130,11 +129,12 @@ struct rvin_dev { struct mutex lock; struct vb2_queue queue; + void *scratch; + dma_addr_t scratch_phys; spinlock_t qlock; struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; struct list_head buf_list; - bool continuous; unsigned int sequence; enum rvin_dma_state state; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index b2e080ef5391..dc7e280c91b4 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -274,7 +274,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) { struct dma_slave_config dma_cfg; unsigned int i; - int ret = -ENODEV; + int ret; for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { struct rcar_drif *ch = sdr->ch[i]; @@ -282,6 +282,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx"); if (!ch->dmach) { rdrif_err(sdr, "ch%u: dma channel req failed\n", i); + ret = -ENODEV; goto dmach_error; } diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c new file mode 100644 index 000000000000..6599dba5ab84 --- /dev/null +++ b/drivers/media/platform/renesas-ceu.c @@ -0,0 +1,1677 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 Driver for Renesas Capture Engine Unit (CEU) interface + * Copyright (C) 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Based on soc-camera driver "soc_camera/sh_mobile_ceu_camera.c" + * Copyright (C) 2008 Magnus Damm + * + * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", + * Copyright (C) 2006, Sascha Hauer, Pengutronix + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/videodev2.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mediabus.h> +#include <media/videobuf2-dma-contig.h> + +#include <media/drv-intf/renesas-ceu.h> + +#define DRIVER_NAME "renesas-ceu" + +/* CEU registers offsets and masks. */ +#define CEU_CAPSR 0x00 /* Capture start register */ +#define CEU_CAPCR 0x04 /* Capture control register */ +#define CEU_CAMCR 0x08 /* Capture interface control register */ +#define CEU_CAMOR 0x10 /* Capture interface offset register */ +#define CEU_CAPWR 0x14 /* Capture interface width register */ +#define CEU_CAIFR 0x18 /* Capture interface input format register */ +#define CEU_CRCNTR 0x28 /* CEU register control register */ +#define CEU_CRCMPR 0x2c /* CEU register forcible control register */ +#define CEU_CFLCR 0x30 /* Capture filter control register */ +#define CEU_CFSZR 0x34 /* Capture filter size clip register */ +#define CEU_CDWDR 0x38 /* Capture destination width register */ +#define CEU_CDAYR 0x3c /* Capture data address Y register */ +#define CEU_CDACR 0x40 /* Capture data address C register */ +#define CEU_CFWCR 0x5c /* Firewall operation control register */ +#define CEU_CDOCR 0x64 /* Capture data output control register */ +#define CEU_CEIER 0x70 /* Capture event interrupt enable register */ +#define CEU_CETCR 0x74 /* Capture event flag clear register */ +#define CEU_CSTSR 0x7c /* Capture status register */ +#define CEU_CSRTR 0x80 /* Capture software reset register */ + +/* Data synchronous fetch mode. */ +#define CEU_CAMCR_JPEG BIT(4) + +/* Input components ordering: CEU_CAMCR.DTARY field. */ +#define CEU_CAMCR_DTARY_8_UYVY (0x00 << 8) +#define CEU_CAMCR_DTARY_8_VYUY (0x01 << 8) +#define CEU_CAMCR_DTARY_8_YUYV (0x02 << 8) +#define CEU_CAMCR_DTARY_8_YVYU (0x03 << 8) +/* TODO: input components ordering for 16 bits input. */ + +/* Bus transfer MTU. */ +#define CEU_CAPCR_BUS_WIDTH256 (0x3 << 20) + +/* Bus width configuration. */ +#define CEU_CAMCR_DTIF_16BITS BIT(12) + +/* No downsampling to planar YUV420 in image fetch mode. */ +#define CEU_CDOCR_NO_DOWSAMPLE BIT(4) + +/* Swap all input data in 8-bit, 16-bits and 32-bits units (Figure 46.45). */ +#define CEU_CDOCR_SWAP_ENDIANNESS (7) + +/* Capture reset and enable bits. */ +#define CEU_CAPSR_CPKIL BIT(16) +#define CEU_CAPSR_CE BIT(0) + +/* CEU operating flag bit. */ +#define CEU_CAPCR_CTNCP BIT(16) +#define CEU_CSTRST_CPTON BIT(0) + +/* Platform specific IRQ source flags. */ +#define CEU_CETCR_ALL_IRQS_RZ 0x397f313 +#define CEU_CETCR_ALL_IRQS_SH4 0x3d7f313 + +/* Prohibited register access interrupt bit. */ +#define CEU_CETCR_IGRW BIT(4) +/* One-frame capture end interrupt. */ +#define CEU_CEIER_CPE BIT(0) +/* VBP error. */ +#define CEU_CEIER_VBP BIT(20) +#define CEU_CEIER_MASK (CEU_CEIER_CPE | CEU_CEIER_VBP) + +#define CEU_MAX_WIDTH 2560 +#define CEU_MAX_HEIGHT 1920 +#define CEU_MAX_BPL 8188 +#define CEU_W_MAX(w) ((w) < CEU_MAX_WIDTH ? (w) : CEU_MAX_WIDTH) +#define CEU_H_MAX(h) ((h) < CEU_MAX_HEIGHT ? (h) : CEU_MAX_HEIGHT) + +/* + * ceu_bus_fmt - describe a 8-bits yuyv format the sensor can produce + * + * @mbus_code: bus format code + * @fmt_order: CEU_CAMCR.DTARY ordering of input components (Y, Cb, Cr) + * @fmt_order_swap: swapped CEU_CAMCR.DTARY ordering of input components + * (Y, Cr, Cb) + * @swapped: does Cr appear before Cb? + * @bps: number of bits sent over bus for each sample + * @bpp: number of bits per pixels unit + */ +struct ceu_mbus_fmt { + u32 mbus_code; + u32 fmt_order; + u32 fmt_order_swap; + bool swapped; + u8 bps; + u8 bpp; +}; + +/* + * ceu_buffer - Link vb2 buffer to the list of available buffers. + */ +struct ceu_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; +}; + +static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct ceu_buffer, vb); +} + +/* + * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice. + */ +struct ceu_subdev { + struct v4l2_subdev *v4l2_sd; + struct v4l2_async_subdev asd; + + /* per-subdevice mbus configuration options */ + unsigned int mbus_flags; + struct ceu_mbus_fmt mbus_fmt; +}; + +static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_subdev *asd) +{ + return container_of(asd, struct ceu_subdev, asd); +} + +/* + * ceu_device - CEU device instance + */ +struct ceu_device { + struct device *dev; + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* subdevices descriptors */ + struct ceu_subdev *subdevs; + /* the subdevice currently in use */ + struct ceu_subdev *sd; + unsigned int sd_index; + unsigned int num_sd; + + /* platform specific mask with all IRQ sources flagged */ + u32 irq_mask; + + /* currently configured field and pixel format */ + enum v4l2_field field; + struct v4l2_pix_format_mplane v4l2_pix; + + /* async subdev notification helpers */ + struct v4l2_async_notifier notifier; + /* pointers to "struct ceu_subdevice -> asd" */ + struct v4l2_async_subdev **asds; + + /* vb2 queue, capture buffer list and active buffer pointer */ + struct vb2_queue vb2_vq; + struct list_head capture; + struct vb2_v4l2_buffer *active; + unsigned int sequence; + + /* mlock - lock access to interface reset and vb2 queue */ + struct mutex mlock; + + /* lock - lock access to capture buffer queue and active buffer */ + spinlock_t lock; + + /* base - CEU memory base address */ + void __iomem *base; +}; + +static inline struct ceu_device *v4l2_to_ceu(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct ceu_device, v4l2_dev); +} + +/* --- CEU memory output formats --- */ + +/* + * ceu_fmt - describe a memory output format supported by CEU interface. + * + * @fourcc: memory layout fourcc format code + * @bpp: number of bits for each pixel stored in memory + */ +struct ceu_fmt { + u32 fourcc; + u32 bpp; +}; + +/* + * ceu_format_list - List of supported memory output formats + * + * If sensor provides any YUYV bus format, all the following planar memory + * formats are available thanks to CEU re-ordering and sub-sampling + * capabilities. + */ +static const struct ceu_fmt ceu_fmt_list[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .bpp = 16, + }, +}; + +static const struct ceu_fmt *get_ceu_fmt_from_fourcc(unsigned int fourcc) +{ + const struct ceu_fmt *fmt = &ceu_fmt_list[0]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ceu_fmt_list); i++, fmt++) + if (fmt->fourcc == fourcc) + return fmt; + + return NULL; +} + +static bool ceu_fmt_mplane(struct v4l2_pix_format_mplane *pix) +{ + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + return false; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + return true; + default: + return false; + } +} + +/* --- CEU HW operations --- */ + +static void ceu_write(struct ceu_device *priv, unsigned int reg_offs, u32 data) +{ + iowrite32(data, priv->base + reg_offs); +} + +static u32 ceu_read(struct ceu_device *priv, unsigned int reg_offs) +{ + return ioread32(priv->base + reg_offs); +} + +/* + * ceu_soft_reset() - Software reset the CEU interface. + * @ceu_device: CEU device. + * + * Returns 0 for success, -EIO for error. + */ +static int ceu_soft_reset(struct ceu_device *ceudev) +{ + unsigned int i; + + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CPKIL); + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CSTSR) & CEU_CSTRST_CPTON)) + break; + udelay(1); + } + + if (i == 100) { + dev_err(ceudev->dev, "soft reset time out\n"); + return -EIO; + } + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CAPSR) & CEU_CAPSR_CPKIL)) + return 0; + udelay(1); + } + + /* If we get here, CEU has not reset properly. */ + return -EIO; +} + +/* --- CEU Capture Operations --- */ + +/* + * ceu_hw_config() - Configure CEU interface registers. + */ +static int ceu_hw_config(struct ceu_device *ceudev) +{ + u32 camcr, cdocr, cfzsr, cdwdr, capwr; + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + unsigned int mbus_flags = ceu_sd->mbus_flags; + + /* Start configuring CEU registers */ + ceu_write(ceudev, CEU_CAIFR, 0); + ceu_write(ceudev, CEU_CFWCR, 0); + ceu_write(ceudev, CEU_CRCNTR, 0); + ceu_write(ceudev, CEU_CRCMPR, 0); + + /* Set the frame capture period for both image capture and data sync. */ + capwr = (pix->height << 16) | pix->width * mbus_fmt->bpp / 8; + + /* + * Swap input data endianness by default. + * In data fetch mode bytes are received in chunks of 8 bytes. + * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) + * The data is however by default written to memory in reverse order: + * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) + * + * Use CEU_CDOCR[2:0] to swap data ordering. + */ + cdocr = CEU_CDOCR_SWAP_ENDIANNESS; + + /* + * Configure CAMCR and CDOCR: + * match input components ordering with memory output format and + * handle downsampling to YUV420. + * + * If the memory output planar format is 'swapped' (Cr before Cb) and + * input format is not, use the swapped version of CAMCR.DTARY. + * + * If the memory output planar format is not 'swapped' (Cb before Cr) + * and input format is, use the swapped version of CAMCR.DTARY. + * + * CEU by default downsample to planar YUV420 (CDCOR[4] = 0). + * If output is planar YUV422 set CDOCR[4] = 1 + * + * No downsample for data fetch sync mode. + */ + switch (pix->pixelformat) { + /* Data fetch sync mode */ + case V4L2_PIX_FMT_YUYV: + /* TODO: handle YUYV permutations through DTARY bits. */ + camcr = CEU_CAMCR_JPEG; + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->plane_fmt[0].bytesperline; + break; + + /* Non-swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV16: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV12: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order_swap; + else + camcr = mbus_fmt->fmt_order; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + /* Swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV61: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV21: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order; + else + camcr = mbus_fmt->fmt_order_swap; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + default: + return -EINVAL; + } + + camcr |= mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; + camcr |= mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; + + /* TODO: handle 16 bit bus width with DTIF bit in CAMCR */ + ceu_write(ceudev, CEU_CAMCR, camcr); + ceu_write(ceudev, CEU_CDOCR, cdocr); + ceu_write(ceudev, CEU_CAPCR, CEU_CAPCR_BUS_WIDTH256); + + /* + * TODO: make CAMOR offsets configurable. + * CAMOR wants to know the number of blanks between a VS/HS signal + * and valid data. This value should actually come from the sensor... + */ + ceu_write(ceudev, CEU_CAMOR, 0); + + /* TODO: 16 bit bus width require re-calculation of cdwdr and cfzsr */ + ceu_write(ceudev, CEU_CAPWR, capwr); + ceu_write(ceudev, CEU_CFSZR, cfzsr); + ceu_write(ceudev, CEU_CDWDR, cdwdr); + + return 0; +} + +/* + * ceu_capture() - Trigger start of a capture sequence. + * + * Program the CEU DMA registers with addresses where to transfer image data. + */ +static int ceu_capture(struct ceu_device *ceudev) +{ + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + dma_addr_t phys_addr_top; + + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, 0); + ceu_write(ceudev, CEU_CDAYR, phys_addr_top); + + /* Ignore CbCr plane for non multi-planar image formats. */ + if (ceu_fmt_mplane(pix)) { + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, + 1); + ceu_write(ceudev, CEU_CDACR, phys_addr_top); + } + + /* + * Trigger new capture start: once for each frame, as we work in + * one-frame capture mode. + */ + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CE); + + return 0; +} + +static irqreturn_t ceu_irq(int irq, void *data) +{ + struct ceu_device *ceudev = data; + struct vb2_v4l2_buffer *vbuf; + struct ceu_buffer *buf; + u32 status; + + /* Clean interrupt status. */ + status = ceu_read(ceudev, CEU_CETCR); + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + + /* Unexpected interrupt. */ + if (!(status & CEU_CEIER_MASK)) + return IRQ_NONE; + + spin_lock(&ceudev->lock); + + /* Stale interrupt from a released buffer, ignore it. */ + vbuf = ceudev->active; + if (!vbuf) { + spin_unlock(&ceudev->lock); + return IRQ_HANDLED; + } + + /* + * When a VBP interrupt occurs, no capture end interrupt will occur + * and the image of that frame is not captured correctly. + */ + if (status & CEU_CEIER_VBP) { + dev_err(ceudev->dev, "VBP interrupt: abort capture\n"); + goto error_irq_out; + } + + /* Prepare to return the 'previous' buffer. */ + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vbuf->sequence = ceudev->sequence++; + vbuf->field = ceudev->field; + + /* Prepare a new 'active' buffer and trigger a new capture. */ + if (!list_empty(&ceudev->capture)) { + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + list_del(&buf->queue); + ceudev->active = &buf->vb; + + ceu_capture(ceudev); + } + + /* Return the 'previous' buffer. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; + +error_irq_out: + /* Return the 'previous' buffer and all queued ones. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR); + + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; +} + +/* --- CEU Videobuf2 operations --- */ + +static void ceu_update_plane_sizes(struct v4l2_plane_pix_format *plane, + unsigned int bpl, unsigned int szimage) +{ + memset(plane, 0, sizeof(*plane)); + + plane->sizeimage = szimage; + if (plane->bytesperline < bpl || plane->bytesperline > CEU_MAX_BPL) + plane->bytesperline = bpl; +} + +/* + * ceu_calc_plane_sizes() - Fill per-plane 'struct v4l2_plane_pix_format' + * information according to the currently configured + * pixel format. + * @ceu_device: CEU device. + * @ceu_fmt: Active image format. + * @pix: Pixel format information (store line width and image sizes) + */ +static void ceu_calc_plane_sizes(struct ceu_device *ceudev, + const struct ceu_fmt *ceu_fmt, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpl, szimage; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + pix->num_planes = 1; + bpl = pix->width * ceu_fmt->bpp / 8; + szimage = pix->height * bpl; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + break; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage / 2); + break; + + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + default: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage); + break; + } +} + +/* + * ceu_vb2_setup() - is called to check whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format, if required. + */ +static int ceu_vb2_setup(struct vb2_queue *vq, unsigned int *count, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + /* num_planes is set: just check plane sizes. */ + if (*num_planes) { + for (i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + /* num_planes not set: called from REQBUFS, just set plane sizes. */ + *num_planes = pix->num_planes; + for (i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + + return 0; +} + +static void ceu_vb2_queue(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ceu_buffer *buf = vb2_to_ceu(vbuf); + unsigned long irqflags; + + spin_lock_irqsave(&ceudev->lock, irqflags); + list_add_tail(&buf->queue, &ceudev->capture); + spin_unlock_irqrestore(&ceudev->lock, irqflags); +} + +static int ceu_vb2_prepare(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + for (i = 0; i < pix->num_planes; i++) { + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { + dev_err(ceudev->dev, + "Plane size too small (%lu < %u)\n", + vb2_plane_size(vb, i), + pix->plane_fmt[i].sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); + } + + return 0; +} + +static int ceu_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + int ret; + + /* Program the CEU interface according to the CEU image format. */ + ret = ceu_hw_config(ceudev); + if (ret) + goto error_return_bufs; + + ret = v4l2_subdev_call(v4l2_sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + dev_dbg(ceudev->dev, + "Subdevice failed to start streaming: %d\n", ret); + goto error_return_bufs; + } + + spin_lock_irqsave(&ceudev->lock, irqflags); + ceudev->sequence = 0; + + /* Grab the first available buffer and trigger the first capture. */ + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + if (!buf) { + spin_unlock_irqrestore(&ceudev->lock, irqflags); + dev_dbg(ceudev->dev, + "No buffer available for capture.\n"); + goto error_stop_sensor; + } + + list_del(&buf->queue); + ceudev->active = &buf->vb; + + /* Clean and program interrupts for first capture. */ + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + ceu_capture(ceudev); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return 0; + +error_stop_sensor: + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + +error_return_bufs: + spin_lock_irqsave(&ceudev->lock, irqflags); + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_QUEUED); + ceudev->active = NULL; + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return ret; +} + +static void ceu_stop_streaming(struct vb2_queue *vq) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + + /* Clean and disable interrupt sources. */ + ceu_write(ceudev, CEU_CETCR, + ceu_read(ceudev, CEU_CETCR) & ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + + spin_lock_irqsave(&ceudev->lock, irqflags); + if (ceudev->active) { + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_ERROR); + ceudev->active = NULL; + } + + /* Release all queued buffers. */ + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&ceudev->capture); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + ceu_soft_reset(ceudev); +} + +static const struct vb2_ops ceu_vb2_ops = { + .queue_setup = ceu_vb2_setup, + .buf_queue = ceu_vb2_queue, + .buf_prepare = ceu_vb2_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = ceu_start_streaming, + .stop_streaming = ceu_stop_streaming, +}; + +/* --- CEU image formats handling --- */ + +/* + * ceu_try_fmt() - test format on CEU and sensor + * @ceudev: The CEU device. + * @v4l2_fmt: format to test. + * + * Returns 0 for success, < 0 for errors. + */ +static int ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + struct v4l2_subdev_pad_config pad_cfg; + const struct ceu_fmt *ceu_fmt; + int ret; + + struct v4l2_subdev_format sd_format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + break; + + default: + pix->pixelformat = V4L2_PIX_FMT_NV16; + break; + } + + ceu_fmt = get_ceu_fmt_from_fourcc(pix->pixelformat); + + /* CFSZR requires height and width to be 4-pixel aligned. */ + v4l_bound_align_image(&pix->width, 2, CEU_MAX_WIDTH, 4, + &pix->height, 4, CEU_MAX_HEIGHT, 4, 0); + + /* + * Set format on sensor sub device: bus format used to produce memory + * format is selected at initialization time. + */ + v4l2_fill_mbus_format_mplane(&sd_format.format, pix); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format); + if (ret) + return ret; + + /* Apply size returned by sensor as the CEU can't scale. */ + v4l2_fill_pix_format_mplane(pix, &sd_format.format); + + /* Calculate per-plane sizes based on image format. */ + ceu_calc_plane_sizes(ceudev, ceu_fmt, pix); + + return 0; +} + +/* + * ceu_set_fmt() - Apply the supplied format to both sensor and CEU + */ +static int ceu_set_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + ret = ceu_try_fmt(ceudev, v4l2_fmt); + if (ret) + return ret; + + v4l2_fill_mbus_format_mplane(&format.format, &v4l2_fmt->fmt.pix_mp); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, NULL, &format); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt->fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_set_default_fmt() - Apply default NV16 memory output format with VGA + * sizes. + */ +static int ceu_set_default_fmt(struct ceu_device *ceudev) +{ + int ret; + + struct v4l2_format v4l2_fmt = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .field = V4L2_FIELD_NONE, + .pixelformat = V4L2_PIX_FMT_NV16, + .num_planes = 2, + .plane_fmt = { + [0] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + [1] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + }, + }, + }; + + ret = ceu_try_fmt(ceudev, &v4l2_fmt); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt.fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_init_mbus_fmt() - Query sensor for supported formats and initialize + * CEU media bus format used to produce memory formats. + * + * Find out if sensor can produce a permutation of 8-bits YUYV bus format. + * From a single 8-bits YUYV bus format the CEU can produce several memory + * output formats: + * - NV[12|21|16|61] through image fetch mode; + * - YUYV422 if sensor provides YUYV422 + * + * TODO: Other YUYV422 permutations through data fetch sync mode and DTARY + * TODO: Binary data (eg. JPEG) and raw formats through data fetch sync mode + */ +static int ceu_init_mbus_fmt(struct ceu_device *ceudev) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + bool yuyv_bus_fmt = false; + + struct v4l2_subdev_mbus_code_enum sd_mbus_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = 0, + }; + + /* Find out if sensor can produce any permutation of 8-bits YUYV422. */ + while (!yuyv_bus_fmt && + !v4l2_subdev_call(v4l2_sd, pad, enum_mbus_code, + NULL, &sd_mbus_fmt)) { + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + yuyv_bus_fmt = true; + break; + default: + /* + * Only support 8-bits YUYV bus formats at the moment; + * + * TODO: add support for binary formats (data sync + * fetch mode). + */ + break; + } + + sd_mbus_fmt.index++; + } + + if (!yuyv_bus_fmt) + return -ENXIO; + + /* + * Save the first encountered YUYV format as "mbus_fmt" and use it + * to output all planar YUV422 and YUV420 (NV*) formats to memory as + * well as for data synch fetch mode (YUYV - YVYU etc. ). + */ + mbus_fmt->mbus_code = sd_mbus_fmt.code; + mbus_fmt->bps = 8; + + /* Annotate the selected bus format components ordering. */ + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_YVYU8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_UYVY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_VYUY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + } + + return 0; +} + +/* --- Runtime PM Handlers --- */ + +/* + * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. + */ +static int __maybe_unused ceu_runtime_resume(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 1); + + ceu_soft_reset(ceudev); + + return 0; +} + +/* + * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. + * Turn sensor power off. + */ +static int __maybe_unused ceu_runtime_suspend(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 0); + + ceu_write(ceudev, CEU_CEIER, 0); + ceu_soft_reset(ceudev); + + return 0; +} + +/* --- File Operations --- */ + +static int ceu_open(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + int ret; + + ret = v4l2_fh_open(file); + if (ret) + return ret; + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power on on first open */ + pm_runtime_get_sync(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static int ceu_release(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + + vb2_fop_release(file); + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power down on last close */ + pm_runtime_put(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static const struct v4l2_file_operations ceu_fops = { + .owner = THIS_MODULE, + .open = ceu_open, + .release = ceu_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +/* --- Video Device IOCTLs --- */ + +static int ceu_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct ceu_device *ceudev = video_drvdata(file); + + strlcpy(cap->card, "Renesas CEU", sizeof(cap->card)); + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:renesas-ceu-%s", dev_name(ceudev->dev)); + + return 0; +} + +static int ceu_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ceu_fmt *fmt; + + if (f->index >= ARRAY_SIZE(ceu_fmt_list)) + return -EINVAL; + + fmt = &ceu_fmt_list[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int ceu_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return ceu_try_fmt(ceudev, f); +} + +static int ceu_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + return ceu_set_fmt(ceudev, f); +} + +static int ceu_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + f->fmt.pix_mp = ceudev->v4l2_pix; + + return 0; +} + +static int ceu_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceusd; + + if (inp->index >= ceudev->num_sd) + return -EINVAL; + + ceusd = &ceudev->subdevs[inp->index]; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = 0; + snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", + inp->index, ceusd->v4l2_sd->name); + + return 0; +} + +static int ceu_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct ceu_device *ceudev = video_drvdata(file); + + *i = ceudev->sd_index; + + return 0; +} + +static int ceu_s_input(struct file *file, void *priv, unsigned int i) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd_old; + int ret; + + if (i >= ceudev->num_sd) + return -EINVAL; + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + if (i == ceudev->sd_index) + return 0; + + ceu_sd_old = ceudev->sd; + ceudev->sd = &ceudev->subdevs[i]; + + /* + * Make sure we can generate output image formats and apply + * default one. + */ + ret = ceu_init_mbus_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + ret = ceu_set_default_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + /* Now that we're sure we can use the sensor, power off the old one. */ + v4l2_subdev_call(ceu_sd_old->v4l2_sd, core, s_power, 0); + v4l2_subdev_call(ceudev->sd->v4l2_sd, core, s_power, 1); + + ceudev->sd_index = i; + + return 0; +} + +static int ceu_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_size_enum fse = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fsize->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = CEU_W_MAX(fse.max_width); + fsize->discrete.height = CEU_H_MAX(fse.max_height); + + return 0; +} + +static int ceu_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_interval_enum fie = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fival->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_interval, NULL, + &fie); + if (ret) + return ret; + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static const struct v4l2_ioctl_ops ceu_ioctl_ops = { + .vidioc_querycap = ceu_querycap, + + .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, + + .vidioc_enum_input = ceu_enum_input, + .vidioc_g_input = ceu_g_input, + .vidioc_s_input = ceu_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_parm = ceu_g_parm, + .vidioc_s_parm = ceu_s_parm, + .vidioc_enum_framesizes = ceu_enum_framesizes, + .vidioc_enum_frameintervals = ceu_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * ceu_vdev_release() - release CEU video device memory when last reference + * to this driver is closed + */ +static void ceu_vdev_release(struct video_device *vdev) +{ + struct ceu_device *ceudev = video_get_drvdata(vdev); + + kfree(ceudev); +} + +static int ceu_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *v4l2_sd, + struct v4l2_async_subdev *asd) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct ceu_subdev *ceu_sd = to_ceu_subdev(asd); + + ceu_sd->v4l2_sd = v4l2_sd; + ceudev->num_sd++; + + return 0; +} + +static int ceu_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct video_device *vdev = &ceudev->vdev; + struct vb2_queue *q = &ceudev->vb2_vq; + struct v4l2_subdev *v4l2_sd; + int ret; + + /* Initialize vb2 queue. */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = ceudev; + q->ops = &ceu_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct ceu_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &ceudev->mlock; + q->dev = ceudev->v4l2_dev.dev; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + /* + * Make sure at least one sensor is primary and use it to initialize + * ceu formats. + */ + if (!ceudev->sd) { + ceudev->sd = &ceudev->subdevs[0]; + ceudev->sd_index = 0; + } + + v4l2_sd = ceudev->sd->v4l2_sd; + + ret = ceu_init_mbus_fmt(ceudev); + if (ret) + return ret; + + ret = ceu_set_default_fmt(ceudev); + if (ret) + return ret; + + /* Register the video device. */ + strncpy(vdev->name, DRIVER_NAME, strlen(DRIVER_NAME)); + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &ceudev->mlock; + vdev->queue = &ceudev->vb2_vq; + vdev->ctrl_handler = v4l2_sd->ctrl_handler; + vdev->fops = &ceu_fops; + vdev->ioctl_ops = &ceu_ioctl_ops; + vdev->release = ceu_vdev_release; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + video_set_drvdata(vdev, ceudev); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + v4l2_err(vdev->v4l2_dev, + "video_register_device failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct v4l2_async_notifier_operations ceu_notify_ops = { + .bound = ceu_notify_bound, + .complete = ceu_notify_complete, +}; + +/* + * ceu_init_async_subdevs() - Initialize CEU subdevices and async_subdevs in + * ceu device. Both DT and platform data parsing use + * this routine. + * + * Returns 0 for success, -ENOMEM for failure. + */ +static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd) +{ + /* Reserve memory for 'n_sd' ceu_subdev descriptors. */ + ceudev->subdevs = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->subdevs), GFP_KERNEL); + if (!ceudev->subdevs) + return -ENOMEM; + + /* + * Reserve memory for 'n_sd' pointers to async_subdevices. + * ceudev->asds members will point to &ceu_subdev.asd + */ + ceudev->asds = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->asds), GFP_KERNEL); + if (!ceudev->asds) + return -ENOMEM; + + ceudev->sd = NULL; + ceudev->sd_index = 0; + ceudev->num_sd = 0; + + return 0; +} + +/* + * ceu_parse_platform_data() - Initialize async_subdevices using platform + * device provided data. + */ +static int ceu_parse_platform_data(struct ceu_device *ceudev, + const struct ceu_platform_data *pdata) +{ + const struct ceu_async_subdev *async_sd; + struct ceu_subdev *ceu_sd; + unsigned int i; + int ret; + + if (pdata->num_subdevs == 0) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, pdata->num_subdevs); + if (ret) + return ret; + + for (i = 0; i < pdata->num_subdevs; i++) { + /* Setup the ceu subdevice and the async subdevice. */ + async_sd = &pdata->subdevs[i]; + ceu_sd = &ceudev->subdevs[i]; + + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = async_sd->flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_I2C; + ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id; + ceu_sd->asd.match.i2c.address = async_sd->i2c_address; + + ceudev->asds[i] = &ceu_sd->asd; + } + + return pdata->num_subdevs; +} + +/* + * ceu_parse_dt() - Initialize async_subdevs parsing device tree graph. + */ +static int ceu_parse_dt(struct ceu_device *ceudev) +{ + struct device_node *of = ceudev->dev->of_node; + struct v4l2_fwnode_endpoint fw_ep; + struct ceu_subdev *ceu_sd; + struct device_node *ep; + unsigned int i; + int num_ep; + int ret; + + num_ep = of_graph_get_endpoint_count(of); + if (!num_ep) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, num_ep); + if (ret) + return ret; + + for (i = 0; i < num_ep; i++) { + ep = of_graph_get_endpoint_by_regs(of, 0, i); + if (!ep) { + dev_err(ceudev->dev, + "No subdevice connected on endpoint %u.\n", i); + ret = -ENODEV; + goto error_put_node; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep); + if (ret) { + dev_err(ceudev->dev, + "Unable to parse endpoint #%u.\n", i); + goto error_put_node; + } + + if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) { + dev_err(ceudev->dev, + "Only parallel input supported.\n"); + ret = -EINVAL; + goto error_put_node; + } + + /* Setup the ceu subdevice and the async subdevice. */ + ceu_sd = &ceudev->subdevs[i]; + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + ceu_sd->asd.match.fwnode = + fwnode_graph_get_remote_port_parent( + of_fwnode_handle(ep)); + + ceudev->asds[i] = &ceu_sd->asd; + of_node_put(ep); + } + + return num_ep; + +error_put_node: + of_node_put(ep); + return ret; +} + +/* + * struct ceu_data - Platform specific CEU data + * @irq_mask: CETCR mask with all interrupt sources enabled. The mask differs + * between SH4 and RZ platforms. + */ +struct ceu_data { + u32 irq_mask; +}; + +static const struct ceu_data ceu_data_rz = { + .irq_mask = CEU_CETCR_ALL_IRQS_RZ, +}; + +static const struct ceu_data ceu_data_sh4 = { + .irq_mask = CEU_CETCR_ALL_IRQS_SH4, +}; + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ceu_of_match[] = { + { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz }, + { } +}; +MODULE_DEVICE_TABLE(of, ceu_of_match); +#endif + +static int ceu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct ceu_data *ceu_data; + struct ceu_device *ceudev; + struct resource *res; + unsigned int irq; + int num_subdevs; + int ret; + + ceudev = kzalloc(sizeof(*ceudev), GFP_KERNEL); + if (!ceudev) + return -ENOMEM; + + platform_set_drvdata(pdev, ceudev); + ceudev->dev = dev; + + INIT_LIST_HEAD(&ceudev->capture); + spin_lock_init(&ceudev->lock); + mutex_init(&ceudev->mlock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ceudev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ceudev->base)) { + ret = PTR_ERR(ceudev->base); + goto error_free_ceudev; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "Failed to get irq: %d\n", ret); + goto error_free_ceudev; + } + irq = ret; + + ret = devm_request_irq(dev, irq, ceu_irq, + 0, dev_name(dev), ceudev); + if (ret) { + dev_err(&pdev->dev, "Unable to request CEU interrupt.\n"); + goto error_free_ceudev; + } + + pm_runtime_enable(dev); + + ret = v4l2_device_register(dev, &ceudev->v4l2_dev); + if (ret) + goto error_pm_disable; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + ceu_data = of_match_device(ceu_of_match, dev)->data; + num_subdevs = ceu_parse_dt(ceudev); + } else if (dev->platform_data) { + /* Assume SH4 if booting with platform data. */ + ceu_data = &ceu_data_sh4; + num_subdevs = ceu_parse_platform_data(ceudev, + dev->platform_data); + } else { + num_subdevs = -EINVAL; + } + + if (num_subdevs < 0) { + ret = num_subdevs; + goto error_v4l2_unregister; + } + ceudev->irq_mask = ceu_data->irq_mask; + + ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; + ceudev->notifier.subdevs = ceudev->asds; + ceudev->notifier.num_subdevs = num_subdevs; + ceudev->notifier.ops = &ceu_notify_ops; + ret = v4l2_async_notifier_register(&ceudev->v4l2_dev, + &ceudev->notifier); + if (ret) + goto error_v4l2_unregister; + + dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev)); + + return 0; + +error_v4l2_unregister: + v4l2_device_unregister(&ceudev->v4l2_dev); +error_pm_disable: + pm_runtime_disable(dev); +error_free_ceudev: + kfree(ceudev); + + return ret; +} + +static int ceu_remove(struct platform_device *pdev) +{ + struct ceu_device *ceudev = platform_get_drvdata(pdev); + + pm_runtime_disable(ceudev->dev); + + v4l2_async_notifier_unregister(&ceudev->notifier); + + v4l2_device_unregister(&ceudev->v4l2_dev); + + video_unregister_device(&ceudev->vdev); + + return 0; +} + +static const struct dev_pm_ops ceu_pm_ops = { + SET_RUNTIME_PM_OPS(ceu_runtime_suspend, + ceu_runtime_resume, + NULL) +}; + +static struct platform_driver ceu_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &ceu_pm_ops, + .of_match_table = of_match_ptr(ceu_of_match), + }, + .probe = ceu_probe, + .remove = ceu_remove, +}; + +module_platform_driver(ceu_driver); + +MODULE_DESCRIPTION("Renesas CEU camera driver"); +MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 49cacc7a48d1..fa1ba98c96dc 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -140,7 +140,8 @@ void rga_buf_map(struct vb2_buffer *vb) address = sg_phys(sgl); for (p = 0; p < len; p++) { - dma_addr_t phys = address + (p << PAGE_SHIFT); + dma_addr_t phys = address + + ((dma_addr_t)p << PAGE_SHIFT); pages[mapped_size + p] = phys; } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 89296de9cf4a..d508a8ba6f89 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -207,7 +207,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx) return 0; } -struct rga_fmt formats[] = { +static struct rga_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB32, .color_swap = RGA_COLOR_RB_SWAP, diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 437395a61065..9ab8e7ee2e1e 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h new file mode 100644 index 000000000000..fadd9139b489 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register definition file for Samsung MFC V10.x Interface (FIMV) driver + * + */ + +#ifndef _REGS_MFC_V10_H +#define _REGS_MFC_V10_H + +#include <linux/sizes.h> +#include "regs-mfc-v8.h" + +/* MFCv10 register definitions*/ +#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 +#define S5P_FIMV_MFC_STATE_V10 0x7124 +#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 +#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 +#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30 +#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4 +#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8 +#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC +#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0 +#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4 +#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8 + +/* MFCv10 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) +#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) +#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) + +/* MFCv10 variant defines */ +#define MAX_FW_SIZE_V10 (SZ_1M) +#define MAX_CPB_SIZE_V10 (3 * SZ_1M) +#define MFC_VERSION_V10 0xA0 +#define MFC_NUM_PORTS_V10 1 + +/* MFCv10 codec defines*/ +#define S5P_FIMV_CODEC_HEVC_DEC 17 +#define S5P_FIMV_CODEC_VP9_DEC 18 +#define S5P_FIMV_CODEC_HEVC_ENC 26 + +/* Decoder buffer size for MFC v10 */ +#define DEC_VP9_STATIC_BUFFER_SIZE 20480 + +/* Encoder buffer size for MFC v10.0 */ +#define ENC_V100_BASE_SIZE(x, y) \ + (((x + 3) * (y + 3) * 8) \ + + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8)) + +#define ENC_V100_H264_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 64) * 32)) + +#define ENC_V100_MPEG4_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 128) * 16)) + +#define ENC_V100_VP8_ME_SIZE(x, y) \ + ENC_V100_BASE_SIZE(x, y) + +#define ENC_V100_HEVC_ME_SIZE(x, y) \ + (((x + 3) * (y + 3) * 32) \ + + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4)) + +#endif /*_REGS_MFC_V10_H*/ + diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 75f5f7511d72..bd639ae71023 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -17,6 +17,7 @@ /* Additional registers for v8 */ #define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104 +#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108 #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144 #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148 #define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150 @@ -84,6 +85,7 @@ #define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c #define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790 +#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894 #define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c #define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d5b94fc0040e..a80251ed3143 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -526,6 +526,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else @@ -1607,6 +1609,29 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .num_clocks = 3, }; +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V10, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, + .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, +}; + +static struct s5p_mfc_buf_size buf_size_v10 = { + .fw = MAX_FW_SIZE_V10, + .cpb = MAX_CPB_SIZE_V10, + .priv = &mfc_buf_size_v10, +}; + +static struct s5p_mfc_variant mfc_drvdata_v10 = { + .version = MFC_VERSION_V10, + .version_bit = MFC_V10_BIT, + .port_num = MFC_NUM_PORTS_V10, + .buf_size = &buf_size_v10, + .fw_name[0] = "s5p-mfc-v10.fw", +}; + static const struct of_device_id exynos_mfc_match[] = { { .compatible = "samsung,mfc-v5", @@ -1623,6 +1648,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,exynos5433-mfc", .data = &mfc_drvdata_v8_5433, + }, { + .compatible = "samsung,mfc-v10", + .data = &mfc_drvdata_v10, }, {}, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index b1b149151d2d..7521fceb68f1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -101,6 +101,12 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_DEC: codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; break; + case S5P_MFC_CODEC_HEVC_DEC: + codec_type = S5P_FIMV_CODEC_HEVC_DEC; + break; + case S5P_MFC_CODEC_VP9_DEC: + codec_type = S5P_FIMV_CODEC_VP9_DEC; + break; case S5P_MFC_CODEC_H264_ENC: codec_type = S5P_FIMV_CODEC_H264_ENC_V6; break; @@ -116,6 +122,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_ENC: codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; break; + case S5P_MFC_CODEC_HEVC_ENC: + codec_type = S5P_FIMV_CODEC_HEVC_ENC; + break; default: codec_type = S5P_FIMV_CODEC_NONE_V6; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 76119a8cc477..20442a9b9f7a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -23,7 +23,7 @@ #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> #include "regs-mfc.h" -#include "regs-mfc-v8.h" +#include "regs-mfc-v10.h" #define S5P_MFC_NAME "s5p-mfc" @@ -61,7 +61,7 @@ #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 77 +#define MFC_MAX_CTRLS 128 #define S5P_MFC_CODEC_NONE -1 #define S5P_MFC_CODEC_H264_DEC 0 @@ -72,12 +72,15 @@ #define S5P_MFC_CODEC_H263_DEC 5 #define S5P_MFC_CODEC_VC1RCV_DEC 6 #define S5P_MFC_CODEC_VP8_DEC 7 +#define S5P_MFC_CODEC_HEVC_DEC 17 +#define S5P_MFC_CODEC_VP9_DEC 18 #define S5P_MFC_CODEC_H264_ENC 20 #define S5P_MFC_CODEC_H264_MVC_ENC 21 #define S5P_MFC_CODEC_MPEG4_ENC 22 #define S5P_MFC_CODEC_H263_ENC 23 #define S5P_MFC_CODEC_VP8_ENC 24 +#define S5P_MFC_CODEC_HEVC_ENC 26 #define S5P_MFC_R2H_CMD_EMPTY 0 #define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 @@ -213,6 +216,7 @@ struct s5p_mfc_buf_size_v6 { unsigned int h264_dec_ctx; unsigned int other_dec_ctx; unsigned int h264_enc_ctx; + unsigned int hevc_enc_ctx; unsigned int other_enc_ctx; }; @@ -430,6 +434,55 @@ struct s5p_mfc_vp8_enc_params { u8 profile; }; +struct s5p_mfc_hevc_enc_params { + enum v4l2_mpeg_video_hevc_profile profile; + int level; + enum v4l2_mpeg_video_h264_level level_v4l2; + u8 tier; + u32 rc_framerate; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_lcu_dark; + u8 rc_lcu_smooth; + u8 rc_lcu_static; + u8 rc_lcu_activity; + u8 rc_frame_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + u8 max_partition_depth; + u8 num_refs_for_p; + u8 refreshtype; + u16 refreshperiod; + s32 lf_beta_offset_div2; + s32 lf_tc_offset_div2; + u8 loopfilter; + u8 loopfilter_disable; + u8 loopfilter_across; + u8 nal_control_length_filed; + u8 nal_control_user_ref; + u8 nal_control_store_ref; + u8 const_intra_period_enable; + u8 lossless_cu_enable; + u8 wavefront_enable; + u8 enable_ltr; + u8 hier_qp_enable; + enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type; + u8 num_hier_layer; + u8 hier_qp_layer[7]; + u32 hier_bit_layer[7]; + u8 sign_data_hiding; + u8 general_pb_enable; + u8 temporal_id_enable; + u8 strong_intra_smooth; + u8 intra_pu_split_disable; + u8 tmv_prediction_disable; + u8 max_num_merge_mv; + u8 eco_mode_enable; + u8 encoding_nostartcode_enable; + u8 size_of_length_field; + u8 prepend_sps_pps_to_idr; +}; + /** * struct s5p_mfc_enc_params - general encoding parameters */ @@ -467,6 +520,7 @@ struct s5p_mfc_enc_params { struct s5p_mfc_h264_enc_params h264; struct s5p_mfc_mpeg4_enc_params mpeg4; struct s5p_mfc_vp8_enc_params vp8; + struct s5p_mfc_hevc_enc_params hevc; } codec; }; @@ -714,12 +768,20 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) #define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) #define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) -#define IS_MFCV8(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) +#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev)) #define MFC_V5_BIT BIT(0) #define MFC_V6_BIT BIT(1) #define MFC_V7_BIT BIT(2) #define MFC_V8_BIT BIT(3) +#define MFC_V10_BIT BIT(5) +#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \ + MFC_V8_BIT | MFC_V10_BIT) +#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \ + MFC_V10_BIT) +#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT) #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f95cd76af537..ee7b15b335e0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -62,7 +62,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) if (!dev->variant->fw_name[i]) continue; err = request_firmware((const struct firmware **)&fw_blob, - dev->variant->fw_name[i], dev->v4l2_dev.dev); + dev->variant->fw_name[i], &dev->plat_dev->dev); if (!err) { dev->fw_ver = (enum s5p_mfc_fw_ver) i; break; @@ -239,6 +239,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } else mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + + if (IS_MFCV10(dev)) + mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10); + mfc_debug(2, "Will now wait for completion of firmware transfer\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); @@ -399,7 +403,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Send MFC wakeup command and wait for completion*/ - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ret = s5p_mfc_v8_wait_wakeup(dev); else ret = s5p_mfc_wait_wakeup(dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 8937b0af7cb3..5cf4d9921264 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -54,7 +54,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -62,7 +62,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -70,8 +70,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H264/MVC Encoded Stream", @@ -79,7 +78,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -87,8 +86,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG1 Encoded Stream", @@ -96,8 +94,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG2 Encoded Stream", @@ -105,8 +102,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -114,8 +110,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "XviD Encoded Stream", @@ -123,8 +118,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 Encoded Stream", @@ -132,8 +126,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 RCV Encoded Stream", @@ -141,8 +134,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -150,7 +142,21 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .codec_mode = S5P_FIMV_CODEC_VP9_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, }, }; @@ -1177,7 +1183,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) struct v4l2_format f; f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; ctx->src_fmt = find_format(&f, MFC_FMT_DEC); - if (IS_MFCV8(ctx->dev)) + if (IS_MFCV8_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; else if (IS_MFCV6_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 0d5d465561be..5c0462ca9993 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -57,8 +57,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -66,7 +65,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -74,8 +73,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -83,8 +81,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -92,8 +89,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -101,7 +97,14 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V7PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V10_BIT, }, }; @@ -697,6 +700,368 @@ static struct mfc_control controls[] = { .default_value = 0, }, { + .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC I Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC P Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Minimum number of output bufs", @@ -817,6 +1182,11 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) get_enc_dpb_count, dev); if (ctx->pb_count < enc_pb_count) ctx->pb_count = enc_pb_count; + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_e_min_scratch_buf_size, dev); + ctx->bank1.size += ctx->scratch_buf_size; + } ctx->state = MFCINST_HEAD_PRODUCED; } @@ -850,7 +1220,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *mb_entry; - unsigned long enc_y_addr, enc_c_addr; + unsigned long enc_y_addr = 0, enc_c_addr = 0; unsigned long mb_y_addr, mb_c_addr; int slice_type; unsigned int strm_size; @@ -1358,6 +1728,26 @@ static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) return t[lvl]; } +static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl) +{ + static unsigned int t[] = { + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62, + }; + return t[lvl]; +} + static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) { static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { @@ -1383,6 +1773,42 @@ static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) return t[sar]; } +/* + * Update range of all HEVC quantization parameter controls that depend on the + * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls. + */ +static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx, + int min, int max) +{ + static const int __hevc_qp_ctrls[] = { + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + }; + struct v4l2_ctrl *ctrl = NULL; + int i, j; + + for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) { + for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) { + if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) { + ctrl = ctx->ctrls[j]; + break; + } + } + if (WARN_ON(!ctrl)) + break; + + __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min); + } +} + static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) { struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); @@ -1634,6 +2060,157 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: p->codec.vp8.profile = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + p->codec.hevc.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p->codec.hevc.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + p->codec.hevc.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: + p->codec.hevc.rc_framerate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + p->codec.hevc.rc_min_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val, + p->codec.hevc.rc_max_qp); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + p->codec.hevc.rc_max_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp, + ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + p->codec.hevc.level_v4l2 = ctrl->val; + p->codec.hevc.level = hevc_level(ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + p->codec.hevc.tier = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: + p->codec.hevc.max_partition_depth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: + p->codec.hevc.num_refs_for_p = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + p->codec.hevc.refreshtype = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + p->codec.hevc.const_intra_period_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + p->codec.hevc.lossless_cu_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + p->codec.hevc.wavefront_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + p->codec.hevc.loopfilter = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: + p->codec.hevc.hier_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + p->codec.hevc.hier_qp_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: + p->codec.hevc.num_hier_layer = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: + p->codec.hevc.hier_qp_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: + p->codec.hevc.hier_qp_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: + p->codec.hevc.hier_qp_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: + p->codec.hevc.hier_qp_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: + p->codec.hevc.hier_qp_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: + p->codec.hevc.hier_qp_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: + p->codec.hevc.hier_qp_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: + p->codec.hevc.hier_bit_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: + p->codec.hevc.hier_bit_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: + p->codec.hevc.hier_bit_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: + p->codec.hevc.hier_bit_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: + p->codec.hevc.hier_bit_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: + p->codec.hevc.hier_bit_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: + p->codec.hevc.hier_bit_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: + p->codec.hevc.general_pb_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: + p->codec.hevc.temporal_id_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + p->codec.hevc.strong_intra_smooth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: + p->codec.hevc.intra_pu_split_disable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + p->codec.hevc.tmv_prediction_disable = !ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + p->codec.hevc.max_num_merge_mv = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: + p->codec.hevc.encoding_nostartcode_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + p->codec.hevc.refreshperiod = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + p->codec.hevc.lf_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + p->codec.hevc.lf_tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + p->codec.hevc.size_of_length_field = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val; + break; default: v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", ctrl->id, ctrl->val); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 16d553fcff08..8c295f0f9740 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -169,6 +169,9 @@ struct s5p_mfc_regs { void __iomem *d_decoded_third_addr;/* only v7 */ void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_min_scratch_buffer_size; /* v10 */ + void __iomem *d_static_buffer_addr; /* v10 */ + void __iomem *d_static_buffer_size; /* v10 */ /* encoder registers */ void __iomem *e_frame_width; @@ -268,6 +271,15 @@ struct s5p_mfc_regs { void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + void __iomem *e_min_scratch_buffer_size; /* v10 */ + void __iomem *e_num_t_layer; /* v10 */ + void __iomem *e_hier_qp_layer0; /* v10 */ + void __iomem *e_hier_bit_rate_layer0; /* v10 */ + void __iomem *e_hevc_options; /* v10 */ + void __iomem *e_hevc_refresh_period; /* v10 */ + void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */ + void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */ + void __iomem *e_hevc_nal_control; /* v10 */ }; struct s5p_mfc_hw_ops { @@ -311,6 +323,8 @@ struct s5p_mfc_hw_ops { unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); + int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev); + int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev); }; void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 88dbb9c341ec..7c629be43205 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -64,6 +64,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; int ret; mb_width = MB_WIDTH(ctx->img_width); @@ -74,7 +75,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size, ctx->chroma_size, ctx->mv_size); mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); } else if (ctx->type == MFCINST_ENCODER) { - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + ctx->tmv_buffer_size = 0; + } else if (IS_MFCV8_PLUS(dev)) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); @@ -82,14 +85,37 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); - - ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_LUMA_MB_TO_PIXEL_V6, - S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); - ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, - S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width); + lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height); + if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) { + ctx->luma_dpb_size = + ALIGN((mb_width * 16), 64) + * ALIGN((mb_height * 16), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((mb_width * 16), 64) + * (mb_height * 8) + + 64; + } else { + ctx->luma_dpb_size = + ALIGN((lcu_width * 32), 64) + * ALIGN((lcu_height * 32), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((lcu_width * 32), 64) + * (lcu_height * 16) + + 64; + } + } else { + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + } + if (IS_MFCV8_PLUS(dev)) ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( ctx->img_width, ctx->img_height, mb_width, mb_height), @@ -110,7 +136,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( mb_width, @@ -127,7 +155,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) (ctx->mv_count * ctx->mv_size); break; case S5P_MFC_CODEC_MPEG4_DEC: - if (IS_MFCV7_PLUS(dev)) { + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV7_PLUS(dev)) { ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7( mb_width, @@ -145,10 +175,14 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_VC1RCV_DEC: case S5P_MFC_CODEC_VC1_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; @@ -158,16 +192,21 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_H263_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_VP8_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( mb_width, @@ -181,8 +220,24 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; + case S5P_MFC_CODEC_HEVC_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_VP9_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + DEC_VP9_STATIC_BUFFER_SIZE; + break; case S5P_MFC_CODEC_H264_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( mb_width, @@ -202,10 +257,16 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, + mb_height), 16); + } else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = @@ -215,7 +276,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_VP8_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), + 16); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( mb_width, @@ -233,6 +299,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->chroma_dpb_size + ctx->me_buffer_size)); ctx->bank2.size = 0; break; + case S5P_MFC_CODEC_HEVC_ENC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; default: break; } @@ -267,6 +344,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: + case S5P_MFC_CODEC_HEVC_DEC: ctx->ctx.size = buf_size->h264_dec_ctx; break; case S5P_MFC_CODEC_MPEG4_DEC: @@ -275,11 +353,15 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VC1_DEC: case S5P_MFC_CODEC_MPEG2_DEC: case S5P_MFC_CODEC_VP8_DEC: + case S5P_MFC_CODEC_VP9_DEC: ctx->ctx.size = buf_size->other_dec_ctx; break; case S5P_MFC_CODEC_H264_ENC: ctx->ctx.size = buf_size->h264_enc_ctx; break; + case S5P_MFC_CODEC_HEVC_ENC: + ctx->ctx.size = buf_size->hevc_enc_ctx; + break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: case S5P_MFC_CODEC_VP8_ENC: @@ -356,6 +438,7 @@ static int calc_plane(int width, int height) static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) { + struct s5p_mfc_dev *dev = ctx->dev; ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" @@ -364,7 +447,7 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); - if (IS_MFCV8(ctx->dev)) { + if (IS_MFCV8_PLUS(ctx->dev)) { /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/ ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; @@ -372,9 +455,17 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { - ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + if (IS_MFCV10(dev)) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, + ctx->img_height); + } else { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + } + } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { + ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, ctx->img_height); - ctx->mv_size = ALIGN(ctx->mv_size, 16); + ctx->mv_size = ALIGN(ctx->mv_size, 32); } else { ctx->mv_size = 0; } @@ -445,7 +536,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); - if (IS_MFCV8(dev)) { + if (IS_MFCV8_PLUS(dev)) { writel(ctx->img_width, mfc_regs->d_first_plane_dpb_stride_size); writel(ctx->img_width, @@ -456,7 +547,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= ctx->scratch_buf_size; if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) { writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); writel(ctx->mv_count, mfc_regs->d_num_mv); } @@ -479,7 +571,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_regs->d_second_plane_dpb + i * 4); } if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { for (i = 0; i < ctx->mv_count; i++) { /* To test alignment */ align_gap = buf_addr1; @@ -494,6 +587,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= frame_size_mv; } } + if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) { + writel(buf_addr1, mfc_regs->d_static_buffer_addr); + writel(DEC_VP9_STATIC_BUFFER_SIZE, + mfc_regs->d_static_buffer_size); + buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE; + buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE; + } mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", buf_addr1, buf_size1, ctx->total_dpb_count); @@ -571,15 +671,34 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; - writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; - writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + - ctx->me_buffer_size); + if (IS_MFCV10(dev)) { + /* start address of per buffer is aligned */ + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + buf_size1 -= ctx->luma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + buf_size1 -= ctx->chroma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= ctx->me_buffer_size; + } + } else { + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } } writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); @@ -1321,6 +1440,162 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) return 0; } +static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + writel(reg, mfc_regs->e_gop_config); + + /* UHD encoding case */ + if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { + p_hevc->level = 51; + p_hevc->tier = 0; + /* this tier can be changed */ + } + + /* tier & level */ + reg = 0; + /* profile */ + reg |= p_hevc->profile & 0x3; + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->level << 8); + /* tier - 0 ~ 1 */ + reg |= (p_hevc->tier << 16); + writel(reg, mfc_regs->e_picture_profile); + + switch (p_hevc->loopfilter) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + p_hevc->loopfilter_disable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 0; + break; + } + + /* max partition depth */ + reg = 0; + reg |= (p_hevc->max_partition_depth & 0x1); + reg |= (p_hevc->num_refs_for_p-1) << 2; + reg |= (p_hevc->refreshtype & 0x3) << 3; + reg |= (p_hevc->const_intra_period_enable & 0x1) << 5; + reg |= (p_hevc->lossless_cu_enable & 0x1) << 6; + reg |= (p_hevc->wavefront_enable & 0x1) << 7; + reg |= (p_hevc->loopfilter_disable & 0x1) << 8; + reg |= (p_hevc->loopfilter_across & 0x1) << 9; + reg |= (p_hevc->enable_ltr & 0x1) << 10; + reg |= (p_hevc->hier_qp_enable & 0x1) << 11; + reg |= (p_hevc->general_pb_enable & 0x1) << 13; + reg |= (p_hevc->temporal_id_enable & 0x1) << 14; + reg |= (p_hevc->strong_intra_smooth & 0x1) << 15; + reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16; + reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17; + reg |= (p_hevc->max_num_merge_mv & 0x7) << 18; + reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23; + reg |= (p_hevc->prepend_sps_pps_to_idr << 26); + + writel(reg, mfc_regs->e_hevc_options); + /* refresh period */ + if (p_hevc->refreshtype) { + reg = 0; + reg |= (p_hevc->refreshperiod & 0xFFFF); + writel(reg, mfc_regs->e_hevc_refresh_period); + } + /* loop filter setting */ + if (!(p_hevc->loopfilter_disable & 0x1)) { + reg = 0; + reg |= (p_hevc->lf_beta_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2); + reg = 0; + reg |= (p_hevc->lf_tc_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2); + } + /* hier qp enable */ + if (p_hevc->num_hier_layer) { + reg = 0; + reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; + reg |= p_hevc->num_hier_layer & 0x7; + writel(reg, mfc_regs->e_num_t_layer); + /* QP value for each layer */ + if (p_hevc->hier_qp_enable) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_qp_layer[i], + mfc_regs->e_hier_qp_layer0 + i * 4); + } + if (p->rc_frame) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_bit_layer[i], + mfc_regs->e_hier_bit_rate_layer0 + + i * 4); + } + } + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + writel(reg, mfc_regs->e_rc_config); + /* frame QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_rc_config); + + /* frame rate */ + if (p->rc_frame) { + reg = 0; + reg &= ~(0xFFFF << 16); + reg |= ((p_hevc->rc_framerate) << 16); + reg &= ~(0xFFFF); + reg |= FRAME_DELTA_DEFAULT; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* max & min value of QP */ + reg = 0; + /* max QP */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_max_qp << 8); + /* min QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_min_qp; + writel(reg, mfc_regs->e_rc_qp_bound); + + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg &= ~(0xFF << 16); + reg |= (p_hevc->rc_b_frame_qp << 16); + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_p_frame_qp << 8); + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + mfc_debug_leave(); + + return 0; +} + /* Initialize decoding */ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) { @@ -1440,6 +1715,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params_h263(ctx); else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC) s5p_mfc_set_enc_params_vp8(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC) + s5p_mfc_set_enc_params_hevc(ctx); else { mfc_err("Unknown codec for encoding (%x).\n", ctx->codec_mode); @@ -1895,6 +2172,16 @@ static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) return readl(dev->mfc_regs->d_min_num_mv); } +static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_scratch_buffer_size); +} + +static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_min_scratch_buffer_size); +} + static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) { return readl(dev->mfc_regs->ret_instance_id); @@ -2109,7 +2396,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7); R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7); - if (!IS_MFCV8(dev)) + if (!IS_MFCV8_PLUS(dev)) goto done; /* Initialize registers used in MFC v8 only. @@ -2153,6 +2440,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8); R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8); R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8); + R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8); /* encoder registers */ R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8); @@ -2168,6 +2456,29 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8); R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8); R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); + R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); + + if (!IS_MFCV10(dev)) + goto done; + + /* Initialize registers used in MFC v10 only. + * Also, over-write the registers which have + * a different offset for MFC v10. + */ + + /* decoder registers */ + R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); + R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); + + /* encoder registers */ + R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10); + R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10); + R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10); + R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10); + R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10); + R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10); + R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10); + R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10); done: return &mfc_regs; @@ -2216,6 +2527,8 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, + .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size, + .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, }; struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index 80558484bb40..f013b291ae5b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -24,6 +24,13 @@ #define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) #define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) +#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) +#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) +#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) + +#define s5p_mfc_dec_hevc_mv_size(x, y) \ + (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512) /* Definition */ #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) @@ -39,6 +46,14 @@ #define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) #define FRAME_DELTA_H264_H263 1 #define TIGHT_CBR_MAX 10 +#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_HEVC_QP_INDEX_MIN -12 +#define ENC_HEVC_QP_INDEX_MAX 12 +#define ENC_HEVC_LOOP_FILTER_MIN -12 +#define ENC_HEVC_LOOP_FILTER_MAX 12 +#define ENC_HEVC_LEVEL_MAX 62 + +#define FRAME_DELTA_DEFAULT 1 struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 976ea0bb5b6c..1a0cde017fdf 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -520,8 +520,8 @@ static void sh_veu_colour_offset(struct sh_veu_dev *veu, struct sh_veu_vfmt *vfm /* dst_left and dst_top validity will be verified in CROP / COMPOSE */ unsigned int left = vfmt->frame.left & ~0x03; unsigned int top = vfmt->frame.top; - dma_addr_t offset = ((left * veu->vfmt_out.fmt->depth) >> 3) + - top * veu->vfmt_out.bytesperline; + dma_addr_t offset = (dma_addr_t)top * veu->vfmt_out.bytesperline + + (((dma_addr_t)left * veu->vfmt_out.fmt->depth) >> 3); unsigned int y_line; vfmt->offset_y = offset; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index c86dd2fdab84..69f0d8e80bd8 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -787,7 +787,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); int err; - dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + dev_dbg(icd->pdev, "mmap called, vma=%p\n", vma); if (icd->streamer != file) return -EBUSY; @@ -1788,17 +1788,19 @@ static int default_s_selection(struct soc_camera_device *icd, } static int default_g_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, g_parm, parm); + + return v4l2_g_parm_cap(icd->vdev, sd, a); } static int default_s_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, s_parm, parm); + + return v4l2_s_parm_cap(icd->vdev, sd, a); } static int default_enum_framesizes(struct soc_camera_device *icd, diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 0e5aa17bdd40..7c496bc1cf38 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 CEC driver * Copyright (C) STMicroelectronics SA 2017 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/clk.h> diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 9460b3080dca..2e1933d872ee 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for STM32 Digital Camera Memory Interface * @@ -5,7 +6,6 @@ * Authors: Yannick Fertre <yannick.fertre@st.com> * Hugues Fruchet <hugues.fruchet@st.com> * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 * * This driver is based on atmel_isi.c * @@ -93,6 +93,11 @@ enum state { #define MIN_HEIGHT 16U #define MAX_HEIGHT 2048U +#define MIN_JPEG_WIDTH 16U +#define MAX_JPEG_WIDTH 2592U +#define MIN_JPEG_HEIGHT 16U +#define MAX_JPEG_HEIGHT 2592U + #define TIMEOUT_MS 1000 struct dcmi_graph_entity { @@ -160,6 +165,7 @@ struct stm32_dcmi { dma_cookie_t dma_cookie; u32 misr; int errors_count; + int overrun_count; int buffers_count; }; @@ -190,14 +196,67 @@ static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) static int dcmi_start_capture(struct stm32_dcmi *dcmi); +static void dcmi_buffer_done(struct stm32_dcmi *dcmi, + struct dcmi_buf *buf, + size_t bytesused, + int err) +{ + struct vb2_v4l2_buffer *vbuf; + + if (!buf) + return; + + vbuf = &buf->vb; + + vbuf->sequence = dcmi->sequence++; + vbuf->field = V4L2_FIELD_NONE; + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused); + vb2_buffer_done(&vbuf->vb2_buf, + err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev_dbg(dcmi->dev, "buffer[%d] done seq=%d, bytesused=%zu\n", + vbuf->vb2_buf.index, vbuf->sequence, bytesused); + + dcmi->buffers_count++; + dcmi->active = NULL; +} + +static int dcmi_restart_capture(struct stm32_dcmi *dcmi) +{ + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->state != RUNNING) { + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + /* Restart a new DMA transfer with next buffer */ + if (list_empty(&dcmi->buffers)) { + dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n", + __func__); + dcmi->errors_count++; + dcmi->active = NULL; + + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + dcmi->active = list_entry(dcmi->buffers.next, + struct dcmi_buf, list); + list_del_init(&dcmi->active->list); + + spin_unlock_irq(&dcmi->irqlock); + + return dcmi_start_capture(dcmi); +} + static void dcmi_dma_callback(void *param) { struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param; struct dma_chan *chan = dcmi->dma_chan; struct dma_tx_state state; enum dma_status status; - - spin_lock(&dcmi->irqlock); + struct dcmi_buf *buf = dcmi->active; /* Check DMA status */ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); @@ -215,58 +274,18 @@ static void dcmi_dma_callback(void *param) case DMA_COMPLETE: dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__); - if (dcmi->active) { - struct dcmi_buf *buf = dcmi->active; - struct vb2_v4l2_buffer *vbuf = &dcmi->active->vb; - - vbuf->sequence = dcmi->sequence++; - vbuf->field = V4L2_FIELD_NONE; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vb2_set_plane_payload(&vbuf->vb2_buf, 0, buf->size); - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); - dev_dbg(dcmi->dev, "buffer[%d] done seq=%d\n", - vbuf->vb2_buf.index, vbuf->sequence); - - dcmi->buffers_count++; - dcmi->active = NULL; - } - - /* Restart a new DMA transfer with next buffer */ - if (dcmi->state == RUNNING) { - if (list_empty(&dcmi->buffers)) { - dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer", - __func__); - dcmi->errors_count++; - dcmi->active = NULL; - - spin_unlock(&dcmi->irqlock); - return; - } - - dcmi->active = list_entry(dcmi->buffers.next, - struct dcmi_buf, list); - - list_del_init(&dcmi->active->list); - - if (dcmi_start_capture(dcmi)) { - dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete", - __func__); - - spin_unlock(&dcmi->irqlock); - return; - } - - /* Enable capture */ - reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE); - } + /* Return buffer to V4L2 */ + dcmi_buffer_done(dcmi, buf, buf->size, 0); + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", + __func__); break; default: dev_err(dcmi->dev, "%s: Received unknown status\n", __func__); break; } - - spin_unlock(&dcmi->irqlock); } static int dcmi_start_dma(struct stm32_dcmi *dcmi, @@ -359,11 +378,57 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi) reg_set(dcmi->regs, DCMI_CR, CR_CROP); } +static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) +{ + struct dma_tx_state state; + enum dma_status status; + struct dma_chan *chan = dcmi->dma_chan; + struct dcmi_buf *buf = dcmi->active; + + if (!buf) + return; + + /* + * Because of variable JPEG buffer size sent by sensor, + * DMA transfer never completes due to transfer size + * never reached. + * In order to ensure that all the JPEG data are transferred + * in active buffer memory, DMA is drained. + * Then DMA tx status gives the amount of data transferred + * to memory, which is then returned to V4L2 through the active + * buffer payload. + */ + + /* Drain DMA */ + dmaengine_synchronize(chan); + + /* Get DMA residue to get JPEG size */ + status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); + if (status != DMA_ERROR && state.residue < buf->size) { + /* Return JPEG buffer to V4L2 with received JPEG buffer size */ + dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0); + } else { + dcmi->errors_count++; + dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n", + __func__); + /* Return JPEG buffer to V4L2 in ERROR state */ + dcmi_buffer_done(dcmi, buf, 0, -EIO); + } + + /* Abort DMA operation */ + dmaengine_terminate_all(dcmi->dma_chan); + + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n", + __func__); +} + static irqreturn_t dcmi_irq_thread(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; - spin_lock(&dcmi->irqlock); + spin_lock_irq(&dcmi->irqlock); /* Stop capture is required */ if (dcmi->state == STOPPING) { @@ -373,50 +438,41 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) complete(&dcmi->complete); - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { - /* - * An overflow or an error has been detected, - * stop current DMA transfert & restart it - */ - dev_warn(dcmi->dev, "%s: Overflow or error detected\n", - __func__); - dcmi->errors_count++; - dmaengine_terminate_all(dcmi->dma_chan); - - reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - - dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n"); - - if (dcmi_start_capture(dcmi)) { - dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", - __func__); + if (dcmi->misr & IT_OVR) + dcmi->overrun_count++; + } - spin_unlock(&dcmi->irqlock); - return IRQ_HANDLED; - } + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && + dcmi->misr & IT_FRAME) { + /* JPEG received */ + spin_unlock_irq(&dcmi->irqlock); + dcmi_process_jpeg(dcmi); + return IRQ_HANDLED; } - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } static irqreturn_t dcmi_irq_callback(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; + unsigned long flags; - spin_lock(&dcmi->irqlock); + spin_lock_irqsave(&dcmi->irqlock, flags); dcmi->misr = reg_read(dcmi->regs, DCMI_MIS); /* Clear interrupt */ reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock(&dcmi->irqlock); + spin_unlock_irqrestore(&dcmi->irqlock, flags); return IRQ_WAKE_THREAD; } @@ -483,7 +539,7 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); - dev_dbg(dcmi->dev, "buffer[%d] phy=0x%pad size=%zu\n", + dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", vb->index, &buf->paddr, buf->size); } @@ -495,29 +551,24 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); - unsigned long flags = 0; - spin_lock_irqsave(&dcmi->irqlock, flags); + spin_lock_irq(&dcmi->irqlock); - if ((dcmi->state == RUNNING) && (!dcmi->active)) { + if (dcmi->state == RUNNING && !dcmi->active) { dcmi->active = buf; dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n", buf->vb.vb2_buf.index); - if (dcmi_start_capture(dcmi)) { + spin_unlock_irq(&dcmi->irqlock); + if (dcmi_start_capture(dcmi)) dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", __func__); - - spin_unlock_irqrestore(&dcmi->irqlock, flags); - return; - } } else { /* Enqueue to video buffers list */ list_add_tail(&buf->list, &dcmi->buffers); + spin_unlock_irq(&dcmi->irqlock); } - - spin_unlock_irqrestore(&dcmi->irqlock, flags); } static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) @@ -529,7 +580,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) ret = clk_enable(dcmi->mclk); if (ret) { - dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock", + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n", __func__); goto err_release_buffers; } @@ -578,6 +629,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (dcmi->do_crop) dcmi_set_crop(dcmi); + /* Enable jpeg capture */ + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) + reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ + /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); @@ -585,6 +640,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi->sequence = 0; dcmi->errors_count = 0; + dcmi->overrun_count = 0; dcmi->buffers_count = 0; dcmi->active = NULL; @@ -603,20 +659,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dev_dbg(dcmi->dev, "Start streaming, starting capture\n"); + spin_unlock_irq(&dcmi->irqlock); ret = dcmi_start_capture(dcmi); if (ret) { - dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture", + dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", __func__); - - spin_unlock_irq(&dcmi->irqlock); goto err_subdev_streamoff; } /* Enable interruptions */ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock_irq(&dcmi->irqlock); - return 0; err_subdev_streamoff: @@ -656,9 +709,12 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Disable stream on the sub device */ ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); if (ret && ret != -ENOIOCTLCMD) - dev_err(dcmi->dev, "stream off failed in subdev\n"); + dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", + __func__, ret); + spin_lock_irq(&dcmi->irqlock); dcmi->state = STOPPING; + spin_unlock_irq(&dcmi->irqlock); timeout = wait_for_completion_interruptible_timeout(&dcmi->complete, time_ms); @@ -672,7 +728,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE); if (!timeout) { - dev_err(dcmi->dev, "Timeout during stop streaming\n"); + dev_err(dcmi->dev, "%s: Timeout during stop streaming\n", + __func__); dcmi->state = STOPPED; } @@ -694,8 +751,13 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) clk_disable(dcmi->mclk); - dev_dbg(dcmi->dev, "Stop streaming, errors=%d buffers=%d\n", - dcmi->errors_count, dcmi->buffers_count); + if (dcmi->errors_count) + dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); + dev_dbg(dcmi->dev, "Stop streaming, errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); } static const struct vb2_ops dcmi_video_qops = { @@ -749,7 +811,7 @@ static void __find_outer_frame_size(struct stm32_dcmi *dcmi, int h_err = (fsize->height - pix->height); int err = w_err + h_err; - if ((w_err >= 0) && (h_err >= 0) && (err < min_err)) { + if (w_err >= 0 && h_err >= 0 && err < min_err) { min_err = err; match = fsize; } @@ -771,6 +833,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; + bool do_crop; int ret; sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); @@ -780,10 +843,19 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } /* Limit to hardware capabilities */ - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + pix->width = clamp(pix->width, MIN_JPEG_WIDTH, MAX_JPEG_WIDTH); + pix->height = + clamp(pix->height, MIN_JPEG_HEIGHT, MAX_JPEG_HEIGHT); + } else { + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + } - if (dcmi->do_crop && dcmi->num_of_sd_framesizes) { + /* No crop if JPEG is requested */ + do_crop = dcmi->do_crop && (pix->pixelformat != V4L2_PIX_FMT_JPEG); + + if (do_crop && dcmi->num_of_sd_framesizes) { struct dcmi_framesize outer_sd_fsize; /* * If crop is requested and sensor have discrete frame sizes, @@ -807,7 +879,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, sd_fsize.width = pix->width; sd_fsize.height = pix->height; - if (dcmi->do_crop) { + if (do_crop) { struct v4l2_rect c = dcmi->crop; struct v4l2_rect max_rect; @@ -862,6 +934,10 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) if (ret) return ret; + /* Disable crop if JPEG is requested */ + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) + dcmi->do_crop = false; + /* pix to mbus format */ v4l2_fill_mbus_format(mf, pix, sd_format->mbus_code); @@ -1084,10 +1160,10 @@ static int dcmi_s_selection(struct file *file, void *priv, r.top = clamp_t(s32, r.top, 0, pix.height - r.height); r.left = clamp_t(s32, r.left, 0, pix.width - r.width); - if (!((r.top == dcmi->sd_bounds.top) && - (r.left == dcmi->sd_bounds.left) && - (r.width == dcmi->sd_bounds.width) && - (r.height == dcmi->sd_bounds.height))) { + if (!(r.top == dcmi->sd_bounds.top && + r.left == dcmi->sd_bounds.left && + r.width == dcmi->sd_bounds.width && + r.height == dcmi->sd_bounds.height)) { /* Crop if request is different than sensor resolution */ dcmi->do_crop = true; dcmi->crop = r; @@ -1167,6 +1243,22 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, return 0; } +static int dcmi_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + +static int dcmi_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + static int dcmi_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { @@ -1269,6 +1361,9 @@ static const struct v4l2_ioctl_ops dcmi_ioctl_ops = { .vidioc_g_input = dcmi_g_input, .vidioc_s_input = dcmi_s_input, + .vidioc_g_parm = dcmi_g_parm, + .vidioc_s_parm = dcmi_s_parm, + .vidioc_enum_framesizes = dcmi_enum_framesizes, .vidioc_enum_frameintervals = dcmi_enum_frameintervals, @@ -1334,6 +1429,10 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_JPEG, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + .bpp = 1, }, }; diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index f77be9302120..e9a02639554b 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1112,7 +1112,7 @@ static int viacam_g_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, g_parm, parm); + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; @@ -1125,7 +1125,7 @@ static int viacam_s_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, s_parm, parm); + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 9d63c84a9876..617415c224fe 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -434,7 +434,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, v4l2_set_subdevdata(sd, ved); /* Expose this subdev to user space */ - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; /* Initialize the media entity */ ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 4d663e89d33f..6e10b63ba9ec 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -533,7 +533,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_deb_ops); diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index e1602e0bc230..e583ec7a91da 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -395,7 +395,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_sca_ops); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 457e211514c6..605e2a2d5dd5 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -23,6 +23,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/v4l2-subdev.h> #include <media/tpg/v4l2-tpg.h> @@ -284,11 +285,18 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static struct v4l2_subdev_core_ops vimc_sen_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { .s_stream = vimc_sen_s_stream, }; static const struct v4l2_subdev_ops vimc_sen_ops = { + .core = &vimc_sen_core_ops, .pad = &vimc_sen_pad_ops, .video = &vimc_sen_video_ops, }; @@ -378,7 +386,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 1, + MEDIA_ENT_F_CAM_SENSOR, 1, (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, &vimc_sen_ops); if (ret) diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index b55d278d38a7..71105fa4c5f9 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-cec.c - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <media/cec.h> @@ -82,11 +70,18 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, if (adap == NULL) return; - ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL + - len * 10 * CEC_TIM_DATA_BIT_TOTAL)); - cec_queue_pin_cec_event(adap, false, ts); + + /* + * Suffix ULL on constant 10 makes the expression + * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL + * to be evaluated using 64-bit unsigned arithmetic (u64), which + * is what ktime_sub_us expects as second argument. + */ + ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); + cec_queue_pin_cec_event(adap, false, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); for (i = 0; i < 10 * len; i++) { @@ -101,12 +96,12 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, bit = cec_msg_is_broadcast(msg) ^ nacked; break; } - cec_queue_pin_cec_event(adap, false, ts); + cec_queue_pin_cec_event(adap, false, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); else ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); else diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h index 3926b1422777..7524ed48a914 100644 --- a/drivers/media/platform/vivid/vivid-cec.h +++ b/drivers/media/platform/vivid/vivid-cec.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-cec.h - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifdef CONFIG_VIDEO_VIVID_CEC diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 9f036c5f51b0..82ec216f2ad8 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-core.c - A Virtual Video Test Driver, core initialization * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index c90e4a0ab94e..477c80a4d44c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-core.h - core datastructures * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CORE_H_ diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 3f9d354827af..6b0bfa091592 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-ctrls.c - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -1208,6 +1196,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; break; case V4L2_CID_RDS_RECEPTION: dev->radio_rx_rds_enabled = ctrl->val; @@ -1282,6 +1271,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; if (!dev->radio_tx_rds_controls) dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; break; case V4L2_CID_RDS_TX_PTY: if (dev->radio_rx_rds_controls) diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h index 9bcca9d56359..6fad5f5d0054 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.h +++ b/drivers/media/platform/vivid/vivid-ctrls.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-ctrls.h - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CTRLS_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 6ca71aabb576..3fdb280c36ca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h index 5b92fc9a0d04..0f43015306d6 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.h +++ b/drivers/media/platform/vivid/vivid-kthread-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index 98eed5889bc1..9981e7548019 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h index 2bf04a17b05d..d5bcf44bbaca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.h +++ b/drivers/media/platform/vivid/vivid-kthread-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index bdc380b14e0c..bbbc1b6938a5 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-osd.c - osd support for testing overlays. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h index 57c9daa5940a..f9ac1af25dd3 100644 --- a/drivers/media/platform/vivid/vivid-osd.h +++ b/drivers/media/platform/vivid/vivid-osd.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-osd.h - output overlay support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_OSD_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c index 78c1e920670a..7c8efe38ff5b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.c +++ b/drivers/media/platform/vivid/vivid-radio-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-common.c - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h index 92fe589141b7..30a9900e5b2b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.h +++ b/drivers/media/platform/vivid/vivid-radio-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-common.h - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c index f834f7df8cf9..1f86d7d4f72f 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-rx.c - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -259,7 +247,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) vt->rangehigh = FM_FREQ_RANGE_HIGH; sig_qual = dev->radio_rx_sig_qual; vt->signal = abs(sig_qual) > delta ? 0 : - 0xffff - (abs(sig_qual) * 0xffff) / delta; + 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta; vt->afc = sig_qual > delta ? 0 : sig_qual; if (abs(sig_qual) > delta) vt->rxsubchans = 0; diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h index 2b33edb60942..c9c7849f6f99 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.h +++ b/drivers/media/platform/vivid/vivid-radio-rx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-rx.h - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_RX_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c index 308b13f85dc0..1a3749ba5e7e 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.c +++ b/drivers/media/platform/vivid/vivid-radio-tx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-tx.c - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h index 3c3343d70cbc..c2bf1e7e634a 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.h +++ b/drivers/media/platform/vivid/vivid-radio-tx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-tx.h - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_TX_H_ diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c index 996e35e28d37..39ca9a56448c 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ b/drivers/media/platform/vivid/vivid-rds-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-rds-gen.c - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/kernel.h> diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h index e55e3b22b7ca..35ac5742302b 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.h +++ b/drivers/media/platform/vivid/vivid-rds-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-rds-gen.h - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RDS_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index ebd7b9c4dd83..cfb7cb4d37a8 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-sdr-cap.c - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h index 43014b2733db..813c9248e5a7 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.h +++ b/drivers/media/platform/vivid/vivid-sdr-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-sdr-cap.h - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_SDR_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index d66ef95dd2b5..92a852955173 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-cap.c - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h index 2d8ea0bac743..91d2de01381c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.h +++ b/drivers/media/platform/vivid/vivid-vbi-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-cap.h - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c index 02c79d7cedab..acc98445a1fa 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-gen.c - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h index 8444abe905ea..2657a7f5571c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.h +++ b/drivers/media/platform/vivid/vivid-vbi-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-gen.h - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index d2989195cf03..69486c130a7e 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-out.c - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h index 6555ba9d2860..76584940cdaf 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.h +++ b/drivers/media/platform/vivid/vivid-vbi-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-out.h - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 0fbbcde19f0d..01c703683657 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-cap.c - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -573,9 +561,8 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, mp->field = vivid_field_cap(dev, mp->field); if (vivid_is_webcam(dev)) { const struct v4l2_frmsize_discrete *sz = - v4l2_find_nearest_format(webcam_sizes, - VIVID_WEBCAM_SIZES, - mp->width, mp->height); + v4l2_find_nearest_size(webcam_sizes, width, height, + mp->width, mp->height); w = sz->width; h = sz->height; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h index 94079815dbc2..47d8b48820df 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.h +++ b/drivers/media/platform/vivid/vivid-vid-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-cap.h - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index a651527d80db..e5914be0e12d 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-common.c - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -874,7 +862,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (edid->start_block + edid->blocks > dev->edid_blocks) edid->blocks = dev->edid_blocks - edid->start_block; - cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); + if (adap) + cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 4b6175eab8a2..29b6c0b40a1b 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-common.h - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 0b1b6218ede8..51fec66d8d45 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-out.c - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h index dfa84db184ed..e87aacf843c5 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-out.h - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_OUT_H_ diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 4257451f1bd8..0b86ed01e85d 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -509,7 +509,8 @@ static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm) return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); else - return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR)); + return !!(vsp1_read(vsp1, VI6_CMD(dlm->index)) + & VI6_CMD_UPDHDR); } static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 7ce69f23f50a..b8fee1834253 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -27,6 +27,7 @@ #include "vsp1_pipe.h" #include "vsp1_rwpf.h" +#define BRU_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS" /* ----------------------------------------------------------------------------- * Interrupt Handling @@ -88,7 +89,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, struct vsp1_entity *next; struct vsp1_dl_list *dl; struct v4l2_subdev_format format; - const char *bru_name; unsigned long flags; unsigned int i; int ret; @@ -99,7 +99,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, drm_pipe = &vsp1->drm->pipe[pipe_index]; pipe = &drm_pipe->pipe; bru = to_bru(&pipe->bru->subdev); - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; if (!cfg) { /* @@ -165,7 +164,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); } format.pad = pipe->bru->source_pad; @@ -181,7 +180,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); format.pad = RWPF_PAD_SINK; ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL, @@ -473,9 +472,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, format.pad); + format.format.code, BRU_NAME(pipe->bru), format.pad); sel.pad = bru_input; sel.target = V4L2_SEL_TGT_COMPOSE; @@ -486,10 +485,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, - "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n", __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, - sel.pad); + BRU_NAME(pipe->bru), sel.pad); return 0; } @@ -514,12 +512,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_entity *entity; struct vsp1_entity *next; struct vsp1_dl_list *dl; - const char *bru_name; unsigned int i; int ret; - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; - /* Prepare the display list. */ dl = vsp1_dl_list_get(pipe->output->dlm); @@ -530,6 +525,15 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; + /* + * Make sure we don't accept more inputs than the hardware can + * handle. This is a temporary fix to avoid display stall, we + * need to instead allocate the BRU or BRS to display pipelines + * dynamically based on the number of planes they each use. + */ + if (pipe->num_inputs >= pipe->bru->source_pad) + pipe->inputs[i] = NULL; + if (!pipe->inputs[i]) continue; @@ -561,7 +565,7 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) rpf->entity.sink_pad = i; dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n", - __func__, rpf->entity.index, bru_name, i); + __func__, rpf->entity.index, BRU_NAME(pipe->bru), i); ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e6fa16d7fda8..704920753998 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -155,6 +155,18 @@ static void lif_configure(struct vsp1_entity *entity, (obth << VI6_LIF_CTRL_OBTH_SHIFT) | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); + + /* + * On R-Car V3M the LIF0 buffer attribute register has to be set to a + * non-default value to guarantee proper operation (otherwise artifacts + * may appear on the output). The value required by the manual is not + * explained but is likely a buffer size or threshold. + */ + if ((entity->vsp1->version & VI6_IP_VERSION_MASK) == + (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M)) + vsp1_lif_write(lif, dl, VI6_LIF_LBA, + VI6_LIF_LBA_LBA0 | + (1536 << VI6_LIF_LBA_LBA1_SHIFT)); } static const struct vsp1_entity_operations lif_entity_ops = { diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 26c4ffad2f46..dae0c1901297 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -225,7 +225,7 @@ #define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_BOTH (3 << 8) -#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff < 0) +#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0) #define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0 /* ----------------------------------------------------------------------------- @@ -693,6 +693,11 @@ #define VI6_LIF_CSBTH_LBTH_MASK (0x7ff << 0) #define VI6_LIF_CSBTH_LBTH_SHIFT 0 +#define VI6_LIF_LBA 0x3b0c +#define VI6_LIF_LBA_LBA0 (1 << 31) +#define VI6_LIF_LBA_LBA1_MASK (0xfff << 16) +#define VI6_LIF_LBA_LBA1_SHIFT 16 + /* ----------------------------------------------------------------------------- * Security Control Registers */ @@ -705,6 +710,7 @@ */ #define VI6_IP_VERSION 0x3f00 +#define VI6_IP_VERSION_MASK (0xffff << 0) #define VI6_IP_VERSION_MODEL_MASK (0xff << 8) #define VI6_IP_VERSION_MODEL_VSPS_H2 (0x09 << 8) #define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8) diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index dc6c4f985911..0f292c6ba338 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -511,7 +511,7 @@ static int usb_amradio_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct amradio_device *radio; - int retval = 0; + int retval; radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 70a2c86774ce..9a5079d64c4a 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/kernel.h> diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 58e944591602..8f9f8dfc3497 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -671,7 +671,7 @@ fail: static int wl1273_fm_suspend(struct wl1273_device *radio) { struct wl1273_core *core = radio->core; - int r = 0; + int r; /* Cannot go from OFF to SUSPENDED */ if (core->mode == WL1273_MODE_RX) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index e0054e0f410d..b94d66e53d4e 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -207,6 +207,15 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) unsigned long time_left; bool timed_out = false; + retval = si470x_get_register(radio, POWERCFG); + if (retval) + return retval; + + if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE)) + != (POWERCFG_ENABLE|POWERCFG_DMUTE)) { + return 0; + } + /* start tuning */ radio->registers[CHANNEL] &= ~CHANNEL_CHAN; radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; @@ -377,8 +386,12 @@ int si470x_start(struct si470x_device *radio) goto done; /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = - (de << 11) & SYSCONFIG1_DE; /* DE*/ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN | + SYSCONFIG1_RDS; + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; + radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT; + if (de) + radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE; retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) goto done; diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b3034f80163f..41709b24b28f 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -43,7 +43,6 @@ static const struct i2c_device_id si470x_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, si470x_i2c_id); - /************************************************************************** * Module Parameters **************************************************************************/ @@ -362,22 +361,43 @@ static int si470x_i2c_probe(struct i2c_client *client, mutex_init(&radio->lock); init_completion(&radio->completion); + retval = v4l2_device_register(&client->dev, &radio->v4l2_dev); + if (retval < 0) { + dev_err(&client->dev, "couldn't register v4l2_device\n"); + goto err_radio; + } + + v4l2_ctrl_handler_init(&radio->hdl, 2); + v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15); + if (radio->hdl.error) { + retval = radio->hdl.error; + dev_err(&client->dev, "couldn't register control\n"); + goto err_dev; + } + /* video device initialization */ radio->videodev = si470x_viddev_template; + radio->videodev.ctrl_handler = &radio->hdl; + radio->videodev.lock = &radio->lock; + radio->videodev.v4l2_dev = &radio->v4l2_dev; + radio->videodev.release = video_device_release_empty; video_set_drvdata(&radio->videodev, radio); /* power up : need 110ms */ radio->registers[POWERCFG] = POWERCFG_ENABLE; if (si470x_set_register(radio, POWERCFG) < 0) { retval = -EIO; - goto err_radio; + goto err_ctrl; } msleep(110); /* get device and chip versions */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; - goto err_radio; + goto err_ctrl; } dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[SI_CHIPID]); @@ -407,7 +427,7 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; - goto err_radio; + goto err_ctrl; } /* rds buffer configuration */ @@ -437,6 +457,10 @@ err_all: free_irq(client->irq, radio); err_rds: kfree(radio->buffer); +err_ctrl: + v4l2_ctrl_handler_free(&radio->hdl); +err_dev: + v4l2_device_unregister(&radio->v4l2_dev); err_radio: kfree(radio); err_initial: diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index c311f9951d80..2277e850bb5e 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -578,7 +578,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, struct si470x_device *radio; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - int i, int_end_size, retval = 0; + int i, int_end_size, retval; unsigned char version_warning = 0; /* private data allocation and initialization */ diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index eb7b834a0ae5..0202f8eb90c4 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -79,6 +79,8 @@ #define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ #define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ #define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ +#define SYSCONFIG1_GPIO2_DIS 0x0000 /* Disable GPIO 2 interrupt */ +#define SYSCONFIG1_GPIO2_INT 0x0004 /* Enable STC/RDS interrupt */ #define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ #define SYSCONFIG2 5 /* System Configuration 2 */ diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index a115db24667b..05c66701a899 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* kernel includes */ diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index f14ead5954e0..eb2c3b6eca7f 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -28,14 +28,12 @@ config LIRC menuconfig RC_DECODERS bool "Remote controller decoders" depends on RC_CORE - default y if RC_DECODERS config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with NEC protocol, and @@ -45,7 +43,6 @@ config IR_RC5_DECODER tristate "Enable IR raw decoder for the RC-5 protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with RC-5 protocol, and @@ -55,7 +52,6 @@ config IR_RC6_DECODER tristate "Enable IR raw decoder for the RC6 protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -65,7 +61,6 @@ config IR_JVC_DECODER tristate "Enable IR raw decoder for the JVC protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -75,7 +70,6 @@ config IR_SONY_DECODER tristate "Enable IR raw decoder for the Sony protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -84,7 +78,6 @@ config IR_SONY_DECODER config IR_SANYO_DECODER tristate "Enable IR raw decoder for the Sanyo protocol" depends on RC_CORE - default y ---help--- Enable this option if you have an infrared remote control which @@ -94,7 +87,6 @@ config IR_SANYO_DECODER config IR_SHARP_DECODER tristate "Enable IR raw decoder for the Sharp protocol" depends on RC_CORE - default y ---help--- Enable this option if you have an infrared remote control which @@ -105,7 +97,6 @@ config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have a Microsoft Remote Keyboard for @@ -116,11 +107,19 @@ config IR_XMP_DECODER tristate "Enable IR raw decoder for the XMP protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with XMP protocol, and if the IR is decoded in software + +config IR_IMON_DECODER + tristate "Enable IR raw decoder for the iMON protocol" + depends on RC_CORE + ---help--- + Enable this option if you have iMON PAD or Antec Veris infrared + remote control and you would like to use it with a raw IR + receiver, or if you wish to use an encoder to transmit this IR. + endif #RC_DECODERS menuconfig RC_DEVICES @@ -185,6 +184,18 @@ config IR_IMON To compile this driver as a module, choose M here: the module will be called imon. +config IR_IMON_RAW + tristate "SoundGraph iMON Receiver (early raw IR models)" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a SoundGraph iMON IR Receiver, + early raw models. + + To compile this driver as a module, choose M here: the + module will be called imon_raw. + config IR_MCEUSB tristate "Windows Media Center Ed. eHome Infrared Transceiver" depends on USB_ARCH_HAS_HCD @@ -446,7 +457,6 @@ config IR_SERIAL config IR_SERIAL_TRANSMITTER bool "Serial Port Transmitter" - default y depends on IR_SERIAL ---help--- Serial Port Transmitter support diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 0e857816ac2d..2e1c87066f6c 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -14,11 +14,13 @@ obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o +obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o # stand-alone IR receivers/transmitters obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o obj-$(CONFIG_IR_IMON) += imon.o +obj-$(CONFIG_IR_IMON_RAW) += imon_raw.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_FINTEK) += fintek-cir.o diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 950d068ba806..1041c056854d 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -92,7 +92,6 @@ struct imon_usb_dev_descr { __u16 flags; #define IMON_NO_FLAGS 0 #define IMON_NEED_20MS_PKT_DELAY 1 -#define IMON_IR_RAW 2 struct imon_panel_key_table key_table[]; }; @@ -123,12 +122,6 @@ struct imon_context { unsigned char usb_tx_buf[8]; unsigned int send_packet_delay; - struct rx_data { - int count; /* length of 0 or 1 sequence */ - int prev_bit; /* logic level of sequence */ - int initial_space; /* initial space flag */ - } rx; - struct tx_t { unsigned char data_buf[35]; /* user data buffer */ struct completion finished; /* wait for write to finish */ @@ -331,10 +324,6 @@ static const struct imon_usb_dev_descr imon_DH102 = { } }; -static const struct imon_usb_dev_descr imon_ir_raw = { - .flags = IMON_IR_RAW, -}; - /* * USB Device ID for iMON USB Control Boards * @@ -418,18 +407,6 @@ static const struct usb_device_id imon_usb_id_table[] = { /* device specifics unknown */ { USB_DEVICE(0x15c2, 0x0046), .driver_info = (unsigned long)&imon_default_table}, - /* TriGem iMON (IR only) -- TG_iMON.inf */ - { USB_DEVICE(0x0aa8, 0x8001), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON (IR only) -- sg_imon.inf */ - { USB_DEVICE(0x04e8, 0xff30), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ - { USB_DEVICE(0x0aa8, 0xffda), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ - { USB_DEVICE(0x15c2, 0xffda), - .driver_info = (unsigned long)&imon_ir_raw}, {} }; @@ -1133,18 +1110,18 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; *rc_proto = RC_PROTO_BIT_RC6_MCE; - } else if (*rc_proto & RC_PROTO_BIT_OTHER) { + } else if (*rc_proto & RC_PROTO_BIT_IMON) { dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_proto = RC_PROTO_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_IMON; } else { dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_proto = RC_PROTO_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_IMON; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); @@ -1411,7 +1388,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1478,7 +1455,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1572,94 +1549,11 @@ static int imon_parse_press_type(struct imon_context *ictx, /* * Process the incoming packet */ -/* - * Convert bit count to time duration (in us) and submit - * the value to lirc_dev. - */ -static void submit_data(struct imon_context *context) -{ - DEFINE_IR_RAW_EVENT(ev); - - ev.pulse = context->rx.prev_bit; - ev.duration = US_TO_NS(context->rx.count * BIT_DURATION); - ir_raw_event_store_with_filter(context->rdev, &ev); -} - -/* - * Process the incoming packet - */ -static void imon_incoming_ir_raw(struct imon_context *context, +static void imon_incoming_packet(struct imon_context *ictx, struct urb *urb, int intf) { int len = urb->actual_length; unsigned char *buf = urb->transfer_buffer; - struct device *dev = context->dev; - int octet, bit; - unsigned char mask; - - if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n", - __func__, len, intf); - return; - } - - if (debug) - dev_info(dev, "raw packet: %*ph\n", len, buf); - /* - * Translate received data to pulse and space lengths. - * Received data is active low, i.e. pulses are 0 and - * spaces are 1. - * - * My original algorithm was essentially similar to - * Changwoo Ryu's with the exception that he switched - * the incoming bits to active high and also fed an - * initial space to LIRC at the start of a new sequence - * if the previous bit was a pulse. - * - * I've decided to adopt his algorithm. - */ - - if (buf[7] == 1 && context->rx.initial_space) { - /* LIRC requires a leading space */ - context->rx.prev_bit = 0; - context->rx.count = 4; - submit_data(context); - context->rx.count = 0; - } - - for (octet = 0; octet < 5; ++octet) { - mask = 0x80; - for (bit = 0; bit < 8; ++bit) { - int curr_bit = !(buf[octet] & mask); - - if (curr_bit != context->rx.prev_bit) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.prev_bit = curr_bit; - } - ++context->rx.count; - mask >>= 1; - } - } - - if (buf[7] == 10) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.initial_space = context->rx.prev_bit; - } - - ir_raw_event_handle(context->rdev); -} - -static void imon_incoming_scancode(struct imon_context *ictx, - struct urb *urb, int intf) -{ - int len = urb->actual_length; - unsigned char *buf = urb->transfer_buffer; struct device *dev = ictx->dev; unsigned long flags; u32 kc; @@ -1745,11 +1639,18 @@ static void imon_incoming_scancode(struct imon_context *ictx, if (press_type == 0) rc_keyup(ictx->rdev); else { - if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || - ictx->rc_proto == RC_PROTO_BIT_OTHER) - rc_keydown(ictx->rdev, - ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ? RC_PROTO_RC6_MCE : RC_PROTO_OTHER, - ictx->rc_scancode, ictx->rc_toggle); + enum rc_proto proto; + + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) + proto = RC_PROTO_RC6_MCE; + else if (ictx->rc_proto == RC_PROTO_BIT_IMON) + proto = RC_PROTO_IMON; + else + return; + + rc_keydown(ictx->rdev, proto, ictx->rc_scancode, + ictx->rc_toggle); + spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1839,10 +1740,7 @@ static void usb_rx_callback_intf0(struct urb *urb) break; case 0: - if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) - imon_incoming_ir_raw(ictx, urb, intfnum); - else - imon_incoming_scancode(ictx, urb, intfnum); + imon_incoming_packet(ictx, urb, intfnum); break; default: @@ -1883,10 +1781,7 @@ static void usb_rx_callback_intf1(struct urb *urb) break; case 0: - if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) - imon_incoming_ir_raw(ictx, urb, intfnum); - else - imon_incoming_scancode(ictx, urb, intfnum); + imon_incoming_packet(ictx, urb, intfnum); break; default: @@ -1912,7 +1807,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_PROTO_BIT_OTHER; + u64 allowed_protos = RC_PROTO_BIT_IMON; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -1960,8 +1855,10 @@ static void imon_get_ffdc_type(struct imon_context *ictx) default: dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - /* We don't know which one it is, allow user to set the - * RC6 one from userspace if OTHER wasn't correct. */ + /* + * We don't know which one it is, allow user to set the + * RC6 one from userspace if IMON wasn't correct. + */ allowed_protos |= RC_PROTO_BIT_RC6_MCE; break; } @@ -2000,14 +1897,11 @@ static void imon_set_display_type(struct imon_context *ictx) case 0x0041: case 0x0042: case 0x0043: - case 0x8001: - case 0xff30: configured_display_type = IMON_DISPLAY_TYPE_NONE; ictx->display_supported = false; break; case 0x0036: case 0x0044: - case 0xffda: default: configured_display_type = IMON_DISPLAY_TYPE_VFD; break; @@ -2032,8 +1926,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) static const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 }; - rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ? - RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE); + rdev = rc_allocate_device(RC_DRIVER_SCANCODE); if (!rdev) { dev_err(ictx->dev, "remote control dev allocation failed\n"); goto out; @@ -2051,12 +1944,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->dev.parent = ictx->dev; rdev->priv = ictx; - if (ictx->dev_descr->flags & IMON_IR_RAW) - rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - else - /* iMON PAD or MCE */ - rdev->allowed_protocols = RC_PROTO_BIT_OTHER | - RC_PROTO_BIT_RC6_MCE; + /* iMON PAD or MCE */ + rdev->allowed_protocols = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE; rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -2074,8 +1963,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) imon_set_display_type(ictx); - if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || - ictx->dev_descr->flags & IMON_IR_RAW) + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) rdev->map_name = RC_MAP_IMON_MCE; else rdev->map_name = RC_MAP_IMON_PAD; diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c new file mode 100644 index 000000000000..32709f96de14 --- /dev/null +++ b/drivers/media/rc/imon_raw.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2018 Sean Young <sean@mess.org> + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/input.h> +#include <media/rc-core.h> + +/* Each bit is 250us */ +#define BIT_DURATION 250000 + +struct imon { + struct device *dev; + struct urb *ir_urb; + struct rc_dev *rcdev; + u8 ir_buf[8]; + char phys[64]; +}; + +/* + * ffs/find_next_bit() searches in the wrong direction, so open-code our own. + */ +static inline int is_bit_set(const u8 *buf, int bit) +{ + return buf[bit / 8] & (0x80 >> (bit & 7)); +} + +static void imon_ir_data(struct imon *imon) +{ + DEFINE_IR_RAW_EVENT(rawir); + int offset = 0, size = 5 * 8; + int bit; + + dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf); + + while (offset < size) { + bit = offset; + while (!is_bit_set(imon->ir_buf, bit) && bit < size) + bit++; + dev_dbg(imon->dev, "pulse: %d bits", bit - offset); + if (bit > offset) { + rawir.pulse = true; + rawir.duration = (bit - offset) * BIT_DURATION; + ir_raw_event_store_with_filter(imon->rcdev, &rawir); + } + + if (bit >= size) + break; + + offset = bit; + while (is_bit_set(imon->ir_buf, bit) && bit < size) + bit++; + dev_dbg(imon->dev, "space: %d bits", bit - offset); + + rawir.pulse = false; + rawir.duration = (bit - offset) * BIT_DURATION; + ir_raw_event_store_with_filter(imon->rcdev, &rawir); + + offset = bit; + } + + if (imon->ir_buf[7] == 0x0a) { + ir_raw_event_set_idle(imon->rcdev, true); + ir_raw_event_handle(imon->rcdev); + } +} + +static void imon_ir_rx(struct urb *urb) +{ + struct imon *imon = urb->context; + int ret; + + switch (urb->status) { + case 0: + if (imon->ir_buf[7] != 0xff) + imon_ir_data(imon); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + case -EPIPE: + default: + dev_dbg(imon->dev, "error: urb status = %d", urb->status); + break; + } + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret && ret != -ENODEV) + dev_warn(imon->dev, "failed to resubmit urb: %d", ret); +} + +static int imon_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *ir_ep = NULL; + struct usb_host_interface *idesc; + struct usb_device *udev; + struct rc_dev *rcdev; + struct imon *imon; + int i, ret; + + udev = interface_to_usbdev(intf); + idesc = intf->cur_altsetting; + + for (i = 0; i < idesc->desc.bNumEndpoints; i++) { + struct usb_endpoint_descriptor *ep = &idesc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(ep)) { + ir_ep = ep; + break; + } + } + + if (!ir_ep) { + dev_err(&intf->dev, "IR endpoint missing"); + return -ENODEV; + } + + imon = devm_kmalloc(&intf->dev, sizeof(*imon), GFP_KERNEL); + if (!imon) + return -ENOMEM; + + imon->ir_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!imon->ir_urb) + return -ENOMEM; + + imon->dev = &intf->dev; + usb_fill_int_urb(imon->ir_urb, udev, + usb_rcvintpipe(udev, ir_ep->bEndpointAddress), + imon->ir_buf, sizeof(imon->ir_buf), + imon_ir_rx, imon, ir_ep->bInterval); + + rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW); + if (!rcdev) { + ret = -ENOMEM; + goto free_urb; + } + + usb_make_path(udev, imon->phys, sizeof(imon->phys)); + + rcdev->device_name = "iMON Station"; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->input_phys = imon->phys; + usb_to_input_id(udev, &rcdev->input_id); + rcdev->dev.parent = &intf->dev; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rcdev->map_name = RC_MAP_IMON_RSC; + rcdev->rx_resolution = BIT_DURATION; + rcdev->priv = imon; + + ret = devm_rc_register_device(&intf->dev, rcdev); + if (ret) + goto free_urb; + + imon->rcdev = rcdev; + + ret = usb_submit_urb(imon->ir_urb, GFP_KERNEL); + if (ret) + goto free_urb; + + usb_set_intfdata(intf, imon); + + return 0; + +free_urb: + usb_free_urb(imon->ir_urb); + return ret; +} + +static void imon_disconnect(struct usb_interface *intf) +{ + struct imon *imon = usb_get_intfdata(intf); + + usb_kill_urb(imon->ir_urb); + usb_free_urb(imon->ir_urb); +} + +static const struct usb_device_id imon_table[] = { + /* SoundGraph iMON (IR only) -- sg_imon.inf */ + { USB_DEVICE(0x04e8, 0xff30) }, + {} +}; + +static struct usb_driver imon_driver = { + .name = KBUILD_MODNAME, + .probe = imon_probe, + .disconnect = imon_disconnect, + .id_table = imon_table +}; + +module_usb_driver(imon_driver); + +MODULE_DESCRIPTION("Early raw iMON IR devices"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, imon_table); diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 0ce11c41dfae..700ab4c563d0 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -71,9 +71,10 @@ struct hix5hd2_ir_priv { unsigned long rate; }; -static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) +static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) { u32 val; + int ret = 0; if (dev->regmap) { regmap_read(dev->regmap, IR_CLK, &val); @@ -87,10 +88,11 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) regmap_write(dev->regmap, IR_CLK, val); } else { if (on) - clk_prepare_enable(dev->clock); + ret = clk_prepare_enable(dev->clock); else clk_disable_unprepare(dev->clock); } + return ret; } static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) @@ -127,9 +129,18 @@ static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) static int hix5hd2_ir_open(struct rc_dev *rdev) { struct hix5hd2_ir_priv *priv = rdev->priv; + int ret; + + ret = hix5hd2_ir_enable(priv, true); + if (ret) + return ret; - hix5hd2_ir_enable(priv, true); - return hix5hd2_ir_config(priv); + ret = hix5hd2_ir_config(priv); + if (ret) { + hix5hd2_ir_enable(priv, false); + return ret; + } + return 0; } static void hix5hd2_ir_close(struct rc_dev *rdev) @@ -239,7 +250,9 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) ret = PTR_ERR(priv->clock); goto err; } - clk_prepare_enable(priv->clock); + ret = clk_prepare_enable(priv->clock); + if (ret) + goto err; priv->rate = clk_get_rate(priv->clock); rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; @@ -309,9 +322,17 @@ static int hix5hd2_ir_suspend(struct device *dev) static int hix5hd2_ir_resume(struct device *dev) { struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); + int ret; - hix5hd2_ir_enable(priv, true); - clk_prepare_enable(priv->clock); + ret = hix5hd2_ir_enable(priv, true); + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clock); + if (ret) { + hix5hd2_ir_enable(priv, false); + return ret; + } writel_relaxed(0x01, priv->base + IR_ENABLE); writel_relaxed(0x00, priv->base + IR_INTM); diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c new file mode 100644 index 000000000000..a1ff06a26542 --- /dev/null +++ b/drivers/media/rc/ir-imon-decoder.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +// ir-imon-decoder.c - handle iMon protocol +// +// Copyright (C) 2018 by Sean Young <sean@mess.org> + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include "rc-core-priv.h" + +#define IMON_UNIT 415662 /* ns */ +#define IMON_BITS 30 +#define IMON_CHKBITS (BIT(30) | BIT(25) | BIT(24) | BIT(22) | \ + BIT(21) | BIT(20) | BIT(19) | BIT(18) | \ + BIT(17) | BIT(16) | BIT(14) | BIT(13) | \ + BIT(12) | BIT(11) | BIT(10) | BIT(9)) + +/* + * This protocol has 30 bits. The format is one IMON_UNIT header pulse, + * followed by 30 bits. Each bit is one IMON_UNIT check field, and then + * one IMON_UNIT field with the actual bit (1=space, 0=pulse). + * The check field is always space for some bits, for others it is pulse if + * both the preceding and current bit are zero, else space. IMON_CHKBITS + * defines which bits are of type check. + * + * There is no way to distinguish an incomplete message from one where + * the lower bits are all set, iow. the last pulse is for the lowest + * bit which is 0. + */ +enum imon_state { + STATE_INACTIVE, + STATE_BIT_CHK, + STATE_BIT_START, + STATE_FINISHED +}; + +/** + * ir_imon_decode() - Decode one iMON pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct imon_dec *data = &dev->raw->imon; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + dev_dbg(&dev->dev, + "iMON decode started at state %d bitno %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), + TO_STR(ev.pulse)); + + for (;;) { + if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2)) + return 0; + + decrease_duration(&ev, IMON_UNIT); + + switch (data->state) { + case STATE_INACTIVE: + if (ev.pulse) { + data->state = STATE_BIT_CHK; + data->bits = 0; + data->count = IMON_BITS; + } + break; + case STATE_BIT_CHK: + if (IMON_CHKBITS & BIT(data->count)) + data->last_chk = ev.pulse; + else if (ev.pulse) + goto err_out; + data->state = STATE_BIT_START; + break; + case STATE_BIT_START: + data->bits <<= 1; + if (!ev.pulse) + data->bits |= 1; + + if (IMON_CHKBITS & BIT(data->count)) { + if (data->last_chk != !(data->bits & 3)) + goto err_out; + } + + if (!data->count--) + data->state = STATE_FINISHED; + else + data->state = STATE_BIT_CHK; + break; + case STATE_FINISHED: + if (ev.pulse) + goto err_out; + rc_keydown(dev, RC_PROTO_IMON, data->bits, 0); + data->state = STATE_INACTIVE; + break; + } + } + +err_out: + dev_dbg(&dev->dev, + "iMON decode failed at state %d bitno %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), + TO_STR(ev.pulse)); + + data->state = STATE_INACTIVE; + + return -EINVAL; +} + +/** + * ir_imon_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_imon_encode(enum rc_proto protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int i, pulse; + + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(e, 1, IMON_UNIT); + + for (i = IMON_BITS; i >= 0; i--) { + if (BIT(i) & IMON_CHKBITS) + pulse = !(scancode & (BIT(i) | BIT(i + 1))); + else + pulse = 0; + + if (pulse == e->pulse) { + e->duration += IMON_UNIT; + } else { + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(++e, pulse, IMON_UNIT); + } + + pulse = !(scancode & BIT(i)); + + if (pulse == e->pulse) { + e->duration += IMON_UNIT; + } else { + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(++e, pulse, IMON_UNIT); + } + } + + if (e->pulse) + e++; + + return e - events; +} + +static struct ir_raw_handler imon_handler = { + .protocols = RC_PROTO_BIT_IMON, + .decode = ir_imon_decode, + .encode = ir_imon_encode, + .carrier = 38000, +}; + +static int __init ir_imon_decode_init(void) +{ + ir_raw_handler_register(&imon_handler); + + pr_info("IR iMON protocol handler initialized\n"); + return 0; +} + +static void __exit ir_imon_decode_exit(void) +{ + ir_raw_handler_unregister(&imon_handler); +} + +module_init(ir_imon_decode_init); +module_exit(ir_imon_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_DESCRIPTION("iMON IR protocol decoder"); diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index c03c776cfa54..8cb68ae43282 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -56,8 +56,8 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) goto out; - IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); again: switch (data->state) { @@ -136,15 +136,15 @@ again: u32 scancode; scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | (bitrev8((data->bits >> 0) & 0xff) << 0); - IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); + dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode); rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle); data->first = false; data->old_bits = data->bits; } else if (data->bits == data->old_bits) { - IR_dprintk(1, "JVC repeat\n"); + dev_dbg(&dev->dev, "JVC repeat\n"); rc_repeat(dev); } else { - IR_dprintk(1, "JVC invalid repeat msg\n"); + dev_dbg(&dev->dev, "JVC invalid repeat msg\n"); break; } @@ -164,8 +164,8 @@ again: } out: - IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 2c3df02e05ff..c110984ca671 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -117,19 +117,19 @@ static unsigned char kbd_keycodes[256] = { static void mce_kbd_rx_timeout(struct timer_list *t) { - struct mce_kbd_dec *mce_kbd = from_timer(mce_kbd, t, rx_timeout); - int i; + struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout); unsigned char maskcode; + int i; - IR_dprintk(2, "timer callback clearing all keys\n"); + dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n"); for (i = 0; i < 7; i++) { maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; - input_report_key(mce_kbd->idev, maskcode, 0); + input_report_key(raw->mce_kbd.idev, maskcode, 0); } for (i = 0; i < MCIR2_MASK_KEYS_START; i++) - input_report_key(mce_kbd->idev, kbd_keycodes[i], 0); + input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); } static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) @@ -144,16 +144,16 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) } } -static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, - u32 scancode) +static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode) { + struct mce_kbd_dec *data = &dev->raw->mce_kbd; u8 keydata = (scancode >> 8) & 0xff; u8 shiftmask = scancode & 0xff; unsigned char keycode, maskcode; int i, keystate; - IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", - keydata, shiftmask); + dev_dbg(&dev->dev, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", + keydata, shiftmask); for (i = 0; i < 7; i++) { maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; @@ -161,20 +161,21 @@ static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, keystate = 1; else keystate = 0; - input_report_key(idev, maskcode, keystate); + input_report_key(data->idev, maskcode, keystate); } if (keydata) { keycode = kbd_keycodes[keydata]; - input_report_key(idev, keycode, 1); + input_report_key(data->idev, keycode, 1); } else { for (i = 0; i < MCIR2_MASK_KEYS_START; i++) - input_report_key(idev, kbd_keycodes[i], 0); + input_report_key(data->idev, kbd_keycodes[i], 0); } } -static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) +static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode) { + struct mce_kbd_dec *data = &dev->raw->mce_kbd; /* raw mouse coordinates */ u8 xdata = (scancode >> 7) & 0x7f; u8 ydata = (scancode >> 14) & 0x7f; @@ -193,14 +194,14 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) else y = ydata; - IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n", - x, y, left ? "L" : "", right ? "R" : ""); + dev_dbg(&dev->dev, "mouse: x = %d, y = %d, btns = %s%s\n", + x, y, left ? "L" : "", right ? "R" : ""); - input_report_rel(idev, REL_X, x); - input_report_rel(idev, REL_Y, y); + input_report_rel(data->idev, REL_X, x); + input_report_rel(data->idev, REL_Y, y); - input_report_key(idev, BTN_LEFT, left); - input_report_key(idev, BTN_RIGHT, right); + input_report_key(data->idev, BTN_LEFT, left); + input_report_key(data->idev, BTN_RIGHT, right); } /** @@ -227,8 +228,8 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) return 0; @@ -280,7 +281,7 @@ again: data->wanted_bits = MCIR2_MOUSE_NBITS; break; default: - IR_dprintk(1, "not keyboard or mouse data\n"); + dev_dbg(&dev->dev, "not keyboard or mouse data\n"); goto out; } @@ -319,25 +320,26 @@ again: switch (data->wanted_bits) { case MCIR2_KEYBOARD_NBITS: scancode = data->body & 0xffff; - IR_dprintk(1, "keyboard data 0x%08x\n", data->body); + dev_dbg(&dev->dev, "keyboard data 0x%08x\n", + data->body); if (dev->timeout) delay = usecs_to_jiffies(dev->timeout / 1000); else delay = msecs_to_jiffies(100); mod_timer(&data->rx_timeout, jiffies + delay); /* Pass data to keyboard buffer parser */ - ir_mce_kbd_process_keyboard_data(data->idev, scancode); + ir_mce_kbd_process_keyboard_data(dev, scancode); lsc.rc_proto = RC_PROTO_MCIR2_KBD; break; case MCIR2_MOUSE_NBITS: scancode = data->body & 0x1fffff; - IR_dprintk(1, "mouse data 0x%06x\n", scancode); + dev_dbg(&dev->dev, "mouse data 0x%06x\n", scancode); /* Pass data to mouse buffer parser */ - ir_mce_kbd_process_mouse_data(data->idev, scancode); + ir_mce_kbd_process_mouse_data(dev, scancode); lsc.rc_proto = RC_PROTO_MCIR2_MSE; break; default: - IR_dprintk(1, "not keyboard or mouse data\n"); + dev_dbg(&dev->dev, "not keyboard or mouse data\n"); goto out; } @@ -350,8 +352,8 @@ again: } out: - IR_dprintk(1, "failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; input_sync(data->idev); return -EINVAL; diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 31d7bafe7bda..21647b809e6f 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -49,8 +49,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "NEC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -99,13 +99,11 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) break; if (data->necx_repeat && data->count == NECX_REPEAT_BITS && - geq_margin(ev.duration, - NEC_TRAILER_SPACE, NEC_UNIT / 2)) { - IR_dprintk(1, "Repeat last key\n"); - rc_repeat(dev); - data->state = STATE_INACTIVE; - return 0; - + geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) { + dev_dbg(&dev->dev, "Repeat last key\n"); + rc_repeat(dev); + data->state = STATE_INACTIVE; + return 0; } else if (data->count > NECX_REPEAT_BITS) data->necx_repeat = false; @@ -164,8 +162,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "NEC decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 11a28f8772da..74d3b859c3a2 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -54,8 +54,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) return 0; @@ -157,8 +157,8 @@ again: } else break; - IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n", - scancode, protocol, toggle); + dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n", + scancode, protocol, toggle); rc_keydown(dev, protocol, scancode, toggle); data->state = STATE_INACTIVE; @@ -166,8 +166,8 @@ again: } out: - IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n", - data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 55bb19bbd4e9..8314da32453f 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -100,8 +100,8 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC6 decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) return 0; @@ -170,7 +170,7 @@ again: break; if (!(data->header & RC6_STARTBIT_MASK)) { - IR_dprintk(1, "RC6 invalid start bit\n"); + dev_dbg(&dev->dev, "RC6 invalid start bit\n"); break; } @@ -187,7 +187,7 @@ again: data->wanted_bits = RC6_6A_NBITS; break; default: - IR_dprintk(1, "RC6 unknown mode\n"); + dev_dbg(&dev->dev, "RC6 unknown mode\n"); goto out; } goto again; @@ -230,13 +230,13 @@ again: scancode = data->body; toggle = data->toggle; protocol = RC_PROTO_RC6_0; - IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", - scancode, toggle); + dev_dbg(&dev->dev, "RC6(0) scancode 0x%04x (toggle: %u)\n", + scancode, toggle); break; case RC6_MODE_6A: if (data->count > CHAR_BIT * sizeof data->body) { - IR_dprintk(1, "RC6 too many (%u) data bits\n", + dev_dbg(&dev->dev, "RC6 too many (%u) data bits\n", data->count); goto out; } @@ -262,15 +262,15 @@ again: } break; default: - IR_dprintk(1, "RC6(6A) unsupported length\n"); + dev_dbg(&dev->dev, "RC6(6A) unsupported length\n"); goto out; } - IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n", - protocol, scancode, toggle); + dev_dbg(&dev->dev, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n", + protocol, scancode, toggle); break; default: - IR_dprintk(1, "RC6 unknown mode\n"); + dev_dbg(&dev->dev, "RC6 unknown mode\n"); goto out; } @@ -280,8 +280,8 @@ again: } out: - IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC6 decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index ded39cdfc6ef..4efe6db5376a 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -52,14 +52,14 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!is_timing_event(ev)) { if (ev.reset) { - IR_dprintk(1, "SANYO event reset received. reset to state 0\n"); + dev_dbg(&dev->dev, "SANYO event reset received. reset to state 0\n"); data->state = STATE_INACTIVE; } return 0; } - IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -102,7 +102,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) { rc_repeat(dev); - IR_dprintk(1, "SANYO repeat last key\n"); + dev_dbg(&dev->dev, "SANYO repeat last key\n"); data->state = STATE_INACTIVE; return 0; } @@ -144,21 +144,21 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) not_command = bitrev8((data->bits >> 0) & 0xff); if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n", - data->bits); + dev_dbg(&dev->dev, "SANYO checksum error: received 0x%08llx\n", + data->bits); data->state = STATE_INACTIVE; return 0; } scancode = address << 8 | command; - IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); + dev_dbg(&dev->dev, "SANYO scancode: 0x%06x\n", scancode); rc_keydown(dev, RC_PROTO_SANYO, scancode, 0); data->state = STATE_INACTIVE; return 0; } - IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index df296991906c..6a38c50566a4 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -54,8 +54,8 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -149,9 +149,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) msg = (data->bits >> 15) & 0x7fff; echo = data->bits & 0x7fff; if ((msg ^ echo) != 0x3ff) { - IR_dprintk(1, - "Sharp checksum error: received 0x%04x, 0x%04x\n", - msg, echo); + dev_dbg(&dev->dev, + "Sharp checksum error: received 0x%04x, 0x%04x\n", + msg, echo); break; } @@ -159,16 +159,15 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) command = bitrev8((msg >> 2) & 0xff); scancode = address << 8 | command; - IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); + dev_dbg(&dev->dev, "Sharp scancode 0x%04x\n", scancode); rc_keydown(dev, RC_PROTO_SHARP, scancode, 0); data->state = STATE_INACTIVE; return 0; } - IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), - TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index e4bcff21c025..6764ec9de646 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -55,8 +55,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) goto out; - IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -148,19 +148,21 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) protocol = RC_PROTO_SONY20; break; default: - IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); + dev_dbg(&dev->dev, "Sony invalid bitcount %u\n", + data->count); goto out; } scancode = device << 16 | subdevice << 8 | function; - IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); + dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n", data->count, + scancode); rc_keydown(dev, protocol, scancode, 0); goto finish_state_machine; } out: - IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index a32a84ae2d0b..7163d5ce2e64 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -15,21 +15,11 @@ #define IR_SPI_DRIVER_NAME "ir-spi" -/* pulse value for different duty cycles */ -#define IR_SPI_PULSE_DC_50 0xff00 -#define IR_SPI_PULSE_DC_60 0xfc00 -#define IR_SPI_PULSE_DC_70 0xf800 -#define IR_SPI_PULSE_DC_75 0xf000 -#define IR_SPI_PULSE_DC_80 0xc000 -#define IR_SPI_PULSE_DC_90 0x8000 - #define IR_SPI_DEFAULT_FREQUENCY 38000 -#define IR_SPI_BIT_PER_WORD 8 #define IR_SPI_MAX_BUFSIZE 4096 struct ir_spi_data { u32 freq; - u8 duty_cycle; bool negated; u16 tx_buf[IR_SPI_MAX_BUFSIZE]; @@ -105,19 +95,9 @@ static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) { struct ir_spi_data *idata = dev->priv; + int bits = (duty_cycle * 15) / 100; - if (duty_cycle >= 90) - idata->pulse = IR_SPI_PULSE_DC_90; - else if (duty_cycle >= 80) - idata->pulse = IR_SPI_PULSE_DC_80; - else if (duty_cycle >= 75) - idata->pulse = IR_SPI_PULSE_DC_75; - else if (duty_cycle >= 70) - idata->pulse = IR_SPI_PULSE_DC_70; - else if (duty_cycle >= 60) - idata->pulse = IR_SPI_PULSE_DC_60; - else - idata->pulse = IR_SPI_PULSE_DC_50; + idata->pulse = GENMASK(bits, 0); if (idata->negated) { idata->pulse = ~idata->pulse; diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index 712bc6d76e92..58b47af1a763 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -49,8 +49,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n", - data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "XMP decode started at state %d %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -85,7 +85,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; if (data->count != 16) { - IR_dprintk(2, "received TRAILER period at index %d: %u\n", + dev_dbg(&dev->dev, "received TRAILER period at index %d: %u\n", data->count, ev.duration); data->state = STATE_INACTIVE; return -EINVAL; @@ -99,7 +99,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) */ divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000; if (divider < 50) { - IR_dprintk(2, "divider to small %d.\n", divider); + dev_dbg(&dev->dev, "divider to small %d.\n", + divider); data->state = STATE_INACTIVE; return -EINVAL; } @@ -113,7 +114,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) n[12] + n[13] + n[14] + n[15]) % 16; if (sum1 != 15 || sum2 != 15) { - IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n", + dev_dbg(&dev->dev, "checksum errors sum1=0x%X sum2=0x%X\n", sum1, sum2); data->state = STATE_INACTIVE; return -EINVAL; @@ -127,24 +128,24 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) obc1 = n[12] << 4 | n[13]; obc2 = n[14] << 4 | n[15]; if (subaddr != subaddr2) { - IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", + dev_dbg(&dev->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", subaddr, subaddr2); data->state = STATE_INACTIVE; return -EINVAL; } if (oem != 0x44) - IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", + dev_dbg(&dev->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", oem); scancode = addr << 24 | subaddr << 16 | obc1 << 8 | obc2; - IR_dprintk(1, "XMP scancode 0x%06x\n", scancode); + dev_dbg(&dev->dev, "XMP scancode 0x%06x\n", scancode); if (toggle == 0) { rc_keydown(dev, RC_PROTO_XMP, scancode, 0); } else { rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); + dev_dbg(&dev->dev, "Repeat last key\n"); } data->state = STATE_INACTIVE; @@ -153,7 +154,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) { /* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */ if (data->count == 16) { - IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n", + dev_dbg(&dev->dev, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n", data->count, ev.duration); /* * TODO: for now go back to half frame position @@ -164,7 +165,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (data->count != 8) - IR_dprintk(2, "received half frame pulse at index %d: %u\n", + dev_dbg(&dev->dev, "received half frame pulse at index %d: %u\n", data->count, ev.duration); data->state = STATE_LEADER_PULSE; @@ -173,7 +174,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) { /* store nibble raw data, decode after trailer */ if (data->count == 16) { - IR_dprintk(2, "to many pulses (%d) ignoring: %u\n", + dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n", data->count, ev.duration); data->state = STATE_INACTIVE; return -EINVAL; @@ -189,8 +190,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) break; } - IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "XMP decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 50b319355edf..d6b913a3032d 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hisi-tv-demo.o \ rc-imon-mce.o \ rc-imon-pad.o \ + rc-imon-rsc.o \ rc-iodata-bctv7e.o \ rc-it913x-v1.o \ rc-it913x-v2.o \ diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index a7296ffbf218..8501cf0a3253 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -134,8 +134,7 @@ static struct rc_map_list imon_pad_map = { .map = { .scan = imon_pad, .size = ARRAY_SIZE(imon_pad), - /* actual protocol details unknown, hardware decoder */ - .rc_proto = RC_PROTO_OTHER, + .rc_proto = RC_PROTO_IMON, .name = RC_MAP_IMON_PAD, } }; diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c new file mode 100644 index 000000000000..83e4564aaa22 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-imon-rsc.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2018 Sean Young <sean@mess.org> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Note that this remote has a stick which its own IR protocol, +// with 16 directions. This is not supported yet. +// +static struct rc_map_table imon_rsc[] = { + { 0x801010, KEY_EXIT }, + { 0x80102f, KEY_POWER }, + { 0x80104a, KEY_SCREENSAVER }, /* Screensaver */ + { 0x801049, KEY_TIME }, /* Timer */ + { 0x801054, KEY_NUMERIC_1 }, + { 0x801055, KEY_NUMERIC_2 }, + { 0x801056, KEY_NUMERIC_3 }, + { 0x801057, KEY_NUMERIC_4 }, + { 0x801058, KEY_NUMERIC_5 }, + { 0x801059, KEY_NUMERIC_6 }, + { 0x80105a, KEY_NUMERIC_7 }, + { 0x80105b, KEY_NUMERIC_8 }, + { 0x80105c, KEY_NUMERIC_9 }, + { 0x801081, KEY_SCREEN }, /* Desktop */ + { 0x80105d, KEY_NUMERIC_0 }, + { 0x801082, KEY_MAX }, + { 0x801048, KEY_ESC }, + { 0x80104b, KEY_MEDIA }, /* Windows key */ + { 0x801083, KEY_MENU }, + { 0x801045, KEY_APPSELECT }, /* app launcher */ + { 0x801084, KEY_STOP }, + { 0x801046, KEY_CYCLEWINDOWS }, + { 0x801085, KEY_BACKSPACE }, + { 0x801086, KEY_KEYBOARD }, + { 0x801087, KEY_SPACE }, + { 0x80101e, KEY_RESERVED }, /* shift tab */ + { 0x801098, BTN_0 }, + { 0x80101f, KEY_TAB }, + { 0x80101b, BTN_LEFT }, + { 0x80101d, BTN_RIGHT }, + { 0x801016, BTN_MIDDLE }, /* drag and drop */ + { 0x801088, KEY_MUTE }, + { 0x80105e, KEY_VOLUMEDOWN }, + { 0x80105f, KEY_VOLUMEUP }, + { 0x80104c, KEY_PLAY }, + { 0x80104d, KEY_PAUSE }, + { 0x80104f, KEY_EJECTCD }, + { 0x801050, KEY_PREVIOUS }, + { 0x801051, KEY_NEXT }, + { 0x80104e, KEY_STOP }, + { 0x801052, KEY_REWIND }, + { 0x801053, KEY_FASTFORWARD }, + { 0x801089, KEY_ZOOM } /* full screen */ +}; + +static struct rc_map_list imon_rsc_map = { + .map = { + .scan = imon_rsc, + .size = ARRAY_SIZE(imon_rsc), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_IMON_RSC, + } +}; + +static int __init init_rc_map_imon_rsc(void) +{ + return rc_map_register(&imon_rsc_map); +} + +static void __exit exit_rc_map_imon_rsc(void) +{ + rc_map_unregister(&imon_rsc_map); +} + +module_init(init_rc_map_imon_rsc) +module_exit(exit_rc_map_imon_rsc) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index cc863044c880..24e9fbb80e81 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -60,12 +60,12 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) * space with the maximum time value. */ sample = LIRC_SPACE(LIRC_VALUE_MASK); - IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); + dev_dbg(&dev->dev, "delivering reset sync space to lirc_dev\n"); /* Carrier reports */ } else if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); - IR_dprintk(2, "carrier report (freq: %d)\n", sample); + dev_dbg(&dev->dev, "carrier report (freq: %d)\n", sample); /* Packet end */ } else if (ev.timeout) { @@ -77,7 +77,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) dev->gap_duration = ev.duration; sample = LIRC_TIMEOUT(ev.duration / 1000); - IR_dprintk(2, "timeout report (duration: %d)\n", sample); + dev_dbg(&dev->dev, "timeout report (duration: %d)\n", sample); /* Normal sample */ } else { @@ -100,8 +100,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : LIRC_SPACE(ev.duration / 1000); - IR_dprintk(2, "delivering %uus %s to lirc_dev\n", - TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "delivering %uus %s to lirc_dev\n", + TO_US(ev.duration), TO_STR(ev.pulse)); } spin_lock_irqsave(&dev->lirc_fh_lock, flags); @@ -249,8 +249,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, goto out_unlock; } - start = ktime_get(); - if (!dev->tx_ir) { ret = -EINVAL; goto out_unlock; @@ -343,6 +341,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, duration += txbuf[i]; } + start = ktime_get(); + ret = dev->tx_ir(dev, txbuf, count); if (ret < 0) goto out_kfree; @@ -570,7 +570,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd, ret = -EINVAL; else if (dev->s_timeout) ret = dev->s_timeout(dev, tmp); - else if (!ret) + else dev->timeout = tmp; } break; @@ -804,8 +804,8 @@ int __init lirc_dev_init(void) return retval; } - pr_info("IR Remote Control driver registered, major %d\n", - MAJOR(lirc_base_dev)); + pr_debug("IR Remote Control driver registered, major %d\n", + MAJOR(lirc_base_dev)); return 0; } diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index a9187b0b46a1..69ba57372c05 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -42,7 +42,7 @@ #include <linux/pm_wakeup.h> #include <media/rc-core.h> -#define DRIVER_VERSION "1.93" +#define DRIVER_VERSION "1.94" #define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>" #define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ "device driver" @@ -182,6 +182,7 @@ enum mceusb_model_type { MCE_GEN1, MCE_GEN3, MCE_GEN2_TX_INV, + MCE_GEN2_TX_INV_RX_GOOD, POLARIS_EVK, CX_HYBRID_TV, MULTIFUNCTION, @@ -198,6 +199,13 @@ struct mceusb_model { u32 mce_gen3:1; u32 tx_mask_normal:1; u32 no_tx:1; + /* + * 2nd IR receiver (short-range, wideband) for learning mode: + * 0, absent 2nd receiver (rx2) + * 1, rx2 present + * 2, rx2 which under counts IR carrier cycles + */ + u32 rx2; int ir_intfnum; @@ -209,9 +217,11 @@ static const struct mceusb_model mceusb_model[] = { [MCE_GEN1] = { .mce_gen1 = 1, .tx_mask_normal = 1, + .rx2 = 2, }, [MCE_GEN2] = { .mce_gen2 = 1, + .rx2 = 2, }, [MCE_GEN2_NO_TX] = { .mce_gen2 = 1, @@ -220,10 +230,17 @@ static const struct mceusb_model mceusb_model[] = { [MCE_GEN2_TX_INV] = { .mce_gen2 = 1, .tx_mask_normal = 1, + .rx2 = 1, + }, + [MCE_GEN2_TX_INV_RX_GOOD] = { + .mce_gen2 = 1, + .tx_mask_normal = 1, + .rx2 = 2, }, [MCE_GEN3] = { .mce_gen3 = 1, .tx_mask_normal = 1, + .rx2 = 2, }, [POLARIS_EVK] = { /* @@ -232,6 +249,7 @@ static const struct mceusb_model mceusb_model[] = { * to allow testing it */ .name = "Conexant Hybrid TV (cx231xx) MCE IR", + .rx2 = 2, }, [CX_HYBRID_TV] = { .no_tx = 1, /* tx isn't wired up at all */ @@ -244,10 +262,12 @@ static const struct mceusb_model mceusb_model[] = { [MULTIFUNCTION] = { .mce_gen2 = 1, .ir_intfnum = 2, + .rx2 = 2, }, [TIVO_KIT] = { .mce_gen2 = 1, .rc_map = RC_MAP_TIVO, + .rx2 = 2, }, [EVROMEDIA_FULL_HYBRID_FULLHD] = { .name = "Evromedia USB Full Hybrid Full HD", @@ -290,7 +310,7 @@ static const struct usb_device_id mceusb_dev_table[] = { .driver_info = MULTIFUNCTION }, /* SMK/Toshiba G83C0004D410 */ { USB_DEVICE(VENDOR_SMK, 0x031d), - .driver_info = MCE_GEN2_TX_INV }, + .driver_info = MCE_GEN2_TX_INV_RX_GOOD }, /* SMK eHome Infrared Transceiver (Sony VAIO) */ { USB_DEVICE(VENDOR_SMK, 0x0322), .driver_info = MCE_GEN2_TX_INV }, @@ -427,7 +447,8 @@ struct mceusb_dev { struct rc_dev *rc; /* optional features we can enable */ - bool learning_enabled; + bool carrier_report_enabled; + bool wideband_rx_enabled; /* aka learning mode, short-range rx */ /* core device bits */ struct device *dev; @@ -458,6 +479,7 @@ struct mceusb_dev { u32 tx_mask_normal:1; u32 microsoft_gen1:1; u32 no_tx:1; + u32 rx2; } flags; /* transmit support */ @@ -474,6 +496,11 @@ struct mceusb_dev { u8 num_rxports; /* number of receive sensors */ u8 txports_cabled; /* bitmask of transmitters with cable */ u8 rxports_active; /* bitmask of active receive sensors */ + bool learning_active; /* wideband rx is active */ + + /* receiver carrier frequency detection support */ + u32 pulse_tunit; /* IR pulse "on" cumulative time units */ + u32 pulse_count; /* pulse "on" count in measurement interval */ /* * support for async error handler mceusb_deferred_kevent() @@ -684,8 +711,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, /* aka MCE_RSP_EQIRRXCFCNT */ if (out) dev_dbg(dev, "Get receive sensor"); - else if (ir->learning_enabled) - dev_dbg(dev, "RX pulse count: %d", + else + dev_dbg(dev, "RX carrier cycle count: %d", ((data[0] << 8) | data[1])); break; case MCE_RSP_EQIRNUMPORTS: @@ -956,14 +983,78 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) } /* + * Select or deselect the 2nd receiver port. + * Second receiver is learning mode, wide-band, short-range receiver. + * Only one receiver (long or short range) may be active at a time. + */ +static int mceusb_set_rx_wideband(struct rc_dev *dev, int enable) +{ + struct mceusb_dev *ir = dev->priv; + unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR, + MCE_CMD_SETIRRXPORTEN, 0x00 }; + + dev_dbg(ir->dev, "select %s-range receive sensor", + enable ? "short" : "long"); + if (enable) { + ir->wideband_rx_enabled = true; + cmdbuf[2] = 2; /* port 2 is short range receiver */ + } else { + ir->wideband_rx_enabled = false; + cmdbuf[2] = 1; /* port 1 is long range receiver */ + } + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + /* response from device sets ir->learning_active */ + + return 0; +} + +/* + * Enable/disable receiver carrier frequency pass through reporting. + * Only the short-range receiver has carrier frequency measuring capability. + * Implicitly select this receiver when enabling carrier frequency reporting. + */ +static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable) +{ + struct mceusb_dev *ir = dev->priv; + unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR, + MCE_CMD_SETIRRXPORTEN, 0x00 }; + + dev_dbg(ir->dev, "%s short-range receiver carrier reporting", + enable ? "enable" : "disable"); + if (enable) { + ir->carrier_report_enabled = true; + if (!ir->learning_active) { + cmdbuf[2] = 2; /* port 2 is short range receiver */ + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + } + } else { + ir->carrier_report_enabled = false; + /* + * Revert to normal (long-range) receiver only if the + * wideband (short-range) receiver wasn't explicitly + * enabled. + */ + if (ir->learning_active && !ir->wideband_rx_enabled) { + cmdbuf[2] = 1; /* port 1 is long range receiver */ + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + } + } + + return 0; +} + +/* * We don't do anything but print debug spew for many of the command bits * we receive from the hardware, but some of them are useful information * we want to store so that we can use them. */ static void mceusb_handle_command(struct mceusb_dev *ir, int index) { + DEFINE_IR_RAW_EVENT(rawir); u8 hi = ir->buf_in[index + 1] & 0xff; u8 lo = ir->buf_in[index + 2] & 0xff; + u32 carrier_cycles; + u32 cycles_fix; switch (ir->buf_in[index]) { /* the one and only 5-byte return value command */ @@ -980,6 +1071,33 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) ir->num_txports = hi; ir->num_rxports = lo; break; + case MCE_RSP_EQIRRXCFCNT: + /* + * The carrier cycle counter can overflow and wrap around + * without notice from the device. So frequency measurement + * will be inaccurate with long duration IR. + * + * The long-range (non learning) receiver always reports + * zero count so we always ignore its report. + */ + if (ir->carrier_report_enabled && ir->learning_active && + ir->pulse_tunit > 0) { + carrier_cycles = (hi << 8 | lo); + /* + * Adjust carrier cycle count by adding + * 1 missed count per pulse "on" + */ + cycles_fix = ir->flags.rx2 == 2 ? ir->pulse_count : 0; + rawir.carrier_report = 1; + rawir.carrier = (1000000u / MCE_TIME_UNIT) * + (carrier_cycles + cycles_fix) / + ir->pulse_tunit; + dev_dbg(ir->dev, "RX carrier frequency %u Hz (pulse count = %u, cycles = %u, duration = %u, rx2 = %u)", + rawir.carrier, ir->pulse_count, carrier_cycles, + ir->pulse_tunit, ir->flags.rx2); + ir_raw_event_store(ir->rc, &rawir); + } + break; /* 1-byte return value commands */ case MCE_RSP_EQEMVER: @@ -989,8 +1107,12 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) ir->tx_mask = hi; break; case MCE_RSP_EQIRRXPORTEN: - ir->learning_enabled = ((hi & 0x02) == 0x02); - ir->rxports_active = hi; + ir->learning_active = ((hi & 0x02) == 0x02); + if (ir->rxports_active != hi) { + dev_info(ir->dev, "%s-range (0x%x) receiver active", + ir->learning_active ? "short" : "long", hi); + ir->rxports_active = hi; + } break; case MCE_RSP_CMD_ILLEGAL: ir->need_reset = true; @@ -1027,12 +1149,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem--; init_ir_raw_event(&rawir); rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); - rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * US_TO_NS(MCE_TIME_UNIT); + rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK); + if (rawir.pulse) { + ir->pulse_tunit += rawir.duration; + ir->pulse_count++; + } + rawir.duration *= US_TO_NS(MCE_TIME_UNIT); - dev_dbg(ir->dev, "Storing %s with duration %u", + dev_dbg(ir->dev, "Storing %s %u ns (%02x)", rawir.pulse ? "pulse" : "space", - rawir.duration); + rawir.duration, ir->buf_in[i]); if (ir_raw_event_store_with_filter(ir->rc, &rawir)) event = true; @@ -1053,10 +1179,13 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); mceusb_dev_printdata(ir, ir->buf_in, buf_len, i, ir->rem + 1, false); - if (ir->rem) + if (ir->rem) { ir->parser_state = PARSE_IRDATA; - else + } else { ir_raw_event_reset(ir->rc); + ir->pulse_tunit = 0; + ir->pulse_count = 0; + } break; } @@ -1292,6 +1421,10 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->s_tx_carrier = mceusb_set_tx_carrier; rc->tx_ir = mceusb_tx_ir; } + if (ir->flags.rx2 > 0) { + rc->s_learning_mode = mceusb_set_rx_wideband; + rc->s_carrier_report = mceusb_set_rx_carrier_report; + } rc->driver_name = DRIVER_NAME; switch (le16_to_cpu(udev->descriptor.idVendor)) { @@ -1406,6 +1539,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, ir->flags.microsoft_gen1 = is_microsoft_gen1; ir->flags.tx_mask_normal = tx_mask_normal; ir->flags.no_tx = mceusb_model[model].no_tx; + ir->flags.rx2 = mceusb_model[model].rx2; ir->model = model; /* Saving usb interface data for use by the transmitter routine */ diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index f2204eb77e2a..f449b35d25e7 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -97,8 +97,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) status = readl_relaxed(ir->reg + IR_DEC_STATUS); rawir.pulse = !!(status & STATUS_IR_DEC_IN); - ir_raw_event_store(ir->rc, &rawir); - ir_raw_event_handle(ir->rc); + ir_raw_event_store_with_timeout(ir->rc, &rawir); spin_unlock(&ir->lock); @@ -145,7 +144,9 @@ static int meson_ir_probe(struct platform_device *pdev) ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); - ir->rc->timeout = MS_TO_NS(200); + ir->rc->min_timeout = 1; + ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ir->rc->driver_name = DRIVER_NAME; spin_lock_init(&ir->lock); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 458e9eb2d6a9..e0e6a17460f6 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -50,8 +50,9 @@ struct ir_raw_event_ctrl { DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); ktime_t last_event; /* when last event occurred */ struct rc_dev *dev; /* pointer to the parent rc_dev */ - /* edge driver */ - struct timer_list edge_handle; + /* handle delayed ir_raw_event_store_edge processing */ + spinlock_t edge_spinlock; + struct timer_list edge_handle; /* raw decoder state follows */ struct ir_raw_event prev_ev; @@ -117,6 +118,12 @@ struct ir_raw_event_ctrl { unsigned count; u32 durations[16]; } xmp; + struct imon_dec { + int state; + int count; + int last_chk; + unsigned int bits; + } imon; }; /* macros for IR decoders */ @@ -292,11 +299,4 @@ static inline int ir_lirc_register(struct rc_dev *dev) { return 0; } static inline void ir_lirc_unregister(struct rc_dev *dev) { } #endif -/* - * Decoder initialization code - * - * Those load logic are called during ir-core init, and automatically - * loads the compiled decoders for their usage with IR raw events - */ - #endif /* _RC_CORE_PRIV */ diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 18504870b9f0..374f83105a23 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -65,8 +65,8 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) if (!dev->raw) return -EINVAL; - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); + dev_dbg(&dev->dev, "sample: (%05dus %s)\n", + TO_US(ev->duration), TO_STR(ev->pulse)); if (!kfifo_put(&dev->raw->kfifo, *ev)) { dev_err(&dev->dev, "IR event FIFO is full!\n"); @@ -92,7 +92,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) { ktime_t now; DEFINE_IR_RAW_EVENT(ev); - int rc = 0; if (!dev->raw) return -EINVAL; @@ -101,7 +100,33 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); ev.pulse = !pulse; - rc = ir_raw_event_store(dev, &ev); + return ir_raw_event_store_with_timeout(dev, &ev); +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); + +/* + * ir_raw_event_store_with_timeout() - pass a pulse/space duration to the raw + * ir decoders, schedule decoding and + * timeout + * @dev: the struct rc_dev device descriptor + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This routine (which may be called from an interrupt context) stores a + * pulse/space duration for the raw ir decoding state machines, schedules + * decoding and generates a timeout. + */ +int ir_raw_event_store_with_timeout(struct rc_dev *dev, struct ir_raw_event *ev) +{ + ktime_t now; + int rc = 0; + + if (!dev->raw) + return -EINVAL; + + now = ktime_get(); + + spin_lock(&dev->raw->edge_spinlock); + rc = ir_raw_event_store(dev, ev); dev->raw->last_event = now; @@ -112,10 +137,11 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) mod_timer(&dev->raw->edge_handle, jiffies + msecs_to_jiffies(15)); } + spin_unlock(&dev->raw->edge_spinlock); return rc; } -EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); +EXPORT_SYMBOL_GPL(ir_raw_event_store_with_timeout); /** * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing @@ -168,7 +194,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) if (!dev->raw) return; - IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); + dev_dbg(&dev->dev, "%s idle mode\n", idle ? "enter" : "leave"); if (idle) { dev->raw->this_ev.timeout = true; @@ -462,12 +488,26 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, } EXPORT_SYMBOL(ir_raw_encode_scancode); -static void edge_handle(struct timer_list *t) +/** + * ir_raw_edge_handle() - Handle ir_raw_event_store_edge() processing + * + * @t: timer_list + * + * This callback is armed by ir_raw_event_store_edge(). It does two things: + * first of all, rather than calling ir_raw_event_handle() for each + * edge and waking up the rc thread, 15 ms after the first edge + * ir_raw_event_handle() is called. Secondly, generate a timeout event + * no more IR is received after the rc_dev timeout. + */ +static void ir_raw_edge_handle(struct timer_list *t) { struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle); struct rc_dev *dev = raw->dev; - ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event); + unsigned long flags; + ktime_t interval; + spin_lock_irqsave(&dev->raw->edge_spinlock, flags); + interval = ktime_sub(ktime_get(), dev->raw->last_event); if (ktime_to_ns(interval) >= dev->timeout) { DEFINE_IR_RAW_EVENT(ev); @@ -480,6 +520,7 @@ static void edge_handle(struct timer_list *t) jiffies + nsecs_to_jiffies(dev->timeout - ktime_to_ns(interval))); } + spin_unlock_irqrestore(&dev->raw->edge_spinlock, flags); ir_raw_event_handle(dev); } @@ -528,7 +569,8 @@ int ir_raw_event_prepare(struct rc_dev *dev) dev->raw->dev = dev; dev->change_protocol = change_protocol; - timer_setup(&dev->raw->edge_handle, edge_handle, 0); + spin_lock_init(&dev->raw->edge_spinlock); + timer_setup(&dev->raw->edge_handle, ir_raw_edge_handle, 0); INIT_KFIFO(dev->raw->kfifo); return 0; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 1db8d38fed7c..b67be33bd62f 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -68,6 +68,8 @@ static const struct { .scancode_bits = 0x1fff, .repeat_period = 250 }, [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 }, + [RC_PROTO_IMON] = { .name = "imon", + .scancode_bits = 0x7fffffff, .repeat_period = 250 }, }; /* Used to keep track of known keymaps */ @@ -156,6 +158,7 @@ static struct rc_map_list empty_map = { /** * ir_create_table() - initializes a scancode table + * @dev: the rc_dev device * @rc_map: the rc_map to initialize * @name: name to assign to the table * @rc_proto: ir type to assign to the new table @@ -166,7 +169,7 @@ static struct rc_map_list empty_map = { * * return: zero on success or a negative error code */ -static int ir_create_table(struct rc_map *rc_map, +static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map, const char *name, u64 rc_proto, size_t size) { rc_map->name = kstrdup(name, GFP_KERNEL); @@ -182,8 +185,8 @@ static int ir_create_table(struct rc_map *rc_map, return -ENOMEM; } - IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", - rc_map->size, rc_map->alloc); + dev_dbg(&dev->dev, "Allocated space for %u keycode entries (%u bytes)\n", + rc_map->size, rc_map->alloc); return 0; } @@ -205,6 +208,7 @@ static void ir_free_table(struct rc_map *rc_map) /** * ir_resize_table() - resizes a scancode table if necessary + * @dev: the rc_dev device * @rc_map: the rc_map to resize * @gfp_flags: gfp flags to use when allocating memory * @@ -213,7 +217,8 @@ static void ir_free_table(struct rc_map *rc_map) * * return: zero on success or a negative error code */ -static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) +static int ir_resize_table(struct rc_dev *dev, struct rc_map *rc_map, + gfp_t gfp_flags) { unsigned int oldalloc = rc_map->alloc; unsigned int newalloc = oldalloc; @@ -226,23 +231,21 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) return -ENOMEM; newalloc *= 2; - IR_dprintk(1, "Growing table to %u bytes\n", newalloc); + dev_dbg(&dev->dev, "Growing table to %u bytes\n", newalloc); } if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) { /* Less than 1/3 of entries in use -> shrink keytable */ newalloc /= 2; - IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc); + dev_dbg(&dev->dev, "Shrinking table to %u bytes\n", newalloc); } if (newalloc == oldalloc) return 0; newscan = kmalloc(newalloc, gfp_flags); - if (!newscan) { - IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc); + if (!newscan) return -ENOMEM; - } memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table)); rc_map->scan = newscan; @@ -275,16 +278,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { - IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", - index, rc_map->scan[index].scancode); + dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n", + index, rc_map->scan[index].scancode); rc_map->len--; memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], (rc_map->len - index) * sizeof(struct rc_map_table)); } else { - IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n", - index, - old_keycode == KEY_RESERVED ? "New" : "Replacing", - rc_map->scan[index].scancode, new_keycode); + dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n", + index, + old_keycode == KEY_RESERVED ? "New" : "Replacing", + rc_map->scan[index].scancode, new_keycode); rc_map->scan[index].keycode = new_keycode; __set_bit(new_keycode, dev->input_dev->keybit); } @@ -301,7 +304,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, } /* Possibly shrink the keytable, failure is not a problem */ - ir_resize_table(rc_map, GFP_ATOMIC); + ir_resize_table(dev, rc_map, GFP_ATOMIC); } return old_keycode; @@ -352,7 +355,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev, /* No previous mapping found, we might need to grow the table */ if (rc_map->size == rc_map->len) { - if (!resize || ir_resize_table(rc_map, GFP_ATOMIC)) + if (!resize || ir_resize_table(dev, rc_map, GFP_ATOMIC)) return -1U; } @@ -431,8 +434,8 @@ static int ir_setkeytable(struct rc_dev *dev, unsigned int i, index; int rc; - rc = ir_create_table(rc_map, from->name, - from->rc_proto, from->size); + rc = ir_create_table(dev, rc_map, from->name, from->rc_proto, + from->size); if (rc) return rc; @@ -576,8 +579,8 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) spin_unlock_irqrestore(&rc_map->lock, flags); if (keycode != KEY_RESERVED) - IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", - dev->device_name, scancode, keycode); + dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n", + dev->device_name, scancode, keycode); return keycode; } @@ -596,7 +599,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync) if (!dev->keypressed) return; - IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); + dev_dbg(&dev->dev, "keyup key 0x%04x\n", dev->last_keycode); del_timer(&dev->timer_repeat); input_report_key(dev->input_dev, dev->last_keycode, 0); led_trigger_event(led_feedback, LED_OFF); @@ -751,8 +754,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, /* Register a keypress */ dev->keypressed = true; - IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", - dev->device_name, keycode, protocol, scancode); + dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + dev->device_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); led_trigger_event(led_feedback, LED_FULL); @@ -1003,6 +1006,7 @@ static const struct { RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, { RC_PROTO_BIT_CEC, "cec", NULL }, + { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" }, }; /** @@ -1056,8 +1060,8 @@ static ssize_t show_protocols(struct device *device, mutex_unlock(&dev->lock); - IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n", - __func__, (long long)allowed, (long long)enabled); + dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - 0x%llx\n", + __func__, (long long)allowed, (long long)enabled); for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (allowed & enabled & proto_names[i].type) @@ -1083,6 +1087,7 @@ static ssize_t show_protocols(struct device *device, /** * parse_protocol_change() - parses a protocol change request + * @dev: rc_dev device * @protocols: pointer to the bitmask of current protocols * @buf: pointer to the buffer with a list of changes * @@ -1092,7 +1097,8 @@ static ssize_t show_protocols(struct device *device, * Writing "none" will disable all protocols. * Returns the number of changes performed or a negative error code. */ -static int parse_protocol_change(u64 *protocols, const char *buf) +static int parse_protocol_change(struct rc_dev *dev, u64 *protocols, + const char *buf) { const char *tmp; unsigned count = 0; @@ -1128,7 +1134,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf) if (!strcasecmp(tmp, "lirc")) mask = 0; else { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + dev_dbg(&dev->dev, "Unknown protocol: '%s'\n", + tmp); return -EINVAL; } } @@ -1144,7 +1151,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } if (!count) { - IR_dprintk(1, "Protocol not specified\n"); + dev_dbg(&dev->dev, "Protocol not specified\n"); return -EINVAL; } @@ -1217,12 +1224,12 @@ static ssize_t store_protocols(struct device *device, u64 old_protocols, new_protocols; ssize_t rc; - IR_dprintk(1, "Normal protocol change requested\n"); + dev_dbg(&dev->dev, "Normal protocol change requested\n"); current_protocols = &dev->enabled_protocols; filter = &dev->scancode_filter; if (!dev->change_protocol) { - IR_dprintk(1, "Protocol switching not supported\n"); + dev_dbg(&dev->dev, "Protocol switching not supported\n"); return -EINVAL; } @@ -1230,14 +1237,14 @@ static ssize_t store_protocols(struct device *device, old_protocols = *current_protocols; new_protocols = old_protocols; - rc = parse_protocol_change(&new_protocols, buf); + rc = parse_protocol_change(dev, &new_protocols, buf); if (rc < 0) goto out; rc = dev->change_protocol(dev, &new_protocols); if (rc < 0) { - IR_dprintk(1, "Error setting protocols to 0x%llx\n", - (long long)new_protocols); + dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n", + (long long)new_protocols); goto out; } @@ -1246,8 +1253,8 @@ static ssize_t store_protocols(struct device *device, if (new_protocols != old_protocols) { *current_protocols = new_protocols; - IR_dprintk(1, "Protocols changed to 0x%llx\n", - (long long)new_protocols); + dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n", + (long long)new_protocols); } /* @@ -1435,8 +1442,8 @@ static ssize_t show_wakeup_protocols(struct device *device, mutex_unlock(&dev->lock); - IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n", - __func__, (long long)allowed, enabled); + dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - %d\n", + __func__, (long long)allowed, enabled); for (i = 0; i < ARRAY_SIZE(protocols); i++) { if (allowed & (1ULL << i)) { @@ -1511,7 +1518,7 @@ static ssize_t store_wakeup_protocols(struct device *device, if (dev->wakeup_protocol != protocol) { dev->wakeup_protocol = protocol; - IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol); + dev_dbg(&dev->dev, "Wakeup protocol changed to %d\n", protocol); if (protocol == RC_PROTO_RC6_MCE) dev->scancode_wakeup_filter.data = 0x800f0000; @@ -1874,9 +1881,8 @@ int rc_register_device(struct rc_dev *dev) dev->registered = true; - IR_dprintk(1, "Registered rc%u (driver: %s)\n", - dev->minor, - dev->driver_name ? dev->driver_name : "unknown"); + dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor, + dev->driver_name ? dev->driver_name : "unknown"); return 0; @@ -1929,12 +1935,12 @@ void rc_unregister_device(struct rc_dev *dev) if (!dev) return; - del_timer_sync(&dev->timer_keyup); - del_timer_sync(&dev->timer_repeat); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + del_timer_sync(&dev->timer_keyup); + del_timer_sync(&dev->timer_repeat); + rc_free_rx_device(dev); mutex_lock(&dev->lock); @@ -1994,9 +2000,5 @@ static void __exit rc_core_exit(void) subsys_initcall(rc_core_init); module_exit(rc_core_exit); -int rc_core_debug; /* ir_debug level (0,1,2) */ -EXPORT_SYMBOL_GPL(rc_core_debug); -module_param_named(debug, rc_core_debug, int, 0644); - MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 97f367b446c4..f500cea228a9 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -72,12 +72,8 @@ /* CIR_REG register idle threshold */ #define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8))) -/* Required frequency for IR0 or IR1 clock in CIR mode */ +/* Required frequency for IR0 or IR1 clock in CIR mode (default) */ #define SUNXI_IR_BASE_CLK 8000000 -/* Frequency after IR internal divider */ -#define SUNXI_IR_CLK (SUNXI_IR_BASE_CLK / 64) -/* Sample period in ns */ -#define SUNXI_IR_SAMPLE (1000000000ul / SUNXI_IR_CLK) /* Noise threshold in samples */ #define SUNXI_IR_RXNOISE 1 /* Idle Threshold in samples */ @@ -122,7 +118,8 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) /* for each bit in fifo */ dt = readb(ir->base + SUNXI_IR_RXFIFO_REG); rawir.pulse = (dt & 0x80) != 0; - rawir.duration = ((dt & 0x7f) + 1) * SUNXI_IR_SAMPLE; + rawir.duration = ((dt & 0x7f) + 1) * + ir->rc->rx_resolution; ir_raw_event_store_with_filter(ir->rc, &rawir); } } @@ -148,6 +145,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) struct device_node *dn = dev->of_node; struct resource *res; struct sunxi_ir *ir; + u32 b_clk_freq = SUNXI_IR_BASE_CLK; ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL); if (!ir) @@ -172,6 +170,9 @@ static int sunxi_ir_probe(struct platform_device *pdev) return PTR_ERR(ir->clk); } + /* Base clock frequency (optional) */ + of_property_read_u32(dn, "clock-frequency", &b_clk_freq); + /* Reset (optional) */ ir->rst = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(ir->rst)) @@ -180,11 +181,12 @@ static int sunxi_ir_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); + ret = clk_set_rate(ir->clk, b_clk_freq); if (ret) { dev_err(dev, "set ir base clock failed!\n"); goto exit_reset_assert; } + dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq); if (clk_prepare_enable(ir->apb_clk)) { dev_err(dev, "try to enable apb_ir_clk failed\n"); @@ -225,7 +227,8 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - ir->rc->rx_resolution = SUNXI_IR_SAMPLE; + /* Frequency after IR internal divider with sample period in ns */ + ir->rc->rx_resolution = (1000000000ul / (b_clk_freq / 64)); ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT); ir->rc->driver_name = SUNXI_IR_DEV; diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index a21f5a39a440..b07ac86fc53c 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -12,3 +12,17 @@ config VIDEO_GS1662 endmenu endif + +if SPI +menu "Media SPI Adapters" + +config CXD2880_SPI_DRV + tristate "Sony CXD2880 SPI support" + depends on DVB_CORE && SPI + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Choose if you would like to have SPI interface support for Sony CXD2880. + +endmenu + +endif diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile index ea64013d16cc..9e536777a330 100644 --- a/drivers/media/spi/Makefile +++ b/drivers/media/spi/Makefile @@ -1 +1,6 @@ obj-$(CONFIG_VIDEO_GS1662) += gs1662.o +obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/dvb-frontends/cxd2880 diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c new file mode 100644 index 000000000000..4df3bd312f48 --- /dev/null +++ b/drivers/media/spi/cxd2880-spi.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880-spi.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI adapter + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include <linux/spi/spi.h> +#include <linux/ktime.h> + +#include <media/dvb_demux.h> +#include <media/dmxdev.h> +#include <media/dvb_frontend.h> +#include "cxd2880.h" + +#define CXD2880_MAX_FILTER_SIZE 32 +#define BURST_WRITE_MAX 128 +#define MAX_TRANS_PKT 300 + +struct cxd2880_ts_buf_info { + u8 read_ready:1; + u8 almost_full:1; + u8 almost_empty:1; + u8 overflow:1; + u8 underflow:1; + u16 pkt_num; +}; + +struct cxd2880_pid_config { + u8 is_enable; + u16 pid; +}; + +struct cxd2880_pid_filter_config { + u8 is_negative; + struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE]; +}; + +struct cxd2880_dvb_spi { + struct dvb_frontend dvb_fe; + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend dmx_fe; + struct task_struct *cxd2880_ts_read_thread; + struct spi_device *spi; + struct mutex spi_mutex; /* For SPI access exclusive control */ + int feed_count; + int all_pid_feed_count; + u8 *ts_buf; + struct cxd2880_pid_filter_config filter_config; +}; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size) +{ + struct spi_message msg; + struct spi_transfer tx; + + if (!spi || !data) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + memset(&tx, 0, sizeof(tx)); + tx.tx_buf = data; + tx.len = size; + + spi_message_init(&msg); + spi_message_add_tail(&tx, &msg); + + return spi_sync(spi, &msg); +} + +static int cxd2880_write_reg(struct spi_device *spi, + u8 sub_address, const u8 *data, u32 size) +{ + u8 send_data[BURST_WRITE_MAX + 4]; + const u8 *write_data_top = NULL; + int ret = 0; + + if (!spi || !data) { + pr_err("invalid arg\n"); + return -EINVAL; + } + if (size > BURST_WRITE_MAX) { + pr_err("data size > WRITE_MAX\n"); + return -EINVAL; + } + + if (sub_address + size > 0x100) { + pr_err("out of range\n"); + return -EINVAL; + } + + send_data[0] = 0x0e; + write_data_top = data; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = (u8)size; + + memcpy(&send_data[3], write_data_top, send_data[2]); + + ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3); + if (ret) { + pr_err("write spi failed %d\n", ret); + break; + } + sub_address += send_data[2]; + write_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +static int cxd2880_spi_read_ts(struct spi_device *spi, + u8 *read_data, + u32 packet_num) +{ + int ret; + u8 data[3]; + struct spi_message message; + struct spi_transfer transfer[2]; + + if (!spi || !read_data || !packet_num) { + pr_err("invalid arg\n"); + return -EINVAL; + } + if (packet_num > 0xffff) { + pr_err("packet num > 0xffff\n"); + return -EINVAL; + } + + data[0] = 0x10; + data[1] = packet_num >> 8; + data[2] = packet_num; + + spi_message_init(&message); + memset(transfer, 0, sizeof(transfer)); + + transfer[0].len = 3; + transfer[0].tx_buf = data; + spi_message_add_tail(&transfer[0], &message); + transfer[1].len = packet_num * 188; + transfer[1].rx_buf = read_data; + spi_message_add_tail(&transfer[1], &message); + + ret = spi_sync(spi, &message); + if (ret) + pr_err("spi_write_then_read failed\n"); + + return ret; +} + +static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi, + struct cxd2880_ts_buf_info *info) +{ + u8 send_data = 0x20; + u8 recv_data[2]; + int ret; + + if (!spi || !info) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + ret = spi_write_then_read(spi, &send_data, 1, + recv_data, sizeof(recv_data)); + if (ret) + pr_err("spi_write_then_read failed\n"); + + info->read_ready = (recv_data[0] & 0x80) ? 1 : 0; + info->almost_full = (recv_data[0] & 0x40) ? 1 : 0; + info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0; + info->overflow = (recv_data[0] & 0x10) ? 1 : 0; + info->underflow = (recv_data[0] & 0x08) ? 1 : 0; + info->pkt_num = ((recv_data[0] & 0x07) << 8) | recv_data[1]; + + return ret; +} + +static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi) +{ + u8 data = 0x03; + int ret; + + ret = cxd2880_write_spi(spi, &data, 1); + + if (ret) + pr_err("write spi failed\n"); + + return ret; +} + +static int cxd2880_set_pid_filter(struct spi_device *spi, + struct cxd2880_pid_filter_config *cfg) +{ + u8 data[65]; + int i; + u16 pid = 0; + int ret; + + if (!spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + data[0] = 0x00; + ret = cxd2880_write_reg(spi, 0x00, &data[0], 1); + if (ret) + return ret; + if (!cfg) { + data[0] = 0x02; + ret = cxd2880_write_reg(spi, 0x50, &data[0], 1); + } else { + data[0] = cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + pid = cfg->pid_config[i].pid; + if (cfg->pid_config[i].is_enable) { + data[1 + (i * 2)] = (pid >> 8) | 0x20; + data[2 + (i * 2)] = pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; + } + } + ret = cxd2880_write_reg(spi, 0x50, data, 65); + } + + return ret; +} + +static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi, + struct cxd2880_pid_filter_config *cfg, + bool is_all_pid_filter) +{ + int ret; + + if (!dvb_spi || !cfg) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + mutex_lock(&dvb_spi->spi_mutex); + if (is_all_pid_filter) { + struct cxd2880_pid_filter_config tmpcfg; + + memset(&tmpcfg, 0, sizeof(tmpcfg)); + tmpcfg.is_negative = 1; + tmpcfg.pid_config[0].is_enable = 1; + tmpcfg.pid_config[0].pid = 0x1fff; + + ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg); + } else { + ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg); + } + mutex_unlock(&dvb_spi->spi_mutex); + + if (ret) + pr_err("set_pid_filter failed\n"); + + return ret; +} + +static int cxd2880_ts_read(void *arg) +{ + struct cxd2880_dvb_spi *dvb_spi = NULL; + struct cxd2880_ts_buf_info info; + ktime_t start; + u32 i; + int ret; + + dvb_spi = arg; + if (!dvb_spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi); + if (ret) { + pr_err("set_clear_ts_buffer failed\n"); + return ret; + } + + start = ktime_get(); + while (!kthread_should_stop()) { + ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi, + &info); + if (ret) { + pr_err("spi_read_ts_buffer_info error\n"); + return ret; + } + + if (info.pkt_num > MAX_TRANS_PKT) { + for (i = 0; i < info.pkt_num / MAX_TRANS_PKT; i++) { + cxd2880_spi_read_ts(dvb_spi->spi, + dvb_spi->ts_buf, + MAX_TRANS_PKT); + dvb_dmx_swfilter(&dvb_spi->demux, + dvb_spi->ts_buf, + MAX_TRANS_PKT * 188); + } + start = ktime_get(); + } else if ((info.pkt_num > 0) && + (ktime_to_ms(ktime_sub(ktime_get(), start)) >= 500)) { + cxd2880_spi_read_ts(dvb_spi->spi, + dvb_spi->ts_buf, + info.pkt_num); + dvb_dmx_swfilter(&dvb_spi->demux, + dvb_spi->ts_buf, + info.pkt_num * 188); + start = ktime_get(); + } else { + usleep_range(10000, 11000); + } + } + + return 0; +} + +static int cxd2880_start_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + int i = 0; + struct dvb_demux *demux = NULL; + struct cxd2880_dvb_spi *dvb_spi = NULL; + + if (!feed) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + demux = feed->demux; + if (!demux) { + pr_err("feed->demux is NULL\n"); + return -EINVAL; + } + dvb_spi = demux->priv; + + if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) { + pr_err("Exceeded maximum PID count (32)."); + pr_err("Selected PID cannot be enabled.\n"); + return -EINVAL; + } + + if (feed->pid == 0x2000) { + if (dvb_spi->all_pid_feed_count == 0) { + ret = cxd2880_update_pid_filter(dvb_spi, + &dvb_spi->filter_config, + true); + if (ret) { + pr_err("update pid filter failed\n"); + return ret; + } + } + dvb_spi->all_pid_feed_count++; + + pr_debug("all PID feed (count = %d)\n", + dvb_spi->all_pid_feed_count); + } else { + struct cxd2880_pid_filter_config cfgtmp; + + cfgtmp = dvb_spi->filter_config; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + if (cfgtmp.pid_config[i].is_enable == 0) { + cfgtmp.pid_config[i].is_enable = 1; + cfgtmp.pid_config[i].pid = feed->pid; + pr_debug("store PID %d to #%d\n", + feed->pid, i); + break; + } + } + if (i == CXD2880_MAX_FILTER_SIZE) { + pr_err("PID filter is full. Assumed bug.\n"); + return -EINVAL; + } + if (!dvb_spi->all_pid_feed_count) + ret = cxd2880_update_pid_filter(dvb_spi, + &cfgtmp, + false); + if (ret) + return ret; + + dvb_spi->filter_config = cfgtmp; + } + + if (dvb_spi->feed_count == 0) { + dvb_spi->ts_buf = + kmalloc(MAX_TRANS_PKT * 188, + GFP_KERNEL | GFP_DMA); + if (!dvb_spi->ts_buf) { + pr_err("ts buffer allocate failed\n"); + memset(&dvb_spi->filter_config, 0, + sizeof(dvb_spi->filter_config)); + dvb_spi->all_pid_feed_count = 0; + return -ENOMEM; + } + dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read, + dvb_spi, + "cxd2880_ts_read"); + if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) { + pr_err("kthread_run failed/\n"); + kfree(dvb_spi->ts_buf); + dvb_spi->ts_buf = NULL; + memset(&dvb_spi->filter_config, 0, + sizeof(dvb_spi->filter_config)); + dvb_spi->all_pid_feed_count = 0; + return PTR_ERR(dvb_spi->cxd2880_ts_read_thread); + } + } + + dvb_spi->feed_count++; + + pr_debug("start feed (count %d)\n", dvb_spi->feed_count); + return 0; +} + +static int cxd2880_stop_feed(struct dvb_demux_feed *feed) +{ + int i = 0; + int ret; + struct dvb_demux *demux = NULL; + struct cxd2880_dvb_spi *dvb_spi = NULL; + + if (!feed) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + demux = feed->demux; + if (!demux) { + pr_err("feed->demux is NULL\n"); + return -EINVAL; + } + dvb_spi = demux->priv; + + if (!dvb_spi->feed_count) { + pr_err("no feed is started\n"); + return -EINVAL; + } + + if (feed->pid == 0x2000) { + /* + * Special PID case. + * Number of 0x2000 feed request was stored + * in dvb_spi->all_pid_feed_count. + */ + if (dvb_spi->all_pid_feed_count <= 0) { + pr_err("PID %d not found.\n", feed->pid); + return -EINVAL; + } + dvb_spi->all_pid_feed_count--; + } else { + struct cxd2880_pid_filter_config cfgtmp; + + cfgtmp = dvb_spi->filter_config; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + if (feed->pid == cfgtmp.pid_config[i].pid && + cfgtmp.pid_config[i].is_enable != 0) { + cfgtmp.pid_config[i].is_enable = 0; + cfgtmp.pid_config[i].pid = 0; + pr_debug("removed PID %d from #%d\n", + feed->pid, i); + break; + } + } + dvb_spi->filter_config = cfgtmp; + + if (i == CXD2880_MAX_FILTER_SIZE) { + pr_err("PID %d not found\n", feed->pid); + return -EINVAL; + } + } + + ret = cxd2880_update_pid_filter(dvb_spi, + &dvb_spi->filter_config, + dvb_spi->all_pid_feed_count > 0); + dvb_spi->feed_count--; + + if (dvb_spi->feed_count == 0) { + int ret_stop = 0; + + ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread); + if (ret_stop) { + pr_err("'kthread_stop failed. (%d)\n", ret_stop); + ret = ret_stop; + } + kfree(dvb_spi->ts_buf); + dvb_spi->ts_buf = NULL; + } + + pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count); + + return ret; +} + +static const struct of_device_id cxd2880_spi_of_match[] = { + { .compatible = "sony,cxd2880" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match); + +static int +cxd2880_spi_probe(struct spi_device *spi) +{ + int ret; + struct cxd2880_dvb_spi *dvb_spi = NULL; + struct cxd2880_config config; + + if (!spi) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL); + if (!dvb_spi) + return -ENOMEM; + + dvb_spi->spi = spi; + mutex_init(&dvb_spi->spi_mutex); + dev_set_drvdata(&spi->dev, dvb_spi); + config.spi = spi; + config.spi_mutex = &dvb_spi->spi_mutex; + + ret = dvb_register_adapter(&dvb_spi->adapter, + "CXD2880", + THIS_MODULE, + &spi->dev, + adapter_nr); + if (ret < 0) { + pr_err("dvb_register_adapter() failed\n"); + goto fail_adapter; + } + + if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) { + pr_err("cxd2880_attach failed\n"); + goto fail_attach; + } + + ret = dvb_register_frontend(&dvb_spi->adapter, + &dvb_spi->dvb_fe); + if (ret < 0) { + pr_err("dvb_register_frontend() failed\n"); + goto fail_frontend; + } + + dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING; + dvb_spi->demux.priv = dvb_spi; + dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->demux.start_feed = cxd2880_start_feed; + dvb_spi->demux.stop_feed = cxd2880_stop_feed; + + ret = dvb_dmx_init(&dvb_spi->demux); + if (ret < 0) { + pr_err("dvb_dmx_init() failed\n"); + goto fail_dmx; + } + + dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx; + dvb_spi->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&dvb_spi->dmxdev, + &dvb_spi->adapter); + if (ret < 0) { + pr_err("dvb_dmxdev_init() failed\n"); + goto fail_dmxdev; + } + + dvb_spi->dmx_fe.source = DMX_FRONTEND_0; + ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + if (ret < 0) { + pr_err("add_frontend() failed\n"); + goto fail_dmx_fe; + } + + ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + if (ret < 0) { + pr_err("dvb_register_frontend() failed\n"); + goto fail_fe_conn; + } + + pr_info("Sony CXD2880 has successfully attached.\n"); + + return 0; + +fail_fe_conn: + dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); +fail_dmx_fe: + dvb_dmxdev_release(&dvb_spi->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb_spi->demux); +fail_dmx: + dvb_unregister_frontend(&dvb_spi->dvb_fe); +fail_frontend: + dvb_frontend_detach(&dvb_spi->dvb_fe); +fail_attach: + dvb_unregister_adapter(&dvb_spi->adapter); +fail_adapter: + kfree(dvb_spi); + return ret; +} + +static int +cxd2880_spi_remove(struct spi_device *spi) +{ + struct cxd2880_dvb_spi *dvb_spi; + + if (!spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + dvb_spi = dev_get_drvdata(&spi->dev); + + if (!dvb_spi) { + pr_err("failed\n"); + return -EINVAL; + } + dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + dvb_dmxdev_release(&dvb_spi->dmxdev); + dvb_dmx_release(&dvb_spi->demux); + dvb_unregister_frontend(&dvb_spi->dvb_fe); + dvb_frontend_detach(&dvb_spi->dvb_fe); + dvb_unregister_adapter(&dvb_spi->adapter); + + kfree(dvb_spi); + pr_info("cxd2880_spi remove ok.\n"); + + return 0; +} + +static const struct spi_device_id cxd2880_spi_id[] = { + { "cxd2880", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, cxd2880_spi_id); + +static struct spi_driver cxd2880_spi_driver = { + .driver = { + .name = "cxd2880", + .of_match_table = cxd2880_spi_of_match, + }, + .id_table = cxd2880_spi_id, + .probe = cxd2880_spi_probe, + .remove = cxd2880_spi_remove, +}; +module_spi_driver(cxd2880_spi_driver); + +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter"); +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 564a000f503e..b5b9d87ba75c 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -293,28 +293,18 @@ static inline struct e4000_dev *e4000_subdev_to_dev(struct v4l2_subdev *sd) return container_of(sd, struct e4000_dev, sd); } -static int e4000_s_power(struct v4l2_subdev *sd, int on) +static int e4000_standby(struct v4l2_subdev *sd) { struct e4000_dev *dev = e4000_subdev_to_dev(sd); - struct i2c_client *client = dev->client; int ret; - dev_dbg(&client->dev, "on=%d\n", on); - - if (on) - ret = e4000_init(dev); - else - ret = e4000_sleep(dev); + ret = e4000_sleep(dev); if (ret) return ret; return e4000_set_params(dev); } -static const struct v4l2_subdev_core_ops e4000_subdev_core_ops = { - .s_power = e4000_s_power, -}; - static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct e4000_dev *dev = e4000_subdev_to_dev(sd); @@ -382,6 +372,7 @@ static int e4000_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { + .standby = e4000_standby, .g_tuner = e4000_g_tuner, .s_tuner = e4000_s_tuner, .g_frequency = e4000_g_frequency, @@ -390,7 +381,6 @@ static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { }; static const struct v4l2_subdev_ops e4000_subdev_ops = { - .core = &e4000_subdev_core_ops, .tuner = &e4000_subdev_tuner_ops, }; diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index f4d4665de168..743184ae0d26 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -386,28 +386,18 @@ static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd) return container_of(sd, struct fc2580_dev, subdev); } -static int fc2580_s_power(struct v4l2_subdev *sd, int on) +static int fc2580_standby(struct v4l2_subdev *sd) { struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); - struct i2c_client *client = dev->client; int ret; - dev_dbg(&client->dev, "on=%d\n", on); - - if (on) - ret = fc2580_init(dev); - else - ret = fc2580_sleep(dev); + ret = fc2580_sleep(dev); if (ret) return ret; return fc2580_set_params(dev); } -static const struct v4l2_subdev_core_ops fc2580_subdev_core_ops = { - .s_power = fc2580_s_power, -}; - static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); @@ -475,6 +465,7 @@ static int fc2580_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = { + .standby = fc2580_standby, .g_tuner = fc2580_g_tuner, .s_tuner = fc2580_s_tuner, .g_frequency = fc2580_g_frequency, @@ -483,7 +474,6 @@ static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = { }; static const struct v4l2_subdev_ops fc2580_subdev_ops = { - .core = &fc2580_subdev_core_ops, .tuner = &fc2580_subdev_tuner_ops, }; diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index 3a12ef35682b..5de6ed728708 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -291,26 +291,13 @@ err: return ret; } -static int msi001_s_power(struct v4l2_subdev *sd, int on) +static int msi001_standby(struct v4l2_subdev *sd) { struct msi001_dev *dev = sd_to_msi001_dev(sd); - struct spi_device *spi = dev->spi; - int ret; - - dev_dbg(&spi->dev, "on=%d\n", on); - - if (on) - ret = 0; - else - ret = msi001_wreg(dev, 0x000000); - return ret; + return msi001_wreg(dev, 0x000000); } -static const struct v4l2_subdev_core_ops msi001_core_ops = { - .s_power = msi001_s_power, -}; - static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct msi001_dev *dev = sd_to_msi001_dev(sd); @@ -386,6 +373,7 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = { + .standby = msi001_standby, .g_tuner = msi001_g_tuner, .s_tuner = msi001_s_tuner, .g_frequency = msi001_g_frequency, @@ -394,7 +382,6 @@ static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = { }; static const struct v4l2_subdev_ops msi001_ops = { - .core = &msi001_core_ops, .tuner = &msi001_tuner_ops, }; diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index bfaa806633df..65fc067eb864 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 select I2C_ALGOBIT select VIDEO_TVEEPROM - select VIDEOBUF2_VMALLOC + select VIDEOBUF2_VMALLOC if VIDEO_V4L2 select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT @@ -18,7 +18,8 @@ config VIDEO_AU0828 config VIDEO_AU0828_V4L2 bool "Auvitek AU0828 v4l2 analog video support" - depends on VIDEO_AU0828 && VIDEO_V4L2 + depends on VIDEO_AU0828 + depends on VIDEO_V4L2=y || VIDEO_V4L2=VIDEO_AU0828 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index c765d546114d..964cd7bcdd2c 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1091,8 +1091,8 @@ static int au0828_v4l2_close(struct file *filp) */ ret = v4l_enable_media_source(vdev); if (ret == 0) - v4l2_device_call_all(&dev->v4l2_dev, 0, core, - s_power, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, + standby); dev->std_set_in_tuner_core = 0; /* When close the device, set the usb intf0 into alt0 to free diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index f3a1e5b1e57c..b51fc372ca25 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -910,9 +910,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) wake_up_interruptible(&cam->wq_stream); } - DBG("Releasing interface\n"); - usb_driver_release_interface(&cpia2_driver, intf); - LOG("CPiA2 camera disconnected.\n"); } diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index f9ec7fedcd5b..c76b2101193c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -922,6 +922,85 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_HAUPPAUGE_935C] = { + .name = "Hauppauge WinTV-HVR-935C", + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = I2C_1_MUX_3, + .demod_i2c_master = I2C_1_MUX_3, + .has_dvb = 1, + .demod_addr = 0x64, /* 0xc8 >> 1 */ + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_975] = { + .name = "Hauppauge WinTV-HVR-975", + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = I2C_1_MUX_3, + .demod_i2c_master = I2C_1_MUX_3, + .has_dvb = 1, + .demod_addr = 0x59, /* 0xb2 >> 1 */ + .demod_addr2 = 0x64, /* 0xc8 >> 1 */ + .norm = V4L2_STD_ALL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -953,6 +1032,10 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb123), .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, + {USB_DEVICE(0x2040, 0xb151), + .driver_info = CX231XX_BOARD_HAUPPAUGE_935C}, + {USB_DEVICE(0x2040, 0xb150), + .driver_info = CX231XX_BOARD_HAUPPAUGE_975}, {USB_DEVICE(0x2040, 0xb130), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb131), @@ -1135,7 +1218,7 @@ static void cx231xx_config_tuner(struct cx231xx *dev) static int read_eeprom(struct cx231xx *dev, struct i2c_client *client, u8 *eedata, int len) { - int ret = 0; + int ret; u8 start_offset = 0; int len_todo = len; u8 *eedata_cur = eedata; @@ -1211,6 +1294,8 @@ void cx231xx_card_setup(struct cx231xx *dev) case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_955Q: + case CX231XX_BOARD_HAUPPAUGE_935C: + case CX231XX_BOARD_HAUPPAUGE_975: { struct eeprom { struct tveeprom tvee; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index fb5654062b1a..713029420fcf 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -53,9 +53,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX231XX_DVB_NUM_BUFS 5 #define CX231XX_DVB_MAX_PACKETSIZE 564 #define CX231XX_DVB_MAX_PACKETS 64 +#define CX231XX_DVB_MAX_FRONTENDS 2 struct cx231xx_dvb { - struct dvb_frontend *frontend; + struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS]; /* feed count management */ struct mutex lock; @@ -68,7 +69,7 @@ struct cx231xx_dvb { struct dmx_frontend fe_hw; struct dmx_frontend fe_mem; struct dvb_net net; - struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_demod[2]; struct i2c_client *i2c_client_tuner; }; @@ -79,7 +80,7 @@ static struct s5h1432_config dvico_s5h1432_config = { .vsb_if = S5H1432_IF_4000, .inversion = S5H1432_INVERSION_OFF, .status_mode = S5H1432_DEMODLOCKING, - .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { @@ -108,7 +109,7 @@ static struct s5h1411_config tda18271_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config xc5000_s5h1411_config = { .output_mode = S5H1411_SERIAL_OUTPUT, @@ -117,7 +118,7 @@ static struct s5h1411_config xc5000_s5h1411_config = { .qam_if = S5H1411_IF_3250, .inversion = S5H1411_INVERSION_OFF, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct lgdt3305_config hcw_lgdt3305_config = { @@ -386,17 +387,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); cfg.i2c_addr = addr; - if (!dev->dvb->frontend) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n", dev->name); return -EINVAL; } - fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); + fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg); if (!fe) { dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; + dvb_frontend_detach(dev->dvb->frontend[0]); + dev->dvb->frontend[0] = NULL; return -EINVAL; } @@ -408,9 +409,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) { - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->set_analog_params != NULL) { struct analog_parameters params; @@ -421,7 +422,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) /*params.audmode = ; */ /* Set the analog parameters to set the frequency */ - dops->set_analog_params(dev->dvb->frontend, ¶ms); + dops->set_analog_params(dev->dvb->frontend[0], ¶ms); } } @@ -433,15 +434,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev) { int status = 0; - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->init != NULL && !dev->xc_fw_load_done) { dev_dbg(dev->dev, "Reloading firmware for XC5000\n"); - status = dops->init(dev->dvb->frontend); + status = dops->init(dev->dvb->frontend[0]); if (status == 0) { dev->xc_fw_load_done = 1; dev_dbg(dev->dev, @@ -481,17 +482,32 @@ static int register_dvb(struct cx231xx_dvb *dvb, dvb_register_media_controller(&dvb->adapter, dev->media_dev); /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + if (dvb->frontend[1]) + dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; dvb->adapter.priv = dev; /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]); if (result < 0) { dev_warn(dev->dev, "%s: dvb_register_frontend failed (errno = %d)\n", dev->name, result); - goto fail_frontend; + goto fail_frontend0; + } + + if (dvb->frontend[1]) { + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]); + if (result < 0) { + dev_warn(dev->dev, + "%s: 2nd dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend1; + } + + /* MFE lock */ + dvb->adapter.mfe_shared = 1; } /* register demux stuff */ @@ -569,9 +585,14 @@ fail_fe_hw: fail_dmxdev: dvb_dmx_release(&dvb->demux); fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); +fail_frontend1: + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); +fail_frontend0: + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); fail_adapter: return result; @@ -585,8 +606,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); dvb_dmxdev_release(&dvb->dmxdev); dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); /* remove I2C tuner */ client = dvb->i2c_client_tuner; @@ -595,7 +620,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) i2c_unregister_device(client); } /* remove I2C demod */ - client = dvb->i2c_client_demod; + client = dvb->i2c_client_demod[1]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + client = dvb->i2c_client_demod[0]; if (client) { module_put(client->dev.driver->owner); i2c_unregister_device(client); @@ -604,7 +634,7 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) static int dvb_init(struct cx231xx *dev) { - int result = 0; + int result; struct cx231xx_dvb *dvb; struct i2c_adapter *tuner_i2c; struct i2c_adapter *demod_i2c; @@ -635,11 +665,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_CARRAERA: case CX231XX_BOARD_CNXT_RDE_250: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -647,9 +677,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rde250_tunerconfig)) { result = -EINVAL; @@ -660,11 +690,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_SHELBY: case CX231XX_BOARD_CNXT_RDU_250: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &xc5000_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -672,9 +702,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rdu250_tunerconfig)) { result = -EINVAL; @@ -683,11 +713,11 @@ static int dvb_init(struct cx231xx *dev) break; case CX231XX_BOARD_CNXT_RDE_253S: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -695,9 +725,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; @@ -707,11 +737,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &tda18271_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -719,9 +749,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; @@ -734,11 +764,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for tuner / demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(lgdt3305_attach, + dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach LG3305 front end\n"); result = -EINVAL; @@ -746,9 +776,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &hcw_tda18271_config); break; @@ -761,7 +791,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demod */ memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; + si2165_pdata.fe = &dev->dvb->frontend[0]; si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL; si2165_pdata.ref_freq_hz = 16000000; @@ -771,7 +801,7 @@ static int dvb_init(struct cx231xx *dev) info.platform_data = &si2165_pdata; request_module(info.type); client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { + if (!client || !client->dev.driver || !dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach SI2165 front end\n"); result = -EINVAL; @@ -784,14 +814,14 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &hcw_tda18271_config); @@ -808,7 +838,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demod */ memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; + si2165_pdata.fe = &dev->dvb->frontend[0]; si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT; si2165_pdata.ref_freq_hz = 24000000; @@ -818,7 +848,7 @@ static int dvb_init(struct cx231xx *dev) info.platform_data = &si2165_pdata; request_module(info.type); client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { + if (!client || !client->dev.driver || !dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach SI2165 front end\n"); result = -EINVAL; @@ -831,18 +861,18 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; memset(&info, 0, sizeof(struct i2c_board_info)); - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -857,14 +887,14 @@ static int dvb_init(struct cx231xx *dev) tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } @@ -882,26 +912,26 @@ static int dvb_init(struct cx231xx *dev) memset(&info, 0, sizeof(struct i2c_board_info)); - dev->dvb->frontend = dvb_attach(lgdt3306a_attach, + dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach, &hauppauge_955q_lgdt3306a_config, demod_i2c ); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach LGDT3306A frontend.\n"); result = -EINVAL; goto out_free; } - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -916,14 +946,14 @@ static int dvb_init(struct cx231xx *dev) tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } @@ -940,11 +970,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(mb86a20s_attach, + dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach, &pv_mb86a20s_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach mb86a20s demod\n"); result = -EINVAL; @@ -952,9 +982,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &pv_tda18271_config); break; @@ -969,7 +999,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */ - si2168_config.fe = &dev->dvb->frontend; + si2168_config.fe = &dev->dvb->frontend[0]; si2168_config.i2c_adapter = &adapter; si2168_config.ts_clock_inv = true; @@ -991,10 +1021,10 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; /* attach tuner chip */ - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -1010,16 +1040,16 @@ static int dvb_init(struct cx231xx *dev) client = i2c_new_device(tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } @@ -1037,7 +1067,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ mn88473_config.i2c_wr_max = 16; mn88473_config.xtal = 25000000; - mn88473_config.fe = &dev->dvb->frontend; + mn88473_config.fe = &dev->dvb->frontend[0]; strlcpy(info.type, "mn88473", sizeof(info.type)); info.addr = dev->board.demod_addr; @@ -1057,24 +1087,219 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner chip */ - dvb_attach(r820t_attach, dev->dvb->frontend, + dvb_attach(r820t_attach, dev->dvb->frontend[0], tuner_i2c, &astrometa_t2hybrid_r820t_config); break; } + case CX231XX_BOARD_HAUPPAUGE_935C: + { + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_board_info info = {}; + struct si2157_config si2157_config = {}; + struct si2168_config si2168_config = {}; + + /* attach demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend[0]; + si2168_config.i2c_adapter = &adapter; + si2168_config.ts_clock_inv = true; + + strlcpy(info.type, "si2168", sizeof(info.type)); + info.addr = dev->board.demod_addr; + info.platform_data = &si2168_config; + + request_module(info.type); + client = i2c_new_device(demod_i2c, &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod[0] = client; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; + + /* define general-purpose callback pointer */ + dvb->frontend[0]->callback = cx231xx_tuner_callback; + + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend[0]; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = dev->board.tuner_addr; + info.platform_data = &si2157_config; + request_module("si2157"); + + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to obtain %s tuner.\n", info.type); + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + dev->cx231xx_reset_analog_tuner = NULL; + dev->dvb->i2c_client_tuner = client; + break; + } + case CX231XX_BOARD_HAUPPAUGE_975: + { + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_adapter *adapter2; + struct i2c_board_info info = {}; + struct si2157_config si2157_config = {}; + struct lgdt3306a_config lgdt3306a_config = {}; + struct si2168_config si2168_config = {}; + + /* attach first demodulator chip */ + lgdt3306a_config = hauppauge_955q_lgdt3306a_config; + lgdt3306a_config.fe = &dev->dvb->frontend[0]; + lgdt3306a_config.i2c_adapter = &adapter; + lgdt3306a_config.deny_i2c_rptr = 0; + + strlcpy(info.type, "lgdt3306a", sizeof(info.type)); + info.addr = dev->board.demod_addr; + info.platform_data = &lgdt3306a_config; + + request_module(info.type); + client = i2c_new_device(demod_i2c, &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod[0] = client; + + /* attach second demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend[1]; + si2168_config.i2c_adapter = &adapter2; + si2168_config.ts_clock_inv = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", sizeof(info.type)); + info.addr = dev->board.demod_addr2; + info.platform_data = &si2168_config; + + request_module(info.type); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod[1] = client; + dvb->frontend[1]->id = 1; + + /* define general-purpose callback pointer */ + dvb->frontend[0]->callback = cx231xx_tuner_callback; + dvb->frontend[1]->callback = cx231xx_tuner_callback; + + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend[0]; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = dev->board.tuner_addr; + info.platform_data = &si2157_config; + request_module("si2157"); + + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod[1]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[1]); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to obtain %s tuner.\n", info.type); + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod[1]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[1]); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + dev->cx231xx_reset_analog_tuner = NULL; + dvb->i2c_client_tuner = client; + + dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv; + + memcpy(&dvb->frontend[1]->ops.tuner_ops, + &dvb->frontend[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + break; + } default: dev_err(dev->dev, "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); break; } - if (NULL == dvb->frontend) { + if (!dvb->frontend[0]) { dev_err(dev->dev, "%s/2: frontend initialization failed\n", dev->name); result = -EINVAL; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 5b321b8ada3a..f7fcd733a2ca 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1941,7 +1941,7 @@ static int cx231xx_close(struct file *filp) } /* Save some power by putting tuner to sleep */ - call_all(dev, core, s_power, 0); + call_all(dev, tuner, standby); /* do this before setting alternate! */ if (dev->USE_ISO) diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 65b039cf80be..6ffa4bd96484 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -81,6 +81,8 @@ #define CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD 23 #define CX231XX_BOARD_ASTROMETA_T2HYBRID 24 #define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25 +#define CX231XX_BOARD_HAUPPAUGE_935C 26 +#define CX231XX_BOARD_HAUPPAUGE_975 27 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 @@ -343,6 +345,7 @@ struct cx231xx_board { /* demod related */ int demod_addr; + int demod_addr2; u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */ /* GPIO Pins */ diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 0e4944b2b0f4..37053477b84d 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -15,7 +15,8 @@ config DVB_USB_V2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 + depends on DVB_USB_V2 && I2C_MUX + select REGMAP select DVB_AF9013 select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8013659c41b1..39f9ffce3caa 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -29,6 +29,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret, wlen, rlen; u8 write = 1; @@ -66,23 +67,24 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) case BOOT: break; default: - dev_err(&d->udev->dev, "%s: unknown command=%d\n", - KBUILD_MODNAME, req->cmd); + dev_err(&intf->dev, "unknown cmd %d\n", req->cmd); ret = -EIO; goto error; } - /* buffer overflow check */ + /* Buffer overflow check */ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - dev_err(&d->udev->dev, "%s: too much data; cmd=%d len=%d\n", - KBUILD_MODNAME, req->cmd, req->data_len); + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + dev_err(&intf->dev, "too much data, cmd %u, len %u\n", + req->cmd, req->data_len); ret = -EINVAL; goto error; } - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ + /* + * Write receives seq + status = 2 bytes + * Read receives seq + status + data = 2 + N bytes + */ wlen = REQ_HDR_LEN; rlen = ACK_HDR_LEN; if (write) { @@ -96,15 +98,14 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) rlen = 0; - ret = dvb_usbv2_generic_rw_locked(d, - state->buf, wlen, state->buf, rlen); + ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, + state->buf, rlen); if (ret) goto error; /* check status */ if (rlen && state->buf[1]) { - dev_err(&d->udev->dev, "%s: command failed=%d\n", - KBUILD_MODNAME, state->buf[1]); + dev_err(&intf->dev, "cmd failed %u\n", state->buf[1]); ret = -EIO; goto error; } @@ -118,121 +119,66 @@ error: return ret; } -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) + u8 val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); } static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) + u8 *val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); } -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u16 addr; u8 mbox, addr_len; struct req_t req; -/* -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - -................................................ -. AF9015 includes integrated AF9013 demodulator. -. ____________ ____________ . ____________ -.| uC | | demod | . | tuner | -.|------------| |------------| . |------------| -.| AF9015 | | AF9013/5 | . | MXL5003 | -.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | -.| | | | addr 0x38 | . | addr 0xc6 | -.|____________| | |____________| . |____________| -.................|.............................. - | ____________ ____________ - | | demod | | tuner | - | |------------| |------------| - | | AF9013 | | MXL5003 | - +----I2C-------|-----/ -----|-------I2C-------| | - | addr 0x3a | | addr 0xc6 | - |____________| |____________| -*/ + /* + * I2C multiplexing: + * There could be two tuners, both using same I2C address. Demodulator + * I2C-gate is only possibility to select correct tuner. + * + * ........................................... + * . AF9015 integrates AF9013 demodulator . + * . ____________ ____________ . ____________ + * .| USB IF | | demod |. | tuner | + * .|------------| |------------|. |------------| + * .| AF9015 | | AF9013 |. | MXL5003 | + * .| |--+--I2C-----|-----/ -----|.----I2C-----| | + * .| | | | addr 0x1c |. | addr 0x63 | + * .|____________| | |____________|. |____________| + * .................|......................... + * | ____________ ____________ + * | | demod | | tuner | + * | |------------| |------------| + * | | AF9013 | | MXL5003 | + * +--I2C-----|-----/ -----|-----I2C-----| | + * | addr 0x1d | | addr 0x63 | + * |____________| |____________| + */ if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { addr = 0x0000; @@ -243,11 +189,11 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. mbox = 0; addr_len = 1; } else if (msg[0].len == 2) { - addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; mbox = 0; addr_len = 2; } else { - addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; mbox = msg[0].buf[2]; addr_len = 3; } @@ -258,7 +204,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -266,7 +212,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. req.addr = addr; req.mbox = mbox; req.addr_len = addr_len; - req.data_len = msg[0].len-addr_len; + req.data_len = msg[0].len - addr_len; req.data = &msg[0].buf[addr_len]; ret = af9015_ctrl_msg(d, &req); } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && @@ -276,7 +222,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -293,7 +239,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) { + if (msg[0].addr == state->af9013_i2c_addr[0]) { ret = -EINVAL; goto err; } @@ -307,15 +253,14 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = af9015_ctrl_msg(d, &req); } else { ret = -EOPNOTSUPP; - dev_dbg(&d->udev->dev, "%s: unknown msg, num %u\n", - __func__, num); + dev_dbg(&intf->dev, "unknown msg, num %u\n", num); } if (ret) goto err; return num; err: - dev_dbg(&d->udev->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } @@ -331,6 +276,7 @@ static struct i2c_algorithm af9015_i2c_algo = { static int af9015_identify_state(struct dvb_usb_device *d, const char **name) { + struct usb_interface *intf = d->intf; int ret; u8 reply; struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; @@ -339,7 +285,7 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) if (ret) return ret; - dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply); + dev_dbg(&intf->dev, "reply %02x\n", reply); if (reply == 0x02) ret = WARM; @@ -350,52 +296,47 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) } static int af9015_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) + const struct firmware *firmware) { struct af9015_state *state = d_to_priv(d); - int i, len, remaining, ret; + struct usb_interface *intf = d->intf; + int ret, i, rem; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + u16 checksum; - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; + dev_dbg(&intf->dev, "\n"); - state->firmware_size = fw->size; - state->firmware_checksum = checksum; + /* Calc checksum, we need it when copy firmware to slave demod */ + for (i = 0, checksum = 0; i < firmware->size; i++) + checksum += firmware->data[i]; - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; + state->firmware_size = firmware->size; + state->firmware_checksum = checksum; + #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ + for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { + req.data_len = min(LEN_MAX, rem); + req.data = (u8 *)&firmware->data[firmware->size - rem]; + req.addr = 0x5100 + firmware->size - rem; ret = af9015_ctrl_msg(d, &req); if (ret) { - dev_err(&d->udev->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); - goto error; + dev_err(&intf->dev, "firmware download failed %d\n", + ret); + goto err; } } - /* firmware loaded, request boot */ req.cmd = BOOT; req.data_len = 0; ret = af9015_ctrl_msg(d, &req); if (ret) { - dev_err(&d->udev->dev, "%s: firmware boot failed=%d\n", - KBUILD_MODNAME, ret); - goto error; + dev_err(&intf->dev, "firmware boot failed %d\n", ret); + goto err; } -error: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } @@ -407,6 +348,7 @@ error: static int af9015_eeprom_hash(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret, i; u8 buf[AF9015_EEPROM_SIZE]; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL}; @@ -427,24 +369,24 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d) } for (i = 0; i < AF9015_EEPROM_SIZE; i += 16) - dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 16, buf + i); + dev_dbg(&intf->dev, "%*ph\n", 16, buf + i); - dev_dbg(&d->udev->dev, "%s: eeprom sum=%.8x\n", - __func__, state->eeprom_sum); + dev_dbg(&intf->dev, "eeprom sum %.8x\n", state->eeprom_sum); return 0; err: - dev_err(&d->udev->dev, "%s: eeprom failed=%d\n", KBUILD_MODNAME, ret); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } static int af9015_read_config(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u8 val, i, offset = 0; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&intf->dev, "\n"); /* IR remote controller */ req.addr = AF9015_EEPROM_IR_MODE; @@ -462,7 +404,7 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; state->ir_mode = val; - dev_dbg(&d->udev->dev, "%s: IR mode=%d\n", __func__, val); + dev_dbg(&intf->dev, "ir mode %02x\n", val); /* TS mode - one or two receivers */ req.addr = AF9015_EEPROM_TS_MODE; @@ -471,13 +413,9 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; state->dual_mode = val; - dev_dbg(&d->udev->dev, "%s: TS mode=%d\n", __func__, state->dual_mode); + dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode); - /* disable 2nd adapter because we don't have PID-filters */ - if (d->udev->speed == USB_SPEED_FULL) - state->dual_mode = 0; - - state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD; + state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; if (state->dual_mode) { /* read 2nd demodulator I2C address */ @@ -486,7 +424,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[1].i2c_addr = val >> 1; + state->af9013_i2c_addr[1] = val >> 1; } for (i = 0; i < state->dual_mode + 1; i++) { @@ -499,21 +437,20 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; switch (val) { case 0: - state->af9013_config[i].clock = 28800000; + state->af9013_pdata[i].clk = 28800000; break; case 1: - state->af9013_config[i].clock = 20480000; + state->af9013_pdata[i].clk = 20480000; break; case 2: - state->af9013_config[i].clock = 28000000; + state->af9013_pdata[i].clk = 28000000; break; case 3: - state->af9013_config[i].clock = 25000000; + state->af9013_pdata[i].clk = 25000000; break; } - dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n", - __func__, i, val, - state->af9013_config[i].clock); + dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n", + i, val, state->af9013_pdata[i].clk); /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; @@ -521,17 +458,17 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[i].if_frequency = val << 8; + state->af9013_pdata[i].if_frequency = val << 8; req.addr = AF9015_EEPROM_IF1L + offset; ret = af9015_ctrl_msg(d, &req); if (ret) goto error; - state->af9013_config[i].if_frequency += val; - state->af9013_config[i].if_frequency *= 1000; - dev_dbg(&d->udev->dev, "%s: [%d] IF frequency=%d\n", __func__, - i, state->af9013_config[i].if_frequency); + state->af9013_pdata[i].if_frequency += val; + state->af9013_pdata[i].if_frequency *= 1000; + dev_dbg(&intf->dev, "[%d] if frequency %u\n", + i, state->af9013_pdata[i].if_frequency); /* MT2060 IF1 */ req.addr = AF9015_EEPROM_MT2060_IF1H + offset; @@ -544,8 +481,8 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; state->mt2060_if1[i] += val; - dev_dbg(&d->udev->dev, "%s: [%d] MT2060 IF1=%d\n", __func__, i, - state->mt2060_if1[i]); + dev_dbg(&intf->dev, "[%d] MT2060 IF1 %u\n", + i, state->mt2060_if1[i]); /* tuner */ req.addr = AF9015_EEPROM_TUNER_ID1 + offset; @@ -561,71 +498,177 @@ static int af9015_read_config(struct dvb_usb_device *d) case AF9013_TUNER_TDA18271: case AF9013_TUNER_QT1010A: case AF9013_TUNER_TDA18218: - state->af9013_config[i].spec_inv = 1; + state->af9013_pdata[i].spec_inv = 1; break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - state->af9013_config[i].spec_inv = 0; + state->af9013_pdata[i].spec_inv = 0; break; case AF9013_TUNER_MC44S803: - state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; - state->af9013_config[i].spec_inv = 1; + state->af9013_pdata[i].gpio[1] = AF9013_GPIO_LO; + state->af9013_pdata[i].spec_inv = 1; break; default: - dev_err(&d->udev->dev, "%s: tuner id=%d not " \ - "supported, please report!\n", - KBUILD_MODNAME, val); + dev_err(&intf->dev, + "tuner id %02x not supported, please report!\n", + val); return -ENODEV; } - state->af9013_config[i].tuner = val; - dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n", - __func__, i, val); + state->af9013_pdata[i].tuner = val; + dev_dbg(&intf->dev, "[%d] tuner id %02x\n", i, val); } error: if (ret) - dev_err(&d->udev->dev, "%s: eeprom read failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "eeprom read failed %d\n", ret); - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ + /* + * AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + * content :-( Override some wrong values here. Ditto for the + * AVerTV Red HD+ (A850T) device. + */ if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { - dev_dbg(&d->udev->dev, - "%s: AverMedia A850: overriding config\n", - __func__); + ((le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) { + dev_dbg(&intf->dev, "AverMedia A850: overriding config\n"); /* disable dual mode */ state->dual_mode = 0; /* set correct IF */ - state->af9013_config[0].if_frequency = 4570000; + state->af9013_pdata[0].if_frequency = 4570000; } return ret; } static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) + struct usb_data_stream_properties *stream) { struct dvb_usb_device *d = fe_to_d(fe); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id); + struct usb_interface *intf = d->intf; + + dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id); if (d->udev->speed == USB_SPEED_FULL) - stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + stream->u.bulk.buffersize = 5 * 188; + + return 0; +} + +static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int utmp1, utmp2, reg1, reg2; + u8 buf[2]; + const unsigned int adap_id = fe_to_adap(fe)->id; + + dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff); + + if (!state->usb_ts_if_configured[adap_id]) { + dev_dbg(&intf->dev, "set usb and ts interface\n"); + + /* USB IF stream settings */ + utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; + utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; + + buf[0] = (utmp1 >> 0) & 0xff; + buf[1] = (utmp1 >> 8) & 0xff; + if (adap_id == 0) { + /* 1st USB IF (EP4) stream settings */ + reg1 = 0xdd88; + reg2 = 0xdd0c; + } else { + /* 2nd USB IF (EP5) stream settings */ + reg1 = 0xdd8a; + reg2 = 0xdd0d; + } + ret = regmap_bulk_write(state->regmap, reg1, buf, 2); + if (ret) + goto err; + ret = regmap_write(state->regmap, reg2, utmp2); + if (ret) + goto err; + + /* TS IF settings */ + if (state->dual_mode) { + utmp1 = 0x01; + utmp2 = 0x10; + } else { + utmp1 = 0x00; + utmp2 = 0x00; + } + ret = regmap_update_bits(state->regmap, 0xd50b, 0x01, utmp1); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xd520, 0x10, utmp2); + if (ret) + goto err; + + state->usb_ts_if_configured[adap_id] = true; + } + + if (adap_id == 0 && onoff) { + /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ + ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x00); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x20); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x00); + if (ret) + goto err; + } else if (adap_id == 1 && onoff) { + /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ + ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x00); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x40); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x00); + if (ret) + goto err; + } else if (adap_id == 0 && !onoff) { + /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ + ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x04); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x00); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x20); + if (ret) + goto err; + } else if (adap_id == 1 && !onoff) { + /* Adapter 1 stream off. EP5: set reset, disable, set NAK */ + ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x02); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x00); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x40); + if (ret) + goto err; + } return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; } static int af9015_get_adapter_count(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + return state->dual_mode + 1; } @@ -647,7 +690,7 @@ static int af9015_af9013_set_frontend(struct dvb_frontend *fe) /* override demod callbacks for resource locking */ static int af9015_af9013_read_status(struct dvb_frontend *fe, - enum fe_status *status) + enum fe_status *status) { int ret; struct af9015_state *state = fe_to_priv(fe); @@ -729,102 +772,105 @@ static int af9015_tuner_sleep(struct dvb_frontend *fe) static int af9015_copy_firmware(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - fw_params[0] = state->firmware_size >> 8; - fw_params[1] = state->firmware_size & 0xff; - fw_params[2] = state->firmware_checksum >> 8; - fw_params[3] = state->firmware_checksum & 0xff; - - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - if (ret) - goto error; - else - dev_dbg(&d->udev->dev, "%s: firmware status=%02x\n", - __func__, val); + unsigned long timeout; + u8 val, firmware_info[4]; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info}; - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; + dev_dbg(&intf->dev, "\n"); - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + firmware_info[0] = (state->firmware_size >> 8) & 0xff; + firmware_info[1] = (state->firmware_size >> 0) & 0xff; + firmware_info[2] = (state->firmware_checksum >> 8) & 0xff; + firmware_info[3] = (state->firmware_checksum >> 0) & 0xff; + + /* Check whether firmware is already running */ + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); if (ret) - goto error; + goto err; - msleep(50); + dev_dbg(&intf->dev, "firmware status %02x\n", val); - /* copy firmware */ - ret = af9015_ctrl_msg(d, &req); + if (val == 0x0c) + return 0; + + /* Set i2c clock to 625kHz to speed up firmware copy */ + ret = regmap_write(state->regmap, 0xd416, 0x04); if (ret) - dev_err(&d->udev->dev, "%s: firmware copy cmd failed=%d\n", - KBUILD_MODNAME, ret); + goto err; - dev_dbg(&d->udev->dev, "%s: firmware copy done\n", __func__); + /* Copy firmware from master demod to slave demod */ + ret = af9015_ctrl_msg(d, &req); + if (ret) { + dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret); + goto err; + } - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + /* Set i2c clock to 125kHz */ + ret = regmap_write(state->regmap, 0xd416, 0x14); if (ret) - goto error; + goto err; - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0xe205, 1); - dev_dbg(&d->udev->dev, "%s: firmware boot cmd status=%d\n", - __func__, ret); + /* Boot firmware */ + ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 0x01); if (ret) - goto error; + goto err; - for (i = 0; i < 15; i++) { - msleep(100); + /* Poll firmware ready */ + for (val = 0x00, timeout = jiffies + msecs_to_jiffies(1000); + !time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) { + msleep(20); - /* check firmware status */ - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - dev_dbg(&d->udev->dev, "%s: firmware status cmd status=%d " \ - "firmware status=%02x\n", __func__, ret, val); + /* Check firmware status. 0c=OK, 04=fail */ + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], + 0x98be, &val); if (ret) - goto error; + goto err; - if (val == 0x0c || val == 0x04) /* success or fail */ - break; + dev_dbg(&intf->dev, "firmware status %02x\n", val); } + dev_dbg(&intf->dev, "firmware boot took %u ms\n", + jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000)); + if (val == 0x04) { - dev_err(&d->udev->dev, "%s: firmware did not run\n", - KBUILD_MODNAME); - ret = -ETIMEDOUT; + ret = -ENODEV; + dev_err(&intf->dev, "firmware did not run\n"); + goto err; } else if (val != 0x0c) { - dev_err(&d->udev->dev, "%s: firmware boot timeout\n", - KBUILD_MODNAME); ret = -ETIMEDOUT; + dev_err(&intf->dev, "firmware boot timeout\n"); + goto err; } -error: -exit: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { - int ret; struct af9015_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; + struct i2c_client *client; + int ret; + + dev_dbg(&intf->dev, "adap id %u\n", adap->id); if (adap->id == 0) { - state->af9013_config[0].ts_mode = AF9013_TS_USB; - memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; - state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; + state->af9013_pdata[0].ts_mode = AF9013_TS_MODE_USB; + memcpy(state->af9013_pdata[0].api_version, "\x0\x1\x9\x0", 4); + state->af9013_pdata[0].gpio[0] = AF9013_GPIO_HI; + state->af9013_pdata[0].gpio[3] = AF9013_GPIO_TUNER_ON; } else if (adap->id == 1) { - state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; - memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; - state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; + state->af9013_pdata[1].ts_mode = AF9013_TS_MODE_SERIAL; + state->af9013_pdata[1].ts_output_pin = 7; + memcpy(state->af9013_pdata[1].api_version, "\x0\x1\x9\x0", 4); + state->af9013_pdata[1].gpio[0] = AF9013_GPIO_TUNER_ON; + state->af9013_pdata[1].gpio[1] = AF9013_GPIO_LO; /* copy firmware to 2nd demodulator */ if (state->dual_mode) { @@ -833,21 +879,27 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) ret = af9015_copy_firmware(adap_to_d(adap)); if (ret) { - dev_err(&adap_to_d(adap)->udev->dev, - "%s: firmware copy to 2nd " \ - "frontend failed, will " \ - "disable it\n", KBUILD_MODNAME); + dev_err(&intf->dev, + "firmware copy to 2nd frontend failed, will disable it\n"); state->dual_mode = 0; - return -ENODEV; + goto err; } } else { - return -ENODEV; + ret = -ENODEV; + goto err; } } - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9013_attach, - &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); + /* Add I2C demod */ + client = dvb_module_probe("af9013", NULL, &d->i2c_adap, + state->af9013_i2c_addr[adap->id], + &state->af9013_pdata[adap->id]); + if (!client) { + ret = -ENODEV; + goto err; + } + adap->fe[0] = state->af9013_pdata[adap->id].get_dvb_frontend(client); + state->demod_i2c_client[adap->id] = client; /* * AF9015 firmware does not like if it gets interrupted by I2C adapter @@ -857,24 +909,36 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) * those "critical" paths to keep AF9015 happy. */ if (adap->fe[0]) { - state->set_frontend[adap->id] = - adap->fe[0]->ops.set_frontend; - adap->fe[0]->ops.set_frontend = - af9015_af9013_set_frontend; - - state->read_status[adap->id] = - adap->fe[0]->ops.read_status; - adap->fe[0]->ops.read_status = - af9015_af9013_read_status; - + state->set_frontend[adap->id] = adap->fe[0]->ops.set_frontend; + adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend; + state->read_status[adap->id] = adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = af9015_af9013_read_status; state->init[adap->id] = adap->fe[0]->ops.init; adap->fe[0]->ops.init = af9015_af9013_init; - state->sleep[adap->id] = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = af9015_af9013_sleep; } - return adap->fe[0] == NULL ? -ENODEV : 0; + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_frontend_detach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; + struct i2c_client *client; + + dev_dbg(&intf->dev, "adap id %u\n", adap->id); + + /* Remove I2C demod */ + client = state->demod_i2c_client[adap->id]; + dvb_module_release(client); + + return 0; } static struct mt2060_config af9015_mt2060_config = { @@ -944,64 +1008,61 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + struct i2c_client *client; + struct i2c_adapter *adapter; int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - switch (state->af9013_config[adap->id].tuner) { + dev_dbg(&intf->dev, "adap id %u\n", adap->id); + + client = state->demod_i2c_client[adap->id]; + adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client); + + switch (state->af9013_pdata[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, - state->mt2060_if1[adap->id]) - == NULL ? -ENODEV : 0; + ret = dvb_attach(mt2060_attach, adap->fe[0], adapter, + &af9015_mt2060_config, + state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_qt1010_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(qt1010_attach, adap->fe[0], adapter, + &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, - &adap_to_d(adap)->i2c_adap, - &af9015_tda18271_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter, + &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_tda18218_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(tda18218_attach, adap->fe[0], adapter, + &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, - &adap_to_d(adap)->i2c_adap, - DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter, + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mc44s803_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter, + &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter, + 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: default: - dev_err(&d->udev->dev, "%s: unknown tuner id=%d\n", - KBUILD_MODNAME, - state->af9013_config[adap->id].tuner); + dev_err(&intf->dev, "unknown tuner, tuner id %02x\n", + state->af9013_pdata[adap->id].tuner); ret = -ENODEV; } @@ -1022,136 +1083,27 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - if (onoff) - ret = af9015_set_reg_bit(d, 0xd503, 0); - else - ret = af9015_clear_reg_bit(d, 0xd503, 0); - - return ret; -} - -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - u8 idx; - dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); - - ret = af9015_write_reg(d, 0xd505, (pid & 0xff)); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(d, 0xd504, idx); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter_ctrl(adap->fe[0], onoff); + mutex_unlock(&state->fe_mutex); -error: return ret; } -static int af9015_init_endpoint(struct dvb_usb_device *d) +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) { - struct af9015_state *state = d_to_priv(d); + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - u16 frame_size; - u8 packet_size; - dev_dbg(&d->udev->dev, "%s: USB speed=%d\n", __func__, d->udev->speed); - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - /* enable / disable mp2if2 */ - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xd50b, 0); - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd520, 4); - if (ret) - goto error; - } else { - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd520, 4); - if (ret) - goto error; - } - -error: - if (ret) - dev_err(&d->udev->dev, "%s: endpoint init failed=%d\n", - KBUILD_MODNAME, ret); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter(adap->fe[0], index, pid, onoff); + mutex_unlock(&state->fe_mutex); return ret; } @@ -1159,17 +1111,15 @@ error: static int af9015_init(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); mutex_init(&state->fe_mutex); /* init RC canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - ret = af9015_init_endpoint(d); + ret = regmap_write(state->regmap, 0x98e9, 0xff); if (ret) goto error; @@ -1184,7 +1134,7 @@ struct af9015_rc_setup { }; static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) + const struct af9015_rc_setup *table) { for (; table->rc_codes; table++) if (table->id == id) @@ -1212,24 +1162,25 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { static int af9015_rc_query(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u8 buf[17]; /* read registers needed to detect remote controller code */ - ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + ret = regmap_bulk_read(state->regmap, 0x98d9, buf, sizeof(buf)); if (ret) goto error; /* If any of these are non-zero, assume invalid data */ if (buf[1] || buf[2] || buf[3]) { - dev_dbg(&d->udev->dev, "%s: invalid data\n", __func__); + dev_dbg(&intf->dev, "invalid data\n"); return ret; } /* Check for repeat of previous code */ if ((state->rc_repeat != buf[6] || buf[0]) && - !memcmp(&buf[12], state->rc_last, 4)) { - dev_dbg(&d->udev->dev, "%s: key repeated\n", __func__); + !memcmp(&buf[12], state->rc_last, 4)) { + dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; return ret; @@ -1238,18 +1189,18 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Only process key if canary killed */ if (buf[16] != 0xff && buf[0] != 0x01) { enum rc_proto proto; - dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n", - __func__, 4, buf + 12); + + dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12); /* Reset the canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); + ret = regmap_write(state->regmap, 0x98e9, 0xff); if (ret) goto error; /* Remember this key */ memcpy(state->rc_last, &buf[12], 4); - if (buf[14] == (u8) ~buf[15]) { - if (buf[12] == (u8) ~buf[13]) { + if (buf[14] == (u8)~buf[15]) { + if (buf[12] == (u8)~buf[13]) { /* NEC */ state->rc_keycode = RC_SCANCODE_NEC(buf[12], buf[14]); @@ -1271,7 +1222,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) } rc_keydown(d->rc_dev, proto, state->rc_keycode, 0); } else { - dev_dbg(&d->udev->dev, "%s: no key press\n", __func__); + dev_dbg(&intf->dev, "no key press\n"); /* Invalidate last keypress */ /* Not really needed, but helps with debug */ state->rc_last[2] = state->rc_last[3]; @@ -1282,8 +1233,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) error: if (ret) { - dev_warn(&d->udev->dev, "%s: rc query failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&intf->dev, "rc query failed %d\n", ret); /* allow random errors as dvb-usb will stop polling on error */ if (!state->rc_failed) @@ -1306,29 +1256,33 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) /* try to load remote based module param */ if (!rc->map_name) rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, - af9015_rc_setup_modparam); + af9015_rc_setup_modparam); /* try to load remote based eeprom hash */ if (!rc->map_name) rc->map_name = af9015_rc_setup_match(state->eeprom_sum, - af9015_rc_setup_hashes); + af9015_rc_setup_hashes); /* try to load remote based USB iManufacturer string */ if (!rc->map_name && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + /* + * Check USB manufacturer and product strings and try + * to determine correct remote in case of chip vendor + * reference IDs are used. + * DO NOT ADD ANYTHING NEW HERE. Use hashes instead. + */ char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); usb_string(d->udev, d->udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); + manufacturer, sizeof(manufacturer)); if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - rc->map_name = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); + /* + * iManufacturer 1 MSI + * iProduct 2 MSI K-VOX + */ + rc->map_name = af9015_rc_setup_match(AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); } } @@ -1347,15 +1301,68 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) #define af9015_get_rc_config NULL #endif -static int af9015_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int af9015_regmap_write(void *context, const void *data, size_t count) { + struct dvb_usb_device *d = context; + struct usb_interface *intf = d->intf; + int ret; + u16 reg = ((u8 *)data)[0] << 8 | ((u8 *)data)[1] << 0; + u8 *val = &((u8 *)data)[2]; + const unsigned int len = count - 2; + struct req_t req = {WRITE_MEMORY, 0, reg, 0, 0, len, val}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct dvb_usb_device *d = context; + struct usb_interface *intf = d->intf; + int ret; + u16 reg = ((u8 *)reg_buf)[0] << 8 | ((u8 *)reg_buf)[1] << 0; + u8 *val = &((u8 *)val_buf)[0]; + const unsigned int len = val_size; + struct req_t req = {READ_MEMORY, 0, reg, 0, 0, len, val}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_probe(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; struct usb_device *udev = interface_to_usbdev(intf); + int ret; char manufacturer[sizeof("ITE Technologies, Inc.")]; + static const struct regmap_config regmap_config = { + .reg_bits = 16, + .val_bits = 8, + }; + static const struct regmap_bus regmap_bus = { + .read = af9015_regmap_read, + .write = af9015_regmap_write, + }; + + dev_dbg(&intf->dev, "\n"); memset(manufacturer, 0, sizeof(manufacturer)); usb_string(udev, udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); + manufacturer, sizeof(manufacturer)); /* * There is two devices having same ID but different chipset. One uses * AF9015 and the other IT9135 chipset. Only difference seen on lsusb @@ -1374,19 +1381,41 @@ static int af9015_probe(struct usb_interface *intf, * iProduct 2 DVB-T TV Stick */ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && - (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { + (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { if (!strcmp("ITE Technologies, Inc.", manufacturer)) { - dev_dbg(&udev->dev, "%s: rejecting device\n", __func__); - return -ENODEV; + ret = -ENODEV; + dev_dbg(&intf->dev, "rejecting device\n"); + goto err; } } - return dvb_usbv2_probe(intf, id); + state->regmap = regmap_init(&intf->dev, ®map_bus, d, ®map_config); + if (IS_ERR(state->regmap)) { + ret = PTR_ERR(state->regmap); + goto err; + } + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; } -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ -static struct dvb_usb_device_properties af9015_props = { +static void af9015_disconnect(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + + dev_dbg(&intf->dev, "\n"); + + regmap_exit(state->regmap); +} + +/* + * Interface 0 is used by DVB-T receiver and + * interface 1 is for remote controller (HID) + */ +static const struct dvb_usb_device_properties af9015_props = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, .adapter_nr = adapter_nr, @@ -1395,6 +1424,8 @@ static struct dvb_usb_device_properties af9015_props = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = af9015_probe, + .disconnect = af9015_disconnect, .identify_state = af9015_identify_state, .firmware = AF9015_FIRMWARE, .download_firmware = af9015_download_firmware, @@ -1402,10 +1433,12 @@ static struct dvb_usb_device_properties af9015_props = { .i2c_algo = &af9015_i2c_algo, .read_config = af9015_read_config, .frontend_attach = af9015_af9013_frontend_attach, + .frontend_detach = af9015_frontend_detach, .tuner_attach = af9015_tuner_attach, .init = af9015_init, .get_rc_config = af9015_get_rc_config, .get_stream_config = af9015_get_stream_config, + .streaming_ctrl = af9015_streaming_ctrl, .get_adapter_count = af9015_get_adapter_count, .adapter = { @@ -1416,9 +1449,15 @@ static struct dvb_usb_device_properties af9015_props = { .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, - .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), }, { - .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), }, }, }; @@ -1509,7 +1548,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table); static struct usb_driver af9015_usb_driver = { .name = KBUILD_MODNAME, .id_table = af9015_id_table, - .probe = af9015_probe, + .probe = dvb_usbv2_probe, .disconnect = dvb_usbv2_disconnect, .suspend = dvb_usbv2_suspend, .resume = dvb_usbv2_resume, diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 3a9d9815ab7a..ad2b045cc39c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -21,6 +21,7 @@ #define AF9015_H #include <linux/hash.h> +#include <linux/regmap.h> #include "dvb_usb.h" #include "af9013.h" #include "dvb-pll.h" @@ -34,19 +35,6 @@ #define AF9015_FIRMWARE "dvb-usb-af9015.fw" -/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - #define AF9015_I2C_EEPROM 0x50 #define AF9015_I2C_DEMOD 0x1c #define AF9015_USB_TIMEOUT 2000 @@ -113,6 +101,7 @@ enum af9015_ir_mode { #define BUF_LEN 63 struct af9015_state { + struct regmap *regmap; u8 buf[BUF_LEN]; /* bulk USB control message */ u8 ir_mode; u8 rc_repeat; @@ -125,7 +114,10 @@ struct af9015_state { u16 firmware_size; u16 firmware_checksum; u32 eeprom_sum; - struct af9013_config af9013_config[2]; + struct af9013_platform_data af9013_pdata[2]; + struct i2c_client *demod_i2c_client[2]; + u8 af9013_i2c_addr[2]; + bool usb_ts_if_configured[2]; /* for demod callback override */ int (*set_frontend[2]) (struct dvb_frontend *fe); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index d2e80537b2f7..3fd6cc0d6340 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -203,6 +203,8 @@ struct dvb_usb_adapter_properties { * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for * receive * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @probe: like probe on driver model + * @disconnect: like disconnect on driver model * @identify_state: called to determine the firmware state (cold or warm) and * return possible firmware file name to be loaded * @firmware: name of the firmware file to be loaded @@ -239,6 +241,8 @@ struct dvb_usb_device_properties { u8 generic_bulk_ctrl_endpoint_response; unsigned int generic_bulk_ctrl_delay; + int (*probe)(struct dvb_usb_device *); + void (*disconnect)(struct dvb_usb_device *); #define WARM 0 #define COLD 1 int (*identify_state) (struct dvb_usb_device *, const char **); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 2bf3bd81280a..afdcdbf005e9 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -854,8 +854,6 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) dvb_usbv2_remote_exit(d); dvb_usbv2_adapter_exit(d); dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); return 0; } @@ -934,7 +932,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, if (intf->cur_altsetting->desc.bInterfaceNumber != d->props->bInterfaceNumber) { ret = -ENODEV; - goto err_free_all; + goto err_kfree_d; } mutex_init(&d->usb_mutex); @@ -946,10 +944,16 @@ int dvb_usbv2_probe(struct usb_interface *intf, dev_err(&d->udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; - goto err_free_all; + goto err_kfree_d; } } + if (d->props->probe) { + ret = d->props->probe(d); + if (ret) + goto err_kfree_priv; + } + if (d->props->identify_state) { const char *name = NULL; ret = d->props->identify_state(d, &name); @@ -1001,6 +1005,12 @@ exit: return 0; err_free_all: dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); +err_kfree_priv: + kfree(d->priv); +err_kfree_d: + kfree(d); err: dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); return ret; @@ -1021,6 +1031,12 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); + + kfree(d->priv); + kfree(d); + pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, drvname, devname); kfree(devname); diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 2abd15c6df81..387a074ea6ec 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1243,82 +1243,6 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) return 0; } -static int cxusb_mygica_t230c_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - struct cxusb_state *st = d->priv; - struct i2c_adapter *adapter; - struct i2c_client *client_demod; - struct i2c_client *client_tuner; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - - /* attach frontend */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &adap->fe_adap[0].fe; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - si2168_config.ts_clock_inv = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client_demod = i2c_new_device(&d->i2c_adap, &info); - if (client_demod == NULL || client_demod->dev.driver == NULL) - return -ENODEV; - - if (!try_module_get(client_demod->dev.driver->owner)) { - i2c_unregister_device(client_demod); - return -ENODEV; - } - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = adap->fe_adap[0].fe; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2141", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || client_tuner->dev.driver == NULL) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - if (!try_module_get(client_tuner->dev.driver->owner)) { - i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - - st->i2c_client_demod = client_demod; - st->i2c_client_tuner = client_tuner; - - /* hook fe: need to resync the slave fifo when signal locks. */ - mutex_init(&st->stream_mutex); - st->last_lock = 0; - st->fe_read_status = adap->fe_adap[0].fe->ops.read_status; - adap->fe_adap[0].fe->ops.read_status = cxusb_read_status; - - return 0; -} - /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -1401,7 +1325,6 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties; static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; static struct dvb_usb_device_properties cxusb_mygica_t230_properties; -static struct dvb_usb_device_properties cxusb_mygica_t230c_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1434,8 +1357,6 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230c_properties, - THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -1487,7 +1408,6 @@ enum cxusb_table_index { CONEXANT_D680_DMB, MYGICA_D689, MYGICA_T230, - MYGICA_T230C, NR__cxusb_table_index }; @@ -1555,9 +1475,6 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { [MYGICA_T230] = { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) }, - [MYGICA_T230C] = { - USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230+1) - }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -2143,7 +2060,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { .rc.core = { .rc_interval = 100, - .rc_codes = RC_MAP_D680_DMB, + .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, .allowed_protos = RC_PROTO_BIT_UNKNOWN, @@ -2252,7 +2169,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { .rc.core = { .rc_interval = 100, - .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, + .rc_codes = RC_MAP_D680_DMB, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, .allowed_protos = RC_PROTO_BIT_UNKNOWN, @@ -2268,60 +2185,6 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { } }; -static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mygica_t230c_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - } }, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.core = { - .rc_interval = 100, - .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, - .module_name = KBUILD_MODNAME, - .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_PROTO_BIT_UNKNOWN, - }, - - .num_device_descs = 1, - .devices = { - { - "Mygica T230C DVB-T/T2/C", - { NULL }, - { &cxusb_table[MYGICA_T230C], NULL }, - }, - } -}; - static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 3d99e141d566..c53a969bc6be 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -3412,7 +3412,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) static struct s5h1411_config pinnacle_801e_config = { .output_mode = S5H1411_PARALLEL_OUTPUT, .gpio = S5H1411_GPIO_OFF, - .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK, .qam_if = S5H1411_IF_44000, .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 4628d73f46f2..8e799ae1df69 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -1,25 +1,25 @@ -/* - * Empiatech em28x1 audio extension - * - * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> - * - * Copyright (C) 2007-2016 Mauro Carvalho Chehab - * - Port to work with the in-kernel driver - * - Cleanups, fixes, alsa-controls, etc. - * - * This driver is based on my previous au600 usb pstn audio driver - * and inherits all the copyrights - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Empiatech em28x1 audio extension +// +// Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> +// +// Copyright (C) 2007-2016 Mauro Carvalho Chehab +// - Port to work with the in-kernel driver +// - Cleanups, fixes, alsa-controls, etc. +// +// This driver is based on my previous au600 usb pstn audio driver +// and inherits all the copyrights +// +// 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 "em28xx.h" @@ -103,7 +103,7 @@ static void em28xx_audio_isocirq(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dprintk("urb completition error %d.\n", urb->status); + dprintk("urb completion error %d.\n", urb->status); break; } @@ -165,12 +165,11 @@ static void em28xx_audio_isocirq(struct urb *urb) dev_err(&dev->intf->dev, "resubmit of audio urb failed (error=%i)\n", status); - return; } static int em28xx_init_audio_isoc(struct em28xx *dev) { - int i, errCode; + int i, err; dprintk("Starting isoc transfers\n"); @@ -179,16 +178,15 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) memset(dev->adev.transfer_buffer[i], 0x80, dev->adev.urb[i]->transfer_buffer_length); - errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); - if (errCode) { + err = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); + if (err) { dev_err(&dev->intf->dev, "submit of audio urb failed (error=%i)\n", - errCode); + err); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); - return errCode; + return err; } - } return 0; @@ -268,14 +266,17 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } runtime->hw = snd_em28xx_hw_capture; if (dev->adev.users == 0) { - if (dev->alt == 0 || dev->is_audio_only) { - struct usb_device *udev = interface_to_usbdev(dev->intf); + if (!dev->alt || dev->is_audio_only) { + struct usb_device *udev; + + udev = interface_to_usbdev(dev->intf); if (dev->is_audio_only) /* audio is on a separate interface */ @@ -367,9 +368,11 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; #if 0 - /* TODO: set up em28xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ + /* + * TODO: set up em28xx audio chip to deliver the correct audio format, + * current default is 48000hz multiplexed => 96000hz mono + * which shouldn't matter since analogue TV only supports mono + */ unsigned int channels, rate, format; format = params_format(hw_params); @@ -513,8 +516,9 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -551,8 +555,9 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -586,8 +591,9 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -627,8 +633,9 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -762,7 +769,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (intf->num_altsetting <= alt) { dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n", - dev->ifnum, alt); + dev->ifnum, alt); return -ENODEV; } @@ -836,9 +843,8 @@ static int em28xx_audio_urb_init(struct em28xx *dev) dev->adev.transfer_buffer = kcalloc(num_urb, sizeof(*dev->adev.transfer_buffer), GFP_ATOMIC); - if (!dev->adev.transfer_buffer) { + if (!dev->adev.transfer_buffer) return -ENOMEM; - } dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC); if (!dev->adev.urb) { @@ -899,9 +905,11 @@ static int em28xx_audio_init(struct em28xx *dev) int err; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ + /* + * This device does not support the extension (in this case + * the device is expecting the snd-usb-audio module or + * doesn't have analog audio support at all) + */ return 0; } @@ -977,13 +985,15 @@ card_free: static int em28xx_audio_fini(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ + /* + * This device does not support the extension (in this case + * the device is expecting the snd-usb-audio module or + * doesn't have analog audio support at all) + */ return 0; } @@ -1005,7 +1015,7 @@ static int em28xx_audio_fini(struct em28xx *dev) static int em28xx_audio_suspend(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) @@ -1019,7 +1029,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) static int em28xx_audio_resume(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) @@ -1050,7 +1060,7 @@ static void __exit em28xx_alsa_unregister(void) em28xx_unregister_extension(&audio_ops); } -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index ae87dd3e671f..3c2694a16ed1 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -1,23 +1,19 @@ -/* - em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices - - Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org> - Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices +// +// Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org> +// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// 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 "em28xx.h" @@ -49,7 +45,7 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev) { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ { 0x0d, 0x00, 0x00, }, { 0x0a, 0x00, 0x21, }, - { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ + { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */ }; for (i = 0; i < ARRAY_SIZE(regs); i++) @@ -157,7 +153,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) break; default: dev_info(&dev->intf->dev, - "unknown Micron sensor detected: 0x%04x\n", id); + "unknown Micron sensor detected: 0x%04x\n", + id); return 0; } @@ -186,8 +183,10 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; dev->em28xx_sensor = EM28XX_NOSENSOR; - /* NOTE: these devices have the register auto incrementation disabled - * by default, so we have to use single byte reads ! */ + /* + * NOTE: these devices have the register auto incrementation disabled + * by default, so we have to use single byte reads ! + */ for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { client->addr = omnivision_sensor_addrs[i]; /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ @@ -397,7 +396,7 @@ int em28xx_init_camera(struct em28xx *dev) subdev = v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &ov2640_info, NULL); - if (subdev == NULL) + if (!subdev) return -ENODEV; format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 34e16f6ab4ac..6e0e67d23876 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1,27 +1,23 @@ -/* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB +// video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> +// Markus Rechberger <mrechberger@gmail.com> +// Mauro Carvalho Chehab <mchehab@infradead.org> +// Sascha Sommer <saschasommer@freenet.de> +// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// 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 "em28xx.h" @@ -40,7 +36,6 @@ #include <media/v4l2-common.h> #include <sound/ac97_codec.h> - #define DRIVER_NAME "em28xx" static int tuner = -1; @@ -81,26 +76,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev); */ /* Reset for the most [analog] boards */ -static struct em28xx_reg_seq default_analog[] = { +static const struct em28xx_reg_seq default_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; /* Reset for the most [digital] boards */ -static struct em28xx_reg_seq default_digital[] = { +static const struct em28xx_reg_seq default_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 analog */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { {EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10}, { 0x05, 0xff, 0x10, 10}, { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x04, 0x0f, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, @@ -108,25 +103,20 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { }; /* Board Hauppauge WinTV HVR 900 (R2) digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, { -1, -1, -1, -1}, }; /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { +static const struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ - -/* Board - EM2870 Kworld 355u - Analog - No input analog */ - /* Board - EM2882 Kworld 315U digital */ -static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { +static const struct em28xx_reg_seq em2882_kworld_315u_digital[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, {EM2880_R04_GPO, 0x04, 0xff, 10}, @@ -135,7 +125,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { +static const struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { {EM2880_R04_GPO, 0x08, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, @@ -143,30 +133,31 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_330u_analog[] = { +static const struct em28xx_reg_seq kworld_330u_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_330u_digital[] = { +static const struct em28xx_reg_seq kworld_330u_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, }; -/* Evga inDtube - GPIO0 - Enable digital power (s5h1409) - low to enable - GPIO1 - Enable analog power (tvp5150/emp202) - low to enable - GPIO4 - xc3028 reset - GOP3 - s5h1409 reset +/* + * Evga inDtube + * GPIO0 - Enable digital power (s5h1409) - low to enable + * GPIO1 - Enable analog power (tvp5150/emp202) - low to enable + * GPIO4 - xc3028 reset + * GOP3 - s5h1409 reset */ -static struct em28xx_reg_seq evga_indtube_analog[] = { +static const struct em28xx_reg_seq evga_indtube_analog[] = { {EM2820_R08_GPIO_CTRL, 0x79, 0xff, 60}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq evga_indtube_digital[] = { +static const struct em28xx_reg_seq evga_indtube_digital[] = { {EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1}, {EM2880_R04_GPO, 0x04, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 1}, @@ -184,12 +175,12 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { * EM_GPIO_6 - currently unknown * EM_GPIO_7 - currently unknown */ -static struct em28xx_reg_seq kworld_a340_digital[] = { +static const struct em28xx_reg_seq kworld_a340_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { +static const struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100}, @@ -198,45 +189,49 @@ static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { }; /* Pinnacle Hybrid Pro eb1a:2881 */ -static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { +static const struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { {EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { +static const struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */ {EM2880_R04_GPO, 0x0c, 0xff, 1}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { +static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { +static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, }; -/* PCTV HD Mini (80e) GPIOs - 0-5: not used - 6: demod reset, active low - 7: LED on, active high */ -static struct em28xx_reg_seq em2874_pctv_80e_digital[] = { +/* + * PCTV HD Mini (80e) GPIOs + * 0-5: not used + * 6: demod reset, active low + * 7: LED on, active high + */ +static const struct em28xx_reg_seq em2874_pctv_80e_digital[] = { {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10}, { -1, -1, -1, -1}, }; -/* eb1a:2868 Reddo DVB-C USB TV Box - GPIO4 - CU1216L NIM - Other GPIOs seems to be don't care. */ -static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { +/* + * eb1a:2868 Reddo DVB-C USB TV Box + * GPIO4 - CU1216L NIM + * Other GPIOs seems to be don't care. + */ +static const struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xde, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, @@ -248,7 +243,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { }; /* Callback for the most boards */ -static struct em28xx_reg_seq default_tuner_gpio[] = { +static const struct em28xx_reg_seq default_tuner_gpio[] = { {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, @@ -256,69 +251,70 @@ static struct em28xx_reg_seq default_tuner_gpio[] = { }; /* Mute/unmute */ -static struct em28xx_reg_seq compro_unmute_tv_gpio[] = { +static const struct em28xx_reg_seq compro_unmute_tv_gpio[] = { {EM2820_R08_GPIO_CTRL, 5, 7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq compro_unmute_svid_gpio[] = { +static const struct em28xx_reg_seq compro_unmute_svid_gpio[] = { {EM2820_R08_GPIO_CTRL, 4, 7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq compro_mute_gpio[] = { +static const struct em28xx_reg_seq compro_mute_gpio[] = { {EM2820_R08_GPIO_CTRL, 6, 7, 10}, { -1, -1, -1, -1}, }; /* Terratec AV350 */ -static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { +static const struct em28xx_reg_seq terratec_av350_mute_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0x7f, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { +static const struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq silvercrest_reg_seq[] = { +static const struct em28xx_reg_seq silvercrest_reg_seq[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0x01, 0xf7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq vc211a_enable[] = { +static const struct em28xx_reg_seq vc211a_enable[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0x07, 10}, {EM2820_R08_GPIO_CTRL, 0xff, 0x0f, 10}, {EM2820_R08_GPIO_CTRL, 0xff, 0x0b, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq dikom_dk300_digital[] = { +static const struct em28xx_reg_seq dikom_dk300_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, }; /* Reset for the most [digital] boards */ -static struct em28xx_reg_seq leadership_digital[] = { +static const struct em28xx_reg_seq leadership_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq leadership_reset[] = { +static const struct em28xx_reg_seq leadership_reset[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, { -1, -1, -1, -1}, }; -/* 2013:024f PCTV nanoStick T2 290e +/* + * 2013:024f PCTV nanoStick T2 290e * GPIO_6 - demod reset * GPIO_7 - LED */ -static struct em28xx_reg_seq pctv_290e[] = { +static const struct em28xx_reg_seq pctv_290e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80}, {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */ @@ -326,7 +322,7 @@ static struct em28xx_reg_seq pctv_290e[] = { }; #if 0 -static struct em28xx_reg_seq terratec_h5_gpio[] = { +static const struct em28xx_reg_seq terratec_h5_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50}, @@ -334,7 +330,7 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_h5_digital[] = { +static const struct em28xx_reg_seq terratec_h5_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, @@ -342,7 +338,8 @@ static struct em28xx_reg_seq terratec_h5_digital[] = { }; #endif -/* 2013:024f PCTV DVB-S2 Stick 460e +/* + * 2013:024f PCTV DVB-S2 Stick 460e * GPIO_0 - POWER_ON * GPIO_1 - BOOST * GPIO_2 - VUV_LNB (red LED) @@ -352,7 +349,7 @@ static struct em28xx_reg_seq terratec_h5_digital[] = { * GPIO_6 - RESET_DEM * GPIO_7 - LED (green LED) */ -static struct em28xx_reg_seq pctv_460e[] = { +static const struct em28xx_reg_seq pctv_460e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50}, { 0x0d, 0xff, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */ @@ -361,7 +358,7 @@ static struct em28xx_reg_seq pctv_460e[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { +static const struct em28xx_reg_seq c3tech_digital_duo_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10}, /* xc5000 reset */ {EM2874_R80_GPIO_P0_CTRL, 0xf9, 0xff, 35}, @@ -384,7 +381,7 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { * GPIO 6 = #RESET_DEM * GPIO 7 = P07_LED (green LED) */ -static struct em28xx_reg_seq pctv_461e[] = { +static const struct em28xx_reg_seq pctv_461e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0}, {0x0d, 0xff, 0xff, 0}, {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */ @@ -396,7 +393,7 @@ static struct em28xx_reg_seq pctv_461e[] = { }; #if 0 -static struct em28xx_reg_seq hauppauge_930c_gpio[] = { +static const struct em28xx_reg_seq hauppauge_930c_gpio[] = { {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */ {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, @@ -404,7 +401,7 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq hauppauge_930c_digital[] = { +static const struct em28xx_reg_seq hauppauge_930c_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, @@ -412,38 +409,41 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = { }; #endif -/* 1b80:e425 MaxMedia UB425-TC +/* + * 1b80:e425 MaxMedia UB425-TC * 1b80:e1cc Delock 61959 * GPIO_6 - demod reset, 0=active * GPIO_7 - LED, 0=active */ -static struct em28xx_reg_seq maxmedia_ub425_tc[] = { +static const struct em28xx_reg_seq maxmedia_ub425_tc[] = { {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ { -1, -1, -1, -1}, }; -/* 2304:0242 PCTV QuatroStick (510e) +/* + * 2304:0242 PCTV QuatroStick (510e) * GPIO_2: decoder reset, 0=active * GPIO_4: decoder suspend, 0=active * GPIO_6: demod reset, 0=active * GPIO_7: LED, 1=active */ -static struct em28xx_reg_seq pctv_510e[] = { +static const struct em28xx_reg_seq pctv_510e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ { -1, -1, -1, -1}, }; -/* 2013:0251 PCTV QuatroStick nano (520e) +/* + * 2013:0251 PCTV QuatroStick nano (520e) * GPIO_2: decoder reset, 0=active * GPIO_4: decoder suspend, 0=active * GPIO_6: demod reset, 0=active * GPIO_7: LED, 1=active */ -static struct em28xx_reg_seq pctv_520e[] = { +static const struct em28xx_reg_seq pctv_520e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ @@ -451,7 +451,8 @@ static struct em28xx_reg_seq pctv_520e[] = { { -1, -1, -1, -1}, }; -/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam +/* + * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam * reg 0x80/0x84: * GPIO_0: capturing LED, 0=on, 1=off * GPIO_2: AV mute button, 0=pressed, 1=unpressed @@ -460,13 +461,13 @@ static struct em28xx_reg_seq pctv_520e[] = { * reg 0x81/0x85: * GPIO_7: snapshot button, 0=pressed, 1=unpressed */ -static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { +static const struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq pctv_292e[] = { +static const struct em28xx_reg_seq pctv_292e[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 950}, {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100}, @@ -478,7 +479,7 @@ static struct em28xx_reg_seq pctv_292e[] = { {-1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_t2_stick_hd[] = { +static const struct em28xx_reg_seq terratec_t2_stick_hd[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 600}, {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 10}, @@ -492,7 +493,7 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = { {-1, -1, -1, -1}, }; -static struct em28xx_reg_seq plex_px_bcud[] = { +static const struct em28xx_reg_seq plex_px_bcud[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 0}, {EM2874_R50_IR_CONFIG, 0x01, 0xff, 0}, @@ -507,8 +508,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = { }; /* - * 2040:0265 Hauppauge WinTV-dualHD DVB - * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM + * 2040:0265 Hauppauge WinTV-dualHD DVB Isoc + * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk + * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM Isoc + * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk * reg 0x80/0x84: * GPIO_0: Yellow LED tuner 1, 0=on, 1=off * GPIO_1: Green LED tuner 1, 0=on, 1=off @@ -517,7 +520,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = { * GPIO_5: Reset #2, 0=active * GPIO_6: Reset #1, 0=active */ -static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { +static const struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 200}, {0x50, 0x04, 0xff, 300}, @@ -534,7 +537,7 @@ static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { /* * Button definitions */ -static struct em28xx_button std_snapshot_button[] = { +static const struct em28xx_button std_snapshot_button[] = { { .role = EM28XX_BUTTON_SNAPSHOT, .reg_r = EM28XX_R0C_USBSUSP, @@ -545,7 +548,7 @@ static struct em28xx_button std_snapshot_button[] = { {-1, 0, 0, 0, 0}, }; -static struct em28xx_button speedlink_vad_laplace_buttons[] = { +static const struct em28xx_button speedlink_vad_laplace_buttons[] = { { .role = EM28XX_BUTTON_SNAPSHOT, .reg_r = EM2874_R85_GPIO_P1_STATE, @@ -629,7 +632,7 @@ static struct em28xx_led hauppauge_dualhd_leds[] = { /* * Board definitions */ -struct em28xx_board em28xx_boards[] = { +const struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "EM2710/EM2750/EM2751 webcam grabber", .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, @@ -1436,9 +1439,11 @@ struct em28xx_board em28xx_boards[] = { .gpio = default_analog, } }, }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ + /* + * maybe there's a reason behind it why Terratec sells the Hybrid XS + * as Prodigy XS with a different PID, let's keep it separated for now + * maybe we'll need it later on + */ [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .tuner_type = TUNER_XC2028, @@ -1782,8 +1787,9 @@ struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_KWORLD_315U, .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, - /* Analog mode - still not ready */ - /*.input = { { +#if 0 + /* FIXME: Analog mode - still not ready */ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = EM28XX_AMUX_VIDEO, @@ -1801,7 +1807,8 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, .gpio = em2882_kworld_315u_analog1, .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - } }, */ + } }, +#endif }, [EM2880_BOARD_EMPIRE_DUAL_TV] = { .name = "Empire dual TV", @@ -2162,17 +2169,21 @@ struct em28xx_board em28xx_boards[] = { .gpio = evga_indtube_analog, } }, }, - /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 + - Infineon TUA6034) */ + /* + * eb1a:2868 Empia EM2870 + Philips CU1216L NIM + * (Philips TDA10023 + Infineon TUA6034) + */ [EM2870_BOARD_REDDO_DVB_C_USB_BOX] = { .name = "Reddo DVB-C USB TV Box", .tuner_type = TUNER_ABSENT, .tuner_gpio = reddo_dvb_c_usb_box, .has_dvb = 1, }, - /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold + /* + * 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold * initially as the KWorld PlusTV 340U, then as the UB435-Q. - * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */ + * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 + */ [EM2870_BOARD_KWORLD_A340] = { .name = "KWorld PlusTV 340U or UB435-Q (ATSC)", .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ @@ -2180,30 +2191,38 @@ struct em28xx_board em28xx_boards[] = { .dvb_gpio = kworld_a340_digital, .tuner_gpio = default_tuner_gpio, }, - /* 2013:024f PCTV nanoStick T2 290e. - * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ + /* + * 2013:024f PCTV nanoStick T2 290e. + * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 + */ [EM28174_BOARD_PCTV_290E] = { .name = "PCTV nanoStick T2 290e", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_290e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* 2013:024f PCTV DVB-S2 Stick 460e - * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */ + /* + * 2013:024f PCTV DVB-S2 Stick 460e + * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 + */ [EM28174_BOARD_PCTV_460E] = { .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .name = "PCTV DVB-S2 Stick (460e)", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_460e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* eb1a:5006 Honestech VIDBOX NW03 - * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */ + /* + * eb1a:5006 Honestech VIDBOX NW03 + * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner + */ [EM2860_BOARD_HT_VIDBOX_NW03] = { .name = "Honestech Vidbox NW03", .tuner_type = TUNER_ABSENT, @@ -2214,12 +2233,14 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */ + .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs check */ .amux = EM28XX_AMUX_LINE_IN, } }, }, - /* 1b80:e425 MaxMedia UB425-TC - * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */ + /* + * 1b80:e425 MaxMedia UB425-TC + * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 + */ [EM2874_BOARD_MAXMEDIA_UB425_TC] = { .name = "MaxMedia UB425-TC", .tuner_type = TUNER_ABSENT, @@ -2230,8 +2251,10 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 2304:0242 PCTV QuatroStick (510e) - * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ + /* + * 2304:0242 PCTV QuatroStick (510e) + * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 + */ [EM2884_BOARD_PCTV_510E] = { .name = "PCTV QuatroStick (510e)", .tuner_type = TUNER_ABSENT, @@ -2242,8 +2265,10 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 2013:0251 PCTV QuatroStick nano (520e) - * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ + /* + * 2013:0251 PCTV QuatroStick nano (520e) + * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 + */ [EM2884_BOARD_PCTV_520E] = { .name = "PCTV QuatroStick nano (520e)", .tuner_type = TUNER_ABSENT, @@ -2263,9 +2288,11 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 1b80:e1cc Delock 61959 + /* + * 1b80:e1cc Delock 61959 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 - * mostly the same as MaxMedia UB-425-TC but different remote */ + * mostly the same as MaxMedia UB-425-TC but different remote + */ [EM2874_BOARD_DELOCK_61959] = { .name = "Delock 61959", .tuner_type = TUNER_ABSENT, @@ -2311,8 +2338,10 @@ struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_PINNACLE_PCTV_HD, .leds = pctv_80e_leds, }, - /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam - * Empia EM2765 + OmniVision OV2640 */ + /* + * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam + * Empia EM2765 + OmniVision OV2640 + */ [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = { .name = "SpeedLink Vicious And Devine Laplace webcam", .xclk = EM28XX_XCLK_FREQUENCY_24MHZ, @@ -2329,23 +2358,29 @@ struct em28xx_board em28xx_boards[] = { .buttons = speedlink_vad_laplace_buttons, .leds = speedlink_vad_laplace_leds, }, - /* 2013:0258 PCTV DVB-S2 Stick (461e) - * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */ + /* + * 2013:0258 PCTV DVB-S2 Stick (461e) + * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 + */ [EM28178_BOARD_PCTV_461E] = { .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .name = "PCTV DVB-S2 Stick (461e)", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_461e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* 2013:025f PCTV tripleStick (292e). - * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */ + /* + * 2013:025f PCTV tripleStick (292e). + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 + */ [EM28178_BOARD_PCTV_292E] = { .name = "PCTV tripleStick (292e)", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_292e, .has_dvb = 1, @@ -2365,12 +2400,15 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, - /* eb1a:8179 Terratec Cinergy T2 Stick HD. - * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 */ + /* + * eb1a:8179 Terratec Cinergy T2 Stick HD. + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 + */ [EM28178_BOARD_TERRATEC_T2_STICK_HD] = { .name = "Terratec Cinergy T2 Stick HD", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = terratec_t2_stick_hd, .has_dvb = 1, @@ -2391,7 +2429,8 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, }, /* - * 2040:0265 Hauppauge WinTV-dualHD (DVB version). + * 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc. + * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk. * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { @@ -2402,11 +2441,13 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = hauppauge_dualhd_dvb, .has_dvb = 1, + .has_dual_ts = 1, .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, /* - * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM). + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. + * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Bulk. * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = { @@ -2417,6 +2458,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = hauppauge_dualhd_dvb, .has_dvb = 1, + .has_dual_ts = 1, .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, @@ -2485,10 +2527,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0xeb1a, 0xe359), .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0x1b80, 0xe302), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ - { USB_DEVICE(0x1b80, 0xe304), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */ + { USB_DEVICE(0x1b80, 0xe302), /* Kaiser Baas Video to DVD maker */ + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x1b80, 0xe304), /* Kworld DVD Maker 2 */ + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, { USB_DEVICE(0x0ccd, 0x004c), @@ -2547,8 +2589,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, { USB_DEVICE(0x2040, 0x0265), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, { USB_DEVICE(0x2040, 0x026d), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -2609,7 +2655,13 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x025f), .driver_info = EM28178_BOARD_PCTV_292E }, - { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */ + { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */ .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x0413, 0x6f07), .driver_info = EM2861_BOARD_LEADTEK_VC100 }, @@ -2626,7 +2678,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table); /* * EEPROM hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_eeprom_hash[] = { +static const struct em28xx_hash_table em28xx_eeprom_hash[] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, @@ -2639,7 +2691,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { }; /* I2C devicelist hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_i2c_hash[] = { +static const struct em28xx_hash_table em28xx_i2c_hash[] = { {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, @@ -2669,26 +2721,46 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg) } EXPORT_SYMBOL_GPL(em28xx_tuner_callback); -static inline void em28xx_set_model(struct em28xx *dev) +static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) { - dev->board = em28xx_boards[dev->model]; + const struct em28xx_board *board = &em28xx_boards[dev->model]; + u8 xclk = board->xclk, i2c_speed = board->i2c_speed; - /* Those are the default values for the majority of boards - Use those values if not specified otherwise at boards entry + /* + * Those are the default values for the majority of boards + * Use those values if not specified otherwise at boards entry */ - if (!dev->board.xclk) - dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | - EM28XX_XCLK_FREQUENCY_12MHZ; + if (!xclk) + xclk = EM28XX_XCLK_IR_RC5_MODE | + EM28XX_XCLK_FREQUENCY_12MHZ; + + em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); - if (!dev->board.i2c_speed) - dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_FREQ_100_KHZ; + if (!i2c_speed) + i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ; + + dev->i2c_speed = i2c_speed & 0x03; + + if (!dev->board.is_em2800) + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed); + msleep(50); +} + +static inline void em28xx_set_model(struct em28xx *dev) +{ + dev->board = em28xx_boards[dev->model]; + dev->has_msp34xx = dev->board.has_msp34xx; + dev->is_webcam = dev->board.is_webcam; + + em28xx_set_xclk_i2c_speed(dev); /* Should be initialized early, for I2C to work */ dev->def_i2c_bus = dev->board.def_i2c_bus; } -/* Wait until AC97_RESET reports the expected value reliably before proceeding. +/* + * Wait until AC97_RESET reports the expected value reliably before proceeding. * We also check that two unrelated registers accesses don't return the same * value to avoid premature return. * This procedure helps ensuring AC97 register accesses are reliable. @@ -2718,17 +2790,17 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev, return -ETIMEDOUT; } -/* Since em28xx_pre_card_setup() requires a proper dev->model, +/* + * Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ static void em28xx_pre_card_setup(struct em28xx *dev) { - /* Set the initial XCLK and I2C clock values based on the board - definition */ - em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); - if (!dev->board.is_em2800) - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - msleep(50); + /* + * Set the initial XCLK and I2C clock values based on the board + * definition + */ + em28xx_set_xclk_i2c_speed(dev); /* request some modules */ switch (dev->model) { @@ -2739,17 +2811,19 @@ static void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x6d); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x7d); - msleep(10); + usleep_range(10000, 11000); break; case EM2870_BOARD_COMPRO_VIDEOMATE: - /* TODO: someone can do some cleanup here... - not everything's needed */ + /* + * TODO: someone can do some cleanup here... + * not everything's needed + */ em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x01); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc); @@ -2760,8 +2834,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev) mdelay(70); break; case EM2870_BOARD_TERRATEC_XS_MT2060: - /* this device needs some gpio writes to get the DVB-T - demod work */ + /* + * this device needs some gpio writes to get the DVB-T + * demod work + */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); @@ -2770,8 +2846,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev) mdelay(70); break; case EM2870_BOARD_PINNACLE_PCTV_DVB: - /* this device needs some gpio writes to get the - DVB-T demod work */ + /* + * this device needs some gpio writes to get the + * DVB-T demod work + */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); @@ -2787,13 +2865,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev) case EM2882_BOARD_KWORLD_ATSC_315U: em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x08); - msleep(10); + usleep_range(10000, 11000); break; case EM2860_BOARD_KAIOMY_TVNPC_U2: @@ -2801,11 +2879,11 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); em28xx_write_regs(dev, 0x0d, "\x42", 1); em28xx_write_regs(dev, 0x08, "\xfd", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\xff", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\x7f", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\x6b", 1); break; @@ -2817,7 +2895,7 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); @@ -2825,7 +2903,8 @@ static void em28xx_pre_card_setup(struct em28xx *dev) break; case EM2860_BOARD_TERRATEC_GRABBY: - /* HACK?: Ensure AC97 register reading is reliable before + /* + * HACK?: Ensure AC97 register reading is reliable before * proceeding. In practice, this will wait about 1.6 seconds. */ em28xx_wait_until_ac97_features_equals(dev, 0x6a90); @@ -2843,7 +2922,7 @@ static int em28xx_hint_board(struct em28xx *dev) { int i; - if (dev->board.is_webcam) { + if (dev->is_webcam) { if (dev->em28xx_sensor == EM28XX_MT9V011) { dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; } else if (dev->em28xx_sensor == EM28XX_MT9M001 || @@ -2855,7 +2934,8 @@ static int em28xx_hint_board(struct em28xx *dev) return 0; } - /* HINT method: EEPROM + /* + * HINT method: EEPROM * * This method works only for boards with eeprom. * Uses a hash of all eeprom bytes. The hash should be @@ -2881,7 +2961,8 @@ static int em28xx_hint_board(struct em28xx *dev) } } - /* HINT method: I2C attached devices + /* + * HINT method: I2C attached devices * * This method works for all boards. * Uses a hash of i2c scanned devices. @@ -2935,11 +3016,11 @@ static void em28xx_card_setup(struct em28xx *dev) * If the device can be a webcam, seek for a sensor. * If sensor is not found, then it isn't a webcam. */ - if (dev->board.is_webcam) { + if (dev->is_webcam) { em28xx_detect_sensor(dev); if (dev->em28xx_sensor == EM28XX_NOSENSOR) /* NOTE: error/unknown sensor/no sensor */ - dev->board.is_webcam = 0; + dev->is_webcam = 0; } switch (dev->model) { @@ -2959,9 +3040,9 @@ static void em28xx_card_setup(struct em28xx *dev) * This solution is only valid if they do not share eeprom * hash identities which has not been determined as yet. */ - if (em28xx_hint_board(dev) < 0) + if (em28xx_hint_board(dev) < 0) { dev_err(&dev->intf->dev, "Board not discovered\n"); - else { + } else { em28xx_set_model(dev); em28xx_pre_card_setup(dev); } @@ -2971,7 +3052,7 @@ static void em28xx_card_setup(struct em28xx *dev) } dev_info(&dev->intf->dev, "Identified as %s (card=%d)\n", - dev->board.name, dev->model); + dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -2988,7 +3069,7 @@ static void em28xx_card_setup(struct em28xx *dev) { struct tveeprom tv; - if (dev->eedata == NULL) + if (!dev->eedata) break; #if defined(CONFIG_MODULES) && defined(MODULE) request_module("tveeprom"); @@ -3001,15 +3082,15 @@ static void em28xx_card_setup(struct em28xx *dev) if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) { dev->i2s_speed = 2048000; - dev->board.has_msp34xx = 1; + dev->has_msp34xx = 1; } break; } case EM2882_BOARD_KWORLD_ATSC_315U: em28xx_write_reg(dev, 0x0d, 0x42); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); - msleep(10); + usleep_range(10000, 11000); break; case EM2820_BOARD_KWORLD_PVRTV2800RF: /* GPIO enables sound on KWORLD PVR TV 2800RF */ @@ -3034,10 +3115,12 @@ static void em28xx_card_setup(struct em28xx *dev) if (!em28xx_hint_board(dev)) em28xx_set_model(dev); - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ + /* + * In cases where we had to use a board hint, the call to + * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + * so make the call now so the analog GPIOs are set properly + * before probing the i2c bus. + */ em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; @@ -3059,10 +3142,12 @@ static void em28xx_card_setup(struct em28xx *dev) if (!em28xx_hint_board(dev)) em28xx_set_model(dev); - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ + /* + * In cases where we had to use a board hint, the call to + * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + * so make the call now so the analog GPIOs are set properly + * before probing the i2c bus. + */ em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; @@ -3147,8 +3232,8 @@ static void request_module_async(struct work_struct *work) */ /* - * Devicdes with an audio-only interface also have a V4L/DVB/RC - * interface. Don't register extensions twice on those devices. + * Devices with an audio-only intf also have a V4L/DVB/RC + * intf. Don't register extensions twice on those devices. */ if (dev->is_audio_only) { #if defined(CONFIG_MODULES) && defined(MODULE) @@ -3209,7 +3294,6 @@ static int em28xx_media_device_init(struct em28xx *dev, static void em28xx_unregister_media_device(struct em28xx *dev) { - #ifdef CONFIG_MEDIA_CONTROLLER if (dev->media_dev) { media_device_unregister(dev->media_dev); @@ -3224,7 +3308,7 @@ static void em28xx_unregister_media_device(struct em28xx *dev) * em28xx_release_resources() * unregisters the v4l2,i2c and usb devices * called when the device gets disconnected or at module unload -*/ + */ static void em28xx_release_resources(struct em28xx *dev) { struct usb_device *udev = interface_to_usbdev(dev->intf); @@ -3239,7 +3323,8 @@ static void em28xx_release_resources(struct em28xx *dev) em28xx_i2c_unregister(dev, 1); em28xx_i2c_unregister(dev, 0); - usb_put_dev(udev); + if (dev->ts == PRIMARY_TS) + usb_put_dev(udev); /* Mark device as unused */ clear_bit(dev->devno, em28xx_devused); @@ -3273,13 +3358,13 @@ EXPORT_SYMBOL_GPL(em28xx_free_device); * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, - struct usb_interface *interface, + struct usb_interface *intf, int minor) { int retval; const char *chip_name = NULL; - dev->intf = interface; + dev->intf = intf; mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); @@ -3382,17 +3467,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, em28xx_pre_card_setup(dev); - if (!dev->board.is_em2800) { - /* Resets I2C speed */ - retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - if (retval < 0) { - dev_err(&dev->intf->dev, - "%s: em28xx_write_reg failed! retval [%d]\n", - __func__, retval); - return retval; - } - } - rt_mutex_init(&dev->i2c_bus_lock); /* register i2c bus 0 */ @@ -3417,8 +3491,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { dev_err(&dev->intf->dev, - "%s: em28xx_i2c_register bus 1 - error [%d]!\n", - __func__, retval); + "%s: em28xx_i2c_register bus 1 - error [%d]!\n", + __func__, retval); em28xx_i2c_unregister(dev, 0); @@ -3432,14 +3506,147 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, return 0; } +static int em28xx_duplicate_dev(struct em28xx *dev) +{ + int nr; + struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); + + if (!sec_dev) { + dev->dev_next = NULL; + return -ENOMEM; + } + memcpy(sec_dev, dev, sizeof(*sec_dev)); + /* Check to see next free device and mark as used */ + do { + nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); + if (nr >= EM28XX_MAXBOARDS) { + /* No free device slots */ + dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + kfree(sec_dev); + dev->dev_next = NULL; + return -ENOMEM; + } + } while (test_and_set_bit(nr, em28xx_devused)); + sec_dev->devno = nr; + snprintf(sec_dev->name, 28, "em28xx #%d", nr); + sec_dev->dev_next = NULL; + dev->dev_next = sec_dev; + return 0; +} + /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) +static void em28xx_check_usb_descriptor(struct em28xx *dev, + struct usb_device *udev, + struct usb_interface *intf, + int alt, int ep, + bool *has_vendor_audio, + bool *has_video, + bool *has_dvb) +{ + const struct usb_endpoint_descriptor *e; + int sizedescr, size; + + /* + * NOTE: + * + * Old logic with support for isoc transfers only was: + * 0x82 isoc => analog + * 0x83 isoc => audio + * 0x84 isoc => digital + * + * New logic with support for bulk transfers + * 0x82 isoc => analog + * 0x82 bulk => analog + * 0x83 isoc* => audio + * 0x84 isoc => digital + * 0x84 bulk => analog or digital** + * 0x85 isoc => digital TS2 + * 0x85 bulk => digital TS2 + * (*: audio should always be isoc) + * (**: analog, if ep 0x82 is isoc, otherwise digital) + * + * The new logic preserves backwards compatibility and + * reflects the endpoint configurations we have seen + * so far. But there might be devices for which this + * logic is not sufficient... + */ + + e = &intf->altsetting[alt].endpoint[ep].desc; + + if (!usb_endpoint_dir_in(e)) + return; + + sizedescr = le16_to_cpu(e->wMaxPacketSize); + size = sizedescr & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(sizedescr); + + /* Only inspect input endpoints */ + + switch (e->bEndpointAddress) { + case 0x82: + *has_video = true; + if (usb_endpoint_xfer_isoc(e)) { + dev->analog_ep_isoc = e->bEndpointAddress; + dev->alt_max_pkt_size_isoc[alt] = size; + } else if (usb_endpoint_xfer_bulk(e)) { + dev->analog_ep_bulk = e->bEndpointAddress; + } + return; + case 0x83: + if (usb_endpoint_xfer_isoc(e)) + *has_vendor_audio = true; + else + dev_err(&intf->dev, + "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); + return; + case 0x84: + if (*has_video && (usb_endpoint_xfer_bulk(e))) { + dev->analog_ep_bulk = e->bEndpointAddress; + } else { + if (usb_endpoint_xfer_isoc(e)) { + if (size > dev->dvb_max_pkt_size_isoc) { + /* + * 2) some manufacturers (e.g. Terratec) + * disable endpoints by setting + * wMaxPacketSize to 0 bytes for all + * alt settings. So far, we've seen + * this for DVB isoc endpoints only. + */ + *has_dvb = true; + dev->dvb_ep_isoc = e->bEndpointAddress; + dev->dvb_max_pkt_size_isoc = size; + dev->dvb_alt_isoc = alt; + } + } else { + *has_dvb = true; + dev->dvb_ep_bulk = e->bEndpointAddress; + } + } + return; + case 0x85: + if (usb_endpoint_xfer_isoc(e)) { + if (size > dev->dvb_max_pkt_size_isoc_ts2) { + dev->dvb_ep_isoc_ts2 = e->bEndpointAddress; + dev->dvb_max_pkt_size_isoc_ts2 = size; + dev->dvb_alt_isoc = alt; + } + } else { + dev->dvb_ep_bulk_ts2 = e->bEndpointAddress; + } + return; + } +} + /* * em28xx_usb_probe() * checks for supported devices */ -static int em28xx_usb_probe(struct usb_interface *interface, +static int em28xx_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev; @@ -3447,17 +3654,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, int retval; bool has_vendor_audio = false, has_video = false, has_dvb = false; int i, nr, try_bulk; - const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; + const int ifnum = intf->altsetting[0].desc.bInterfaceNumber; char *speed; - udev = usb_get_dev(interface_to_usbdev(interface)); + udev = usb_get_dev(interface_to_usbdev(intf)); /* Check to see next free device and mark as used */ do { nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - dev_err(&interface->dev, + dev_err(&intf->dev, "Driver supports up to %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; @@ -3466,13 +3673,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, } while (test_and_set_bit(nr, em28xx_devused)); /* Don't register audio interfaces */ - if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev_err(&interface->dev, + if (intf->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev_err(&intf->dev, "audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, - interface->altsetting[0].desc.bInterfaceClass); + intf->altsetting[0].desc.bInterfaceClass); retval = -ENODEV; goto err; @@ -3480,106 +3687,33 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { + if (!dev) { retval = -ENOMEM; goto err; } /* compute alternate max packet sizes */ - dev->alt_max_pkt_size_isoc = - kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) * - interface->num_altsetting, GFP_KERNEL); - if (dev->alt_max_pkt_size_isoc == NULL) { + dev->alt_max_pkt_size_isoc = kcalloc(intf->num_altsetting, + sizeof(dev->alt_max_pkt_size_isoc[0]), + GFP_KERNEL); + if (!dev->alt_max_pkt_size_isoc) { kfree(dev); retval = -ENOMEM; goto err; } /* Get endpoints */ - for (i = 0; i < interface->num_altsetting; i++) { + for (i = 0; i < intf->num_altsetting; i++) { int ep; - for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - const struct usb_endpoint_descriptor *e; - int sizedescr, size; - - e = &interface->altsetting[i].endpoint[ep].desc; - - sizedescr = le16_to_cpu(e->wMaxPacketSize); - size = sizedescr & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(sizedescr); - - if (usb_endpoint_dir_in(e)) { - switch (e->bEndpointAddress) { - case 0x82: - has_video = true; - if (usb_endpoint_xfer_isoc(e)) { - dev->analog_ep_isoc = - e->bEndpointAddress; - dev->alt_max_pkt_size_isoc[i] = size; - } else if (usb_endpoint_xfer_bulk(e)) { - dev->analog_ep_bulk = - e->bEndpointAddress; - } - break; - case 0x83: - if (usb_endpoint_xfer_isoc(e)) { - has_vendor_audio = true; - } else { - dev_err(&interface->dev, - "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); - } - break; - case 0x84: - if (has_video && - (usb_endpoint_xfer_bulk(e))) { - dev->analog_ep_bulk = - e->bEndpointAddress; - } else { - if (usb_endpoint_xfer_isoc(e)) { - if (size > dev->dvb_max_pkt_size_isoc) { - has_dvb = true; /* see NOTE (~) */ - dev->dvb_ep_isoc = e->bEndpointAddress; - dev->dvb_max_pkt_size_isoc = size; - dev->dvb_alt_isoc = i; - } - } else { - has_dvb = true; - dev->dvb_ep_bulk = e->bEndpointAddress; - } - } - break; - } - } - /* NOTE: - * Old logic with support for isoc transfers only was: - * 0x82 isoc => analog - * 0x83 isoc => audio - * 0x84 isoc => digital - * - * New logic with support for bulk transfers - * 0x82 isoc => analog - * 0x82 bulk => analog - * 0x83 isoc* => audio - * 0x84 isoc => digital - * 0x84 bulk => analog or digital** - * (*: audio should always be isoc) - * (**: analog, if ep 0x82 is isoc, otherwise digital) - * - * The new logic preserves backwards compatibility and - * reflects the endpoint configurations we have seen - * so far. But there might be devices for which this - * logic is not sufficient... - */ - /* - * NOTE (~): some manufacturers (e.g. Terratec) disable - * endpoints by setting wMaxPacketSize to 0 bytes for - * all alt settings. So far, we've seen this for - * DVB isoc endpoints only. - */ - } + for (ep = 0; + ep < intf->altsetting[i].desc.bNumEndpoints; + ep++) + em28xx_check_usb_descriptor(dev, udev, intf, + i, ep, + &has_vendor_audio, + &has_video, + &has_dvb); } if (!(has_vendor_audio || has_video || has_dvb)) { @@ -3602,7 +3736,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - dev_err(&interface->dev, + dev_err(&intf->dev, "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", @@ -3610,7 +3744,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, - interface->altsetting->desc.bInterfaceNumber); + intf->altsetting->desc.bInterfaceNumber); /* * Make sure we have 480 Mbps of bandwidth, otherwise things like @@ -3618,8 +3752,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - dev_err(&interface->dev, "Device initialization failed.\n"); - dev_err(&interface->dev, + dev_err(&intf->dev, "Device initialization failed.\n"); + dev_err(&intf->dev, "Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; @@ -3632,53 +3766,56 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->has_video = has_video; dev->ifnum = ifnum; + dev->ts = PRIMARY_TS; + snprintf(dev->name, 28, "em28xx"); + dev->dev_next = NULL; + if (has_vendor_audio) { - dev_err(&interface->dev, + dev_err(&intf->dev, "Audio interface %i found (Vendor Class)\n", ifnum); dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; } - /* Checks if audio is provided by a USB Audio Class interface */ + /* Checks if audio is provided by a USB Audio Class intf */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { struct usb_interface *uif = udev->config->interface[i]; if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) - dev_err(&interface->dev, + dev_err(&intf->dev, "em28xx: device seems to have vendor AND usb audio class interfaces !\n" - "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n"); + "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; } } if (has_video) - dev_err(&interface->dev, "Video interface %i found:%s%s\n", + dev_err(&intf->dev, "Video interface %i found:%s%s\n", ifnum, dev->analog_ep_bulk ? " bulk" : "", dev->analog_ep_isoc ? " isoc" : ""); if (has_dvb) - dev_err(&interface->dev, "DVB interface %i found:%s%s\n", + dev_err(&intf->dev, "DVB interface %i found:%s%s\n", ifnum, dev->dvb_ep_bulk ? " bulk" : "", dev->dvb_ep_isoc ? " isoc" : ""); - dev->num_alt = interface->num_altsetting; + dev->num_alt = intf->num_altsetting; - if ((unsigned)card[nr] < em28xx_bcount) + if ((unsigned int)card[nr] < em28xx_bcount) dev->model = card[nr]; - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); + /* save our data pointer in this intf device */ + usb_set_intfdata(intf, dev); /* allocate device struct and check if the device is a webcam */ mutex_init(&dev->lock); - retval = em28xx_init_dev(dev, udev, interface, nr); - if (retval) { + retval = em28xx_init_dev(dev, udev, intf, nr); + if (retval) goto err_free; - } if (usb_xfer_mode < 0) { - if (dev->board.is_webcam) + if (dev->is_webcam) try_bulk = 1; else try_bulk = 0; @@ -3690,8 +3827,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video && dev->board.decoder == EM28XX_NODECODER && dev->em28xx_sensor == EM28XX_NOSENSOR) { - - dev_err(&interface->dev, + dev_err(&intf->dev, "Currently, V4L2 is not supported on this model\n"); has_video = false; dev->has_video = false; @@ -3701,16 +3837,75 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - dev_err(&interface->dev, "analog set to %s mode.\n", + dev_err(&intf->dev, "analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; - dev_err(&interface->dev, "dvb set to %s mode.\n", + dev_err(&intf->dev, "dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); } + if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) { + dev->dev_next->ts = SECONDARY_TS; + dev->dev_next->alt = -1; + dev->dev_next->is_audio_only = has_vendor_audio && + !(has_video || has_dvb); + dev->dev_next->has_video = false; + dev->dev_next->ifnum = ifnum; + dev->dev_next->model = id->driver_info; + + mutex_init(&dev->dev_next->lock); + retval = em28xx_init_dev(dev->dev_next, udev, intf, + dev->dev_next->devno); + if (retval) + goto err_free; + + dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */ + dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */ + + if (usb_xfer_mode < 0) { + if (dev->dev_next->is_webcam) + try_bulk = 1; + else + try_bulk = 0; + } else { + try_bulk = usb_xfer_mode > 0; + } + + /* Select USB transfer types to use */ + if (has_dvb) { + if (!dev->dvb_ep_isoc_ts2 || + (try_bulk && dev->dvb_ep_bulk_ts2)) + dev->dev_next->dvb_xfer_bulk = 1; + dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n", + dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc"); + } + + dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2; + dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2; + dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2; + dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc; + + /* Configuare hardware to support TS2*/ + if (dev->dvb_xfer_bulk) { + /* The ep4 and ep5 are configuared for BULK */ + em28xx_write_reg(dev, 0x0b, 0x96); + mdelay(100); + em28xx_write_reg(dev, 0x0b, 0x80); + mdelay(100); + } else { + /* The ep4 and ep5 are configuared for ISO */ + em28xx_write_reg(dev, 0x0b, 0x96); + mdelay(100); + em28xx_write_reg(dev, 0x0b, 0x82); + mdelay(100); + } + + kref_init(&dev->dev_next->ref); + } + kref_init(&dev->ref); request_modules(dev); @@ -3743,45 +3938,59 @@ err_no_slot: * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ -static void em28xx_usb_disconnect(struct usb_interface *interface) +static void em28xx_usb_disconnect(struct usb_interface *intf) { struct em28xx *dev; - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); if (!dev) return; + if (dev->dev_next) { + dev->dev_next->disconnected = 1; + dev_info(&dev->intf->dev, "Disconnecting %s\n", + dev->dev_next->name); + flush_request_modules(dev->dev_next); + } + dev->disconnected = 1; - dev_err(&dev->intf->dev, "Disconnecting\n"); + dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name); flush_request_modules(dev); em28xx_close_extension(dev); + if (dev->dev_next) + em28xx_release_resources(dev->dev_next); em28xx_release_resources(dev); + + if (dev->dev_next) { + kref_put(&dev->dev_next->ref, em28xx_free_device); + dev->dev_next = NULL; + } kref_put(&dev->ref, em28xx_free_device); } -static int em28xx_usb_suspend(struct usb_interface *interface, +static int em28xx_usb_suspend(struct usb_interface *intf, pm_message_t message) { struct em28xx *dev; - dev = usb_get_intfdata(interface); + dev = usb_get_intfdata(intf); if (!dev) return 0; em28xx_suspend_extension(dev); return 0; } -static int em28xx_usb_resume(struct usb_interface *interface) +static int em28xx_usb_resume(struct usb_interface *intf) { struct em28xx *dev; - dev = usb_get_intfdata(interface); + dev = usb_get_intfdata(intf); if (!dev) return 0; em28xx_resume_extension(dev); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 1d0d8cc06103..36d341fb65dd 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -1,26 +1,22 @@ -/* - em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> +// Markus Rechberger <mrechberger@gmail.com> +// Mauro Carvalho Chehab <mchehab@infradead.org> +// Sascha Sommer <saschasommer@freenet.de> +// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// 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 "em28xx.h" @@ -41,7 +37,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(EM28XX_VERSION); /* #define ENABLE_DEBUG_ISOC_FRAMES */ @@ -60,7 +56,6 @@ static unsigned int reg_debug; module_param(reg_debug, int, 0644); MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); - #define em28xx_regdbg(fmt, arg...) do { \ if (reg_debug) \ dev_printk(KERN_DEBUG, &dev->intf->dev, \ @@ -97,10 +92,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed with error %i\n", - pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8, ret); + pipe, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, ret); mutex_unlock(&dev->ctrl_urb_lock); return usb_translate_errors(ret); } @@ -111,10 +107,10 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, mutex_unlock(&dev->ctrl_urb_lock); em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x <<< %*ph\n", - pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8, len, buf); + pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, len, buf); return ret; } @@ -155,7 +151,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if (dev->disconnected) return -ENODEV; - if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) + if (len < 1 || len > URB_MAX_CTRL_SIZE) return -EINVAL; mutex_lock(&dev->ctrl_urb_lock); @@ -341,8 +337,9 @@ static int set_ac97_input(struct em28xx *dev) int ret, i; enum em28xx_amux amux = dev->ctl_ainput; - /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that - em28xx should point to LINE IN, while AC97 should use VIDEO + /* + * EM28XX_AMUX_VIDEO2 is a special case used to indicate that + * em28xx should point to LINE IN, while AC97 should use VIDEO */ if (amux == EM28XX_AMUX_VIDEO2) amux = EM28XX_AMUX_VIDEO; @@ -378,9 +375,9 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } - if (dev->board.has_msp34xx) + if (dev->has_msp34xx) { input = EM28XX_AUDIO_SRC_TUNER; - else { + } else { switch (dev->ctl_ainput) { case EM28XX_AMUX_VIDEO: input = EM28XX_AUDIO_SRC_TUNER; @@ -399,7 +396,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); if (ret < 0) return ret; - msleep(5); + usleep_range(10000, 11000); switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: @@ -432,8 +429,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) return 0; - /* It is assumed that all devices use master volume for output. - It would be possible to use also line output. + /* + * It is assumed that all devices use master volume for output. + * It would be possible to use also line output. */ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { /* Mute all outputs */ @@ -453,7 +451,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); if (ret < 0) return ret; - msleep(10); + usleep_range(10000, 11000); /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); @@ -487,8 +485,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { int sel = ac97_return_record_select(dev->ctl_aoutput); - /* Use the same input for both left and right - channels */ + /* + * Use the same input for both left and right + * channels + */ sel |= (sel << 8); em28xx_write_ac97(dev, AC97_REC_SEL, sel); @@ -539,7 +539,7 @@ int em28xx_audio_setup(struct em28xx *dev) else i2s_samplerates = 3; dev_info(&dev->intf->dev, "I2S Audio (%d sample rate(s))\n", - i2s_samplerates); + i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; @@ -579,7 +579,7 @@ int em28xx_audio_setup(struct em28xx *dev) dev_warn(&dev->intf->dev, "AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ - if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) + if ((vid == 0xffffffff || vid == 0x83847650) && feat == 0x6a90) dev->audio_mode.ac97 = EM28XX_AC97_EM202; else if ((vid >> 8) == 0x838476) dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; @@ -638,10 +638,29 @@ int em28xx_capture_start(struct em28xx *dev, int start) dev->chip_id == CHIP_ID_EM28174 || dev->chip_id == CHIP_ID_EM28178) { /* The Transport Stream Enable Register moved in em2874 */ - rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - start ? - EM2874_TS1_CAPTURE_ENABLE : 0x00, - EM2874_TS1_CAPTURE_ENABLE); + if (dev->dvb_xfer_bulk) { + /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */ + em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + 0xff); + } else { + /* ISOC Maximum Transfer Size = 188 * 5 */ + em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + dev->dvb_max_pkt_size_isoc / 188); + } + if (dev->ts == PRIMARY_TS) + rc = em28xx_write_reg_bits(dev, + EM2874_R5F_TS_ENABLE, + start ? EM2874_TS1_CAPTURE_ENABLE : 0x00, + EM2874_TS1_CAPTURE_ENABLE); + else + rc = em28xx_write_reg_bits(dev, + EM2874_R5F_TS_ENABLE, + start ? EM2874_TS2_CAPTURE_ENABLE : 0x00, + EM2874_TS2_CAPTURE_ENABLE); } else { /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ @@ -651,7 +670,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; if (start) { - if (dev->board.is_webcam) + if (dev->is_webcam) rc = em28xx_write_reg(dev, 0x13, 0x0c); /* Enable video capture */ @@ -670,7 +689,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) if (rc < 0) return rc; - msleep(6); + usleep_range(10000, 11000); } else { /* disable video capture */ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); @@ -691,7 +710,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; } -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) +int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio) { int rc = 0; @@ -704,7 +723,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); else em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); - msleep(6); + usleep_range(10000, 11000); } /* Send GPIO reset sequences specified at board entry */ @@ -748,9 +767,9 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) } EXPORT_SYMBOL_GPL(em28xx_set_mode); -/* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ +/* + *URB control + */ /* * URB completion handler for isoc/bulk transfers @@ -769,7 +788,7 @@ static void em28xx_irq_callback(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - em28xx_isocdbg("urb completition error %d.\n", urb->status); + em28xx_isocdbg("urb completion error %d.\n", urb->status); break; } @@ -800,11 +819,9 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) { struct urb *urb; struct em28xx_usb_bufs *usb_bufs; - struct usb_device *udev = interface_to_usbdev(dev->intf); int i; - em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n", - mode); + em28xx_isocdbg("called %s in mode %d\n", __func__, mode); if (mode == EM28XX_DIGITAL_MODE) usb_bufs = &dev->usb_ctl.digital_bufs; @@ -819,23 +836,16 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) else usb_unlink_urb(urb); - if (usb_bufs->transfer_buffer[i]) { - usb_free_coherent(udev, - urb->transfer_buffer_length, - usb_bufs->transfer_buffer[i], - urb->transfer_dma); - } usb_free_urb(urb); usb_bufs->urb[i] = NULL; } - usb_bufs->transfer_buffer[i] = NULL; } kfree(usb_bufs->urb); - kfree(usb_bufs->transfer_buffer); + kfree(usb_bufs->buf); usb_bufs->urb = NULL; - usb_bufs->transfer_buffer = NULL; + usb_bufs->buf = NULL; usb_bufs->num_bufs = 0; em28xx_capture_start(dev, 0); @@ -851,7 +861,7 @@ void em28xx_stop_urbs(struct em28xx *dev) struct urb *urb; struct em28xx_usb_bufs *isoc_bufs = &dev->usb_ctl.digital_bufs; - em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n"); + em28xx_isocdbg("called %s\n", __func__); for (i = 0; i < isoc_bufs->num_bufs; i++) { urb = isoc_bufs->urb[i]; @@ -880,10 +890,12 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, int sb_size, pipe; int j, k; - em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); + em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode); - /* Check mode and if we have an endpoint for the selected - transfer type, select buffer */ + /* + * Check mode and if we have an endpoint for the selected + * transfer type, select buffer + */ if (mode == EM28XX_DIGITAL_MODE) { if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { @@ -912,14 +924,13 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->num_bufs = num_bufs; - usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + usb_bufs->urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!usb_bufs->urb) return -ENOMEM; - usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!usb_bufs->transfer_buffer) { - kfree(usb_bufs->urb); + usb_bufs->buf = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); + if (!usb_bufs->buf) { + kfree(usb_bufs->buf); return -ENOMEM; } @@ -942,37 +953,36 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, } usb_bufs->urb[i] = urb; - usb_bufs->transfer_buffer[i] = usb_alloc_coherent(udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!usb_bufs->transfer_buffer[i]) { - dev_err(&dev->intf->dev, - "unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL); + if (!usb_bufs->buf[i]) { em28xx_uninit_usb_xfer(dev, mode); + + for (i--; i >= 0; i--) + kfree(usb_bufs->buf[i]); + + kfree(usb_bufs->buf); + usb_bufs->buf = NULL; + return -ENOMEM; } - memset(usb_bufs->transfer_buffer[i], 0, sb_size); + + urb->transfer_flags = URB_FREE_BUFFER; if (xfer_bulk) { /* bulk */ pipe = usb_rcvbulkpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_bulk : dev->dvb_ep_bulk); - usb_fill_bulk_urb(urb, udev, pipe, - usb_bufs->transfer_buffer[i], sb_size, - em28xx_irq_callback, dev); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->buf[i], + sb_size, em28xx_irq_callback, dev); } else { /* isoc */ pipe = usb_rcvisocpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_isoc : dev->dvb_ep_isoc); - usb_fill_int_urb(urb, udev, pipe, - usb_bufs->transfer_buffer[i], sb_size, - em28xx_irq_callback, dev, 1); - urb->transfer_flags = URB_ISO_ASAP | - URB_NO_TRANSFER_DMA_MAP; + usb_fill_int_urb(urb, udev, pipe, usb_bufs->buf[i], + sb_size, em28xx_irq_callback, dev, 1); + urb->transfer_flags |= URB_ISO_ASAP; k = 0; for (j = 0; j < usb_bufs->num_packets; j++) { urb->iso_frame_desc[j].offset = k; @@ -1005,8 +1015,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, int rc; int alloc; - em28xx_isocdbg("em28xx: called em28xx_init_usb_xfer in mode %d\n", - mode); + em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode); dev->usb_ctl.urb_data_copy = urb_data_copy; @@ -1077,7 +1086,11 @@ int em28xx_register_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->init(dev); + if (ops->init) { + ops->init(dev); + if (dev->dev_next) + ops->init(dev->dev_next); + } } mutex_unlock(&em28xx_devlist_mutex); pr_info("em28xx: Registered (%s) extension\n", ops->name); @@ -1091,7 +1104,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->fini(dev); + if (ops->fini) { + if (dev->dev_next) + ops->fini(dev->dev_next); + ops->fini(dev); + } } list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); @@ -1106,8 +1123,11 @@ void em28xx_init_extension(struct em28xx *dev) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&dev->devlist, &em28xx_devlist); list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->init) + if (ops->init) { ops->init(dev); + if (dev->dev_next) + ops->init(dev->dev_next); + } } mutex_unlock(&em28xx_devlist_mutex); } @@ -1118,8 +1138,11 @@ void em28xx_close_extension(struct em28xx *dev) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->fini) + if (ops->fini) { + if (dev->dev_next) + ops->fini(dev->dev_next); ops->fini(dev); + } } list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); @@ -1134,6 +1157,8 @@ int em28xx_suspend_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) ops->suspend(dev); + if (dev->dev_next) + ops->suspend(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); return 0; @@ -1148,6 +1173,8 @@ int em28xx_resume_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) ops->resume(dev); + if (dev->dev_next) + ops->resume(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 8a81c94a8a27..a54cb8dc52c9 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1,25 +1,25 @@ -/* - DVB device driver for em28xx - - (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org> - - (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> - - Fixes for the driver to properly work with HVR-950 - - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick - - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 - - (c) 2008 Aidan Thornton <makosoft@googlemail.com> - - (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> - - Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: - (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> - (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] - - 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// DVB device driver for em28xx +// +// (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org> +// +// (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> +// - Fixes for the driver to properly work with HVR-950 +// - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick +// - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 +// +// (c) 2008 Aidan Thornton <makosoft@googlemail.com> +// +// (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: +// (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> +// (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] +// +// 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 version 2 of the License. #include "em28xx.h" @@ -64,7 +64,7 @@ #include "qm1d1c0042.h" MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface"); MODULE_VERSION(EM28XX_VERSION); @@ -96,7 +96,7 @@ struct em28xx_dvb { struct dvb_net net; /* Due to DRX-K - probably need changes */ - int (*gate_ctrl)(struct dvb_frontend *, int); + int (*gate_ctrl)(struct dvb_frontend *fe, int gate); struct semaphore pll_mutex; bool dont_attach_fe1; int lna_gpio; @@ -199,7 +199,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) int rc; struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv; struct em28xx *dev = i2c_bus->dev; - struct usb_device *udev = interface_to_usbdev(dev->intf); int dvb_max_packet_size, packet_multiplier, dvb_alt; if (dev->dvb_xfer_bulk) { @@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) dvb_alt = dev->dvb_alt_isoc; } - usb_set_interface(udev, dev->ifnum, dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; @@ -278,14 +276,13 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed) mutex_lock(&dvb->lock); dvb->nfeeds--; - if (0 == dvb->nfeeds) + if (!dvb->nfeeds) err = em28xx_stop_streaming(dvb); mutex_unlock(&dvb->lock); return err; } - /* ------------------------------------------------------------------ */ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { @@ -358,7 +355,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK }; static struct tda18271_std_map kworld_a340_std_map = { @@ -514,14 +511,15 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) em28xx_gpio_set(dev, hauppauge_hvr930c_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, hauppauge_hvr930c_end); msleep(100); @@ -530,8 +528,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) msleep(30); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); - msleep(10); - + usleep_range(10000, 11000); } static void terratec_h5_init(struct em28xx *dev) @@ -571,14 +568,15 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_h5_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_h5_end); }; @@ -624,14 +622,15 @@ static void terratec_htc_stick_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_htc_stick_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_stick_end); }; @@ -682,14 +681,15 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_htc_usb_xs_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_usb_xs_end); }; @@ -718,7 +718,8 @@ static void pctv_520e_init(struct em28xx *dev) dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */ for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); }; static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) @@ -780,7 +781,7 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) static u8 tuner_go[] = { TUNER_GO, 0x01}; mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); + usleep_range(200, 250); mt352_write(fe, reset, sizeof(reset)); mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); mt352_write(fe, agc_cfg, sizeof(agc_cfg)); @@ -840,8 +841,8 @@ static void px_bcud_init(struct em28xx *dev) /* sleeping ISDB-T */ dev->dvb->i2c_client_demod->addr = 0x14; for (i = 0; i < ARRAY_SIZE(regs1); i++) - i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r, - regs1[i].len); + i2c_master_send(dev->dvb->i2c_client_demod, + regs1[i].r, regs1[i].len); /* sleeping ISDB-S */ dev->dvb->i2c_client_demod->addr = 0x15; for (i = 0; i < ARRAY_SIZE(regs2); i++) @@ -934,7 +935,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = { /* ------------------------------------------------------------------ */ -static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) +static noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; @@ -1077,7 +1078,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); /* If the analog part won't create RF connectors, DVB will do it */ - if (!dev->has_video || (dev->tuner_type == TUNER_ABSENT)) + if (!dev->has_video || dev->tuner_type == TUNER_ABSENT) create_rf_connector = true; result = dvb_create_media_graph(&dvb->adapter, create_rf_connector); @@ -1126,10 +1127,285 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) dvb_unregister_adapter(&dvb->adapter); } +static int em28174_dvb_init_pctv_460e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct tda10071_platform_data tda10071_pdata = {}; + struct a8293_platform_data a8293_pdata = {}; + + /* attach demod + tuner combo */ + tda10071_pdata.clk = 40444000; /* 40.444 MHz */ + tda10071_pdata.i2c_wr_max = 64; + tda10071_pdata.ts_mode = TDA10071_TS_SERIAL; + tda10071_pdata.pll_multiplier = 20; + tda10071_pdata.tuner_i2c_addr = 0x14; + + dvb->i2c_client_demod = dvb_module_probe("tda10071", "tda10071_cx24118", + &dev->i2c_adap[dev->def_i2c_bus], + 0x55, &tda10071_pdata); + if (!dvb->i2c_client_demod) + return -ENODEV; + + dvb->fe[0] = tda10071_pdata.get_dvb_frontend(dvb->i2c_client_demod); + + /* attach SEC */ + a8293_pdata.dvb_frontend = dvb->fe[0]; + + dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x08, &a8293_pdata); + if (!dvb->i2c_client_sec) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + return 0; +} + +static int em28178_dvb_init_pctv_461e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *i2c_adapter; + struct m88ds3103_platform_data m88ds3103_pdata = {}; + struct ts2020_config ts2020_config = {}; + struct a8293_platform_data a8293_pdata = {}; + + /* attach demod */ + m88ds3103_pdata.clk = 27000000; + m88ds3103_pdata.i2c_wr_max = 33; + m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; + m88ds3103_pdata.ts_clk = 16000; + m88ds3103_pdata.ts_clk_pol = 1; + m88ds3103_pdata.agc = 0x99; + + dvb->i2c_client_demod = dvb_module_probe("m88ds3103", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x68, &m88ds3103_pdata); + if (!dvb->i2c_client_demod) + return -ENODEV; + + dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod); + i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod); + + /* attach tuner */ + ts2020_config.fe = dvb->fe[0]; + + dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022", + i2c_adapter, + 0x60, &ts2020_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + /* delegate signal strength measurement to tuner */ + dvb->fe[0]->ops.read_signal_strength = + dvb->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SEC */ + a8293_pdata.dvb_frontend = dvb->fe[0]; + dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x08, &a8293_pdata); + if (!dvb->i2c_client_sec) { + dvb_module_release(dvb->i2c_client_tuner); + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + return 0; +} + +static int em28178_dvb_init_pctv_292e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; + + /* attach demod */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + si2168_config.spectral_inversion = true; + + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x64, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; + + /* attach tuner */ + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; + + return 0; +} + +static int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; + + /* attach demod */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x64, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 0; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + dvb->i2c_client_tuner = dvb_module_probe("si2157", "si2146", + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + return 0; +} + +static int em28178_dvb_init_plex_px_bcud(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct tc90522_config tc90522_config = {}; + struct qm1d1c0042_config qm1d1c0042_config = {}; + + /* attach demod */ + dvb->i2c_client_demod = dvb_module_probe("tc90522", "tc90522sat", + &dev->i2c_adap[dev->def_i2c_bus], + 0x15, &tc90522_config); + if (!dvb->i2c_client_demod) + return -ENODEV; + + /* attach tuner */ + qm1d1c0042_config.fe = tc90522_config.fe; + qm1d1c0042_config.lpf = 1; + + dvb->i2c_client_tuner = dvb_module_probe("qm1d1c0042", NULL, + tc90522_config.tuner_i2c, + 0x61, &qm1d1c0042_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + dvb->fe[0] = tc90522_config.fe; + px_bcud_init(dev); + + return 0; +} + +static int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; + unsigned char addr; + + /* attach demod */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.spectral_inversion = true; + addr = (dev->ts == PRIMARY_TS) ? 0x64 : 0x67; + + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + addr, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x63; + + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + addr, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + return 0; +} + +static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct lgdt3306a_config lgdt3306a_config = {}; + struct si2157_config si2157_config = {}; + unsigned char addr; + + /* attach demod */ + lgdt3306a_config = hauppauge_01595_lgdt3306a_config; + lgdt3306a_config.fe = &dvb->fe[0]; + lgdt3306a_config.i2c_adapter = &adapter; + addr = (dev->ts == PRIMARY_TS) ? 0x59 : 0x0e; + + dvb->i2c_client_demod = dvb_module_probe("lgdt3306a", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + addr, &lgdt3306a_config); + if (!dvb->i2c_client_demod) + return -ENODEV; + + /* attach tuner */ + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; + si2157_config.inversion = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x62; + + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; + } + + return 0; +} + static int em28xx_dvb_init(struct em28xx *dev) { - int result = 0; + int result = 0, dvb_alt = 0; struct em28xx_dvb *dvb; + struct usb_device *udev; if (dev->is_audio_only) { /* Shouldn't initialize IR for this interface */ @@ -1143,12 +1419,13 @@ static int em28xx_dvb_init(struct em28xx *dev) dev_info(&dev->intf->dev, "Binding DVB extension\n"); - dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); + dvb = kzalloc(sizeof(*dvb), GFP_KERNEL); if (!dvb) return -ENOMEM; dev->dvb = dvb; - dvb->fe[0] = dvb->fe[1] = NULL; + dvb->fe[0] = NULL; + dvb->fe[1] = NULL; /* pre-allocate DVB usb transfer buffers */ if (dev->dvb_xfer_bulk) { @@ -1178,7 +1455,8 @@ static int em28xx_dvb_init(struct em28xx *dev) switch (dev->model) { case EM2874_BOARD_LEADERSHIP_ISDBT: dvb->fe[0] = dvb_attach(s921_attach, - &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]); + &sharp_isdbt, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; @@ -1191,8 +1469,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->fe[0] = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap[dev->def_i2c_bus]); + &em2880_lgdt3303_dev, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1200,8 +1478,8 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2880_BOARD_KWORLD_DVB_310U: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_with_xc3028, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1211,8 +1489,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2882_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1223,16 +1501,17 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2881_BOARD_PINNACLE_HYBRID_PRO: case EM2882_BOARD_DIKOM_DK300: case EM2882_BOARD_KWORLD_VS_DVBT: + /* + * Those boards could have either a zl10353 or a mt352. + * If the chip id isn't for zl10353, try mt352. + */ dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] == NULL) { - /* This board could have either a zl10353 or a mt352. - If the chip id isn't for zl10353, try mt352 */ + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap[dev->def_i2c_bus]); + if (!dvb->fe[0]) dvb->fe[0] = dvb_attach(mt352_attach, - &terratec_xs_mt352_cfg, - &dev->i2c_adap[dev->def_i2c_bus]); - } + &terratec_xs_mt352_cfg, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; @@ -1241,27 +1520,28 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2870_BOARD_TERRATEC_XS_MT2060: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_no_i2c_gate_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { dvb_attach(mt2060_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], - &em28xx_mt2060_config, 1220); + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_mt2060_config, 1220); } break; case EM2870_BOARD_KWORLD_355U: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_no_i2c_gate_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) dvb_attach(qt1010_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config); + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_qt1010_config); break; case EM2883_BOARD_KWORLD_HYBRID_330U: case EM2882_BOARD_EVGA_INDTUBE: dvb->fe[0] = dvb_attach(s5h1409_attach, - &em28xx_s5h1409_with_xc3028, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_s5h1409_with_xc3028, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1269,9 +1549,9 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2882_BOARD_KWORLD_ATSC_315U: dvb->fe[0] = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { + &em2880_lgdt3303_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) { @@ -1293,8 +1573,9 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2870_BOARD_REDDO_DVB_C_USB_BOX: /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ dvb->fe[0] = dvb_attach(tda10023_attach, - &em28xx_tda10023_config, - &dev->i2c_adap[dev->def_i2c_bus], 0x48); + &em28xx_tda10023_config, + &dev->i2c_adap[dev->def_i2c_bus], + 0x48); if (dvb->fe[0]) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], @@ -1306,18 +1587,18 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2870_BOARD_KWORLD_A340: dvb->fe[0] = dvb_attach(lgdt3305_attach, - &em2870_lgdt3304_dev, - &dev->i2c_adap[dev->def_i2c_bus]); + &em2870_lgdt3304_dev, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; } if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, &dev->i2c_adap[dev->def_i2c_bus], - &kworld_a340_config)) { - dvb_frontend_detach(dvb->fe[0]); - result = -EINVAL; - goto out_free; + &kworld_a340_config)) { + dvb_frontend_detach(dvb->fe[0]); + result = -EINVAL; + goto out_free; } break; case EM28174_BOARD_PCTV_290E: @@ -1335,7 +1616,6 @@ static int em28xx_dvb_init(struct em28xx *dev) 0x60, &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { - dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -1360,12 +1640,13 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: { - struct xc5000_config cfg; + struct xc5000_config cfg = {}; hauppauge_hvr930c_init(dev); dvb->fe[0] = dvb_attach(drxk_attach, - &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]); + &hauppauge_930c_drxk, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1377,14 +1658,13 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; /* Attach xc5000 */ - memset(&cfg, 0, sizeof(cfg)); cfg.i2c_address = 0x61; cfg.if_khz = 4000; if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], - &cfg)) { + if (!dvb_attach(xc5000_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], &cfg)) { result = -EINVAL; goto out_free; } @@ -1396,7 +1676,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2884_BOARD_TERRATEC_H5: terratec_h5_init(dev); - dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]); + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1410,7 +1691,8 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Attach tda18271 to DVB-C frontend */ if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { + if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { result = -EINVAL; goto out_free; } @@ -1420,72 +1702,23 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2884_BOARD_C3TECH_DIGITAL_DUO: dvb->fe[0] = dvb_attach(mb86a20s_attach, - &c3tech_duo_mb86a20s_config, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) + &c3tech_duo_mb86a20s_config, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) dvb_attach(tda18271_attach, dvb->fe[0], 0x60, &dev->i2c_adap[dev->def_i2c_bus], &c3tech_duo_tda18271_config); break; - case EM28174_BOARD_PCTV_460E: { - struct i2c_client *client; - struct i2c_board_info board_info; - struct tda10071_platform_data tda10071_pdata = {}; - struct a8293_platform_data a8293_pdata = {}; - - /* attach demod + tuner combo */ - tda10071_pdata.clk = 40444000, /* 40.444 MHz */ - tda10071_pdata.i2c_wr_max = 64, - tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, - tda10071_pdata.pll_multiplier = 20, - tda10071_pdata.tuner_i2c_addr = 0x14, - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); - board_info.addr = 0x55; - board_info.platform_data = &tda10071_pdata; - request_module("tda10071"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; + case EM28174_BOARD_PCTV_460E: + result = em28174_dvb_init_pctv_460e(dev); + if (result) goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client); - dvb->i2c_client_demod = client; - - /* attach SEC */ - a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_sec = client; break; - } case EM2874_BOARD_DELOCK_61959: case EM2874_BOARD_MAXMEDIA_UB425_TC: /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, - &dev->i2c_adap[dev->def_i2c_bus]); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* disable I2C-gate */ @@ -1507,7 +1740,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, - &dev->i2c_adap[dev->def_i2c_bus]); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* attach tuner */ @@ -1579,13 +1812,7 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2874_BOARD_KWORLD_UB435Q_V3: { - struct i2c_client *client; struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus]; - struct i2c_board_info board_info = { - .type = "tda18212", - .addr = 0x60, - .platform_data = &kworld_ub435q_v3_config, - }; dvb->fe[0] = dvb_attach(lgdt3305_attach, &em2874_lgdt3305_nogate_dev, @@ -1597,28 +1824,23 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach tuner */ kworld_ub435q_v3_config.fe = dvb->fe[0]; - request_module("tda18212"); - client = i2c_new_device(adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dvb->fe[0]); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL, + adapter, 0x60, + &kworld_ub435q_v3_config); + if (!dvb->i2c_client_tuner) { dvb_frontend_detach(dvb->fe[0]); result = -ENODEV; goto out_free; } - - dvb->i2c_client_tuner = client; break; } case EM2874_BOARD_PCTV_HD_MINI_80E: - dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { - dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + dvb->fe[0] = dvb_attach(drx39xxj_attach, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { + dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], + 0x60, &dev->i2c_adap[dev->def_i2c_bus], &pinnacle_80e_dvb_config); if (!dvb->fe[0]) { @@ -1627,410 +1849,42 @@ static int em28xx_dvb_init(struct em28xx *dev) } } break; - case EM28178_BOARD_PCTV_461E: { - struct i2c_client *client; - struct i2c_adapter *i2c_adapter; - struct i2c_board_info board_info; - struct m88ds3103_platform_data m88ds3103_pdata = {}; - struct ts2020_config ts2020_config = {}; - struct a8293_platform_data a8293_pdata = {}; - - /* attach demod */ - m88ds3103_pdata.clk = 27000000; - m88ds3103_pdata.i2c_wr_max = 33; - m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; - m88ds3103_pdata.ts_clk = 16000; - m88ds3103_pdata.ts_clk_pol = 1; - m88ds3103_pdata.agc = 0x99; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); - board_info.addr = 0x68; - board_info.platform_data = &m88ds3103_pdata; - request_module("m88ds3103"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client); - i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client); - dvb->i2c_client_demod = client; - - /* attach tuner */ - ts2020_config.fe = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); - board_info.addr = 0x60; - board_info.platform_data = &ts2020_config; - request_module("ts2020"); - client = i2c_new_device(i2c_adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_tuner = client; - /* delegate signal strength measurement to tuner */ - dvb->fe[0]->ops.read_signal_strength = - dvb->fe[0]->ops.tuner_ops.get_rf_strength; - - /* attach SEC */ - a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; + case EM28178_BOARD_PCTV_461E: + result = em28178_dvb_init_pctv_461e(dev); + if (result) goto out_free; - } - dvb->i2c_client_sec = client; break; - } case EM28178_BOARD_PCTV_292E: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; - } + result = em28178_dvb_init_pctv_292e(dev); + if (result) + goto out_free; break; case EM28178_BOARD_TERRATEC_T2_STICK_HD: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 0; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2146", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - } + result = em28178_dvb_init_terratec_t2_stick_hd(dev); + if (result) + goto out_free; break; - case EM28178_BOARD_PLEX_PX_BCUD: - { - struct i2c_client *client; - struct i2c_board_info info; - struct tc90522_config tc90522_config; - struct qm1d1c0042_config qm1d1c0042_config; - - /* attach demod */ - memset(&tc90522_config, 0, sizeof(tc90522_config)); - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); - info.addr = 0x15; - info.platform_data = &tc90522_config; - request_module("tc90522"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_demod = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - /* attach tuner */ - memset(&qm1d1c0042_config, 0, - sizeof(qm1d1c0042_config)); - qm1d1c0042_config.fe = tc90522_config.fe; - qm1d1c0042_config.lpf = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); - info.addr = 0x61; - info.platform_data = &qm1d1c0042_config; - request_module(info.type); - client = i2c_new_device(tc90522_config.tuner_i2c, - &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_tuner = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = tc90522_config.fe; - px_bcud_init(dev); - } + result = em28178_dvb_init_plex_px_bcud(dev); + if (result) + goto out_free; break; case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_SERIAL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - - } + result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev); + if (result) + goto out_free; break; case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info = {}; - struct lgdt3306a_config lgdt3306a_config; - struct si2157_config si2157_config = {}; - - /* attach demod */ - lgdt3306a_config = hauppauge_01595_lgdt3306a_config; - lgdt3306a_config.fe = &dvb->fe[0]; - lgdt3306a_config.i2c_adapter = &adapter; - strlcpy(info.type, "lgdt3306a", sizeof(info.type)); - info.addr = 0x59; - info.platform_data = &lgdt3306a_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], - &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; - si2157_config.inversion = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", sizeof(info.type)); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - } + result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev); + if (result) + goto out_free; break; default: dev_err(&dev->intf->dev, "The frontend of your DVB/ATSC card isn't supported yet\n"); break; } - if (NULL == dvb->fe[0]) { + if (!dvb->fe[0]) { dev_err(&dev->intf->dev, "frontend initialization failed\n"); result = -EINVAL; goto out_free; @@ -2046,6 +1900,14 @@ static int em28xx_dvb_init(struct em28xx *dev) if (result < 0) goto out_free; + if (dev->dvb_xfer_bulk) { + dvb_alt = 0; + } else { /* isoc */ + dvb_alt = dev->dvb_alt_isoc; + } + + udev = interface_to_usbdev(dev->intf); + usb_set_interface(udev, dev->ifnum, dvb_alt); dev_info(&dev->intf->dev, "DVB extension successfully initialized\n"); kref_get(&dev->ref); @@ -2071,7 +1933,6 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops) static int em28xx_dvb_fini(struct em28xx *dev) { struct em28xx_dvb *dvb; - struct i2c_client *client; if (dev->is_audio_only) { /* Shouldn't initialize IR for this interface */ @@ -2093,8 +1954,10 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); if (dev->disconnected) { - /* We cannot tell the device to sleep - * once it has been unplugged. */ + /* + * We cannot tell the device to sleep + * once it has been unplugged. + */ if (dvb->fe[0]) { prevent_sleep(&dvb->fe[0]->ops); dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED; @@ -2107,26 +1970,10 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_unregister_dvb(dvb); - /* remove I2C SEC */ - client = dvb->i2c_client_sec; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - /* remove I2C tuner */ - client = dvb->i2c_client_tuner; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - /* remove I2C demod */ - client = dvb->i2c_client_demod; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + /* release I2C module bindings */ + dvb_module_release(dvb->i2c_client_sec); + dvb_module_release(dvb->i2c_client_tuner); + dvb_module_release(dvb->i2c_client_demod); kfree(dvb); dev->dvb = NULL; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9bf49d666e5a..9151bccd859a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -1,26 +1,22 @@ -/* - em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> +// Markus Rechberger <mrechberger@gmail.com> +// Mauro Carvalho Chehab <mchehab@infradead.org> +// Sascha Sommer <saschasommer@freenet.de> +// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// 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 "em28xx.h" @@ -50,6 +46,35 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I "i2c: %s: " fmt, __func__, ## arg); \ } while (0) +/* + * Time in msecs to wait for i2c xfers to finish. + * 35ms is the maximum time a SMBUS device could wait when + * clock stretching is used. As the transfer itself will take + * some time to happen, set it to 35 ms. + * + * Ok, I2C doesn't specify any limit. So, eventually, we may need + * to increase this timeout. + */ +#define EM28XX_I2C_XFER_TIMEOUT 35 /* ms */ + +static int em28xx_i2c_timeout(struct em28xx *dev) +{ + int time = EM28XX_I2C_XFER_TIMEOUT; + + switch (dev->i2c_speed & 0x03) { + case EM28XX_I2C_FREQ_25_KHZ: + time += 4; /* Assume 4 ms for transfers */ + break; + case EM28XX_I2C_FREQ_100_KHZ: + case EM28XX_I2C_FREQ_400_KHZ: + time += 1; /* Assume 1 ms for transfers */ + break; + default: /* EM28XX_I2C_FREQ_1_5_MHZ */ + break; + } + + return msecs_to_jiffies(time); +} /* * em2800_i2c_send_bytes() @@ -57,14 +82,13 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I */ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); int ret; u8 b2[6]; if (len < 1 || len > 4) return -EOPNOTSUPP; - BUG_ON(len < 1 || len > 4); b2[5] = 0x80 + len - 1; b2[4] = addr; b2[3] = buf[0]; @@ -98,7 +122,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) ret); return ret; } - msleep(5); + usleep_range(5000, 6000); } dprintk(0, "write to i2c device at 0x%x timed out\n", addr); return -ETIMEDOUT; @@ -110,7 +134,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) */ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); u8 buf2[4]; int ret; int i; @@ -145,14 +169,13 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) ret); return ret; } - msleep(5); + usleep_range(5000, 6000); } - if (ret != 0x84 + len - 1) { + if (ret != 0x84 + len - 1) dprintk(0, "read from i2c device at 0x%x timed out\n", addr); - } /* get the received message */ - ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); + ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4 - len, buf2, len); if (ret != len) { dev_warn(&dev->intf->dev, "reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", @@ -186,7 +209,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len, int stop) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); int ret; if (len < 1 || len > 64) @@ -204,12 +227,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; - } else { - dev_warn(&dev->intf->dev, - "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); - return -EIO; } + dev_warn(&dev->intf->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); + return -EIO; } /* wait for completion */ @@ -228,7 +250,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret); return ret; } - msleep(5); + usleep_range(5000, 6000); /* * NOTE: do we really have to wait for success ? * Never seen anything else than 0x00 or 0x10 @@ -351,12 +373,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; - } else { - dev_warn(&dev->intf->dev, - "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); - return -EIO; } + + dev_warn(&dev->intf->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); + return -EIO; } /* Check success */ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000); @@ -366,7 +388,8 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) { + + if (ret > 0) { dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -420,7 +443,8 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) { + + if (ret > 0) { dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -508,13 +532,15 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, { struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; struct em28xx *dev = i2c_bus->dev; - unsigned bus = i2c_bus->bus; + unsigned int bus = i2c_bus->bus; int addr, rc, i; u8 reg; - /* prevent i2c xfer attempts after device is disconnected - some fe's try to do i2c writes/reads from their release - interfaces when called in disconnect path */ + /* + * prevent i2c xfer attempts after device is disconnected + * some fe's try to do i2c writes/reads from their release + * interfaces when called in disconnect path + */ if (dev->disconnected) return -ENODEV; @@ -597,12 +623,13 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) if (len == length) { c = (char)len; len = -1; - } else + } else { c = *buf++; + } l = (l << 8) | c; len++; if ((len & (32 / 8 - 1)) == 0) - hash = ((hash^l) * 0x9e370001UL); + hash = ((hash ^ l) * 0x9e370001UL); } while (len); return (hash >> (32 - bits)) & 0xffffffffUL; @@ -612,7 +639,7 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) * Helper function to read data blocks from i2c clients with 8 or 16 bit * address width, 8 bit register width and auto incrementation been activated */ -static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, +static int em28xx_i2c_read_block(struct em28xx *dev, unsigned int bus, u16 addr, bool addr_w16, u16 len, u8 *data) { int remain = len, rsize, rsize_max, ret; @@ -624,7 +651,8 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, /* Select address */ buf[0] = addr >> 8; buf[1] = addr & 0xff; - ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16); + ret = i2c_master_send(&dev->i2c_client[bus], + buf + !addr_w16, 1 + addr_w16); if (ret < 0) return ret; /* Read data */ @@ -649,7 +677,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, return len; } -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, +static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned int bus, u8 **eedata, u16 *eedata_len) { const u16 len = 256; @@ -677,7 +705,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, } data = kzalloc(len, GFP_KERNEL); - if (data == NULL) + if (!data) return -ENOMEM; /* Read EEPROM content */ @@ -710,8 +738,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ dev_info(&dev->intf->dev, - "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n", + data, dev->hash); dev_info(&dev->intf->dev, "EEPROM info:\n"); dev_info(&dev->intf->dev, @@ -769,15 +797,18 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, return 0; } - /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */ + /* + * TODO: decrypt eeprom data for camera bridges + * (em25xx, em276x+) + */ } else if (!dev->eeprom_addrwidth_16bit && data[0] == 0x1a && data[1] == 0xeb && data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); dev_info(&dev->intf->dev, - "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n", + data, dev->hash); dev_info(&dev->intf->dev, "EEPROM info:\n"); } else { @@ -859,8 +890,8 @@ static u32 functionality(struct i2c_adapter *i2c_adap) { struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; - if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) || - (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) { + if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX || + i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) { return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) & @@ -893,7 +924,7 @@ static const struct i2c_client em28xx_client_template = { * incomplete list of known devices */ static char *i2c_devs[128] = { - [0x1c >> 1] = "lgdt330x", + [0x1c >> 1] = "lgdt330x", [0x3e >> 1] = "remote IR sensor", [0x4a >> 1] = "saa7113h", [0x52 >> 1] = "drxk", @@ -916,7 +947,7 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus) { u8 i2c_devicelist[128]; unsigned char buf; @@ -944,13 +975,14 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) * em28xx_i2c_register() * register i2c bus */ -int em28xx_i2c_register(struct em28xx *dev, unsigned bus, +int em28xx_i2c_register(struct em28xx *dev, unsigned int bus, enum em28xx_i2c_algo_type algo_type) { int retval; - BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); - BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); + if (WARN_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg || + !dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req)) + return -ENODEV; if (bus >= NUM_I2C_BUSES) return -ENODEV; @@ -977,8 +1009,9 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, /* Up to now, all eeproms are at bus 0 */ if (!bus) { - retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); - if ((retval < 0) && (retval != -ENODEV)) { + retval = em28xx_i2c_eeprom(dev, bus, + &dev->eedata, &dev->eedata_len); + if (retval < 0 && retval != -ENODEV) { dev_err(&dev->intf->dev, "%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); @@ -995,7 +1028,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, * em28xx_i2c_unregister() * unregister i2c_bus */ -int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus) +int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus) { if (bus >= NUM_I2C_BUSES) return -ENODEV; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 046223de1e91..2dc1be00b8b8 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -1,25 +1,21 @@ -/* - handle em28xx IR remotes via linux kernel input layer. - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// handle em28xx IR remotes via linux kernel input layer. +// +// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> +// Markus Rechberger <mrechberger@gmail.com> +// Mauro Carvalho Chehab <mchehab@infradead.org> +// Sascha Sommer <saschasommer@freenet.de> +// +// 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 "em28xx.h" @@ -41,15 +37,15 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define MODULE_NAME "em28xx" -#define dprintk( fmt, arg...) do { \ +#define dprintk(fmt, arg...) do { \ if (ir_debug) \ dev_printk(KERN_DEBUG, &ir->dev->intf->dev, \ "input: %s: " fmt, __func__, ## arg); \ } while (0) -/********************************************************** - Polling structure used by em28xx IR's - **********************************************************/ +/* + * Polling structure used by em28xx IR's + */ struct em28xx_ir_poll_result { unsigned int toggle_bit:1; @@ -76,24 +72,31 @@ struct em28xx_IR { int (*get_key_i2c)(struct i2c_client *ir, enum rc_proto *protocol, u32 *scancode); - int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); + int (*get_key)(struct em28xx_IR *ir, struct em28xx_ir_poll_result *r); }; -/********************************************************** - I2C IR based get keycodes - should be used with ir-kbd-i2c - **********************************************************/ +/* + * I2C IR based get keycodes - should be used with ir-kbd-i2c + */ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, enum rc_proto *protocol, u32 *scancode) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(i2c_dev, &b, 1)) + rc = i2c_master_recv(i2c_dev, &b, 1); + if (rc != 1) { + if (rc < 0) + return rc; return -EIO; + } - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold down. */ + /* + * it seems that 0xFE indicates that a button is still hold + * down, while 0xff indicates that no button is hold down. + */ if (b == 0xff) return 0; @@ -145,7 +148,7 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev, /* poll IR chip */ - if (3 != i2c_master_recv(i2c_dev, buf, 3)) + if (i2c_master_recv(i2c_dev, buf, 3) != 3) return -EIO; if (buf[0] != 0x00) @@ -162,18 +165,28 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, { unsigned char subaddr, keydetect, key; - struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1}, - { .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} }; + struct i2c_msg msg[] = { + { + .addr = i2c_dev->addr, + .flags = 0, + .buf = &subaddr, .len = 1 + }, { + .addr = i2c_dev->addr, + .flags = I2C_M_RD, + .buf = &keydetect, + .len = 1 + } + }; subaddr = 0x10; - if (2 != i2c_transfer(i2c_dev->adapter, msg, 2)) + if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2) return -EIO; if (keydetect == 0x00) return 0; subaddr = 0x00; msg[1].buf = &key; - if (2 != i2c_transfer(i2c_dev->adapter, msg, 2)) + if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2) return -EIO; if (key == 0x00) return 0; @@ -183,9 +196,9 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, return 1; } -/********************************************************** - Poll based get keycode functions - **********************************************************/ +/* + * Poll based get keycode functions + */ /* This is for the em2860/em2880 */ static int default_polling_getkey(struct em28xx_IR *ir, @@ -195,8 +208,9 @@ static int default_polling_getkey(struct em28xx_IR *ir, int rc; u8 msg[3] = { 0, 0, 0 }; - /* Read key toggle, brand, and key code - on registers 0x45, 0x46 and 0x47 + /* + * Read key toggle, brand, and key code + * on registers 0x45, 0x46 and 0x47 */ rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, msg, sizeof(msg)); @@ -237,8 +251,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, int rc; u8 msg[5] = { 0, 0, 0, 0, 0 }; - /* Read key toggle, brand, and key code - on registers 0x51-55 + /* + * Read key toggle, brand, and key code + * on registers 0x51-55 */ rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, msg, sizeof(msg)); @@ -294,9 +309,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, return 0; } -/********************************************************** - Polling code for em28xx - **********************************************************/ +/* + * Polling code for em28xx + */ static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir) { @@ -347,11 +362,14 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) if (ir->dev->chip_id == CHIP_ID_EM2874 || ir->dev->chip_id == CHIP_ID_EM2884) - /* The em2874 clears the readcount field every time the - register is read. The em2860/2880 datasheet says that it - is supposed to clear the readcount, but it doesn't. So with - the em2874, we are looking for a non-zero read count as - opposed to a readcount that is incrementing */ + /* + * The em2874 clears the readcount field every time the + * register is read. The em2860/2880 datasheet says + * that it is supposed to clear the readcount, but it + * doesn't. So with the em2874, we are looking for a + * non-zero read count as opposed to a readcount + * that is incrementing + */ ir->last_readcount = 0; else ir->last_readcount = poll_result.read_count; @@ -476,15 +494,18 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto) static int em28xx_probe_i2c_ir(struct em28xx *dev) { int i = 0; - /* Leadtek winfast tv USBII deluxe can find a non working IR-device */ - /* at address 0x18, so if that address is needed for another board in */ - /* the future, please put it after 0x1f. */ + /* + * Leadtek winfast tv USBII deluxe can find a non working IR-device + * at address 0x18, so if that address is needed for another board in + * the future, please put it after 0x1f. + */ const unsigned short addr_list[] = { 0x1f, 0x30, 0x47, I2C_CLIENT_END }; while (addr_list[i] != I2C_CLIENT_END) { - if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1) + if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], + addr_list[i]) == 1) return addr_list[i]; i++; } @@ -492,9 +513,9 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) return -ENODEV; } -/********************************************************** - Handle buttons - **********************************************************/ +/* + * Handle buttons + */ static void em28xx_query_buttons(struct work_struct *work) { @@ -515,7 +536,10 @@ static void em28xx_query_buttons(struct work_struct *work) j = 0; while (dev->board.buttons[j].role >= 0 && dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) { - struct em28xx_button *button = &dev->board.buttons[j]; + const struct em28xx_button *button; + + button = &dev->board.buttons[j]; + /* Check if button uses the current address */ if (button->reg_r != dev->button_polling_addresses[i]) { j++; @@ -618,7 +642,8 @@ static void em28xx_init_buttons(struct em28xx *dev) dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL; while (dev->board.buttons[i].role >= 0 && dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) { - struct em28xx_button *button = &dev->board.buttons[i]; + const struct em28xx_button *button = &dev->board.buttons[i]; + /* Check if polling address is already on the list */ addr_new = true; for (j = 0; j < dev->num_button_polling_addresses; j++) { @@ -649,6 +674,7 @@ static void em28xx_init_buttons(struct em28xx *dev) /* Add read address to list of polling addresses */ if (addr_new) { unsigned int index = dev->num_button_polling_addresses; + dev->button_polling_addresses[index] = button->reg_r; dev->num_button_polling_addresses++; } @@ -677,7 +703,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) /* Clear polling addresses list */ dev->num_button_polling_addresses = 0; /* Deregister input devices */ - if (dev->sbutton_input_dev != NULL) { + if (dev->sbutton_input_dev) { dev_info(&dev->intf->dev, "Deregistering snapshot button\n"); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; @@ -714,7 +740,7 @@ static int em28xx_ir_init(struct em28xx *dev) } } - if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { + if (!dev->board.ir_codes && !dev->board.has_ir_i2c) { /* No remote control support */ dev_warn(&dev->intf->dev, "Remote control support is not available for this card.\n"); @@ -764,7 +790,7 @@ static int em28xx_ir_init(struct em28xx *dev) goto error; } - ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + ir->i2c_client = kzalloc(sizeof(*ir->i2c_client), GFP_KERNEL); if (!ir->i2c_client) goto error; ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus]; @@ -881,9 +907,11 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); - /* is canceling delayed work sufficient or does the rc event - kthread needs stopping? kthread is stopped in - ir_raw_event_unregister() */ + /* + * is canceling delayed work sufficient or does the rc event + * kthread needs stopping? kthread is stopped in + * ir_raw_event_unregister() + */ return 0; } @@ -895,8 +923,10 @@ static int em28xx_ir_resume(struct em28xx *dev) return 0; dev_info(&dev->intf->dev, "Resuming input extension\n"); - /* if suspend calls ir_raw_event_unregister(), the should call - ir_raw_event_register() */ + /* + * if suspend calls ir_raw_event_unregister(), the should call + * ir_raw_event_register() + */ if (ir) schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); if (dev->num_button_polling_addresses) @@ -924,7 +954,7 @@ static void __exit em28xx_rc_unregister(void) em28xx_unregister_extension(&rc_ops); } -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - input interface"); MODULE_VERSION(EM28XX_VERSION); diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 9e5cdfb25a73..f53afe18e92d 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -1,17 +1,22 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#define EM_GPIO_0 (1 << 0) -#define EM_GPIO_1 (1 << 1) -#define EM_GPIO_2 (1 << 2) -#define EM_GPIO_3 (1 << 3) -#define EM_GPIO_4 (1 << 4) -#define EM_GPIO_5 (1 << 5) -#define EM_GPIO_6 (1 << 6) -#define EM_GPIO_7 (1 << 7) - -#define EM_GPO_0 (1 << 0) -#define EM_GPO_1 (1 << 1) -#define EM_GPO_2 (1 << 2) -#define EM_GPO_3 (1 << 3) + +/* + * em28xx-reg.h - Register definitions for em28xx driver + */ + +#define EM_GPIO_0 ((unsigned char)BIT(0)) +#define EM_GPIO_1 ((unsigned char)BIT(1)) +#define EM_GPIO_2 ((unsigned char)BIT(2)) +#define EM_GPIO_3 ((unsigned char)BIT(3)) +#define EM_GPIO_4 ((unsigned char)BIT(4)) +#define EM_GPIO_5 ((unsigned char)BIT(5)) +#define EM_GPIO_6 ((unsigned char)BIT(6)) +#define EM_GPIO_7 ((unsigned char)BIT(7)) + +#define EM_GPO_0 ((unsigned char)BIT(0)) +#define EM_GPO_1 ((unsigned char)BIT(1)) +#define EM_GPO_2 ((unsigned char)BIT(2)) +#define EM_GPO_3 ((unsigned char)BIT(3)) /* em28xx endpoints */ /* 0x82: (always ?) analog */ @@ -203,10 +208,11 @@ #define EM28XX_R43_AC97BUSY 0x43 #define EM28XX_R45_IR 0x45 - /* 0x45 bit 7 - parity bit - bits 6-0 - count - 0x46 IR brand - 0x47 IR data + /* + * 0x45 bit 7 - parity bit + * bits 6-0 - count + * 0x46 IR brand + * 0x47 IR data */ /* em2874 registers */ @@ -249,12 +255,12 @@ #define EM2874_IR_RC6_MODE_6A 0x0b /* em2874 Transport Stream Enable Register (0x5f) */ -#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) -#define EM2874_TS1_FILTER_ENABLE (1 << 1) -#define EM2874_TS1_NULL_DISCARD (1 << 2) -#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) -#define EM2874_TS2_FILTER_ENABLE (1 << 5) -#define EM2874_TS2_NULL_DISCARD (1 << 6) +#define EM2874_TS1_CAPTURE_ENABLE ((unsigned char)BIT(0)) +#define EM2874_TS1_FILTER_ENABLE ((unsigned char)BIT(1)) +#define EM2874_TS1_NULL_DISCARD ((unsigned char)BIT(2)) +#define EM2874_TS2_CAPTURE_ENABLE ((unsigned char)BIT(4)) +#define EM2874_TS2_FILTER_ENABLE ((unsigned char)BIT(5)) +#define EM2874_TS2_NULL_DISCARD ((unsigned char)BIT(6)) /* register settings */ #define EM2800_AUDIO_SRC_TUNER 0x0d diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h index 9c411aac3878..1788dbf9024a 100644 --- a/drivers/media/usb/em28xx/em28xx-v4l.h +++ b/drivers/media/usb/em28xx/em28xx-v4l.h @@ -1,17 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com> - - 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 version 2 of the License. - - 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. + * em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB + * video capture devices + * + * Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com> + * + * 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 version 2 of the License. + * + * 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. */ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index f5123651ef30..63c48361d3f2 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -1,25 +1,20 @@ -/* - em28xx-vbi.c - VBI driver for em28xx - - Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> - - This work was sponsored by EyeMagnet Limited. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-vbi.c - VBI driver for em28xx +// +// Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> +// +// This work was sponsored by EyeMagnet Limited. +// +// 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 "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index a2ba2d905952..d70ee13cc52e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1,30 +1,26 @@ -/* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> - - Some parts based on SN9C10x PC Camera Controllers GPL driver made - by Luca Risolia <luca.risolia@studio.unibo.it> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB +// video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> +// Markus Rechberger <mrechberger@gmail.com> +// Mauro Carvalho Chehab <mchehab@infradead.org> +// Sascha Sommer <saschasommer@freenet.de> +// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> +// +// Some parts based on SN9C10x PC Camera Controllers GPL driver made +// by Luca Risolia <luca.risolia@studio.unibo.it> +// +// 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 "em28xx.h" @@ -77,7 +73,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(EM28XX_VERSION); #define EM25XX_FRMDATAHDR_BYTE1 0x02 @@ -148,7 +144,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (dev->board.is_webcam) + if (dev->is_webcam) return v4l2->sensor_xres; if (dev->board.max_range_640_480) @@ -161,7 +157,7 @@ static inline unsigned int norm_maxh(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (dev->board.is_webcam) + if (dev->is_webcam) return v4l2->sensor_yres; if (dev->board.max_range_640_480) @@ -176,7 +172,7 @@ static int em28xx_vbi_supported(struct em28xx *dev) if (disable_vbi == 1) return 0; - if (dev->board.is_webcam) + if (dev->is_webcam) return 0; /* FIXME: check subdevices for VBI support */ @@ -250,7 +246,8 @@ static int em28xx_set_outfmt(struct em28xx *dev) if (em28xx_vbi_supported(dev) == 1) { vinctrl |= EM28XX_VINCTRL_VBI_RAW; em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); - em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4); + em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, + v4l2->vbi_width / 4); em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height); if (v4l2->norm & V4L2_STD_525_60) { /* NTSC */ @@ -320,8 +317,10 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) buf[0] = v; buf[1] = v >> 8; em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); - /* it seems that both H and V scalers must be active - to work correctly */ + /* + * it seems that both H and V scalers must be active + * to work correctly + */ mode = (h || v) ? 0x30 : 0x00; } return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode); @@ -345,13 +344,15 @@ static int em28xx_resolution_set(struct em28xx *dev) em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); - /* If we don't set the start position to 2 in VBI mode, we end up - with line 20/21 being YUYV encoded instead of being in 8-bit - greyscale. The core of the issue is that line 21 (and line 23 for - PAL WSS) are inside of active video region, and as a result they - get the pixelformatting associated with that area. So by cropping - it out, we end up with the same format as the rest of the VBI - region */ + /* + * If we don't set the start position to 2 in VBI mode, we end up + * with line 20/21 being YUYV encoded instead of being in 8-bit + * greyscale. The core of the issue is that line 21 (and line 23 for + * PAL WSS) are inside of active video region, and as a result they + * get the pixelformatting associated with that area. So by cropping + * it out, we end up with the same format as the rest of the VBI + * region + */ if (em28xx_vbi_supported(dev) == 1) em28xx_capture_area_set(dev, 0, 2, width, height); else @@ -365,14 +366,16 @@ static int em28xx_set_alternate(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); - int errCode; + int err; int i; unsigned int min_pkt_size = v4l2->width * 2 + 4; - /* NOTE: for isoc transfers, only alt settings > 0 are allowed - bulk transfers seem to work only with alt=0 ! */ + /* + * NOTE: for isoc transfers, only alt settings > 0 are allowed + * bulk transfers seem to work only with alt=0 ! + */ dev->alt = 0; - if ((alt > 0) && (alt < dev->num_alt)) { + if (alt > 0 && alt < dev->num_alt) { em28xx_videodbg("alternate forced to %d\n", dev->alt); dev->alt = alt; goto set_alt; @@ -380,9 +383,10 @@ static int em28xx_set_alternate(struct em28xx *dev) if (dev->analog_xfer_bulk) goto set_alt; - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. + /* + * When image size is bigger than a certain value, + * the frame size should be increased, otherwise, only + * green screen will be received. */ if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2) min_pkt_size *= 2; @@ -392,18 +396,22 @@ static int em28xx_set_alternate(struct em28xx *dev) if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { dev->alt = i; break; - /* otherwise make sure that we end up with the maximum bandwidth - because the min_pkt_size equation might be wrong... - */ + /* + * otherwise make sure that we end up with the maximum + * bandwidth because the min_pkt_size equation might be wrong. + * + */ } else if (dev->alt_max_pkt_size_isoc[i] > dev->alt_max_pkt_size_isoc[dev->alt]) dev->alt = i; } set_alt: - /* NOTE: for bulk transfers, we need to call usb_set_interface() + /* + * NOTE: for bulk transfers, we need to call usb_set_interface() * even if the previous settings were the same. Otherwise streaming - * fails with all urbs having status = -EOVERFLOW ! */ + * fails with all urbs having status = -EOVERFLOW ! + */ if (dev->analog_xfer_bulk) { dev->max_pkt_size = 512; /* USB 2.0 spec */ dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; @@ -416,19 +424,19 @@ set_alt: } em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(udev, dev->ifnum, dev->alt); - if (errCode < 0) { + err = usb_set_interface(udev, dev->ifnum, dev->alt); + if (err < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); - return errCode; + dev->alt, err); + return err; } return 0; } -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ +/* + * DMA and thread functions + */ /* * Finish the current buffer @@ -514,8 +522,9 @@ static void em28xx_copy_video(struct em28xx *dev, em28xx_isocdbg("Overflow of %zu bytes past buffer end(2)\n", ((char *)startwrite + lencopy) - ((char *)buf->vb_buf + buf->length)); - lencopy = remain = (char *)buf->vb_buf + buf->length - - (char *)startwrite; + remain = (char *)buf->vb_buf + buf->length - + (char *)startwrite; + lencopy = remain; } if (lencopy <= 0) break; @@ -623,11 +632,11 @@ finish_field_prepare_next(struct em28xx *dev, struct em28xx_v4l2 *v4l2 = dev->v4l2; if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */ - if (buf != NULL) + if (buf) finish_buffer(dev, buf); buf = get_next_buf(dev, dma_q); } - if (buf != NULL) { + if (buf) { buf->top_field = v4l2->top_field; buf->pos = 0; } @@ -648,13 +657,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, struct em28xx_dmaqueue *dma_q = &dev->vidq; struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; - /* capture type 0 = vbi start - capture type 1 = vbi in progress - capture type 2 = video start - capture type 3 = video in progress */ + /* + * capture type 0 = vbi start + * capture type 1 = vbi in progress + * capture type 2 = video start + * capture type 3 = video in progress + */ if (data_len >= 4) { - /* NOTE: Headers are always 4 bytes and - * never split across packets */ + /* + * NOTE: Headers are always 4 bytes and + * never split across packets + */ if (data_pkt[0] == 0x88 && data_pkt[1] == 0x88 && data_pkt[2] == 0x88 && data_pkt[3] == 0x88) { /* Continuation */ @@ -677,8 +690,10 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, data_len -= 4; } } - /* NOTE: With bulk transfers, intermediate data packets - * have no continuation header */ + /* + * NOTE: With bulk transfers, intermediate data packets + * have no continuation header + */ if (v4l2->capture_type == 0) { vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q); @@ -692,7 +707,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, (vbi_size - v4l2->vbi_read) : data_len; /* Copy VBI data */ - if (vbi_buf != NULL) + if (vbi_buf) em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len); v4l2->vbi_read += vbi_data_len; @@ -710,7 +725,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, v4l2->capture_type = 3; } - if (v4l2->capture_type == 3 && buf != NULL && data_len > 0) + if (v4l2->capture_type == 3 && buf && data_len > 0) em28xx_copy_video(dev, buf, data_pkt, data_len); } @@ -727,8 +742,10 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, bool frame_end = false; /* Check for header */ - /* NOTE: at least with bulk transfers, only the first packet - * has a header and has always set the FRAME_END bit */ + /* + * NOTE: at least with bulk transfers, only the first packet + * has a header and has always set the FRAME_END bit + */ if (data_len >= 2) { /* em25xx header is only 2 bytes long */ if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) && ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) { @@ -745,14 +762,15 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, buf = finish_field_prepare_next(dev, buf, dmaq); dev->usb_ctl.vid_buf = buf; } - /* NOTE: in ISOC mode when a new frame starts and buf==NULL, + /* + * NOTE: in ISOC mode when a new frame starts and buf==NULL, * we COULD already prepare a buffer here to avoid skipping the * first frame. */ } /* Copy data */ - if (buf != NULL && data_len > 0) + if (buf && data_len > 0) em28xx_copy_video(dev, buf, data_pkt, data_len); /* Finish frame (ISOC only) => avoids lag of 1 frame */ @@ -761,14 +779,17 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, dev->usb_ctl.vid_buf = buf; } - /* NOTE: Tested with USB bulk transfers only ! + /* + * NOTES: + * + * 1) Tested with USB bulk transfers only ! * The wording in the datasheet suggests that isoc might work different. * The current code assumes that with isoc transfers each packet has a * header like with the other em28xx devices. + * + * 2) Support for interlaced mode is pure theory. It has not been + * tested and it is unknown if these devices actually support it. */ - /* NOTE: Support for interlaced mode is pure theory. It has not been - * tested and it is unknown if these devices actually support it. */ - /* NOTE: No VBI support yet (these chips likely do not support VBI). */ } /* Processes and copies the URB data content (video and VBI data) */ @@ -829,12 +850,11 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) else process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len); - } return 1; } -static int get_ressource(enum v4l2_buf_type f_type) +static int get_resource(enum v4l2_buf_type f_type) { switch (f_type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -842,14 +862,15 @@ static int get_ressource(enum v4l2_buf_type f_type) case V4L2_BUF_TYPE_VBI_CAPTURE: return EM28XX_RESOURCE_VBI; default: - BUG(); + WARN_ON(1); + return -1; /* Indicate that device is busy */ } } /* Usage lock check functions */ static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type) { - int res_type = get_ressource(f_type); + int res_type = get_resource(f_type); /* is it free? */ if (dev->resources & res_type) { @@ -865,7 +886,7 @@ static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type) static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type) { - int res_type = get_ressource(f_type); + int res_type = get_resource(f_type); dev->resources &= ~res_type; em28xx_videodbg("res: put %d\n", res_type); @@ -937,10 +958,11 @@ static int em28xx_enable_analog_tuner(struct em28xx *dev) flags ? "enabled" : "disabled", ret); return ret; - } else - em28xx_videodbg("link %s->%s was %s\n", - source->name, sink->name, - flags ? "ENABLED" : "disabled"); + } + + em28xx_videodbg("link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); } #endif return 0; @@ -976,7 +998,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) } /* Webcams don't have input connectors */ - if (dev->board.is_webcam) + if (dev->is_webcam) return; /* Create entities for each input connector */ @@ -1016,10 +1038,9 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) #endif } - -/* ------------------------------------------------------------------ - Videobuf2 operations - ------------------------------------------------------------------*/ +/* + * Videobuf2 operations + */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, @@ -1072,8 +1093,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) em28xx_videodbg("%s\n", __func__); - /* Make sure streaming is not already in progress for this type - of filehandle (e.g. video, vbi) */ + /* + * Make sure streaming is not already in progress for this type + * of filehandle (e.g. video, vbi) + */ rc = res_get(dev, vq->type); if (rc) return rc; @@ -1084,9 +1107,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) /* Allocate the USB bandwidth */ em28xx_set_alternate(dev); - /* Needed, since GPIO might have disabled power of - some i2c device - */ + /* + * Needed, since GPIO might have disabled power of + * some i2c device + */ em28xx_wake_i2c(dev); v4l2->capture_type = -1; @@ -1145,7 +1169,7 @@ static void em28xx_stop_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); - if (dev->usb_ctl.vid_buf != NULL) { + if (dev->usb_ctl.vid_buf) { vb2_buffer_done(&dev->usb_ctl.vid_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); dev->usb_ctl.vid_buf = NULL; @@ -1180,7 +1204,7 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); - if (dev->usb_ctl.vbi_buf != NULL) { + if (dev->usb_ctl.vbi_buf) { vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); dev->usb_ctl.vbi_buf = NULL; @@ -1261,7 +1285,9 @@ static int em28xx_vb2_setup(struct em28xx *dev) return 0; } -/********************* v4l2 interface **************************************/ +/* + * v4l2 interface + */ static void video_mux(struct em28xx *dev, int index) { @@ -1277,7 +1303,7 @@ static void video_mux(struct em28xx *dev, int index) v4l2_device_call_all(v4l2_dev, 0, video, s_routing, INPUT(index)->vmux, 0, 0); - if (dev->board.has_msp34xx) { + if (dev->has_msp34xx) { if (dev->i2s_speed) { v4l2_device_call_all(v4l2_dev, 0, audio, s_i2s_clock_freq, dev->i2s_speed); @@ -1394,9 +1420,9 @@ static void scale_to_size(struct em28xx *dev, *height = 1; } -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ +/* + * IOCTL vidioc handling + */ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -1462,8 +1488,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, if (width == maxw && height == maxh) width /= 2; } else { - /* width must even because of the YUYV format - height must be even because of interlacing */ + /* + * width must even because of the YUYV format + * height must be even because of interlacing + */ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); } @@ -1493,7 +1521,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, - unsigned width, unsigned height) + unsigned int width, unsigned int height) { struct em28xx_fmt *fmt; struct em28xx_v4l2 *v4l2 = dev->v4l2; @@ -1582,17 +1610,26 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { + struct v4l2_subdev_frame_interval ival = { 0 }; struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; int rc = 0; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + p->parm.capture.readbuffers = EM28XX_MIN_BUF; - if (dev->board.is_webcam) + p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + if (dev->is_webcam) { rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0, - video, g_parm, p); - else + video, g_frame_interval, &ival); + if (!rc) + p->parm.capture.timeperframe = ival.interval; + } else { v4l2_video_std_frame_period(v4l2->norm, &p->parm.capture.timeperframe); + } return rc; } @@ -1601,10 +1638,27 @@ static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { struct em28xx *dev = video_drvdata(file); + struct v4l2_subdev_frame_interval ival = { + 0, + p->parm.capture.timeperframe + }; + int rc = 0; + + if (!dev->is_webcam) + return -ENOTTY; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + memset(&p->parm, 0, sizeof(p->parm)); p->parm.capture.readbuffers = EM28XX_MIN_BUF; - return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, - 0, video, s_parm, p); + p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0, + video, s_frame_interval, &ival); + if (!rc) + p->parm.capture.timeperframe = ival.interval; + return rc; } static int vidioc_enum_input(struct file *file, void *priv, @@ -1616,20 +1670,19 @@ static int vidioc_enum_input(struct file *file, void *priv, n = i->index; if (n >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(n)->type) + if (!INPUT(n)->type) return -EINVAL; - i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type)) + if (INPUT(n)->type == EM28XX_VMUX_TELEVISION) i->type = V4L2_INPUT_TYPE_TUNER; i->std = dev->v4l2->vdev.tvnorms; /* webcams do not have the STD API */ - if (dev->board.is_webcam) + if (dev->is_webcam) i->capabilities = 0; return 0; @@ -1650,7 +1703,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (i >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(i)->type) + if (!INPUT(i)->type) return -EINVAL; video_mux(dev, i); @@ -1696,13 +1749,14 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) return 0; } -static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) +static int vidioc_s_audio(struct file *file, void *priv, + const struct v4l2_audio *a) { struct em28xx *dev = video_drvdata(file); if (a->index >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(a->index)->type) + if (!INPUT(a->index)->type) return -EINVAL; dev->ctl_ainput = INPUT(a->index)->amux; @@ -1719,7 +1773,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; strcpy(t->name, "Tuner"); @@ -1733,7 +1787,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); @@ -1746,7 +1800,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (0 != f->tuner) + if (f->tuner != 0) return -EINVAL; f->frequency = v4l2->frequency; @@ -1760,7 +1814,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (0 != f->tuner) + if (f->tuner != 0) return -EINVAL; v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f); @@ -1884,8 +1938,9 @@ static int vidioc_querycap(struct file *file, void *priv, if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | + V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; if (video_is_registered(&v4l2->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; if (video_is_registered(&v4l2->radio_dev)) @@ -1978,9 +2033,9 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, return 0; } -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ +/* + * RADIO ESPECIFIC IOCTLS + */ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) @@ -2002,7 +2057,7 @@ static int radio_s_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); @@ -2097,7 +2152,7 @@ static int em28xx_v4l2_open(struct file *filp) * em28xx_v4l2_fini() * unregisters the v4l2,i2c and usb devices * called when the device gets disconected or at module unload -*/ + */ static int em28xx_v4l2_fini(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; @@ -2112,7 +2167,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) return 0; } - if (v4l2 == NULL) + if (!v4l2) return 0; dev_info(&dev->intf->dev, "Closing video extension\n"); @@ -2127,17 +2182,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (video_is_registered(&v4l2->radio_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2189,7 +2244,7 @@ static int em28xx_v4l2_close(struct file *filp) struct em28xx *dev = video_drvdata(filp); struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); - int errCode; + int err; em28xx_videodbg("users=%d\n", v4l2->users); @@ -2202,7 +2257,7 @@ static int em28xx_v4l2_close(struct file *filp) goto exit; /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby); /* do this before setting alternate! */ em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -2210,11 +2265,11 @@ static int em28xx_v4l2_close(struct file *filp) /* set alternate 0 */ dev->alt = 0; em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(udev, 0, 0); - if (errCode < 0) { + err = usb_set_interface(udev, 0, 0); + if (err < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to 0 (error=%i)\n", - errCode); + err); } } @@ -2343,7 +2398,7 @@ static void em28xx_vdev_init(struct em28xx *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2->v4l2_dev; vfd->lock = &dev->lock; - if (dev->board.is_webcam) + if (dev->is_webcam) vfd->tvnorms = 0; snprintf(vfd->name, sizeof(vfd->name), "%s %s", @@ -2372,7 +2427,7 @@ static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr) 0, tuner, s_type_addr, &tun_setup); } - if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type) { tun_setup.type = dev->tuner_type; tun_setup.addr = tuner_addr; @@ -2435,7 +2490,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_lock(&dev->lock); - v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL); + v4l2 = kzalloc(sizeof(*v4l2), GFP_KERNEL); if (!v4l2) { mutex_unlock(&dev->lock); return -ENOMEM; @@ -2458,7 +2513,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2_ctrl_handler_init(hdl, 8); v4l2->v4l2_dev.ctrl_handler = hdl; - if (dev->board.is_webcam) + if (dev->is_webcam) v4l2->progressive = true; /* @@ -2470,7 +2525,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* request some modules */ - if (dev->board.has_msp34xx) + if (dev->has_msp34xx) v4l2_i2c_new_subdev(&v4l2->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "msp3400", 0, msp3400_addrs); @@ -2559,7 +2614,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vbiq.active); - if (dev->board.has_msp34xx) { + if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { @@ -2568,7 +2623,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) __func__, ret); goto unregister_dev; } - msleep(3); + usleep_range(10000, 11000); ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { @@ -2577,7 +2632,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) __func__, ret); goto unregister_dev; } - msleep(3); + usleep_range(10000, 11000); } /* set default norm */ @@ -2589,8 +2644,10 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->format = &format[0]; maxw = norm_maxw(dev); - /* MaxPacketSize for em2800 is too small to capture at full resolution - * use half of maxw as the scaler can only scale to 50% */ + /* + * MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% + */ if (dev->board.is_em2800) maxw /= 2; @@ -2611,29 +2668,33 @@ static int em28xx_v4l2_init(struct em28xx *dev) em28xx_set_outfmt(dev); /* Add image controls */ - /* NOTE: at this point, the subdevices are already registered, so bridge - * controls are only added/enabled when no subdevice provides them */ - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST)) + + /* + * NOTE: at this point, the subdevices are already registered, so + * bridge controls are only added/enabled when no subdevice provides + * them + */ + if (!v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_CONTRAST, 0, 0x1f, 1, CONTRAST_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BRIGHTNESS, -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_SATURATION)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SATURATION, 0, 0x1f, 1, SATURATION_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, RED_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SHARPNESS, 0, 0x0f, 1, SHARPNESS_DEFAULT); @@ -2653,7 +2714,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->vdev.queue->lock = &v4l2->vb_queue_lock; /* disable inapplicable ioctls */ - if (dev->board.is_webcam) { + if (dev->is_webcam) { v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD); v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD); v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD); @@ -2683,7 +2744,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Allocate and fill vbi video_device struct */ if (em28xx_vbi_supported(dev) == 1) { em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template, - "vbi"); + "vbi"); v4l2->vbi_dev.queue = &v4l2->vb_vbiq; v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock; @@ -2713,7 +2774,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template, - "radio"); + "radio"); ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { @@ -2749,7 +2810,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby); /* initialize videobuf2 stuff */ em28xx_vb2_setup(dev); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 88084f24f033..63c7c6124707 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -1,31 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* - em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com> - Ludovico Cavedon <cavedon@sssup.it> - Mauro Carvalho Chehab <mchehab@infradead.org> - Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> - - Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de> - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices + * + * Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com> + * Ludovico Cavedon <cavedon@sssup.it> + * Mauro Carvalho Chehab <mchehab@infradead.org> + * Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> + * + * Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de> + * + * 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 _EM28XX_H #define _EM28XX_H +#include <linux/bitfield.h> + #define EM28XX_VERSION "0.2.2" #define DRIVER_DESC "Empia em28xx device driver" @@ -166,7 +165,7 @@ #define EM28XX_STOP_AUDIO 0 /* maximum number of em28xx boards */ -#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ +#define EM28XX_MAXBOARDS DVB_MAX_ADAPTERS /* All adapters could be em28xx */ /* maximum number of frames that can be queued */ #define EM28XX_NUM_FRAMES 5 @@ -180,43 +179,32 @@ /* max number of I2C buses on em28xx devices */ #define NUM_I2C_BUSES 2 -/* isoc transfers: number of packets for each buffer - windows requests only 64 packets .. so we better do the same - this is what I found out for all alternate numbers there! +/* + * isoc transfers: number of packets for each buffer + * windows requests only 64 packets .. so we better do the same + * this is what I found out for all alternate numbers there! */ #define EM28XX_NUM_ISOC_PACKETS 64 #define EM28XX_DVB_NUM_ISOC_PACKETS 64 -/* bulk transfers: transfer buffer size = packet size * packet multiplier - USB 2.0 spec says bulk packet size is always 512 bytes +/* + * bulk transfers: transfer buffer size = packet size * packet multiplier + * USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 -#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384 +#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 #define EM28XX_INTERLACED_DEFAULT 1 -/* - * Time in msecs to wait for i2c xfers to finish. - * 35ms is the maximum time a SMBUS device could wait when - * clock stretching is used. As the transfer itself will take - * some time to happen, set it to 35 ms. - * - * Ok, I2C doesn't specify any limit. So, eventually, we may need - * to increase this timeout. - * - * FIXME: this assumes that an I2C message is not longer than 1ms. - * This is actually dependent on the I2C bus speed, although most - * devices use a 100kHz clock. So, this assumtion is true most of - * the time. - */ -#define EM28XX_I2C_XFER_TIMEOUT 36 - /* time in msecs to wait for AC97 xfers to finish */ #define EM28XX_AC97_XFER_TIMEOUT 100 /* max. number of button state polling addresses */ #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5 +#define PRIMARY_TS 0 +#define SECONDARY_TS 1 + enum em28xx_mode { EM28XX_SUSPEND, EM28XX_ANALOG_MODE, @@ -225,64 +213,83 @@ enum em28xx_mode { struct em28xx; +/** + * struct em28xx_usb_bufs - Contains URB-related buffer data + * + * @max_pkt_size: max packet size of isoc transaction + * @num_packets: number of packets in each buffer + * @num_bufs: number of allocated urb + * @urb: urb for isoc/bulk transfers + * @buf: transfer buffers for isoc/bulk transfer + */ struct em28xx_usb_bufs { - /* max packet size of isoc transaction */ int max_pkt_size; - - /* number of packets in each buffer */ int num_packets; - - /* number of allocated urbs */ int num_bufs; - - /* urb for isoc/bulk transfers */ struct urb **urb; - - /* transfer buffers for isoc/bulk transfer */ - char **transfer_buffer; + char **buf; }; +/** + * struct em28xx_usb_ctl - Contains URB-related buffer data + * + * @analog_bufs: isoc/bulk transfer buffers for analog mode + * @digital_bufs: isoc/bulk transfer buffers for digital mode + * @vid_buf: Stores already requested video buffers + * @vbi_buf: Stores already requested VBI buffers + * @urb_data_copy: copy data from URB + */ struct em28xx_usb_ctl { - /* isoc/bulk transfer buffers for analog mode */ struct em28xx_usb_bufs analog_bufs; - - /* isoc/bulk transfer buffers for digital mode */ struct em28xx_usb_bufs digital_bufs; - - /* Stores already requested buffers */ struct em28xx_buffer *vid_buf; struct em28xx_buffer *vbi_buf; - - /* copy data from URB */ int (*urb_data_copy)(struct em28xx *dev, struct urb *urb); - }; -/* Struct to enumberate video formats */ +/** + * struct em28xx_fmt - Struct to enumberate video formats + * + * @name: Name for the video standard + * @fourcc: v4l2 format id + * @depth: mean number of bits to represent a pixel + * @reg: em28xx register value to set it + */ struct em28xx_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int reg; + char *name; + u32 fourcc; + int depth; + int reg; }; -/* buffer for one video frame */ +/** + * struct em28xx_buffer- buffer for storing one video frame + * + * @vb: common v4l buffer stuff + * @list: List to associate it with the other buffers + * @mem: pointer to the buffer, as returned by vb2_plane_vaddr() + * @length: length of the buffer, as returned by vb2_plane_size() + * @top_field: If non-zero, indicate that the buffer is the top field + * @pos: Indicate the next position of the buffer to be filled. + * @vb_buf: pointer to vmalloc memory address in vb + * + * .. note:: + * + * in interlaced mode, @pos is reset to zero at the start of each new + * field (not frame !) + */ struct em28xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head list; + struct vb2_v4l2_buffer vb; /* must be first */ - void *mem; - unsigned int length; - int top_field; + struct list_head list; - /* counter to control buffer fill */ - unsigned int pos; - /* NOTE; in interlaced mode, this value is reset to zero at - * the start of each new field (not frame !) */ + void *mem; + unsigned int length; + int top_field; - /* pointer to vmalloc memory address in vb */ - char *vb_buf; + unsigned int pos; + + char *vb_buf; }; struct em28xx_dmaqueue { @@ -324,20 +331,48 @@ enum em28xx_usb_audio_type { EM28XX_USB_AUDIO_VENDOR, }; -/* em28xx has two audio inputs: tuner and line in. - However, on most devices, an auxiliary AC97 codec device is used. - The AC97 device may have several different inputs and outputs, - depending on their model. So, it is possible to use AC97 mixer to - address more than two different entries. +/** + * em28xx_amux - describes the type of audio input used by em28xx + * + * @EM28XX_AMUX_VIDEO: + * On devices without AC97, this is the only value that it is currently + * allowed. + * On devices with AC97, it corresponds to the AC97 mixer "Video" control. + * @EM28XX_AMUX_LINE_IN: + * Only for devices with AC97. Corresponds to AC97 mixer "Line In". + * @EM28XX_AMUX_VIDEO2: + * Only for devices with AC97. It means that em28xx should use "Line In" + * And AC97 should use the "Video" mixer control. + * @EM28XX_AMUX_PHONE: + * Only for devices with AC97. Corresponds to AC97 mixer "Phone". + * @EM28XX_AMUX_MIC: + * Only for devices with AC97. Corresponds to AC97 mixer "Mic". + * @EM28XX_AMUX_CD: + * Only for devices with AC97. Corresponds to AC97 mixer "CD". + * @EM28XX_AMUX_AUX: + * Only for devices with AC97. Corresponds to AC97 mixer "Aux". + * @EM28XX_AMUX_PCM_OUT: + * Only for devices with AC97. Corresponds to AC97 mixer "PCM out". + * + * The em28xx chip itself has only two audio inputs: tuner and line in. + * On almost all devices, only the tuner input is used. + * + * However, on most devices, an auxiliary AC97 codec device is used, + * usually connected to the em28xx tuner input (except for + * @EM28XX_AMUX_LINE_IN). + * + * The AC97 device typically have several different inputs and outputs. + * The exact number and description depends on their model. + * + * It is possible to AC97 to mixer more than one different entries at the + * same time, via the alsa mux. */ enum em28xx_amux { - /* This is the only entry for em28xx tuner input */ - EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ - - EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ + EM28XX_AMUX_VIDEO, + EM28XX_AMUX_LINE_IN, /* Some less-common mixer setups */ - EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ + EM28XX_AMUX_VIDEO2, EM28XX_AMUX_PHONE, EM28XX_AMUX_MIC, EM28XX_AMUX_CD, @@ -347,14 +382,14 @@ enum em28xx_amux { enum em28xx_aout { /* AC97 outputs */ - EM28XX_AOUT_MASTER = 1 << 0, - EM28XX_AOUT_LINE = 1 << 1, - EM28XX_AOUT_MONO = 1 << 2, - EM28XX_AOUT_LFE = 1 << 3, - EM28XX_AOUT_SURR = 1 << 4, + EM28XX_AOUT_MASTER = BIT(0), + EM28XX_AOUT_LINE = BIT(1), + EM28XX_AOUT_MONO = BIT(2), + EM28XX_AOUT_LFE = BIT(3), + EM28XX_AOUT_SURR = BIT(4), /* PCM IN Mixer - used by AC97_RECORD_SELECT register */ - EM28XX_AOUT_PCM_IN = 1 << 7, + EM28XX_AOUT_PCM_IN = BIT(7), /* Bits 10-8 are used to indicate the PCM IN record select */ EM28XX_AOUT_PCM_MIC_PCM = 0 << 8, @@ -383,7 +418,7 @@ struct em28xx_input { unsigned int vmux; enum em28xx_amux amux; enum em28xx_aout aout; - struct em28xx_reg_seq *gpio; + const struct em28xx_reg_seq *gpio; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -441,22 +476,23 @@ struct em28xx_board { int vchannels; int tuner_type; int tuner_addr; - unsigned def_i2c_bus; /* Default I2C bus */ + unsigned int def_i2c_bus; /* Default I2C bus */ /* i2c flags */ unsigned int tda9887_conf; /* GPIO sequences */ - struct em28xx_reg_seq *dvb_gpio; - struct em28xx_reg_seq *suspend_gpio; - struct em28xx_reg_seq *tuner_gpio; - struct em28xx_reg_seq *mute_gpio; + const struct em28xx_reg_seq *dvb_gpio; + const struct em28xx_reg_seq *suspend_gpio; + const struct em28xx_reg_seq *tuner_gpio; + const struct em28xx_reg_seq *mute_gpio; unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int mts_firmware:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; + unsigned int has_dual_ts:1; unsigned int is_webcam:1; unsigned int valid:1; unsigned int has_ir_i2c:1; @@ -476,7 +512,7 @@ struct em28xx_board { struct em28xx_led *leds; /* Buttons */ - struct em28xx_button *buttons; + const struct em28xx_button *buttons; }; struct em28xx_eeprom { @@ -519,8 +555,8 @@ struct em28xx_v4l2 { /* Videobuf2 */ struct vb2_queue vb_vidq; struct vb2_queue vb_vbiq; - struct mutex vb_queue_lock; - struct mutex vb_vbi_queue_lock; + struct mutex vb_queue_lock; /* Protects vb_vidq */ + struct mutex vb_vbi_queue_lock; /* Protects vb_vbiq */ u8 vinmode; u8 vinctl; @@ -546,8 +582,8 @@ struct em28xx_v4l2 { /* Frame properties */ int width; /* current frame width */ int height; /* current frame height */ - unsigned hscale; /* horizontal scale factor (see datasheet) */ - unsigned vscale; /* vertical scale factor (see datasheet) */ + unsigned int hscale; /* horizontal scale factor (see datasheet) */ + unsigned int vscale; /* vertical scale factor (see datasheet) */ unsigned int vbi_width; unsigned int vbi_height; /* lines per field */ @@ -565,7 +601,7 @@ struct em28xx_v4l2 { struct em28xx_audio { char name[50]; - unsigned num_urb; + unsigned int num_urb; char **transfer_buffer; struct urb **urb; struct usb_device *udev; @@ -578,7 +614,7 @@ struct em28xx_audio { size_t period; int users; - spinlock_t slock; + spinlock_t slock; /* Protects struct em28xx_audio */ /* Controls streaming */ struct work_struct wq_trigger; /* trigger to start/stop audio */ @@ -596,7 +632,7 @@ enum em28xx_i2c_algo_type { struct em28xx_i2c_bus { struct em28xx *dev; - unsigned bus; + unsigned int bus; enum em28xx_i2c_algo_type algo_type; }; @@ -604,102 +640,111 @@ struct em28xx_i2c_bus { struct em28xx { struct kref ref; - /* Sub-module data */ + // Sub-module data struct em28xx_v4l2 *v4l2; struct em28xx_dvb *dvb; struct em28xx_audio adev; struct em28xx_IR *ir; - /* generic device properties */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ + // generic device properties + int model; // index in the device_data struct + int devno; // marks the number of this device enum em28xx_chip_id chip_id; - unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ - unsigned char disconnected:1; /* device has been diconnected */ + unsigned int is_em25xx:1; // em25xx/em276x/7x/8x family bridge + unsigned int disconnected:1; // device has been diconnected unsigned int has_video:1; unsigned int is_audio_only:1; + unsigned int is_webcam:1; + unsigned int has_msp34xx:1; + unsigned int i2c_speed:2; enum em28xx_int_audio_type int_audio_type; enum em28xx_usb_audio_type usb_audio_type; + unsigned char name[32]; struct em28xx_board board; - enum em28xx_sensor em28xx_sensor; /* camera specific */ + enum em28xx_sensor em28xx_sensor; // camera specific - /* Some older em28xx chips needs a waiting time after writing */ + // Some older em28xx chips needs a waiting time after writing unsigned int wait_after_write; struct list_head devlist; - u32 i2s_speed; /* I2S speed for audio digital stream */ + u32 i2s_speed; // I2S speed for audio digital stream struct em28xx_audio_mode audio_mode; - int tuner_type; /* type of the tuner */ + int tuner_type; // type of the tuner - /* i2c i/o */ + // i2c i/o struct i2c_adapter i2c_adap[NUM_I2C_BUSES]; struct i2c_client i2c_client[NUM_I2C_BUSES]; struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES]; unsigned char eeprom_addrwidth_16bit:1; - unsigned def_i2c_bus; /* Default I2C bus */ - unsigned cur_i2c_bus; /* Current I2C bus */ + unsigned int def_i2c_bus; // Default I2C bus + unsigned int cur_i2c_bus; // Current I2C bus struct rt_mutex i2c_bus_lock; - /* video for linux */ - unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput;/* selected audio input */ - unsigned int ctl_aoutput;/* selected audio output */ + // video for linux + unsigned int ctl_input; // selected input + unsigned int ctl_ainput;// selected audio input + unsigned int ctl_aoutput;// selected audio output int mute; int volume; - unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - - for boards with generic ID */ + unsigned long hash; // eeprom hash - for boards with generic ID + unsigned long i2c_hash; // i2c devicelist hash - + // for boards with generic ID struct work_struct request_module_wk; - /* locks */ - struct mutex lock; + // locks + struct mutex lock; /* protects em28xx struct */ struct mutex ctrl_urb_lock; /* protects urb_buf */ - /* resources in use */ + // resources in use unsigned int resources; - /* eeprom content */ + // eeprom content u8 *eedata; u16 eedata_len; - /* Isoc control struct */ + // Isoc control struct struct em28xx_dmaqueue vidq; struct em28xx_dmaqueue vbiq; struct em28xx_usb_ctl usb_ctl; - spinlock_t slock; - - /* usb transfer */ - struct usb_interface *intf; /* the usb interface */ - u8 ifnum; /* number of the assigned usb interface */ - u8 analog_ep_isoc; /* address of isoc endpoint for analog */ - u8 analog_ep_bulk; /* address of bulk endpoint for analog */ - u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ - u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */ - int alt; /* alternate setting */ - int max_pkt_size; /* max packet size of the selected ep at alt */ - int packet_multiplier; /* multiplier for wMaxPacketSize, used for - URB buffer size definition */ - int num_alt; /* number of alternative settings */ - unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */ - unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc - transfers for analog */ - int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */ - unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the - selected DVB ep at dvb_alt */ - unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc - transfers for DVB */ - char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ - - /* helper funcs that call usb_control_msg */ + + spinlock_t slock; /* Protects em28xx video/vbi/dvb IRQ stream data */ + + // usb transfer + struct usb_interface *intf; // the usb interface + u8 ifnum; // number of the assigned usb interface + u8 analog_ep_isoc; // address of isoc endpoint for analog + u8 analog_ep_bulk; // address of bulk endpoint for analog + u8 dvb_ep_isoc_ts2; // address of isoc endpoint for DVB TS2 + u8 dvb_ep_bulk_ts2; // address of bulk endpoint for DVB TS2 + u8 dvb_ep_isoc; // address of isoc endpoint for DVB + u8 dvb_ep_bulk; // address of bulk endpoint for DVB + int alt; // alternate setting + int max_pkt_size; // max packet size of the selected ep at alt + int packet_multiplier; // multiplier for wMaxPacketSize, used for + // URB buffer size definition + int num_alt; // number of alternative settings + unsigned int *alt_max_pkt_size_isoc; // array of isoc wMaxPacketSize + unsigned int analog_xfer_bulk:1; // use bulk instead of isoc + // transfers for analog + int dvb_alt_isoc; // alternate setting for DVB isoc transfers + unsigned int dvb_max_pkt_size_isoc; // isoc max packet size of the + // selected DVB ep at dvb_alt + unsigned int dvb_max_pkt_size_isoc_ts2; // isoc max packet size of the + // selected DVB ep at dvb_alt + unsigned int dvb_xfer_bulk:1; // use bulk instead of isoc + // transfers for DVB + char urb_buf[URB_MAX_CTRL_SIZE]; // urb control msg buffer + + // helper funcs that call usb_control_msg int (*em28xx_write_regs)(struct em28xx *dev, u16 reg, char *buf, int len); int (*em28xx_read_reg)(struct em28xx *dev, u16 reg); @@ -711,14 +756,14 @@ struct em28xx { enum em28xx_mode mode; - /* Button state polling */ + // Button state polling struct delayed_work buttons_query_work; u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; u8 num_button_polling_addresses; - u16 button_polling_interval; /* [ms] */ - /* Snapshot button input device */ - char snapshot_button_path[30]; /* path of the input dev */ + u16 button_polling_interval; // [ms] + // Snapshot button input device + char snapshot_button_path[30]; // path of the input dev struct input_dev *sbutton_input_dev; #ifdef CONFIG_MEDIA_CONTROLLER @@ -726,6 +771,9 @@ struct em28xx { struct media_entity input_ent[MAX_EM28XX_INPUT]; struct media_pad input_pad[MAX_EM28XX_INPUT]; #endif + + struct em28xx *dev_next; + int ts; }; #define kref_to_dev(d) container_of(d, struct em28xx, ref) @@ -734,17 +782,17 @@ struct em28xx_ops { struct list_head next; char *name; int id; - int (*init)(struct em28xx *); - int (*fini)(struct em28xx *); - int (*suspend)(struct em28xx *); - int (*resume)(struct em28xx *); + int (*init)(struct em28xx *dev); + int (*fini)(struct em28xx *dev); + int (*suspend)(struct em28xx *dev); + int (*resume)(struct em28xx *dev); }; /* Provided by em28xx-i2c.c */ -void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus); -int em28xx_i2c_register(struct em28xx *dev, unsigned bus, +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus); +int em28xx_i2c_register(struct em28xx *dev, unsigned int bus, enum em28xx_i2c_algo_type algo_type); -int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus); +int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus); /* Provided by em28xx-core.c */ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, @@ -778,7 +826,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode); void em28xx_stop_urbs(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); +int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); @@ -787,7 +835,7 @@ int em28xx_suspend_extension(struct em28xx *dev); int em28xx_resume_extension(struct em28xx *dev); /* Provided by em28xx-cards.c */ -extern struct em28xx_board em28xx_boards[]; +extern const struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl); diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index c618764480c6..f84a2130f033 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -227,7 +227,7 @@ int go7007_snd_init(struct go7007 *go) { static int dev; struct go7007_snd *gosnd; - int ret = 0; + int ret; if (dev >= SNDRV_CARDS) return -ENODEV; diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c index cdf27cf0112a..7654c8c08eda 100644 --- a/drivers/media/usb/gspca/dtcs033.c +++ b/drivers/media/usb/gspca/dtcs033.c @@ -76,12 +76,10 @@ static int reg_reqs(struct gspca_dev *gspca_dev, } else if (preq->bRequestType & USB_DIR_IN) { gspca_dbg(gspca_dev, D_STREAM, - "USB IN (%d) returned[%d] %02X %02X %02X %s\n", + "USB IN (%d) returned[%d] %3ph %s", i, preq->wLength, - gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2], + gspca_dev->usb_buf, preq->wLength > 3 ? "...\n" : "\n"); } diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 8c2a86d71e8a..82927eb334c4 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -648,8 +648,8 @@ static void s2255_fillbuff(struct s2255_vc *vc, pr_err("s2255: =======no frame\n"); return; } - dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n", - (unsigned long)vbuf, pos); + dprintk(dev, 2, "s2255fill at : Buffer %p size= %d\n", + vbuf, pos); } @@ -803,10 +803,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_2CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; else f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; } else { @@ -820,10 +816,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) f->fmt.pix.width = LINE_SZ_4CIFS_PAL; - else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) - f->fmt.pix.width = LINE_SZ_2CIFS_PAL; - else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) - f->fmt.pix.width = LINE_SZ_1CIFS_PAL; else f->fmt.pix.width = LINE_SZ_1CIFS_PAL; } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index f13e4b01b5a5..6d436e9e454f 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -179,8 +179,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, smsusb_onresponse, surb ); - surb->urb.transfer_dma = surb->cb->phys; - surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + surb->urb.transfer_flags |= URB_FREE_BUFFER; return usb_submit_urb(&surb->urb, GFP_ATOMIC); } @@ -446,6 +445,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) dev->in_ep, dev->out_ep); params.device = &dev->udev->dev; + params.usb_device = dev->udev; params.buffer_size = dev->buffer_size; params.num_buffers = MAX_BUFFERS; params.sendrequest_handler = smsusb_sendrequest; diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 4d5f4cc4887e..70939e96b856 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1174,7 +1174,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, { struct usb_device *usbdev; struct tm6000_core *dev; - int i, rc = 0; + int i, rc; int nr = 0; char *speed; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 8314d3fa9241..b2399d4266da 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1346,9 +1346,8 @@ static int __tm6000_open(struct file *file) fh->width = dev->width; fh->height = dev->height; - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&dev->vidq); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=%p, dev=%p, dev->vidq=%p\n", + fh, dev, &dev->vidq); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n", list_empty(&dev->vidq.queued)); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n", diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 127f8a0c098b..5095c380b2c1 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -112,6 +112,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_audio_fail: + /* we must not free at this point */ + usb_get_dev(usbtv->udev); usbtv_video_free(usbtv); usbtv_video_fail: @@ -145,6 +147,7 @@ static void usbtv_disconnect(struct usb_interface *intf) static const struct usb_device_id usbtv_id_table[] = { { USB_DEVICE(0x1b71, 0x3002) }, { USB_DEVICE(0x1f71, 0x3301) }, + { USB_DEVICE(0x1f71, 0x3306) }, {} }; MODULE_DEVICE_TABLE(usb, usbtv_id_table); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 20397aba6849..102594ec3e97 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -366,10 +366,10 @@ static struct uvc_menu_info exposure_auto_controls[] = { { 8, "Aperture Priority Mode" }, }; -static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { - __s8 zoom = (__s8)data[0]; + s8 zoom = (s8)data[0]; switch (query) { case UVC_GET_CUR: @@ -385,17 +385,17 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, } static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; data[2] = min((int)abs(value), 0xff); } -static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { unsigned int first = mapping->offset / 8; - __s8 rel = (__s8)data[first]; + s8 rel = (s8)data[first]; switch (query) { case UVC_GET_CUR: @@ -412,7 +412,7 @@ static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, } static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { unsigned int first = mapping->offset / 8; @@ -745,17 +745,17 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { * Utility functions */ -static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) +static inline u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) { return ctrl->uvc_data + id * ctrl->info.size; } -static inline int uvc_test_bit(const __u8 *data, int bit) +static inline int uvc_test_bit(const u8 *data, int bit) { return (data[bit >> 3] >> (bit & 7)) & 1; } -static inline void uvc_clear_bit(__u8 *data, int bit) +static inline void uvc_clear_bit(u8 *data, int bit) { data[bit >> 3] &= ~(1 << (bit & 7)); } @@ -765,20 +765,20 @@ static inline void uvc_clear_bit(__u8 *data, int bit) * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */ -static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { int bits = mapping->size; int offset = mapping->offset; - __s32 value = 0; - __u8 mask; + s32 value = 0; + u8 mask; data += offset / 8; offset &= 7; mask = ((1LL << bits) - 1) << offset; for (; bits > 0; data++) { - __u8 byte = *data & mask; + u8 byte = *data & mask; value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); bits -= 8 - (offset > 0 ? offset : 0); offset -= 8; @@ -796,11 +796,11 @@ static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, * in the little-endian data stored at 'data' to the value 'value'. */ static void uvc_set_le_value(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { int bits = mapping->size; int offset = mapping->offset; - __u8 mask; + u8 mask; /* According to the v4l2 spec, writing any value to a button control * should result in the action belonging to the button control being @@ -826,13 +826,13 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, * Terminal and unit management */ -static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; -static const __u8 uvc_media_transport_input_guid[16] = +static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; +static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; +static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static int uvc_entity_match_guid(const struct uvc_entity *entity, - const __u8 guid[16]) + const u8 guid[16]) { switch (UVC_ENTITY_TYPE(entity)) { case UVC_ITT_CAMERA: @@ -857,7 +857,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity, * UVC Controls */ -static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, +static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, struct uvc_control_mapping **mapping, struct uvc_control **control, int next) { @@ -890,7 +890,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, } static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, - __u32 v4l2_id, struct uvc_control_mapping **mapping) + u32 v4l2_id, struct uvc_control_mapping **mapping) { struct uvc_control *ctrl = NULL; struct uvc_entity *entity; @@ -1019,10 +1019,10 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct uvc_menu_info *menu; unsigned int i; - memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; - strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); + strlcpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name)); v4l2_ctrl->flags = 0; if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) @@ -1182,7 +1182,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, } } - strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); + strlcpy(query_menu->name, menu_info->name, sizeof(query_menu->name)); done: mutex_unlock(&chain->ctrl_mutex); @@ -1590,6 +1590,36 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, * Dynamic controls */ +/* + * Retrieve flags for a given control + */ +static int uvc_ctrl_get_flags(struct uvc_device *dev, + const struct uvc_control *ctrl, + struct uvc_control_info *info) +{ + u8 *data; + int ret; + + data = kmalloc(1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, + info->selector, data, 1); + if (!ret) + info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX + | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF + | (data[0] & UVC_CONTROL_CAP_GET ? + UVC_CTRL_FLAG_GET_CUR : 0) + | (data[0] & UVC_CONTROL_CAP_SET ? + UVC_CTRL_FLAG_SET_CUR : 0) + | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? + UVC_CTRL_FLAG_AUTO_UPDATE : 0); + + kfree(data); + return ret; +} + static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev, const struct uvc_control *ctrl, struct uvc_control_info *info) { @@ -1659,25 +1689,14 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev, info->size = le16_to_cpup((__le16 *)data); - /* Query the control information (GET_INFO) */ - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, - info->selector, data, 1); + ret = uvc_ctrl_get_flags(dev, ctrl, info); if (ret < 0) { uvc_trace(UVC_TRACE_CONTROL, - "GET_INFO failed on control %pUl/%u (%d).\n", + "Failed to get flags for control %pUl/%u (%d).\n", info->entity, info->selector, ret); goto done; } - info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX - | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF - | (data[0] & UVC_CONTROL_CAP_GET ? - UVC_CTRL_FLAG_GET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_SET ? - UVC_CTRL_FLAG_SET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? - UVC_CTRL_FLAG_AUTO_UPDATE : 0); - uvc_ctrl_fixup_xu_info(dev, ctrl, info); uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, " @@ -1723,9 +1742,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_entity *entity; struct uvc_control *ctrl; unsigned int i, found = 0; - __u32 reqflags; - __u16 size; - __u8 *data = NULL; + u32 reqflags; + u16 size; + u8 *data = NULL; int ret; /* Find the extension unit. */ @@ -1902,6 +1921,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, goto done; } + /* + * Retrieve control flags from the device. Ignore errors and work with + * default flag values from the uvc_ctrl array when the device doesn't + * properly implement GET_INFO on standard controls. + */ + uvc_ctrl_get_flags(dev, ctrl, &ctrl->info); + ctrl->initialized = 1; uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " @@ -2150,7 +2176,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) list_for_each_entry(entity, &dev->entities, list) { struct uvc_control *ctrl; unsigned int bControlSize = 0, ncontrols; - __u8 *bmControls = NULL; + u8 *bmControls = NULL; if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { bmControls = entity->extension.bmControls; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index fd387bf3f02d..2469b49b2b30 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -216,7 +216,7 @@ static struct uvc_format_desc uvc_fmts[] = { */ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, - __u8 epaddr) + u8 epaddr) { struct usb_host_endpoint *ep; unsigned int i; @@ -230,7 +230,7 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, return NULL; } -static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16]) +static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) { unsigned int len = ARRAY_SIZE(uvc_fmts); unsigned int i; @@ -243,9 +243,9 @@ static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16]) return NULL; } -static __u32 uvc_colorspace(const __u8 primaries) +static u32 uvc_colorspace(const u8 primaries) { - static const __u8 colorprimaries[] = { + static const u8 colorprimaries[] = { 0, V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_470_SYSTEM_M, @@ -267,14 +267,14 @@ static __u32 uvc_colorspace(const __u8 primaries) * continued fraction decomposition. Using 8 and 333 for n_terms and threshold * respectively seems to give nice results. */ -void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, +void uvc_simplify_fraction(u32 *numerator, u32 *denominator, unsigned int n_terms, unsigned int threshold) { - uint32_t *an; - uint32_t x, y, r; + u32 *an; + u32 x, y, r; unsigned int i, n; - an = kmalloc(n_terms * sizeof *an, GFP_KERNEL); + an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL); if (an == NULL) return; @@ -318,21 +318,21 @@ void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, * to compute numerator / denominator * 10000000 using 32 bit fixed point * arithmetic only. */ -uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) +u32 uvc_fraction_to_interval(u32 numerator, u32 denominator) { - uint32_t multiplier; + u32 multiplier; /* Saturate the result if the operation would overflow. */ if (denominator == 0 || - numerator/denominator >= ((uint32_t)-1)/10000000) - return (uint32_t)-1; + numerator/denominator >= ((u32)-1)/10000000) + return (u32)-1; /* Divide both the denominator and the multiplier by two until * numerator * multiplier doesn't overflow. If anyone knows a better * algorithm please let me know. */ multiplier = 10000000; - while (numerator > ((uint32_t)-1)/multiplier) { + while (numerator > ((u32)-1)/multiplier) { multiplier /= 2; denominator /= 2; } @@ -391,7 +391,7 @@ static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) static int uvc_parse_format(struct uvc_device *dev, struct uvc_streaming *streaming, struct uvc_format *format, - __u32 **intervals, unsigned char *buffer, int buflen) + u32 **intervals, unsigned char *buffer, int buflen) { struct usb_interface *intf = streaming->intf; struct usb_host_interface *alts = intf->cur_altsetting; @@ -401,7 +401,7 @@ static int uvc_parse_format(struct uvc_device *dev, unsigned int width_multiplier = 1; unsigned int interval; unsigned int i, n; - __u8 ftype; + u8 ftype; format->type = buffer[2]; format->index = buffer[3]; @@ -423,7 +423,7 @@ static int uvc_parse_format(struct uvc_device *dev, if (fmtdesc != NULL) { strlcpy(format->name, fmtdesc->name, - sizeof format->name); + sizeof(format->name)); format->fcc = fmtdesc->fcc; } else { uvc_printk(KERN_INFO, "Unknown video format %pUl\n", @@ -466,7 +466,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strlcpy(format->name, "MJPEG", sizeof format->name); + strlcpy(format->name, "MJPEG", sizeof(format->name)); format->fcc = V4L2_PIX_FMT_MJPEG; format->flags = UVC_FMT_FLAG_COMPRESSED; format->bpp = 0; @@ -484,13 +484,13 @@ static int uvc_parse_format(struct uvc_device *dev, switch (buffer[8] & 0x7f) { case 0: - strlcpy(format->name, "SD-DV", sizeof format->name); + strlcpy(format->name, "SD-DV", sizeof(format->name)); break; case 1: - strlcpy(format->name, "SDL-DV", sizeof format->name); + strlcpy(format->name, "SDL-DV", sizeof(format->name)); break; case 2: - strlcpy(format->name, "HD-DV", sizeof format->name); + strlcpy(format->name, "HD-DV", sizeof(format->name)); break; default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " @@ -501,7 +501,7 @@ static int uvc_parse_format(struct uvc_device *dev, } strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", - sizeof format->name); + sizeof(format->name)); format->fcc = V4L2_PIX_FMT_DV; format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; @@ -510,7 +510,7 @@ static int uvc_parse_format(struct uvc_device *dev, /* Create a dummy frame descriptor. */ frame = &format->frame[0]; - memset(&format->frame[0], 0, sizeof format->frame[0]); + memset(&format->frame[0], 0, sizeof(format->frame[0])); frame->bFrameIntervalType = 1; frame->dwDefaultFrameInterval = 1; frame->dwFrameInterval = *intervals; @@ -658,8 +658,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, int _buflen, buflen = alts->extralen; unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; - __u32 *interval; - __u16 psize; + u32 *interval; + u16 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -677,7 +677,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return -EINVAL; } - streaming = kzalloc(sizeof *streaming, GFP_KERNEL); + streaming = kzalloc(sizeof(*streaming), GFP_KERNEL); if (streaming == NULL) { usb_driver_release_interface(&uvc_driver.driver, intf); return -EINVAL; @@ -827,8 +827,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, goto error; } - size = nformats * sizeof *format + nframes * sizeof *frame - + nintervals * sizeof *interval; + size = nformats * sizeof(*format) + nframes * sizeof(*frame) + + nintervals * sizeof(*interval); format = kzalloc(size, GFP_KERNEL); if (format == NULL) { ret = -ENOMEM; @@ -836,7 +836,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, } frame = (struct uvc_frame *)&format[nformats]; - interval = (__u32 *)&frame[nframes]; + interval = (u32 *)&frame[nframes]; streaming->format = format; streaming->nformats = nformats; @@ -930,7 +930,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; entity->bNrInPins = num_inputs; - entity->baSourceID = (__u8 *)(&entity->pads[num_pads]); + entity->baSourceID = (u8 *)(&entity->pads[num_pads]); return entity; } @@ -995,14 +995,14 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof(*unit); - unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit) + unit->extension.bmControls = (u8 *)unit + sizeof(*unit); + unit->extension.bmControlsType = (u8 *)unit + sizeof(*unit) + n; memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); if (buffer[24+p+2*n] != 0) usb_string(udev, buffer[24+p+2*n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Extension %u", buffer[3]); @@ -1022,7 +1022,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, struct usb_interface *intf; struct usb_host_interface *alts = dev->intf->cur_altsetting; unsigned int i, n, p, len; - __u16 type; + u16 type; switch (buffer[2]) { case UVC_VC_HEADER: @@ -1101,7 +1101,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; - term->camera.bmControls = (__u8 *)term + sizeof *term; + term->camera.bmControls = (u8 *)term + sizeof(*term); term->camera.wObjectiveFocalLengthMin = get_unaligned_le16(&buffer[8]); term->camera.wObjectiveFocalLengthMax = @@ -1112,17 +1112,17 @@ static int uvc_parse_standard_control(struct uvc_device *dev, } else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) { term->media.bControlSize = n; - term->media.bmControls = (__u8 *)term + sizeof *term; + term->media.bmControls = (u8 *)term + sizeof(*term); term->media.bTransportModeSize = p; - term->media.bmTransportModes = (__u8 *)term - + sizeof *term + n; + term->media.bmTransportModes = (u8 *)term + + sizeof(*term) + n; memcpy(term->media.bmControls, &buffer[9], n); memcpy(term->media.bmTransportModes, &buffer[10+n], p); } if (buffer[7] != 0) usb_string(udev, buffer[7], term->name, - sizeof term->name); + sizeof(term->name)); else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) sprintf(term->name, "Camera %u", buffer[3]); else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) @@ -1162,7 +1162,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (buffer[8] != 0) usb_string(udev, buffer[8], term->name, - sizeof term->name); + sizeof(term->name)); else sprintf(term->name, "Output %u", buffer[3]); @@ -1187,7 +1187,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (buffer[5+p] != 0) usb_string(udev, buffer[5+p], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Selector %u", buffer[3]); @@ -1213,14 +1213,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->processing.wMaxMultiplier = get_unaligned_le16(&buffer[5]); unit->processing.bControlSize = buffer[7]; - unit->processing.bmControls = (__u8 *)unit + sizeof *unit; + unit->processing.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->processing.bmControls, &buffer[8], n); if (dev->uvc_version >= 0x0110) unit->processing.bmVideoStandards = buffer[9+n]; if (buffer[8+n] != 0) usb_string(udev, buffer[8+n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Processing %u", buffer[3]); @@ -1246,12 +1246,12 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof *unit; + unit->extension.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->extension.bmControls, &buffer[23+p], n); if (buffer[23+p+n] != 0) usb_string(udev, buffer[23+p+n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Extension %u", buffer[3]); @@ -1936,7 +1936,7 @@ int uvc_register_video_device(struct uvc_device *dev, break; } - strlcpy(vdev->name, dev->name, sizeof vdev->name); + strlcpy(vdev->name, dev->name, sizeof(vdev->name)); /* * Set the driver data before calling video_register_device, otherwise @@ -2070,7 +2070,8 @@ static int uvc_probe(struct usb_interface *intf, udev->devpath); /* Allocate memory for the device and initialize it. */ - if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL) + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) return -ENOMEM; INIT_LIST_HEAD(&dev->entities); @@ -2089,9 +2090,9 @@ static int uvc_probe(struct usb_interface *intf, dev->meta_format = info->meta_format; if (udev->product != NULL) - strlcpy(dev->name, udev->product, sizeof dev->name); + strlcpy(dev->name, udev->product, sizeof(dev->name)); else - snprintf(dev->name, sizeof dev->name, + snprintf(dev->name, sizeof(dev->name), "UVC Camera (%04x:%04x)", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c index 5059fbf41020..81e6f2187bfb 100644 --- a/drivers/media/usb/uvc/uvc_isight.c +++ b/drivers/media/usb/uvc/uvc_isight.c @@ -37,16 +37,16 @@ */ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, - const __u8 *data, unsigned int len) + const u8 *data, unsigned int len) { - static const __u8 hdr[] = { + static const u8 hdr[] = { 0x11, 0x22, 0x33, 0x44, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xfa, 0xce }; unsigned int maxlen, nbytes; - __u8 *mem; + u8 *mem; int is_header = 0; if (buf == NULL) diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 1ef20e74b7ac..7b710410584a 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -78,7 +78,7 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, /* -------------------------------------------------------------------------- * Status interrupt endpoint */ -static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) +static void uvc_event_streaming(struct uvc_device *dev, u8 *data, int len) { if (len < 3) { uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " @@ -99,7 +99,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) } } -static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len) +static void uvc_event_control(struct uvc_device *dev, u8 *data, int len) { char *attrs[3] = { "value", "info", "failure" }; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index a13ad4e178be..bd32914259ae 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -40,13 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, unsigned int size; int ret; - map = kzalloc(sizeof *map, GFP_KERNEL); + map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) return -ENOMEM; map->id = xmap->id; - memcpy(map->name, xmap->name, sizeof map->name); - memcpy(map->entity, xmap->entity, sizeof map->entity); + memcpy(map->name, xmap->name, sizeof(map->name)); + memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; map->size = xmap->size; map->offset = xmap->offset; @@ -105,12 +105,12 @@ free_map: * the Video Probe and Commit negotiation, but some hardware don't implement * that feature. */ -static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) +static u32 uvc_try_frame_interval(struct uvc_frame *frame, u32 interval) { unsigned int i; if (frame->bFrameIntervalType) { - __u32 best = -1, dist; + u32 best = -1, dist; for (i = 0; i < frame->bFrameIntervalType; ++i) { dist = interval > frame->dwFrameInterval[i] @@ -125,9 +125,9 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) interval = frame->dwFrameInterval[i-1]; } else { - const __u32 min = frame->dwFrameInterval[0]; - const __u32 max = frame->dwFrameInterval[1]; - const __u32 step = frame->dwFrameInterval[2]; + const u32 min = frame->dwFrameInterval[0]; + const u32 max = frame->dwFrameInterval[1]; + const u32 step = frame->dwFrameInterval[2]; interval = min + (interval - min + step/2) / step * step; if (interval > max) @@ -137,7 +137,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) return interval; } -static __u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, +static u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, const struct uvc_frame *frame) { switch (format->fcc) { @@ -158,17 +158,17 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, { struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; - __u16 rw, rh; + u16 rw, rh; unsigned int d, maxd; unsigned int i; - __u32 interval; + u32 interval; int ret = 0; - __u8 *fcc; + u8 *fcc; if (fmt->type != stream->type) return -EINVAL; - fcc = (__u8 *)&fmt->fmt.pix.pixelformat; + fcc = (u8 *)&fmt->fmt.pix.pixelformat; uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n", fmt->fmt.pix.pixelformat, fcc[0], fcc[1], fcc[2], fcc[3], @@ -197,8 +197,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, maxd = (unsigned int)-1; for (i = 0; i < format->nframes; ++i) { - __u16 w = format->frame[i].wWidth; - __u16 h = format->frame[i].wHeight; + u16 w = format->frame[i].wWidth; + u16 h = format->frame[i].wHeight; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; @@ -224,7 +224,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, (100000000/interval)%10); /* Set the format index, frame index and frame interval. */ - memset(probe, 0, sizeof *probe); + memset(probe, 0, sizeof(*probe)); probe->bmHint = 1; /* dwFrameInterval */ probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; @@ -336,7 +336,7 @@ done: static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { - uint32_t numerator, denominator; + u32 numerator, denominator; if (parm->type != stream->type) return -EINVAL; @@ -348,7 +348,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, denominator = 10000000; uvc_simplify_fraction(&numerator, &denominator, 8, 333); - memset(parm, 0, sizeof *parm); + memset(parm, 0, sizeof(*parm)); parm->type = stream->type; if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, { struct uvc_streaming_control probe; struct v4l2_fract timeperframe; - uint32_t interval; + struct uvc_format *format; + struct uvc_frame *frame; + u32 interval, maxd; + unsigned int i; int ret; if (parm->type != stream->type) @@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, return -EBUSY; } + format = stream->cur_format; + frame = stream->cur_frame; probe = stream->ctrl; - probe.dwFrameInterval = - uvc_try_frame_interval(stream->cur_frame, interval); + probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); + maxd = abs((s32)probe.dwFrameInterval - interval); + + /* Try frames with matching size to find the best frame interval. */ + for (i = 0; i < format->nframes && maxd != 0; i++) { + u32 d, ival; + + if (&format->frame[i] == stream->cur_frame) + continue; + + if (format->frame[i].wWidth != stream->cur_frame->wWidth || + format->frame[i].wHeight != stream->cur_frame->wHeight) + continue; + + ival = uvc_try_frame_interval(&format->frame[i], interval); + d = abs((s32)ival - interval); + if (d >= maxd) + continue; + + frame = &format->frame[i]; + probe.bFrameIndex = frame->bFrameIndex; + probe.dwFrameInterval = ival; + maxd = d; + } /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); @@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, } stream->ctrl = probe; + stream->cur_frame = frame; mutex_unlock(&stream->mutex); /* Return the actual frame period. */ @@ -498,7 +526,7 @@ static int uvc_v4l2_open(struct file *file) return ret; /* Create the device handle. */ - handle = kzalloc(sizeof *handle, GFP_KERNEL); + handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (handle == NULL) { usb_autopm_put_interface(stream->dev->intf); return -ENOMEM; @@ -577,7 +605,7 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, { struct uvc_format *format; enum v4l2_buf_type type = fmt->type; - __u32 index = fmt->index; + u32 index = fmt->index; if (fmt->type != stream->type || fmt->index >= stream->nformats) return -EINVAL; @@ -1145,8 +1173,9 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, struct uvc_fh *handle = fh; struct uvc_streaming *stream = handle->stream; struct uvc_format *format = NULL; - struct uvc_frame *frame; - int i; + struct uvc_frame *frame = NULL; + unsigned int index; + unsigned int i; /* Look for the given pixel format */ for (i = 0; i < stream->nformats; i++) { @@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, if (format == NULL) return -EINVAL; - if (fsize->index >= format->nframes) + /* Skip duplicate frame sizes */ + for (i = 0, index = 0; i < format->nframes; i++) { + if (frame && frame->wWidth == format->frame[i].wWidth && + frame->wHeight == format->frame[i].wHeight) + continue; + frame = &format->frame[i]; + if (index == fsize->index) + break; + index++; + } + + if (i == format->nframes) return -EINVAL; - frame = &format->frame[fsize->index]; fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = frame->wWidth; fsize->discrete.height = frame->wHeight; @@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, struct uvc_streaming *stream = handle->stream; struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; - int i; + unsigned int nintervals; + unsigned int index; + unsigned int i; /* Look for the given pixel format and frame size */ for (i = 0; i < stream->nformats; i++) { @@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, if (format == NULL) return -EINVAL; + index = fival->index; for (i = 0; i < format->nframes; i++) { if (format->frame[i].wWidth == fival->width && format->frame[i].wHeight == fival->height) { frame = &format->frame[i]; - break; + nintervals = frame->bFrameIntervalType ?: 1; + if (index < nintervals) + break; + index -= nintervals; } } - if (frame == NULL) + if (i == format->nframes) return -EINVAL; if (frame->bFrameIntervalType) { - if (fival->index >= frame->bFrameIntervalType) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete.numerator = - frame->dwFrameInterval[fival->index]; + frame->dwFrameInterval[index]; fival->discrete.denominator = 10000000; uvc_simplify_fraction(&fival->discrete.numerator, &fival->discrete.denominator, 8, 333); } else { - if (fival->index) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; fival->stepwise.min.numerator = frame->dwFrameInterval[0]; fival->stepwise.min.denominator = 10000000; @@ -1261,20 +1300,20 @@ static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, #ifdef CONFIG_COMPAT struct uvc_xu_control_mapping32 { - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; + u32 id; + u8 name[32]; + u8 entity[16]; + u8 selector; - __u8 size; - __u8 offset; - __u32 v4l2_type; - __u32 data_type; + u8 size; + u8 offset; + u32 v4l2_type; + u32 data_type; compat_caddr_t menu_info; - __u32 menu_count; + u32 menu_count; - __u32 reserved[4]; + u32 reserved[4]; }; static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, @@ -1310,10 +1349,10 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, } struct uvc_xu_control_query32 { - __u8 unit; - __u8 selector; - __u8 query; - __u16 size; + u8 unit; + u8 selector; + u8 query; + u16 size; compat_caddr_t data; }; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 5441553f74e1..aa0082fe5833 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -30,11 +30,11 @@ * UVC Controls */ -static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size, +static int __uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size, int timeout) { - __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; unsigned int pipe; pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) @@ -45,7 +45,7 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, unit << 8 | intfnum, data, size, timeout); } -static const char *uvc_query_name(__u8 query) +static const char *uvc_query_name(u8 query) { switch (query) { case UVC_SET_CUR: @@ -69,8 +69,8 @@ static const char *uvc_query_name(__u8 query) } } -int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size) +int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size) { int ret; @@ -164,10 +164,10 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, } static int uvc_get_video_ctrl(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl, int probe, __u8 query) + struct uvc_streaming_control *ctrl, int probe, u8 query) { - __u8 *data; - __u16 size; + u8 *data; + u16 size; int ret; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; @@ -191,7 +191,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " "compliance - GET_MIN/MAX(PROBE) incorrectly " "supported. Enabling workaround.\n"); - memset(ctrl, 0, sizeof *ctrl); + memset(ctrl, 0, sizeof(*ctrl)); ctrl->wCompQuality = le16_to_cpup((__le16 *)data); ret = 0; goto out; @@ -254,8 +254,8 @@ out: static int uvc_set_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe) { - __u8 *data; - __u16 size; + u8 *data; + u16 size; int ret; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; @@ -301,7 +301,7 @@ int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe) { struct uvc_streaming_control probe_min, probe_max; - __u16 bandwidth; + u16 bandwidth; unsigned int i; int ret; @@ -379,7 +379,7 @@ static inline ktime_t uvc_video_get_time(void) static void uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, - const __u8 *data, int len) + const u8 *data, int len) { struct uvc_clock_sample *sample; unsigned int header_size; @@ -705,7 +705,7 @@ done: */ static void uvc_video_stats_decode(struct uvc_streaming *stream, - const __u8 *data, int len) + const u8 *data, int len) { unsigned int header_size; bool has_pts = false; @@ -946,9 +946,9 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream) * uvc_video_decode_end will never be called with a NULL buffer. */ static int uvc_video_decode_start(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { - __u8 fid; + u8 fid; /* Sanity checks: * - packet must be at least 2 bytes long @@ -1009,7 +1009,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, buf->buf.field = V4L2_FIELD_NONE; buf->buf.sequence = stream->sequence; - buf->buf.vb2_buf.timestamp = uvc_video_get_time(); + buf->buf.vb2_buf.timestamp = ktime_to_ns(uvc_video_get_time()); /* TODO: Handle PTS and SCR. */ buf->state = UVC_BUF_STATE_ACTIVE; @@ -1043,7 +1043,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, } static void uvc_video_decode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { unsigned int maxlen, nbytes; void *mem; @@ -1067,7 +1067,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, } static void uvc_video_decode_end(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { /* Mark the buffer as done if the EOF marker is set. */ if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { @@ -1092,7 +1092,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, * video buffer to the transfer buffer. */ static int uvc_video_encode_header(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) + struct uvc_buffer *buf, u8 *data, int len) { data[0] = 2; /* Header length */ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF @@ -1101,7 +1101,7 @@ static int uvc_video_encode_header(struct uvc_streaming *stream, } static int uvc_video_encode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) + struct uvc_buffer *buf, u8 *data, int len) { struct uvc_video_queue *queue = &stream->queue; unsigned int nbytes; @@ -1191,7 +1191,8 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, uvc_trace(UVC_TRACE_FRAME, "%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n", - __func__, time, meta->sof, meta->length, meta->flags, + __func__, ktime_to_ns(time), meta->sof, meta->length, + meta->flags, has_pts ? *(u32 *)meta->buf : 0, has_scr ? *(u32 *)scr : 0, has_scr ? *(u32 *)(scr + 4) & 0x7ff : 0); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index d9e7c70788d0..be5cf179228b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -208,60 +208,60 @@ struct uvc_device; struct uvc_control_info { struct list_head mappings; - __u8 entity[16]; - __u8 index; /* Bit index in bmControls */ - __u8 selector; + u8 entity[16]; + u8 index; /* Bit index in bmControls */ + u8 selector; - __u16 size; - __u32 flags; + u16 size; + u32 flags; }; struct uvc_control_mapping { struct list_head list; struct list_head ev_subs; - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; + u32 id; + u8 name[32]; + u8 entity[16]; + u8 selector; - __u8 size; - __u8 offset; + u8 size; + u8 offset; enum v4l2_ctrl_type v4l2_type; - __u32 data_type; + u32 data_type; struct uvc_menu_info *menu_info; - __u32 menu_count; + u32 menu_count; - __u32 master_id; - __s32 master_manual; - __u32 slave_ids[2]; + u32 master_id; + s32 master_manual; + u32 slave_ids[2]; - __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query, - const __u8 *data); - void (*set) (struct uvc_control_mapping *mapping, __s32 value, - __u8 *data); + s32 (*get)(struct uvc_control_mapping *mapping, u8 query, + const u8 *data); + void (*set)(struct uvc_control_mapping *mapping, s32 value, + u8 *data); }; struct uvc_control { struct uvc_entity *entity; struct uvc_control_info info; - __u8 index; /* Used to match the uvc_control entry with a + u8 index; /* Used to match the uvc_control entry with a uvc_control_info. */ - __u8 dirty:1, - loaded:1, - modified:1, - cached:1, - initialized:1; + u8 dirty:1, + loaded:1, + modified:1, + cached:1, + initialized:1; - __u8 *uvc_data; + u8 *uvc_data; }; struct uvc_format_desc { char *name; - __u8 guid[16]; - __u32 fcc; + u8 guid[16]; + u32 fcc; }; /* The term 'entity' refers to both UVC units and UVC terminals. @@ -287,8 +287,8 @@ struct uvc_entity { * chain. */ unsigned int flags; - __u8 id; - __u16 type; + u8 id; + u16 type; char name[64]; /* Media controller-related fields. */ @@ -300,69 +300,69 @@ struct uvc_entity { union { struct { - __u16 wObjectiveFocalLengthMin; - __u16 wObjectiveFocalLengthMax; - __u16 wOcularFocalLength; - __u8 bControlSize; - __u8 *bmControls; + u16 wObjectiveFocalLengthMin; + u16 wObjectiveFocalLengthMax; + u16 wOcularFocalLength; + u8 bControlSize; + u8 *bmControls; } camera; struct { - __u8 bControlSize; - __u8 *bmControls; - __u8 bTransportModeSize; - __u8 *bmTransportModes; + u8 bControlSize; + u8 *bmControls; + u8 bTransportModeSize; + u8 *bmTransportModes; } media; struct { } output; struct { - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 *bmControls; - __u8 bmVideoStandards; + u16 wMaxMultiplier; + u8 bControlSize; + u8 *bmControls; + u8 bmVideoStandards; } processing; struct { } selector; struct { - __u8 guidExtensionCode[16]; - __u8 bNumControls; - __u8 bControlSize; - __u8 *bmControls; - __u8 *bmControlsType; + u8 guidExtensionCode[16]; + u8 bNumControls; + u8 bControlSize; + u8 *bmControls; + u8 *bmControlsType; } extension; }; - __u8 bNrInPins; - __u8 *baSourceID; + u8 bNrInPins; + u8 *baSourceID; unsigned int ncontrols; struct uvc_control *controls; }; struct uvc_frame { - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u8 bFrameIntervalType; - __u32 dwDefaultFrameInterval; - __u32 *dwFrameInterval; + u8 bFrameIndex; + u8 bmCapabilities; + u16 wWidth; + u16 wHeight; + u32 dwMinBitRate; + u32 dwMaxBitRate; + u32 dwMaxVideoFrameBufferSize; + u8 bFrameIntervalType; + u32 dwDefaultFrameInterval; + u32 *dwFrameInterval; }; struct uvc_format { - __u8 type; - __u8 index; - __u8 bpp; - __u8 colorspace; - __u32 fcc; - __u32 flags; + u8 type; + u8 index; + u8 bpp; + u8 colorspace; + u32 fcc; + u32 flags; char name[32]; @@ -371,16 +371,16 @@ struct uvc_format { }; struct uvc_streaming_header { - __u8 bNumFormats; - __u8 bEndpointAddress; - __u8 bTerminalLink; - __u8 bControlSize; - __u8 *bmaControls; + u8 bNumFormats; + u8 bEndpointAddress; + u8 bTerminalLink; + u8 bControlSize; + u8 *bmaControls; /* The following fields are used by input headers only. */ - __u8 bmInfo; - __u8 bStillCaptureMethod; - __u8 bTriggerSupport; - __u8 bTriggerUsage; + u8 bmInfo; + u8 bStillCaptureMethod; + u8 bTriggerSupport; + u8 bTriggerUsage; }; enum uvc_buffer_state { @@ -490,7 +490,7 @@ struct uvc_streaming { struct usb_interface *intf; int intfnum; - __u16 maxpsize; + u16 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; @@ -517,16 +517,16 @@ struct uvc_streaming { struct { struct video_device vdev; struct uvc_video_queue queue; - __u32 format; + u32 format; } meta; /* Context data used by the bulk completion handler. */ struct { - __u8 header[256]; + u8 header[256]; unsigned int header_size; int skip_payload; - __u32 payload_size; - __u32 max_payload_size; + u32 payload_size; + u32 max_payload_size; } bulk; struct urb *urb[UVC_URBS]; @@ -534,8 +534,8 @@ struct uvc_streaming { dma_addr_t urb_dma[UVC_URBS]; unsigned int urb_size; - __u32 sequence; - __u8 last_fid; + u32 sequence; + u8 last_fid; /* debugfs */ struct dentry *debugfs_dir; @@ -570,8 +570,8 @@ struct uvc_device { struct usb_device *udev; struct usb_interface *intf; unsigned long warnings; - __u32 quirks; - __u32 meta_format; + u32 quirks; + u32 meta_format; int intfnum; char name[32]; @@ -584,8 +584,8 @@ struct uvc_device { struct media_device mdev; #endif struct v4l2_device vdev; - __u16 uvc_version; - __u32 clock_frequency; + u16 uvc_version; + u32 clock_frequency; struct list_head entities; struct list_head chains; @@ -597,7 +597,7 @@ struct uvc_device { /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; - __u8 *status; + u8 *status; struct input_dev *input; char input_phys[64]; }; @@ -667,40 +667,38 @@ extern unsigned int uvc_hw_timestamps_param; /* Core driver */ extern struct uvc_driver uvc_driver; -extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); +struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -extern int uvc_queue_init(struct uvc_video_queue *queue, - enum v4l2_buf_type type, int drop_corrupted); -extern void uvc_queue_release(struct uvc_video_queue *queue); -extern int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb); -extern int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *v4l2_cb); -extern int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp); -extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -extern int uvc_queue_streamon(struct uvc_video_queue *queue, - enum v4l2_buf_type type); -extern int uvc_queue_streamoff(struct uvc_video_queue *queue, - enum v4l2_buf_type type); -extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); -extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf); -extern int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); -extern __poll_t uvc_queue_poll(struct uvc_video_queue *queue, - struct file *file, poll_table *wait); +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + int drop_corrupted); +void uvc_queue_release(struct uvc_video_queue *queue); +int uvc_request_buffers(struct uvc_video_queue *queue, + struct v4l2_requestbuffers *rb); +int uvc_query_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf); +int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *v4l2_cb); +int uvc_queue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf); +int uvc_export_buffer(struct uvc_video_queue *queue, + struct v4l2_exportbuffer *exp); +int uvc_dequeue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf, int nonblocking); +int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type); +int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); +void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); +struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, + struct uvc_buffer *buf); +int uvc_queue_mmap(struct uvc_video_queue *queue, + struct vm_area_struct *vma); +__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, + poll_table *wait); #ifndef CONFIG_MMU -extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff); +unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, + unsigned long pgoff); #endif -extern int uvc_queue_allocated(struct uvc_video_queue *queue); +int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return vb2_is_streaming(&queue->queue); @@ -711,18 +709,18 @@ extern const struct v4l2_ioctl_ops uvc_ioctl_ops; extern const struct v4l2_file_operations uvc_fops; /* Media controller */ -extern int uvc_mc_register_entities(struct uvc_video_chain *chain); -extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); +int uvc_mc_register_entities(struct uvc_video_chain *chain); +void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ -extern int uvc_video_init(struct uvc_streaming *stream); -extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream, int reset); -extern int uvc_video_enable(struct uvc_streaming *stream, int enable); -extern int uvc_probe_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe); -extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size); +int uvc_video_init(struct uvc_streaming *stream); +int uvc_video_suspend(struct uvc_streaming *stream); +int uvc_video_resume(struct uvc_streaming *stream, int reset); +int uvc_video_enable(struct uvc_streaming *stream, int enable); +int uvc_probe_video(struct uvc_streaming *stream, + struct uvc_streaming_control *probe); +int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size); void uvc_video_clock_update(struct uvc_streaming *stream, struct vb2_v4l2_buffer *vbuf, struct uvc_buffer *buf); @@ -737,32 +735,32 @@ int uvc_register_video_device(struct uvc_device *dev, const struct v4l2_ioctl_ops *ioctl_ops); /* Status */ -extern int uvc_status_init(struct uvc_device *dev); -extern void uvc_status_cleanup(struct uvc_device *dev); -extern int uvc_status_start(struct uvc_device *dev, gfp_t flags); -extern void uvc_status_stop(struct uvc_device *dev); +int uvc_status_init(struct uvc_device *dev); +void uvc_status_cleanup(struct uvc_device *dev); +int uvc_status_start(struct uvc_device *dev, gfp_t flags); +void uvc_status_stop(struct uvc_device *dev); /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; -extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl); -extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu); - -extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, - const struct uvc_control_mapping *mapping); -extern int uvc_ctrl_init_device(struct uvc_device *dev); -extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); -extern int uvc_ctrl_restore_values(struct uvc_device *dev); - -extern int uvc_ctrl_begin(struct uvc_video_chain *chain); -extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count); +int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + struct v4l2_queryctrl *v4l2_ctrl); +int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu); + +int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, + const struct uvc_control_mapping *mapping); +int uvc_ctrl_init_device(struct uvc_device *dev); +void uvc_ctrl_cleanup_device(struct uvc_device *dev); +int uvc_ctrl_restore_values(struct uvc_device *dev); + +int uvc_ctrl_begin(struct uvc_video_chain *chain); +int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count); static inline int uvc_ctrl_commit(struct uvc_fh *handle, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count) + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count) { return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count); } @@ -771,25 +769,23 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) return __uvc_ctrl_commit(handle, 1, NULL, 0); } -extern int uvc_ctrl_get(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); -extern int uvc_ctrl_set(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); +int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); +int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, - struct uvc_xu_control_query *xqry); +int uvc_xu_ctrl_query(struct uvc_video_chain *chain, + struct uvc_xu_control_query *xqry); /* Utility functions */ -extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, - unsigned int n_terms, unsigned int threshold); -extern uint32_t uvc_fraction_to_interval(uint32_t numerator, - uint32_t denominator); -extern struct usb_host_endpoint *uvc_find_endpoint( - struct usb_host_interface *alts, __u8 epaddr); +void uvc_simplify_fraction(u32 *numerator, u32 *denominator, + unsigned int n_terms, unsigned int threshold); +u32 uvc_fraction_to_interval(u32 numerator, u32 denominator); +struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, + u8 epaddr); /* Quirks support */ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf, struct uvc_buffer *meta_buf); + struct uvc_buffer *buf, + struct uvc_buffer *meta_buf); /* debugfs and statistics */ void uvc_debugfs_init(void); diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 8b7c19943d46..b8886102c5ed 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -517,8 +517,7 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam, printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n"); return; } - DBG("%s: Buffer 0x%08lx size= %d\n", __func__, - (unsigned long)vbuf, pos); + DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos); /* tell v4l buffer was filled */ buf->vb.field_count = cam->frame_count * 2; @@ -1277,7 +1276,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) DBG("%s: cam == NULL\n", __func__); return -ENODEV; } - DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma); + DBG("mmap called, vma=%p\n", vma); ret = videobuf_mmap_mapper(&cam->vb_vidq, vma); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 82852f23a3b6..7f858c39753c 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1099,23 +1099,14 @@ static int tuner_s_radio(struct v4l2_subdev *sd) */ /** - * tuner_s_power - controls the power state of the tuner + * tuner_standby - places the tuner in standby mode * @sd: pointer to struct v4l2_subdev - * @on: a zero value puts the tuner to sleep, non-zero wakes it up */ -static int tuner_s_power(struct v4l2_subdev *sd, int on) +static int tuner_standby(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (on) { - if (t->standby && set_mode(t, t->mode) == 0) { - dprintk("Waking up tuner\n"); - set_freq(t, 0); - } - return 0; - } - dprintk("Putting tuner to sleep\n"); t->standby = true; if (analog_ops->standby) @@ -1328,10 +1319,10 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg) static const struct v4l2_subdev_core_ops tuner_core_ops = { .log_status = tuner_log_status, - .s_power = tuner_s_power, }; static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = { + .standby = tuner_standby, .s_radio = tuner_s_radio, .g_tuner = tuner_g_tuner, .s_tuner = tuner_s_tuner, diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 8650ad92b64d..b518b92d6d96 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -357,31 +357,35 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } EXPORT_SYMBOL_GPL(v4l_bound_align_image); -const struct v4l2_frmsize_discrete * -v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes, - size_t num_sizes, - s32 width, s32 height) +const void * +__v4l2_find_nearest_size(const void *array, size_t array_size, + size_t entry_size, size_t width_offset, + size_t height_offset, s32 width, s32 height) { - int i; - u32 error, min_error = UINT_MAX; - const struct v4l2_frmsize_discrete *size, *best = NULL; + u32 error, min_error = U32_MAX; + const void *best = NULL; + unsigned int i; - if (!sizes) + if (!array) return NULL; - for (i = 0, size = sizes; i < num_sizes; i++, size++) { - error = abs(size->width - width) + abs(size->height - height); - if (error < min_error) { - min_error = error; - best = size; - } + for (i = 0; i < array_size; i++, array += entry_size) { + const u32 *entry_width = array + width_offset; + const u32 *entry_height = array + height_offset; + + error = abs(*entry_width - width) + abs(*entry_height - height); + if (error > min_error) + continue; + + min_error = error; + best = array; if (!error) break; } return best; } -EXPORT_SYMBOL_GPL(v4l2_find_nearest_format); +EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size); void v4l2_get_timestamp(struct timeval *tv) { @@ -392,3 +396,51 @@ void v4l2_get_timestamp(struct timeval *tv) tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; } EXPORT_SYMBOL_GPL(v4l2_get_timestamp); + +int v4l2_g_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct v4l2_subdev_frame_interval ival = { 0 }; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + if (vdev->device_caps & V4L2_CAP_READWRITE) + a->parm.capture.readbuffers = 2; + if (v4l2_subdev_has_op(sd, video, g_frame_interval)) + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival); + if (!ret) + a->parm.capture.timeperframe = ival.interval; + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_g_parm_cap); + +int v4l2_s_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct v4l2_subdev_frame_interval ival = { + .interval = a->parm.capture.timeperframe + }; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + memset(&a->parm, 0, sizeof(a->parm)); + if (vdev->device_caps & V4L2_CAP_READWRITE) + a->parm.capture.readbuffers = 2; + else + a->parm.capture.readbuffers = 0; + + if (v4l2_subdev_has_op(sd, video, g_frame_interval)) + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival); + if (!ret) + a->parm.capture.timeperframe = ival.interval; + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_s_parm_cap); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ce08b50b8290..d29e45516eb7 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -480,6 +480,57 @@ const char * const *v4l2_ctrl_get_menu(u32 id) NULL, }; + static const char * const hevc_profile[] = { + "Main", + "Main Still Picture", + "Main 10", + NULL, + }; + static const char * const hevc_level[] = { + "1", + "2", + "2.1", + "3", + "3.1", + "4", + "4.1", + "5", + "5.1", + "5.2", + "6", + "6.1", + "6.2", + NULL, + }; + static const char * const hevc_hierarchial_coding_type[] = { + "B", + "P", + NULL, + }; + static const char * const hevc_refresh_type[] = { + "None", + "CRA", + "IDR", + NULL, + }; + static const char * const hevc_size_of_length_field[] = { + "0", + "1", + "2", + "4", + NULL, + }; + static const char * const hevc_tier[] = { + "Main", + "High", + NULL, + }; + static const char * const hevc_loop_filter_mode[] = { + "Disabled", + "Enabled", + "Disabled at slice boundary", + "NULL", + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -575,6 +626,20 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return dv_it_content_type; case V4L2_CID_DETECT_MD_MODE: return detect_md_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + return hevc_profile; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + return hevc_level; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + return hevc_hierarchial_coding_type; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + return hevc_refresh_type; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + return hevc_size_of_length_field; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + return hevc_tier; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + return hevc_loop_filter_mode; default: return NULL; @@ -776,6 +841,53 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: return "VPX Profile"; + /* HEVC controls */ + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile"; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level"; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier"; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding"; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB"; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID"; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing"; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split"; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs"; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; + /* CAMERA controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ case V4L2_CID_CAMERA_CLASS: return "Camera Controls"; @@ -1069,6 +1181,13 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_TUNE_DEEMPHASIS: case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: case V4L2_CID_DETECT_MD_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index e2ee5f00c445..c81faea96fba 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-dv-timings - dv-timings helper functions * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #include <linux/module.h> @@ -27,6 +14,7 @@ #include <linux/v4l2-dv-timings.h> #include <media/v4l2-dv-timings.h> #include <linux/math64.h> +#include <linux/hdmi.h> MODULE_AUTHOR("Hans Verkuil"); MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions"); @@ -814,3 +802,143 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) return aspect; } EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio); + +/** v4l2_hdmi_rx_colorimetry - determine HDMI colorimetry information + * based on various InfoFrames. + * @avi: the AVI InfoFrame + * @hdmi: the HDMI Vendor InfoFrame, may be NULL + * @height: the frame height + * + * Determines the HDMI colorimetry information, i.e. how the HDMI + * pixel color data should be interpreted. + * + * Note that some of the newer features (DCI-P3, HDR) are not yet + * implemented: the hdmi.h header needs to be updated to the HDMI 2.0 + * and CTA-861-G standards. + */ +struct v4l2_hdmi_colorimetry +v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi, + const struct hdmi_vendor_infoframe *hdmi, + unsigned int height) +{ + struct v4l2_hdmi_colorimetry c = { + V4L2_COLORSPACE_SRGB, + V4L2_YCBCR_ENC_DEFAULT, + V4L2_QUANTIZATION_FULL_RANGE, + V4L2_XFER_FUNC_SRGB + }; + bool is_ce = avi->video_code || (hdmi && hdmi->vic); + bool is_sdtv = height <= 576; + bool default_is_lim_range_rgb = avi->video_code > 1; + + switch (avi->colorspace) { + case HDMI_COLORSPACE_RGB: + /* RGB pixel encoding */ + switch (avi->colorimetry) { + case HDMI_COLORIMETRY_EXTENDED: + switch (avi->extended_colorimetry) { + case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB: + c.colorspace = V4L2_COLORSPACE_ADOBERGB; + c.xfer_func = V4L2_XFER_FUNC_ADOBERGB; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + default: + break; + } + break; + default: + break; + } + switch (avi->quantization_range) { + case HDMI_QUANTIZATION_RANGE_LIMITED: + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + break; + case HDMI_QUANTIZATION_RANGE_FULL: + break; + default: + if (default_is_lim_range_rgb) + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + break; + } + break; + + default: + /* YCbCr pixel encoding */ + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + switch (avi->colorimetry) { + case HDMI_COLORIMETRY_NONE: + if (!is_ce) + break; + if (is_sdtv) { + c.colorspace = V4L2_COLORSPACE_SMPTE170M; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + } else { + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + } + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_ITU_601: + c.colorspace = V4L2_COLORSPACE_SMPTE170M; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_ITU_709: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_EXTENDED: + switch (avi->extended_colorimetry) { + case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_XV709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_XV601; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_S_YCC_601: + c.colorspace = V4L2_COLORSPACE_SRGB; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_SRGB; + break; + case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601: + c.colorspace = V4L2_COLORSPACE_ADOBERGB; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_ADOBERGB; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020_CONST_LUM; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + default: /* fall back to ITU_709 */ + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + } + break; + default: + break; + } + /* + * YCC Quantization Range signaling is more-or-less broken, + * let's just ignore this. + */ + break; + } + return c; +} +EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 260288ca4f55..f48c505550e0 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1273,6 +1273,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; case V4L2_PIX_FMT_VP8: descr = "VP8"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; + case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; @@ -2611,7 +2612,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE), IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, INFO_FL_CLEAR(v4l2_enum_dv_timings, pad)), IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, INFO_FL_ALWAYS_COPY), - IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), + IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, pad)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)), IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)), @@ -2832,14 +2833,15 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, size_t array_size = 0; void __user *user_ptr = NULL; void **kernel_ptr = NULL; + const size_t ioc_size = _IOC_SIZE(cmd); /* Copy arguments into temp kernel buffer */ if (_IOC_DIR(cmd) != _IOC_NONE) { - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + if (ioc_size <= sizeof(sbuf)) { parg = sbuf; } else { /* too big to allocate from stack */ - mbuf = kvmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + mbuf = kvmalloc(ioc_size, GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; @@ -2847,7 +2849,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned int n = _IOC_SIZE(cmd); + unsigned int n = ioc_size; /* * In some cases, only a few fields are used as input, @@ -2868,11 +2870,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, goto out; /* zero out anything we don't copy from userspace */ - if (n < _IOC_SIZE(cmd)) - memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); + if (n < ioc_size) + memset((u8 *)parg + n, 0, ioc_size - n); } else { /* read-only ioctl */ - memset(parg, 0, _IOC_SIZE(cmd)); + memset(parg, 0, ioc_size); } } @@ -2930,7 +2932,7 @@ out_array_args: switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + if (copy_to_user((void __user *)arg, parg, ioc_size)) err = -EFAULT; break; } diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index 1d550afeda13..0fc185a2ce90 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Media Controller ancillary functions * @@ -5,16 +7,6 @@ * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com> * Copyright (C) 2006-2010 Nokia Corporation * Copyright (c) 2016 Intel Corporation. - * - * 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 <linux/module.h> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index c5639817db34..f9eed938d348 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -187,27 +187,51 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_QUERYCTRL: + /* + * TODO: this really should be folded into v4l2_queryctrl (this + * currently returns -EINVAL for NULL control handlers). + * However, v4l2_queryctrl() is still called directly by + * drivers as well and until that has been addressed I believe + * it is safer to do the check here. The same is true for the + * other control ioctls below. + */ + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_queryctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERY_EXT_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERYMENU: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_querymenu(vfh->ctrl_handler, arg); case VIDIOC_G_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_g_ctrl(vfh->ctrl_handler, arg); case VIDIOC_S_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_DQEVENT: @@ -239,6 +263,19 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return -EPERM; return v4l2_subdev_call(sd, core, s_register, p); } + case VIDIOC_DBG_G_CHIP_INFO: + { + struct v4l2_dbg_chip_info *p = arg; + + if (p->match.type != V4L2_CHIP_MATCH_SUBDEV || p->match.addr) + return -EINVAL; + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; + } #endif case VIDIOC_LOG_STATUS: { @@ -260,6 +297,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(format->reserved, 0, sizeof(format->reserved)); + memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); } @@ -270,6 +309,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(format->reserved, 0, sizeof(format->reserved)); + memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); } @@ -281,6 +322,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -298,6 +340,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; + memset(crop->reserved, 0, sizeof(crop->reserved)); rval = check_crop(sd, crop); if (rval) return rval; @@ -326,6 +369,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (code->pad >= sd->entity.num_pads) return -EINVAL; + memset(code->reserved, 0, sizeof(code->reserved)); return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); } @@ -340,6 +384,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fse->pad >= sd->entity.num_pads) return -EINVAL; + memset(fse->reserved, 0, sizeof(fse->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); } @@ -350,6 +395,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fi->pad >= sd->entity.num_pads) return -EINVAL; + memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, g_frame_interval, arg); } @@ -359,6 +405,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fi->pad >= sd->entity.num_pads) return -EINVAL; + memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -372,6 +419,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fie->pad >= sd->entity.num_pads) return -EINVAL; + memset(fie->reserved, 0, sizeof(fie->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); } @@ -383,6 +431,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); } @@ -394,6 +443,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); } diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index f412429cf5ba..add2edb23eac 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -244,9 +244,8 @@ static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, goto out_free_pages; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vaddr, - nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + dma->vaddr, nr_pages << PAGE_SHIFT); memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index e68e1d343d53..4c495a10025c 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -23,12 +23,14 @@ source "drivers/staging/media/atomisp/Kconfig" source "drivers/staging/media/bcm2048/Kconfig" -source "drivers/staging/media/cxd2099/Kconfig" - source "drivers/staging/media/davinci_vpfe/Kconfig" source "drivers/staging/media/imx/Kconfig" +source "drivers/staging/media/imx074/Kconfig" + +source "drivers/staging/media/mt9t031/Kconfig" + source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/tegra-vde/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 59a47f69884f..61a5765cb98f 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_I2C_BCM2048) += bcm2048/ -obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ +obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074/ +obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index db054d3c7ed6..f7f7177b9b37 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -28,18 +28,6 @@ config VIDEO_ATOMISP_GC2235 It currently only works with the atomisp driver. -config VIDEO_ATOMISP_OV8858 - tristate "Omnivision ov8858 sensor support" - depends on ACPI - depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP - ---help--- - This is a Video4Linux2 sensor-level driver for the Omnivision - ov8858 RAW sensor. - - OV8858 is a 8M raw sensor. - - It currently only works with the atomisp driver. - config VIDEO_ATOMISP_MSRLIST_HELPER tristate "Helper library to load, parse and apply large register lists." depends on I2C diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 61b7598469eb..93753cb96180 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -1204,57 +1204,6 @@ fail_power_off: return ret; } -static int gc0310_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc0310_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc0310_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc0310_res = gc0310_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc0310_res = gc0310_res_still; - N_RES = N_RES_STILL; - break; - default: - gc0310_res = gc0310_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - static int gc0310_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { @@ -1313,8 +1262,6 @@ static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { static const struct v4l2_subdev_video_ops gc0310_video_ops = { .s_stream = gc0310_s_stream, - .g_parm = gc0310_g_parm, - .s_parm = gc0310_s_parm, .g_frame_interval = gc0310_g_frame_interval, }; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index d8de46da64ae..93f9c618f3d8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -944,57 +944,6 @@ fail_power_off: return ret; } -static int gc2235_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc2235_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc2235_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc2235_res = gc2235_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc2235_res = gc2235_res_still; - N_RES = N_RES_STILL; - break; - default: - gc2235_res = gc2235_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - static int gc2235_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { @@ -1052,8 +1001,6 @@ static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = { static const struct v4l2_subdev_video_ops gc2235_video_ops = { .s_stream = gc2235_s_stream, - .g_parm = gc2235_g_parm, - .s_parm = gc2235_s_parm, .g_frame_interval = gc2235_g_frame_interval, }; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index df253a557c76..834fba8c4fa0 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1684,11 +1684,6 @@ static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value) return !!err; } -static int mt9m114_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - return 0; -} static int mt9m114_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) @@ -1781,7 +1776,6 @@ static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) } static const struct v4l2_subdev_video_ops mt9m114_video_ops = { - .s_parm = mt9m114_s_parm, .s_stream = mt9m114_s_stream, .g_frame_interval = mt9m114_g_frame_interval, }; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 84f8d33ce2d1..11412061c40e 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -1280,60 +1280,6 @@ fail_power_off: return ret; } -static int ov2680_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2680_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2680_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - dev->run_mode = param->parm.capture.capturemode; - - v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode); - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2680_res = ov2680_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2680_res = ov2680_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - static int ov2680_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { @@ -1387,8 +1333,6 @@ static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) static const struct v4l2_subdev_video_ops ov2680_video_ops = { .s_stream = ov2680_s_stream, - .g_parm = ov2680_g_parm, - .s_parm = ov2680_s_parm, .g_frame_interval = ov2680_g_frame_interval, }; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 2b6ae0faf972..e59358ac89ce 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -1083,57 +1083,6 @@ fail_power_off: return ret; } -static int ov2722_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2722_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2722_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2722_res = ov2722_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2722_res = ov2722_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2722_res = ov2722_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - static int ov2722_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { @@ -1192,8 +1141,6 @@ static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = { static const struct v4l2_subdev_video_ops ov2722_video_ops = { .s_stream = ov2722_s_stream, - .g_parm = ov2722_g_parm, - .s_parm = ov2722_s_parm, .g_frame_interval = ov2722_g_frame_interval, }; diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index c422d0398fc7..af6b11f6e5e7 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -150,7 +150,6 @@ struct gc0310_device { struct camera_sensor_platform_data *platform_data; int vt_pix_clk_freq_mhz; int fmt_idx; - int run_mode; u8 res; u8 type; }; @@ -400,48 +399,6 @@ struct gc0310_resolution gc0310_res_preview[] = { }; #define N_RES_PREVIEW (ARRAY_SIZE(gc0310_res_preview)) -struct gc0310_resolution gc0310_res_still[] = { - { - .desc = "gc0310_VGA_30fps", - .width = 656, // 648, - .height = 496, // 488, - .fps = 30, - //.pix_clk_freq = 73, - .used = 0, -#if 0 - .pixels_per_line = 0x0314, - .lines_per_frame = 0x0213, -#endif - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .skip_frames = 2, - .regs = gc0310_VGA_30fps, - }, -}; -#define N_RES_STILL (ARRAY_SIZE(gc0310_res_still)) - -struct gc0310_resolution gc0310_res_video[] = { - { - .desc = "gc0310_VGA_30fps", - .width = 656, // 648, - .height = 496, // 488, - .fps = 30, - //.pix_clk_freq = 73, - .used = 0, -#if 0 - .pixels_per_line = 0x0314, - .lines_per_frame = 0x0213, -#endif - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .skip_frames = 2, - .regs = gc0310_VGA_30fps, - }, -}; -#define N_RES_VIDEO (ARRAY_SIZE(gc0310_res_video)) - static struct gc0310_resolution *gc0310_res = gc0310_res_preview; static unsigned long N_RES = N_RES_PREVIEW; #endif diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 3c30a05c3991..0e805bcfa4d8 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -156,7 +156,6 @@ struct gc2235_device { struct camera_sensor_platform_data *platform_data; int vt_pix_clk_freq_mhz; int fmt_idx; - int run_mode; u8 res; u8 type; }; @@ -575,6 +574,11 @@ static struct gc2235_resolution gc2235_res_preview[] = { }; #define N_RES_PREVIEW (ARRAY_SIZE(gc2235_res_preview)) +/* + * Disable non-preview configurations until the configuration selection is + * improved. + */ +#if 0 static struct gc2235_resolution gc2235_res_still[] = { { .desc = "gc2235_1600_900_30fps", @@ -659,6 +663,7 @@ static struct gc2235_resolution gc2235_res_video[] = { }; #define N_RES_VIDEO (ARRAY_SIZE(gc2235_res_video)) +#endif static struct gc2235_resolution *gc2235_res = gc2235_res_preview; static unsigned long N_RES = N_RES_PREVIEW; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 03f75dd80f87..cb38e6e79409 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -850,74 +850,6 @@ struct ov2680_format { }; #define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview)) -static struct ov2680_resolution ov2680_res_still[] = { - { - .desc = "ov2680_1616x1216_30fps", - .width = 1616, - .height = 1216, - .pix_clk_freq = 66, - .fps = 30, - .used = 0, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x1216_30fps, - }, - { - .desc = "ov2680_1616x916_30fps", - .width = 1616, - .height = 916, - .fps = 30, - .pix_clk_freq = 66, - .used = 0, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x916_30fps, - }, -}; -#define N_RES_STILL (ARRAY_SIZE(ov2680_res_still)) - -static struct ov2680_resolution ov2680_res_video[] = { - { - .desc = "ov2680_1616x1216_30fps", - .width = 1616, - .height = 1216, - .pix_clk_freq = 66, - .fps = 30, - .used = 0, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x1216_30fps, - }, - { - .desc = "ov2680_720p_30fps", - .width = 1616, - .height = 916, - .fps = 30, - .pix_clk_freq = 66, - .used = 0, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x916_30fps, - }, -}; -#define N_RES_VIDEO (ARRAY_SIZE(ov2680_res_video)) - static struct ov2680_resolution *ov2680_res = ov2680_res_preview; static unsigned long N_RES = N_RES_PREVIEW; diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index d8a973d71699..028b04aaaa8f 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -1148,6 +1148,11 @@ struct ov2722_resolution ov2722_res_preview[] = { }; #define N_RES_PREVIEW (ARRAY_SIZE(ov2722_res_preview)) +/* + * Disable non-preview configurations until the configuration selection is + * improved. + */ +#if 0 struct ov2722_resolution ov2722_res_still[] = { { .desc = "ov2722_480P_30fps", @@ -1250,6 +1255,7 @@ struct ov2722_resolution ov2722_res_video[] = { }, }; #define N_RES_VIDEO (ARRAY_SIZE(ov2722_res_video)) +#endif static struct ov2722_resolution *ov2722_res = ov2722_res_preview; static unsigned long N_RES = N_RES_PREVIEW; diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 40d01bf4bf28..30a735e59e54 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1805,58 +1805,6 @@ fail_power_off: return ret; } -static int ov5693_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov5693_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov5693_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov5693_res = ov5693_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov5693_res = ov5693_res_still; - N_RES = N_RES_STILL; - break; - default: - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - static int ov5693_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { @@ -1899,8 +1847,6 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ov5693_video_ops = { .s_stream = ov5693_s_stream, - .g_parm = ov5693_g_parm, - .s_parm = ov5693_s_parm, .g_frame_interval = ov5693_g_frame_interval, }; @@ -1947,7 +1893,7 @@ static int ov5693_probe(struct i2c_client *client) struct ov5693_device *dev; int i2c; int ret = 0; - void *pdata = client->dev.platform_data; + void *pdata; unsigned int i; /* diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index 68cfcb4a6c3c..6d27dd849a62 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -1147,6 +1147,11 @@ struct ov5693_resolution ov5693_res_preview[] = { }; #define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview)) +/* + * Disable non-preview configurations until the configuration selection is + * improved. + */ +#if 0 struct ov5693_resolution ov5693_res_still[] = { { .desc = "ov5693_736x496_30fps", @@ -1364,6 +1369,7 @@ struct ov5693_resolution ov5693_res_video[] = { }, }; #define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video)) +#endif static struct ov5693_resolution *ov5693_res = ov5693_res_preview; static unsigned long N_RES = N_RES_PREVIEW; diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c deleted file mode 100644 index 3cf8c710ac65..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ /dev/null @@ -1,2169 +0,0 @@ -/* - * Support for OmniVision ov8858 camera sensor. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#include <linux/delay.h> -#include <linux/module.h> -#include <media/v4l2-device.h> -#include <linux/acpi.h> -#include "../include/linux/atomisp_gmin_platform.h" -#ifdef CONFIG_PLATFORM_BTNS -#include "ov8858_btns.h" -#else -#include "ov8858.h" -#endif -static int ov8858_i2c_read(struct i2c_client *client, u16 len, u16 addr, - u8 *buf) -{ - struct i2c_msg msg[2]; - u8 address[2]; - int err; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no adapter\n", __func__); - return -ENODEV; - } - - dev_dbg(&client->dev, "%s: len = %d, addr = 0x%04x\n", - __func__, len, addr); - - memset(msg, 0, sizeof(msg)); - - address[0] = (addr >> 8) & 0xff; - address[1] = addr & 0xff; - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = address; - - msg[1].addr = client->addr; - msg[1].len = len; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - - err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (err != 2) { - if (err >= 0) - err = -EIO; - goto error; - } - - return 0; -error: - dev_err(&client->dev, "reading from address 0x%x error %d", addr, err); - return err; -} - -static int ov8858_read_reg(struct i2c_client *client, u16 type, u16 reg, - u16 *val) -{ - u8 data[OV8858_SHORT_MAX]; - int err; - - dev_dbg(&client->dev, "%s: type = %d, reg = 0x%04x\n", - __func__, type, reg); - - /* read only 8 and 16 bit values */ - if (type != OV8858_8BIT && type != OV8858_16BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(data, 0, sizeof(data)); - - err = ov8858_i2c_read(client, type, reg, data); - if (err) - goto error; - - /* high byte comes first */ - if (type == OV8858_8BIT) - *val = (u8)data[0]; - else - *val = data[0] << 8 | data[1]; - - dev_dbg(&client->dev, "%s: val = 0x%04x\n", __func__, *val); - - return 0; - -error: - dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); - return err; -} - -static int ov8858_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int -ov8858_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - dev_dbg(&client->dev, - "%s: data_length = %d, reg = 0x%04x, val = 0x%04x\n", - __func__, data_length, reg, val); - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no adapter\n", __func__); - return -ENODEV; - } - - if (data_length != OV8858_8BIT && data_length != OV8858_16BIT) { - dev_err(&client->dev, "%s error, invalid length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - wreg = (u16 *)data; - *wreg = cpu_to_be16(reg); - - if (data_length == OV8858_8BIT) { - data[2] = (u8)(val); - } else { - /* OV8858_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = be16_to_cpu(val); - } - - ret = ov8858_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov8858_write_reg_array - Initializes a list of registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov8858_flush_reg_array(), __ov8858_buf_reg_array() and - * __ov8858_write_reg_is_consecutive() are internal functions to - * ov8858_write_reg_array() and should be not used anywhere else. - * - */ -static int __ov8858_flush_reg_array(struct i2c_client *client, - struct ov8858_write_ctrl *ctrl) -{ - u16 size; - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov8858_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov8858_buf_reg_array(struct i2c_client *client, - struct ov8858_write_ctrl *ctrl, - const struct ov8858_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV8858_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV8858_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->sreg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV8858_MAX_WRITE_BUF_SIZE) - __ov8858_flush_reg_array(client, ctrl); - - return 0; -} - -static int -__ov8858_write_reg_is_consecutive(struct i2c_client *client, - struct ov8858_write_ctrl *ctrl, - const struct ov8858_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->sreg; -} - -static int ov8858_write_reg_array(struct i2c_client *client, - const struct ov8858_reg *reglist) -{ - const struct ov8858_reg *next = reglist; - struct ov8858_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV8858_TOK_TERM; next++) { - switch (next->type & OV8858_TOK_MASK) { - case OV8858_TOK_DELAY: - err = __ov8858_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceeding - */ - if (!__ov8858_write_reg_is_consecutive(client, - &ctrl, next)) { - err = __ov8858_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov8858_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error\n", - __func__); - return err; - } - break; - } - } - - return __ov8858_flush_reg_array(client, &ctrl); -} - -static int __ov8858_min_fps_diff(int fps, - const struct ov8858_fps_setting *fps_list) -{ - int diff = INT_MAX; - int i; - - if (fps == 0) - return 0; - - for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { - if (!fps_list[i].fps) - break; - if (abs(fps_list[i].fps - fps) < diff) - diff = abs(fps_list[i].fps - fps); - } - - return diff; -} - -static int __ov8858_nearest_fps_index(int fps, - const struct ov8858_fps_setting *fps_list) -{ - int fps_index = 0; - int i; - - for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { - if (!fps_list[i].fps) - break; - if (abs(fps_list[i].fps - fps) - < abs(fps_list[fps_index].fps - fps)) - fps_index = i; - } - return fps_index; -} - -static int __ov8858_update_frame_timing(struct v4l2_subdev *sd, - u16 *hts, u16 *vts) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - - dev_dbg(&client->dev, "%s OV8858_TIMING_HTS=0x%04x\n", - __func__, *hts); - - /* HTS = pixel_per_line / 2 */ - ret = ov8858_write_reg(client, OV8858_16BIT, - OV8858_TIMING_HTS, *hts >> 1); - if (ret) - return ret; - dev_dbg(&client->dev, "%s OV8858_TIMING_VTS=0x%04x\n", - __func__, *vts); - - return ov8858_write_reg(client, OV8858_16BIT, OV8858_TIMING_VTS, *vts); -} - -static int __ov8858_set_exposure(struct v4l2_subdev *sd, int exposure, int gain, - int dig_gain, u16 *hts, u16 *vts) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int exp_val, ret; - dev_dbg(&client->dev, "%s, exposure = %d, gain=%d, dig_gain=%d\n", - __func__, exposure, gain, dig_gain); - - if (dev->limit_exposure_flag) { - if (exposure > *vts - OV8858_INTEGRATION_TIME_MARGIN) - exposure = *vts - OV8858_INTEGRATION_TIME_MARGIN; - } else { - if (*vts < exposure + OV8858_INTEGRATION_TIME_MARGIN) - *vts = (u16) exposure + OV8858_INTEGRATION_TIME_MARGIN; - } - - ret = __ov8858_update_frame_timing(sd, hts, vts); - if (ret) - return ret; - - /* For ov8858, the low 4 bits are fraction bits and must be kept 0 */ - exp_val = exposure << 4; - ret = ov8858_write_reg(client, OV8858_8BIT, - OV8858_LONG_EXPO+2, exp_val & 0xFF); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_8BIT, - OV8858_LONG_EXPO+1, (exp_val >> 8) & 0xFF); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_8BIT, - OV8858_LONG_EXPO, (exp_val >> 16) & 0x0F); - if (ret) - return ret; - - /* Digital gain : to all MWB channel gains */ - if (dig_gain) { - ret = ov8858_write_reg(client, OV8858_16BIT, - OV8858_MWB_RED_GAIN_H, dig_gain); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_16BIT, - OV8858_MWB_GREEN_GAIN_H, dig_gain); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_16BIT, - OV8858_MWB_BLUE_GAIN_H, dig_gain); - if (ret) - return ret; - } - - ret = ov8858_write_reg(client, OV8858_16BIT, OV8858_LONG_GAIN, - gain & 0x07ff); - if (ret) - return ret; - - dev->gain = gain; - dev->exposure = exposure; - dev->digital_gain = dig_gain; - - return 0; -} - -static int ov8858_set_exposure(struct v4l2_subdev *sd, int exposure, int gain, - int dig_gain) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - const struct ov8858_resolution *res; - u16 hts, vts; - int ret; - - mutex_lock(&dev->input_lock); - - /* Validate exposure: cannot exceed 16bit value */ - exposure = clamp_t(int, exposure, 0, OV8858_MAX_EXPOSURE_VALUE); - - /* Validate gain: must not exceed maximum 8bit value */ - gain = clamp_t(int, gain, 0, OV8858_MAX_GAIN_VALUE); - - /* Validate digital gain: must not exceed 12 bit value*/ - dig_gain = clamp_t(int, dig_gain, 0, OV8858_MWB_GAIN_MAX); - - res = &dev->curr_res_table[dev->fmt_idx]; - /* - * Vendor: HTS reg value is half the total pixel line - */ - hts = res->fps_options[dev->fps_index].pixels_per_line; - vts = res->fps_options[dev->fps_index].lines_per_frame; - - ret = __ov8858_set_exposure(sd, exposure, gain, dig_gain, &hts, &vts); - - mutex_unlock(&dev->input_lock); - - return ret; -} - -/* - When exposure gain value set to sensor, the sensor changed value. - So we need the function to get real value - */ -static int ov8858_g_update_exposure(struct v4l2_subdev *sd, - struct atomisp_update_exposure *exposure) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int gain = exposure->gain; - - dev_dbg(&client->dev, "%s: gain: %d, digi_gain: %d\n", __func__, - exposure->gain, exposure->digi_gain); - exposure->update_digi_gain = dev->digital_gain; - /* This real gain value fetching function is provided by vendor */ - exposure->update_gain = (((gain & 0x700) >> 8) + 1) * (gain & 0xFF); - - return 0; -} - -static int ov8858_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - return ov8858_set_exposure(sd, exposure->integration_time[0], - exposure->gain[0], exposure->gain[1]); -} - -static int ov8858_priv_int_data_init(struct v4l2_subdev *sd) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 size = OV8858_OTP_END_ADDR - OV8858_OTP_START_ADDR + 1; - int r; - u16 isp_ctrl2 = 0; - - if (!dev->otp_data) { - dev->otp_data = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!dev->otp_data) { - r = -ENOMEM; - goto error3; - } - - /* Streaming has to be on */ - r = ov8858_write_reg(client, OV8858_8BIT, OV8858_STREAM_MODE, - 0x01); - if (r) - goto error2; - - /* Turn off Dead Pixel Correction */ - r = ov8858_read_reg(client, OV8858_8BIT, - OV8858_OTP_ISP_CTRL2, &isp_ctrl2); - if (r) - goto error1; - - r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2, - isp_ctrl2 & ~OV8858_OTP_DPC_ENABLE); - if (r) - goto error1; - - /* Enable partial OTP read mode */ - r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_MODE_CTRL, - OV8858_OTP_MODE_PROGRAM_DISABLE | - OV8858_OTP_MODE_MANUAL); - if (r) - goto error1; - - /* Set address range of OTP memory to read */ - r = ov8858_write_reg(client, OV8858_16BIT, - OV8858_OTP_START_ADDR_REG, - OV8858_OTP_START_ADDR); - if (r) - goto error1; - - r = ov8858_write_reg(client, OV8858_16BIT, - OV8858_OTP_END_ADDR_REG, - OV8858_OTP_END_ADDR); - if (r) - goto error1; - - /* Load the OTP data into the OTP buffer */ - r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_LOAD_CTRL, - OV8858_OTP_LOAD_ENABLE); - if (r) - goto error1; - - /* Wait for the data to load into the buffer */ - usleep_range(5000, 5500); - - /* Read the OTP data from the buffer */ - r = ov8858_i2c_read(client, size, OV8858_OTP_START_ADDR, - dev->otp_data); - if (r) - goto error1; - - /* Turn on Dead Pixel Correction */ - r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2, - isp_ctrl2 | OV8858_OTP_DPC_ENABLE); - if (r) - goto error1; - - /* Stop streaming */ - r = ov8858_write_reg(client, 1, OV8858_STREAM_MODE, 0x00); - if (r) { - dev_err(&client->dev, "%s: cannot turn off streaming\n", - __func__); - goto error1; - } - } - - - return 0; - -error1: - /* Turn on Dead Pixel Correction and set streaming off */ - ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2, - isp_ctrl2 | OV8858_OTP_DPC_ENABLE); - ov8858_write_reg(client, 1, OV8858_STREAM_MODE, 0x00); -error2: - devm_kfree(&client->dev, dev->otp_data); - dev->otp_data = NULL; -error3: - dev_err(&client->dev, "%s: OTP reading failed\n", __func__); - return r; -} - -static int ov8858_g_priv_int_data(struct v4l2_subdev *sd, - struct v4l2_private_int_data *priv) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 size = OV8858_OTP_END_ADDR - OV8858_OTP_START_ADDR + 1; - int r; - - mutex_lock(&dev->input_lock); - - if (!dev->otp_data) { - dev_err(&client->dev, "%s: otp data is NULL\n", __func__); - mutex_unlock(&dev->input_lock); - return -EFAULT; - } - - if (copy_to_user(priv->data, dev->otp_data, - min_t(__u32, priv->size, size))) { - r = -EFAULT; - dev_err(&client->dev, "%s: OTP reading failed\n", __func__); - mutex_unlock(&dev->input_lock); - return r; - } - - priv->size = size; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int __ov8858_init(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret; - dev_dbg(&client->dev, "%s\n", __func__); - - /* Sets the default FPS */ - dev->fps_index = 0; - - /* Set default exposure values (initially start values) */ - dev->exposure = 256; - dev->gain = 16; - dev->digital_gain = 1024; - dev->limit_exposure_flag = false; - - dev_dbg(&client->dev, "%s: Writing basic settings to ov8858\n", - __func__); - ret = ov8858_write_reg_array(client, ov8858_BasicSettings); - if (ret) - return ret; - - return ov8858_priv_int_data_init(sd); -} - -static int ov8858_init(struct v4l2_subdev *sd, u32 val) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov8858_init(sd); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static void ov8858_uninit(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct v4l2_ctrl *ctrl; - dev_dbg(&client->dev, "%s:\n", __func__); - - dev->exposure = 0; - dev->gain = 0; - dev->digital_gain = 0; - dev->limit_exposure_flag = false; - mutex_unlock(&dev->input_lock); - ctrl = v4l2_ctrl_find(sd->ctrl_handler, - V4L2_CID_EXPOSURE_AUTO_PRIORITY); - if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, V4L2_EXPOSURE_AUTO); - mutex_lock(&dev->input_lock); -} - -static int ov8858_g_comp_delay(struct v4l2_subdev *sd, unsigned int *usec) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret = 0, exposure; - u16 vts, data; - - if (dev->exposure == 0) { - ret = ov8858_read_reg(client, OV8858_16BIT, - OV8858_LONG_EXPO + 1, &data); - if (ret) - return ret; - exposure = data; - exposure >>= 4; - } else { - exposure = dev->exposure; - } - - ret = ov8858_read_reg(client, OV8858_16BIT, OV8858_TIMING_VTS, &vts); - if (ret || vts == 0) - vts = OV8858_DEPTH_VTS_CONST; - - *usec = (exposure * 33333 / vts); - if (*usec > OV8858_DEPTH_COMP_CONST) - *usec = *usec - OV8858_DEPTH_COMP_CONST; - else - *usec = OV8858_DEPTH_COMP_CONST; - - return 0; -} - -static long ov8858_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov8858_s_exposure(sd, (struct atomisp_exposure *)arg); - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - return ov8858_g_priv_int_data(sd, arg); - case ATOMISP_IOC_G_DEPTH_SYNC_COMP: - return ov8858_g_comp_delay(sd, (unsigned int *)arg); - case ATOMISP_IOC_G_UPDATE_EXPOSURE: - return ov8858_g_update_exposure(sd, - (struct atomisp_update_exposure *)arg); - default: - dev_dbg(&client->dev, "Unhandled command 0x%X\n", cmd); - return -EINVAL; - } -} - -static int __power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - if (dev->platform_data->v1p2_ctrl) { - ret = dev->platform_data->v1p2_ctrl(sd, flag); - if (ret) { - dev_err(&client->dev, - "failed to power %s 1.2v power rail\n", - flag ? "up" : "down"); - return ret; - } - } - - if (dev->platform_data->v2p8_ctrl) { - ret = dev->platform_data->v2p8_ctrl(sd, flag); - if (ret) { - dev_err(&client->dev, - "failed to power %s 2.8v power rail\n", - flag ? "up" : "down"); - return ret; - } - } - - if (dev->platform_data->v1p8_ctrl) { - ret = dev->platform_data->v1p8_ctrl(sd, flag); - if (ret) { - dev_err(&client->dev, - "failed to power %s 1.8v power rail\n", - flag ? "up" : "down"); - if (dev->platform_data->v2p8_ctrl) - dev->platform_data->v2p8_ctrl(sd, 0); - return ret; - } - } - - if (flag) - msleep(20); /* Wait for power lines to stabilize */ - return ret; -} - -static int __gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct i2c_client *client; - struct ov8858_device *dev; - - if (!sd) - return -EINVAL; - - client = v4l2_get_subdevdata(sd); - dev = to_ov8858_sensor(sd); - - if (!client || !dev || !dev->platform_data) - return -ENODEV; - - if (dev->platform_data->gpio0_ctrl) - return dev->platform_data->gpio0_ctrl(sd, flag); - - dev_err(&client->dev, "failed to find platform gpio callback\n"); - - return -EINVAL; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret; - dev_dbg(&client->dev, "%s\n", __func__); - - /* Enable power */ - ret = __power_ctrl(sd, 1); - if (ret) { - dev_err(&client->dev, "power rail on failed %d.\n", ret); - goto fail_power; - } - - /* Enable clock */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) { - dev_err(&client->dev, "flisclk on failed %d\n", ret); - goto fail_clk; - } - - /* Release reset */ - ret = __gpio_ctrl(sd, 1); - if (ret) { - dev_err(&client->dev, "gpio on failed %d\n", ret); - goto fail_gpio; - } - - /* Minumum delay is 8192 clock cycles before first i2c transaction, - * which is 1.37 ms at the lowest allowed clock rate 6 MHz */ - usleep_range(2000, 2500); - return 0; - -fail_gpio: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - __power_ctrl(sd, 0); -fail_power: - dev_err(&client->dev, "Sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - dev_dbg(&client->dev, "%s\n", __func__); - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk off failed\n"); - - ret = __gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio off failed\n"); - - ret = __power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "power rail off failed.\n"); - - return ret; -} - -static int __ov8858_s_power(struct v4l2_subdev *sd, int on) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret, r = 0; - - if (on == 0) { - ov8858_uninit(sd); - if (dev->vcm_driver && dev->vcm_driver->power_down) - r = dev->vcm_driver->power_down(sd); - ret = power_down(sd); - if (r != 0 && ret == 0) - ret = r; - } else { - ret = power_up(sd); - if (ret) - power_down(sd); - if (dev->vcm_driver && dev->vcm_driver->power_up) { - ret = dev->vcm_driver->power_up(sd); - if (ret) { - power_down(sd); - return ret; - } - } - return __ov8858_init(sd); - } - - return ret; -} - -static int ov8858_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - struct ov8858_device *dev = to_ov8858_sensor(sd); - - mutex_lock(&dev->input_lock); - ret = __ov8858_s_power(sd, on); - mutex_unlock(&dev->input_lock); - - /* - * FIXME: Compatibility with old behaviour: return to preview - * when the device is power cycled. - */ - if (!ret && on) - v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); - - return ret; -} - -/* - * Return value of the specified register, first try getting it from - * the register list and if not found, get from the sensor via i2c. - */ -static int ov8858_get_register(struct v4l2_subdev *sd, int reg, int type, - const struct ov8858_reg *reglist) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct ov8858_reg *next; - u16 val; - - /* Try if the values are in the register list */ - for (next = reglist; next->type != OV8858_TOK_TERM; next++) { - if (next->sreg == reg) { - if (type == OV8858_8BIT) - return next->val; - - if (type == OV8858_16BIT && - next[1].type != OV8858_TOK_TERM) - return next[0].val << 8 | next[1].val; - } - } - - /* If not, read from sensor */ - if (ov8858_read_reg(client, type, reg, &val)) { - dev_err(&client->dev, "failed to read register 0x%08x\n", reg); - return -EIO; - } - - return val; -} - -static inline int ov8858_get_register_16bit(struct v4l2_subdev *sd, int reg, - const struct ov8858_reg *reglist) -{ - return ov8858_get_register(sd, reg, OV8858_16BIT, reglist); -} - -static inline int ov8858_get_register_8bit(struct v4l2_subdev *sd, int reg, - const struct ov8858_reg *reglist) -{ - return ov8858_get_register(sd, reg, OV8858_8BIT, reglist); -} - -static int __ov8858_get_pll1_values(struct v4l2_subdev *sd, - int *value, - const struct ov8858_reg *reglist) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int prediv_idx; - unsigned int multiplier; - unsigned int sys_prediv; - unsigned int prediv_coef[] = {2, 3, 4, 5, 6, 8, 12, 16}; - int ret; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL1_PREDIV0, reglist); - if (ret < 0) - return ret; - - if (ret & OV8858_PLL1_PREDIV0_MASK) - *value /= 2; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL1_PREDIV, reglist); - - if (ret < 0) - return ret; - - prediv_idx = ret & OV8858_PLL1_PREDIV_MASK; - *value = *value * 2 / prediv_coef[prediv_idx]; - - ret = ov8858_get_register_16bit(sd, OV8858_PLL1_MULTIPLIER, reglist); - if (ret < 0) - return ret; - - multiplier = ret; - *value *= multiplier & OV8858_PLL1_MULTIPLIER_MASK; - ret = ov8858_get_register_8bit(sd, OV8858_PLL1_SYS_PRE_DIV, reglist); - - if (ret < 0) - return ret; - - sys_prediv = ret & OV8858_PLL1_SYS_PRE_DIV_MASK; - *value /= (sys_prediv + 3); - ret = ov8858_get_register_8bit(sd, OV8858_PLL1_SYS_DIVIDER, reglist); - - if (ret < 0) - return ret; - - if (ret & OV8858_PLL1_SYS_DIVIDER_MASK) - *value /= 2; - - dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value); - - return 0; -} - -static int __ov8858_get_pll2a_values(struct v4l2_subdev *sd, int *value, - const struct ov8858_reg *reglist) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int prediv_idx; - unsigned int multiplier; - unsigned int prediv_coef[] = {2, 3, 4, 5, 6, 8, 12, 16}; - int ret; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL2_PREDIV0, reglist); - if (ret < 0) - return ret; - - if (ret & OV8858_PLL2_PREDIV0_MASK) - *value /= 2; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL2_PREDIV, reglist); - if (ret < 0) - return ret; - - prediv_idx = (ret & OV8858_PLL2_PREDIV_MASK); - *value = *value * 2 / prediv_coef[prediv_idx]; - - ret = ov8858_get_register_16bit(sd, OV8858_PLL2_MULTIPLIER, reglist); - if (ret < 0) - return ret; - - multiplier = ret; - *value *= multiplier & OV8858_PLL2_MULTIPLIER_MASK; - dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value); - - return 0; -} -static int __ov8858_get_pll2b_values(struct v4l2_subdev *sd, int *value, - const struct ov8858_reg *reglist) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int dac_divider; - int ret; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL2_DAC_DIVIDER, reglist); - if (ret < 0) - return ret; - - dac_divider = (ret & OV8858_PLL2_DAC_DIVIDER_MASK) + 1; - *value /= dac_divider; - - dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value); - - return 0; -} -static int __ov8858_get_pll2c_values(struct v4l2_subdev *sd, int *value, - const struct ov8858_reg *reglist) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int sys_pre_div; - unsigned int sys_divider_idx; - unsigned int sys_divider_coef[] = {2, 3, 4, 5, 6, 7, 8, 10}; - int ret; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL2_SYS_PRE_DIV, reglist); - if (ret < 0) - return ret; - - sys_pre_div = (ret & OV8858_PLL2_SYS_PRE_DIV_MASK) + 1; - *value /= sys_pre_div; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL2_SYS_DIVIDER, reglist); - if (ret < 0) - return ret; - - sys_divider_idx = ret & OV8858_PLL2_SYS_DIVIDER_MASK; - *value *= 2 / sys_divider_coef[sys_divider_idx]; - - dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value); - - return 0; -} - -static int ov8858_get_intg_factor(struct v4l2_subdev *sd, - struct camera_mipi_info *info, - const struct ov8858_reg *reglist) -{ - const unsigned int ext_clk = 19200000; /* Hz */ - struct atomisp_sensor_mode_data *m = &info->data; - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *d = &client->dev; - const struct ov8858_resolution *res = - &dev->curr_res_table[dev->fmt_idx]; - unsigned int pll_sclksel1; - unsigned int pll_sclksel2; - unsigned int sys_pre_div; - unsigned int sclk_pdiv; - unsigned int sclk = ext_clk; - u16 hts; - int ret; - - memset(&info->data, 0, sizeof(info->data)); - - ret = ov8858_get_register_8bit(sd, OV8858_PLL_SCLKSEL1, reglist); - if (ret < 0) - return ret; - - dev_dbg(d, "%s: OV8858_PLL_SCLKSEL1: 0x%02x\n", __func__, ret); - pll_sclksel1 = ret & OV8858_PLL_SCLKSEL1_MASK; - - ret = ov8858_get_register_8bit(sd, OV8858_PLL_SCLKSEL2, reglist); - if (ret < 0) - return ret; - - dev_dbg(d, "%s: OV8858_PLL_SCLKSEL2: 0x%02x\n", __func__, ret); - pll_sclksel2 = ret & OV8858_PLL_SCLKSEL2_MASK; - - if (pll_sclksel2) { - ret = __ov8858_get_pll2a_values(sd, &sclk, reglist); - if (ret < 0) - return ret; - ret = __ov8858_get_pll2b_values(sd, &sclk, reglist); - if (ret < 0) - return ret; - } else if (pll_sclksel1) { - ret = __ov8858_get_pll2a_values(sd, &sclk, reglist); - if (ret < 0) - return ret; - ret = __ov8858_get_pll2c_values(sd, &sclk, reglist); - if (ret < 0) - return ret; - } else { - ret = __ov8858_get_pll1_values(sd, &sclk, reglist); - if (ret < 0) - return ret; - } - - ret = ov8858_get_register_8bit(sd, OV8858_SRB_HOST_INPUT_DIS, reglist); - if (ret < 0) - return ret; - - dev_dbg(d, "%s: OV8858_SRB_HOST_INPUT_DIS: 0x%02x\n", __func__, ret); - - sys_pre_div = ret & OV8858_SYS_PRE_DIV_MASK; - sys_pre_div >>= OV8858_SYS_PRE_DIV_OFFSET; - - if (sys_pre_div == 1) - sclk /= 2; - else if (sys_pre_div == 2) - sclk /= 4; - - sclk_pdiv = ret & OV8858_SCLK_PDIV_MASK; - sclk_pdiv >>= OV8858_SCLK_PDIV_OFFSET; - - if (sclk_pdiv > 1) - sclk /= sclk_pdiv; - - dev_dbg(d, "%s: sclk: %d\n", __func__, sclk); - - dev->vt_pix_clk_freq_mhz = sclk; - m->vt_pix_clk_freq_mhz = sclk; - - /* HTS and VTS */ - m->frame_length_lines = - res->fps_options[dev->fps_index].lines_per_frame; - m->line_length_pck = res->fps_options[dev->fps_index].pixels_per_line; - - m->coarse_integration_time_min = 0; - m->coarse_integration_time_max_margin = OV8858_INTEGRATION_TIME_MARGIN; - ret = ov8858_read_reg(client, OV8858_16BIT, OV8858_TIMING_HTS, &hts); - if (ret < 0) - return ret; - m->hts = hts; - dev_dbg(&client->dev, "%s: get HTS %d\n", __func__, hts); - - /* OV Sensor do not use fine integration time. */ - m->fine_integration_time_min = 0; - m->fine_integration_time_max_margin = 0; - - /* - * read_mode indicate whether binning is used for calculating - * the correct exposure value from the user side. So adapt the - * read mode values accordingly. - */ - m->read_mode = res->bin_factor_x ? - OV8858_READ_MODE_BINNING_ON : OV8858_READ_MODE_BINNING_OFF; - - ret = ov8858_get_register_8bit(sd, OV8858_H_INC_ODD, res->regs); - if (ret < 0) - return ret; - m->binning_factor_x = (ret + 1) / 2; - - ret = ov8858_get_register_8bit(sd, OV8858_V_INC_ODD, res->regs); - if (ret < 0) - return ret; - m->binning_factor_y = (ret + 1) / 2; - - /* Get the cropping and output resolution to ISP for this mode. */ - ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_START_H, - res->regs); - if (ret < 0) - return ret; - - m->crop_horizontal_start = ret; - - ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_START_H, res->regs); - if (ret < 0) - return ret; - - m->crop_vertical_start = ret; - - ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_END_H, res->regs); - if (ret < 0) - return ret; - - m->crop_horizontal_end = ret; - - ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_END_H, res->regs); - if (ret < 0) - return ret; - - m->crop_vertical_end = ret; - - ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_OUTPUT_SIZE_H, - res->regs); - if (ret < 0) - return ret; - - m->output_width = ret; - - ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_OUTPUT_SIZE_H, - res->regs); - if (ret < 0) - return ret; - - m->output_height = ret; - - return 0; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between res_w/res_h and w/h. - * distance = (res_w/res_h - w/h) / (w/h) * 8192 - * res->width/height smaller than w/h wouldn't be considered. - * The gap of ratio larger than 1/8 wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 -static int distance(struct ov8858_resolution const *res, const u32 w, - const u32 h) -{ - int ratio; - int distance; - - if (w == 0 || h == 0 || - res->width < w || res->height < h) - return -1; - - ratio = res->width << 13; - ratio /= w; - ratio *= h; - ratio /= res->height; - - distance = abs(ratio - 8192); - - if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) - return -1; - return distance; -} - -/* - * Returns the nearest higher resolution index. - * @w: width - * @h: height - * matching is done based on enveloping resolution and - * aspect ratio. If the aspect ratio cannot be matched - * to any index, -1 is returned. - */ -static int nearest_resolution_index(struct v4l2_subdev *sd, int w, int h) -{ - int i; - int idx = -1; - int dist; - int fps_diff; - int min_fps_diff = INT_MAX; - int min_dist = INT_MAX; - int min_res_w = INT_MAX; - const struct ov8858_resolution *tmp_res = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov8858_device *dev = to_ov8858_sensor(sd); - dev_dbg(&client->dev, "%s: w=%d, h=%d\n", __func__, w, h); - - for (i = 0; i < dev->entries_curr_table; i++) { - tmp_res = &dev->curr_res_table[i]; - dist = distance(tmp_res, w, h); - dev_dbg(&client->dev, - "%s[%d]: %dx%d distance=%d\n", tmp_res->desc, - i, tmp_res->width, tmp_res->height, dist); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - min_res_w = tmp_res->width; - min_fps_diff = __ov8858_min_fps_diff(dev->fps, - tmp_res->fps_options); - idx = i; - } - if (dist == min_dist) { - fps_diff = __ov8858_min_fps_diff(dev->fps, - tmp_res->fps_options); - if (fps_diff < min_fps_diff) { - min_fps_diff = fps_diff; - idx = i; - } - if (tmp_res->width < min_res_w) { - min_res_w = tmp_res->width; - idx = i; - } - } - } - - return idx; -} - -static int ov8858_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct camera_mipi_info *ov8858_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct ov8858_resolution *res; - int ret; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - ov8858_info = v4l2_get_subdev_hostdata(sd); - if (ov8858_info == NULL) - return -EINVAL; - - mutex_lock(&dev->input_lock); - - if ((fmt->width > OV8858_RES_WIDTH_MAX) || - (fmt->height > OV8858_RES_HEIGHT_MAX)) { - fmt->width = OV8858_RES_WIDTH_MAX; - fmt->height = OV8858_RES_HEIGHT_MAX; - } else { - idx = nearest_resolution_index(sd, fmt->width, fmt->height); - - /* - * nearest_resolution_index() doesn't return smaller - * resolutions. If it fails, it means the requested resolution - * is higher than we can support. Fallback to highest possible - * resolution in this case. - */ - if (idx == -1) - idx = dev->entries_curr_table - 1; - - fmt->width = dev->curr_res_table[idx].width; - fmt->height = dev->curr_res_table[idx].height; - } - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = nearest_resolution_index(sd, fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - ret = -EINVAL; - goto out; - } - res = &dev->curr_res_table[dev->fmt_idx]; - dev_dbg(&client->dev, "%s: selected width = %d, height = %d\n", - __func__, res->width, res->height); - - /* Adjust the FPS selection based on the resolution selected */ - dev->fps_index = __ov8858_nearest_fps_index(dev->fps, res->fps_options); - dev->fps = res->fps_options[dev->fps_index].fps; - dev->regs = res->fps_options[dev->fps_index].regs; - if (!dev->regs) - dev->regs = res->regs; - - ret = ov8858_write_reg_array(client, dev->regs); - if (ret) - goto out; - - dev->pixels_per_line = res->fps_options[dev->fps_index].pixels_per_line; - dev->lines_per_frame = res->fps_options[dev->fps_index].lines_per_frame; - - /* ov8858 only support RGB RAW10 output */ - ov8858_info->metadata_width = res->width * 10 / 8; - ov8858_info->metadata_height = 2; - ov8858_info->metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED; - - /* Set the initial exposure */ - ret = __ov8858_set_exposure(sd, dev->exposure, dev->gain, - dev->digital_gain, &dev->pixels_per_line, - &dev->lines_per_frame); - if (ret) - goto out; - - ret = ov8858_get_intg_factor(sd, ov8858_info, dev->regs); - -out: - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ov8858_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov8858_device *dev = to_ov8858_sensor(sd); - - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - mutex_lock(&dev->input_lock); - fmt->width = dev->curr_res_table[dev->fmt_idx].width; - fmt->height = dev->curr_res_table[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int ov8858_detect(struct i2c_client *client, u16 *id) -{ - struct i2c_adapter *adapter = client->adapter; - u16 id_hi = 0; - u16 id_low = 0; - int ret; - - /* i2c check */ - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - dev_dbg(&client->dev, "%s: I2C functionality ok\n", __func__); - ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_CHIP_ID_HIGH, &id_hi); - if (ret) - return ret; - dev_dbg(&client->dev, "%s: id_high = 0x%04x\n", __func__, id_hi); - ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_CHIP_ID_LOW, &id_low); - if (ret) - return ret; - dev_dbg(&client->dev, "%s: id_low = 0x%04x\n", __func__, id_low); - *id = (id_hi << 8) | id_low; - - dev_dbg(&client->dev, "%s: chip_id = 0x%04x\n", __func__, *id); - - dev_info(&client->dev, "%s: chip_id = 0x%04x\n", __func__, *id); - if (*id != OV8858_CHIP_ID) - return -ENODEV; - - /* Stream off now. */ - return ov8858_write_reg(client, OV8858_8BIT, OV8858_STREAM_MODE, 0); -} - -static void __ov8858_print_timing(struct v4l2_subdev *sd) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 width = dev->curr_res_table[dev->fmt_idx].width; - u16 height = dev->curr_res_table[dev->fmt_idx].height; - - dev_dbg(&client->dev, "Dump ov8858 timing in stream on:\n"); - dev_dbg(&client->dev, "width: %d:\n", width); - dev_dbg(&client->dev, "height: %d:\n", height); - dev_dbg(&client->dev, "pixels_per_line: %d:\n", dev->pixels_per_line); - dev_dbg(&client->dev, "line per frame: %d:\n", dev->lines_per_frame); - dev_dbg(&client->dev, "pix freq: %d:\n", dev->vt_pix_clk_freq_mhz); - /* updated formula: pixels_per_line = 2 * HTS */ - /* updated formula: fps = SCLK / (VTS * HTS) */ - dev_dbg(&client->dev, "init fps: %d:\n", dev->vt_pix_clk_freq_mhz / - (dev->pixels_per_line / 2) / dev->lines_per_frame); - dev_dbg(&client->dev, "HBlank: %d nS:\n", - 1000 * (dev->pixels_per_line - width) / - (dev->vt_pix_clk_freq_mhz / 1000000)); - dev_dbg(&client->dev, "VBlank: %d uS:\n", - (dev->lines_per_frame - height) * dev->pixels_per_line / - (dev->vt_pix_clk_freq_mhz / 1000000)); -} - -/* - * ov8858 stream on/off - */ -static int ov8858_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - dev_dbg(&client->dev, "%s: enable = %d\n", __func__, enable); - - /* Set orientation */ - ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_FORMAT2, &val); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_8BIT, OV8858_FORMAT2, - dev->hflip ? val | OV8858_FLIP_ENABLE : - val & ~OV8858_FLIP_ENABLE); - if (ret) - return ret; - - ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_FORMAT1, &val); - if (ret) - return ret; - - ret = ov8858_write_reg(client, OV8858_8BIT, OV8858_FORMAT1, - dev->vflip ? val | OV8858_FLIP_ENABLE : - val & ~OV8858_FLIP_ENABLE); - if (ret) - return ret; - - mutex_lock(&dev->input_lock); - if (enable) { - __ov8858_print_timing(sd); - ret = ov8858_write_reg_array(client, ov8858_streaming); - if (ret != 0) { - dev_err(&client->dev, "write_reg_array err\n"); - goto out; - } - dev->streaming = 1; - } else { - ret = ov8858_write_reg_array(client, ov8858_soft_standby); - if (ret != 0) { - dev_err(&client->dev, "write_reg_array err\n"); - goto out; - } - dev->streaming = 0; - dev->fps_index = 0; - dev->fps = 0; - } -out: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int __update_ov8858_device_settings(struct ov8858_device *dev, - u16 sensor_id) -{ - if (sensor_id == OV8858_CHIP_ID) -#ifdef CONFIG_PLATFORM_BTNS - dev->vcm_driver = &ov8858_vcms[OV8858_ID_DEFAULT]; -#else - dev->vcm_driver = &ov8858_vcms[OV8858_SUNNY]; -#endif - else - return -ENODEV; - - if (dev->vcm_driver && dev->vcm_driver->init) - return dev->vcm_driver->init(&dev->sd); - - return 0; -} - -static int ov8858_s_config(struct v4l2_subdev *sd, - int irq, void *pdata) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 sensor_id; - int ret; - - if (pdata == NULL) - return -ENODEV; - - dev->platform_data = pdata; - - mutex_lock(&dev->input_lock); - - ret = __ov8858_s_power(sd, 1); - if (ret) { - dev_err(&client->dev, "power-up error %d!\n", ret); - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov8858_detect(client, &sensor_id); - if (ret) { - dev_err(&client->dev, "detect error %d!\n", ret); - goto fail_detect; - } - - dev->sensor_id = sensor_id; - - /* power off sensor */ - ret = __ov8858_s_power(sd, 0); - if (ret) { - dev->platform_data->csi_cfg(sd, 0); - dev_err(&client->dev, "__ov8858_s_power-down error %d!\n", ret); - goto fail_update; - } - - /* Resolution settings depend on sensor type and platform */ - ret = __update_ov8858_device_settings(dev, dev->sensor_id); - if (ret) { - dev->platform_data->csi_cfg(sd, 0); - dev_err(&client->dev, "__update_ov8858_device_settings error %d!\n", ret); - goto fail_update; - } - - mutex_unlock(&dev->input_lock); - return ret; - -fail_detect: - dev->platform_data->csi_cfg(sd, 0); -fail_csi_cfg: - __ov8858_s_power(sd, 0); -fail_update: - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "sensor power-gating failed\n"); - return ret; -} - -static int -ov8858_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index) - return -EINVAL; - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int -ov8858_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - struct ov8858_device *dev = to_ov8858_sensor(sd); - - mutex_lock(&dev->input_lock); - if (index >= dev->entries_curr_table) { - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - fse->min_width = dev->curr_res_table[index].width; - fse->min_height = dev->curr_res_table[index].height; - fse->max_width = dev->curr_res_table[index].width; - fse->max_height = dev->curr_res_table[index].height; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int ov8858_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov8858_device *dev = container_of( - ctrl->handler, struct ov8858_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - - /* input_lock is taken by the control framework, so it - * doesn't need to be taken here. - */ - - switch (ctrl->id) { - case V4L2_CID_RUN_MODE: - switch (ctrl->val) { - case ATOMISP_RUN_MODE_VIDEO: - dev->curr_res_table = ov8858_res_video; - dev->entries_curr_table = ARRAY_SIZE(ov8858_res_video); - break; - case ATOMISP_RUN_MODE_STILL_CAPTURE: - dev->curr_res_table = ov8858_res_still; - dev->entries_curr_table = ARRAY_SIZE(ov8858_res_still); - break; - default: - dev->curr_res_table = ov8858_res_preview; - dev->entries_curr_table = - ARRAY_SIZE(ov8858_res_preview); - } - - dev->fmt_idx = 0; - dev->fps_index = 0; - - return 0; - case V4L2_CID_FOCUS_ABSOLUTE: - if (dev->vcm_driver && dev->vcm_driver->t_focus_abs) - return dev->vcm_driver->t_focus_abs(&dev->sd, - ctrl->val); - return 0; - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: - if (ctrl->val == V4L2_EXPOSURE_AUTO) - dev->limit_exposure_flag = false; - else if (ctrl->val == V4L2_EXPOSURE_APERTURE_PRIORITY) - dev->limit_exposure_flag = true; - return 0; - case V4L2_CID_HFLIP: - dev->hflip = ctrl->val; - return 0; - case V4L2_CID_VFLIP: - dev->vflip = ctrl->val; - return 0; - default: - dev_err(&client->dev, "%s: Error: Invalid ctrl: 0x%X\n", - __func__, ctrl->id); - return -EINVAL; - } -} - -static int ov8858_g_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov8858_device *dev = container_of( - ctrl->handler, struct ov8858_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int r_odd, r_even; - int i = dev->fmt_idx; - - switch (ctrl->id) { - case V4L2_CID_FOCUS_STATUS: - if (dev->vcm_driver && dev->vcm_driver->q_focus_status) - return dev->vcm_driver->q_focus_status(&dev->sd, - &(ctrl->val)); - return 0; - case V4L2_CID_BIN_FACTOR_HORZ: - r_odd = ov8858_get_register_8bit(&dev->sd, OV8858_H_INC_ODD, - dev->curr_res_table[i].regs); - if (r_odd < 0) - return r_odd; - r_even = ov8858_get_register_8bit(&dev->sd, OV8858_H_INC_EVEN, - dev->curr_res_table[i].regs); - if (r_even < 0) - return r_even; - ctrl->val = fls(r_odd + (r_even)) - 2; - return 0; - - case V4L2_CID_BIN_FACTOR_VERT: - r_odd = ov8858_get_register_8bit(&dev->sd, OV8858_V_INC_ODD, - dev->curr_res_table[i].regs); - if (r_odd < 0) - return r_odd; - r_even = ov8858_get_register_8bit(&dev->sd, OV8858_V_INC_EVEN, - dev->curr_res_table[i].regs); - if (r_even < 0) - return r_even; - ctrl->val = fls(r_odd + (r_even)) - 2; - return 0; - case V4L2_CID_HFLIP: - ctrl->val = dev->hflip; - break; - case V4L2_CID_VFLIP: - ctrl->val = dev->vflip; - break; - case V4L2_CID_EXPOSURE_ABSOLUTE: - ctrl->val = dev->exposure; - break; - default: - dev_warn(&client->dev, - "%s: Error: Invalid ctrl: 0x%X\n", __func__, ctrl->id); - return -EINVAL; - } - - return 0; -} - -static int -ov8858_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - const struct ov8858_resolution *res = - &dev->curr_res_table[dev->fmt_idx]; - - mutex_lock(&dev->input_lock); - interval->interval.denominator = res->fps_options[dev->fps_index].fps; - interval->interval.numerator = 1; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int __ov8858_s_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct ov8858_resolution *res = - &dev->curr_res_table[dev->fmt_idx]; - struct camera_mipi_info *info = NULL; - unsigned int fps_index; - int ret = 0; - int fps; - - info = v4l2_get_subdev_hostdata(sd); - if (info == NULL) - return -EINVAL; - - if (!interval->interval.numerator) - interval->interval.numerator = 1; - - fps = interval->interval.denominator / interval->interval.numerator; - - /* No need to proceed further if we are not streaming */ - if (!dev->streaming) { - /* Save the new FPS and use it while selecting setting */ - dev->fps = fps; - return 0; - } - - /* Ignore if we are already using the required FPS. */ - if (fps == res->fps_options[dev->fps_index].fps) - return 0; - - fps_index = __ov8858_nearest_fps_index(fps, res->fps_options); - - if (res->fps_options[fps_index].regs && - res->fps_options[fps_index].regs != dev->regs) { - dev_err(&client->dev, - "Sensor is streaming, can't apply new configuration\n"); - return -EBUSY; - } - - dev->fps_index = fps_index; - dev->fps = res->fps_options[dev->fps_index].fps; - - /* Update the new frametimings based on FPS */ - dev->pixels_per_line = - res->fps_options[dev->fps_index].pixels_per_line; - dev->lines_per_frame = - res->fps_options[dev->fps_index].lines_per_frame; - - /* update frametiming. Conside the curren exposure/gain as well */ - ret = __ov8858_update_frame_timing(sd, - &dev->pixels_per_line, &dev->lines_per_frame); - if (ret) - return ret; - - /* Update the new values so that user side knows the current settings */ - ret = ov8858_get_intg_factor(sd, info, dev->regs); - if (ret) - return ret; - - interval->interval.denominator = res->fps_options[dev->fps_index].fps; - interval->interval.numerator = 1; - __ov8858_print_timing(sd); - - return ret; -} - -static int ov8858_s_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov8858_s_frame_interval(sd, interval); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ov8858_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct ov8858_device *dev = to_ov8858_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = dev->curr_res_table[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops ov8858_sensor_ops = { - .g_skip_frames = ov8858_g_skip_frames, -}; - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov8858_s_ctrl, - .g_volatile_ctrl = ov8858_g_ctrl, -}; - -static const struct v4l2_subdev_video_ops ov8858_video_ops = { - .s_stream = ov8858_s_stream, - .g_frame_interval = ov8858_g_frame_interval, - .s_frame_interval = ov8858_s_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov8858_core_ops = { - .s_power = ov8858_s_power, - .ioctl = ov8858_ioctl, - .init = ov8858_init, -}; - -static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { - .enum_mbus_code = ov8858_enum_mbus_code, - .enum_frame_size = ov8858_enum_frame_size, - .get_fmt = ov8858_get_fmt, - .set_fmt = ov8858_set_fmt, -}; - -static const struct v4l2_subdev_ops ov8858_ops = { - .core = &ov8858_core_ops, - .video = &ov8858_video_ops, - .pad = &ov8858_pad_ops, - .sensor = &ov8858_sensor_ops, -}; - -static const struct media_entity_operations ov_entity_ops = { - .link_setup = NULL, -}; - -static int ov8858_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov8858_device *dev = to_ov8858_sensor(sd); - - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - dev->platform_data->csi_cfg(sd, 0); - v4l2_device_unregister_subdev(sd); - kfree(dev); - - return 0; -} - -static const char * const ctrl_run_mode_menu[] = { - NULL, - "Video", - "Still capture", - "Continuous capture", - "Preview", -}; - -static const struct v4l2_ctrl_config ctrl_run_mode = { - .ops = &ctrl_ops, - .id = V4L2_CID_RUN_MODE, - .name = "run mode", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .def = 4, - .max = 4, - .qmenu = ctrl_run_mode_menu, -}; - -static const struct v4l2_ctrl_config ctrls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .name = "Vertical flip", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .min = false, - .max = true, - .step = 1, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .name = "Horizontal flip", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .min = false, - .max = true, - .step = 1, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .name = "Absolute exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .max = 0xffff, - .min = 0x0, - .step = 1, - .def = 0x00, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_ABSOLUTE, - .name = "Focus absolute", - .type = V4L2_CTRL_TYPE_INTEGER, - .step = 1, - .max = OV8858_MAX_FOCUS_POS, - }, { - /* This one is junk: see the spec for proper use of this CID. */ - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_STATUS, - .name = "Focus status", - .type = V4L2_CTRL_TYPE_INTEGER, - .step = 1, - .max = 100, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - }, { - /* This is crap. For compatibility use only. */ - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .name = "Focal lenght", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = (OV8858_FOCAL_LENGTH_NUM << 16) | - OV8858_FOCAL_LENGTH_DEM, - .max = (OV8858_FOCAL_LENGTH_NUM << 16) | - OV8858_FOCAL_LENGTH_DEM, - .step = 1, - .def = (OV8858_FOCAL_LENGTH_NUM << 16) | - OV8858_FOCAL_LENGTH_DEM, - .flags = V4L2_CTRL_FLAG_READ_ONLY, - }, { - /* This one is crap, too. For compatibility use only. */ - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .name = "F-number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = (OV8858_F_NUMBER_DEFAULT_NUM << 16) | - OV8858_F_NUMBER_DEM, - .max = (OV8858_F_NUMBER_DEFAULT_NUM << 16) | - OV8858_F_NUMBER_DEM, - .step = 1, - .def = (OV8858_F_NUMBER_DEFAULT_NUM << 16) | - OV8858_F_NUMBER_DEM, - .flags = V4L2_CTRL_FLAG_READ_ONLY, - }, { - /* - * The most utter crap. _Never_ use this, even for - * compatibility reasons! - */ - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .name = "F-number range", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = (OV8858_F_NUMBER_DEFAULT_NUM << 24) | - (OV8858_F_NUMBER_DEM << 16) | - (OV8858_F_NUMBER_DEFAULT_NUM << 8) | - OV8858_F_NUMBER_DEM, - .max = (OV8858_F_NUMBER_DEFAULT_NUM << 24) | - (OV8858_F_NUMBER_DEM << 16) | - (OV8858_F_NUMBER_DEFAULT_NUM << 8) | - OV8858_F_NUMBER_DEM, - .step = 1, - .def = (OV8858_F_NUMBER_DEFAULT_NUM << 24) | - (OV8858_F_NUMBER_DEM << 16) | - (OV8858_F_NUMBER_DEFAULT_NUM << 8) | - OV8858_F_NUMBER_DEM, - .flags = V4L2_CTRL_FLAG_READ_ONLY, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .name = "Horizontal binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .max = OV8858_BIN_FACTOR_MAX, - .step = 1, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .name = "Vertical binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .max = OV8858_BIN_FACTOR_MAX, - .step = 1, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - }, { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY, - .name = "Exposure auto priority", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = V4L2_EXPOSURE_AUTO, - .max = V4L2_EXPOSURE_APERTURE_PRIORITY, - .step = 1, - } -}; - -static int ov8858_probe(struct i2c_client *client) -{ - struct ov8858_device *dev; - unsigned int i; - int ret = 0; - struct camera_sensor_platform_data *pdata; - - dev_dbg(&client->dev, "%s:\n", __func__); - - /* allocate sensor device & init sub device */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - dev->sensor_id = OV_ID_DEFAULT; - dev->vcm_driver = &ov8858_vcms[OV8858_ID_DEFAULT]; - - v4l2_i2c_subdev_init(&(dev->sd), client, &ov8858_ops); - - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - if (!pdata) { - dev_err(&client->dev, - "%s: failed to get acpi platform data\n", - __func__); - goto out_free; - } - ret = ov8858_s_config(&dev->sd, client->irq, pdata); - if (ret) { - dev_err(&client->dev, - "%s: failed to set config\n", __func__); - goto out_free; - } - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) { - dev_err(&client->dev, - "%s: failed to register subdev\n", __func__); - goto out_free; - } - - /* - * sd->name is updated with sensor driver name by the v4l2. - * change it to sensor name in this case. - */ - snprintf(dev->sd.name, sizeof(dev->sd.name), "%s%x %d-%04x", - OV_SUBDEV_PREFIX, dev->sensor_id, - i2c_adapter_id(client->adapter), client->addr); - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.ops = &ov_entity_ops; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1); - if (ret) { - ov8858_remove(client); - return ret; - } - - dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler, - &ctrl_run_mode, NULL); - - for (i = 0; i < ARRAY_SIZE(ctrls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); - - if (dev->ctrl_handler.error) { - ov8858_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) { - ov8858_remove(client); - return ret; - } - - return 0; - -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id ov8858_acpi_match[] = { - {"INT3477"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov8858_acpi_match); - -static struct i2c_driver ov8858_driver = { - .driver = { - .name = "ov8858", - .acpi_match_table = ov8858_acpi_match, - }, - .probe_new = ov8858_probe, - .remove = ov8858_remove, -}; -module_i2c_driver(ov8858_driver); - -MODULE_DESCRIPTION("A low-level driver for Omnivision OV8858 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov8858.h b/drivers/staging/media/atomisp/i2c/ov8858.h deleted file mode 100644 index 6c89568bb44e..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov8858.h +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * Support for the Omnivision OV8858 camera sensor. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __OV8858_H__ -#define __OV8858_H__ -#include "../include/linux/atomisp_platform.h" -#include <media/v4l2-ctrls.h> - -#define I2C_MSG_LENGTH 0x2 - -/* - * This should be added into include/linux/videodev2.h - * NOTE: This is most likely not used anywhere. - */ -#define V4L2_IDENT_OV8858 V4L2_IDENT_UNKNOWN - -/* - * Indexes for VCM driver lists - */ -#define OV8858_ID_DEFAULT 0 -#define OV8858_SUNNY 1 - -#define OV8858_OTP_START_ADDR 0x7010 -#define OV8858_OTP_END_ADDR 0x7186 - -/* - * ov8858 System control registers - */ - -#define OV8858_OTP_LOAD_CTRL 0x3D81 -#define OV8858_OTP_MODE_CTRL 0x3D84 -#define OV8858_OTP_START_ADDR_REG 0x3D88 -#define OV8858_OTP_END_ADDR_REG 0x3D8A -#define OV8858_OTP_ISP_CTRL2 0x5002 - -#define OV8858_OTP_MODE_MANUAL BIT(6) -#define OV8858_OTP_MODE_PROGRAM_DISABLE BIT(7) -#define OV8858_OTP_LOAD_ENABLE BIT(0) -#define OV8858_OTP_DPC_ENABLE BIT(3) - -#define OV8858_PLL1_PREDIV0 0x030A -#define OV8858_PLL1_PREDIV 0x0300 -#define OV8858_PLL1_MULTIPLIER 0x0301 -#define OV8858_PLL1_SYS_PRE_DIV 0x0305 -#define OV8858_PLL1_SYS_DIVIDER 0x0306 - -#define OV8858_PLL1_PREDIV0_MASK BIT(0) -#define OV8858_PLL1_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2)) -#define OV8858_PLL1_MULTIPLIER_MASK 0x01FF -#define OV8858_PLL1_SYS_PRE_DIV_MASK (BIT(0) | BIT(1)) -#define OV8858_PLL1_SYS_DIVIDER_MASK BIT(0) - -#define OV8858_PLL2_PREDIV0 0x0312 -#define OV8858_PLL2_PREDIV 0x030B -#define OV8858_PLL2_MULTIPLIER 0x030C -#define OV8858_PLL2_DAC_DIVIDER 0x0312 -#define OV8858_PLL2_SYS_PRE_DIV 0x030F -#define OV8858_PLL2_SYS_DIVIDER 0x030E - -#define OV8858_PLL2_PREDIV0_MASK BIT(4) -#define OV8858_PLL2_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2)) -#define OV8858_PLL2_MULTIPLIER_MASK 0x01FF -#define OV8858_PLL2_DAC_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -#define OV8858_PLL2_SYS_PRE_DIV_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -#define OV8858_PLL2_SYS_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2)) - -#define OV8858_PLL_SCLKSEL1 0x3032 -#define OV8858_PLL_SCLKSEL2 0x3033 -#define OV8858_SRB_HOST_INPUT_DIS 0x3106 - -#define OV8858_PLL_SCLKSEL1_MASK BIT(7) -#define OV8858_PLL_SCLKSEL2_MASK BIT(1) - -#define OV8858_SYS_PRE_DIV_OFFSET 2 -#define OV8858_SYS_PRE_DIV_MASK (BIT(2) | BIT(3)) -#define OV8858_SCLK_PDIV_OFFSET 4 -#define OV8858_SCLK_PDIV_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7)) - -#define OV8858_TIMING_HTS 0x380C -#define OV8858_TIMING_VTS 0x380E - -#define OV8858_HORIZONTAL_START_H 0x3800 -#define OV8858_VERTICAL_START_H 0x3802 -#define OV8858_HORIZONTAL_END_H 0x3804 -#define OV8858_VERTICAL_END_H 0x3806 -#define OV8858_HORIZONTAL_OUTPUT_SIZE_H 0x3808 -#define OV8858_VERTICAL_OUTPUT_SIZE_H 0x380A - -#define OV8858_GROUP_ACCESS 0x3208 -#define OV8858_GROUP_ZERO 0x00 -#define OV8858_GROUP_ACCESS_HOLD_START 0x00 -#define OV8858_GROUP_ACCESS_HOLD_END 0x10 -#define OV8858_GROUP_ACCESS_DELAY_LAUNCH 0xA0 -#define OV8858_GROUP_ACCESS_QUICK_LAUNCH 0xE0 - -#define OV_SUBDEV_PREFIX "ov" -#define OV_ID_DEFAULT 0x0000 -#define OV8858_CHIP_ID 0x8858 - -#define OV8858_LONG_EXPO 0x3500 -#define OV8858_LONG_GAIN 0x3508 -#define OV8858_LONG_DIGI_GAIN 0x350A -#define OV8858_SHORT_GAIN 0x350C -#define OV8858_SHORT_DIGI_GAIN 0x350E - -#define OV8858_FORMAT1 0x3820 -#define OV8858_FORMAT2 0x3821 - -#define OV8858_FLIP_ENABLE 0x06 - -#define OV8858_MWB_RED_GAIN_H 0x5032 -#define OV8858_MWB_GREEN_GAIN_H 0x5034 -#define OV8858_MWB_BLUE_GAIN_H 0x5036 -#define OV8858_MWB_GAIN_MAX 0x0FFF - -#define OV8858_CHIP_ID_HIGH 0x300B -#define OV8858_CHIP_ID_LOW 0x300C -#define OV8858_STREAM_MODE 0x0100 - -#define OV8858_FOCAL_LENGTH_NUM 294 /* 2.94mm */ -#define OV8858_FOCAL_LENGTH_DEM 100 -#define OV8858_F_NUMBER_DEFAULT_NUM 24 /* 2.4 */ -#define OV8858_F_NUMBER_DEM 10 - -#define OV8858_H_INC_ODD 0x3814 -#define OV8858_H_INC_EVEN 0x3815 -#define OV8858_V_INC_ODD 0x382A -#define OV8858_V_INC_EVEN 0x382B - -#define OV8858_READ_MODE_BINNING_ON 0x0400 /* ToDo: Check this */ -#define OV8858_READ_MODE_BINNING_OFF 0x00 /* ToDo: Check this */ -#define OV8858_BIN_FACTOR_MAX 2 -#define OV8858_INTEGRATION_TIME_MARGIN 14 - -#define OV8858_MAX_VTS_VALUE 0xFFFF -#define OV8858_MAX_EXPOSURE_VALUE \ - (OV8858_MAX_VTS_VALUE - OV8858_INTEGRATION_TIME_MARGIN) -#define OV8858_MAX_GAIN_VALUE 0x07FF - -#define OV8858_MAX_FOCUS_POS 1023 - -#define OV8858_TEST_PATTERN_REG 0x5E00 - -struct ov8858_vcm { - int (*power_up)(struct v4l2_subdev *sd); - int (*power_down)(struct v4l2_subdev *sd); - int (*init)(struct v4l2_subdev *sd); - int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); - int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); - int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value); - int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value); - int (*t_vcm_slew)(struct v4l2_subdev *sd, s32 value); - int (*t_vcm_timing)(struct v4l2_subdev *sd, s32 value); -}; - -/* - * Defines for register writes and register array processing - * */ -#define OV8858_BYTE_MAX 32 -#define OV8858_SHORT_MAX 16 -#define OV8858_TOK_MASK 0xFFF0 - -#define MAX_FPS_OPTIONS_SUPPORTED 3 - -#define OV8858_DEPTH_COMP_CONST 2200 -#define OV8858_DEPTH_VTS_CONST 2573 - -enum ov8858_tok_type { - OV8858_8BIT = 0x0001, - OV8858_16BIT = 0x0002, - OV8858_TOK_TERM = 0xF000, /* terminating token for reg list */ - OV8858_TOK_DELAY = 0xFE00 /* delay token for reg list */ -}; - -/* - * If register address or register width is not 32 bit width, - * user needs to convert it manually - */ -struct s_register_setting { - u32 reg; - u32 val; -}; - -/** - * struct ov8858_reg - MI sensor register format - * @type: type of the register - * @reg: 16-bit offset to register - * @val: 8/16/32-bit register value - * - * Define a structure for sensor register initialization values - */ -struct ov8858_reg { - enum ov8858_tok_type type; - u16 sreg; - u32 val; /* @set value for read/mod/write, @mask */ -}; - -struct ov8858_fps_setting { - int fps; - unsigned short pixels_per_line; - unsigned short lines_per_frame; - const struct ov8858_reg *regs; /* regs that the fps setting needs */ -}; - -struct ov8858_resolution { - u8 *desc; - const struct ov8858_reg *regs; - int res; - int width; - int height; - bool used; - u8 bin_factor_x; - u8 bin_factor_y; - unsigned short skip_frames; - const struct ov8858_fps_setting fps_options[MAX_FPS_OPTIONS_SUPPORTED]; -}; - -/* - * ov8858 device structure - * */ -struct ov8858_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_mbus_framefmt format; - - struct camera_sensor_platform_data *platform_data; - struct mutex input_lock; /* serialize sensor's ioctl */ - int fmt_idx; - int streaming; - int vt_pix_clk_freq_mhz; - int fps_index; - u16 sensor_id; /* Sensor id from registers */ - u16 i2c_id; /* Sensor id from i2c_device_id */ - int exposure; - int gain; - u16 digital_gain; - u16 pixels_per_line; - u16 lines_per_frame; - u8 fps; - u8 *otp_data; - /* Prevent the framerate from being lowered in low light scenes. */ - int limit_exposure_flag; - bool hflip; - bool vflip; - - const struct ov8858_reg *regs; - struct ov8858_vcm *vcm_driver; - const struct ov8858_resolution *curr_res_table; - unsigned long entries_curr_table; - - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *run_mode; -}; - -#define to_ov8858_sensor(x) container_of(x, struct ov8858_device, sd) - -#define OV8858_MAX_WRITE_BUF_SIZE 32 -struct ov8858_write_buffer { - u16 addr; - u8 data[OV8858_MAX_WRITE_BUF_SIZE]; -}; - -struct ov8858_write_ctrl { - int index; - struct ov8858_write_buffer buffer; -}; - -static const struct ov8858_reg ov8858_soft_standby[] = { - {OV8858_8BIT, 0x0100, 0x00}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_streaming[] = { - {OV8858_8BIT, 0x0100, 0x01}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_param_hold[] = { - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_START}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_param_update[] = { - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_END}, - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_DELAY_LAUNCH}, - {OV8858_TOK_TERM, 0, 0} -}; - -extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); -extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9718_vcm_init(struct v4l2_subdev *sd); -extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int vcm_power_up(struct v4l2_subdev *sd); -extern int vcm_power_down(struct v4l2_subdev *sd); - -static struct ov8858_vcm ov8858_vcms[] = { - [OV8858_SUNNY] = { - .power_up = dw9718_vcm_power_up, - .power_down = dw9718_vcm_power_down, - .init = dw9718_vcm_init, - .t_focus_abs = dw9718_t_focus_abs, - .t_focus_rel = dw9718_t_focus_rel, - .q_focus_status = dw9718_q_focus_status, - .q_focus_abs = dw9718_q_focus_abs, - .t_vcm_slew = dw9718_t_vcm_slew, - .t_vcm_timing = dw9718_t_vcm_timing, - }, - [OV8858_ID_DEFAULT] = { - .power_up = NULL, - .power_down = NULL, - }, -}; - - -#define OV8858_RES_WIDTH_MAX 3280 -#define OV8858_RES_HEIGHT_MAX 2464 - -static struct ov8858_reg ov8858_BasicSettings[] = { - {OV8858_8BIT, 0x0103, 0x01}, /* software_reset */ - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - /* PLL settings */ - {OV8858_8BIT, 0x0300, 0x05}, /* pll1_pre_div = /4 */ - {OV8858_8BIT, 0x0302, 0xAF}, /* pll1_multiplier = 175 */ - {OV8858_8BIT, 0x0303, 0x00}, /* pll1_divm = /(1 + 0) */ - {OV8858_8BIT, 0x0304, 0x03}, /* pll1_div_mipi = /8 */ - {OV8858_8BIT, 0x030B, 0x02}, /* pll2_pre_div = /2 */ - {OV8858_8BIT, 0x030D, 0x4E}, /* pll2_r_divp = 78 */ - {OV8858_8BIT, 0x030E, 0x00}, /* pll2_r_divs = /1 */ - {OV8858_8BIT, 0x030F, 0x04}, /* pll2_r_divsp = /(1 + 4) */ - /* pll2_pre_div0 = /1, pll2_r_divdac = /(1 + 1) */ - {OV8858_8BIT, 0x0312, 0x01}, - {OV8858_8BIT, 0x031E, 0x0C}, /* pll1_no_lat = 1, mipi_bitsel_man = 0 */ - - /* PAD OEN2, VSYNC out enable=0x80, disable=0x00 */ - {OV8858_8BIT, 0x3002, 0x80}, - /* PAD OUT2, VSYNC pulse direction low-to-high = 1 */ - {OV8858_8BIT, 0x3007, 0x01}, - /* PAD SEL2, VSYNC out value = 0 */ - {OV8858_8BIT, 0x300D, 0x00}, - /* PAD OUT2, VSYNC out select = 0 */ - {OV8858_8BIT, 0x3010, 0x00}, - - /* Npump clock div = /2, Ppump clock div = /4 */ - {OV8858_8BIT, 0x3015, 0x01}, - /* - * mipi_lane_mode = 1+3, mipi_lvds_sel = 1 = MIPI enable, - * r_phy_pd_mipi_man = 0, lane_dis_option = 0 - */ - {OV8858_8BIT, 0x3018, 0x72}, - /* Clock switch output = normal, pclk_div = /1 */ - {OV8858_8BIT, 0x3020, 0x93}, - /* - * lvds_mode_o = 0, clock lane disable when pd_mipi = 0, - * pd_mipi enable when rst_sync = 1 - */ - {OV8858_8BIT, 0x3022, 0x01}, - {OV8858_8BIT, 0x3031, 0x0A}, /* mipi_bit_sel = 10 */ - {OV8858_8BIT, 0x3034, 0x00}, /* Unknown */ - /* sclk_div = /1, sclk_pre_div = /1, chip debug = 1 */ - {OV8858_8BIT, 0x3106, 0x01}, - - {OV8858_8BIT, 0x3305, 0xF1}, /* Unknown */ - {OV8858_8BIT, 0x3307, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x3308, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3309, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x330A, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330B, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x330C, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330F, 0x40}, /* Unknown */ - - {OV8858_8BIT, 0x3500, 0x00}, /* long exposure = 0x9A20 */ - {OV8858_8BIT, 0x3501, 0x9A}, /* long exposure = 0x9A20 */ - {OV8858_8BIT, 0x3502, 0x20}, /* long exposure = 0x9A20 */ - /* - * Digital fraction gain delay option = Delay 1 frame, - * Gain change delay option = Delay 1 frame, - * Gain delay option = Delay 1 frame, - * Gain manual as sensor gain = Input gain as real gain format, - * Exposure delay option (must be 0 = Delay 1 frame, - * Exposure change delay option (must be 0) = Delay 1 frame - */ - {OV8858_8BIT, 0x3503, 0x00}, - {OV8858_8BIT, 0x3505, 0x80}, /* gain conversation option */ - /* - * [10:7] are integer gain, [6:0] are fraction gain. For example: - * 0x80 is 1x gain, 0x100 is 2x gain, 0x1C0 is 3.5x gain - */ - {OV8858_8BIT, 0x3508, 0x02}, /* long gain = 0x0200 */ - {OV8858_8BIT, 0x3509, 0x00}, /* long gain = 0x0200 */ - {OV8858_8BIT, 0x350C, 0x00}, /* short gain = 0x0080 */ - {OV8858_8BIT, 0x350D, 0x80}, /* short gain = 0x0080 */ - {OV8858_8BIT, 0x3510, 0x00}, /* short exposure = 0x000200 */ - {OV8858_8BIT, 0x3511, 0x02}, /* short exposure = 0x000200 */ - {OV8858_8BIT, 0x3512, 0x00}, /* short exposure = 0x000200 */ - - {OV8858_8BIT, 0x3600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3601, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3602, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3603, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3604, 0x22}, /* Unknown */ - {OV8858_8BIT, 0x3605, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x3606, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3607, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3608, 0x11}, /* Unknown */ - {OV8858_8BIT, 0x3609, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x360A, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x360B, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x360C, 0xDC}, /* Unknown */ - {OV8858_8BIT, 0x360D, 0x40}, /* Unknown */ - {OV8858_8BIT, 0x360E, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x360F, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3610, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x3611, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3612, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x3613, 0x80}, /* Unknown */ - {OV8858_8BIT, 0x3614, 0x58}, /* Unknown */ - {OV8858_8BIT, 0x3615, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3616, 0x4A}, /* Unknown */ - {OV8858_8BIT, 0x3617, 0x90}, /* Unknown */ - {OV8858_8BIT, 0x3618, 0x56}, /* Unknown */ - {OV8858_8BIT, 0x3619, 0x70}, /* Unknown */ - {OV8858_8BIT, 0x361A, 0x99}, /* Unknown */ - {OV8858_8BIT, 0x361B, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361C, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x361D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361F, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3633, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3634, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3635, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3636, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3638, 0xFF}, /* Unknown */ - {OV8858_8BIT, 0x3645, 0x13}, /* Unknown */ - {OV8858_8BIT, 0x3646, 0x83}, /* Unknown */ - {OV8858_8BIT, 0x364A, 0x07}, /* Unknown */ - - {OV8858_8BIT, 0x3700, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x3701, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x3702, 0x50}, /* Unknown */ - {OV8858_8BIT, 0x3703, 0x32}, /* Unknown */ - {OV8858_8BIT, 0x3704, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3705, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3706, 0x6A}, /* Unknown */ - {OV8858_8BIT, 0x3707, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3708, 0x48}, /* Unknown */ - {OV8858_8BIT, 0x3709, 0x66}, /* Unknown */ - {OV8858_8BIT, 0x370A, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x370B, 0x6A}, /* Unknown */ - {OV8858_8BIT, 0x370C, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x3712, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x3714, 0x24}, /* Unknown */ - {OV8858_8BIT, 0x3718, 0x14}, /* Unknown */ - {OV8858_8BIT, 0x3719, 0x31}, /* Unknown */ - {OV8858_8BIT, 0x371E, 0x31}, /* Unknown */ - {OV8858_8BIT, 0x371F, 0x7F}, /* Unknown */ - {OV8858_8BIT, 0x3720, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3721, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3724, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3725, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3726, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3728, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3729, 0x03}, /* Unknown */ - {OV8858_8BIT, 0x372A, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x372B, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372C, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372D, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372E, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x372F, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3730, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3731, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3732, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3733, 0x10}, /* Unknown */ - {OV8858_8BIT, 0x3734, 0x40}, /* Unknown */ - {OV8858_8BIT, 0x3736, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x373A, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x373B, 0x0B}, /* Unknown */ - {OV8858_8BIT, 0x373C, 0x14}, /* Unknown */ - {OV8858_8BIT, 0x373E, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3755, 0x10}, /* Unknown */ - {OV8858_8BIT, 0x3758, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3759, 0x4C}, /* Unknown */ - {OV8858_8BIT, 0x375A, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x375B, 0x26}, /* Unknown */ - {OV8858_8BIT, 0x375C, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x375D, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x375E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x375F, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3760, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3761, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3762, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3763, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3766, 0xFF}, /* Unknown */ - {OV8858_8BIT, 0x3768, 0x22}, /* Unknown */ - {OV8858_8BIT, 0x3769, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x376A, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x376B, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x376F, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3772, 0x46}, /* Unknown */ - {OV8858_8BIT, 0x3773, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x3774, 0x2C}, /* Unknown */ - {OV8858_8BIT, 0x3775, 0x13}, /* Unknown */ - {OV8858_8BIT, 0x3776, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3777, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x37A0, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37A1, 0x7A}, /* Unknown */ - {OV8858_8BIT, 0x37A2, 0x7A}, /* Unknown */ - {OV8858_8BIT, 0x37A3, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A4, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A5, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A6, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A7, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37A8, 0x98}, /* Unknown */ - {OV8858_8BIT, 0x37A9, 0x98}, /* Unknown */ - {OV8858_8BIT, 0x37AA, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37AB, 0x5C}, /* Unknown */ - {OV8858_8BIT, 0x37AC, 0x5C}, /* Unknown */ - {OV8858_8BIT, 0x37AD, 0x55}, /* Unknown */ - {OV8858_8BIT, 0x37AE, 0x19}, /* Unknown */ - {OV8858_8BIT, 0x37AF, 0x19}, /* Unknown */ - {OV8858_8BIT, 0x37B0, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B1, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B2, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B3, 0x84}, /* Unknown */ - {OV8858_8BIT, 0x37B4, 0x84}, /* Unknown */ - {OV8858_8BIT, 0x37B5, 0x66}, /* Unknown */ - {OV8858_8BIT, 0x37B6, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B7, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B8, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B9, 0xFF}, /* Unknown */ - - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high */ - {OV8858_8BIT, 0x3809, 0xC0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x90}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3810, 0x00}, /* h_win offset high */ - {OV8858_8BIT, 0x3811, 0x04}, /* h_win offset low */ - {OV8858_8BIT, 0x3812, 0x00}, /* v_win offset high */ - {OV8858_8BIT, 0x3813, 0x02}, /* v_win offset low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3837, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x3841, 0xFF}, /* AUTO_SIZE_CTRL */ - {OV8858_8BIT, 0x3846, 0x48}, /* Unknown */ - - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3D8C, 0x73}, /* OTP_SETTING_STT_ADDRESS */ - {OV8858_8BIT, 0x3D8D, 0xDE}, /* OTP_SETTING_STT_ADDRESS */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x3F0A, 0x80}, /* PSRAM control register */ - - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4300, 0xFF}, /* clip_max[11:4] = 0xFFF */ - {OV8858_8BIT, 0x4301, 0x00}, /* clip_min[11:4] = 0 */ - {OV8858_8BIT, 0x4302, 0x0F}, /* clip_min/max[3:0] */ - {OV8858_8BIT, 0x4307, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4316, 0x00}, /* CTRL16 = default */ - {OV8858_8BIT, 0x4503, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x4500, 0x38}, /* Unknown */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - /* wkup_dly = Mark1 wakeup delay/2^10 = 0x25 */ - {OV8858_8BIT, 0x4808, 0x25}, - {OV8858_8BIT, 0x4816, 0x52}, /* Embedded data type*/ - {OV8858_8BIT, 0x481F, 0x32}, /* clk_prepare_min = 0x32 */ - {OV8858_8BIT, 0x4825, 0x3A}, /* lpx_p_min = 0x3A */ - {OV8858_8BIT, 0x4826, 0x40}, /* hs_prepare_min = 0x40 */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_8BIT, 0x4850, 0x10}, /* LANE SEL01 */ - {OV8858_8BIT, 0x4851, 0x32}, /* LANE SEL02 */ - - {OV8858_8BIT, 0x4B00, 0x2A}, /* Unknown */ - {OV8858_8BIT, 0x4B0D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4D00, 0x04}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D01, 0x18}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D02, 0xC3}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D03, 0xFF}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D04, 0xFF}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D05, 0xFF}, /* TPM_CTRL_REG */ - - /* - * Lens correction (LENC) function enable = 0 - * Slave sensor AWB Gain function enable = 1 - * Slave sensor AWB Statistics function enable = 1 - * Master sensor AWB Gain function enable = 1 - * Master sensor AWB Statistics function enable = 1 - * Black DPC function enable = 1 - * White DPC function enable =1 - */ - {OV8858_8BIT, 0x5000, 0x7E}, - {OV8858_8BIT, 0x5001, 0x01}, /* BLC function enable = 1 */ - /* - * Horizontal scale function enable = 0 - * WBMATCH bypass mode = Select slave sensor's gain - * WBMATCH function enable = 0 - * Master MWB gain support RGBC = 0 - * OTP_DPC function enable = 1 - * Manual mode of VarioPixel function enable = 0 - * Manual enable of VarioPixel function enable = 0 - * Use VSYNC to latch ISP modules's function enable signals = 0 - */ - {OV8858_8BIT, 0x5002, 0x08}, - /* - * Bypass all ISP modules after BLC module = 0 - * DPC_DBC buffer control enable = 1 - * WBMATCH VSYNC selection = Select master sensor's VSYNC fall - * Select master AWB gain to embed line = AWB gain before manual mode - * Enable BLC's input flip_i signal = 0 - */ - {OV8858_8BIT, 0x5003, 0x20}, - {OV8858_8BIT, 0x5041, 0x1D}, /* ISP CTRL41 - embedded data=on */ - {OV8858_8BIT, 0x5046, 0x12}, /* ISP CTRL46 = default */ - /* - * Tail enable = 1 - * Saturate cross cluster enable = 1 - * Remove cross cluster enable = 1 - * Enable to remove connected defect pixels in same channel = 1 - * Enable to remove connected defect pixels in different channel = 1 - * Smooth enable, use average G for recovery = 1 - * Black/white sensor mode enable = 0 - * Manual mode enable = 0 - */ - {OV8858_8BIT, 0x5780, 0xFC}, - {OV8858_8BIT, 0x5784, 0x0C}, /* DPC CTRL04 */ - {OV8858_8BIT, 0x5787, 0x40}, /* DPC CTRL07 */ - {OV8858_8BIT, 0x5788, 0x08}, /* DPC CTRL08 */ - {OV8858_8BIT, 0x578A, 0x02}, /* DPC CTRL0A */ - {OV8858_8BIT, 0x578B, 0x01}, /* DPC CTRL0B */ - {OV8858_8BIT, 0x578C, 0x01}, /* DPC CTRL0C */ - {OV8858_8BIT, 0x578E, 0x02}, /* DPC CTRL0E */ - {OV8858_8BIT, 0x578F, 0x01}, /* DPC CTRL0F */ - {OV8858_8BIT, 0x5790, 0x01}, /* DPC CTRL10 */ - {OV8858_8BIT, 0x5901, 0x00}, /* VAP CTRL01 = default */ - /* WINC CTRL08 = embedded data in 1st line*/ - {OV8858_8BIT, 0x5A08, 0x00}, - {OV8858_8BIT, 0x5B00, 0x02}, /* OTP CTRL00 */ - {OV8858_8BIT, 0x5B01, 0x10}, /* OTP CTRL01 */ - {OV8858_8BIT, 0x5B02, 0x03}, /* OTP CTRL02 */ - {OV8858_8BIT, 0x5B03, 0xCF}, /* OTP CTRL03 */ - {OV8858_8BIT, 0x5B05, 0x6C}, /* OTP CTRL05 = default */ - {OV8858_8BIT, 0x5E00, 0x00}, /* PRE CTRL00 = default */ - {OV8858_8BIT, 0x5E01, 0x41}, /* PRE_CTRL01 = default */ - - {OV8858_TOK_TERM, 0, 0} -}; - -/*****************************STILL********************************/ - -static const struct ov8858_reg ov8858_8M[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low 3283 */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 2464 */ - {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0xa0}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_3276x1848[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x10}, /* h_crop_start low 0c->10*/ - {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x42}, /* v_crop_start low 3e->42*/ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3276 x 1848 */ - {OV8858_8BIT, 0x3809, 0xCC}, /* h_output_size low d0->cc*/ - {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x38}, /* v_output_size low 3c->38*/ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_6M[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x3E}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 1852 */ - {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x3C}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */ - {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */ - {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1080P_60[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/ - {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x04}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xEC}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x07}, /* Anchor left end = 0x072D */ - {OV8858_8BIT, 0x4023, 0x2D}, /* Anchor left end = 0x072D */ - {OV8858_8BIT, 0x4024, 0x07}, /* Anchor right start = 0x079E */ - {OV8858_8BIT, 0x4025, 0x9E}, /* Anchor right start = 0x079E */ - {OV8858_8BIT, 0x4026, 0x07}, /* Anchor right end = 0x079F */ - {OV8858_8BIT, 0x4027, 0x9F}, /* Anchor right end = 0x079F */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1080P_30[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/ - {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x07}, /* Anchor left end = 0x072D */ - {OV8858_8BIT, 0x4023, 0x2D}, /* Anchor left end = 0x072D */ - {OV8858_8BIT, 0x4024, 0x07}, /* Anchor right start = 0x079E */ - {OV8858_8BIT, 0x4025, 0x9E}, /* Anchor right start = 0x079E */ - {OV8858_8BIT, 0x4026, 0x07}, /* Anchor right end = 0x079F */ - {OV8858_8BIT, 0x4027, 0x9F}, /* Anchor right end = 0x079F */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1640x1232[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1232 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0xD0}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1640x1096[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1096 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - - -static const struct ov8858_reg ov8858_1640x926[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 926 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x03}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x9E}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */ - {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */ - {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */ - {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static struct ov8858_resolution ov8858_res_preview[] = { - { - .desc = "ov8858_1640x926_PREVIEW", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1232_PREVIEW", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_3276x1848_PREVIEW", - .width = 3276, - .height = 1848, - .used = 0, - .regs = ov8858_3276x1848, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_8M_PREVIEW", - .width = 3280, - .height = 2464, - .used = 0, - .regs = ov8858_8M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, -}; - -static struct ov8858_resolution ov8858_res_still[] = { - { - .desc = "ov8858_1640x1232_STILL", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x926_STILL", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_3276X1848_STILL", - .width = 3276, - .height = 1848, - .used = 0, - .regs = ov8858_3276x1848, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_8M_STILL", - .width = 3280, - .height = 2464, - .used = 0, - .regs = ov8858_8M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - /* Pixel clock: 149.76MHZ */ - .fps = 10, - .pixels_per_line = 3880, - .lines_per_frame = 3859, - }, - { - } - }, - }, -}; - -static struct ov8858_resolution ov8858_res_video[] = { - { - .desc = "ov8858_1640x926_VIDEO", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1232_VIDEO", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1096_VIDEO", - .width = 1640, - .height = 1096, - .used = 0, - .regs = ov8858_1640x1096, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_6M_VIDEO", - .width = 3280, - .height = 1852, - .used = 0, - .regs = ov8858_6M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_8M_VIDEO", - .width = 3280, - .height = 2464, - .used = 0, - .regs = ov8858_8M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, -}; - -#endif /* __OV8858_H__ */ diff --git a/drivers/staging/media/atomisp/i2c/ov8858_btns.h b/drivers/staging/media/atomisp/i2c/ov8858_btns.h deleted file mode 100644 index f81851306832..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov8858_btns.h +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * Support for the Omnivision OV8858 camera sensor. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __OV8858_H__ -#define __OV8858_H__ -#include "../include/linux/atomisp_platform.h" -#include <media/v4l2-ctrls.h> - -#define I2C_MSG_LENGTH 0x2 - -/* - * This should be added into include/linux/videodev2.h - * NOTE: This is most likely not used anywhere. - */ -#define V4L2_IDENT_OV8858 V4L2_IDENT_UNKNOWN - -/* - * Indexes for VCM driver lists - */ -#define OV8858_ID_DEFAULT 0 -#define OV8858_SUNNY 1 - -#define OV8858_OTP_START_ADDR 0x7010 -#define OV8858_OTP_END_ADDR 0x7186 - -/* - * ov8858 System control registers - */ - -#define OV8858_OTP_LOAD_CTRL 0x3D81 -#define OV8858_OTP_MODE_CTRL 0x3D84 -#define OV8858_OTP_START_ADDR_REG 0x3D88 -#define OV8858_OTP_END_ADDR_REG 0x3D8A -#define OV8858_OTP_ISP_CTRL2 0x5002 - -#define OV8858_OTP_MODE_MANUAL BIT(6) -#define OV8858_OTP_MODE_PROGRAM_DISABLE BIT(7) -#define OV8858_OTP_LOAD_ENABLE BIT(0) -#define OV8858_OTP_DPC_ENABLE BIT(3) - -#define OV8858_PLL1_PREDIV0 0x030A -#define OV8858_PLL1_PREDIV 0x0300 -#define OV8858_PLL1_MULTIPLIER 0x0301 -#define OV8858_PLL1_SYS_PRE_DIV 0x0305 -#define OV8858_PLL1_SYS_DIVIDER 0x0306 - -#define OV8858_PLL1_PREDIV0_MASK BIT(0) -#define OV8858_PLL1_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2)) -#define OV8858_PLL1_MULTIPLIER_MASK 0x01FF -#define OV8858_PLL1_SYS_PRE_DIV_MASK (BIT(0) | BIT(1)) -#define OV8858_PLL1_SYS_DIVIDER_MASK BIT(0) - -#define OV8858_PLL2_PREDIV0 0x0312 -#define OV8858_PLL2_PREDIV 0x030B -#define OV8858_PLL2_MULTIPLIER 0x030C -#define OV8858_PLL2_DAC_DIVIDER 0x0312 -#define OV8858_PLL2_SYS_PRE_DIV 0x030F -#define OV8858_PLL2_SYS_DIVIDER 0x030E - -#define OV8858_PLL2_PREDIV0_MASK BIT(4) -#define OV8858_PLL2_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2)) -#define OV8858_PLL2_MULTIPLIER_MASK 0x01FF -#define OV8858_PLL2_DAC_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -#define OV8858_PLL2_SYS_PRE_DIV_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -#define OV8858_PLL2_SYS_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2)) - -#define OV8858_PLL_SCLKSEL1 0x3032 -#define OV8858_PLL_SCLKSEL2 0x3033 -#define OV8858_SRB_HOST_INPUT_DIS 0x3106 - -#define OV8858_PLL_SCLKSEL1_MASK BIT(7) -#define OV8858_PLL_SCLKSEL2_MASK BIT(1) - -#define OV8858_SYS_PRE_DIV_OFFSET 2 -#define OV8858_SYS_PRE_DIV_MASK (BIT(2) | BIT(3)) -#define OV8858_SCLK_PDIV_OFFSET 4 -#define OV8858_SCLK_PDIV_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7)) - -#define OV8858_TIMING_HTS 0x380C -#define OV8858_TIMING_VTS 0x380E - -#define OV8858_HORIZONTAL_START_H 0x3800 -#define OV8858_VERTICAL_START_H 0x3802 -#define OV8858_HORIZONTAL_END_H 0x3804 -#define OV8858_VERTICAL_END_H 0x3806 -#define OV8858_HORIZONTAL_OUTPUT_SIZE_H 0x3808 -#define OV8858_VERTICAL_OUTPUT_SIZE_H 0x380A - -#define OV8858_GROUP_ACCESS 0x3208 -#define OV8858_GROUP_ZERO 0x00 -#define OV8858_GROUP_ACCESS_HOLD_START 0x00 -#define OV8858_GROUP_ACCESS_HOLD_END 0x10 -#define OV8858_GROUP_ACCESS_DELAY_LAUNCH 0xA0 -#define OV8858_GROUP_ACCESS_QUICK_LAUNCH 0xE0 - -#define OV_SUBDEV_PREFIX "ov" -#define OV_ID_DEFAULT 0x0000 -#define OV8858_CHIP_ID 0x8858 - -#define OV8858_LONG_EXPO 0x3500 -#define OV8858_LONG_GAIN 0x3508 -#define OV8858_LONG_DIGI_GAIN 0x350A -#define OV8858_SHORT_GAIN 0x350C -#define OV8858_SHORT_DIGI_GAIN 0x350E - -#define OV8858_FORMAT1 0x3820 -#define OV8858_FORMAT2 0x3821 - -#define OV8858_FLIP_ENABLE 0x06 - -#define OV8858_MWB_RED_GAIN_H 0x5032 -#define OV8858_MWB_GREEN_GAIN_H 0x5034 -#define OV8858_MWB_BLUE_GAIN_H 0x5036 -#define OV8858_MWB_GAIN_MAX 0x0FFF - -#define OV8858_CHIP_ID_HIGH 0x300B -#define OV8858_CHIP_ID_LOW 0x300C -#define OV8858_STREAM_MODE 0x0100 - -#define OV8858_FOCAL_LENGTH_NUM 294 /* 2.94mm */ -#define OV8858_FOCAL_LENGTH_DEM 100 -#define OV8858_F_NUMBER_DEFAULT_NUM 24 /* 2.4 */ -#define OV8858_F_NUMBER_DEM 10 - -#define OV8858_H_INC_ODD 0x3814 -#define OV8858_H_INC_EVEN 0x3815 -#define OV8858_V_INC_ODD 0x382A -#define OV8858_V_INC_EVEN 0x382B - -#define OV8858_READ_MODE_BINNING_ON 0x0400 /* ToDo: Check this */ -#define OV8858_READ_MODE_BINNING_OFF 0x00 /* ToDo: Check this */ -#define OV8858_BIN_FACTOR_MAX 2 -#define OV8858_INTEGRATION_TIME_MARGIN 14 - -#define OV8858_MAX_VTS_VALUE 0xFFFF -#define OV8858_MAX_EXPOSURE_VALUE \ - (OV8858_MAX_VTS_VALUE - OV8858_INTEGRATION_TIME_MARGIN) -#define OV8858_MAX_GAIN_VALUE 0x07FF - -#define OV8858_MAX_FOCUS_POS 1023 - -#define OV8858_TEST_PATTERN_REG 0x5E00 - -struct ov8858_vcm { - int (*power_up)(struct v4l2_subdev *sd); - int (*power_down)(struct v4l2_subdev *sd); - int (*init)(struct v4l2_subdev *sd); - int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); - int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); - int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value); - int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value); - int (*t_vcm_slew)(struct v4l2_subdev *sd, s32 value); - int (*t_vcm_timing)(struct v4l2_subdev *sd, s32 value); -}; - -/* - * Defines for register writes and register array processing - * */ -#define OV8858_BYTE_MAX 32 -#define OV8858_SHORT_MAX 16 -#define OV8858_TOK_MASK 0xFFF0 - -#define MAX_FPS_OPTIONS_SUPPORTED 3 - -#define OV8858_DEPTH_COMP_CONST 2200 -#define OV8858_DEPTH_VTS_CONST 2573 - -enum ov8858_tok_type { - OV8858_8BIT = 0x0001, - OV8858_16BIT = 0x0002, - OV8858_TOK_TERM = 0xF000, /* terminating token for reg list */ - OV8858_TOK_DELAY = 0xFE00 /* delay token for reg list */ -}; - -/* - * If register address or register width is not 32 bit width, - * user needs to convert it manually - */ -struct s_register_setting { - u32 reg; - u32 val; -}; - -/** - * struct ov8858_reg - MI sensor register format - * @type: type of the register - * @reg: 16-bit offset to register - * @val: 8/16/32-bit register value - * - * Define a structure for sensor register initialization values - */ -struct ov8858_reg { - enum ov8858_tok_type type; - u16 sreg; - u32 val; /* @set value for read/mod/write, @mask */ -}; - -struct ov8858_fps_setting { - int fps; - unsigned short pixels_per_line; - unsigned short lines_per_frame; - const struct ov8858_reg *regs; /* regs that the fps setting needs */ -}; - -struct ov8858_resolution { - u8 *desc; - const struct ov8858_reg *regs; - int res; - int width; - int height; - bool used; - u8 bin_factor_x; - u8 bin_factor_y; - unsigned short skip_frames; - const struct ov8858_fps_setting fps_options[MAX_FPS_OPTIONS_SUPPORTED]; -}; - -/* - * ov8858 device structure - * */ -struct ov8858_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_mbus_framefmt format; - - struct camera_sensor_platform_data *platform_data; - struct mutex input_lock; /* serialize sensor's ioctl */ - int fmt_idx; - int streaming; - int vt_pix_clk_freq_mhz; - int fps_index; - u16 sensor_id; /* Sensor id from registers */ - u16 i2c_id; /* Sensor id from i2c_device_id */ - int exposure; - int gain; - u16 digital_gain; - u16 pixels_per_line; - u16 lines_per_frame; - u8 fps; - u8 *otp_data; - /* Prevent the framerate from being lowered in low light scenes. */ - int limit_exposure_flag; - bool hflip; - bool vflip; - - const struct ov8858_reg *regs; - struct ov8858_vcm *vcm_driver; - const struct ov8858_resolution *curr_res_table; - unsigned long entries_curr_table; - - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *run_mode; -}; - -#define to_ov8858_sensor(x) container_of(x, struct ov8858_device, sd) - -#define OV8858_MAX_WRITE_BUF_SIZE 32 -struct ov8858_write_buffer { - u16 addr; - u8 data[OV8858_MAX_WRITE_BUF_SIZE]; -}; - -struct ov8858_write_ctrl { - int index; - struct ov8858_write_buffer buffer; -}; - -static const struct ov8858_reg ov8858_soft_standby[] = { - {OV8858_8BIT, 0x0100, 0x00}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_streaming[] = { - {OV8858_8BIT, 0x0100, 0x01}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_param_hold[] = { - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_START}, - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_param_update[] = { - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_END}, - {OV8858_8BIT, OV8858_GROUP_ACCESS, - OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_DELAY_LAUNCH}, - {OV8858_TOK_TERM, 0, 0} -}; - -extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); -extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9718_vcm_init(struct v4l2_subdev *sd); -extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int vcm_power_up(struct v4l2_subdev *sd); -extern int vcm_power_down(struct v4l2_subdev *sd); - -static struct ov8858_vcm ov8858_vcms[] = { - [OV8858_SUNNY] = { - .power_up = dw9718_vcm_power_up, - .power_down = dw9718_vcm_power_down, - .init = dw9718_vcm_init, - .t_focus_abs = dw9718_t_focus_abs, - .t_focus_rel = dw9718_t_focus_rel, - .q_focus_status = dw9718_q_focus_status, - .q_focus_abs = dw9718_q_focus_abs, - .t_vcm_slew = dw9718_t_vcm_slew, - .t_vcm_timing = dw9718_t_vcm_timing, - }, - [OV8858_ID_DEFAULT] = { - .power_up = NULL, - .power_down = NULL, - }, -}; - - -#define OV8858_RES_WIDTH_MAX 3280 -#define OV8858_RES_HEIGHT_MAX 2464 - -static struct ov8858_reg ov8858_BasicSettings[] = { - {OV8858_8BIT, 0x0103, 0x01}, /* software_reset */ - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - /* PLL settings */ - {OV8858_8BIT, 0x0300, 0x05}, /* pll1_pre_div = /4 */ - {OV8858_8BIT, 0x0302, 0xAF}, /* pll1_multiplier = 175 */ - {OV8858_8BIT, 0x0303, 0x00}, /* pll1_divm = /(1 + 0) */ - {OV8858_8BIT, 0x0304, 0x03}, /* pll1_div_mipi = /8 */ - {OV8858_8BIT, 0x030B, 0x02}, /* pll2_pre_div = /2 */ - {OV8858_8BIT, 0x030D, 0x4E}, /* pll2_r_divp = 78 */ - {OV8858_8BIT, 0x030E, 0x00}, /* pll2_r_divs = /1 */ - {OV8858_8BIT, 0x030F, 0x04}, /* pll2_r_divsp = /(1 + 4) */ - /* pll2_pre_div0 = /1, pll2_r_divdac = /(1 + 1) */ - {OV8858_8BIT, 0x0312, 0x01}, - {OV8858_8BIT, 0x031E, 0x0C}, /* pll1_no_lat = 1, mipi_bitsel_man = 0 */ - - /* PAD OEN2, VSYNC out enable=0x80, disable=0x00 */ - {OV8858_8BIT, 0x3002, 0x80}, - /* PAD OUT2, VSYNC pulse direction low-to-high = 1 */ - {OV8858_8BIT, 0x3007, 0x01}, - /* PAD SEL2, VSYNC out value = 0 */ - {OV8858_8BIT, 0x300D, 0x00}, - /* PAD OUT2, VSYNC out select = 0 */ - {OV8858_8BIT, 0x3010, 0x00}, - - /* Npump clock div = /2, Ppump clock div = /4 */ - {OV8858_8BIT, 0x3015, 0x01}, - /* - * mipi_lane_mode = 1+3, mipi_lvds_sel = 1 = MIPI enable, - * r_phy_pd_mipi_man = 0, lane_dis_option = 0 - */ - {OV8858_8BIT, 0x3018, 0x72}, - /* Clock switch output = normal, pclk_div = /1 */ - {OV8858_8BIT, 0x3020, 0x93}, - /* - * lvds_mode_o = 0, clock lane disable when pd_mipi = 0, - * pd_mipi enable when rst_sync = 1 - */ - {OV8858_8BIT, 0x3022, 0x01}, - {OV8858_8BIT, 0x3031, 0x0A}, /* mipi_bit_sel = 10 */ - {OV8858_8BIT, 0x3034, 0x00}, /* Unknown */ - /* sclk_div = /1, sclk_pre_div = /1, chip debug = 1 */ - {OV8858_8BIT, 0x3106, 0x01}, - - {OV8858_8BIT, 0x3305, 0xF1}, /* Unknown */ - {OV8858_8BIT, 0x3307, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x3308, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3309, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x330A, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330B, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x330C, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x330F, 0x40}, /* Unknown */ - - {OV8858_8BIT, 0x3500, 0x00}, /* long exposure = 0x9A20 */ - {OV8858_8BIT, 0x3501, 0x9A}, /* long exposure = 0x9A20 */ - {OV8858_8BIT, 0x3502, 0x20}, /* long exposure = 0x9A20 */ - /* - * Digital fraction gain delay option = Delay 1 frame, - * Gain change delay option = Delay 1 frame, - * Gain delay option = Delay 1 frame, - * Gain manual as sensor gain = Input gain as real gain format, - * Exposure delay option (must be 0 = Delay 1 frame, - * Exposure change delay option (must be 0) = Delay 1 frame - */ - {OV8858_8BIT, 0x3503, 0x00}, - {OV8858_8BIT, 0x3505, 0x80}, /* gain conversation option */ - /* - * [10:7] are integer gain, [6:0] are fraction gain. For example: - * 0x80 is 1x gain, 0x100 is 2x gain, 0x1C0 is 3.5x gain - */ - {OV8858_8BIT, 0x3508, 0x02}, /* long gain = 0x0200 */ - {OV8858_8BIT, 0x3509, 0x00}, /* long gain = 0x0200 */ - {OV8858_8BIT, 0x350C, 0x00}, /* short gain = 0x0080 */ - {OV8858_8BIT, 0x350D, 0x80}, /* short gain = 0x0080 */ - {OV8858_8BIT, 0x3510, 0x00}, /* short exposure = 0x000200 */ - {OV8858_8BIT, 0x3511, 0x02}, /* short exposure = 0x000200 */ - {OV8858_8BIT, 0x3512, 0x00}, /* short exposure = 0x000200 */ - - {OV8858_8BIT, 0x3600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3601, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3602, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3603, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3604, 0x22}, /* Unknown */ - {OV8858_8BIT, 0x3605, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x3606, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3607, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3608, 0x11}, /* Unknown */ - {OV8858_8BIT, 0x3609, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x360A, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x360B, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x360C, 0xDC}, /* Unknown */ - {OV8858_8BIT, 0x360D, 0x40}, /* Unknown */ - {OV8858_8BIT, 0x360E, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x360F, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3610, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x3611, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3612, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x3613, 0x80}, /* Unknown */ - {OV8858_8BIT, 0x3614, 0x58}, /* Unknown */ - {OV8858_8BIT, 0x3615, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3616, 0x4A}, /* Unknown */ - {OV8858_8BIT, 0x3617, 0x90}, /* Unknown */ - {OV8858_8BIT, 0x3618, 0x56}, /* Unknown */ - {OV8858_8BIT, 0x3619, 0x70}, /* Unknown */ - {OV8858_8BIT, 0x361A, 0x99}, /* Unknown */ - {OV8858_8BIT, 0x361B, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361C, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x361D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x361F, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3633, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3634, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3635, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3636, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3638, 0xFF}, /* Unknown */ - {OV8858_8BIT, 0x3645, 0x13}, /* Unknown */ - {OV8858_8BIT, 0x3646, 0x83}, /* Unknown */ - {OV8858_8BIT, 0x364A, 0x07}, /* Unknown */ - - {OV8858_8BIT, 0x3700, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x3701, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x3702, 0x50}, /* Unknown */ - {OV8858_8BIT, 0x3703, 0x32}, /* Unknown */ - {OV8858_8BIT, 0x3704, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3705, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3706, 0x6A}, /* Unknown */ - {OV8858_8BIT, 0x3707, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3708, 0x48}, /* Unknown */ - {OV8858_8BIT, 0x3709, 0x66}, /* Unknown */ - {OV8858_8BIT, 0x370A, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x370B, 0x6A}, /* Unknown */ - {OV8858_8BIT, 0x370C, 0x07}, /* Unknown */ - {OV8858_8BIT, 0x3712, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x3714, 0x24}, /* Unknown */ - {OV8858_8BIT, 0x3718, 0x14}, /* Unknown */ - {OV8858_8BIT, 0x3719, 0x31}, /* Unknown */ - {OV8858_8BIT, 0x371E, 0x31}, /* Unknown */ - {OV8858_8BIT, 0x371F, 0x7F}, /* Unknown */ - {OV8858_8BIT, 0x3720, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3721, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3724, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3725, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3726, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3728, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x3729, 0x03}, /* Unknown */ - {OV8858_8BIT, 0x372A, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x372B, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372C, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372D, 0xA6}, /* Unknown */ - {OV8858_8BIT, 0x372E, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x372F, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x3730, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3731, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x3732, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3733, 0x10}, /* Unknown */ - {OV8858_8BIT, 0x3734, 0x40}, /* Unknown */ - {OV8858_8BIT, 0x3736, 0x30}, /* Unknown */ - {OV8858_8BIT, 0x373A, 0x0A}, /* Unknown */ - {OV8858_8BIT, 0x373B, 0x0B}, /* Unknown */ - {OV8858_8BIT, 0x373C, 0x14}, /* Unknown */ - {OV8858_8BIT, 0x373E, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3755, 0x10}, /* Unknown */ - {OV8858_8BIT, 0x3758, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3759, 0x4C}, /* Unknown */ - {OV8858_8BIT, 0x375A, 0x0C}, /* Unknown */ - {OV8858_8BIT, 0x375B, 0x26}, /* Unknown */ - {OV8858_8BIT, 0x375C, 0x20}, /* Unknown */ - {OV8858_8BIT, 0x375D, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x375E, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x375F, 0x28}, /* Unknown */ - {OV8858_8BIT, 0x3760, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3761, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3762, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3763, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3766, 0xFF}, /* Unknown */ - {OV8858_8BIT, 0x3768, 0x22}, /* Unknown */ - {OV8858_8BIT, 0x3769, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x376A, 0x44}, /* Unknown */ - {OV8858_8BIT, 0x376B, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x376F, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3772, 0x46}, /* Unknown */ - {OV8858_8BIT, 0x3773, 0x04}, /* Unknown */ - {OV8858_8BIT, 0x3774, 0x2C}, /* Unknown */ - {OV8858_8BIT, 0x3775, 0x13}, /* Unknown */ - {OV8858_8BIT, 0x3776, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3777, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x37A0, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37A1, 0x7A}, /* Unknown */ - {OV8858_8BIT, 0x37A2, 0x7A}, /* Unknown */ - {OV8858_8BIT, 0x37A3, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A4, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A5, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A6, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37A7, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37A8, 0x98}, /* Unknown */ - {OV8858_8BIT, 0x37A9, 0x98}, /* Unknown */ - {OV8858_8BIT, 0x37AA, 0x88}, /* Unknown */ - {OV8858_8BIT, 0x37AB, 0x5C}, /* Unknown */ - {OV8858_8BIT, 0x37AC, 0x5C}, /* Unknown */ - {OV8858_8BIT, 0x37AD, 0x55}, /* Unknown */ - {OV8858_8BIT, 0x37AE, 0x19}, /* Unknown */ - {OV8858_8BIT, 0x37AF, 0x19}, /* Unknown */ - {OV8858_8BIT, 0x37B0, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B1, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B2, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B3, 0x84}, /* Unknown */ - {OV8858_8BIT, 0x37B4, 0x84}, /* Unknown */ - {OV8858_8BIT, 0x37B5, 0x66}, /* Unknown */ - {OV8858_8BIT, 0x37B6, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B7, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B8, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x37B9, 0xFF}, /* Unknown */ - - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high */ - {OV8858_8BIT, 0x3809, 0xC0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x90}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3810, 0x00}, /* h_win offset high */ - {OV8858_8BIT, 0x3811, 0x04}, /* h_win offset low */ - {OV8858_8BIT, 0x3812, 0x00}, /* v_win offset high */ - {OV8858_8BIT, 0x3813, 0x02}, /* v_win offset low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3837, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x3841, 0xFF}, /* AUTO_SIZE_CTRL */ - {OV8858_8BIT, 0x3846, 0x48}, /* Unknown */ - - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3D8C, 0x73}, /* OTP_SETTING_STT_ADDRESS */ - {OV8858_8BIT, 0x3D8D, 0xDE}, /* OTP_SETTING_STT_ADDRESS */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x3F0A, 0x80}, /* PSRAM control register */ - - {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */ - {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */ - {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */ - {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */ - {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */ - {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */ - {OV8858_8BIT, 0x400A, 0x01}, - {OV8858_8BIT, 0x4011, 0x20}, /* BLC CTRL11 = 0x20 */ - {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */ - {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */ - {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */ - {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */ - {OV8858_8BIT, 0x4022, 0x0C}, /* Anchor left end = 0x0C60 */ - {OV8858_8BIT, 0x4023, 0x60}, /* Anchor left end = 0x0C60 */ - {OV8858_8BIT, 0x4024, 0x0F}, /* Anchor right start = 0x0F36 */ - {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0F36 */ - {OV8858_8BIT, 0x4026, 0x0F}, /* Anchor right end = 0x0F37 */ - {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0F37 */ - {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */ - {OV8858_8BIT, 0x4029, 0x04}, /* Top zero line number = 4 */ - {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */ - {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */ - {OV8858_8BIT, 0x402C, 0x00}, /* Bottom zero start line = 0 */ - {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */ - {OV8858_8BIT, 0x402E, 0x04}, /* Bottom black line start = 4 */ - {OV8858_8BIT, 0x402F, 0x08}, /* Bottom black line number = 8 */ - - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4300, 0xFF}, /* clip_max[11:4] = 0xFFF */ - {OV8858_8BIT, 0x4301, 0x00}, /* clip_min[11:4] = 0 */ - {OV8858_8BIT, 0x4302, 0x0F}, /* clip_min/max[3:0] */ - {OV8858_8BIT, 0x4307, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4316, 0x00}, /* CTRL16 = default */ - {OV8858_8BIT, 0x4503, 0x18}, /* Unknown */ - {OV8858_8BIT, 0x4500, 0x38}, /* Unknown */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - /* wkup_dly = Mark1 wakeup delay/2^10 = 0x25 */ - {OV8858_8BIT, 0x4808, 0x25}, - {OV8858_8BIT, 0x4816, 0x52}, /* Embedded data type*/ - {OV8858_8BIT, 0x481F, 0x32}, /* clk_prepare_min = 0x32 */ - {OV8858_8BIT, 0x4825, 0x3A}, /* lpx_p_min = 0x3A */ - {OV8858_8BIT, 0x4826, 0x40}, /* hs_prepare_min = 0x40 */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_8BIT, 0x4850, 0x10}, /* LANE SEL01 */ - {OV8858_8BIT, 0x4851, 0x32}, /* LANE SEL02 */ - - {OV8858_8BIT, 0x4B00, 0x2A}, /* Unknown */ - {OV8858_8BIT, 0x4B0D, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4D00, 0x04}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D01, 0x18}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D02, 0xC3}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D03, 0xFF}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D04, 0xFF}, /* TPM_CTRL_REG */ - {OV8858_8BIT, 0x4D05, 0xFF}, /* TPM_CTRL_REG */ - - /* - * Lens correction (LENC) function enable = 0 - * Slave sensor AWB Gain function enable = 1 - * Slave sensor AWB Statistics function enable = 1 - * Master sensor AWB Gain function enable = 1 - * Master sensor AWB Statistics function enable = 1 - * Black DPC function enable = 1 - * White DPC function enable =1 - */ - {OV8858_8BIT, 0x5000, 0x7E}, - {OV8858_8BIT, 0x5001, 0x01}, /* BLC function enable = 1 */ - /* - * Horizontal scale function enable = 0 - * WBMATCH bypass mode = Select slave sensor's gain - * WBMATCH function enable = 0 - * Master MWB gain support RGBC = 0 - * OTP_DPC function enable = 1 - * Manual mode of VarioPixel function enable = 0 - * Manual enable of VarioPixel function enable = 0 - * Use VSYNC to latch ISP modules's function enable signals = 0 - */ - {OV8858_8BIT, 0x5002, 0x08}, - /* - * Bypass all ISP modules after BLC module = 0 - * DPC_DBC buffer control enable = 1 - * WBMATCH VSYNC selection = Select master sensor's VSYNC fall - * Select master AWB gain to embed line = AWB gain before manual mode - * Enable BLC's input flip_i signal = 0 - */ - {OV8858_8BIT, 0x5003, 0x20}, - {OV8858_8BIT, 0x5041, 0x1D}, /* ISP CTRL41 - embedded data=on */ - {OV8858_8BIT, 0x5046, 0x12}, /* ISP CTRL46 = default */ - /* - * Tail enable = 1 - * Saturate cross cluster enable = 1 - * Remove cross cluster enable = 1 - * Enable to remove connected defect pixels in same channel = 1 - * Enable to remove connected defect pixels in different channel = 1 - * Smooth enable, use average G for recovery = 1 - * Black/white sensor mode enable = 0 - * Manual mode enable = 0 - */ - {OV8858_8BIT, 0x5780, 0xFC}, - {OV8858_8BIT, 0x5784, 0x0C}, /* DPC CTRL04 */ - {OV8858_8BIT, 0x5787, 0x40}, /* DPC CTRL07 */ - {OV8858_8BIT, 0x5788, 0x08}, /* DPC CTRL08 */ - {OV8858_8BIT, 0x578A, 0x02}, /* DPC CTRL0A */ - {OV8858_8BIT, 0x578B, 0x01}, /* DPC CTRL0B */ - {OV8858_8BIT, 0x578C, 0x01}, /* DPC CTRL0C */ - {OV8858_8BIT, 0x578E, 0x02}, /* DPC CTRL0E */ - {OV8858_8BIT, 0x578F, 0x01}, /* DPC CTRL0F */ - {OV8858_8BIT, 0x5790, 0x01}, /* DPC CTRL10 */ - {OV8858_8BIT, 0x5901, 0x00}, /* VAP CTRL01 = default */ - /* WINC CTRL08 = embedded data in 1st line*/ - {OV8858_8BIT, 0x5A08, 0x00}, - {OV8858_8BIT, 0x5B00, 0x02}, /* OTP CTRL00 */ - {OV8858_8BIT, 0x5B01, 0x10}, /* OTP CTRL01 */ - {OV8858_8BIT, 0x5B02, 0x03}, /* OTP CTRL02 */ - {OV8858_8BIT, 0x5B03, 0xCF}, /* OTP CTRL03 */ - {OV8858_8BIT, 0x5B05, 0x6C}, /* OTP CTRL05 = default */ - {OV8858_8BIT, 0x5E00, 0x00}, /* PRE CTRL00 = default */ - {OV8858_8BIT, 0x5E01, 0x41}, /* PRE_CTRL01 = default */ - - {OV8858_TOK_TERM, 0, 0} -}; - -/*****************************STILL********************************/ - -static const struct ov8858_reg ov8858_8M[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low 3283 */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 2464 */ - {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0xa0}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_3276x1848[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x10}, /* h_crop_start low 0c->10*/ - {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x42}, /* v_crop_start low 3e->42*/ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3276 x 1848 */ - {OV8858_8BIT, 0x3809, 0xCC}, /* h_output_size low d0->cc*/ - {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x38}, /* v_output_size low 3c->38*/ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_6M[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x3E}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 1852 */ - {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x3C}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1080P_60[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/ - {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x04}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xEC}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1080P_30[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/ - {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x40}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1640x1232[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1232 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0xD0}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static const struct ov8858_reg ov8858_1640x1096[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1096 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - - -static const struct ov8858_reg ov8858_1640x926[] = { - {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */ - {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */ - {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */ - {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */ - {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */ - {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */ - {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */ - {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */ - {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */ - {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */ - {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 926 */ - {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */ - {OV8858_8BIT, 0x380A, 0x03}, /* v_output_size high */ - {OV8858_8BIT, 0x380B, 0x9E}, /* v_output_size low */ - {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */ - {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */ - {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */ - {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */ - {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */ - {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */ - {OV8858_8BIT, 0x3820, 0x00}, /* format1 */ - {OV8858_8BIT, 0x3821, 0x67}, /* format2 */ - {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */ - {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */ - {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */ - {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */ - {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */ - {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */ - {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */ - {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */ - {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */ - {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */ - {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */ - {OV8858_TOK_TERM, 0, 0} -}; - -static struct ov8858_resolution ov8858_res_preview[] = { - { - .desc = "ov8858_1640x926_PREVIEW", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1232_PREVIEW", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1936x1096_PREVIEW", - .width = 1936, - .height = 1096, - .used = 0, - .regs = ov8858_1080P_30, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_3276x1848_PREVIEW", - .width = 3276, - .height = 1848, - .used = 0, - .regs = ov8858_3276x1848, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_8M_PREVIEW", - .width = 3280, - .height = 2464, - .used = 0, - .regs = ov8858_8M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, -}; - -static struct ov8858_resolution ov8858_res_still[] = { - { - .desc = "ov8858_1640x1232_STILL", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x926_STILL", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_3276X1848_STILL", - .width = 3276, - .height = 1848, - .used = 0, - .regs = ov8858_3276x1848, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_8M_STILL", - .width = 3280, - .height = 2464, - .used = 0, - .regs = ov8858_8M, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - /* Pixel clock: 149.76MHZ */ - .fps = 10, - .pixels_per_line = 3880, - .lines_per_frame = 3859, - }, - { - } - }, - }, -}; - -static struct ov8858_resolution ov8858_res_video[] = { - { - .desc = "ov8858_1640x926_VIDEO", - .width = 1640, - .height = 926, - .used = 0, - .regs = ov8858_1640x926, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1232_VIDEO", - .width = 1640, - .height = 1232, - .used = 0, - .regs = ov8858_1640x1232, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1640x1096_VIDEO", - .width = 1640, - .height = 1096, - .used = 0, - .regs = ov8858_1640x1096, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, - { - .desc = "ov8858_1080P_30_VIDEO", - .width = 1936, - .height = 1096, - .used = 0, - .regs = ov8858_1080P_30, - .bin_factor_x = 0, - .bin_factor_y = 0, - .skip_frames = 1, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3880, - .lines_per_frame = 2573, - }, - { - } - }, - }, -}; - -#endif /* __OV8858_H__ */ diff --git a/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h b/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h deleted file mode 100644 index ed709bdd6498..000000000000 --- a/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * vlv2_plat_clock.h - * - * Copyright (C) 2013 Intel Corp - * Author: Asutosh Pathak <asutosh.pathak@intel.com> - * - * 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; version 2 of the License. - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef __VLV2_PLAT_CLOCK_H -#define __VLV2_PLAT_CLOCK_H - -int vlv2_plat_set_clock_freq(int clock_num, int freq_type); -int vlv2_plat_get_clock_freq(int clock_num); - -int vlv2_plat_configure_clock(int clock_num, u32 conf); -int vlv2_plat_get_clock_status(int clock_num); - -#endif /* __VLV2_PLAT_CLOCK_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/Makefile b/drivers/staging/media/atomisp/pci/atomisp2/Makefile index ac3805345f20..83f816faba1b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/Makefile +++ b/drivers/staging/media/atomisp/pci/atomisp2/Makefile @@ -215,7 +215,6 @@ INCLUDES += \ -I$(atomisp)/css2400/isp/kernels/aa/aa_2/ \ -I$(atomisp)/css2400/isp/kernels/anr/anr_1.0/ \ -I$(atomisp)/css2400/isp/kernels/anr/anr_2/ \ - -I$(atomisp)/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ \ -I$(atomisp)/css2400/isp/kernels/bh/bh_2/ \ -I$(atomisp)/css2400/isp/kernels/bnlm/ \ -I$(atomisp)/css2400/isp/kernels/bnr/ \ @@ -258,14 +257,10 @@ INCLUDES += \ -I$(atomisp)/css2400/isp/kernels/io_ls/ \ -I$(atomisp)/css2400/isp/kernels/io_ls/bayer_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/io_ls/common/ \ - -I$(atomisp)/css2400/isp/kernels/io_ls/plane_io_ls/ \ - -I$(atomisp)/css2400/isp/kernels/io_ls/yuv420_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/io_ls/yuv444_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/bayer_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/common/ \ - -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ \ - -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/yuv444_io_ls/ \ -I$(atomisp)/css2400/isp/kernels/iterator/ \ -I$(atomisp)/css2400/isp/kernels/iterator/iterator_1.0/ \ @@ -289,9 +284,6 @@ INCLUDES += \ -I$(atomisp)/css2400/isp/kernels/ref/ref_1.0/ \ -I$(atomisp)/css2400/isp/kernels/s3a/ \ -I$(atomisp)/css2400/isp/kernels/s3a/s3a_1.0/ \ - -I$(atomisp)/css2400/isp/kernels/s3a_stat_ls/ \ - -I$(atomisp)/css2400/isp/kernels/scale/ \ - -I$(atomisp)/css2400/isp/kernels/scale/scale_1.0/ \ -I$(atomisp)/css2400/isp/kernels/sc/ \ -I$(atomisp)/css2400/isp/kernels/sc/sc_1.0/ \ -I$(atomisp)/css2400/isp/kernels/sdis/ \ @@ -315,8 +307,6 @@ INCLUDES += \ -I$(atomisp)/css2400/isp/kernels/ynr/ \ -I$(atomisp)/css2400/isp/kernels/ynr/ynr_1.0/ \ -I$(atomisp)/css2400/isp/kernels/ynr/ynr_2/ \ - -I$(atomisp)/css2400/isp/kernels/yuv_ls \ - -I$(atomisp)/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ \ -I$(atomisp)/css2400/isp/modes/interface/ \ -I$(atomisp)/css2400/runtime/binary/interface/ \ -I$(atomisp)/css2400/runtime/bufq/interface/ \ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index debf0e3853ff..22f2dbcecc15 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -1850,7 +1850,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) bool frame_done_found[MAX_STREAM_NUM] = {0}; bool css_pipe_done[MAX_STREAM_NUM] = {0}; unsigned int i; - struct atomisp_sub_device *asd = &isp->asd[0]; + struct atomisp_sub_device *asd; dev_dbg(isp->dev, ">%s\n", __func__); @@ -2091,7 +2091,7 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, struct atomisp_device *isp = asd->isp; struct v4l2_ctrl *c; struct v4l2_streamparm p = {0}; - int ret; + int ret = 0; int modes[] = { CI_MODE_NONE, CI_MODE_VIDEO, CI_MODE_STILL_CAPTURE, @@ -2105,13 +2105,8 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler, V4L2_CID_RUN_MODE); - if (c) { + if (c) ret = v4l2_ctrl_s_ctrl(c, runmode->mode); - } else { - p.parm.capture.capturemode = modes[runmode->mode]; - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - video, s_parm, &p); - } mutex_unlock(asd->ctrl_handler.lock); return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c index b7f9da014641..7621b4537147 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c @@ -4502,7 +4502,7 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, { enum atomisp_input_stream_id stream_id = 0; struct atomisp_css_event current_event; - struct atomisp_sub_device *asd = &isp->asd[0]; + struct atomisp_sub_device *asd; #ifndef ISP2401 bool reset_wdt_timer[MAX_STREAM_NUM] = {false}; #endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c index 377ec2a9fa6d..c6d96987561d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c @@ -77,20 +77,6 @@ static int file_input_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int file_input_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - /*to fake*/ - return 0; -} - -static int file_input_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - /*to fake*/ - return 0; -} - static int file_input_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) @@ -166,8 +152,6 @@ static int file_input_enum_frame_ival(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops file_input_video_ops = { .s_stream = file_input_s_stream, - .g_parm = file_input_g_parm, - .s_parm = file_input_s_parm, }; static const struct v4l2_subdev_core_ops file_input_core_ops = { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c index 4f9f9dca5e6a..545ef024841d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c @@ -1279,7 +1279,10 @@ const struct v4l2_file_operations atomisp_fops = { .mmap = atomisp_mmap, .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT + /* + * There are problems with this code. Disable this for now. .compat_ioctl32 = atomisp_compat_ioctl32, + */ #endif .poll = atomisp_poll, }; @@ -1291,7 +1294,10 @@ const struct v4l2_file_operations atomisp_file_fops = { .mmap = atomisp_file_mmap, .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT + /* + * There are problems with this code. Disable this for now. .compat_ioctl32 = atomisp_compat_ioctl32, + */ #endif .poll = atomisp_poll, }; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c index f3e18d627b0a..b78276ac22da 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c @@ -819,12 +819,6 @@ static int __atomisp_update_run_mode(struct atomisp_sub_device *asd) struct atomisp_device *isp = asd->isp; struct v4l2_ctrl *ctrl = asd->run_mode; struct v4l2_ctrl *c; - struct v4l2_streamparm p = {0}; - int modes[] = { CI_MODE_NONE, - CI_MODE_VIDEO, - CI_MODE_STILL_CAPTURE, - CI_MODE_CONTINUOUS, - CI_MODE_PREVIEW }; s32 mode; if (ctrl->val != ATOMISP_RUN_MODE_VIDEO && @@ -840,11 +834,7 @@ static int __atomisp_update_run_mode(struct atomisp_sub_device *asd) if (c) return v4l2_ctrl_s_ctrl(c, mode); - /* Fall back to obsolete s_parm */ - p.parm.capture.capturemode = modes[mode]; - - return v4l2_subdev_call( - isp->inputs[asd->input_curr].camera, video, s_parm, &p); + return 0; } int atomisp_update_run_mode(struct atomisp_sub_device *asd) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c index b71cc7bcdbab..adc900272f6f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c @@ -27,18 +27,6 @@ static int tpg_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int tpg_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) -{ - /*to fake*/ - return 0; -} - -static int tpg_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) -{ - /*to fake*/ - return 0; -} - static int tpg_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) @@ -101,8 +89,6 @@ static int tpg_enum_frame_ival(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops tpg_video_ops = { .s_stream = tpg_s_stream, - .g_parm = tpg_g_parm, - .s_parm = tpg_s_parm, }; static const struct v4l2_subdev_core_ops tpg_core_ops = { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index 548e00e7d67b..ba20344ec560 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -1137,7 +1137,6 @@ static int init_atomisp_wdts(struct atomisp_device *isp) for (i = 0; i < isp->num_of_streams; i++) { struct atomisp_sub_device *asd = &isp->asd[i]; - asd = &isp->asd[i]; #ifndef ISP2401 timer_setup(&asd->wdt, atomisp_wdt, 0); #else diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h deleted file mode 100644 index 34e734f6648e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _gp_regs_defs_h -#define _gp_regs_defs_h - -#define _HRT_GP_REGS_IS_FWD_REG_IDX 0 - -#define _HRT_GP_REGS_REG_ALIGN 4 - -#endif /* _gp_regs_defs_h */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h deleted file mode 100644 index 7ee4deba519a..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _sp_hrt_h_ -#define _sp_hrt_h_ - -#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem) - -#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell)) - -#endif /* _sp_hrt_h_ */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h deleted file mode 100644 index 34e734f6648e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _gp_regs_defs_h -#define _gp_regs_defs_h - -#define _HRT_GP_REGS_IS_FWD_REG_IDX 0 - -#define _HRT_GP_REGS_REG_ALIGN 4 - -#endif /* _gp_regs_defs_h */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h deleted file mode 100644 index 7ee4deba519a..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _sp_hrt_h_ -#define _sp_hrt_h_ - -#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem) - -#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell)) - -#endif /* _sp_hrt_h_ */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h deleted file mode 100644 index 34e734f6648e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _gp_regs_defs_h -#define _gp_regs_defs_h - -#define _HRT_GP_REGS_IS_FWD_REG_IDX 0 - -#define _HRT_GP_REGS_REG_ALIGN 4 - -#endif /* _gp_regs_defs_h */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h deleted file mode 100644 index 7ee4deba519a..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _sp_hrt_h_ -#define _sp_hrt_h_ - -#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem) - -#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell)) - -#endif /* _sp_hrt_h_ */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h deleted file mode 100644 index efcd6e1679e8..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h +++ /dev/null @@ -1,673 +0,0 @@ -/* -#ifndef ISP2401 - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ -#else -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. -#endif - -#ifdef ISP2401 -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ -#endif -#ifndef __CSS_API_VERSION_H -#define __CSS_API_VERSION_H - -/* @file - * CSS API version file. This file contains the version number of the CSS-API. - * - * This file is generated from a set of input files describing the CSS-API - * changes. Don't edit this file directly. - */ - - -/** - -The version string has four dot-separated numbers, read left to right: - The first two are the API version, and should not be changed. - The third number is incremented by a CSS firmware developer when the - API change is not backwards compatible. - The fourth number is incremented by the a CSS firmware developer for - every API change. - It should be zeroed when the third number changes. - -*/ - -#ifndef ISP2401 -#define CSS_API_VERSION_STRING "2.1.15.3" -#else -#define CSS_API_VERSION_STRING "2.1.20.9" -#endif - -/* -Change log - -v2.0.1.0, initial version: -- added API versioning - -v2.0.1.1, activate CSS-API versioning: -- added description of major and minor version numbers - -v2.0.1.2, modified struct ia_css_frame_info: -- added new member ia_css_crop_info - -v2.0.1.3, added IA_CSS_ERR_NOT_SUPPORTED - -v2.1.0.0 -- moved version number to 2.1.0.0 -- created new files for refactoring the code - -v2.1.1.0, modified struct ia_css_pipe_config and struct ia_css_pipe_info and struct ia_css_pipe: -- use array to handle multiple output ports - -v2.1.1.1 -- added api to lock/unlock of RAW Buffers to Support HALv3 Feature - -v2.1.1.2, modified struct ia_css_stream_config: -- to support multiple isys streams in one virtual channel, keep the old one for backward compatibility - -v2.1.2.0, modify ia_css_stream_config: -- add isys_config and input_config to support multiple isys stream within one virtual channel - -v2.1.2.1, add IA_CSS_STREAM_FORMAT_NUM -- add IA_CSS_STREAM_FORMAT_NUM definition to reflect the number of ia_css_stream_format enums - -v2.1.2.2, modified enum ia_css_stream_format -- Add 16bit YUV formats to ia_css_stream_format enum: -- IA_CSS_STREAM_FORMAT_YUV420_16 (directly after IA_CSS_STREAM_FORMAT_YUV420_10) -- IA_CSS_STREAM_FORMAT_YUV422_16 (directly after IA_CSS_STREAM_FORMAT_YUV422_10) - -v2.1.2.3 -- added api to enable/disable digital zoom for capture pipe. - -v2.1.2.4, change CSS API to generate the shading table which should be directly sent to ISP: -- keep the old CSS API (which uses the conversion of the shading table in CSS) for backward compatibility - -v2.1.2.5 -- Added SP frame time measurement (in ticks) and result is sent on a new member -- in ia_css_buffer.h. - -v2.1.2.6, add function ia_css_check_firmware_version() -- the function ia_css_check_firmware_version() returns true when the firmware version matches and returns false otherwise. - -v2.1.2.7 -- rename dynamic_data_index to dynamic_queue_id in struct ia_css_frame. -- update IA_CSS_PIPE_MODE_NUM - -v2.1.2.8 -- added flag for video full range - -v2.1.2.9 -- add public parameters for xnr3 kernel - -v2.1.2.10 -- add new interface to enable output mirroring - -v2.1.2.11, MIPI buffers optimization -- modified struct ia_css_mipi_buffer_config, added number of MIPI buffers needed for the stream -- backwards compatible, need another patch to remove legacy function and code - -v2.1.2.12 -- create consolidated firmware package for 2400, 2401, csi2p, bxtpoc - -v2.1.3.0 -- rename ia_css_output_config.enable_mirror -- add new interface to enable vertical output flipping - -v2.1.3.1 -- deprecated ia_css_rx_get_irq_info and ia_css_rx_clear_irq_info because both are hardcoded to work on CSI port 1. -- added new functions ia_css_rx_port_get_irq_info and ia_css_rx_port_clear_irq_info, both have a port ID as extra argument. - -v2.1.3.2 -- reverted v2.1.3.0 change - -v2.1.3.3 -- Added isys event queue. -- Renamed ia_css_dequeue_event to ia_css_dequeue_psys_event -- Made ia_css_dequeue_event deprecated - -v2.1.3.4 -- added new interface to support ACC extension QoS feature. -- added IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE. - -v2.1.3.5 -- added tiled frame format IA_CSS_FRAME_FORMAT_NV12_TILEY - -v2.1.3.6 -- added functions ia_css_host_data_allocate and ia_css_host_data_free - -v2.1.4.0, default pipe config change -- disable enable_dz param by default - -v2.1.5.0 -- removed mix_range field from yuvp1_y_ee_nr_frng_public_config - -v2.1.5.1, exposure IDs per stream -- added MIN/MAX exposure ID macros -- made exposure ID sequence per-stream instead of global (across all streams) - -#ifdef ISP2401 -v2.1.5.1, Add parameters to mmgr routines via a macro. -- Replaced mmgr funtions with macros to add caller func name + line #. -- This is done to help debug memory access issues, allocation issues, etc. - -#endif -v2.1.6.0, Interface for vertical output flip -- add new interface to enable vertical output flipping -- rename ia_css_output_config.enable_mirror - -#ifndef ISP2401 -v2.1.6.1, Effective res on pipe -#else -v2.1.6.2 (2 changes parallel), Effective res on pipe -#endif -- Added input_effective_res to struct ia_css_pipe_config in ia_css_pipe_public.h. - -#ifndef ISP2401 -v2.1.6.2, CSS-API version file generated from individual changes -#else -v2.1.6.3 (2 changes parallel), CSS-API version file generated from individual changes -#endif -- Avoid merge-conflicts by generating version file from individual CSS-API changes. -- Parallel CSS-API changes can map to the same version number after this change. -- Version numbers for a change could increase due to parallel changes being merged. -- The version number would not decrease for a change. - -#ifndef ISP2401 -v2.1.6.5 (2 changes parallel), Add SP FW error event -#else -v2.1.6.6 (4 changes parallel), Add SP FW error event -#endif -- Added FW error event. This gets raised when the SP FW runs into an -- error situation from which it cannot recover. - -#ifndef ISP2401 -v2.1.6.5 (2 changes parallel), expose bnr FF enable bits in bnr public API -#else -v2.1.6.6 (4 changes parallel), expose bnr FF enable bits in bnr public API -#endif -- Added ff enable bits to bnr_public_config_dn_detect_ctrl_config_t struct - -#ifndef ISP2401 -v2.1.6.5 (2 changes parallel), ISP configuration per pipe -#else -v2.1.6.6 (4 changes parallel), ISP configuration per pipe -#endif -- Added ISP configuration per pipe support: p_isp_config field in -- struct ia_css_pipe_config and ia_css_pipe_set_isp_config_on_pipe -- and ia_css_pipe_set_isp_config functions - -#ifndef ISP2401 -v2.1.7.0, removed css_version.h -#else -v2.1.7.0 (2 changes parallel), removed css_version.h -#endif -- Removed css_version.h that was used for versioning in manual (non-CI) releases. - -#ifndef ISP2401 -v2.1.7.1, Add helpers (get and set) for ISP cfg per pipe -#else -v2.1.7.2 (2 changes parallel), Add helpers (get and set) for ISP cfg per pipe -#endif -- Add helpers (get and set) for ISP configuration per pipe - -#ifndef ISP2401 -v2.1.7.2, Add feature to lock all RAW buffers -#else -v2.1.7.3 (2 changes parallel), Add feature to lock all RAW buffers -#endif -- This API change adds a boolean flag (lock_all) in the stream_config struct. -- If this flag is set to true, then all frames will be locked if locking is -- enabled. By default this flag is set to false. -- When this flag is false, then only buffers that are sent to the preview pipe -- will be locked. If continuous viewfinder is disabled, the flag should be set -- to true. - -#ifndef ISP2401 -v2.1.8.0 (2 changes parallel), Various changes to support ACC configuration per pipe -#else -v2.1.8.0 (4 changes parallel), Various changes to support ACC configuration per pipe -#endif -- Add ia_css_pipe_get_isp_config() -- Remove ia_css_pipe_set_isp_config_on_pipe (duplicated -- by ia_css_pipe_set_isp_config) -- Add isp configuration as parameter for -- ia_css_pipe_set_isp_config -- Remove ia_css_pipe_isp_config_set() -- Remove ia_css_pipe_isp_config_get() - -#ifndef ISP2401 -v2.1.8.2 (2 changes parallel), Added member num_invalid_frames to ia_css_pipe_info structure. -#else -v2.1.8.3 (4 changes parallel), Added member num_invalid_frames to ia_css_pipe_info structure. -#endif -- Added member num_invalid_frames to ia_css_pipe_info structure. -- This helps the driver make sure that the first valid output -- frame goes into the first user-supplied output buffer. - -#ifndef ISP2401 -v2.1.8.4 (2 changes parallel), ISYS EOF timestamp for output buffers -#else -v2.1.8.5 (4 changes parallel), ISYS EOF timestamp for output buffers -#endif -- driver gets EOF timer to every out frame . ia_css_buffer modified to accomodate same. - -#ifndef ISP2401 -v2.1.8.4 (4 changes parallel), display_config -#else -v2.1.8.5 (6 changes parallel), display_config -#endif -- Added formats- and output config parameters for configuration of the (optional) display output. - -#ifndef ISP2401 -v2.1.8.4 (2 changes parallel), Adding zoom region parameters to CSS API -#else -v2.1.8.5 (4 changes parallel), Adding zoom region parameters to CSS API -#endif -- Adding ia_css_point and ia_css_region structures to css-api. -- Adding zoom_region(type ia_css_region) parameter to ia_css_dz_config structure. -- By using this user can do the zoom based on zoom region and -- the center of the zoom region is not restricted at the center of the input frame. - -#ifndef ISP2401 -v2.1.8.6 (1 changes parallel), Add new ia_css_fw_warning type -#else -v2.1.8.7 (3 changes parallel), Add new ia_css_fw_warning type -#endif -- Add IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED enum to ia_css_fw_warning type -- Extend sp_warning() with exp_id parameter - -#ifndef ISP2401 -v2.1.8.6 (1 changes parallel), Add includes in GC, GC2 kernel interface files -#else -v2.1.8.7 (3 changes parallel), Add includes in GC, GC2 kernel interface files -#endif -- add ia_css_ctc_types.h includes in ia_css_gc_types.h and ia_css_gc2_types.h. Needed to get ia_css_vamem_type. - -#ifndef ISP2401 -v2.1.9.0 (1 changes parallel), Introduce sp assert event. -#else -v2.1.9.0 (3 changes parallel), Introduce sp assert event. -#endif -- Add IA_CSS_EVENT_TYPE_FW_ASSERT. The FW sends the event in case an assert goes off. - -#ifndef ISP2401 -v2.1.9.1 (1 changes parallel), Exclude driver part from ia_css_buffer.h as it is also used by SP -#else -v2.1.9.2 (3 changes parallel), Exclude driver part from ia_css_buffer.h as it is also used by SP -#endif -- Excluded driver part of the interface from SP/ISP code -- Driver I/F is not affected - -#ifndef ISP2401 -v2.1.9.2, added IA_CSS_EVENT_TYPE_TIMER -#else -v2.1.9.3 (2 changes parallel), added IA_CSS_EVENT_TYPE_TIMER -#endif -- Added a new event called IA_CSS_EVENT_TYPE_TIMER - -#ifndef ISP2401 -v2.1.10.0 (4 changes parallel), Add a flag "enable_dpc" to "struct ia_css_pipe_config" -#else -v2.1.10.0 (6 changes parallel), Add a flag "enable_dpc" to "struct ia_css_pipe_config" -#endif -- Add a flag "enable_dpc" to "struct ia_css_pipe_config" - -#ifndef ISP2401 -v2.1.10.6 (6 changes parallel), change the pipe version type from integer to enum -#else -v2.1.10.8 (9 changes parallel), change the pipe version type from integer to enum -#endif -- add new enum to enumerate ISP pipe version -- change the pipe version type in pipe_config from integer to enum - -#ifndef ISP2401 -v2.1.13.0 (8 changes parallel), Stop Support for Skycam B0 -#else -v2.1.14.0 (12 changes parallel), Stop Support for Skycam B0 -#endif -- Remove a few pre-processor defines for Skycam B0/C0 as support - -#ifndef ISP2401 -v2.1.14.0 (24 changes parallel), change the pipe version type from integer to enum -#else -v2.1.15.0 (28 changes parallel), change the pipe version type from integer to enum -#endif -- remove the temporary workaround for backward compatability - -#ifndef ISP2401 -v2.1.14.0 (13 changes parallel), expose_gamma_enable_option -#else -v2.1.15.0 (17 changes parallel), expose_gamma_enable_option -#endif -- added enable param to gamma_corr_public_config -- added documentation to rgbpp_public.h - -#ifndef ISP2401 -v2.1.14.0 (12 changes parallel), Remove deprecated FW_ERROR event. -#else -v2.1.15.0 (16 changes parallel), Remove deprecated FW_ERROR event. -#endif -- Remove code for deprecated FW_ERROR event. - -#ifndef ISP2401 -v2.1.14.3 (5 changes parallel), fix IEFD's puclic API types -#else -v2.1.15.5 (8 changes parallel), fix IEFD's puclic API types -#endif -- fix IEFD public API members types: rad_cu6_x1,rad_cu_unsharp_x1 & unsharp_amount - -#ifndef ISP2401 -v2.1.14.3 (5 changes parallel), Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH -#else -v2.1.15.5 (8 changes parallel), Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH -#endif -- Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH enum to ia_css_fw_warning type - -#ifndef ISP2401 -v2.1.14.4 (5 changes parallel), new API getter functions for gdc in buffer information -#else -v2.1.15.8 (11 changes parallel), add_flag_to_disable_continous_viewfinder -- add a new flag in stream_config to disable continuous viewfinder -- in ZSL use case. - -v2.1.16.0 (8 changes parallel), revert ia_css_skc_dvs_statistics field size change -- Reverted field size change, change was not ready for driver yet. - -v2.1.17.0 (7 changes parallel), change CSS API to fix the shading correction off-center issue -- update the ia_css_shading_info structure in ia_css_types.h - -v2.1.17.0 (32 changes parallel), add_flag_to_disable_continous_viewfinder_part2 -- remove the old interfaces - -v2.1.17.4 (8 changes parallel), Added public interface for setting the scaler LUT. -- Added the public struct to output system and modified the global config struct. - -v2.1.17.5 (7 changes parallel), Add parameters for new TNR3 component -- Add new parameters for new TNR3 component - -v2.1.17.6 (9 changes parallel), Update skycam DPC_MAX_NUMBER_OF_DP -- Automated tooling requires an API change request -- This change changes the implementation of #define DPC_MAX_NUMBER_OF_DP -- it now returns a different number - -v2.1.17.6 (8 changes parallel), Return an error when both DPC and BDS are enabled in a pipe config -- Return an error when both DPC and BDS are enabled in a pipe config - -v2.1.17.6 (9 changes parallel), new API getter functions for gdc in buffer information -#endif -- ia_css_pipe_get_dvs_filter() added -- ia_css_pipe_get_gdc_in_buffer_info() added - -#ifndef ISP2401 -v2.1.14.5 (8 changes parallel), Update CNR2 ineffective values -#else -v2.1.17.7 (12 changes parallel), Update CNR2 ineffective values -#endif -- Fixed Incorrect ineffective values listed in ia_css_cnr_config -- Correct Ineffective value is 8191 - -#ifndef ISP2401 -v2.1.14.5 (8 changes parallel), af_roi_api -#else -v2.1.17.7 (12 changes parallel), af_roi_api -#endif -- added a new function to set AF ROI ia_css_set_af_roi -- added a new struct ia_css_s3a_roi_offset - -#ifndef ISP2401 -v2.1.14.5 (8 changes parallel), remove x_y_end_from_ae_and_awb -#else -v2.1.17.7 (12 changes parallel), Enlarge AF AWB_FR stats buffers -- Enlarge AF and AWB_FR stats buffers to support max grid width per stripe as oppose to per frame - -v2.1.17.7 (12 changes parallel), remove x_y_end_from_ae_and_awb -#endif -- added a flag to prepare removal of x_end and y_end from ae grid public config -- added a flag to prepare removal of x_end and y_end from awb grid public config - -#ifndef ISP2401 -v2.1.14.5 (4 changes parallel), Added public interface for setting the scaler LUT. -- Added the public struct to output system and modified the global config struct. -#else -v2.1.17.8 (5 changes parallel) -- added input_yuv , input_raw to ia_css_binary_info.enable -- struct, these attributes were always there but not saved -- in the binary_info struct -#endif - -#ifndef ISP2401 -v2.1.14.6 (8 changes parallel), add_flag_to_disable_continous_viewfinder -- add a new flag in stream_config to disable continuous viewfinder -- in ZSL use case. -#else -v2.1.17.9 (6 changes parallel), cleanup_awb_ae_rgb_integration_flags -- this change only cleans up an approved api CR see wikis below -#endif - -#ifndef ISP2401 -v2.1.14.6 (8 changes parallel), Enlarge AF AWB_FR stats buffers -- Enlarge AF and AWB_FR stats buffers to support max grid width per stripe as oppose to per frame -#else -v2.1.17.10 (6 changes parallel), output_system_input_resolution -- adedd gdc_output_system_in_resolution to pipe config struct -#endif - -#ifndef ISP2401 -v2.1.14.8 (6 changes parallel), pipe config option for vf output bci mode downscaling -#else -v2.1.17.10 (5 changes parallel), Per pipe DPC configuration is added to ia_css_isp_parameters -- Per pipe DPC configuration is added to ia_css_isp_parameters - -v2.1.17.10 (10 changes parallel), pipe config option for vf output bci mode downscaling -#endif -- vf downscaling using yuv_scale binary. - -#ifndef ISP2401 -v2.1.14.10 (7 changes parallel), Add scale mode GDC V2 LUT to CSS API -#else -v2.1.17.12 (11 changes parallel), Add scale mode GDC V2 LUT to CSS API -#endif -- Allow client to set global LUT for gdc v2 (First step in this change. See wiki page for more details) - -#ifndef ISP2401 -v2.1.14.10 (8 changes parallel), Include added to type-support.h. -#else -v2.1.17.12 (12 changes parallel), Include added to type-support.h. -#endif -- Include of hive/cell_support.h was added to type-support.h, in order to -- have access to define HAVE_STDINT. - -#ifndef ISP2401 -v2.1.14.11 (7 changes parallel), Pipe configuration to enable BLI mode downscaling for -#else -v2.1.17.13 (11 changes parallel), Pipe configuration to enable BLI mode downscaling for -#endif -- BLI mode downscaling for capture post-processing - -#ifndef ISP2401 -v2.1.14.14 (9 changes parallel), Fix copyright headers (no functional change) -#else -v2.1.17.15 (8 changes parallel), Add copyright headers to css files -- Add copyright headers to css API files - -v2.1.17.15 (8 changes parallel), add copyright header to include files -- add copyright header to include files - -v2.1.17.15 (8 changes parallel), add copyright header to isp files -- add copyright header to isp files - -v2.1.17.15 (8 changes parallel), add copyright header to refactored code -- add copyright header to refactored code -- (base, camera, runtime directories) - -v2.1.17.16 (13 changes parallel), Fix copyright headers (no functional change) -#endif -- No functional change; only fixes copyright headers - -#ifndef ISP2401 -v2.1.14.14 (6 changes parallel), Remove continuous mode special case handling in ia_css_pipe_set_isp_config -#else -v2.1.17.16 (10 changes parallel), Remove continuous mode special case handling in ia_css_pipe_set_isp_config -#endif -- For continuous mode isp_config was being send to all pipes, -- even though API ia_css_pipe_set_isp_config is for single pipe -- Removed incorrect case - -#ifndef ISP2401 -v2.1.14.14 (6 changes parallel), DVS statistics grid produced by accelerator -#else -v2.1.17.16 (5 changes parallel), Added documentation to formats_config header file -- Added description of ranges for full-range flag - -v2.1.17.16 (10 changes parallel), DVS statistics grid produced by accelerator -#endif -- Add DVS statistics produced by accelerator grid to pipe info -- Add ia_css_pipe_has_dvs_stats function - -#ifndef ISP2401 -v2.1.14.15 (7 changes parallel), cont_remove_x_y_end_from_ae_and_awb -#else -v2.1.17.17 (5 changes parallel), Provide the CSS interface to select the luma only binaries -- Add a flag "enable_luma_only" to "struct ia_css_pipe_config" - -v2.1.17.17 (11 changes parallel), cont_remove_x_y_end_from_ae_and_awb -#endif -- this patch doesn't introduce any new api change, it only fixes a recent -- api merged change (#31938) , in order to have success CI i had to upload an api change request - -#ifndef ISP2401 -v2.1.14.17 (6 changes parallel), Add XNR3 blending strength to kernel interface -- Added a blending strength field to the XNR3 kernel interface to add -- support for blending. -#else -v2.1.17.17 (10 changes parallel), GAC state dump for debug -- added ia_css_dump_gac_state function - -v2.1.17.18 (23 changes parallel), output_format_nv12_16 -- added new output fromat nv12_16 -#endif - -#ifndef ISP2401 -v2.1.14.18 (22 changes parallel), eliminate two_pixels_per_clock field -#else -v2.1.17.18 (4 changes parallel), Remove author details from SKC src code -- remove author details from skc src code - -v2.1.17.19 (26 changes parallel), eliminate two_pixels_per_clock field -#endif -- remove obsolete field two_pixels_per_clock - -#ifndef ISP2401 -v2.1.14.19 (3 changes parallel), Fix copyright headers (no functional change) -#else -v2.1.17.20 (7 changes parallel), Fix copyright headers (no functional change) -#endif -- No functional change; only fixes copyright headers - -#ifndef ISP2401 -v2.1.14.21 (3 changes parallel), ia_css_skc_dvs_statistics field size change -- ia_css_skc_dvs_statistics field size change -#else -v2.1.17.20 (11 changes parallel), Add XNR3 blending strength to kernel interface -- Added a blending strength field to the XNR3 kernel interface to add -- support for blending. -#endif - -#ifndef ISP2401 -v2.1.15.0 (3 changes parallel), revert ia_css_skc_dvs_statistics field size change -- Reverted field size change, change was not ready for driver yet. -#else -v2.1.17.21 (24 changes parallel), Add N_CSS_PRBS_IDS and N_CSS_TPG_IDS -- Add N_CSS_PRBS_IDS to reflect the number of ia_css_prbs_id enum -- Add N_CSS_TPG_IDS to reflect the number of ia_css_tpg_id enum -#endif - -#ifndef ISP2401 -v2.1.15.2 (3 changes parallel), Return an error when both DPC and BDS are enabled in a pipe config -- Return an error when both DPC and BDS are enabled in a pipe config -#else -v2.1.17.23 (8 changes parallel), ia_css_skc_dvs_statistics field size change -- ia_css_skc_dvs_statistics field size change -#endif - -#ifndef ISP2401 -v2.1.15.3 (2 changes parallel), Update skycam DPC_MAX_NUMBER_OF_DP -- Automated tooling requires an API change request -- This change changes the implementation of #define DPC_MAX_NUMBER_OF_DP -- it now returns a different number -#else -v2.1.19.0 (6 changes parallel) -- Added code to calculate input_res using the Windows specification of binning -#endif - -#ifndef ISP2401 -v2.1.15.3 (18 changes parallel), output_format_nv12_16 -- added new output fromat nv12_16 -#else -v2.1.20.0 (7 changes parallel), Add interface to select TNR enabled binaries -- Add a bool "enable_tnr" to "struct ia_css_pipe_config" - -v2.1.20.0 (6 changes parallel), OSYS & GDC Debug dump function addition -- add GDC state dump function -- add OSYS state dump function - -v2.1.20.4 (7 changes parallel), Add ref_buf_select parameter for TNR3 to kernel interface -- Added a ref_buf_select parameter to the TNR3 kernel interface to add -- support for multiple reference buffers. - -v2.1.20.4 (6 changes parallel), DVS MAX grid dimensions to cover maximal resolution -- rename DVS_TABLE_HEIGHT/WIDTH to MAX_DVS_COORDS_TABLE_HEIGHT/WIDTH -- modify value of the above macros to cover max resolution - -v2.1.20.5 (54 changes parallel), add input feeder calculations getter -- add input_feeder_config public struct -- add get_input_feeder_config getter - -v2.1.20.5 (4 changes parallel), Enable runtime updating mapped args for QoS extension pipe -- added ia_css_pipe_update_qos_ext_mapped_arg() - -v2.1.20.7 (77 changes parallel), Add parameters to CPU routines via a macro. -- Replaced CPU memory allocation functions with macros to add caller func name + line number. -- This is done to help debug memory access issues, allocation issues, etc. -- Changed API: only ia_css_env.h - -v2.1.20.7 (2 changes parallel), Frame format override -- Added a function call to the pipe interface for overriding -- the frame format as set in the pipe. -- This is an optional interface that can be used under -- some strict conditions. - -v2.1.20.7 (2 changes parallel), Output_system_in_res Information -- Output_system_in_res_info field added to pipe_info struct - -v2.1.20.8, Temprarily disable memory debug features for SVOS. -- Temporary commented out the additions to allow SKC testing till root cause found -- Changed files ia_css_env.h and sh_css.c. - -v2.1.20.9, Enable ISP 2.7 naming -- Add IA_CSS_PIPE_VERSION_2_7 to enum ia_css_pipe_version -- Add #define SH_CSS_ISP_PIPE_VERSION_2_7 4 -#endif - -*/ - -#endif /*__CSS_API_VERSION_H*/ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h deleted file mode 100644 index 39785aa21459..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _hive_isp_css_ddr_hrt_modified_h_ -#define _hive_isp_css_ddr_hrt_modified_h_ - -#include <hmm_64/hmm.h> - -/* This function reads an image from DDR and stores it in the img_buf array - that has been allocated by the caller. - The specifics of how the pixels are stored into DDR by the DMA are taken - into account (bits padded to a width of 256, depending on the number of - elements per ddr word). - The DMA specific parameters give to this function (elems_per_xword and sign_extend) - should correspond to those given to the DMA engine. - The address is a virtual address which will be translated to a physical address before - data is loaded from or stored to that address. - - The return value is 0 in case of success and 1 in case of failure. - */ -unsigned int -hrt_isp_css_read_image_from_ddr( - unsigned short *img_buf, - unsigned int width, - unsigned int height, - unsigned int elems_per_xword, - unsigned int sign_extend, - hmm_ptr virt_addr); - -/* This function writes an image to DDR, keeping the same aspects into account as the read_image function - above. */ -unsigned int -hrt_isp_css_write_image_to_ddr( - const unsigned short *img_buf, - unsigned int width, - unsigned int height, - unsigned int elems_per_xword, - unsigned int sign_extend, - hmm_ptr virt_addr); - -/* return the size in bytes of an image (frame or plane). */ -unsigned int -hrt_isp_css_sizeof_image_in_ddr( - unsigned int width, - unsigned int height, - unsigned int bits_per_element); - -unsigned int -hrt_isp_css_stride_of_image_in_ddr( - unsigned int width, - unsigned int bits_per_element); - -hmm_ptr -hrt_isp_css_alloc_image_in_ddr( - unsigned int width, - unsigned int height, - unsigned int elems_per_xword); - -hmm_ptr -hrt_isp_css_calloc_image_in_ddr( - unsigned int width, - unsigned int height, - unsigned int elems_per_xword); - -#ifndef HIVE_ISP_NO_GDC -#include "gdc_v2_defs.h" - -hmm_ptr -hrt_isp_css_alloc_gdc_lut_in_ddr(void); - -void -hrt_isp_css_write_gdc_lut_to_ddr( - short values[4][HRT_GDC_N], - hmm_ptr virt_addr); -#endif - -#ifdef _HIVE_ISP_CSS_FPGA_SYSTEM -hmm_ptr -hrt_isp_css_alloc_image_for_display( - unsigned int width, - unsigned int height, - unsigned int elems_per_xword); - -hmm_ptr -hrt_isp_css_calloc_image_for_display( - unsigned int width, - unsigned int height, - unsigned int elems_per_xword); -#endif - -/* New set of functions, these do not require the elems_per_xword, but use bits_per_element instead, - this way the user does not need to know about the width of a DDR word. */ -unsigned int -hrt_isp_css_read_unsigned( - unsigned short *target, - unsigned int width, - unsigned int height, - unsigned int source_bits_per_element, - hmm_ptr source); - -unsigned int -hrt_isp_css_read_signed( - short *target, - unsigned int width, - unsigned int height, - unsigned int source_bits_per_element, - hmm_ptr source); - -unsigned int -hrt_isp_css_write_unsigned( - const unsigned short *source, - unsigned int width, - unsigned int height, - unsigned int target_bits_per_element, - hmm_ptr target); - -unsigned int -hrt_isp_css_write_signed( - const short *source, - unsigned int width, - unsigned int height, - unsigned int target_bits_per_element, - hmm_ptr target); - -hmm_ptr -hrt_isp_css_alloc( - unsigned int width, - unsigned int height, - unsigned int bits_per_element); - -hmm_ptr -hrt_isp_css_calloc( - unsigned int width, - unsigned int height, - unsigned int bits_per_element); - -#endif /* _hive_isp_css_ddr_hrt_modified_h_ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h deleted file mode 100644 index 342553d10e08..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _hive_isp_css_hrt_h -#define _hive_isp_css_hrt_h - -#include "system_types.h" - -#include "hive_isp_css_host_ids_hrt.h" -#include "hive_isp_css_defs.h" - -#ifdef HRT_ISP_CSS_CUSTOM_HOST -#ifndef HRT_USE_VIR_ADDRS -#define HRT_USE_VIR_ADDRS -#endif -/*#include "hive_isp_css_custom_host_hrt.h"*/ -#endif - -#include <gpio_block.h> -#include <gp_regs.h> -#include <gp_timer_hrt.h> - #include <css_receiver_2400_hrt.h> -// #include <isp2400_mamoiada_params.h> -// #include <isp2400_support.h> - /* insert idle signal clearing and setting around hrt_main */ - #if !defined(HRT_HW) || defined(HRT_ISP_CSS_INSERT_IDLE_SIGNAL) - #define hrt_main _hrt_isp_css_main - #endif - #ifdef _HIVE_ISP_CSS_SPECMAN_SYSTEM - #include "hive_isp_css_2400_specman_system.h" - #else -#if defined(IS_ISP_2400_MAMOIADA_SYSTEM) - #include "hive_isp_css_2400_system.h" -#elif defined(IS_ISP_2401_MAMOIADA_SYSTEM) - #include "hive_isp_css_2401_system.h" -#else -#error "hive_isp_css_hrt_modified.h: SYSTEM must be one of {2400_MAMOIADA_SYSTEM, 2401_MAMOIADA_SYSTEM}" -#endif - #endif -#include <sp_hrt.h> -#include <input_system_hrt.h> -#include <input_selector_hrt.h> -#include <sig_monitor_hrt.h> - -#include "hive_isp_css_sdram_wakeup_hrt.h" -#include "hive_isp_css_idle_signal_hrt.h" -#include "hive_isp_css_sp_hrt.h" -#include "hive_isp_css_isp_hrt.h" -#include "hive_isp_css_streaming_to_mipi_hrt.h" -#include "hive_isp_css_testbench_hrt.h" -#include "hive_isp_css_streaming_monitors_hrt.h" -#include "hive_isp_css_gp_regs_hrt.h" -#if defined(IS_ISP_2400_MAMOIADA_SYSTEM) -#include "hive_isp_css_irq_hrt.h" -#elif defined(IS_ISP_2401_MAMOIADA_SYSTEM) -#include "hive_isp_css_2401_irq_hrt.h" -#else -#error "hive_isp_css_hrt_modified.h: SYSTEM must be one of {2400_MAMOIADA_SYSTEM, 2401_MAMOIADA_SYSTEM}" -#endif - -#include "hive_isp_css_stream_switch_hrt.h" - -#include "hive_isp_css_ddr_hrt_modified.h" -#include "hive_isp_css_dma_set_hrt.h" - -#define HIVE_ISP_CSS_NO_STREAM_SWITCH 1 - -#endif /* _hive_isp_css_hrt_h */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h index 5654d911db65..7558f4964313 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h @@ -107,22 +107,6 @@ struct input_formatter_cfg_s { uint32_t block_no_reqs; }; -#define DEFAULT_IF_CONFIG \ -{ \ - 0, /* start_line */\ - 0, /* start_column */\ - 0, /* left_padding */\ - 0, /* cropped_height */\ - 0, /* cropped_width */\ - 0, /* deinterleaving */\ - 0, /*.buf_vecs */\ - 0, /* buf_start_index */\ - 0, /* buf_increment */\ - 0, /* buf_eol_offset */\ - false, /* is_yuv420_format */\ - false /* block_no_reqs */\ -} - extern const hrt_address HIVE_IF_SRST_ADDRESS[N_INPUT_FORMATTER_ID]; extern const hrt_data HIVE_IF_SRST_MASK[N_INPUT_FORMATTER_ID]; extern const uint8_t HIVE_IF_SWITCH_CODE[N_INPUT_FORMATTER_ID]; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h deleted file mode 100644 index 01c915c033a9..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __RESOURCE_GLOBAL_H_INCLUDED__ -#define __RESOURCE_GLOBAL_H_INCLUDED__ - -#define IS_RESOURCE_VERSION_1 - -typedef enum { - DMA_CHANNEL_RESOURCE_TYPE, - IRQ_CHANNEL_RESOURCE_TYPE, - MEM_SECTION_RESOURCE_TYPE, - N_RESOURCE_TYPE -} resource_type_ID_t; - -typedef enum { - PERMANENT_RESOURCE_RESERVATION, - PERSISTENT_RESOURCE_RESERVATION, - DEDICTATED_RESOURCE_RESERVATION, - SHARED_RESOURCE_RESERVATION, - N_RESOURCE_RESERVATION -} resource_reservation_t; - -#endif /* __RESOURCE_GLOBAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h deleted file mode 100644 index 1d3a43abe55d..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __XMEM_GLOBAL_H_INCLUDED__ -#define __XMEM_GLOBAL_H_INCLUDED__ - -#include "isp.h" - -#endif /* __XMEM_GLOBAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h deleted file mode 100644 index 6928965cf513..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __BAMEM_H_INCLUDED__ -#define __BAMEM_H_INCLUDED__ - -/* - * This file is included on every cell {SP,ISP,host} and on every system - * that uses the BAMEM device. It defines the API to DLI bridge - * - * System and cell specific interfaces and inline code are included - * conditionally through Makefile path settings. - * - * - . system and cell agnostic interfaces, constants and identifiers - * - public: system agnostic, cell specific interfaces - * - private: system dependent, cell specific interfaces & inline implementations - * - global: system specific constants and identifiers - * - local: system and cell specific constants and identifiers - */ - - -#include "system_local.h" -#include "bamem_local.h" - -#ifndef __INLINE_BAMEM__ -#define STORAGE_CLASS_BAMEM_H extern -#define STORAGE_CLASS_BAMEM_C -#include "bamem_public.h" -#else /* __INLINE_BAMEM__ */ -#define STORAGE_CLASS_BAMEM_H static inline -#define STORAGE_CLASS_BAMEM_C static inline -#include "bamem_private.h" -#endif /* __INLINE_BAMEM__ */ - -#endif /* __BAMEM_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h deleted file mode 100644 index 18bc5ef3d0bf..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __BBB_CONFIG_H_INCLUDED__ -#define __BBB_CONFIG_H_INCLUDED__ -/* This header contains BBB defines common to ISP and host */ - -#define BFA_MAX_KWAY (49) -#define BFA_RW_LUT_SIZE (7) - -#define SAD3x3_IN_SHIFT (2) /* input right shift value for SAD3x3 */ -#define SAD3x3_OUT_SHIFT (2) /* output right shift value for SAD3x3 */ - -/* XCU and BMA related defines shared between host and ISP - * also need to be moved here */ -#endif /* __BBB_CONFIG_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h deleted file mode 100644 index 6d014fafb713..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __CPU_MEM_SUPPORT_H_INCLUDED__ -#define __CPU_MEM_SUPPORT_H_INCLUDED__ - -#if defined (__KERNEL__) -#include <linux/string.h> /* memset */ -#else -#include <string.h> /* memset */ -#endif - -#include "sh_css_internal.h" /* sh_css_malloc and sh_css_free */ - -static inline void* -ia_css_cpu_mem_alloc(unsigned int size) -{ - return sh_css_malloc(size); -} - -static inline void* -ia_css_cpu_mem_copy(void* dst, const void* src, unsigned int size) -{ - if(!src || !dst) - return NULL; - - return memcpy(dst, src, size); -} - -static inline void* -ia_css_cpu_mem_set_zero(void* dst, unsigned int size) -{ - if(!dst) - return NULL; - - return memset(dst, 0, size); -} - -static inline void -ia_css_cpu_mem_free(void* ptr) -{ - if(!ptr) - return; - - sh_css_free(ptr); -} - -#endif /* __CPU_MEM_SUPPORT_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h deleted file mode 100644 index ab3391716c82..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP2400_CONFIG_H_INCLUDED__ -#define __ISP2400_CONFIG_H_INCLUDED__ - -#define NUM_BITS 14 -#define NUM_SLICE_ELEMS 4 -#define ROUNDMODE ROUND_NEAREST_EVEN -#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */ -#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */ - -#endif /* __ISP2400_CONFIG_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h deleted file mode 100644 index 4fae856f5a23..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP2500_CONFIG_H_INCLUDED__ -#define __ISP2500_CONFIG_H_INCLUDED__ - -#define NUM_BITS 12 -#define NUM_SLICE_ELEMS 4 -#define ROUNDMODE ROUND_NEAREST_EVEN -#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */ -#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */ - - -#define HAS_div_unit - -#define HAS_vec_sub - -#endif /* __ISP2500_CONFIG_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h deleted file mode 100644 index 6086be8cb0d3..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP2600_CONFIG_H_INCLUDED__ -#define __ISP2600_CONFIG_H_INCLUDED__ - - -#define NUM_BITS 16 - - -#define NUM_SLICE_ELEMS 8 -#define ROUNDMODE ROUND_NEAREST_EVEN -#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */ -#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */ -#define ISP_NWAY 32 /* Number of elements in a vector in ISP 2600 */ - -#define HAS_div_unit -#define HAS_1w_sqrt_u_unit -#define HAS_2w_sqrt_u_unit - -#define HAS_vec_sub - -#endif /* __ISP2600_CONFIG_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h deleted file mode 100644 index beceefa24ca0..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP2601_CONFIG_H_INCLUDED__ -#define __ISP2601_CONFIG_H_INCLUDED__ - -#define NUM_BITS 16 -#define ISP_VEC_ELEMBITS NUM_BITS -#define ISP_NWAY 32 -#define NUM_SLICE_ELEMS 4 -#define ROUNDMODE ROUND_NEAREST_EVEN -#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */ -#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */ - -#define HAS_div_unit -#define HAS_bfa_unit -#define HAS_1w_sqrt_u_unit -#define HAS_2w_sqrt_u_unit - -#define HAS_vec_sub - -/* Bit widths and element widths defined in HW implementation of BFA */ -#define BFA_THRESHOLD_BIT_CNT (8) -#define BFA_THRESHOLD_MASK ((1<<BFA_THRESHOLD_BIT_CNT)-1) -#define BFA_SW_BIT_CNT (7) -#define BFA_SW_MASK ((1<<BFA_SW_BIT_CNT)-1) - -#define BFA_RW_BIT_CNT (7) -#define BFA_RW_MASK ((1<<BFA_RW_BIT_CNT)-1) -#define BFA_RW_SLOPE_BIT_POS (8) -#define BFA_RW_SLOPE_BIT_SHIFT (5) - -#define BFA_RW_IDX_BIT_CNT (3) -#define BFA_RW_FRAC_BIT_CNT (5) -#define BFA_RW_LUT0_FRAC_START_BIT (0) -#define BFA_RW_LUT0_FRAC_END_BIT (BFA_RW_LUT0_FRAC_START_BIT+BFA_RW_FRAC_BIT_CNT-1) /* 4 */ -#define BFA_RW_LUT1_FRAC_START_BIT (2) -#define BFA_RW_LUT1_FRAC_END_BIT (BFA_RW_LUT1_FRAC_START_BIT+BFA_RW_FRAC_BIT_CNT-1) /* 6 */ -/* LUT IDX end bit computation, start+idx_bit_cnt-2, one -1 comes as we count - * bits from 0, another -1 comes as we use 2 lut table, so idx_bit_cnt is one - * bit more */ -#define BFA_RW_LUT0_IDX_START_BIT (BFA_RW_LUT0_FRAC_END_BIT+1) /* 5 */ -#define BFA_RW_LUT0_IDX_END_BIT (BFA_RW_LUT0_IDX_START_BIT+BFA_RW_IDX_BIT_CNT-2) /* 6 */ -#define BFA_RW_LUT1_IDX_START_BIT (BFA_RW_LUT1_FRAC_END_BIT + 1) /* 7 */ -#define BFA_RW_LUT1_IDX_END_BIT (BFA_RW_LUT1_IDX_START_BIT+BFA_RW_IDX_BIT_CNT-2) /* 8 */ -#define BFA_RW_LUT_THRESHOLD (1<<(BFA_RW_LUT1_IDX_END_BIT-1)) /* 0x80 : next bit after lut1 end is set */ -#define BFA_RW_LUT1_IDX_OFFSET ((1<<(BFA_RW_IDX_BIT_CNT-1))-1) /* 3 */ - -#define BFA_CP_MASK (0xFFFFFF80) -#define BFA_SUBABS_SHIFT (6) -#define BFA_SUBABS_BIT_CNT (8) -#define BFA_SUBABS_MAX ((1<<BFA_SUBABS_BIT_CNT)-1) -#define BFA_SUBABSSAT_BIT_CNT (9) -#define BFA_SUBABSSAT_MAX ((1<<BFA_SUBABSSAT_BIT_CNT)-1) -#define BFA_WEIGHT_SHIFT (6) - -#endif /* __ISP2601_CONFIG_H_INCLUDED__ */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h deleted file mode 100644 index 80506f2419a8..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_CONFIG_H_INCLUDED__ -#define __ISP_CONFIG_H_INCLUDED__ - -#if defined(ISP2400) || defined(ISP2401) -#include "isp2400_config.h" -#else -#error "Please define a core {ISP2400, ISP2401}" -#endif - -#endif /* __ISP_CONFIG_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h deleted file mode 100644 index 0d978e5911c0..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h +++ /dev/null @@ -1,844 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_OP1W_H_INCLUDED__ -#define __ISP_OP1W_H_INCLUDED__ - -/* - * This file is part of the Multi-precision vector operations exstension package. - */ - -/* - * Single-precision vector operations - */ - -/* - * Prerequisites: - * - */ - -#ifdef INLINE_ISP_OP1W -#define STORAGE_CLASS_ISP_OP1W_FUNC_H static inline -#define STORAGE_CLASS_ISP_OP1W_DATA_H static inline_DATA -#else /* INLINE_ISP_OP1W */ -#define STORAGE_CLASS_ISP_OP1W_FUNC_H extern -#define STORAGE_CLASS_ISP_OP1W_DATA_H extern_DATA -#endif /* INLINE_ISP_OP1W */ - -/* - * Single-precision data type specification - */ - -#include "isp_op1w_types.h" -#include "isp_op2w_types.h" // for doubling operations. - -/* - * Single-precision prototype specification - */ - -/* Arithmetic */ - -/* @brief bitwise AND - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise and of both input arguments - * - * This function will calculate the bitwise and. - * result = _a & _b - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_and( - const tvector1w _a, - const tvector1w _b); - -/* @brief bitwise OR - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise or of both input arguments - * - * This function will calculate the bitwise or. - * result = _a | _b - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_or( - const tvector1w _a, - const tvector1w _b); - -/* @brief bitwise XOR - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise xor of both input arguments - * - * This function will calculate the bitwise xor. - * result = _a ^ _b - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_xor( - const tvector1w _a, - const tvector1w _b); - -/* @brief bitwise inverse - * - * @param[in] _a first argument - * - * @return bitwise inverse of both input arguments - * - * This function will calculate the bitwise inverse. - * result = ~_a - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_inv( - const tvector1w _a); - -/* Additive */ - -/* @brief addition - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return sum of both input arguments - * - * This function will calculate the sum of the input arguments. - * in case of overflow it will wrap around. - * result = _a + _b - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_add( - const tvector1w _a, - const tvector1w _b); - -/* @brief subtraction - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _b subtracted from _a. - * - * This function will subtract _b from _a. - * in case of overflow it will wrap around. - * result = _a - _b - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_sub( - const tvector1w _a, - const tvector1w _b); - -/* @brief saturated addition - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated sum of both input arguments - * - * This function will calculate the sum of the input arguments. - * in case of overflow it will saturate. - * result = CLIP(_a + _b, MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_addsat( - const tvector1w _a, - const tvector1w _b); - -/* @brief saturated subtraction - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated subtraction of both input arguments - * - * This function will subtract _b from _a. - * in case of overflow it will saturate. - * result = CLIP(_a - _b, MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subsat( - const tvector1w _a, - const tvector1w _b); - -#ifdef ISP2401 -/* @brief Unsigned saturated subtraction - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated subtraction of both input arguments - * - * This function will subtract _b from _a. - * in case of overflow it will saturate. - * result = CLIP(_a - _b, 0, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w_unsigned OP_1w_subsat_u( - const tvector1w_unsigned _a, - const tvector1w_unsigned _b); - -#endif -/* @brief subtraction with shift right and rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (a - b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit with rounding. - * No overflow can occur. - * result = (_a - _b) >> 1 - * - * Note: This function will be deprecated due to - * the naming confusion and it will be replaced - * by "OP_1w_subhalfrnd". - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subasr1( - const tvector1w _a, - const tvector1w _b); - -/* @brief Subtraction with shift right and rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a - _b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit with rounding. - * No overflow can occur. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subhalfrnd( - const tvector1w _a, - const tvector1w _b); - -/* @brief Subtraction with shift right and no rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a - _b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit without rounding (i.e. truncation). - * No overflow can occur. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subhalf( - const tvector1w _a, - const tvector1w _b); - - -/* @brief saturated absolute value - * - * @param[in] _a input - * - * @return saturated absolute value of the input - * - * This function will calculate the saturated absolute value of the input. - * in case of overflow it will saturate. - * if (_a > 0) return _a;<br> - * else return CLIP(-_a, MIN_RANGE, MAX_RANGE);<br> - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_abs( - const tvector1w _a); - -/* @brief saturated absolute difference - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return sat(abs(a-b)); - * - * This function will calculate the saturated absolute value - * of the saturated difference of both inputs. - * result = sat(abs(sat(_a - _b))); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subabssat( - const tvector1w _a, - const tvector1w _b); - -/* Multiplicative */ - -/* @brief doubling multiply - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return product of _a and _b - * - * This function will calculate the product - * of the input arguments and returns a double - * precision result. - * No overflow can occur. - * result = _a * _b; - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector2w OP_1w_muld( - const tvector1w _a, - const tvector1w _b); - -/* @brief integer multiply - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return product of _a and _b - * - * This function will calculate the product - * of the input arguments and returns the LSB - * aligned single precision result. - * In case of overflow it will wrap around. - * result = _a * _b; - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mul( - const tvector1w _a, - const tvector1w _b); - -/* @brief fractional saturating multiply - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated product of _a and _b - * - * This function will calculate the fixed point - * product of the input arguments - * and returns a single precision result. - * In case of overflow it will saturate. - * FP_UNITY * FP_UNITY => FP_UNITY. - * result = CLIP(_a * _b >> (NUM_BITS-1), MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qmul( - const tvector1w _a, - const tvector1w _b); - -/* @brief fractional saturating multiply with rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return product of _a and _b - * - * This function will calculate the fixed point - * product of the input arguments - * and returns a single precision result. - * FP_UNITY * FP_UNITY => FP_UNITY. - * Depending on the rounding mode of the core - * it will round to nearest or to nearest even. - * result = CLIP(_a * _b >> (NUM_BITS-1), MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qrmul( - const tvector1w _a, - const tvector1w _b); - -/* Comparative */ - -/* @brief equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a == _b - * - * This function will return true if both inputs - * are equal, and false if not equal. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_eq( - const tvector1w _a, - const tvector1w _b); - -/* @brief not equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a != _b - * - * This function will return false if both inputs - * are equal, and true if not equal. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_ne( - const tvector1w _a, - const tvector1w _b); - -/* @brief less or equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a <= _b - * - * This function will return true if _a is smaller - * or equal than _b. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_le( - const tvector1w _a, - const tvector1w _b); - -/* @brief less then - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a < _b - * - * This function will return true if _a is smaller - * than _b. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_lt( - const tvector1w _a, - const tvector1w _b); - -/* @brief greater or equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a >= _b - * - * This function will return true if _a is greater - * or equal than _b. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_ge( - const tvector1w _a, - const tvector1w _b); - -/* @brief greater than - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a > _b - * - * This function will return true if _a is greater - * than _b. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_gt( - const tvector1w _a, - const tvector1w _b); - -/* Shift */ - -/* @brief aritmetic shift right - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * This function will shift _a with _b bits to the right, - * preserving the sign bit. - * It asserts 0 <= _b <= MAX_SHIFT_1W. - * - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asr( - const tvector1w _a, - const tvector1w _b); - -/* @brief aritmetic shift right with rounding - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * If _b < NUM_BITS, this function will shift _a with _b bits to the right, - * preserving the sign bit, and depending on the rounding mode of the core - * it will round to nearest or to nearest even. - * If _b >= NUM_BITS, this function will return 0. - * It asserts 0 <= _b <= MAX_SHIFT_1W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asrrnd( - const tvector1w _a, - const tvector1w _b); - -/* @brief saturating arithmetic shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * If _b < MAX_BITDEPTH, this function will shift _a with _b bits to the left, - * saturating at MIN_RANGE/MAX_RANGE in case of overflow. - * If _b >= MAX_BITDEPTH, this function will return MIN_RANGE if _a < 0, - * MAX_RANGE if _a > 0, 0 if _a == 0. - * (with MAX_BITDEPTH=64) - * It asserts 0 <= _b <= MAX_SHIFT_1W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asl( - const tvector1w _a, - const tvector1w _b); - -/* @brief saturating aritmetic shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * This function is identical to OP_1w_asl( ) - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_aslsat( - const tvector1w _a, - const tvector1w _b); - -/* @brief logical shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * This function will shift _a with _b bits to the left. - * It will insert zeroes on the right. - * It asserts 0 <= _b <= MAX_SHIFT_1W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lsl( - const tvector1w _a, - const tvector1w _b); - -/* @brief logical shift right - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * This function will shift _a with _b bits to the right. - * It will insert zeroes on the left. - * It asserts 0 <= _b <= MAX_SHIFT_1W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lsr( - const tvector1w _a, - const tvector1w _b); - -#ifdef ISP2401 -/* @brief bidirectional saturating arithmetic shift - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << |_b| if _b is positive - * _a >> |_b| if _b is negative - * - * If _b > 0, this function will shift _a with _b bits to the left, - * saturating at MIN_RANGE/MAX_RANGE in case of overflow. - * if _b < 0, this function will shift _a with _b bits to the right. - * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W. - * If _b = 0, it returns _a. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_ashift_sat( - const tvector1w _a, - const tvector1w _b); - -/* @brief bidirectional non-saturating arithmetic shift - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << |_b| if _b is positive - * _a >> |_b| if _b is negative - * - * If _b > 0, this function will shift _a with _b bits to the left, - * no saturation is performed in case of overflow. - * if _b < 0, this function will shift _a with _b bits to the right. - * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W. - * If _b = 0, it returns _a. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_ashift( - const tvector1w _a, - const tvector1w _b); - - -/* @brief bidirectional logical shift - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << |_b| if _b is positive - * _a >> |_b| if _b is negative - * - * This function will shift _a with _b bits to the left if _b is positive. - * This function will shift _a with _b bits to the right if _b is negative. - * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W. - * It inserts zeros on the left or right depending on the shift direction: - * right or left. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lshift( - const tvector1w _a, - const tvector1w _b); - -#endif -/* Cast */ - -/* @brief Cast from int to 1w - * - * @param[in] _a input - * - * @return _a - * - * This function casts the input from integer type to - * single precision. It asserts there is no overflow. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_int_cast_to_1w( - const int _a); - -/* @brief Cast from 1w to int - * - * @param[in] _a input - * - * @return _a - * - * This function casts the input from single precision type to - * integer, preserving value and sign. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H int OP_1w_cast_to_int( - const tvector1w _a); - -/* @brief Cast from 1w to 2w - * - * @param[in] _a input - * - * @return _a - * - * This function casts the input from single precision type to - * double precision, preserving value and sign. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector2w OP_1w_cast_to_2w( - const tvector1w _a); - -/* @brief Cast from 2w to 1w - * - * @param[in] _a input - * - * @return _a - * - * This function casts the input from double precision type to - * single precision. In case of overflow it will wrap around. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_2w_cast_to_1w( - const tvector2w _a); - - -/* @brief Cast from 2w to 1w with saturation - * - * @param[in] _a input - * - * @return _a - * - * This function casts the input from double precision type to - * single precision after saturating it to the range of single - * precision. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_2w_sat_cast_to_1w( - const tvector2w _a); - -/* clipping */ - -/* @brief Clip asymmetrical - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a clipped between ~_b and b - * - * This function will clip the first argument between - * (-_b - 1) and _b. - * It asserts _b >= 0. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_clip_asym( - const tvector1w _a, - const tvector1w _b); - -/* @brief Clip zero - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a clipped beteween 0 and _b - * - * This function will clip the first argument between - * zero and _b. - * It asserts _b >= 0. - * - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_clipz( - const tvector1w _a, - const tvector1w _b); - -/* division */ - -/* @brief Truncated division - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return trunc( _a / _b ) - * - * This function will divide the first argument by - * the second argument, with rounding toward 0. - * If _b == 0 and _a < 0, the function will return MIN_RANGE. - * If _b == 0 and _a == 0, the function will return 0. - * If _b == 0 and _a > 0, the function will return MAX_RANGE. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_div( - const tvector1w _a, - const tvector1w _b); - -/* @brief Fractional saturating divide - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a / _b - * - * This function will perform fixed point division of - * the first argument by the second argument, with rounding toward 0. - * In case of overflow it will saturate. - * If _b == 0 and _a < 0, the function will return MIN_RANGE. - * If _b == 0 and _a == 0, the function will return 0. - * If _b == 0 and _a > 0, the function will return MAX_RANGE. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qdiv( - const tvector1w _a, - const tvector1w _b); - -/* @brief Modulo - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a % _b - * - * This function will return the remainder r = _a - _b * trunc( _a / _b ), - * Note that the sign of the remainder is always equal to the sign of _a. - * If _b == 0 the function will return _a. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mod( - const tvector1w _a, - const tvector1w _b); - -/* @brief Unsigned integer Square root - * - * @param[in] _a input - * - * @return Integer square root of _a - * - * This function will calculate the Integer square root of _a - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w_unsigned OP_1w_sqrt_u( - const tvector1w_unsigned _a); - -/* Miscellaneous */ - -/* @brief Multiplexer - * - * @param[in] _a first argument - * @param[in] _b second argument - * @param[in] _c condition - * - * @return _c ? _a : _b - * - * This function will return _a if the condition _c - * is true and _b otherwise. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mux( - const tvector1w _a, - const tvector1w _b, - const tflags _c); - -/* @brief Average without rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a + _b) >> 1 - * - * This function will add _a and _b, and right shift - * the result by one without rounding. No overflow - * will occur because addition is performed in the - * proper precision. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_avg( - const tvector1w _a, - const tvector1w _b); - -/* @brief Average with rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a + _b) >> 1 - * - * This function will add _a and _b at full precision, - * and right shift with rounding the result with 1 bit. - * Depending on the rounding mode of the core - * it will round to nearest or to nearest even. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_avgrnd( - const tvector1w _a, - const tvector1w _b); - -/* @brief Minimum - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a < _b) ? _a : _b; - * - * This function will return the smallest of both - * input arguments. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_min( - const tvector1w _a, - const tvector1w _b); - -/* @brief Maximum - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a > _b) ? _a : _b; - * - * This function will return the largest of both - * input arguments. - */ -STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_max( - const tvector1w _a, - const tvector1w _b); - -#ifndef INLINE_ISP_OP1W -#define STORAGE_CLASS_ISP_OP1W_FUNC_C -#define STORAGE_CLASS_ISP_OP1W_DATA_C const -#else /* INLINE_ISP_OP1W */ -#define STORAGE_CLASS_ISP_OP1W_FUNC_C STORAGE_CLASS_ISP_OP1W_FUNC_H -#define STORAGE_CLASS_ISP_OP1W_DATA_C STORAGE_CLASS_ISP_OP1W_DATA_H -#include "isp_op1w.c" -#define ISP_OP1W_INLINED -#endif /* INLINE_ISP_OP1W */ - -#endif /* __ISP_OP1W_H_INCLUDED__ */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h deleted file mode 100644 index c81e587509a1..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_OP1W_TYPES_H_INCLUDED__ -#define __ISP_OP1W_TYPES_H_INCLUDED__ - -/* - * This file is part of the Multi-precision vector operations exstension package. - */ - -/* - * Single-precision vector operations - */ - -/* - * Prerequisites: - * - */ - -#include "mpmath.h" - -/* - * Single-precision data type specification - */ - - -typedef mpsdata_t tvector1w; -typedef mpsdata_t tscalar1w; -typedef spsdata_t tflags; -typedef mpudata_t tvector1w_unsigned; -typedef mpsdata_t tscalar1w_weight; -typedef mpsdata_t tvector1w_signed_positive; -typedef mpsdata_t tvector1w_weight; -#ifdef ISP2401 -typedef bool tscalar_bool; -#endif - -typedef struct { - tvector1w d; - tflags f; -} tvector1w_tflags1w; - -#endif /* __ISP_OP1W_TYPES_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h deleted file mode 100644 index 7575d260b837..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_OP2W_H_INCLUDED__ -#define __ISP_OP2W_H_INCLUDED__ - -/* - * This file is part of the Multi-precision vector operations exstension package. - */ - -/* - * Double-precision vector operations - */ - -/* - * Prerequisites: - * - */ - -#ifdef INLINE_ISP_OP2W -#define STORAGE_CLASS_ISP_OP2W_FUNC_H static inline -#define STORAGE_CLASS_ISP_OP2W_DATA_H static inline_DATA -#else /* INLINE_ISP_OP2W */ -#define STORAGE_CLASS_ISP_OP2W_FUNC_H extern -#define STORAGE_CLASS_ISP_OP2W_DATA_H extern_DATA -#endif /* INLINE_ISP_OP2W */ - -/* - * Double-precision data type specification - */ - -#include "isp_op2w_types.h" - -/* - * Double-precision prototype specification - */ - -/* Arithmetic */ - -/* @brief bitwise AND - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise and of both input arguments - * - * This function will calculate the bitwise and. - * result = _a & _b - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_and( - const tvector2w _a, - const tvector2w _b); - -/* @brief bitwise OR - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise or of both input arguments - * - * This function will calculate the bitwise or. - * result = _a | _b - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_or( - const tvector2w _a, - const tvector2w _b); - -/* @brief bitwise XOR - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return bitwise xor of both input arguments - * - * This function will calculate the bitwise xor. - * result = _a ^ _b - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_xor( - const tvector2w _a, - const tvector2w _b); - -/* @brief bitwise inverse - * - * @param[in] _a first argument - * - * @return bitwise inverse of both input arguments - * - * This function will calculate the bitwise inverse. - * result = ~_a - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_inv( - const tvector2w _a); - -/* Additive */ - -/* @brief addition - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return sum of both input arguments - * - * This function will calculate the sum of the input arguments. - * in case of overflow it will wrap around. - * result = _a + _b - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_add( - const tvector2w _a, - const tvector2w _b); - -/* @brief subtraction - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _b subtracted from _a. - * - * This function will subtract _b from _a. - * in case of overflow it will wrap around. - * result = _a - _b - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_sub( - const tvector2w _a, - const tvector2w _b); - -/* @brief saturated addition - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated sum of both input arguments - * - * This function will calculate the sum of the input arguments. - * in case of overflow it will saturate - * result = CLIP(_a + _b, MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_addsat( - const tvector2w _a, - const tvector2w _b); - -/* @brief saturated subtraction - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated subtraction of both input arguments - * - * This function will subtract _b from _a. - * in case of overflow it will saturate - * result = CLIP(_a - _b, MIN_RANGE, MAX_RANGE); - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subsat( - const tvector2w _a, - const tvector2w _b); - -/* @brief subtraction with shift right and rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (a - b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit with rounding. - * No overflow can occur. - * result = (_a - _b) >> 1 - * - * Note: This function will be deprecated due to - * the naming confusion and it will be replaced - * by "OP_2w_subhalfrnd". - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subasr1( - const tvector2w _a, - const tvector2w _b); - -/* @brief Subtraction with shift right and rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a - _b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit with rounding. - * No overflow can occur. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subhalfrnd( - const tvector2w _a, - const tvector2w _b); - -/* @brief Subtraction with shift right and no rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a - _b) >> 1 - * - * This function subtracts _b from _a and right shifts - * the result by 1 bit without rounding (i.e. truncation). - * No overflow can occur. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subhalf( - const tvector2w _a, - const tvector2w _b); - -/* @brief saturated absolute value - * - * @param[in] _a input - * - * @return saturated absolute value of the input - * - * This function will calculate the saturated absolute value of the input. - * In case of overflow it will saturate. - * if (_a > 0) return _a;<br> - * else return CLIP(-_a, MIN_RANGE, MAX_RANGE);<br> - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_abs( - const tvector2w _a); - -/* @brief saturated absolute difference - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return sat(abs(sat(a-b))); - * - * This function will calculate the saturated absolute value - * of the saturated difference of both inputs. - * result = sat(abs(sat(_a - _b))); - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subabssat( - const tvector2w _a, - const tvector2w _b); - -/* Multiplicative */ - -/* @brief integer multiply - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return product of _a and _b - * - * This function will calculate the product - * of the input arguments and returns the LSB - * aligned double precision result. - * In case of overflow it will wrap around. - * result = _a * _b; - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mul( - const tvector2w _a, - const tvector2w _b); - -/* @brief fractional saturating multiply - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return saturated product of _a and _b - * - * This function will calculate the fixed point - * product of the input arguments - * and returns a double precision result. - * In case of overflow it will saturate. - * result =((_a * _b) << 1) >> (2*NUM_BITS); - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_qmul( - const tvector2w _a, - const tvector2w _b); - -/* @brief fractional saturating multiply with rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return product of _a and _b - * - * This function will calculate the fixed point - * product of the input arguments - * and returns a double precision result. - * Depending on the rounding mode of the core - * it will round to nearest or to nearest even. - * In case of overflow it will saturate. - * result = ((_a * _b) << 1) >> (2*NUM_BITS); - */ - -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_qrmul( - const tvector2w _a, - const tvector2w _b); - -/* Comparative */ - -/* @brief equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a == _b - * - * This function will return true if both inputs - * are equal, and false if not equal. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_eq( - const tvector2w _a, - const tvector2w _b); - -/* @brief not equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a != _b - * - * This function will return false if both inputs - * are equal, and true if not equal. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_ne( - const tvector2w _a, - const tvector2w _b); - -/* @brief less or equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a <= _b - * - * This function will return true if _a is smaller - * or equal than _b. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_le( - const tvector2w _a, - const tvector2w _b); - -/* @brief less then - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a < _b - * - * This function will return true if _a is smaller - * than _b. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_lt( - const tvector2w _a, - const tvector2w _b); - -/* @brief greater or equal - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a >= _b - * - * This function will return true if _a is greater - * or equal than _b. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_ge( - const tvector2w _a, - const tvector2w _b); - -/* @brief greater than - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a > _b - * - * This function will return true if _a is greater - * than _b. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_gt( - const tvector2w _a, - const tvector2w _b); - -/* Shift */ - -/* @brief aritmetic shift right - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * This function will shift _a with _b bits to the right, - * preserving the sign bit. - * It asserts 0 <= _b <= MAX_SHIFT_2W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asr( - const tvector2w _a, - const tvector2w _b); - -/* @brief aritmetic shift right with rounding - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * If _b < 2*NUM_BITS, this function will shift _a with _b bits to the right, - * preserving the sign bit, and depending on the rounding mode of the core - * it will round to nearest or to nearest even. - * If _b >= 2*NUM_BITS, this function will return 0. - * It asserts 0 <= _b <= MAX_SHIFT_2W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asrrnd( - const tvector2w _a, - const tvector2w _b); - -/* @brief saturating aritmetic shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * If _b < MAX_BITDEPTH, this function will shift _a with _b bits to the left, - * saturating at MIN_RANGE/MAX_RANGE in case of overflow. - * If _b >= MAX_BITDEPTH, this function will return MIN_RANGE if _a < 0, - * MAX_RANGE if _a > 0, 0 if _a == 0. - * (with MAX_BITDEPTH=64) - * It asserts 0 <= _b <= MAX_SHIFT_2W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asl( - const tvector2w _a, - const tvector2w _b); - -/* @brief saturating aritmetic shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * This function is identical to OP_2w_asl( ) - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_aslsat( - const tvector2w _a, - const tvector2w _b); - -/* @brief logical shift left - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a << _b - * - * This function will shift _a with _b bits to the left. - * It will insert zeroes on the right. - * It asserts 0 <= _b <= MAX_SHIFT_2W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_lsl( - const tvector2w _a, - const tvector2w _b); - -/* @brief logical shift right - * - * @param[in] _a input - * @param[in] _b shift amount - * - * @return _a >> _b - * - * This function will shift _a with _b bits to the right. - * It will insert zeroes on the left. - * It asserts 0 <= _b <= MAX_SHIFT_2W. - * The operation count for this function assumes that - * the shift amount is a cloned scalar input. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_lsr( - const tvector2w _a, - const tvector2w _b); - -/* clipping */ - -/* @brief Clip asymmetrical - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a clipped between ~_b and b - * - * This function will clip the first argument between - * (-_b - 1) and _b. - * It asserts _b >= 0. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_clip_asym( - const tvector2w _a, - const tvector2w _b); - -/* @brief Clip zero - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return _a clipped beteween 0 and _b - * - * This function will clip the first argument between - * zero and _b. - * It asserts _b >= 0. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_clipz( - const tvector2w _a, - const tvector2w _b); - -/* division */ - -/* @brief Truncated division - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return trunc( _a / _b ) - * - * This function will divide the first argument by - * the second argument, with rounding toward 0. - * If _b == 0 and _a < 0, the function will return MIN_RANGE. - * If _b == 0 and _a == 0, the function will return 0. - * If _b == 0 and _a > 0, the function will return MAX_RANGE. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_div( - const tvector2w _a, - const tvector2w _b); - -/* @brief Saturating truncated division - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return CLIP( trunc( _a / _b ), MIN_RANGE1w, MAX_RANGE1w ) - * - * This function will divide the first argument by - * the second argument, with rounding toward 0, and - * saturate the result to the range of single precision. - * If _b == 0 and _a < 0, the function will return MIN_RANGE. - * If _b == 0 and _a == 0, the function will return 0. - * If _b == 0 and _a > 0, the function will return MAX_RANGE. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector1w OP_2w_divh( - const tvector2w _a, - const tvector1w _b); - -/* @brief Modulo - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return n/a - * - * This function has not yet been implemented. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mod( - const tvector2w _a, - const tvector2w _b); - -/* @brief Unsigned Integer Square root - * - * @param[in] _a input - * - * @return square root of _a - * - * This function will calculate the unsigned integer square root of _a - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector1w_unsigned OP_2w_sqrt_u( - const tvector2w_unsigned _a); - -/* Miscellaneous */ - -/* @brief Multiplexer - * - * @param[in] _a first argument - * @param[in] _b second argument - * @param[in] _c condition - * - * @return _c ? _a : _b - * - * This function will return _a if the condition _c - * is true and _b otherwise. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mux( - const tvector2w _a, - const tvector2w _b, - const tflags _c); - -/* @brief Average without rounding - * - * @param[in] _a first operand - * @param[in] _b second operand - * - * @return (_a + _b) >> 1 - * - * This function will add _a and _b, and right shift - * the result by one without rounding. No overflow - * will occur because addition is performed in the - * proper precision. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_avg( - const tvector2w _a, - const tvector2w _b); - -/* @brief Average with rounding - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a + _b) >> 1 - * - * This function will add _a and _b at full precision, - * and right shift with rounding the result with 1 bit. - * Depending on the rounding mode of the core - * it will round to nearest or to nearest even. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_avgrnd( - const tvector2w _a, - const tvector2w _b); - -/* @brief Minimum - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a < _b) ? _a : _b; - * - * This function will return the smallest of both - * input arguments. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_min( - const tvector2w _a, - const tvector2w _b); - -/* @brief Maximum - * - * @param[in] _a first argument - * @param[in] _b second argument - * - * @return (_a > _b) ? _a : _b; - * - * This function will return the largest of both - * input arguments. - */ -STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_max( - const tvector2w _a, - const tvector2w _b); - -#ifndef INLINE_ISP_OP2W -#define STORAGE_CLASS_ISP_OP2W_FUNC_C -#define STORAGE_CLASS_ISP_OP2W_DATA_C const -#else /* INLINE_ISP_OP2W */ -#define STORAGE_CLASS_ISP_OP2W_FUNC_C STORAGE_CLASS_ISP_OP2W_FUNC_H -#define STORAGE_CLASS_ISP_OP2W_DATA_C STORAGE_CLASS_ISP_OP2W_DATA_H -#include "isp_op2w.c" -#define ISP_OP2W_INLINED -#endif /* INLINE_ISP_OP2W */ - -#endif /* __ISP_OP2W_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h deleted file mode 100644 index 7e86083a8a33..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_OP2W_TYPES_H_INCLUDED__ -#define __ISP_OP2W_TYPES_H_INCLUDED__ - -/* - * This file is part of the Multi-precision vector operations exstension package. - */ - -/* - * Double-precision vector operations - */ - -/* - * Prerequisites: - * - */ -#include "mpmath.h" -#include "isp_op1w_types.h" - -/* - * Single-precision data type specification - */ - - -typedef mpsdata_t tvector2w; -typedef mpsdata_t tscalar2w; -typedef mpsdata_t tvector2w_signed_positive; -typedef mpudata_t tvector2w_unsigned; - - -typedef struct { - tvector2w d; - tflags f; -} tvector2w_tflags; - -#endif /* __ISP_OP2W_TYPES_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h deleted file mode 100644 index 8e7b48d026b0..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __ISP_OP_COUNT_H_INCLUDED__ -#define __ISP_OP_COUNT_H_INCLUDED__ - -#include <stdio.h> - -typedef struct { - long long bbb_cnt; /* number of bbb */ - int bbb_op; /* operations per bbb */ - long long total_cnt; /* bbb_cnt * bbb_op */ -} bbb_stat_t; - -typedef enum { - bbb_func_OP_1w_and, - bbb_func_OP_1w_or, - bbb_func_OP_1w_xor, - bbb_func_OP_1w_inv, - bbb_func_OP_1w_add, - bbb_func_OP_1w_sub, - bbb_func_OP_1w_addsat, - bbb_func_OP_1w_subsat, - bbb_func_OP_1w_subasr1, - bbb_func_OP_1w_subhalf, - bbb_func_OP_1w_subhalfrnd, - bbb_func_OP_1w_abs, - bbb_func_OP_1w_subabssat, -#ifdef ISP2401 - bbb_func_OP_1w_subsat_u, -#endif - bbb_func_OP_1w_muld, - bbb_func_OP_1w_mul, - bbb_func_OP_1w_qmul, - bbb_func_OP_1w_qrmul, - bbb_func_OP_1w_eq, - bbb_func_OP_1w_ne, - bbb_func_OP_1w_le, - bbb_func_OP_1w_lt, - bbb_func_OP_1w_ge, - bbb_func_OP_1w_gt, - bbb_func_OP_1w_asr, - bbb_func_OP_1w_asrrnd, - bbb_func_OP_1w_asl, - bbb_func_OP_1w_aslsat, - bbb_func_OP_1w_lsl, - bbb_func_OP_1w_lsr, -#ifdef ISP2401 - bbb_func_OP_1w_ashift, - bbb_func_OP_1w_lshift, -#endif - bbb_func_OP_int_cast_to_1w , - bbb_func_OP_1w_cast_to_int , - bbb_func_OP_1w_cast_to_2w , - bbb_func_OP_2w_cast_to_1w , - bbb_func_OP_2w_sat_cast_to_1w , - bbb_func_OP_1w_clip_asym, - bbb_func_OP_1w_clipz, - bbb_func_OP_1w_div, - bbb_func_OP_1w_qdiv, - bbb_func_OP_1w_mod, - bbb_func_OP_1w_sqrt_u, - bbb_func_OP_1w_mux, - bbb_func_OP_1w_avg, - bbb_func_OP_1w_avgrnd, - bbb_func_OP_1w_min, - bbb_func_OP_1w_max, - bbb_func_OP_2w_and, - bbb_func_OP_2w_or, - bbb_func_OP_2w_xor, - bbb_func_OP_2w_inv, - bbb_func_OP_2w_add, - bbb_func_OP_2w_sub, - bbb_func_OP_2w_addsat, - bbb_func_OP_2w_subsat, - bbb_func_OP_2w_subasr1, - bbb_func_OP_2w_subhalf, - bbb_func_OP_2w_subhalfrnd, - bbb_func_OP_2w_abs, - bbb_func_OP_2w_subabssat, - bbb_func_OP_2w_mul, - bbb_func_OP_2w_qmul, - bbb_func_OP_2w_qrmul, - bbb_func_OP_2w_eq, - bbb_func_OP_2w_ne, - bbb_func_OP_2w_le, - bbb_func_OP_2w_lt, - bbb_func_OP_2w_ge, - bbb_func_OP_2w_gt, - bbb_func_OP_2w_asr, - bbb_func_OP_2w_asrrnd, - bbb_func_OP_2w_asl, - bbb_func_OP_2w_aslsat, - bbb_func_OP_2w_lsl, - bbb_func_OP_2w_lsr, - bbb_func_OP_2w_clip_asym, - bbb_func_OP_2w_clipz, - bbb_func_OP_2w_div, - bbb_func_OP_2w_divh, - bbb_func_OP_2w_mod, - bbb_func_OP_2w_sqrt_u, - bbb_func_OP_2w_mux, - bbb_func_OP_2w_avg, - bbb_func_OP_2w_avgrnd, - bbb_func_OP_2w_min, - bbb_func_OP_2w_max, - bbb_func_OP_1w_mul_realigning, -#ifdef ISP2401 - bbb_func_OP_1w_imax32, - bbb_func_OP_1w_imaxidx32, - bbb_func_OP_1w_cond_add, -#endif - - bbb_func_num_functions -} bbb_functions_t; - -typedef enum { - core_func_OP_and, - core_func_OP_or, - core_func_OP_xor, - core_func_OP_inv, - core_func_OP_add, - core_func_OP_sub, - core_func_OP_addsat, - core_func_OP_subsat, - core_func_OP_subasr1, - core_func_OP_abs, - core_func_OP_subabssat, -#ifdef ISP2401 - core_func_OP_subsat_u, -#endif - core_func_OP_muld, - core_func_OP_mul, - core_func_OP_qrmul, - core_func_OP_eq, - core_func_OP_ne, - core_func_OP_le, - core_func_OP_lt, - core_func_OP_ge, - core_func_OP_gt, - core_func_OP_asr, - core_func_OP_asl, - core_func_OP_asrrnd, - core_func_OP_lsl, - core_func_OP_lslsat, - core_func_OP_lsr, - core_func_OP_lsrrnd, - core_func_OP_clip_asym, - core_func_OP_clipz, - core_func_OP_div, - core_func_OP_mod, - core_func_OP_sqrt, - core_func_OP_mux, - core_func_OP_avgrnd, - core_func_OP_min, - core_func_OP_max, - - core_func_num_functions - -} core_functions_t; - -/* inc_bbb_count() can be used for building blocks that are implemented with one operation - inc_bbb_count_ext() will be used in case the operation count is not known or greater than one. - - For some operations there is a difference in operation count for the cloned version and the - not cloned version. this difference is not vissible on the reference code side. - We could add a min and max operation count for those operations, and keep track of those counts - separately. That way in the report the impact can be seen. */ - -#ifdef DISABLE_OPCNT -#define inc_bbb_count(func) -#define inc_bbb_count_ext(func, cnt) -#define enable_bbb_count() -#define disable_bbb_count() -#else -#define inc_bbb_count(func) _inc_bbb_count(func) -#define inc_bbb_count_ext(func, cnt) _inc_bbb_count_ext(func, cnt) -#define enable_bbb_count() _enable_bbb_count() -#define disable_bbb_count() _disable_bbb_count() -#endif - -void -inc_core_count_n( - core_functions_t func, - unsigned n); - -void -_enable_bbb_count(void); - -void -_disable_bbb_count(void); - -void -_inc_bbb_count( - bbb_functions_t func); - -void -_inc_bbb_count_ext( - bbb_functions_t func, - int op_count); - -void -bbb_func_reset_count(void); - -void -bbb_func_print_totals( - FILE * fp, - unsigned non_zero_only); - -void -core_func_print_totals( - FILE* fp, - unsigned non_zero_only); - -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h deleted file mode 100644 index 8695e3c01fa6..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __OSYS_PUBLIC_H_INCLUDED__ -#define __OSYS_PUBLIC_H_INCLUDED__ - -#include "system_types.h" - -#endif /* __OSYS_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h deleted file mode 100644 index 32cea582b4c4..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __PIPELINE_PUBLIC_H_INCLUDED__ -#define __PIPELINE_PUBLIC_H_INCLUDED__ - -#endif /* __PIPELINE_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h deleted file mode 100644 index c1638c06407d..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h +++ /dev/null @@ -1,1221 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _REF_VECTOR_FUNC_H_INCLUDED_ -#define _REF_VECTOR_FUNC_H_INCLUDED_ - - -#ifdef INLINE_VECTOR_FUNC -#define STORAGE_CLASS_REF_VECTOR_FUNC_H static inline -#define STORAGE_CLASS_REF_VECTOR_DATA_H static inline_DATA -#else /* INLINE_VECTOR_FUNC */ -#define STORAGE_CLASS_REF_VECTOR_FUNC_H extern -#define STORAGE_CLASS_REF_VECTOR_DATA_H extern_DATA -#endif /* INLINE_VECTOR_FUNC */ - - -#include "ref_vector_func_types.h" - -/* @brief Doubling multiply accumulate with saturation - * - * @param[in] acc accumulator - * @param[in] a multiply input - * @param[in] b multiply input - * - * @return acc + (a*b) - * - * This function will do a doubling multiply ont - * inputs a and b, and will add the result to acc. - * in case of an overflow of acc, it will saturate. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector2w OP_1w_maccd_sat( - tvector2w acc, - tvector1w a, - tvector1w b ); - -/* @brief Doubling multiply accumulate - * - * @param[in] acc accumulator - * @param[in] a multiply input - * @param[in] b multiply input - * - * @return acc + (a*b) - * - * This function will do a doubling multiply ont - * inputs a and b, and will add the result to acc. - * in case of overflow it will not saturate but wrap around. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector2w OP_1w_maccd( - tvector2w acc, - tvector1w a, - tvector1w b ); - -/* @brief Re-aligning multiply - * - * @param[in] a multiply input - * @param[in] b multiply input - * @param[in] shift shift amount - * - * @return (a*b)>>shift - * - * This function will multiply a with b, followed by a right - * shift with rounding. the result is saturated and casted - * to single precision. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_mul_realigning( - tvector1w a, - tvector1w b, - tscalar1w shift ); - -/* @brief Leading bit index - * - * @param[in] a input - * - * @return index of the leading bit of each element - * - * This function finds the index of leading one (set) bit of the - * input. The index starts with 0 for the LSB and can go upto - * ISP_VEC_ELEMBITS-1 for the MSB. For an input equal to zero, - * the returned index is -1. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_lod( - tvector1w a); - -/* @brief Config Unit Input Processing - * - * @param[in] a input - * @param[in] input_scale input scaling factor - * @param[in] input_offset input offset factor - * - * @return scaled & offset added input clamped to MAXVALUE - * - * As part of input processing for piecewise linear estimation config unit, - * this function will perform scaling followed by adding offset and - * then clamping to the MAX InputValue - * It asserts -MAX_SHIFT_1W <= input_scale <= MAX_SHIFT_1W, and - * -MAX_SHIFT_1W <= input_offset <= MAX_SHIFT_1W - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_input_scaling_offset_clamping( - tvector1w a, - tscalar1w_5bit_signed input_scale, - tscalar1w_5bit_signed input_offset); - -/* @brief Config Unit Output Processing - * - * @param[in] a output - * @param[in] output_scale output scaling factor - * - * @return scaled & clamped output value - * - * As part of output processing for piecewise linear estimation config unit, - * This function will perform scaling and then clamping to output - * MAX value. - * It asserts -MAX_SHIFT_1W <= output_scale <= MAX_SHIFT_1W - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_output_scaling_clamping( - tvector1w a, - tscalar1w_5bit_signed output_scale); - -/* @brief Config Unit Piecewiselinear estimation - * - * @param[in] a input - * @param[in] config_points config parameter structure - * - * @return piecewise linear estimated output - * - * Given a set of N points {(x1,y1),()x2,y2), ....,(xn,yn)}, to find - * the functional value at an arbitrary point around the input set, - * this function will perform input processing followed by piecewise - * linear estimation and then output processing to yield the final value. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_piecewise_estimation( - tvector1w a, - ref_config_points config_points); - -/* @brief Fast Config Unit - * - * @param[in] x input - * @param[in] init_vectors LUT data structure - * - * @return piecewise linear estimated output - * This block gets an input x and a set of input configuration points stored in a look-up - * table of 32 elements. First, the x input is clipped to be within the range [x1, xn+1]. - * Then, it computes the interval in which the input lies. Finally, the output is computed - * by performing linear interpolation based on the interval properties (i.e. x_prev, slope, - * and offset). This block assumes that the points are equally spaced and that the interval - * size is a power of 2. - **/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_XCU( - tvector1w x, - xcu_ref_init_vectors init_vectors); - - -/* @brief LXCU - * - * @param[in] x input - * @param[in] init_vectors LUT data structure - * - * @return logarithmic piecewise linear estimated output. - * This block gets an input x and a set of input configuration points stored in a look-up - * table of 32 elements. It computes the interval in which the input lies. - * Then output is computed by performing linear interpolation based on the interval - * properties (i.e. x_prev, slope, * and offset). - * This BBB assumes spacing x-coordinates of "init vectors" increase exponentially as - * shown below. - * interval size : 2^0 2^1 2^2 2^3 - * x-coordinates: x0<--->x1<---->x2<---->x3<----> - **/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_LXCU( - tvector1w x, - xcu_ref_init_vectors init_vectors); - -/* @brief Coring - * - * @param[in] coring_vec Amount of coring based on brightness level - * @param[in] filt_input Vector of input pixels on which Coring is applied - * @param[in] m_CnrCoring0 Coring Level0 - * - * @return vector of filtered pixels after coring is applied - * - * This function will perform adaptive coring based on brightness level to - * remove noise - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w coring( - tvector1w coring_vec, - tvector1w filt_input, - tscalar1w m_CnrCoring0 ); - -/* @brief Normalised FIR with coefficients [3,4,1] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [3,4,1], - *-5dB at Fs/2, -90 degree phase shift (quarter pixel) - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_5dB_m90_nrm ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [1,4,3] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1,4,3], - *-5dB at Fs/2, +90 degree phase shift (quarter pixel) - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_5dB_p90_nrm ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [1,2,1] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1,2,1], -6dB at Fs/2 - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [13,16,3] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [13,16,3], - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph0 ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [9,16,7] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [9,16,7], - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph1 ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [5,16,11] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [5,16,11], - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph2 ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with coefficients [1,16,15] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1,16,15], - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph3 ( - const s_1w_1x3_matrix m); - -/* @brief Normalised FIR with programable phase shift - * - * @param[in] m 1x3 matrix with pixels - * @param[in] coeff phase shift - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [8-coeff,16,8+coeff], - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_calc_coeff ( - const s_1w_1x3_matrix m, tscalar1w_3bit coeff); - -/* @brief 3 tap FIR with coefficients [1,1,1] - * - * @param[in] m 1x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * FIR with coefficients [1,1,1], -9dB at Fs/2 normalized with factor 1/2 - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_9dB_nrm ( - const s_1w_1x3_matrix m); - -#ifdef ISP2401 -/* @brief symmetric 3 tap FIR acts as LPF or BSF - * - * @param[in] m 1x3 matrix with pixels - * @param[in] k filter coefficient shift - * @param[in] bsf_flag 1 for BSF and 0 for LPF - * - * @return filtered output - * - * This function performs variable coefficient symmetric 3 tap filter which can - * be either used as Low Pass Filter or Band Stop Filter. - * Symmetric 3tap tap filter with DC gain 1 has filter coefficients [a, 1-2a, a] - * For LPF 'a' can be approximated as (1 - 2^(-k))/4, k = 0, 1, 2, ... - * and filter output can be approximated as: - * out_LPF = ((v00 + v02) - ((v00 + v02) >> k) + (2 * (v01 + (v01 >> k)))) >> 2 - * For BSF 'a' can be approximated as (1 + 2^(-k))/4, k = 0, 1, 2, ... - * and filter output can be approximated as: - * out_BSF = ((v00 + v02) + ((v00 + v02) >> k) + (2 * (v01 - (v01 >> k)))) >> 2 - * For a given filter coefficient shift 'k' and bsf_flag this function - * behaves either as LPF or BSF. - * All computation is done using 1w arithmetic and implementation does not use - * any multiplication. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -sym_fir1x3m_lpf_bsf(s_1w_1x3_matrix m, - tscalar1w k, - tscalar_bool bsf_flag); -#endif - -/* @brief Normalised 2D FIR with coefficients [1;2;1] * [1,2,1] - * - * @param[in] m 3x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1;2;1] * [1,2,1] - * Unity gain filter through repeated scaling and rounding - * - 6 rotate operations per output - * - 8 vector operations per output - * _______ - * 14 total operations - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir3x3m_6dB_nrm ( - const s_1w_3x3_matrix m); - -/* @brief Normalised 2D FIR with coefficients [1;1;1] * [1,1,1] - * - * @param[in] m 3x3 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1;1;1] * [1,1,1] - * - * (near) Unity gain filter through repeated scaling and rounding - * - 6 rotate operations per output - * - 8 vector operations per output - * _______ - * 14 operations - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir3x3m_9dB_nrm ( - const s_1w_3x3_matrix m); - -/* @brief Normalised dual output 2D FIR with coefficients [1;2;1] * [1,2,1] - * - * @param[in] m 4x3 matrix with pixels - * - * @return two filtered outputs (2x1 matrix) - * - * This function will calculate the - * Normalised FIR with coefficients [1;2;1] * [1,2,1] - * and produce two outputs (vertical) - * Unity gain filter through repeated scaling and rounding - * compute two outputs per call to re-use common intermediates - * - 4 rotate operations per output - * - 6 vector operations per output (alternative possible, but in this - * form it's not obvious to re-use variables) - * _______ - * 10 total operations - */ - STORAGE_CLASS_REF_VECTOR_FUNC_H s_1w_2x1_matrix fir3x3m_6dB_out2x1_nrm ( - const s_1w_4x3_matrix m); - -/* @brief Normalised dual output 2D FIR with coefficients [1;1;1] * [1,1,1] - * - * @param[in] m 4x3 matrix with pixels - * - * @return two filtered outputs (2x1 matrix) - * - * This function will calculate the - * Normalised FIR with coefficients [1;1;1] * [1,1,1] - * and produce two outputs (vertical) - * (near) Unity gain filter through repeated scaling and rounding - * compute two outputs per call to re-use common intermediates - * - 4 rotate operations per output - * - 7 vector operations per output (alternative possible, but in this - * form it's not obvious to re-use variables) - * _______ - * 11 total operations - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H s_1w_2x1_matrix fir3x3m_9dB_out2x1_nrm ( - const s_1w_4x3_matrix m); - -/* @brief Normalised 2D FIR 5x5 - * - * @param[in] m 5x5 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1;1;1] * [1;2;1] * [1,2,1] * [1,1,1] - * and produce a filtered output - * (near) Unity gain filter through repeated scaling and rounding - * - 20 rotate operations per output - * - 28 vector operations per output - * _______ - * 48 total operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir5x5m_15dB_nrm ( - const s_1w_5x5_matrix m); - -/* @brief Normalised FIR 1x5 - * - * @param[in] m 1x5 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1,2,1] * [1,1,1] = [1,4,6,4,1] - * and produce a filtered output - * (near) Unity gain filter through repeated scaling and rounding - * - 4 rotate operations per output - * - 5 vector operations per output - * _______ - * 9 total operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x5m_12dB_nrm ( - const s_1w_1x5_matrix m); - -/* @brief Normalised 2D FIR 5x5 - * - * @param[in] m 5x5 matrix with pixels - * - * @return filtered output - * - * This function will calculate the - * Normalised FIR with coefficients [1;2;1] * [1;2;1] * [1,2,1] * [1,2,1] - * and produce a filtered output - * (near) Unity gain filter through repeated scaling and rounding - * - 20 rotate operations per output - * - 30 vector operations per output - * _______ - * 50 total operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir5x5m_12dB_nrm ( - const s_1w_5x5_matrix m); - -/* @brief Approximate averaging FIR 1x5 - * - * @param[in] m 1x5 matrix with pixels - * - * @return filtered output - * - * This function will produce filtered output by - * applying the filter coefficients (1/8) * [1,1,1,1,1] - * _______ - * 5 vector operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x5m_box ( - s_1w_1x5_matrix m); - -/* @brief Approximate averaging FIR 1x9 - * - * @param[in] m 1x9 matrix with pixels - * - * @return filtered output - * - * This function will produce filtered output by - * applying the filter coefficients (1/16) * [1,1,1,1,1,1,1,1,1] - * _______ - * 9 vector operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x9m_box ( - s_1w_1x9_matrix m); - -/* @brief Approximate averaging FIR 1x11 - * - * @param[in] m 1x11 matrix with pixels - * - * @return filtered output - * - * This function will produce filtered output by - * applying the filter coefficients (1/16) * [1,1,1,1,1,1,1,1,1,1,1] - * _______ - * 12 vector operations -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x11m_box ( - s_1w_1x11_matrix m); - -/* @brief Symmetric 7 tap filter with normalization - * - * @param[in] in 1x7 matrix with pixels - * @param[in] coeff 1x4 matrix with coefficients - * @param[in] out_shift output pixel shift value for normalization - * - * @return symmetric 7 tap filter output - * - * This function performs symmetric 7 tap filter over input pixels. - * Filter sum is normalized by shifting out_shift bits. - * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3 - * is implemented as: (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0 to - * reduce multiplication. - * Input pixels should to be scaled, otherwise overflow is possible during - * addition -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x7m_sym_nrm(s_1w_1x7_matrix in, - s_1w_1x4_matrix coeff, - tvector1w out_shift); - -/* @brief Symmetric 7 tap filter with normalization at input side - * - * @param[in] in 1x7 matrix with pixels - * @param[in] coeff 1x4 matrix with coefficients - * - * @return symmetric 7 tap filter output - * - * This function performs symmetric 7 tap filter over input pixels. - * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3 - * = (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0 - * Input pixels and coefficients are in Qn format, where n = - * ISP_VEC_ELEMBITS - 1 (ie Q15 for Broxton) - * To avoid double precision arithmetic input pixel sum and final sum is - * implemented using avgrnd and coefficient multiplication using qrmul. - * Final result is in Qm format where m = ISP_VEC_ELEMBITS - 2 (ie Q14 for - * Broxton) -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x7m_sym_innrm_approx(s_1w_1x7_matrix in, - s_1w_1x4_matrix coeff); - -/* @brief Symmetric 7 tap filter with normalization at output side - * - * @param[in] in 1x7 matrix with pixels - * @param[in] coeff 1x4 matrix with coefficients - * - * @return symmetric 7 tap filter output - * - * This function performs symmetric 7 tap filter over input pixels. - * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3 - * = (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0 - * Input pixels are in Qn and coefficients are in Qm format, where n = - * ISP_VEC_ELEMBITS - 2 and m = ISP_VEC_ELEMBITS - 1 (ie Q14 and Q15 - * respectively for Broxton) - * To avoid double precision arithmetic input pixel sum and final sum is - * implemented using addsat and coefficient multiplication using qrmul. - * Final sum is left shifted by 2 and saturated to produce result is Qm format - * (ie Q15 for Broxton) -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x7m_sym_outnrm_approx(s_1w_1x7_matrix in, - s_1w_1x4_matrix coeff); - -/* @brief 4 tap filter with normalization - * - * @param[in] in 1x4 matrix with pixels - * @param[in] coeff 1x4 matrix with coefficients - * @param[in] out_shift output pixel shift value for normalization - * - * @return 4 tap filter output - * - * This function performs 4 tap filter over input pixels. - * Filter sum is normalized by shifting out_shift bits. - * Filter sum: p0*c0 + p1*c1 + p2*c2 + p3*c3 -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x4m_nrm(s_1w_1x4_matrix in, - s_1w_1x4_matrix coeff, - tvector1w out_shift); - -/* @brief 4 tap filter with normalization for half pixel interpolation - * - * @param[in] in 1x4 matrix with pixels - * - * @return 4 tap filter output with filter tap [-1 9 9 -1]/16 - * - * This function performs 4 tap filter over input pixels. - * Filter sum: -p0 + 9*p1 + 9*p2 - p3 - * This filter implementation is completely free from multiplication and double - * precision arithmetic. - * Typical usage of this filter is to half pixel interpolation of Bezier - * surface - * */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x4m_bicubic_bezier_half(s_1w_1x4_matrix in); - -/* @brief 4 tap filter with normalization for quarter pixel interpolation - * - * @param[in] in 1x4 matrix with pixels - * @param[in] coeff 1x4 matrix with coefficients - * - * @return 4 tap filter output - * - * This function performs 4 tap filter over input pixels. - * Filter sum: p0*c0 + p1*c1 + p2*c2 + p3*c3 - * To avoid double precision arithmetic we implemented multiplication using - * qrmul and addition using avgrnd. Coefficients( c0 to c3) formats are assumed - * to be: Qm, Qn, Qo, Qm, where m = n + 2 and o = n + 1. - * Typical usage of this filter is to quarter pixel interpolation of Bezier - * surface with filter coefficients:[-9 111 29 -3]/128. For which coefficient - * values should be: [-9216/2^17 28416/2^15 1484/2^16 -3072/2^17] for - * ISP_VEC_ELEMBITS = 16. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x4m_bicubic_bezier_quarter(s_1w_1x4_matrix in, - s_1w_1x4_matrix coeff); - - -/* @brief Symmetric 3 tap filter with normalization - * - * @param[in] in 1x3 matrix with pixels - * @param[in] coeff 1x2 matrix with coefficients - * @param[in] out_shift output pixel shift value for normalization - * - * @return symmetric 3 tap filter output - * - * This function performs symmetric 3 tap filter input pixels. - * Filter sum is normalized by shifting out_shift bits. - * Filter sum: p0*c1 + p1*c0 + p2*c1 - * is implemented as: (p0 + p2)*c1 + p1*c0 to reduce multiplication. - * Input pixels should to be scaled, otherwise overflow is possible during - * addition -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x3m_sym_nrm(s_1w_1x3_matrix in, - s_1w_1x2_matrix coeff, - tvector1w out_shift); - -/* @brief Symmetric 3 tap filter with normalization - * - * @param[in] in 1x3 matrix with pixels - * @param[in] coeff 1x2 matrix with coefficients - * - * @return symmetric 3 tap filter output - * - * This function performs symmetric 3 tap filter over input pixels. - * Filter sum: p0*c1 + p1*c0 + p2*c1 = (p0 + p2)*c1 + p1*c0 - * Input pixels are in Qn and coefficient c0 is in Qm and c1 is in Qn format, - * where n = ISP_VEC_ELEMBITS - 1 and m = ISP_VEC_ELEMBITS - 2 ( ie Q15 and Q14 - * respectively for Broxton) - * To avoid double precision arithmetic input pixel sum is implemented using - * avgrnd, coefficient multiplication using qrmul and final sum using addsat - * Final sum is Qm format (ie Q14 for Broxton) -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -fir1x3m_sym_nrm_approx(s_1w_1x3_matrix in, - s_1w_1x2_matrix coeff); - -/* @brief Mean of 1x3 matrix - * - * @param[in] m 1x3 matrix with pixels - * - * @return mean of 1x3 matrix - * - * This function calculates the mean of 1x3 pixels, - * with a factor of 4/3. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x3m( - s_1w_1x3_matrix m); - -/* @brief Mean of 3x3 matrix - * - * @param[in] m 3x3 matrix with pixels - * - * @return mean of 3x3 matrix - * - * This function calculates the mean of 3x3 pixels, - * with a factor of 16/9. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean3x3m( - s_1w_3x3_matrix m); - -/* @brief Mean of 1x4 matrix - * - * @param[in] m 1x4 matrix with pixels - * - * @return mean of 1x4 matrix - * - * This function calculates the mean of 1x4 pixels -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x4m( - s_1w_1x4_matrix m); - -/* @brief Mean of 4x4 matrix - * - * @param[in] m 4x4 matrix with pixels - * - * @return mean of 4x4 matrix - * - * This function calculates the mean of 4x4 matrix with pixels -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean4x4m( - s_1w_4x4_matrix m); - -/* @brief Mean of 2x3 matrix - * - * @param[in] m 2x3 matrix with pixels - * - * @return mean of 2x3 matrix - * - * This function calculates the mean of 2x3 matrix with pixels - * with a factor of 8/6. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean2x3m( - s_1w_2x3_matrix m); - -/* @brief Mean of 1x5 matrix - * - * @param[in] m 1x5 matrix with pixels - * - * @return mean of 1x5 matrix - * - * This function calculates the mean of 1x5 matrix with pixels - * with a factor of 8/5. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x5m(s_1w_1x5_matrix m); - -/* @brief Mean of 1x6 matrix - * - * @param[in] m 1x6 matrix with pixels - * - * @return mean of 1x6 matrix - * - * This function calculates the mean of 1x6 matrix with pixels - * with a factor of 8/6. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x6m( - s_1w_1x6_matrix m); - -/* @brief Mean of 5x5 matrix - * - * @param[in] m 5x5 matrix with pixels - * - * @return mean of 5x5 matrix - * - * This function calculates the mean of 5x5 matrix with pixels - * with a factor of 32/25. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean5x5m( - s_1w_5x5_matrix m); - -/* @brief Mean of 6x6 matrix - * - * @param[in] m 6x6 matrix with pixels - * - * @return mean of 6x6 matrix - * - * This function calculates the mean of 6x6 matrix with pixels - * with a factor of 64/36. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean6x6m( - s_1w_6x6_matrix m); - -/* @brief Minimum of 4x4 matrix - * - * @param[in] m 4x4 matrix with pixels - * - * @return minimum of 4x4 matrix - * - * This function calculates the minimum of - * 4x4 matrix with pixels. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w min4x4m( - s_1w_4x4_matrix m); - -/* @brief Maximum of 4x4 matrix - * - * @param[in] m 4x4 matrix with pixels - * - * @return maximum of 4x4 matrix - * - * This function calculates the maximum of - * 4x4 matrix with pixels. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w max4x4m( - s_1w_4x4_matrix m); - -/* @brief SAD between two 3x3 matrices - * - * @param[in] a 3x3 matrix with pixels - * - * @param[in] b 3x3 matrix with pixels - * - * @return 3x3 matrix SAD - * - * This function calculates the sum of absolute difference between two matrices. - * Both input pixels and SAD are normalized by a factor of SAD3x3_IN_SHIFT and - * SAD3x3_OUT_SHIFT respectively. - * Computed SAD is 1/(2 ^ (SAD3x3_IN_SHIFT + SAD3x3_OUT_SHIFT)) ie 1/16 factor - * of original SAD and it's more precise than sad3x3m() -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad3x3m_precise( - s_1w_3x3_matrix a, - s_1w_3x3_matrix b); - -/* @brief SAD between two 3x3 matrices - * - * @param[in] a 3x3 matrix with pixels - * - * @param[in] b 3x3 matrix with pixels - * - * @return 3x3 matrix SAD - * - * This function calculates the sum of absolute difference between two matrices. - * This version saves cycles by avoiding input normalization and wide vector - * operation during sum computation - * Input pixel differences are computed by absolute of rounded, halved - * subtraction. Normalized sum is computed by rounded averages. - * Computed SAD is (1/2)*(1/16) = 1/32 factor of original SAD. Factor 1/2 comes - * from input halving operation and factor 1/16 comes from mean operation -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad3x3m( - s_1w_3x3_matrix a, - s_1w_3x3_matrix b); - -/* @brief SAD between two 5x5 matrices - * - * @param[in] a 5x5 matrix with pixels - * - * @param[in] b 5x5 matrix with pixels - * - * @return 5x5 matrix SAD - * - * Computed SAD is = 1/32 factor of original SAD. -*/ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad5x5m( - s_1w_5x5_matrix a, - s_1w_5x5_matrix b); - -/* @brief Absolute gradient between two sets of 1x5 matrices - * - * @param[in] m0 first set of 1x5 matrix with pixels - * @param[in] m1 second set of 1x5 matrix with pixels - * - * @return absolute gradient between two 1x5 matrices - * - * This function computes mean of two input 1x5 matrices and returns - * absolute difference between two mean values. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w -absgrad1x5m(s_1w_1x5_matrix m0, s_1w_1x5_matrix m1); - -/* @brief Bi-linear Interpolation optimized(approximate) - * - * @param[in] a input0 - * @param[in] b input1 - * @param[in] c cloned weight factor - * - * @return (a-b)*c + b - * - * This function will do bi-linear Interpolation on - * inputs a and b using constant weight factor c - * - * Inputs a,b are assumed in S1.15 format - * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format - * - * The bilinear interpolation equation is (a*c) + b*(1-c), - * But this is implemented as (a-b)*c + b for optimization - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol_approx_c( - tvector1w a, - tvector1w b, - tscalar1w_weight c); - -/* @brief Bi-linear Interpolation optimized(approximate) - * - * @param[in] a input0 - * @param[in] b input1 - * @param[in] c weight factor - * - * @return (a-b)*c + b - * - * This function will do bi-linear Interpolation on - * inputs a and b using weight factor c - * - * Inputs a,b are assumed in S1.15 format - * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format - * - * The bilinear interpolation equation is (a*c) + b*(1-c), - * But this is implemented as (a-b)*c + b for optimization - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol_approx( - tvector1w a, - tvector1w b, - tvector1w_weight c); - -/* @brief Bi-linear Interpolation - * - * @param[in] a input0 - * @param[in] b input1 - * @param[in] c weight factor - * - * @return (a*c) + b*(1-c) - * - * This function will do bi-linear Interpolation on - * inputs a and b using weight factor c - * - * Inputs a,b are assumed in S1.15 format - * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format - * - * The bilinear interpolation equation is (a*c) + b*(1-c), - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol( - tvector1w a, - tvector1w b, - tscalar1w_weight c); - -/* @brief Generic Block Matching Algorithm - * @param[in] search_window pointer to input search window of 16x16 pixels - * @param[in] ref_block pointer to input reference block of 8x8 pixels, where N<=M - * @param[in] output pointer to output sads - * @param[in] search_sz search size for SAD computation - * @param[in] ref_sz block size - * @param[in] pixel_shift pixel shift to search the data - * @param[in] search_block_sz search window block size - * @param[in] shift shift value, with which the output is shifted right - * - * @return 0 when the computation is successful. - - * * This function compares the reference block with a block of size NxN in the search - * window. Sum of absolute differences for each pixel in the reference block and the - * corresponding pixel in the search block. Whole search window os traversed with the - * reference block with the given pixel shift. - * - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H int generic_block_matching_algorithm( - tscalar1w **search_window, - tscalar1w **ref_block, - tscalar1w *output, - int search_sz, - int ref_sz, - int pixel_shift, - int search_block_sz, - tscalar1w_4bit_bma_shift shift); - -#ifndef ISP2401 -/* @brief OP_1w_asp_bma_16_1_32way -#else -/* @brief OP_1w_asp_bma_16_1_32way_nomask -#endif - * - * @param[in] search_area input search window of 16x16 pixels - * @param[in] input_block input reference block of 8x8 pixels, where N<=M - * @param[in] shift shift value, with which the output is shifted right - * - * @return 81 SADs for all the search blocks. - - * This function compares the reference block with a block of size 8x8 pixels in the - * search window of 16x16 pixels. Sum of absolute differences for each pixel in the - * reference block and the corresponding pixel in the search block is calculated. - * Whole search window is traversed with the reference block with the pixel shift of 1 - * pixels. The output is right shifted with the given shift value. The shift value is - * a 4 bit value. - * - */ - -#ifndef ISP2401 -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_1 OP_1w_asp_bma_16_1_32way( -#else -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_1 OP_1w_asp_bma_16_1_32way_nomask( -#endif - bma_16x16_search_window search_area, - ref_block_8x8 input_block, - tscalar1w_4bit_bma_shift shift); - -#ifndef ISP2401 -/* @brief OP_1w_asp_bma_16_2_32way -#else -/* @brief OP_1w_asp_bma_16_2_32way_nomask -#endif - * - * @param[in] search_area input search window of 16x16 pixels - * @param[in] input_block input reference block of 8x8 pixels, where N<=M - * @param[in] shift shift value, with which the output is shifted right - * - * @return 25 SADs for all the search blocks. - * This function compares the reference block with a block of size 8x8 in the search - * window of 16x61. Sum of absolute differences for each pixel in the reference block - * and the corresponding pixel in the search block is computed. Whole search window is - * traversed with the reference block with the given pixel shift of 2 pixels. The output - * is right shifted with the given shift value. The shift value is a 4 bit value. - * - */ - -#ifndef ISP2401 -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_2 OP_1w_asp_bma_16_2_32way( -#else -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_2 OP_1w_asp_bma_16_2_32way_nomask( -#endif - bma_16x16_search_window search_area, - ref_block_8x8 input_block, - tscalar1w_4bit_bma_shift shift); -#ifndef ISP2401 -/* @brief OP_1w_asp_bma_14_1_32way -#else -/* @brief OP_1w_asp_bma_14_1_32way_nomask -#endif - * - * @param[in] search_area input search block of 16x16 pixels with search window of 14x14 pixels - * @param[in] input_block input reference block of 8x8 pixels, where N<=M - * @param[in] shift shift value, with which the output is shifted right - * - * @return 49 SADs for all the search blocks. - * This function compares the reference block with a block of size 8x8 in the search - * window of 14x14. Sum of absolute differences for each pixel in the reference block - * and the corresponding pixel in the search block. Whole search window is traversed - * with the reference block with 2 pixel shift. The output is right shifted with the - * given shift value. The shift value is a 4 bit value. Input is always a 16x16 block - * but the search window is 14x14, with last 2 pixels of row and column are not used - * for computation. - * - */ - -#ifndef ISP2401 -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_1 OP_1w_asp_bma_14_1_32way( -#else -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_1 OP_1w_asp_bma_14_1_32way_nomask( -#endif - bma_16x16_search_window search_area, - ref_block_8x8 input_block, - tscalar1w_4bit_bma_shift shift); - -#ifndef ISP2401 -/* @brief OP_1w_asp_bma_14_2_32way -#else -/* @brief OP_1w_asp_bma_14_2_32way_nomask -#endif - * - * @param[in] search_area input search block of 16x16 pixels with search window of 14x14 pixels - * @param[in] input_block input reference block of 8x8 pixels, where N<=M - * @param[in] shift shift value, with which the output is shifted right - * - * @return 16 SADs for all the search blocks. - * This function compares the reference block with a block of size 8x8 in the search - * window of 14x14. Sum of absolute differences for each pixel in the reference block - * and the corresponding pixel in the search block. Whole search window is traversed - * with the reference block with 2 pixels shift. The output is right shifted with the - * given shift value. The shift value is a 4 bit value. - * - */ - -#ifndef ISP2401 -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_2 OP_1w_asp_bma_14_2_32way( -#else -STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_2 OP_1w_asp_bma_14_2_32way_nomask( -#endif - bma_16x16_search_window search_area, - ref_block_8x8 input_block, - tscalar1w_4bit_bma_shift shift); - -#ifdef ISP2401 -/* @brief multiplex addition and passing - * - * @param[in] _a first pixel - * @param[in] _b second pixel - * @param[in] _c condition flag - * - * @return (_a + _b) if condition flag is true - * _a if condition flag is false - * - * This function does multiplex addition depending on the input condition flag - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_cond_add( - tvector1w _a, - tvector1w _b, - tflags _c); - -#endif -#ifdef HAS_bfa_unit -/* @brief OP_1w_single_bfa_7x7 - * - * @param[in] weights - spatial and range weight lut - * @param[in] threshold - threshold plane, for range weight scaling - * @param[in] central_pix - central pixel plane - * @param[in] src_plane - src pixel plane - * - * @return Bilateral filter output - * - * This function implements, 7x7 single bilateral filter. - * Output = {sum(pixel * weight), sum(weight)} - * Where sum is summation over 7x7 block set. - * weight = spatial weight * range weight - * spatial weights are loaded from spatial_weight_lut depending on src pixel - * position in the 7x7 block - * range weights are computed by table look up from range_weight_lut depending - * on scaled absolute difference between src and central pixels. - * threshold is used as scaling factor. range_weight_lut consists of - * BFA_RW_LUT_SIZE numbers of LUT entries to model any distribution function. - * Piecewise linear approximation technique is used to compute range weight - * It computes absolute difference between central pixel and 61 src pixels. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H bfa_7x7_output OP_1w_single_bfa_7x7( - bfa_weights weights, - tvector1w threshold, - tvector1w central_pix, - s_1w_7x7_matrix src_plane); - -/* @brief OP_1w_joint_bfa_7x7 - * - * @param[in] weights - spatial and range weight lut - * @param[in] threshold0 - 1st threshold plane, for range weight scaling - * @param[in] central_pix0 - 1st central pixel plane - * @param[in] src0_plane - 1st pixel plane - * @param[in] threshold1 - 2nd threshold plane, for range weight scaling - * @param[in] central_pix1 - 2nd central pixel plane - * @param[in] src1_plane - 2nd pixel plane - * - * @return Joint bilateral filter output - * - * This function implements, 7x7 joint bilateral filter. - * Output = {sum(pixel * weight), sum(weight)} - * Where sum is summation over 7x7 block set. - * weight = spatial weight * range weight - * spatial weights are loaded from spatial_weight_lut depending on src pixel - * position in the 7x7 block - * range weights are computed by table look up from range_weight_lut depending - * on sum of scaled absolute difference between central pixel and two src pixel - * planes. threshold is used as scaling factor. range_weight_lut consists of - * BFA_RW_LUT_SIZE numbers of LUT entries to model any distribution function. - * Piecewise linear approximation technique is used to compute range weight - * It computes absolute difference between central pixel and 61 src pixels. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H bfa_7x7_output OP_1w_joint_bfa_7x7( - bfa_weights weights, - tvector1w threshold0, - tvector1w central_pix0, - s_1w_7x7_matrix src0_plane, - tvector1w threshold1, - tvector1w central_pix1, - s_1w_7x7_matrix src1_plane); - -/* @brief bbb_bfa_gen_spatial_weight_lut - * - * @param[in] in - 7x7 matrix of spatial weights - * @param[in] out - generated LUT - * - * @return None - * - * This function implements, creates spatial weight look up table used - * for bilaterl filter instruction. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H void bbb_bfa_gen_spatial_weight_lut( - s_1w_7x7_matrix in, - tvector1w out[BFA_MAX_KWAY]); - -/* @brief bbb_bfa_gen_range_weight_lut - * - * @param[in] in - input range weight, - * @param[in] out - generated LUT - * - * @return None - * - * This function implements, creates range weight look up table used - * for bilaterl filter instruction. - * 8 unsigned 7b weights are represented in 7 16bits LUT - * LUT formation is done as follows: - * higher 8 bit: Point(N) = Point(N+1) - Point(N) - * lower 8 bit: Point(N) = Point(N) - * Weight function can be any monotonic decreasing function for x >= 0 - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H void bbb_bfa_gen_range_weight_lut( - tvector1w in[BFA_RW_LUT_SIZE+1], - tvector1w out[BFA_RW_LUT_SIZE]); -#endif - -#ifdef ISP2401 -/* @brief OP_1w_imax32 - * - * @param[in] src - structure that holds an array of 32 elements. - * - * @return maximum element among input array. - * - *This function gets maximum element from an array of 32 elements. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H int OP_1w_imax32( - imax32_ref_in_vector src); - -/* @brief OP_1w_imaxidx32 - * - * @param[in] src - structure that holds a vector of elements. - * - * @return index of first element with maximum value among array. - * - * This function gets index of first element with maximum value - * from 32 elements. - */ -STORAGE_CLASS_REF_VECTOR_FUNC_H int OP_1w_imaxidx32( - imax32_ref_in_vector src); - -#endif -#ifndef INLINE_VECTOR_FUNC -#define STORAGE_CLASS_REF_VECTOR_FUNC_C -#define STORAGE_CLASS_REF_VECTOR_DATA_C const -#else /* INLINE_VECTOR_FUNC */ -#define STORAGE_CLASS_REF_VECTOR_FUNC_C STORAGE_CLASS_REF_VECTOR_FUNC_H -#define STORAGE_CLASS_REF_VECTOR_DATA_C STORAGE_CLASS_REF_VECTOR_DATA_H -#include "ref_vector_func.c" -#define VECTOR_FUNC_INLINED -#endif /* INLINE_VECTOR_FUNC */ - -#endif /*_REF_VECTOR_FUNC_H_INCLUDED_*/ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h deleted file mode 100644 index 4dd05eba852e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __REF_VECTOR_FUNC_TYPES_H_INCLUDED__ -#define __REF_VECTOR_FUNC_TYPES_H_INCLUDED__ - - -/* - * Prerequisites: - * - */ -#include "mpmath.h" -#include "bbb_config.h" -#include "isp_op1w_types.h" -#include "isp_op2w_types.h" - -/* Defines for the Config Unit */ -#define MAX_CONFIG_POINTS 5 -#define INPUT_OFFSET_FACTOR 10 -#define INPUT_SCALE_FACTOR 10 -#define OUTPUT_SCALE_FACTOR 10 -#define SLOPE_A_RESOLUTION 10 -#define CONFIG_UNIT_LUT_SIZE_32 32 /*XCU works for ISP_NWAY = 32 */ -#define LXCU_LUT_SIZE 16 -#ifdef ISP2401 -#define IMAX32_ELEM_SIZE 32 -#endif - -#define ONE_IN_Q14 (1<<(NUM_BITS-2)) -#define Q29_TO_Q15_SHIFT_VAL (NUM_BITS-2) -#define Q28_TO_Q15_SHIFT_VAL (NUM_BITS-3) -#define MAX_ELEM(width_in_bits) ((1<<(width_in_bits))-1) - -/* Block matching algorithm related data */ -/* NUM_OF_SADS = ((SEARCH_AREA_HEIGHT - REF_BLOCK_HEIGHT)/PIXEL_SHIFT + 1)* \ - ((SEARCH_AREA_WIDTH - REF_BLOCK_WIDTH)/PIXEL_SHIFT + 1) */ - -#define SADS(sw_h,sw_w, ref_h, ref_w, p_sh) (((sw_h - ref_h)/p_sh + 1)*((sw_w - ref_w)/p_sh + 1)) -#define SADS_16x16_1 SADS(16, 16, 8, 8, 1) -#define SADS_16x16_2 SADS(16, 16, 8, 8, 2) -#define SADS_14x14_1 SADS(14, 14, 8, 8, 1) -#define SADS_14x14_2 SADS(14, 14, 8, 8, 2) - -#define BMA_OUTPUT_MATRIX_DIM(sw_h, ref_h, p_sh) ((sw_h - ref_h)/p_sh + 1) -#define BMA_OUT_16x16_2_32 BMA_OUTPUT_MATRIX_DIM(16, 8, 2) -#define BMA_OUT_14x14_2_32 BMA_OUTPUT_MATRIX_DIM(14, 8, 2) -#define BMA_OUT_16x16_1_32 BMA_OUTPUT_MATRIX_DIM(16, 8, 1) -#define BMA_OUT_14x14_1_32 BMA_OUTPUT_MATRIX_DIM(14, 8, 1) -#define BMA_SEARCH_BLOCK_SZ_16 16 -#define BMA_REF_BLOCK_SZ_8 8 -#define PIXEL_SHIFT_2 2 -#define PIXEL_SHIFT_1 1 -#define BMA_SEARCH_WIN_SZ_16 16 -#define BMA_SEARCH_WIN_SZ_14 14 - - -/* - * Struct type specification - */ - -typedef unsigned short tscalar1w_3bit; /* tscalar1w in interval [0, 2^3) */ -typedef short tscalar1w_5bit_signed; /* tscalar1w in interval [-2^(5-1), 2^(5-1)) */ -typedef unsigned short tscalar1w_5bit; /* tscalar1w in interval [0, 2^5) */ -typedef short tscalar1w_range1wbit; /* tscalar1w in interval [-NUM_BITS, NUM_BITS] */ -typedef short tscalar1w_unsigned_range1wbit; /* tscalar1w in interval [0, NUM_BITS] */ -typedef unsigned short tvector_8bit; /* 8 bit positive number */ -typedef unsigned short tvector_5bit; -typedef unsigned short tvector_4bit; -typedef unsigned short tscalar1w_16bit; -typedef unsigned short tscalar1w_4bit_bma_shift; - -typedef struct { - tvector1w v0 ; - tvector1w v1 ; -} s_1w_2x1_matrix; - -#define S_1W_2X1_MATRIX_DEFAULT ((s_1w_2x1_matrix)\ - { 0, 0 }) - -typedef struct { - tvector1w v00; - tvector1w v01; -} s_1w_1x2_matrix; - -#define S_1W_1X2_MATRIX_DEFAULT ((s_1w_1x2_matrix)\ - { 0, 0 }) - -typedef struct { - tvector1w v00 ; - tvector1w v01 ; - tvector1w v02 ; -} s_1w_1x3_matrix; - -#define S_1W_1X3_MATRIX_DEFAULT ((s_1w_1x3_matrix)\ - { 0, 0, 0, }) - -typedef struct { - tvector1w v00; tvector1w v01; tvector1w v02; - tvector1w v10; tvector1w v11; tvector1w v12; -} s_1w_2x3_matrix; - -#define S_1W_2X3_MATRIX_DEFAULT ((s_1w_2x3_matrix)\ - { 0, 0, 0, \ - 0, 0, 0 }) - -typedef struct { - tvector1w v00 ; tvector1w v01 ; tvector1w v02 ; - tvector1w v10 ; tvector1w v11 ; tvector1w v12 ; - tvector1w v20 ; tvector1w v21 ; tvector1w v22 ; -} s_1w_3x3_matrix; - -#define S_1W_3X3_MATRIX_DEFAULT ((s_1w_3x3_matrix)\ - { 0, 0, 0, \ - 0, 0, 0, \ - 0, 0, 0 }) - -typedef struct { - tvector1w v00 ; tvector1w v01 ; tvector1w v02 ; - tvector1w v10 ; tvector1w v11 ; tvector1w v12 ; - tvector1w v20 ; tvector1w v21 ; tvector1w v22 ; - tvector1w v30 ; tvector1w v31 ; tvector1w v32 ; -} s_1w_4x3_matrix; - -#define S_1W_4X3_MATRIX_DEFAULT ((s_1w_4x3_matrix)\ - { 0, 0, 0, \ - 0, 0, 0, \ - 0, 0, 0, \ - 0, 0, 0 }) - -typedef struct { - tvector1w v00 ; - tvector1w v01 ; - tvector1w v02 ; - tvector1w v03 ; - tvector1w v04 ; -} s_1w_1x5_matrix; - -#define S_1W_1X5_MATRIX_DEFAULT ((s_1w_1x5_matrix)\ - { 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00 ; tvector1w v01 ; tvector1w v02 ; tvector1w v03 ; tvector1w v04 ; - tvector1w v10 ; tvector1w v11 ; tvector1w v12 ; tvector1w v13 ; tvector1w v14 ; - tvector1w v20 ; tvector1w v21 ; tvector1w v22 ; tvector1w v23 ; tvector1w v24 ; - tvector1w v30 ; tvector1w v31 ; tvector1w v32 ; tvector1w v33 ; tvector1w v34 ; - tvector1w v40 ; tvector1w v41 ; tvector1w v42 ; tvector1w v43 ; tvector1w v44 ; -} s_1w_5x5_matrix; - -#define S_1W_5X5_MATRIX_DEFAULT ((s_1w_5x5_matrix)\ - { 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0 }) -#ifndef ISP2401 - -#else - -#endif -typedef struct { - tvector1w v00; - tvector1w v01; - tvector1w v02; - tvector1w v03; - tvector1w v04; - tvector1w v05; - tvector1w v06; -} s_1w_1x7_matrix; - -#define S_1W_1X7_MATRIX_DEFAULT ((s_1w_1x7_matrix)\ - { 0, 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; - tvector1w v01; - tvector1w v02; - tvector1w v03; - tvector1w v04; - tvector1w v05; - tvector1w v06; - tvector1w v07; - tvector1w v08; -} s_1w_1x9_matrix; - -#define S_1W_1X9_MATRIX_DEFAULT ((s_1w_1x9_matrix)\ - { 0, 0, 0, 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; - tvector1w v01; - tvector1w v02; - tvector1w v03; -} s_1w_1x4_matrix; - -#define S_1W_1X4_MATRIX ((s_1w_1x4_matrix)\ - { 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; - tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; - tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; - tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; -} s_1w_4x4_matrix; - -#define S_1W_4X4_MATRIX_DEFAULT ((s_1w_4x4_matrix)\ - { 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; - tvector1w v01; - tvector1w v02; - tvector1w v03; - tvector1w v04; - tvector1w v05; -} s_1w_1x6_matrix; - -#define S_1W_1X6_MATRIX_DEFAULT ((s_1w_1x6_matrix)\ - { 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04; tvector1w v05; - tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14; tvector1w v15; - tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24; tvector1w v25; - tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34; tvector1w v35; - tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44; tvector1w v45; - tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54; tvector1w v55; -} s_1w_6x6_matrix; - -#define S_1W_6X6_MATRIX_DEFAULT ((s_1w_6x6_matrix)\ - { 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04; - tvector1w v05; tvector1w v06; tvector1w v07; tvector1w v08; - tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14; - tvector1w v15; tvector1w v16; tvector1w v17; tvector1w v18; - tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24; - tvector1w v25; tvector1w v26; tvector1w v27; tvector1w v28; - tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34; - tvector1w v35; tvector1w v36; tvector1w v37; tvector1w v38; - tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44; - tvector1w v45; tvector1w v46; tvector1w v47; tvector1w v48; - tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54; - tvector1w v55; tvector1w v56; tvector1w v57; tvector1w v58; - tvector1w v60; tvector1w v61; tvector1w v62; tvector1w v63; tvector1w v64; - tvector1w v65; tvector1w v66; tvector1w v67; tvector1w v68; - tvector1w v70; tvector1w v71; tvector1w v72; tvector1w v73; tvector1w v74; - tvector1w v75; tvector1w v76; tvector1w v77; tvector1w v78; - tvector1w v80; tvector1w v81; tvector1w v82; tvector1w v83; tvector1w v84; - tvector1w v85; tvector1w v86; tvector1w v87; tvector1w v88; -} s_1w_9x9_matrix; - -#define S_1W_9X9_MATRIX_DEFAULT ((s_1w_9x9_matrix)\ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04; - tvector1w v05; tvector1w v06; - tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14; - tvector1w v15; tvector1w v16; - tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24; - tvector1w v25; tvector1w v26; - tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34; - tvector1w v35; tvector1w v36; - tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44; - tvector1w v45; tvector1w v46; - tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54; - tvector1w v55; tvector1w v56; - tvector1w v60; tvector1w v61; tvector1w v62; tvector1w v63; tvector1w v64; - tvector1w v65; tvector1w v66; -} s_1w_7x7_matrix; - -#define S_1W_7X7_MATRIX_DEFAULT ((s_1w_7x7_matrix)\ - { 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w v0_0; - tvector1w v0_1; - tvector1w v0_2; - tvector1w v0_3; - tvector1w v0_4; - tvector1w v0_5; - tvector1w v0_6; - tvector1w v0_7; - tvector1w v0_8; - tvector1w v0_9; - tvector1w v0_10; -} s_1w_1x11_matrix; - -#define S_1W_1X11_MATRIX_DEFAULT ((s_1w_1x11_matrix)\ - { 0, 0, 0, 0, 0, 0, 0, 0, 0 }) - -typedef struct { - tvector1w x_cord[MAX_CONFIG_POINTS]; - tvector1w slope[MAX_CONFIG_POINTS-1]; - tvector1w y_offset[MAX_CONFIG_POINTS-1]; -} ref_config_points; - -typedef struct { - tscalar1w_range1wbit slope_vec[CONFIG_UNIT_LUT_SIZE_32]; - tscalar1w_range1wbit offset_vec[CONFIG_UNIT_LUT_SIZE_32]; - tscalar1w_16bit x_cord_vec[CONFIG_UNIT_LUT_SIZE_32]; - tscalar1w_16bit x_cord_max; - tscalar1w_5bit exponent; - tscalar1w_5bit slope_resolution; -} xcu_ref_init_vectors; - -typedef struct { -#ifdef ISP2401 - tvector1w elem[IMAX32_ELEM_SIZE]; -} imax32_ref_in_vector; - -typedef struct { -#endif - tscalar1w search[BMA_SEARCH_BLOCK_SZ_16][BMA_SEARCH_BLOCK_SZ_16]; -} bma_16x16_search_window; - -typedef struct { - tscalar1w ref[BMA_REF_BLOCK_SZ_8][BMA_REF_BLOCK_SZ_8]; -} ref_block_8x8; - -typedef struct { - tscalar1w sads[SADS_16x16_1]; -} bma_output_16_1; - -typedef struct { - tscalar1w sads[SADS_16x16_2]; -} bma_output_16_2; - -typedef struct { - tscalar1w sads[SADS_14x14_2]; -} bma_output_14_2; - -typedef struct { - tscalar1w sads[SADS_14x14_1]; -} bma_output_14_1; - -typedef struct { - tvector1w spatial_weight_lut[BFA_MAX_KWAY]; /* spatial weight LUT */ - /* range weight LUT, (BFA_RW_LUT_SIZE + 1) numbers of LUT values are compressed in BFA_RW_LUT_SIZE buffer. - * range_weight_lut[k] = packed(drop[k], range_weight[k]) - * where, drop[k] = range_weight[k+1] - range_weight[k] - * pack(msb, lsb): two 8bits numbers packed in one 16bits number */ - tvector1w range_weight_lut[BFA_RW_LUT_SIZE]; -} bfa_weights; - -/* Return type for BFA BBBs */ -typedef struct { - tvector2w sop; /* weighted sum of pixels */ - tvector1w sow; /* sum of weights */ -} bfa_7x7_output; -#endif /* __REF_VECTOR_FUNC_TYPES_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h deleted file mode 100644 index cd938375e02e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __MPMATH_H_INCLUDED__ -#define __MPMATH_H_INCLUDED__ - - -#ifdef INLINE_MPMATH -#define STORAGE_CLASS_MPMATH_FUNC_H static inline -#define STORAGE_CLASS_MPMATH_DATA_H static inline_DATA -#else /* INLINE_MPMATH */ -#define STORAGE_CLASS_MPMATH_FUNC_H extern -#define STORAGE_CLASS_MPMATH_DATA_H extern_DATA -#endif /* INLINE_MPMATH */ - -#include <type_support.h> - -/* - * Implementation limits - */ -#define MIN_BITDEPTH 1 -#define MAX_BITDEPTH 64 - -#define ROUND_NEAREST_EVEN 0 -#define ROUND_NEAREST 1 - -/* - * The MP types - * - * "vector lane data" is scalar. With "scalar data" for limited range shift and address values - */ -typedef unsigned long long mpudata_t; /* Type of reference MP scalar / vector lane data; unsigned */ -typedef long long mpsdata_t; /* Type of reference MP scalar / vector lane data; signed */ -typedef unsigned short spudata_t; /* Type of reference SP scalar / vector lane data; unsigned */ -typedef short spsdata_t; /* Type of reference SP scalar / vector lane data; signed */ -typedef unsigned short bitdepth_t; - -typedef enum { - mp_zero_ID, - mp_one_ID, - mp_mone_ID, - mp_smin_ID, - mp_smax_ID, - mp_umin_ID, - mp_umax_ID, - N_mp_const_ID -} mp_const_ID_t; - -#ifdef ISP2401 -/* _isValidMpudata is for internal use by mpmath and bbb's. - * isValidMpudata is for external use by functions on top. - */ -#ifndef ENABLE_VALID_MP_DATA_CHECK -#define _isValidMpsdata(data,bitdepth) (1) -#define _isValidMpudata(data,bitdepth) (1) -#else -#define _isValidMpsdata(data,bitdepth) isValidMpsdata(data,bitdepth) -#define _isValidMpudata(data,bitdepth) isValidMpsdata(data,bitdepth) - -#endif -#endif -STORAGE_CLASS_MPMATH_FUNC_H bool isValidMpsdata( - const mpsdata_t data, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H bool isValidMpudata( - const mpudata_t data, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_castd ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_casth ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_scasth ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qcastd ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qcasth ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qrcasth ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_abs ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_limit ( - const mpsdata_t bnd_low, - const mpsdata_t in0, - const mpsdata_t bnd_high, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_max ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_min ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_mux ( - const spudata_t sel, - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_rmux ( - const spudata_t sel, - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_add ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_sadd ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_sub ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_ssub ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_addasr1 ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_subasr1 ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_lsr ( - const mpsdata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_asr ( - const mpsdata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_rasr ( - const mpsdata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -/* "mp_rasr_u()" is implemented by "mp_rasr()" */ -STORAGE_CLASS_MPMATH_FUNC_H mpudata_t mp_rasr_u ( - const mpudata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_lsl ( - const mpsdata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_asl ( - const mpsdata_t in0, - const spsdata_t shft, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_muld ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_mul ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qmul ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qrmul ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qdiv ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qdivh ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_div ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_divh ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_and ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_compl ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_or ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_xor ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isEQ ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isNE ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGT ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGE ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLT ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLE ( - const mpsdata_t in0, - const mpsdata_t in1, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isEQZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isNEZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGTZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGEZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLTZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLEZ ( - const mpsdata_t in0, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_const ( - const mp_const_ID_t ID, - const bitdepth_t bitdepth); - -STORAGE_CLASS_MPMATH_FUNC_H mpudata_t mp_sqrt_u( - const mpudata_t in0, - const bitdepth_t bitdepth); - -#ifndef INLINE_MPMATH -#define STORAGE_CLASS_MPMATH_FUNC_C -#define STORAGE_CLASS_MPMATH_DATA_C const -#else /* INLINE_MPMATH */ -#define STORAGE_CLASS_MPMATH_FUNC_C STORAGE_CLASS_MPMATH_FUNC_H -#define STORAGE_CLASS_MPMATH_DATA_C STORAGE_CLASS_MPMATH_DATA_H -#include "mpmath.c" -#define MPMATH_INLINED -#endif /* INLINE_MPMATH */ - -#endif /* __MPMATH_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h deleted file mode 100644 index a607242c5f1a..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __OSYS_H_INCLUDED__ -#define __OSYS_H_INCLUDED__ - -/* - * This file is included on every cell {SP,ISP,host} and on every system - * that uses the OSYS device. It defines the API to DLI bridge - * - * System and cell specific interfaces and inline code are included - * conditionally through Makefile path settings. - * - * - . system and cell agnostic interfaces, constants and identifiers - * - public: system agnostic, cell specific interfaces - * - private: system dependent, cell specific interfaces & inline implementations - * - global: system specific constants and identifiers - * - local: system and cell specific constants and identifiers - * - */ - - -#include "system_local.h" -#include "osys_local.h" - -#ifndef __INLINE_OSYS__ -#define STORAGE_CLASS_OSYS_H extern -#define STORAGE_CLASS_OSYS_C -#include "osys_public.h" -#else /* __INLINE_OSYS__ */ -#define STORAGE_CLASS_OSYS_H static inline -#define STORAGE_CLASS_OSYS_C static inline -#include "osys_private.h" -#endif /* __INLINE_OSYS__ */ - -#endif /* __OSYS_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h deleted file mode 100644 index 53d535e4f2ae..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __STREAM_BUFFER_H_INCLUDED__ -#define __STREAM_BUFFER_H_INCLUDED__ - -/* - * This file is included on every cell {SP,ISP,host} and on every system - * that uses the DMA device. It defines the API to DLI bridge - * - * System and cell specific interfaces and inline code are included - * conditionally through Makefile path settings. - * - * - . system and cell agnostic interfaces, constants and identifiers - * - public: system agnostic, cell specific interfaces - * - private: system dependent, cell specific interfaces & inline implementations - * - global: system specific constants and identifiers - * - local: system and cell specific constants and identifiers - * - */ - - -#include "system_local.h" -#include "stream_buffer_local.h" - -#ifndef __INLINE_STREAM_BUFFER__ -#define STORAGE_CLASS_STREAM_BUFFER_H extern -#define STORAGE_CLASS_STREAM_BUFFER_C -#include "stream_buffer_public.h" -#else /* __INLINE_STREAM_BUFFER__ */ -#define STORAGE_CLASS_STREAM_BUFFER_H static inline -#define STORAGE_CLASS_STREAM_BUFFER_C static inline -#include "stream_buffer_private.h" -#endif /* __INLINE_STREAM_BUFFER__ */ - -#endif /* __STREAM_BUFFER_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h deleted file mode 100644 index 5368b9062897..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __VECTOR_FUNC_H_INCLUDED__ -#define __VECTOR_FUNC_H_INCLUDED__ - - -/* TODO: Later filters will be moved to types directory, - * and we should only include matrix_MxN types */ -#include "filters/filters_1.0/filter_2x2.h" -#include "filters/filters_1.0/filter_3x3.h" -#include "filters/filters_1.0/filter_4x4.h" -#include "filters/filters_1.0/filter_5x5.h" - -#include "vector_func_local.h" - -#ifndef __INLINE_VECTOR_FUNC__ -#define STORAGE_CLASS_VECTOR_FUNC_H extern -#define STORAGE_CLASS_VECTOR_FUNC_C -#include "vector_func_public.h" -#else /* __INLINE_VECTOR_FUNC__ */ -#define STORAGE_CLASS_VECTOR_FUNC_H static inline -#define STORAGE_CLASS_VECTOR_FUNC_C static inline -#include "vector_func_private.h" -#endif /* __INLINE_VECTOR_FUNC__ */ - -#endif /* __VECTOR_FUNC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h deleted file mode 100644 index 4923f2d5518b..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __VECTOR_OPS_H_INCLUDED__ -#define __VECTOR_OPS_H_INCLUDED__ - - -#include "vector_ops_local.h" - -#ifndef __INLINE_VECTOR_OPS__ -#define STORAGE_CLASS_VECTOR_OPS_H extern -#define STORAGE_CLASS_VECTOR_OPS_C -#include "vector_ops_public.h" -#else /* __INLINE_VECTOR_OPS__ */ -#define STORAGE_CLASS_VECTOR_OPS_H static inline -#define STORAGE_CLASS_VECTOR_OPS_C static inline -#include "vector_ops_private.h" -#endif /* __INLINE_VECTOR_OPS__ */ - -#endif /* __VECTOR_OPS_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h deleted file mode 100644 index 13083fe55141..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __XMEM_H_INCLUDED__ -#define __XMEM_H_INCLUDED__ - -/* - * This file is included on every cell {SP,ISP,host} and on every system - * that uses the XMEM device. It defines the API to DLI bridge - * - * System and cell specific interfaces and inline code are included - * conditionally through Makefile path settings. - * - * - . system and cell agnostic interfaces, constants and identifiers - * - public: system agnostic, cell specific interfaces - * - private: system dependent, cell specific interfaces & inline implementations - * - global: system specific constants and identifiers - * - local: system and cell specific constants and identifiers - */ - - -#include "system_local.h" -#include "xmem_local.h" - -#ifndef __INLINE_XMEM__ -#define STORAGE_CLASS_XMEM_H extern -#define STORAGE_CLASS_XMEM_C -#include "xmem_public.h" -#else /* __INLINE_XMEM__ */ -#define STORAGE_CLASS_XMEM_H static inline -#define STORAGE_CLASS_XMEM_C static inline -#include "xmem_private.h" -#endif /* __INLINE_XMEM__ */ - -#endif /* __XMEM_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h deleted file mode 100644 index 2b7025e90250..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __SOCKET_GLOBAL_H_INCLUDED__ -#define __SOCKET_GLOBAL_H_INCLUDED__ - -#include "stream_buffer.h" - -/* define the socket port direction */ -typedef enum { - SOCKET_PORT_DIRECTION_NULL, - SOCKET_PORT_DIRECTION_IN, - SOCKET_PORT_DIRECTION_OUT -} socket_port_direction_t; - -/* pointer to the port's callout function */ -typedef void (*socket_port_callout_fp)(void); -typedef struct socket_port_s socket_port_t; -typedef struct socket_s socket_t; - -/* data structure of the socket port */ -struct socket_port_s { - unsigned channel; /* the port entity */ - socket_port_direction_t direction; /* the port direction */ - socket_port_callout_fp callout; /* the port callout function */ - - socket_t *socket; /* point to the socket */ - - struct { - unsigned data; - } buf; /* the buffer at the port */ -}; - -/* data structure of the socket */ -struct socket_s { - socket_port_t *in; /* the in-direction port */ - socket_port_t *out; /* the out-direction port */ - stream_buffer_t buf; /* the buffer between in-ports and out-ports */ -}; - -#endif /* __SOCKET_GLOBAL_H_INCLUDED__ */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h deleted file mode 100644 index b9664b9608dc..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __STREAM_BUFFER_GLOBAL_H_INCLUDED__ -#define __STREAM_BUFFER_GLOBAL_H_INCLUDED__ - -typedef struct stream_buffer_s stream_buffer_t; -struct stream_buffer_s { - unsigned base; - unsigned limit; - unsigned top; -}; - -#endif /* __STREAM_BUFFER_GLOBAL_H_INCLUDED__ */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h index ba7a076c3afa..0beb7347a4f3 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h @@ -121,15 +121,9 @@ struct ia_css_frame_info { }; #define IA_CSS_BINARY_DEFAULT_FRAME_INFO \ -{ \ - {0, /* width */ \ - 0}, /* height */ \ - 0, /* padded_width */ \ - IA_CSS_FRAME_FORMAT_NUM, /* format */ \ - 0, /* raw_bit_depth */ \ - IA_CSS_BAYER_ORDER_NUM, /* raw_bayer_order */ \ - {0, /*start col */ \ - 0}, /*start line */ \ +(struct ia_css_frame_info) { \ + .format = IA_CSS_FRAME_FORMAT_NUM, \ + .raw_bayer_order = IA_CSS_BAYER_ORDER_NUM, \ } /** @@ -190,18 +184,11 @@ struct ia_css_frame { }; #define DEFAULT_FRAME \ -{ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* info */ \ - 0, /* data */ \ - 0, /* data_bytes */ \ - SH_CSS_INVALID_QUEUE_ID, /* dynamic_data_index */ \ - IA_CSS_BUFFER_TYPE_INVALID, /* buf_type */ \ - IA_CSS_FRAME_FLASH_STATE_NONE, /* flash_state */ \ - 0, /* exp_id */ \ - 0, /* isp_config_id */ \ - false, /* valid */ \ - false, /* contiguous */ \ - { 0 } /* planes */ \ +(struct ia_css_frame) { \ + .info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID, \ + .buf_type = IA_CSS_BUFFER_TYPE_INVALID, \ + .flash_state = IA_CSS_FRAME_FLASH_STATE_NONE, \ } /* @brief Fill a frame with zeros diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h index d0c0e6b92025..f6870fa7a18c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h @@ -33,22 +33,17 @@ struct ia_css_preview_settings { /* 2401 only for these two - do we in fact use them for anything real */ struct ia_css_frame *delay_frames[MAX_NUM_DELAY_FRAMES]; struct ia_css_frame *tnr_frames[NUM_TNR_FRAMES]; - + struct ia_css_pipe *copy_pipe; struct ia_css_pipe *capture_pipe; struct ia_css_pipe *acc_pipe; }; #define IA_CSS_DEFAULT_PREVIEW_SETTINGS \ -{ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* preview_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */\ - { NULL }, /* dvs_frames */ \ - { NULL }, /* tnr_frames */ \ - NULL, /* copy_pipe */\ - NULL, /* capture_pipe */\ - NULL, /* acc_pipe */\ +(struct ia_css_preview_settings) { \ + .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .preview_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ } struct ia_css_capture_settings { @@ -70,20 +65,15 @@ struct ia_css_capture_settings { }; #define IA_CSS_DEFAULT_CAPTURE_SETTINGS \ -{ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */\ - {IA_CSS_BINARY_DEFAULT_SETTINGS}, /* primary_binary */\ - 0, /* num_primary_stage */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* pre_isp_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* anr_gdc_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* post_isp_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* capture_pp_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */\ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* capture_ldc_binary */\ - NULL, /* yuv_scaler_binary */ \ - { NULL }, /* delay_frames[ref_frames] */ \ - NULL, /* is_output_stage */ \ - 0, /* num_yuv_scaler */ \ +(struct ia_css_capture_settings) { \ + .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .primary_binary = {IA_CSS_BINARY_DEFAULT_SETTINGS}, \ + .pre_isp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .anr_gdc_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .post_isp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .capture_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .capture_ldc_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ } struct ia_css_video_settings { @@ -105,18 +95,10 @@ struct ia_css_video_settings { }; #define IA_CSS_DEFAULT_VIDEO_SETTINGS \ -{ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* video_binary */ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */ \ - NULL, /* yuv_scaler_binary */ \ - { NULL }, /* delay_frames */ \ - { NULL }, /* tnr_frames */ \ - NULL, /* vf_pp_in_frame */ \ - NULL, /* copy_pipe */ \ - NULL, /* capture_pipe */ \ - NULL, /* is_output_stage */ \ - 0, /* num_yuv_scaler */ \ +(struct ia_css_video_settings) { \ + .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .video_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ + .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ } struct ia_css_yuvpp_settings { @@ -130,14 +112,8 @@ struct ia_css_yuvpp_settings { }; #define IA_CSS_DEFAULT_YUVPP_SETTINGS \ -{ \ - IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */ \ - NULL, /* yuv_scaler_binary */ \ - NULL, /* vf_pp_binary */ \ - NULL, /* is_output_stage */ \ - 0, /* num_yuv_scaler */ \ - 0, /* num_vf_pp */ \ - 0, /* num_output */ \ +(struct ia_css_yuvpp_settings) { \ + .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \ } struct osys_object; @@ -185,35 +161,26 @@ struct ia_css_pipe { }; #define IA_CSS_DEFAULT_PIPE \ -{ \ - false, /* stop_requested */ \ - DEFAULT_PIPE_CONFIG, /* config */ \ - DEFAULT_PIPE_EXTRA_CONFIG, /* extra_config */ \ - DEFAULT_PIPE_INFO, /* info */ \ - IA_CSS_PIPE_ID_ACC, /* mode (pipe_id) */ \ - NULL, /* shading_table */ \ - DEFAULT_PIPELINE, /* pipeline */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* bds_output_info */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* out_yuv_ds_input_info */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* vf_yuv_ds_input_info */ \ - NULL, /* output_stage */ \ - NULL, /* vf_stage */ \ - SH_CSS_BDS_FACTOR_1_00, /* required_bds_factor */ \ - 1, /* dvs_frame_delay */ \ - 0, /* num_invalid_frames */ \ - {true}, /* enable_viewfinder */ \ - NULL, /* stream */ \ - DEFAULT_FRAME, /* in_frame_struct */ \ - DEFAULT_FRAME, /* out_frame_struct */ \ - DEFAULT_FRAME, /* vf_frame_struct */ \ - { NULL }, /* continuous_frames */ \ - { NULL }, /* cont_md_buffers */ \ - { IA_CSS_DEFAULT_PREVIEW_SETTINGS }, /* pipe_settings */ \ - 0, /* scaler_pp_lut */ \ - NULL, /* osys object */ \ - PIPE_ENTRY_EMPTY_TOKEN, /* pipe_num */\ +(struct ia_css_pipe) { \ + .config = DEFAULT_PIPE_CONFIG, \ + .info = DEFAULT_PIPE_INFO, \ + .mode = IA_CSS_PIPE_ID_ACC, /* (pipe_id) */ \ + .pipeline = DEFAULT_PIPELINE, \ + .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .bds_output_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .out_yuv_ds_input_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .vf_yuv_ds_input_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .required_bds_factor = SH_CSS_BDS_FACTOR_1_00, \ + .dvs_frame_delay = 1, \ + .enable_viewfinder = {true}, \ + .in_frame_struct = DEFAULT_FRAME, \ + .out_frame_struct = DEFAULT_FRAME, \ + .vf_frame_struct = DEFAULT_FRAME, \ + .pipe_settings = { \ + .preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS \ + }, \ + .pipe_num = PIPE_ENTRY_EMPTY_TOKEN, \ } void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h index df0aad9a6ab9..11225d5ac442 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h @@ -152,82 +152,20 @@ struct ia_css_pipe_config { }; -#ifdef ISP2401 -/** - * Default origin of internal frame positioned on shading table. - */ -#define IA_CSS_PIPE_DEFAULT_INTERNAL_FRAME_ORIGIN_BQS_ON_SCTBL \ -{ \ - 0, /* x [bqs] */ \ - 0 /* y [bqs] */ \ -} - -/** - * Default settings for newly created pipe configurations. - */ -#define DEFAULT_PIPE_CONFIG \ -{ \ - IA_CSS_PIPE_MODE_PREVIEW, /* mode */ \ - 1, /* isp_pipe_version */ \ - { 0, 0 }, /* pipe_effective_input_res */ \ - { 0, 0 }, /* bayer_ds_out_res */ \ - { 0, 0 }, /* vf_pp_in_res */ \ - { 0, 0 }, /* capt_pp_in_res */ \ - { 0, 0 }, /* output_system_in_res */ \ - { 0, 0 }, /* dvs_crop_out_res */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \ - NULL, /* acc_extension */ \ - NULL, /* acc_stages */ \ - 0, /* num_acc_stages */ \ - DEFAULT_CAPTURE_CONFIG, /* default_capture_config */ \ - { 0, 0 }, /* dvs_envelope */ \ - IA_CSS_FRAME_DELAY_1, /* dvs_frame_delay */ \ - -1, /* acc_num_execs */ \ - false, /* enable_dz */ \ - false, /* enable_dpc */ \ - false, /* enable_vfpp_bci */ \ - false, /* enable_luma_only */ \ - false, /* enable_tnr */ \ - NULL, /* p_isp_config */\ - { 0, 0 }, /* gdc_in_buffer_res */ \ - { 0, 0 }, /* gdc_in_buffer_offset */ \ - IA_CSS_PIPE_DEFAULT_INTERNAL_FRAME_ORIGIN_BQS_ON_SCTBL /* internal_frame_origin_bqs_on_sctbl */ \ -} - -#else - /** * Default settings for newly created pipe configurations. */ #define DEFAULT_PIPE_CONFIG \ -{ \ - IA_CSS_PIPE_MODE_PREVIEW, /* mode */ \ - 1, /* isp_pipe_version */ \ - { 0, 0 }, /* pipe_effective_input_res */ \ - { 0, 0 }, /* bayer_ds_out_res */ \ - { 0, 0 }, /* vf_pp_in_res */ \ - { 0, 0 }, /* capt_pp_in_res */ \ - { 0, 0 }, /* dvs_crop_out_res */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \ - NULL, /* acc_extension */ \ - NULL, /* acc_stages */ \ - 0, /* num_acc_stages */ \ - DEFAULT_CAPTURE_CONFIG, /* default_capture_config */ \ - { 0, 0 }, /* dvs_envelope */ \ - IA_CSS_FRAME_DELAY_1, /* dvs_frame_delay */ \ - -1, /* acc_num_execs */ \ - false, /* enable_dz */ \ - false, /* enable_dpc */ \ - false, /* enable_vfpp_bci */ \ - NULL, /* p_isp_config */\ - { 0, 0 }, /* gdc_in_buffer_res */ \ - { 0, 0 } /* gdc_in_buffer_offset */ \ +(struct ia_css_pipe_config) { \ + .mode = IA_CSS_PIPE_MODE_PREVIEW, \ + .isp_pipe_version = 1, \ + .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .default_capture_config = DEFAULT_CAPTURE_CONFIG, \ + .dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \ + .acc_num_execs = -1, \ } -#endif - /* Pipe info, this struct describes properties of a pipe after it's stream has * been created. * ~~~** DO NOT ADD NEW FIELD **~~~ This structure will be deprecated. @@ -272,33 +210,15 @@ struct ia_css_pipe_info { /** * Defaults for ia_css_pipe_info structs. */ -#ifdef ISP2401 - -#define DEFAULT_PIPE_INFO \ -{ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* raw_output_info */ \ - { 0, 0}, /* output system in res */ \ - DEFAULT_SHADING_INFO, /* shading_info */ \ - DEFAULT_GRID_INFO, /* grid_info */ \ - 0 /* num_invalid_frames */ \ -} - -#else - #define DEFAULT_PIPE_INFO \ -{ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* raw_output_info */ \ - DEFAULT_SHADING_INFO, /* shading_info */ \ - DEFAULT_GRID_INFO, /* grid_info */ \ - 0 /* num_invalid_frames */ \ +(struct ia_css_pipe_info) { \ + .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .raw_output_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .shading_info = DEFAULT_SHADING_INFO, \ + .grid_info = DEFAULT_GRID_INFO, \ } -#endif - /* @brief Load default pipe configuration * @param[out] pipe_config The pipe configuration. * @return None @@ -402,7 +322,7 @@ ia_css_pipe_set_isp_config(struct ia_css_pipe *pipe, exception holds for IA_CSS_EVENT_TYPE_PORT_EOF, for this event an IRQ is always raised. Note that events are still queued and the Host can poll for them. The - or_mask and and_mask may be be active at the same time\n + or_mask and and_mask may be active at the same time\n \n Default values, for all pipe id's, after ia_css_init:\n or_mask = IA_CSS_EVENT_TYPE_ALL\n diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h index 725b90072cfe..259ab3f074ba 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h @@ -370,52 +370,20 @@ struct ia_css_shading_info { } info; }; -#ifndef ISP2401 - -/* Default Shading Correction information of Shading Correction Type 1. */ -#define DEFAULT_SHADING_INFO_TYPE_1 \ -{ \ - IA_CSS_SHADING_CORRECTION_TYPE_1, /* type */ \ - { /* info */ \ - { \ - 0, /* enable */ \ - 0, /* num_hor_grids */ \ - 0, /* num_ver_grids */ \ - 0, /* bqs_per_grid_cell */ \ - 1, /* bayer_scale_hor_ratio_in */ \ - 1, /* bayer_scale_hor_ratio_out */ \ - 1, /* bayer_scale_ver_ratio_in */ \ - 1, /* bayer_scale_ver_ratio_out */ \ - 0, /* sc_bayer_origin_x_bqs_on_shading_table */ \ - 0 /* sc_bayer_origin_y_bqs_on_shading_table */ \ - } \ - } \ -} - -#else - /* Default Shading Correction information of Shading Correction Type 1. */ #define DEFAULT_SHADING_INFO_TYPE_1 \ -{ \ - IA_CSS_SHADING_CORRECTION_TYPE_1, /* type */ \ - { /* info */ \ - { \ - 0, /* num_hor_grids */ \ - 0, /* num_ver_grids */ \ - 0, /* bqs_per_grid_cell */ \ - 1, /* bayer_scale_hor_ratio_in */ \ - 1, /* bayer_scale_hor_ratio_out */ \ - 1, /* bayer_scale_ver_ratio_in */ \ - 1, /* bayer_scale_ver_ratio_out */ \ - {0, 0}, /* isp_input_sensor_data_res_bqs */ \ - {0, 0}, /* sensor_data_res_bqs */ \ - {0, 0} /* sensor_data_origin_bqs_on_sctbl */ \ +(struct ia_css_shading_info) { \ + .type = IA_CSS_SHADING_CORRECTION_TYPE_1, \ + .info = { \ + .type_1 = { \ + .bayer_scale_hor_ratio_in = 1, \ + .bayer_scale_hor_ratio_out = 1, \ + .bayer_scale_ver_ratio_in = 1, \ + .bayer_scale_ver_ratio_out = 1, \ } \ } \ } -#endif - /* Default Shading Correction information. */ #define DEFAULT_SHADING_INFO DEFAULT_SHADING_INFO_TYPE_1 @@ -438,12 +406,9 @@ struct ia_css_grid_info { /* defaults for ia_css_grid_info structs */ #define DEFAULT_GRID_INFO \ -{ \ - 0, /* isp_in_width */ \ - 0, /* isp_in_height */ \ - DEFAULT_3A_GRID_INFO, /* s3a_grid */ \ - DEFAULT_DVS_GRID_INFO, /* dvs_grid */ \ - IA_CSS_VAMEM_TYPE_1 /* vamem_type */ \ +(struct ia_css_grid_info) { \ + .dvs_grid = DEFAULT_DVS_GRID_INFO, \ + .vamem_type = IA_CSS_VAMEM_TYPE_1 \ } /* Morphing table, used for geometric distortion and chromatic abberration @@ -534,11 +499,8 @@ struct ia_css_capture_config { /* default settings for ia_css_capture_config structs */ #define DEFAULT_CAPTURE_CONFIG \ -{ \ - IA_CSS_CAPTURE_MODE_PRIMARY, /* mode (capture) */ \ - false, /* enable_xnr */ \ - false, /* enable_raw_output */ \ - false /* enable_capture_pp_bli */ \ +(struct ia_css_capture_config) { \ + .mode = IA_CSS_CAPTURE_MODE_PRIMARY, \ } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h deleted file mode 100644 index cc404018b112..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_AA2_STATE_H -#define __IA_CSS_AA2_STATE_H - -#include "type_support.h" -#include "vmem.h" /* for VMEM_ARRAY*/ - -/* Denotes the maximum number of pixels per line that can be processed: -* MAX_AA_VECTORS_PER_LINE = maximum_line_width / ISP_NWAY */ -#ifndef MAX_AA_VECTORS_PER_LINE -#error Please define MAX_AA_VECTORS_PER_LINE. -#endif - -/* This uses 2 history lines for both y, u and v*/ -#define AA_STATE_Y_BUFFER_HEIGHT 2 -#define AA_STATE_UV_BUFFER_HEIGHT 2 -#define AA_STATE_Y_BUFFER_WIDTH MAX_AA_VECTORS_PER_LINE -/* The number of u and v elements is half y due to yuv420 downsampling. */ -#define AA_STATE_UV_BUFFER_WIDTH (AA_STATE_Y_BUFFER_WIDTH/2) - - -struct ia_css_isp_aa_vmem_state { - VMEM_ARRAY(y[AA_STATE_Y_BUFFER_HEIGHT], AA_STATE_Y_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(u[AA_STATE_UV_BUFFER_HEIGHT], AA_STATE_UV_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(v[AA_STATE_UV_BUFFER_HEIGHT], AA_STATE_UV_BUFFER_WIDTH*ISP_NWAY); -}; - -#endif /* __IA_CSS_AA2_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h deleted file mode 100644 index 8e1f300bcd39..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_BAYER_LOAD_PARAM_H -#define __IA_CSS_BAYER_LOAD_PARAM_H - -#include "ia_css_bayer_ls_param.h" - -#endif /* __IA_CSS_BAYER_LOAD_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h deleted file mode 100644 index a0d355454aa3..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_BAYER_LS_PARAM_H -#define __IA_CSS_BAYER_LS_PARAM_H - -#include "type_support.h" -#ifndef ISP2401 - -#define NUM_BAYER_LS 2 -#define BAYER_IDX_GR 0 -#define BAYER_IDX_R 1 -#define BAYER_IDX_B 2 -#define BAYER_IDX_GB 3 -#define BAYER_QUAD_WIDTH 2 -#define BAYER_QUAD_HEIGHT 2 -#define NOF_BAYER_VECTORS 4 - -/* bayer load/store */ -struct sh_css_isp_bayer_ls_isp_config { - uint32_t base_address[NUM_BAYER_LS]; - uint32_t width[NUM_BAYER_LS]; - uint32_t height[NUM_BAYER_LS]; - uint32_t stride[NUM_BAYER_LS]; -}; - -#else -#include "../../io_ls/common/ia_css_common_io_types.h" -#endif - -#endif /* __IA_CSS_BAYER_LS_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h deleted file mode 100644 index f330be80efa6..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_BAYER_STORE_PARAM_H -#define __IA_CSS_BAYER_STORE_PARAM_H - -#include "ia_css_bayer_ls_param.h" - - -#endif /* __IA_CSS_BAYER_STORE_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h deleted file mode 100644 index 79cce0e40e82..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_BNLM_STATE_H -#define __IA_CSS_BNLM_STATE_H - - -#include "type_support.h" -#include "vmem.h" /* for VMEM_ARRAY*/ -#include "bnlm.isp.h" - -struct bnlm_vmem_state { - /* State buffers required for BNLM */ - VMEM_ARRAY(buf[BNLM_STATE_BUF_HEIGHT], BNLM_STATE_BUF_WIDTH*ISP_NWAY); -}; - - - -#endif /* __IA_CSS_BNLM_STATE_H */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h deleted file mode 100644 index 795fba76bb20..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_CNR_STATE_H -#define __IA_CSS_CNR_STATE_H - -#include "type_support.h" - -#include "vmem.h" - -typedef struct -{ - VMEM_ARRAY(u, ISP_NWAY); - VMEM_ARRAY(v, ISP_NWAY); -} s_cnr_buf; - -/* CNR (color noise reduction) */ -struct sh_css_isp_cnr_vmem_state { - s_cnr_buf cnr_buf[2][MAX_VECTORS_PER_BUF_LINE/2]; -}; - -#endif /* __IA_CSS_CNR_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h deleted file mode 100644 index e533e2fa8cd5..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_CNR2_STATE_H -#define __IA_CSS_CNR2_STATE_H - -#include "type_support.h" -#include "vmem.h" - -typedef struct -{ - VMEM_ARRAY(y, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY); - VMEM_ARRAY(u, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY); - VMEM_ARRAY(v, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY); -} s_cnr_buf; - -/* CNR (color noise reduction) */ -struct sh_css_isp_cnr_vmem_state { - s_cnr_buf cnr_buf; -}; - -#endif /* __IA_CSS_CNR2_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h deleted file mode 100644 index f832b3697908..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_DP_STATE_H -#define __IA_CSS_DP_STATE_H - -#include "type_support.h" - -#include "vmem.h" -#ifndef ISP2401 -#if NEED_BDS_OTHER_THAN_1_00 -#else -#if ENABLE_FIXED_BAYER_DS -#endif -#define MAX_VECTORS_PER_DP_LINE MAX_VECTORS_PER_BUF_INPUT_LINE -#else -#define MAX_VECTORS_PER_DP_LINE MAX_VECTORS_PER_BUF_LINE -#endif - -/* DP (Defect Pixel Correction) */ -struct sh_css_isp_dp_vmem_state { - VMEM_ARRAY(dp_buf[4], MAX_VECTORS_PER_DP_LINE*ISP_NWAY); -}; - -#endif /* __IA_CSS_DP_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h deleted file mode 100644 index cbf1e81e83a6..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_DPC2_STATE_H -#define __IA_CSS_DPC2_STATE_H - -#include "type_support.h" -#include "vmem.h" /* for VMEM_ARRAY*/ - -#include "ia_css_dpc2_param.h" - -struct sh_css_isp_dpc2_vmem_state { - VMEM_ARRAY(dpc2_input_lines[DPC2_STATE_INPUT_BUFFER_HEIGHT], DPC2_STATE_INPUT_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(dpc2_local_deviations[DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT], DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(dpc2_second_min[DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT], DPC2_STATE_SECOND_MINMAX_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(dpc2_second_max[DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT], DPC2_STATE_SECOND_MINMAX_BUFFER_WIDTH*ISP_NWAY); -}; - -#endif /* __IA_CSS_DPC2_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h deleted file mode 100644 index 47e451b15044..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_EED1_8_STATE_H -#define __IA_CSS_EED1_8_STATE_H - -#include "type_support.h" -#include "vmem.h" /* for VMEM_ARRAY*/ - -#include "ia_css_eed1_8_param.h" - -struct eed1_8_vmem_state { - VMEM_ARRAY(eed1_8_input_lines[EED1_8_STATE_INPUT_BUFFER_HEIGHT], EED1_8_STATE_INPUT_BUFFER_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_LD_H[EED1_8_STATE_LD_H_HEIGHT], EED1_8_STATE_LD_H_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_LD_V[EED1_8_STATE_LD_V_HEIGHT], EED1_8_STATE_LD_V_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_D_Hr[EED1_8_STATE_D_HR_HEIGHT], EED1_8_STATE_D_HR_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_D_Hb[EED1_8_STATE_D_HB_HEIGHT], EED1_8_STATE_D_HB_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_D_Vr[EED1_8_STATE_D_VR_HEIGHT], EED1_8_STATE_D_VR_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_D_Vb[EED1_8_STATE_D_VB_HEIGHT], EED1_8_STATE_D_VB_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_rb_zipped[EED1_8_STATE_RB_ZIPPED_HEIGHT], EED1_8_STATE_RB_ZIPPED_WIDTH*ISP_NWAY); -#if EED1_8_FC_ENABLE_MEDIAN - VMEM_ARRAY(eed1_8_Yc[EED1_8_STATE_YC_HEIGHT], EED1_8_STATE_YC_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_Cg[EED1_8_STATE_CG_HEIGHT], EED1_8_STATE_CG_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_Co[EED1_8_STATE_CO_HEIGHT], EED1_8_STATE_CO_WIDTH*ISP_NWAY); - VMEM_ARRAY(eed1_8_AbsK[EED1_8_STATE_ABSK_HEIGHT], EED1_8_STATE_ABSK_WIDTH*ISP_NWAY); -#endif -}; - -#endif /* __IA_CSS_EED1_8_STATE_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h deleted file mode 100644 index 213ef3b385aa..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_PLANE_IO_PARAM_H -#define __IA_CSS_PLANE_IO_PARAM_H - -#include "../common/ia_css_common_io_param.h" - -#endif /* __IA_CSS_PLANE_IO_PARAM_H */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h deleted file mode 100644 index d635741505e2..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_PLANE_IO_TYPES_H -#define __IA_CSS_PLANE_IO_TYPES_H - -#include "../common/ia_css_common_io_types.h" - -#define PLANE_IO_LS_NUM_PLANES 3 - -struct ia_css_plane_io_config { - struct ia_css_common_io_config get_plane_io_config[PLANE_IO_LS_NUM_PLANES]; - struct ia_css_common_io_config put_plane_io_config[PLANE_IO_LS_NUM_PLANES]; -}; - -#endif /* __IA_CSS_PLANE_IO_TYPES_H */ - -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h deleted file mode 100644 index 52450a9a55a1..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_YUV420_IO_PARAM -#define __IA_CSS_YUV420_IO_PARAM - -#include "../common/ia_css_common_io_param.h" - -#endif -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h deleted file mode 100644 index 99ec1143b214..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_YUV420_IO_TYPES -#define __IA_CSS_YUV420_IO_TYPES - -#include "../common/ia_css_common_io_types.h" - -#endif -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h deleted file mode 100644 index 881b7e5236dc..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifdef ISP2401 -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ - -#ifndef __IA_CSS_PLANE_IO_PARAM_H -#define __IA_CSS_PLANE_IO_PARAM_H - -#include "../common/ia_css_common_io_param.h" - -#endif /* __IA_CSS_PLANE_IO_PARAM_H */ -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h deleted file mode 100644 index f4b9e8de3d8e..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifdef ISP2401 -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ - -#ifndef __IA_CSS_PLANE_IO_TYPES_H -#define __IA_CSS_PLANE_IO_TYPES_H - -#include "../common/ia_css_common_io_types.h" - -#define PLANE_IO_LS_NUM_PLANES 3 - -struct ia_css_plane_io_config { - struct ia_css_common_io_config get_plane_io_config[PLANE_IO_LS_NUM_PLANES]; - struct ia_css_common_io_config put_plane_io_config[PLANE_IO_LS_NUM_PLANES]; -}; - -#endif /* __IA_CSS_PLANE_IO_TYPES_H */ - -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h deleted file mode 100644 index 86184b545fed..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifdef ISP2401 -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ - -#ifndef __IA_CSS_YUV420_IO_PARAM -#define __IA_CSS_YUV420_IO_PARAM - -#include "../common/ia_css_common_io_param.h" - -#endif -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h deleted file mode 100644 index ad750f530013..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifdef ISP2401 -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ - -#ifndef __IA_CSS_YUV420_IO_TYPES -#define __IA_CSS_YUV420_IO_TYPES - -#include "../common/ia_css_common_io_types.h" - -#endif -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h deleted file mode 100644 index 5581bddf9f9b..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_NORM_TYPES_H -#define __IA_CSS_NORM_TYPES_H - - -#endif /* __IA_CSS_NORM_TYPES_H */ - - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h index 8d674d2c6427..63e70669f085 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h @@ -28,7 +28,7 @@ /* 3A configuration. This configures the 3A statistics collection * module. */ - + /* 3A statistics grid * * ISP block: S3A1 (3A Support for 3A ver.1 (Histogram is not used for AE)) @@ -54,7 +54,7 @@ struct ia_css_3a_grid_info { uint32_t awb_fr_enable; /** awb_fr enabled in binary, 0:disabled, 1:enabled */ struct awb_fr_public_grid_config awb_fr_grd_info;/** see description in awb_fr_public.h*/ - + uint32_t elem_bit_depth; /** TODO:Taken from BYT - need input from AIQ if needed for SKC Bit depth of element used @@ -98,52 +98,6 @@ struct ia_css_3a_grid_info { }; -#if defined(SYSTEM_css_skycam_c0_system) -#if defined USE_NEW_AE_STRUCT || defined USE_NEW_AWB_STRUCT -#define DEFAULT_3A_GRID_INFO \ -{ \ - 0, /* ae_enable */ \ - {0,0,0,0,0,0,0}, /* AE: width,height,b_width,b_height,x_start,y_start*/ \ - 0, /* awb_enable */ \ - {0,0,0,0,0,0}, /* AWB: width,height,b_width,b_height,x_start,y_start*/ \ - 0, /* af_enable */ \ - {0,0,0,0,0,0,0}, /* AF: width,height,b_width,b_height,x_start,y_start,ff_en*/ \ - 0, /* awb_fr_enable */ \ - {0,0,0,0,0,0,0}, /* AWB_FR: width,height,b_width,b_height,x_start,y_start,ff_en*/ \ - 0, /* elem_bit_depth */ \ -} -#else -#define DEFAULT_3A_GRID_INFO \ -{ \ - 0, /* ae_enable */ \ - {0,0,0,0,0,0,0,0,0}, /* AE: width,height,b_width,b_height,x_start,y_start,x_end,y_end*/ \ - 0, /* awb_enable */ \ - {0,0,0,0,0,0,0,0}, /* AWB: width,height,b_width,b_height,x_start,y_start,x_end,y_end*/ \ - 0, /* af_enable */ \ - {0,0,0,0,0,0,0}, /* AF: width,height,b_width,b_height,x_start,y_start,ff_en*/ \ - 0, /* awb_fr_enable */ \ - {0,0,0,0,0,0,0}, /* AWB_FR: width,height,b_width,b_height,x_start,y_start,ff_en*/ \ - 0, /* elem_bit_depth */ \ -} -#endif /* USE_NEW_AE_STRUCT || defined USE_NEW_AWB_STRUCT */ - -#else -#define DEFAULT_3A_GRID_INFO \ -{ \ - 0, /* enable */ \ - 0, /* use_dmem */ \ - 0, /* has_histogram */ \ - 0, /* width */ \ - 0, /* height */ \ - 0, /* aligned_width */ \ - 0, /* aligned_height */ \ - 0, /* bqs_per_grid_cell */ \ - 0, /* deci_factor_log2 */ \ - 0, /* elem_bit_depth */ \ -} - -#endif - /* This struct should be split into 3, for AE, AWB and AF. * However, that will require driver/ 3A lib modifications. */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h deleted file mode 100644 index 9aa019539f47..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_S3A_STAT_LS_PARAM_H -#define __IA_CSS_S3A_STAT_LS_PARAM_H - -#include "type_support.h" -#ifdef ISP2401 -#include "../../io_ls/common/ia_css_common_io_types.h" -#endif - -#define NUM_S3A_LS 1 - -/* s3a statistics store */ -#ifdef ISP2401 -struct ia_css_s3a_stat_ls_configuration { - uint32_t s3a_grid_size_log2; -}; - -#endif -struct sh_css_isp_s3a_stat_ls_isp_config { -#ifndef ISP2401 - uint32_t base_address[NUM_S3A_LS]; - uint32_t width[NUM_S3A_LS]; - uint32_t height[NUM_S3A_LS]; - uint32_t stride[NUM_S3A_LS]; -#endif - uint32_t s3a_grid_size_log2[NUM_S3A_LS]; -}; - -#ifndef ISP2401 - -#endif -#endif /* __IA_CSS_S3A_STAT_LS_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h deleted file mode 100644 index 676b42d364e8..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_S3A_STAT_STORE_PARAM_H -#define __IA_CSS_S3A_STAT_STORE_PARAM_H - -#include "ia_css_s3a_stat_ls_param.h" - - -#endif /* __IA_CSS_S3A_STAT_STORE_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h deleted file mode 100644 index fd19f008ff91..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef _IA_CSS_SCALE_PARAM_H -#define _IA_CSS_SCALE_PARAM_H - -#include "uds/uds_1.0/ia_css_uds_param.h" - -#endif /* _IA_CSS_SCALE_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h index 031983c357e4..381e5730d405 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h @@ -41,20 +41,6 @@ struct ia_css_sdis_info { uint32_t deci_factor_log2; }; -#define IA_CSS_DEFAULT_SDIS_INFO \ - { \ - { { 0, 0 }, /* dim */ \ - { 0, 0 }, /* pad */ \ - }, /* grid */ \ - { { 0, 0 }, /* dim */ \ - { 0, 0 }, /* pad */ \ - }, /* coef */ \ - { { 0, 0 }, /* dim */ \ - { 0, 0 }, /* pad */ \ - }, /* proj */ \ - 0, /* dis_deci_factor_log2 */ \ - } - /* DVS statistics grid * * ISP block: SDVS1 (DIS/DVS Support for DIS/DVS ver.1 (2-axes)) @@ -209,16 +195,17 @@ struct ia_css_dvs_stat_grid_info { /* DVS statistics generated by accelerator default grid info */ -#define DEFAULT_DVS_GRID_INFO { \ -{ \ - { 0, 0, 0}, /* GBL CFG reg: kappa, match_shifrt, binning mode*/ \ - {{{0, 0, 0, 0}, {0, 0, 0}, {0, 0} }, \ - {{0, 0, 0, 0}, {0, 0, 0}, {0, 0} }, \ - {{0, 0, 0, 0}, {0, 0, 0}, {0, 0} } }, \ - {{0, 0, 0, 0}, {4, 0, 0, 0}, {0, 0, 0, 0} } } \ +#define DEFAULT_DVS_GRID_INFO \ +(union ia_css_dvs_grid_u) { \ + .dvs_stat_grid_info = (struct ia_css_dvs_stat_grid_info) { \ + .fe_roi_cfg = { \ + [1] = (struct dvs_stat_public_dvs_level_fe_roi_cfg) { \ + .x_start = 4 \ + } \ + } \ + } \ } - /* Union that holds all types of DVS statistics grid info in * CSS format * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h deleted file mode 100644 index 586cc4315c1f..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_SDIS_PARAM_COMMON_H -#define __IA_CSS_SDIS_PARAM_COMMON_H - - -#include "sdis/common/ia_css_sdis_common.host.h" - -#endif /* __IA_CSS_SDIS_PARAM_COMMON_H */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c index 9478c12abe89..0fdd696bf654 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c @@ -169,8 +169,7 @@ ia_css_sdis_init_info( unsigned enabled) { if (!enabled) { - struct ia_css_sdis_info default_dis = IA_CSS_DEFAULT_SDIS_INFO; - *dis = default_dis; + *dis = (struct ia_css_sdis_info) { }; return; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h deleted file mode 100644 index 2dd8696802d0..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_SDIS_PARAM_H -#define __IA_CSS_SDIS_PARAM_H - -#include "sdis.isp.h" - -#endif /* __IA_CSS_SDIS_PARAM_H */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h deleted file mode 100644 index cea352e45713..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_SDIS2_PARAM_H -#define __IA_CSS_SDIS2_PARAM_H - -#include "sdis.isp.h" - -#endif /* __IA_CSS_SDIS2_PARAM_H */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h deleted file mode 100644 index 1a98555fd5d9..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_XNR3_WRAPPER_PARAM_H -#define __IA_CSS_XNR3_WRAPPER_PARAM_H - -#include "ia_css_xnr3_param.h" - -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h deleted file mode 100644 index 400c6790cbf5..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_YUV_LOAD_PARAM_H -#define __IA_CSS_YUV_LOAD_PARAM_H - -#include "ia_css_yuv_ls_param.h" - -#endif /* __IA_CSS_YUV_LOAD_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h deleted file mode 100644 index c9ff0cb2493a..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_YUV_LS_PARAM_H -#define __IA_CSS_YUV_LS_PARAM_H - -#include "type_support.h" -#ifndef ISP2401 - -/* The number of load/store kernels in a pipeline can be greater than one. - * A kernel can consume more than one input or can produce more - * than one output. - */ -#define NUM_YUV_LS 2 - -/* YUV load/store */ -struct sh_css_isp_yuv_ls_isp_config { - unsigned base_address[NUM_YUV_LS]; - unsigned width[NUM_YUV_LS]; - unsigned height[NUM_YUV_LS]; - unsigned stride[NUM_YUV_LS]; -}; - -#else -#include "../../io_ls/common/ia_css_common_io_types.h" -#endif - -#endif /* __IA_CSS_YUV_LS_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h deleted file mode 100644 index 69c474ea1ffd..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __IA_CSS_YUV_STORE_PARAM_H -#define __IA_CSS_YUV_STORE_PARAM_H - -#include "ia_css_yuv_ls_param.h" - - -#endif /* __IA_CSS_YUV_STORE_PARAM_H */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h deleted file mode 100644 index e625ba62cc15..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h +++ /dev/null @@ -1,286 +0,0 @@ -#ifndef ISP2401 -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ -#else -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. -*/ -#endif - -#ifndef _COMMON_ISP_EXPRS_H_ -#define _COMMON_ISP_EXPRS_H_ - -/* Binary independent pre-processor expressions */ - -#include "sh_css_defs.h" -#include "isp_const.h" - -#ifdef __HOST -#error "isp_exprs.h: Do not include on HOST, contains ISP specific defines" -#endif - -#ifndef __ISP -#if defined(MODE) -#define MODE aap -#error "isp_exprs.h: is mode independent, but MODE is set" -#endif -#if defined(VARIABLE_RESOLUTION) -#define VARIABLE_RESOLUTION noot -#error "isp_exprs.h: is mode independent, but VARIABLE_RESOLUTION is set" -#endif -#if defined(DECI_FACTOR_LOG2) -#define DECI_FACTOR_LOG2 mies -#error "isp_exprs.h: is mode independent, but DECI_FACTOR_LOG2 is set" -#endif -#endif - -#define LOG_VECTOR_STEP _ISP_LOG_VECTOR_STEP(MODE) -/* should be even and multiple of vf downscaling */ -#define ISP_OUTPUT_CHUNK_LOG_FACTOR (MAX_VF_LOG_DOWNSCALE<=1 ? LOG_VECTOR_STEP : \ - umax(VF_LOG_DOWNSCALE, LOG_VECTOR_STEP)) - -#define CEIL_DIV_CHUNKS(n,c) ((c) == 1 ? (n) \ - : CEIL_SHIFT(CEIL_DIV((n), (c)), ISP_OUTPUT_CHUNK_LOG_FACTOR)<<ISP_OUTPUT_CHUNK_LOG_FACTOR) - - -#define ISP_VARIABLE_INPUT (ISP_INPUT == IA_CSS_BINARY_INPUT_VARIABLE) - -/* Binary independent versions, see isp_defs.h for binary dependent ones */ -#ifndef __ISP -#define IMAGEFORMAT_IS_RAW(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RAW) - -#define IMAGEFORMAT_IS_RAW_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RAW) - -#define IMAGEFORMAT_IS_RGB(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888 || (fmt) == IA_CSS_FRAME_FORMAT_PLANAR_RGB888 || \ - (fmt) == IA_CSS_FRAME_FORMAT_RGB565) - -#define IMAGEFORMAT_IS_RGB_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888 || (fmt) == IA_CSS_FRAME_FORMAT_RGB565) - -#define IMAGEFORMAT_UV_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV11 || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV12 || (fmt) == IA_CSS_FRAME_FORMAT_NV21 || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV16 || (fmt) == IA_CSS_FRAME_FORMAT_NV61 || \ - (fmt) == IA_CSS_FRAME_FORMAT_UYVY || (fmt) == IA_CSS_FRAME_FORMAT_YUYV || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12_TILEY) - -#define IMAGEFORMAT_YUV_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_UYVY || (fmt) == IA_CSS_FRAME_FORMAT_YUYV) - -#define IMAGEFORMAT_INTERLEAVED(fmt) (IMAGEFORMAT_UV_INTERLEAVED(fmt) || IMAGEFORMAT_IS_RGB_INTERLEAVED(fmt)) - -#define IMAGEFORMAT_SUB_SAMPL_420(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV420 || (fmt) == IA_CSS_FRAME_FORMAT_YV12 || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV12 || (fmt) == IA_CSS_FRAME_FORMAT_NV21 || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12TILEY) - -#define IMAGEFORMAT_SUB_SAMPL_422(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV422 || (fmt) == IA_CSS_FRAME_FORMAT_YV16 || \ - (fmt) == IA_CSS_FRAME_FORMAT_NV16 || (fmt) == IA_CSS_FRAME_FORMAT_NV61) - -#define IMAGEFORMAT_SUB_SAMPL_444(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV444) - -#define IMAGEFORMAT_UV_SWAPPED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV21 || (fmt) == IA_CSS_FRAME_FORMAT_NV61) - -#define IMAGEFORMAT_IS_RGBA(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888) - -#define IMAGEFORMAT_IS_NV11(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV11) - -#define IMAGEFORMAT_IS_16BIT(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV420_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_YUV422_16) - -#endif - - -/******** GDCAC settings *******/ -#define GDCAC_BPP ISP_VEC_ELEMBITS /* We use 14 bits per pixel component for the GDCAC mode */ -#define GDC_INPUT_BLOCK_WIDTH 2 /* Two vectors are needed */ -#define GDC_OUTPUT_BLOCK_WIDTH 1 /* One vector is produced */ - -#if ISP_VEC_NELEMS == 16 -/* For 16*16 output block, the distortion fits in 13.312 lines __ALWAYS__ */ -#define GDC_INPUT_BLOCK_HEIGHT 14 -#elif ISP_VEC_NELEMS == 64 -/* For 64*64 output block, the distortion fits in 47. lines __ALWAYS__ */ -#define GDC_INPUT_BLOCK_HEIGHT 48 -#endif -/*******************************/ - - -#define ENABLE_HUP ((isp_input_width - isp_envelope_width) < isp_output_width) -#define ENABLE_VUP ((isp_input_height - isp_envelope_height) < isp_output_height) - -#define ISP_INPUT_WIDTH (ENABLE_DS | ENABLE_HUP ? isp_input_width : ISP_INTERNAL_WIDTH) -#define ISP_INPUT_HEIGHT (ENABLE_DS | ENABLE_VUP ? isp_input_height : isp_internal_height) - -#define DECI_FACTOR_LOG2 (ISP_FIXED_S3A_DECI_LOG ? ISP_FIXED_S3A_DECI_LOG : isp_deci_log_factor) - -#define ISP_S3ATBL_WIDTH \ - _ISP_S3ATBL_ISP_WIDTH(_ISP_S3A_ELEMS_ISP_WIDTH((ENABLE_HUP ? ISP_INTERNAL_WIDTH : ISP_INPUT_WIDTH), ISP_LEFT_CROPPING), \ - DECI_FACTOR_LOG2) -#define S3ATBL_WIDTH_BYTES (sizeof(struct ia_css_3a_output) * ISP_S3ATBL_WIDTH) -#define S3ATBL_WIDTH_SHORTS (S3ATBL_WIDTH_BYTES / sizeof(short)) - -/* should be even?? */ -#define ISP_UV_OUTPUT_CHUNK_VECS CEIL_DIV(ISP_OUTPUT_CHUNK_VECS, 2) - - -#if defined(__ISP) || defined(INIT_VARS) - -#define ISP_USE_IF (ISP_INPUT == IA_CSS_BINARY_INPUT_MEMORY ? 0 : \ - ISP_INPUT == IA_CSS_BINARY_INPUT_SENSOR ? 1 : \ - isp_online) - -#define ISP_DVS_ENVELOPE_WIDTH 0 -#define ISP_DVS_ENVELOPE_HEIGHT 0 - -#define _ISP_INPUT_WIDTH_VECS _ISP_VECS(ISP_INPUT_WIDTH) - -#if !defined(__ISP) || (VARIABLE_RESOLUTION && !__HOST) -#define ISP_INPUT_WIDTH_VECS isp_vectors_per_input_line -#else -#define ISP_INPUT_WIDTH_VECS _ISP_INPUT_WIDTH_VECS -#endif - -#if !defined(__ISP) || VARIABLE_RESOLUTION -#define ISP_INTERNAL_WIDTH_VECS isp_vectors_per_line -#else -#define ISP_INTERNAL_WIDTH_VECS _ISP_INTERNAL_WIDTH_VECS -#endif - -#define _ISP_INTERNAL_HEIGHT __ISP_INTERNAL_HEIGHT(isp_output_height, ISP_TOP_CROPPING, ISP_DVS_ENVELOPE_HEIGHT) - -#define ISP_INTERNAL_HEIGHT isp_internal_height - -#define _ISP_INTERNAL_WIDTH __ISP_INTERNAL_WIDTH(ISP_OUTPUT_WIDTH, ISP_DVS_ENVELOPE_WIDTH, \ - ISP_LEFT_CROPPING, MODE, ISP_C_SUBSAMPLING, \ - OUTPUT_NUM_CHUNKS, ISP_PIPELINING) - -#define ISP_UV_INTERNAL_WIDTH (ISP_INTERNAL_WIDTH / 2) -#define ISP_UV_INTERNAL_HEIGHT (ISP_INTERNAL_HEIGHT / 2) - -#define _ISP_INTERNAL_WIDTH_VECS (_ISP_INTERNAL_WIDTH / ISP_VEC_NELEMS) -#define _ISP_UV_INTERNAL_WIDTH_VECS CEIL_DIV(ISP_UV_INTERNAL_WIDTH, ISP_VEC_NELEMS) - -#define ISP_VF_OUTPUT_WIDTH _ISP_VF_OUTPUT_WIDTH(ISP_VF_OUTPUT_WIDTH_VECS) -#define ISP_VF_OUTPUT_HEIGHT _ISP_VF_OUTPUT_HEIGHT(isp_output_height, VF_LOG_DOWNSCALE) - -#if defined (__ISP) && !VARIABLE_RESOLUTION -#define ISP_INTERNAL_WIDTH _ISP_INTERNAL_WIDTH -#define ISP_VF_OUTPUT_WIDTH_VECS _ISP_VF_OUTPUT_WIDTH_VECS -#else -#define ISP_INTERNAL_WIDTH (VARIABLE_RESOLUTION ? isp_internal_width : _ISP_INTERNAL_WIDTH) -#define ISP_VF_OUTPUT_WIDTH_VECS (VARIABLE_RESOLUTION ? isp_vf_output_width_vecs : _ISP_VF_OUTPUT_WIDTH_VECS) -#endif - -#if defined(__ISP) && !VARIABLE_RESOLUTION -#define ISP_OUTPUT_WIDTH ISP_MAX_OUTPUT_WIDTH -#define VF_LOG_DOWNSCALE MAX_VF_LOG_DOWNSCALE -#else -#define ISP_OUTPUT_WIDTH isp_output_width -#define VF_LOG_DOWNSCALE isp_vf_downscale_bits -#endif - -#if !defined(__ISP) || VARIABLE_RESOLUTION -#define _ISP_MAX_VF_OUTPUT_WIDTH __ISP_MAX_VF_OUTPUT_WIDTH(2*SH_CSS_MAX_VF_WIDTH, ISP_LEFT_CROPPING) -#elif defined(MODE) && MODE == IA_CSS_BINARY_MODE_PRIMARY && ISP_OUTPUT_WIDTH > 3328 -/* Because of vmem issues, should be fixed later */ -#define _ISP_MAX_VF_OUTPUT_WIDTH (SH_CSS_MAX_VF_WIDTH - 2*ISP_VEC_NELEMS + (ISP_LEFT_CROPPING ? 2 * ISP_VEC_NELEMS : 0)) -#else -#define _ISP_MAX_VF_OUTPUT_WIDTH (ISP_VF_OUTPUT_WIDTH + (ISP_LEFT_CROPPING ? (2 >> VF_LOG_DOWNSCALE) * ISP_VEC_NELEMS : 0)) -#endif - -#define ISP_MAX_VF_OUTPUT_VECS CEIL_DIV(_ISP_MAX_VF_OUTPUT_WIDTH, ISP_VEC_NELEMS) - - - -#define ISP_MIN_STRIPE_WIDTH (ISP_PIPELINING * (1<<_ISP_LOG_VECTOR_STEP(MODE))) - -/******* STRIPING-RELATED MACROS *******/ -#define NO_STRIPING (ISP_NUM_STRIPES == 1) - -#define ISP_OUTPUT_CHUNK_VECS \ - (NO_STRIPING ? CEIL_DIV_CHUNKS(ISP_OUTPUT_VECS_EXTRA_CROP, OUTPUT_NUM_CHUNKS) \ - : ISP_IO_STRIPE_WIDTH_VECS(ISP_OUTPUT_VECS_EXTRA_CROP, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH) ) - -#define VECTORS_PER_LINE \ - (NO_STRIPING ? ISP_INTERNAL_WIDTH_VECS \ - : ISP_IO_STRIPE_WIDTH_VECS(ISP_INTERNAL_WIDTH_VECS, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH) ) - -#define VECTORS_PER_INPUT_LINE \ - (NO_STRIPING ? ISP_INPUT_WIDTH_VECS \ - : ISP_IO_STRIPE_WIDTH_VECS(ISP_INPUT_WIDTH_VECS, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH)+_ISP_EXTRA_PADDING_VECS) - - -#define ISP_MAX_VF_OUTPUT_STRIPE_VECS \ - (NO_STRIPING ? ISP_MAX_VF_OUTPUT_VECS \ - : CEIL_MUL(CEIL_DIV(ISP_MAX_VF_OUTPUT_VECS, ISP_NUM_STRIPES), 2)) -#define _ISP_VF_OUTPUT_WIDTH_VECS \ - (NO_STRIPING ? __ISP_VF_OUTPUT_WIDTH_VECS(ISP_OUTPUT_WIDTH, VF_LOG_DOWNSCALE) \ - : __ISP_VF_OUTPUT_WIDTH_VECS(CEIL_DIV(ISP_OUTPUT_WIDTH, ISP_NUM_STRIPES), VF_LOG_DOWNSCALE)) - -#define ISP_IO_STRIPE_WIDTH_VECS(width, padding, num_stripes, min_stripe) \ - MAX(CEIL_MUL(padding + CEIL_DIV(width-padding, num_stripes) \ - , 2) \ - , min_stripe) -////////// INPUT & INTERNAL -/* should be even */ -#define INPUT_NUM_CHUNKS OUTPUT_NUM_CHUNKS - -#define INPUT_VECTORS_PER_CHUNK CEIL_DIV_CHUNKS(VECTORS_PER_INPUT_LINE, INPUT_NUM_CHUNKS) - -/* only for ISP code, will be removed: */ -#define VECTORS_PER_FULL_LINE ISP_INTERNAL_WIDTH_VECS -#define VECTORS_PER_INPUT_FULL_LINE ISP_INPUT_WIDTH_VECS - -////////// OUTPUT -/* should at least even and also multiple of vf scaling */ -#define ISP_OUTPUT_VECS_EXTRA_CROP CEIL_DIV(ISP_OUTPUT_WIDTH_EXTRA_CROP, ISP_VEC_NELEMS) - -/* Output is decoupled from input */ -#define ISP_OUTPUT_WIDTH_EXTRA_CROP CEIL_MUL(CEIL_MUL((ENABLE_DVS_ENVELOPE ? ISP_OUTPUT_WIDTH : ISP_INTERNAL_WIDTH), 2*ISP_VEC_NELEMS), \ - ISP_C_SUBSAMPLING * OUTPUT_NUM_CHUNKS * HIVE_ISP_DDR_WORD_BYTES) - -#define ISP_MAX_VF_OUTPUT_CHUNK_VECS \ - (NO_CHUNKING ? ISP_MAX_VF_OUTPUT_STRIPE_VECS \ - : 2*CEIL_DIV(ISP_MAX_VF_OUTPUT_STRIPE_VECS, 2*OUTPUT_NUM_CHUNKS)) - -#define OUTPUT_VECTORS_PER_CHUNK CEIL_DIV_CHUNKS(VECTORS_PER_LINE,OUTPUT_NUM_CHUNKS) - -/* should be even?? */ -#define OUTPUT_C_VECTORS_PER_CHUNK CEIL_DIV(OUTPUT_VECTORS_PER_CHUNK, 2) - -#ifndef ISP2401 -/**** SCTBL defs *******/ -#define ISP_SCTBL_HEIGHT \ - _ISP_SCTBL_HEIGHT(ISP_INPUT_HEIGHT, DECI_FACTOR_LOG2) - -#endif -/**** UDS defs *********/ -#define UDS_DMACH_STRIDE_B_IN_Y (( ISP_INTERNAL_WIDTH /BITS8_ELEMENTS_PER_XMEM_ADDR)*HIVE_ISP_DDR_WORD_BYTES) -#define UDS_DMACH_STRIDE_B_IN_C (((ISP_INTERNAL_WIDTH/2)/BITS8_ELEMENTS_PER_XMEM_ADDR)*HIVE_ISP_DDR_WORD_BYTES) - -#else /* defined(__ISP) || defined(INIT_VARS) */ - -#define ISP_INTERNAL_WIDTH isp_internal_width -#define ISP_INTERNAL_HEIGHT isp_internal_height - -#endif /* defined(__ISP) || defined(INIT_VARS) */ - -#endif /* _COMMON_ISP_EXPRS_H_ */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h index 5a58abe2b233..732e49a241eb 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h @@ -93,17 +93,6 @@ struct ia_css_cas_binary_descr { bool *is_output_stage; }; -#define IA_CSS_DEFAULT_CAS_BINARY_DESCR \ -{ \ - 0, \ - 0, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ -} - struct ia_css_binary_descr { int mode; bool online; @@ -171,80 +160,15 @@ struct ia_css_binary { struct ia_css_isp_param_css_segments css_params; }; -#ifdef ISP2401 - #define IA_CSS_BINARY_DEFAULT_SETTINGS \ -{ \ - NULL, \ - IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ - { 0, 0},/* effective_in_frame_res */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - 0, /* input_buf_vectors */ \ - 0, /* deci_factor_log2 */ \ - 0, /* vf_downscale_log2 */ \ - 0, /* s3atbl_width */ \ - 0, /* s3atbl_height */ \ - 0, /* s3atbl_isp_width */ \ - 0, /* s3atbl_isp_height */ \ - 0, /* morph_tbl_width */ \ - 0, /* morph_tbl_aligned_width */ \ - 0, /* morph_tbl_height */ \ - 0, /* sctbl_width_per_color */ \ - 0, /* sctbl_aligned_width_per_color */ \ - 0, /* sctbl_height */ \ - 0, /* sctbl_legacy_width_per_color */ \ - 0, /* sctbl_legacy_height */ \ - IA_CSS_DEFAULT_SDIS_INFO, /* dis */ \ - { 0, 0},/* dvs_envelope_info */ \ - false, /* online */ \ - 0, /* uds_xc */ \ - 0, /* uds_yc */ \ - 0, /* left_padding */ \ - DEFAULT_BINARY_METRICS, /* metrics */ \ - IA_CSS_DEFAULT_ISP_MEM_PARAMS, /* mem_params */ \ - IA_CSS_DEFAULT_ISP_CSS_PARAMS, /* css_params */ \ +(struct ia_css_binary) { \ + .input_format = IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \ + .in_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .internal_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .out_frame_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .vf_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ } -#else - -#define IA_CSS_BINARY_DEFAULT_SETTINGS \ -{ \ - NULL, \ - IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ - { 0, 0},/* effective_in_frame_res */ \ - IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ - 0, /* input_buf_vectors */ \ - 0, /* deci_factor_log2 */ \ - 0, /* vf_downscale_log2 */ \ - 0, /* s3atbl_width */ \ - 0, /* s3atbl_height */ \ - 0, /* s3atbl_isp_width */ \ - 0, /* s3atbl_isp_height */ \ - 0, /* morph_tbl_width */ \ - 0, /* morph_tbl_aligned_width */ \ - 0, /* morph_tbl_height */ \ - 0, /* sctbl_width_per_color */ \ - 0, /* sctbl_aligned_width_per_color */ \ - 0, /* sctbl_height */ \ - IA_CSS_DEFAULT_SDIS_INFO, /* dis */ \ - { 0, 0},/* dvs_envelope_info */ \ - false, /* online */ \ - 0, /* uds_xc */ \ - 0, /* uds_yc */ \ - 0, /* left_padding */ \ - DEFAULT_BINARY_METRICS, /* metrics */ \ - IA_CSS_DEFAULT_ISP_MEM_PARAMS, /* mem_params */ \ - IA_CSS_DEFAULT_ISP_CSS_PARAMS, /* css_params */ \ -} - -#endif - enum ia_css_err ia_css_binary_init_infos(void); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c index 295e07049393..a0f0e9062c4c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c @@ -490,7 +490,6 @@ ia_css_binary_get_shading_info_type_1(const struct ia_css_binary *binary, /* [in struct sh_css_shading_table_bayer_origin_compute_results res; #else struct sh_css_binary_sc_requirements scr; - struct ia_css_shading_info default_shading_info_type_1 = DEFAULT_SHADING_INFO_TYPE_1; #endif #ifndef ISP2401 @@ -542,7 +541,7 @@ ia_css_binary_get_shading_info_type_1(const struct ia_css_binary *binary, /* [in &res); if (err != IA_CSS_SUCCESS) #else - *shading_info = default_shading_info_type_1; + *shading_info = DEFAULT_SHADING_INFO_TYPE_1; err = sh_css_binary_get_sc_requirements(binary, required_bds_factor, stream_config, &scr); if (err != IA_CSS_SUCCESS) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c index f22d73b56bc6..60395904f89a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c @@ -2858,13 +2858,7 @@ ia_css_debug_pipe_graph_dump_stage( if (l && enable_info[l-1] == ',') enable_info[--l] = '\0'; - if (l <= ENABLE_LINE_MAX_LENGTH) { - /* It fits on one line, copy string and init */ - /* other helper strings with empty string */ - strcpy_s(enable_info, - sizeof(enable_info), - ei); - } else { + if (l > ENABLE_LINE_MAX_LENGTH) { /* Too big for one line, find last comma */ p = ENABLE_LINE_MAX_LENGTH; while (ei[p] != ',') diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c index 5faa89ad8a23..7562beadabef 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c @@ -196,7 +196,7 @@ enum ia_css_err ia_css_frame_map(struct ia_css_frame **frame, attribute, context); if (me->data == mmgr_NULL) err = IA_CSS_ERR_INVALID_ARGUMENTS; - }; + } if (err != IA_CSS_SUCCESS) { sh_css_free(me); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h index fa3f09347b22..9d111793bb65 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h @@ -94,14 +94,5 @@ union ia_css_all_memory_offsets { } array[IA_CSS_NUM_PARAM_CLASSES]; }; -#define IA_CSS_DEFAULT_ISP_MEM_PARAMS \ - { { { { NULL, 0 } } } } - -#define IA_CSS_DEFAULT_ISP_CSS_PARAMS \ - { { { { 0, 0 } } } } - -#define IA_CSS_DEFAULT_ISP_ISP_PARAMS \ - { { { { 0, 0 } } } } - #endif /* _IA_CSS_ISP_PARAM_TYPES_H_ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h index e64936e2d46e..85ed7db0af55 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h @@ -74,21 +74,15 @@ struct ia_css_pipeline { }; #define DEFAULT_PIPELINE \ -{ \ - IA_CSS_PIPE_ID_PREVIEW, /* pipe_id */ \ - 0, /* pipe_num */ \ - false, /* stop_requested */ \ - NULL, /* stages */ \ - NULL, /* current_stage */ \ - 0, /* num_stages */ \ - DEFAULT_FRAME, /* in_frame */ \ - {DEFAULT_FRAME}, /* out_frame */ \ - {DEFAULT_FRAME}, /* vf_frame */ \ - IA_CSS_FRAME_DELAY_1, /* frame_delay */ \ - 0, /* inout_port_config */ \ - -1, /* num_execs */ \ - true, /* acquire_isp_each_stage */\ - QOS_INVALID /* pipe_qos_config */\ +(struct ia_css_pipeline) { \ + .pipe_id = IA_CSS_PIPE_ID_PREVIEW, \ + .in_frame = DEFAULT_FRAME, \ + .out_frame = {DEFAULT_FRAME}, \ + .vf_frame = {DEFAULT_FRAME}, \ + .dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \ + .num_execs = -1, \ + .acquire_isp_each_stage = true, \ + .pipe_qos_config = QOS_INVALID \ } /* Stage descriptor used to create a new stage in the pipeline */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c index 8f93d29d1c51..81a50c73ad0b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c @@ -692,17 +692,16 @@ static void pipeline_init_defaults( unsigned int pipe_num, unsigned int dvs_frame_delay) { - struct ia_css_frame init_frame = DEFAULT_FRAME; unsigned int i; pipeline->pipe_id = pipe_id; pipeline->stages = NULL; pipeline->stop_requested = false; pipeline->current_stage = NULL; - pipeline->in_frame = init_frame; + pipeline->in_frame = DEFAULT_FRAME; for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { - pipeline->out_frame[i] = init_frame; - pipeline->vf_frame[i] = init_frame; + pipeline->out_frame[i] = DEFAULT_FRAME; + pipeline->vf_frame[i] = DEFAULT_FRAME; } pipeline->num_execs = -1; pipeline->acquire_isp_each_stage = true; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c index 322bb3de6098..37116faab631 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c @@ -112,8 +112,6 @@ static int thread_alive; #define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \ (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis)) -#define DEFAULT_PLANES { {0, 0, 0, 0} } - struct sh_css my_css; int (*sh_css_printf) (const char *fmt, va_list args) = NULL; @@ -194,7 +192,7 @@ sh_css_pipe_start(struct ia_css_stream *stream); * @param[in] stream Point to the target "ia_css_stream" instance. * * @return - * - IA_CSS_SUCCESS, if the "stop" requests have been sucessfully sent out. + * - IA_CSS_SUCCESS, if the "stop" requests have been successfully sent out. * - CSS error code, otherwise. * * @@ -1054,7 +1052,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) { /* * We need to poll the ISYS HW in capture_indication itself - * for "non-continous" capture usecase for getting accurate + * for "non-continuous" capture usecase for getting accurate * isys frame capture timestamps. * This is because the capturepipe propcessing takes longer * to execute than the input system frame capture. @@ -2291,25 +2289,19 @@ init_pipe_defaults(enum ia_css_pipe_mode mode, struct ia_css_pipe *pipe, bool copy_pipe) { - static struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE; - static struct ia_css_preview_settings prev = IA_CSS_DEFAULT_PREVIEW_SETTINGS; - static struct ia_css_capture_settings capt = IA_CSS_DEFAULT_CAPTURE_SETTINGS; - static struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS; - static struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS; - if (pipe == NULL) { IA_CSS_ERROR("NULL pipe parameter"); return IA_CSS_ERR_INVALID_ARGUMENTS; } /* Initialize pipe to pre-defined defaults */ - *pipe = default_pipe; + *pipe = IA_CSS_DEFAULT_PIPE; /* TODO: JB should not be needed, but temporary backward reference */ switch (mode) { case IA_CSS_PIPE_MODE_PREVIEW: pipe->mode = IA_CSS_PIPE_ID_PREVIEW; - pipe->pipe_settings.preview = prev; + pipe->pipe_settings.preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS; break; case IA_CSS_PIPE_MODE_CAPTURE: if (copy_pipe) { @@ -2317,11 +2309,11 @@ init_pipe_defaults(enum ia_css_pipe_mode mode, } else { pipe->mode = IA_CSS_PIPE_ID_CAPTURE; } - pipe->pipe_settings.capture = capt; + pipe->pipe_settings.capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS; break; case IA_CSS_PIPE_MODE_VIDEO: pipe->mode = IA_CSS_PIPE_ID_VIDEO; - pipe->pipe_settings.video = video; + pipe->pipe_settings.video = IA_CSS_DEFAULT_VIDEO_SETTINGS; break; case IA_CSS_PIPE_MODE_ACC: pipe->mode = IA_CSS_PIPE_ID_ACC; @@ -2331,7 +2323,7 @@ init_pipe_defaults(enum ia_css_pipe_mode mode, break; case IA_CSS_PIPE_MODE_YUVPP: pipe->mode = IA_CSS_PIPE_ID_YUVPP; - pipe->pipe_settings.yuvpp = yuvpp; + pipe->pipe_settings.yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS; break; default: return IA_CSS_ERR_INVALID_ARGUMENTS; @@ -3657,7 +3649,7 @@ static enum ia_css_err create_host_video_pipeline(struct ia_css_pipe *pipe) in_frame = me->stages->args.out_frame[0]; } else if (pipe->stream->config.continuous) { #ifdef USE_INPUT_SYSTEM_VERSION_2401 - /* When continous is enabled, configure in_frame with the + /* When continuous is enabled, configure in_frame with the * last pipe, which is the copy pipe. */ in_frame = pipe->stream->last_pipe->continuous_frames[0]; @@ -3854,7 +3846,7 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) * - Direct Sensor Mode Online Preview * - Buffered Sensor Mode Online Preview * - Direct Sensor Mode Continuous Preview - * - Buffered Sensor Mode Continous Preview + * - Buffered Sensor Mode Continuous Preview */ sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); @@ -4715,7 +4707,7 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) event->timer_subcode = payload[2]; } /* It's a non timer event. So clear first half of the timer event data. - * If the second part of the TIMER event is not recieved, we discard + * If the second part of the TIMER event is not received, we discard * the first half of the timer data and process the non timer event without * affecting the flow. So the non timer event falls through * the code. */ @@ -5588,8 +5580,7 @@ static enum ia_css_err load_video_binaries(struct ia_css_pipe *pipe) /* we build up the pipeline starting at the end */ /* YUV post-processing if needed */ if (need_scaler) { - struct ia_css_cas_binary_descr cas_scaler_descr - = IA_CSS_DEFAULT_CAS_BINARY_DESCR; + struct ia_css_cas_binary_descr cas_scaler_descr = { }; /* NV12 is the common format that is supported by both */ /* yuv_scaler and the video_xx_isp2_min binaries. */ @@ -6244,8 +6235,8 @@ static enum ia_css_err load_primary_binaries( pipe_out_info->res); if (need_extra_yuv_scaler) { - struct ia_css_cas_binary_descr cas_scaler_descr - = IA_CSS_DEFAULT_CAS_BINARY_DESCR; + struct ia_css_cas_binary_descr cas_scaler_descr = { }; + err = ia_css_pipe_create_cas_scaler_desc_single_output( &capt_pp_out_info, pipe_out_info, @@ -6958,7 +6949,7 @@ static enum ia_css_err ia_css_pipe_create_cas_scaler_desc_single_output( unsigned int i; unsigned int hor_ds_factor = 0, ver_ds_factor = 0; enum ia_css_err err = IA_CSS_SUCCESS; - struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; + struct ia_css_frame_info tmp_in_info; unsigned max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP; @@ -7232,7 +7223,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; struct ia_css_yuvpp_settings *mycs; struct ia_css_binary *next_binary; - struct ia_css_cas_binary_descr cas_scaler_descr = IA_CSS_DEFAULT_CAS_BINARY_DESCR; + struct ia_css_cas_binary_descr cas_scaler_descr = { }; unsigned int i, j; bool need_isp_copy_binary = false; @@ -7610,7 +7601,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) * except for the following: * - Direct Sensor Mode Online Capture * - Direct Sensor Mode Continuous Capture - * - Buffered Sensor Mode Continous Capture + * - Buffered Sensor Mode Continuous Capture */ sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR; @@ -7950,7 +7941,7 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) * - Direct Sensor Mode Online Capture * - Direct Sensor Mode Online Capture * - Direct Sensor Mode Continuous Capture - * - Buffered Sensor Mode Continous Capture + * - Buffered Sensor Mode Continuous Capture */ sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); @@ -8827,10 +8818,8 @@ sh_css_init_host_sp_control_vars(void) */ void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config) { - struct ia_css_pipe_config def_config = DEFAULT_PIPE_CONFIG; - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n"); - *pipe_config = def_config; + *pipe_config = DEFAULT_PIPE_CONFIG; } void @@ -8915,7 +8904,7 @@ ia_css_pipe_create(const struct ia_css_pipe_config *config, err = ia_css_pipe_create_extra(config, NULL, pipe); if(err == IA_CSS_SUCCESS) { - IA_CSS_LOG("pipe created successfuly = %p", *pipe); + IA_CSS_LOG("pipe created successfully = %p", *pipe); } IA_CSS_LEAVE_ERR_PRIVATE(err); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h index 4bcc35d219f8..4fd25ba2cd0d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h @@ -52,17 +52,6 @@ struct ia_css_pipe_extra_config { bool disable_vf_pp; }; -#define DEFAULT_PIPE_EXTRA_CONFIG \ -{ \ - false, /* enable_raw_binning */ \ - false, /* enable_yuv_ds */ \ - false, /* enable_high_speed */ \ - false, /* enable_dvs_6axis */ \ - false, /* enable_reduced_pipe */ \ - false, /* enable_fractional_ds */ \ - false, /* disable_vf_pp */ \ -} - enum ia_css_err ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, const struct ia_css_pipe_extra_config *extra_config, diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h index 40840ea318ab..2ef9238d95ad 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h @@ -24,16 +24,6 @@ struct sh_css_pc_histogram { unsigned *msink; }; -#if !defined(__USE_DESIGNATED_INITIALISERS__) -#define DEFAULT_PC_HISTOGRAM \ -{ \ - 0, \ - NULL, \ - NULL, \ - NULL \ -} -#endif - struct sh_css_binary_metrics { unsigned mode; unsigned id; @@ -42,17 +32,6 @@ struct sh_css_binary_metrics { struct sh_css_binary_metrics *next; }; -#if !defined(__USE_DESIGNATED_INITIALISERS__) -#define DEFAULT_BINARY_METRICS \ -{ \ - 0, \ - 0, \ - DEFAULT_PC_HISTOGRAM, \ - DEFAULT_PC_HISTOGRAM, \ - NULL \ -} -#endif - struct ia_css_frame_metrics { unsigned num_frames; }; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h deleted file mode 100644 index 9e51a657ece4..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is 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 __HMM_BO_DEV_H__ -#define __HMM_BO_DEV_H__ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include "mmu/isp_mmu.h" -#include "hmm/hmm_common.h" -#include "hmm/hmm_vm.h" -#include "ia_css_types.h" - -#define check_bodev_null_return(bdev, exp) \ - check_null_return(bdev, exp, \ - "NULL hmm_bo_device.\n") - -#define check_bodev_null_return_void(bdev) \ - check_null_return_void(bdev, \ - "NULL hmm_bo_device.\n") - -#define HMM_BO_DEVICE_INITED 0x1 - -#define HMM_BO_CACHE_SIZE 2 - - -struct hmm_buffer_object; - -struct hmm_bo_device { - /* isp_mmu provides lock itself */ - struct isp_mmu mmu; - - /* hmm_vm provides lock itself */ - struct hmm_vm vaddr_space; - - struct list_head free_bo_list; - struct list_head active_bo_list; - - /* list lock is used to protect both of the buffer object lists */ - spinlock_t list_lock; -#ifdef CONFIG_ION - struct ion_client *iclient; -#endif - int flag; -}; - -int hmm_bo_device_init(struct hmm_bo_device *bdev, - struct isp_mmu_client *mmu_driver, - unsigned int vaddr_start, unsigned int size); - -/* - * clean up all hmm_bo_device related things. - */ -void hmm_bo_device_exit(struct hmm_bo_device *bdev); - -/* - * whether the bo device is inited or not. - */ -int hmm_bo_device_inited(struct hmm_bo_device *bdev); - -/* - * find the buffer object with virtual address vaddr. - * return NULL if no such buffer object found. - */ -struct hmm_buffer_object *hmm_bo_device_search_start( - struct hmm_bo_device *bdev, ia_css_ptr vaddr); - -/* - * find the buffer object with virtual address vaddr. - * return NULL if no such buffer object found. - */ -struct hmm_buffer_object *hmm_bo_device_search_in_range( - struct hmm_bo_device *bdev, ia_css_ptr vaddr); - -/* - * find the buffer object with kernel virtual address vaddr. - * return NULL if no such buffer object found. - */ -struct hmm_buffer_object *hmm_bo_device_search_vmap_start( - struct hmm_bo_device *bdev, const void *vaddr); - -/* - * find a buffer object with pgnr pages from free_bo_list and - * activate it (remove from free_bo_list and add to - * active_bo_list) - * - * return NULL if no such buffer object found. - */ -struct hmm_buffer_object *hmm_bo_device_get_bo( - struct hmm_bo_device *bdev, unsigned int pgnr); - -/* - * destroy all buffer objects in the free_bo_list. - */ -void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev); -/* - * destroy buffer object with start virtual address vaddr. - */ -void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev, - ia_css_ptr vaddr); -/* - * destroy all buffer objects with pgnr pages. - */ -void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev, - unsigned int pgnr); - -#endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h deleted file mode 100644 index 031c0398bf65..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is 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 SH_MMU_H_ -#define SH_MMU_H_ - - -#include <sh_css.h> - -#include "mmu/isp_mmu.h" - - -/* - * include SH header file here - */ - -/* - * set page directory base address (physical address). - * - * must be provided. - */ -static int sh_set_pd_base(struct isp_mmu *mmu, - unsigned int phys) -{ - sh_css_mmu_set_page_table_base_address((void *)phys); - return 0; -} - -/* - * callback to flush tlb. - * - * tlb_flush_range will at least flush TLBs containing - * address mapping from addr to addr + size. - * - * tlb_flush_all will flush all TLBs. - * - * tlb_flush_all is must be provided. if tlb_flush_range is - * not valid, it will set to tlb_flush_all by default. - */ -static void sh_tlb_flush(struct isp_mmu *mmu) -{ - sh_css_mmu_invalidate_cache(); -} - -static struct isp_mmu_driver sh_mmu_driver = { - .name = "Silicon Hive ISP3000 MMU", - .pte_valid_mask = 0x1, - .set_pd_base = sh_set_pd_base, - .tlb_flush_all = sh_tlb_flush, -}; - -#define ISP_VM_START 0x0 -#define ISP_VM_SIZE (1 << 30) /* 1G address space */ -#define ISP_PTR_NULL NULL - -#endif /* SH_MMU_H_ */ - diff --git a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c index e36c2a33b41a..f21075c1e503 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c @@ -450,7 +450,7 @@ static void mmu_l1_unmap(struct isp_mmu *mmu, phys_addr_t l1_pt, ptr = end; } /* - * use the same L2 page next time, so we dont + * use the same L2 page next time, so we don't * need to invalidate and free this PT. */ /* atomisp_set_pte(l1_pt, idx, NULL_PTE); */ diff --git a/drivers/staging/media/cxd2099/Kconfig b/drivers/staging/media/cxd2099/Kconfig deleted file mode 100644 index b48aefddc84c..000000000000 --- a/drivers/staging/media/cxd2099/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DVB_CXD2099 - tristate "CXD2099AR Common Interface driver" - depends on DVB_CORE && PCI && I2C - ---help--- - Support for the CI module found on cards based on - - Micronas ngene PCIe bridge: cineS2 etc. - - Digital Devices PCIe bridge: Octopus series - - For now, data is passed through '/dev/dvb/adapterX/sec0': - - Encrypted data must be written to 'sec0'. - - Decrypted data can be read from 'sec0'. - - Setup the CAM using device 'ca0'. diff --git a/drivers/staging/media/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile deleted file mode 100644 index 30432c9aabc4..000000000000 --- a/drivers/staging/media/cxd2099/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_DVB_CXD2099) += cxd2099.o - -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ diff --git a/drivers/staging/media/cxd2099/TODO b/drivers/staging/media/cxd2099/TODO deleted file mode 100644 index 375bb6f8ee2c..000000000000 --- a/drivers/staging/media/cxd2099/TODO +++ /dev/null @@ -1,12 +0,0 @@ -For now, data is passed through '/dev/dvb/adapterX/sec0': - - Encrypted data must be written to 'sec0'. - - Decrypted data can be read from 'sec0'. - - Setup the CAM using device 'ca0'. - -But this is wrong. There are some discussions about the proper way for -doing it, as seen at: - http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html - -While there's no proper fix for it, the driver should be kept in staging. - -Patches should be submitted to: linux-media@vger.kernel.org. diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c index bffe2153b910..634d38c4bea1 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c @@ -444,7 +444,7 @@ static int vpfe_register_entities(struct vpfe_device *vpfe_dev) for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) /* * if entity has no pads (ex: amplifier), - * cant establish link + * can't establish link */ if (vpfe_dev->sd[i]->entity.num_pads) { ret = media_create_pad_link(&vpfe_dev->sd[i]->entity, diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 2be921cd0d55..bfc17de56b17 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -1,7 +1,9 @@ config VIDEO_IMX_MEDIA tristate "i.MX5/6 V4L2 media core driver" - depends on MEDIA_CONTROLLER && VIDEO_V4L2 && ARCH_MXC && IMX_IPUV3_CORE + depends on ARCH_MXC || COMPILE_TEST + depends on MEDIA_CONTROLLER && VIDEO_V4L2 && IMX_IPUV3_CORE depends on VIDEO_V4L2_SUBDEV_API + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE ---help--- diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index c6d7e80932ad..98923fc844ce 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -462,6 +462,7 @@ static int prp_registered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops prp_pad_ops = { + .init_cfg = imx_media_init_cfg, .enum_mbus_code = prp_enum_mbus_code, .get_fmt = prp_get_fmt, .set_fmt = prp_set_fmt, diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 143038c6c403..ae453fd422f0 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -923,7 +923,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_frame_size_enum *fse) { struct prp_priv *priv = sd_to_priv(sd); - struct v4l2_subdev_format format = {0}; + struct v4l2_subdev_format format = {}; const struct imx_media_pixfmt *cc; int ret = 0; @@ -1253,6 +1253,7 @@ static void prp_unregistered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops prp_pad_ops = { + .init_cfg = imx_media_init_cfg, .enum_mbus_code = prp_enum_mbus_code, .enum_frame_size = prp_enum_frame_size, .get_fmt = prp_get_fmt, diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index 576bdc7e9c42..0ccabe04b0e1 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -141,7 +141,8 @@ static int capture_enum_frameintervals(struct file *file, void *fh, fie.code = cc->codes[0]; - ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_interval, NULL, &fie); + ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_interval, + NULL, &fie); if (ret) return ret; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index eb7be5093a9d..1aa2be891704 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -400,6 +400,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_GREY: burst_size = 16; passthrough = true; passthrough_bits = 8; @@ -668,11 +669,10 @@ static int csi_setup(struct csi_priv *priv) static int csi_start(struct csi_priv *priv) { - struct v4l2_fract *output_fi, *input_fi; + struct v4l2_fract *output_fi; int ret; output_fi = &priv->frame_interval[priv->active_output_pad]; - input_fi = &priv->frame_interval[CSI_SINK_PAD]; if (priv->dest == IPU_CSI_DEST_IDMAC) { ret = csi_idmac_start(priv); @@ -1715,6 +1715,7 @@ static const struct v4l2_subdev_video_ops csi_video_ops = { }; static const struct v4l2_subdev_pad_ops csi_pad_ops = { + .init_cfg = imx_media_init_cfg, .enum_mbus_code = csi_enum_mbus_code, .enum_frame_size = csi_enum_frame_size, .enum_frame_interval = csi_enum_frame_interval, @@ -1797,6 +1798,10 @@ static int imx_csi_probe(struct platform_device *pdev) */ priv->dev->of_node = pdata->of_node; pinctrl = devm_pinctrl_get_select_default(priv->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(priv->vdev); + goto free; + } ret = v4l2_async_register_subdev(&priv->sd); if (ret) diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index 70833fe503b5..daf66c2d69ab 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -271,7 +271,7 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, int ipu_id) { struct imx_media_internal_sd_platformdata pdata; - struct platform_device_info pdevinfo = {0}; + struct platform_device_info pdevinfo = {}; struct platform_device *pdev; pdata.grp_id = isd->id->grp_id; diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 13dafa77a2eb..fab98fc0d6a0 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -93,7 +93,7 @@ static const struct imx_media_pixfmt rgb_formats[] = { .bpp = 32, .ipufmt = true, }, - /*** raw bayer formats start here ***/ + /*** raw bayer and grayscale formats start here ***/ { .fourcc = V4L2_PIX_FMT_SBGGR8, .codes = {MEDIA_BUS_FMT_SBGGR8_1X8}, @@ -162,6 +162,12 @@ static const struct imx_media_pixfmt rgb_formats[] = { .cs = IPUV3_COLORSPACE_RGB, .bpp = 16, .bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_GREY, + .codes = {MEDIA_BUS_FMT_Y8_1X8}, + .cs = IPUV3_COLORSPACE_RGB, + .bpp = 8, + .bayer = true, }, /*** * non-mbus RGB formats start here. NOTE! when adding non-mbus @@ -219,58 +225,63 @@ static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus, mbus->ycbcr_enc); } +static const +struct imx_media_pixfmt *__find_format(u32 fourcc, + u32 code, + bool allow_non_mbus, + bool allow_bayer, + const struct imx_media_pixfmt *array, + u32 array_size) +{ + const struct imx_media_pixfmt *fmt; + int i, j; + + for (i = 0; i < array_size; i++) { + fmt = &array[i]; + + if ((!allow_non_mbus && !fmt->codes[0]) || + (!allow_bayer && fmt->bayer)) + continue; + + if (fourcc && fmt->fourcc == fourcc) + return fmt; + + if (!code) + continue; + + for (j = 0; fmt->codes[j]; j++) { + if (code == fmt->codes[j]) + return fmt; + } + } + return NULL; +} + static const struct imx_media_pixfmt *find_format(u32 fourcc, u32 code, enum codespace_sel cs_sel, bool allow_non_mbus, bool allow_bayer) { - const struct imx_media_pixfmt *array, *fmt, *ret = NULL; - u32 array_size; - int i, j; + const struct imx_media_pixfmt *ret; switch (cs_sel) { case CS_SEL_YUV: - array_size = NUM_YUV_FORMATS; - array = yuv_formats; - break; + return __find_format(fourcc, code, allow_non_mbus, allow_bayer, + yuv_formats, NUM_YUV_FORMATS); case CS_SEL_RGB: - array_size = NUM_RGB_FORMATS; - array = rgb_formats; - break; + return __find_format(fourcc, code, allow_non_mbus, allow_bayer, + rgb_formats, NUM_RGB_FORMATS); case CS_SEL_ANY: - array_size = NUM_YUV_FORMATS + NUM_RGB_FORMATS; - array = yuv_formats; - break; + ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer, + yuv_formats, NUM_YUV_FORMATS); + if (ret) + return ret; + return __find_format(fourcc, code, allow_non_mbus, allow_bayer, + rgb_formats, NUM_RGB_FORMATS); default: return NULL; } - - for (i = 0; i < array_size; i++) { - if (cs_sel == CS_SEL_ANY && i >= NUM_YUV_FORMATS) - fmt = &rgb_formats[i - NUM_YUV_FORMATS]; - else - fmt = &array[i]; - - if ((!allow_non_mbus && fmt->codes[0] == 0) || - (!allow_bayer && fmt->bayer)) - continue; - - if (fourcc && fmt->fourcc == fourcc) { - ret = fmt; - goto out; - } - - for (j = 0; code && fmt->codes[j]; j++) { - if (code == fmt->codes[j]) { - ret = fmt; - goto out; - } - } - } - -out: - return ret; } static int enum_format(u32 *fourcc, u32 *code, u32 index, @@ -465,6 +476,35 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt); /* + * Initializes the TRY format to the ACTIVE format on all pads + * of a subdev. Can be used as the .init_cfg pad operation. + */ +int imx_media_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *mf_try; + struct v4l2_subdev_format format; + unsigned int pad; + int ret; + + for (pad = 0; pad < sd->entity.num_pads; pad++) { + memset(&format, 0, sizeof(format)); + + format.pad = pad; + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); + if (ret) + continue; + + mf_try = v4l2_subdev_get_try_format(sd, cfg, pad); + *mf_try = format.format; + } + + return 0; +} +EXPORT_SYMBOL_GPL(imx_media_init_cfg); + +/* * Check whether the field and colorimetry parameters in tryfmt are * uninitialized, and if so fill them with the values from fmt, * or if tryfmt->colorspace has been initialized, all the default diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 433474d58e3e..482250d47e7c 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -177,7 +177,7 @@ static int vdic_get_ipu_resources(struct vdic_priv *priv) priv->vdi_in_ch = ch; ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_NEXT); - if (IS_ERR(priv->vdi_in_ch_n)) { + if (IS_ERR(ch)) { err_chan = IPUV3_CHANNEL_MEM_VDI_NEXT; ret = PTR_ERR(ch); goto out_err_chan; @@ -909,6 +909,7 @@ static void vdic_unregistered(struct v4l2_subdev *sd) } static const struct v4l2_subdev_pad_ops vdic_pad_ops = { + .init_cfg = imx_media_init_cfg, .enum_mbus_code = vdic_enum_mbus_code, .get_fmt = vdic_get_fmt, .set_fmt = vdic_set_fmt, diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 2fd6dfdf37d6..e945e0ed6dd6 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -172,6 +172,8 @@ int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel); int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, u32 width, u32 height, u32 code, u32 field, const struct imx_media_pixfmt **cc); +int imx_media_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg); void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, struct v4l2_mbus_framefmt *fmt, bool ic_route); diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index 477d191c568b..ceeeb3069a02 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -447,6 +447,16 @@ out: return ret; } +static struct v4l2_mbus_framefmt * +__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_pad_config *cfg, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csi2->sd, cfg, pad); + else + return &csi2->format_mbus; +} + static int csi2_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *sdformat) @@ -456,11 +466,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd, mutex_lock(&csi2->lock); - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) - fmt = v4l2_subdev_get_try_format(&csi2->sd, cfg, - sdformat->pad); - else - fmt = &csi2->format_mbus; + fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which); sdformat->format = *fmt; @@ -474,6 +480,7 @@ static int csi2_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *sdformat) { struct csi2_dev *csi2 = sd_to_dev(sd); + struct v4l2_mbus_framefmt *fmt; int ret = 0; if (sdformat->pad >= CSI2_NUM_PADS) @@ -490,10 +497,9 @@ static int csi2_set_fmt(struct v4l2_subdev *sd, if (sdformat->pad != CSI2_SINK_PAD) sdformat->format = csi2->format_mbus; - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) - cfg->try_fmt = sdformat->format; - else - csi2->format_mbus = sdformat->format; + fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which); + + *fmt = sdformat->format; out: mutex_unlock(&csi2->lock); return ret; @@ -531,6 +537,7 @@ static const struct v4l2_subdev_video_ops csi2_video_ops = { }; static const struct v4l2_subdev_pad_ops csi2_pad_ops = { + .init_cfg = imx_media_init_cfg, .get_fmt = csi2_get_fmt, .set_fmt = csi2_set_fmt, }; diff --git a/drivers/staging/media/imx074/Kconfig b/drivers/staging/media/imx074/Kconfig new file mode 100644 index 000000000000..229cbeea580b --- /dev/null +++ b/drivers/staging/media/imx074/Kconfig @@ -0,0 +1,5 @@ +config SOC_CAMERA_IMX074 + tristate "imx074 support (DEPRECATED)" + depends on SOC_CAMERA && I2C + help + This driver supports IMX074 cameras from Sony diff --git a/drivers/staging/media/imx074/Makefile b/drivers/staging/media/imx074/Makefile new file mode 100644 index 000000000000..7d183574aa84 --- /dev/null +++ b/drivers/staging/media/imx074/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o diff --git a/drivers/staging/media/imx074/TODO b/drivers/staging/media/imx074/TODO new file mode 100644 index 000000000000..15580a4f950c --- /dev/null +++ b/drivers/staging/media/imx074/TODO @@ -0,0 +1,5 @@ +This sensor driver needs to be converted to a regular +v4l2 subdev driver. The soc_camera framework is deprecated and +will be removed in the future. Unless someone does this work this +sensor driver will be deleted when the soc_camera framework is +deleted. diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/staging/media/imx074/imx074.c index 77f1e0243d6e..77f1e0243d6e 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/staging/media/imx074/imx074.c diff --git a/drivers/staging/media/mt9t031/Kconfig b/drivers/staging/media/mt9t031/Kconfig new file mode 100644 index 000000000000..f48e06a03cdb --- /dev/null +++ b/drivers/staging/media/mt9t031/Kconfig @@ -0,0 +1,11 @@ +config SOC_CAMERA_IMX074 + tristate "imx074 support (DEPRECATED)" + depends on SOC_CAMERA && I2C + help + This driver supports IMX074 cameras from Sony + +config SOC_CAMERA_MT9T031 + tristate "mt9t031 support (DEPRECATED)" + depends on SOC_CAMERA && I2C + help + This driver supports MT9T031 cameras from Micron. diff --git a/drivers/staging/media/mt9t031/Makefile b/drivers/staging/media/mt9t031/Makefile new file mode 100644 index 000000000000..bfd24c442b33 --- /dev/null +++ b/drivers/staging/media/mt9t031/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o diff --git a/drivers/staging/media/mt9t031/TODO b/drivers/staging/media/mt9t031/TODO new file mode 100644 index 000000000000..15580a4f950c --- /dev/null +++ b/drivers/staging/media/mt9t031/TODO @@ -0,0 +1,5 @@ +This sensor driver needs to be converted to a regular +v4l2 subdev driver. The soc_camera framework is deprecated and +will be removed in the future. Unless someone does this work this +sensor driver will be deleted when the soc_camera framework is +deleted. diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/staging/media/mt9t031/mt9t031.c index 4802d30e47de..4802d30e47de 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/staging/media/mt9t031/mt9t031.c diff --git a/include/dt-bindings/media/tda1997x.h b/include/dt-bindings/media/tda1997x.h new file mode 100644 index 000000000000..bd9fbd718ec9 --- /dev/null +++ b/include/dt-bindings/media/tda1997x.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Gateworks Corporation + */ +#ifndef _DT_BINDINGS_MEDIA_TDA1997X_H +#define _DT_BINDINGS_MEDIA_TDA1997X_H + +/* TDA19973 36bit Video Port control registers */ +#define TDA1997X_VP36_35_32 0 +#define TDA1997X_VP36_31_28 1 +#define TDA1997X_VP36_27_24 2 +#define TDA1997X_VP36_23_20 3 +#define TDA1997X_VP36_19_16 4 +#define TDA1997X_VP36_15_12 5 +#define TDA1997X_VP36_11_08 6 +#define TDA1997X_VP36_07_04 7 +#define TDA1997X_VP36_03_00 8 + +/* TDA19971 24bit Video Port control registers */ +#define TDA1997X_VP24_V23_20 0 +#define TDA1997X_VP24_V19_16 1 +#define TDA1997X_VP24_V15_12 3 +#define TDA1997X_VP24_V11_08 4 +#define TDA1997X_VP24_V07_04 6 +#define TDA1997X_VP24_V03_00 7 + +/* Pin groups */ +#define TDA1997X_VP_OUT_EN 0x80 /* enable output group */ +#define TDA1997X_VP_HIZ 0x40 /* hi-Z output group when not used */ +#define TDA1997X_VP_SWP 0x10 /* pin-swap output group */ +#define TDA1997X_R_CR_CBCR_3_0 (0 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_R_CR_CBCR_7_4 (1 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_R_CR_CBCR_11_8 (2 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_B_CB_3_0 (3 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_B_CB_7_4 (4 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_B_CB_11_8 (5 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_G_Y_3_0 (6 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_G_Y_7_4 (7 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +#define TDA1997X_G_Y_11_8 (8 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ) +/* pinswapped groups */ +#define TDA1997X_R_CR_CBCR_3_0_S (TDA1997X_R_CR_CBCR_3_0 | TDA1997X_VP_SWAP) +#define TDA1997X_R_CR_CBCR_7_4_S (TDA1997X_R_CR_CBCR_7_4 | TDA1997X_VP_SWAP) +#define TDA1997X_R_CR_CBCR_11_8_S (TDA1997X_R_CR_CBCR_11_8 | TDA1997X_VP_SWAP) +#define TDA1997X_B_CB_3_0_S (TDA1997X_B_CB_3_0 | TDA1997X_VP_SWAP) +#define TDA1997X_B_CB_7_4_S (TDA1997X_B_CB_7_4 | TDA1997X_VP_SWAP) +#define TDA1997X_B_CB_11_8_S (TDA1997X_B_CB_11_8 | TDA1997X_VP_SWAP) +#define TDA1997X_G_Y_3_0_S (TDA1997X_G_Y_3_0 | TDA1997X_VP_SWAP) +#define TDA1997X_G_Y_7_4_S (TDA1997X_G_Y_7_4 | TDA1997X_VP_SWAP) +#define TDA1997X_G_Y_11_8_S (TDA1997X_G_Y_11_8 | TDA1997X_VP_SWAP) + +/* Audio bus DAI format */ +#define TDA1997X_I2S16 1 /* I2S 16bit */ +#define TDA1997X_I2S32 2 /* I2S 32bit */ +#define TDA1997X_SPDIF 3 /* SPDIF */ +#define TDA1997X_OBA 4 /* One Bit Audio */ +#define TDA1997X_DST 5 /* Direct Stream Transfer */ +#define TDA1997X_I2S16_HBR 6 /* HBR straight in I2S 16bit mode */ +#define TDA1997X_I2S16_HBR_DEMUX 7 /* HBR demux in I2S 16bit mode */ +#define TDA1997X_I2S32_HBR_DEMUX 8 /* HBR demux in I2S 32bit mode */ +#define TDA1997X_SPDIF_HBR_DEMUX 9 /* HBR demux in SPDIF mode */ + +/* Audio bus channel layout */ +#define TDA1997X_LAYOUT0 0 /* 2-channel */ +#define TDA1997X_LAYOUT1 1 /* 8-channel */ + +/* Audio bus clock */ +#define TDA1997X_ACLK_16FS 0 +#define TDA1997X_ACLK_32FS 1 +#define TDA1997X_ACLK_64FS 2 +#define TDA1997X_ACLK_128FS 3 +#define TDA1997X_ACLK_256FS 4 +#define TDA1997X_ACLK_512FS 5 + +#endif /* _DT_BINDINGS_MEDIA_TDA1997X_H */ diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h index 57ec319a7f44..cf0add70b0e7 100644 --- a/include/media/cec-notifier.h +++ b/include/media/cec-notifier.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-notifier.h - notify CEC drivers of physical address changes * * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk> * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef LINUX_CEC_NOTIFIER_H diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h index 83b3e17e0a07..ed16c6dde0ba 100644 --- a/include/media/cec-pin.h +++ b/include/media/cec-pin.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-pin.h - low-level CEC pin control * * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef LINUX_CEC_PIN_H diff --git a/include/media/cec.h b/include/media/cec.h index 7cdf71d7125a..580ab1042898 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec - HDMI Consumer Electronics Control support header * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _MEDIA_CEC_H @@ -104,7 +92,7 @@ struct cec_fh { wait_queue_head_t wait; struct mutex lock; struct list_head events[CEC_NUM_EVENTS]; /* queued events */ - u8 queued_events[CEC_NUM_EVENTS]; + u16 queued_events[CEC_NUM_EVENTS]; unsigned int total_queued_events; struct cec_event_entry core_events[CEC_NUM_CORE_EVENTS]; struct list_head msgs; /* queued messages */ @@ -129,6 +117,10 @@ struct cec_adap_ops { void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); void (*adap_free)(struct cec_adapter *adap); + /* Error injection callbacks */ + int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); + bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line); + /* High-level CEC message callback */ int (*received)(struct cec_adapter *adap, struct cec_msg *msg); }; @@ -201,6 +193,7 @@ struct cec_adapter { struct dentry *cec_dir; struct dentry *status_file; + struct dentry *error_inj_file; u16 phys_addrs[15]; u32 sequence; @@ -298,11 +291,12 @@ static inline void cec_received_msg(struct cec_adapter *adap, * * @adap: pointer to the cec adapter * @is_high: when true the CEC pin is high, otherwise it is low + * @dropped_events: when true some events were dropped * @ts: the timestamp for this event * */ -void cec_queue_pin_cec_event(struct cec_adapter *adap, - bool is_high, ktime_t ts); +void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, + bool dropped_events, ktime_t ts); /** * cec_queue_pin_hpd_event() - queue a pin event with a given timestamp. diff --git a/include/media/drv-intf/renesas-ceu.h b/include/media/drv-intf/renesas-ceu.h new file mode 100644 index 000000000000..52841d1b4763 --- /dev/null +++ b/include/media/drv-intf/renesas-ceu.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * renesas-ceu.h - Renesas CEU driver interface + * + * Copyright 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + */ + +#ifndef __MEDIA_DRV_INTF_RENESAS_CEU_H__ +#define __MEDIA_DRV_INTF_RENESAS_CEU_H__ + +#define CEU_MAX_SUBDEVS 2 + +struct ceu_async_subdev { + unsigned long flags; + unsigned char bus_width; + unsigned char bus_shift; + unsigned int i2c_adapter_id; + unsigned int i2c_address; +}; + +struct ceu_platform_data { + unsigned int num_subdevs; + struct ceu_async_subdev subdevs[CEU_MAX_SUBDEVS]; +}; + +#endif /* ___MEDIA_DRV_INTF_RENESAS_CEU_H__ */ diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h index 554db879527f..ee91516ad074 100644 --- a/include/media/dvbdev.h +++ b/include/media/dvbdev.h @@ -358,7 +358,61 @@ long dvb_generic_ioctl(struct file *file, int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int (*func)(struct file *file, unsigned int cmd, void *arg)); -/** generic DVB attach function. */ +#if IS_ENABLED(CONFIG_I2C) + +struct i2c_adapter; +struct i2c_client; +/** + * dvb_module_probe - helper routine to probe an I2C module + * + * @module_name: + * Name of the I2C module to be probed + * @name: + * Optional name for the I2C module. Used for debug purposes. + * If %NULL, defaults to @module_name. + * @adap: + * pointer to &struct i2c_adapter that describes the I2C adapter where + * the module will be bound. + * @addr: + * I2C address of the adapter, in 7-bit notation. + * @platform_data: + * Platform data to be passed to the I2C module probed. + * + * This function binds an I2C device into the DVB core. Should be used by + * all drivers that use I2C bus to control the hardware. A module bound + * with dvb_module_probe() should use dvb_module_release() to unbind. + * + * Return: + * On success, return an &struct i2c_client, pointing the the bound + * I2C device. %NULL otherwise. + * + * .. note:: + * + * In the past, DVB modules (mainly, frontends) were bound via dvb_attach() + * macro, with does an ugly hack, using I2C low level functions. Such + * usage is deprecated and will be removed soon. Instead, use this routine. + */ +struct i2c_client *dvb_module_probe(const char *module_name, + const char *name, + struct i2c_adapter *adap, + unsigned char addr, + void *platform_data); + +/** + * dvb_module_release - releases an I2C device allocated with + * dvb_module_probe(). + * + * @client: pointer to &struct i2c_client with the I2C client to be released. + * can be %NULL. + * + * This function should be used to free all resources reserved by + * dvb_module_probe() and unbinding the I2C hardware. + */ +void dvb_module_release(struct i2c_client *client); + +#endif /* CONFIG_I2C */ + +/* Legacy generic DVB attach function. */ #ifdef CONFIG_MEDIA_ATTACH /** @@ -371,6 +425,13 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, * the @FUNCTION function there, with @ARGS. * As it increments symbol usage cont, at unregister, dvb_detach() * should be called. + * + * .. note:: + * + * In the past, DVB modules (mainly, frontends) were bound via dvb_attach() + * macro, with does an ugly hack, using I2C low level functions. Such + * usage is deprecated and will be removed soon. Instead, you should use + * dvb_module_probe(). */ #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ @@ -402,6 +463,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, #define dvb_detach(FUNC) {} -#endif +#endif /* CONFIG_MEDIA_ATTACH */ #endif /* #ifndef _DVBDEV_H_ */ diff --git a/include/media/i2c/ad9389b.h b/include/media/i2c/ad9389b.h index 5ba9af869b8b..30f9ea9a1273 100644 --- a/include/media/i2c/ad9389b.h +++ b/include/media/i2c/ad9389b.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Analog Devices AD9389B/AD9889B video encoder driver header * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef AD9389B_H diff --git a/include/media/i2c/adv7511.h b/include/media/i2c/adv7511.h index 61c3d711cc69..1874c05f486f 100644 --- a/include/media/i2c/adv7511.h +++ b/include/media/i2c/adv7511.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Analog Devices ADV7511 HDMI Transmitter Device Driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef ADV7511_H diff --git a/include/media/i2c/adv7604.h b/include/media/i2c/adv7604.h index 2e6857dee0cc..77a9799128b6 100644 --- a/include/media/i2c/adv7604.h +++ b/include/media/i2c/adv7604.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * adv7604 - Analog Devices ADV7604 video decoder driver * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #ifndef _ADV7604_ diff --git a/include/media/i2c/adv7842.h b/include/media/i2c/adv7842.h index 7f53ada9bdf1..05e01f0dd3c2 100644 --- a/include/media/i2c/adv7842.h +++ b/include/media/i2c/adv7842.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * adv7842 - Analog Devices ADV7842 video decoder driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #ifndef _ADV7842_ diff --git a/include/media/i2c/mt9t112.h b/include/media/i2c/mt9t112.h index a43c74ab05ec..cc80d5cc2104 100644 --- a/include/media/i2c/mt9t112.h +++ b/include/media/i2c/mt9t112.h @@ -1,28 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* mt9t112 Camera * * Copyright (C) 2009 Renesas Solutions Corp. * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __MT9T112_H__ #define __MT9T112_H__ -#define MT9T112_FLAG_PCLK_RISING_EDGE (1 << 0) -#define MT9T112_FLAG_DATAWIDTH_8 (1 << 1) /* default width is 10 */ - struct mt9t112_pll_divider { u8 m, n; u8 p1, p2, p3, p4, p5, p6, p7; }; -/* - * mt9t112 camera info +/** + * mt9t112_platform_data - mt9t112 driver interface + * @flags: Sensor media bus configuration. + * @divider: Sensor PLL configuration */ -struct mt9t112_camera_info { +struct mt9t112_platform_data { +#define MT9T112_FLAG_PCLK_RISING_EDGE BIT(0) u32 flags; struct mt9t112_pll_divider divider; }; diff --git a/include/media/i2c/ov772x.h b/include/media/i2c/ov772x.h index 00dbb7c4feae..27d087baffc5 100644 --- a/include/media/i2c/ov772x.h +++ b/include/media/i2c/ov772x.h @@ -48,8 +48,10 @@ struct ov772x_edge_ctrl { .threshold = (t & OV772X_EDGE_THRESHOLD_MASK), \ } -/* - * ov772x camera info +/** + * ov772x_camera_info - ov772x driver interface structure + * @flags: Sensor configuration flags + * @edgectrl: Sensor edge control */ struct ov772x_camera_info { unsigned long flags; diff --git a/include/media/i2c/tc358743.h b/include/media/i2c/tc358743.h index 4513f2f9cfbc..b343650c2948 100644 --- a/include/media/i2c/tc358743.h +++ b/include/media/i2c/tc358743.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * tc358743 - Toshiba HDMI to CSI-2 bridge * - * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights - * reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * + * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ /* diff --git a/include/media/i2c/tda1997x.h b/include/media/i2c/tda1997x.h new file mode 100644 index 000000000000..c6c2a8ae413d --- /dev/null +++ b/include/media/i2c/tda1997x.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * tda1997x - NXP HDMI receiver + * + * Copyright 2017 Tim Harvey <tharvey@gateworks.com> + * + */ + +#ifndef _TDA1997X_ +#define _TDA1997X_ + +/* Platform Data */ +struct tda1997x_platform_data { + enum v4l2_mbus_type vidout_bus_type; + u32 vidout_bus_width; + u8 vidout_port_cfg[9]; + /* pin polarity (1=invert) */ + bool vidout_inv_de; + bool vidout_inv_hs; + bool vidout_inv_vs; + bool vidout_inv_pclk; + /* clock delays (0=-8, 1=-7 ... 15=+7 pixels) */ + u8 vidout_delay_hs; + u8 vidout_delay_vs; + u8 vidout_delay_de; + u8 vidout_delay_pclk; + /* sync selections (controls how sync pins are derived) */ + u8 vidout_sel_hs; + u8 vidout_sel_vs; + u8 vidout_sel_de; + + /* Audio Port Output */ + int audout_format; + u32 audout_mclk_fs; /* clock multiplier */ + u32 audout_width; /* 13 or 32 bit */ + u32 audout_layout; /* layout0=AP0 layout1=AP0,AP1,AP2,AP3 */ + bool audout_layoutauto; /* audio layout dictated by pkt header */ + bool audout_invert_clk; /* data valid on rising edge of BCLK */ + bool audio_auto_mute; /* enable hardware audio auto-mute */ +}; + +#endif diff --git a/include/media/i2c/ths7303.h b/include/media/i2c/ths7303.h index 834e2f95b630..95492d12786d 100644 --- a/include/media/i2c/ths7303.h +++ b/include/media/i2c/ths7303.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Texas Instruments Inc * @@ -7,15 +8,6 @@ * Hans Verkuil <hans.verkuil@cisco.com> * Lad, Prabhakar <prabhakar.lad@ti.com> * Martin Bugge <marbugge@cisco.com> - * - * 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 version 2. - * - * 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 THS7353_H diff --git a/include/media/i2c/tw9910.h b/include/media/i2c/tw9910.h index 90bcf1fa5421..bec8f7bce745 100644 --- a/include/media/i2c/tw9910.h +++ b/include/media/i2c/tw9910.h @@ -18,6 +18,9 @@ #include <media/soc_camera.h> +/** + * tw9910_mpout_pin - MPOUT (multi-purpose output) pin functions + */ enum tw9910_mpout_pin { TW9910_MPO_VLOSS, TW9910_MPO_HLOCK, @@ -29,6 +32,12 @@ enum tw9910_mpout_pin { TW9910_MPO_RTCO, }; +/** + * tw9910_video_info - tw9910 driver interface structure + * @buswidth: Parallel data bus width (8 or 16). + * @mpout: Selected function of MPOUT (multi-purpose output) pin. + * See &enum tw9910_mpout_pin + */ struct tw9910_video_info { unsigned long buswidth; enum tw9910_mpout_pin mpout; diff --git a/include/media/i2c/uda1342.h b/include/media/i2c/uda1342.h index cd156403a368..cb412d4c1088 100644 --- a/include/media/i2c/uda1342.h +++ b/include/media/i2c/uda1342.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * uda1342.h - definition for uda1342 inputs * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #ifndef _UDA1342_H_ diff --git a/include/media/rc-core.h b/include/media/rc-core.h index aed4272d47f5..6742fd86ff65 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -23,13 +23,6 @@ #include <linux/timer.h> #include <media/rc-map.h> -extern int rc_core_debug; -#define IR_dprintk(level, fmt, ...) \ -do { \ - if (rc_core_debug >= level) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ -} while (0) - /** * enum rc_driver_type - type of the RC driver. * @@ -341,7 +334,9 @@ void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse); int ir_raw_event_store_with_filter(struct rc_dev *dev, - struct ir_raw_event *ev); + struct ir_raw_event *ev); +int ir_raw_event_store_with_timeout(struct rc_dev *dev, + struct ir_raw_event *ev); void ir_raw_event_set_idle(struct rc_dev *dev, bool idle); int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 7046734b3895..bfa3017cecba 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -36,6 +36,7 @@ #define RC_PROTO_BIT_SHARP BIT_ULL(RC_PROTO_SHARP) #define RC_PROTO_BIT_XMP BIT_ULL(RC_PROTO_XMP) #define RC_PROTO_BIT_CEC BIT_ULL(RC_PROTO_CEC) +#define RC_PROTO_BIT_IMON BIT_ULL(RC_PROTO_IMON) #define RC_PROTO_BIT_ALL \ (RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \ @@ -49,7 +50,8 @@ RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ - RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC) + RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \ + RC_PROTO_BIT_IMON) /* All rc protocols for which we have decoders */ #define RC_PROTO_BIT_ALL_IR_DECODER \ (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ @@ -62,7 +64,7 @@ RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ - RC_PROTO_BIT_XMP) + RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON) #define RC_PROTO_BIT_ALL_IR_ENCODER \ (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ @@ -75,7 +77,7 @@ RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ RC_PROTO_BIT_RC6_6A_24 | \ RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \ - RC_PROTO_BIT_SHARP) + RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON) #define RC_SCANCODE_UNKNOWN(x) (x) #define RC_SCANCODE_OTHER(x) (x) @@ -211,6 +213,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" #define RC_MAP_IMON_MCE "rc-imon-mce" #define RC_MAP_IMON_PAD "rc-imon-pad" +#define RC_MAP_IMON_RSC "rc-imon-rsc" #define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e" #define RC_MAP_IT913X_V1 "rc-it913x-v1" #define RC_MAP_IT913X_V2 "rc-it913x-v2" diff --git a/include/media/tpg/v4l2-tpg.h b/include/media/tpg/v4l2-tpg.h index 823fadede7bf..eb191e85d363 100644 --- a/include/media/tpg/v4l2-tpg.h +++ b/include/media/tpg/v4l2-tpg.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * v4l2-tpg.h - Test Pattern Generator * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _V4L2_TPG_H_ diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index e0d95a7c5d48..54b689247937 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -316,21 +316,37 @@ void v4l_bound_align_image(unsigned int *width, unsigned int wmin, unsigned int salign); /** - * v4l2_find_nearest_format - find the nearest format size among a discrete - * set of resolutions. + * v4l2_find_nearest_size - Find the nearest size among a discrete + * set of resolutions contained in an array of a driver specific struct. * - * @sizes: array of &struct v4l2_frmsize_discrete image sizes. - * @num_sizes: length of @sizes array. + * @array: a driver specific array of image sizes + * @width_field: the name of the width field in the driver specific struct + * @height_field: the name of the height field in the driver specific struct * @width: desired width. * @height: desired height. * * Finds the closest resolution to minimize the width and height differences - * between what requested and the supported resolutions. + * between what requested and the supported resolutions. The size of the width + * and height fields in the driver specific must equal to that of u32, i.e. four + * bytes. + * + * Returns the best match or NULL if the length of the array is zero. */ -const struct v4l2_frmsize_discrete * -v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes, - const size_t num_sizes, - s32 width, s32 height); +#define v4l2_find_nearest_size(array, width_field, height_field, \ + width, height) \ + ({ \ + BUILD_BUG_ON(sizeof((array)->width_field) != sizeof(u32) || \ + sizeof((array)->height_field) != sizeof(u32)); \ + (typeof(&(*(array))))__v4l2_find_nearest_size( \ + (array), ARRAY_SIZE(array), sizeof(*(array)), \ + offsetof(typeof(*(array)), width_field), \ + offsetof(typeof(*(array)), height_field), \ + width, height); \ + }) +const void * +__v4l2_find_nearest_size(const void *array, size_t array_size, + size_t entry_size, size_t width_offset, + size_t height_offset, s32 width, s32 height); /** * v4l2_get_timestamp - helper routine to get a timestamp to be used when @@ -341,4 +357,30 @@ v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes, */ void v4l2_get_timestamp(struct timeval *tv); +/** + * v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by + * calling the g_frame_interval op of the given subdev. It only works + * for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the + * function name. + * + * @vdev: the struct video_device pointer. Used to determine the device caps. + * @sd: the sub-device pointer. + * @a: the VIDIOC_G_PARM argument. + */ +int v4l2_g_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a); + +/** + * v4l2_s_parm_cap - helper routine for vidioc_s_parm to fill this in by + * calling the s_frame_interval op of the given subdev. It only works + * for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the + * function name. + * + * @vdev: the struct video_device pointer. Used to determine the device caps. + * @sd: the sub-device pointer. + * @a: the VIDIOC_S_PARM argument. + */ +int v4l2_s_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a); + #endif /* V4L2_COMMON_H_ */ diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 05ebb9ef9e73..5b445b5654f7 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -761,8 +761,8 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed); * An error is returned if one of the range arguments is invalid for this * control type. * - * This function assumes that the control handler is not locked and will - * take the lock itself. + * The caller is responsible for acquiring the control handler mutex on behalf + * of __v4l2_ctrl_modify_range(). */ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def); diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 53f32022fabe..27634e8d2585 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -298,10 +298,10 @@ struct video_device * media_entity_to_video_device - Returns a &struct video_device from * the &struct media_entity embedded on it. * - * @entity: pointer to &struct media_entity + * @__entity: pointer to &struct media_entity */ -#define media_entity_to_video_device(entity) \ - container_of(entity, struct video_device, entity) +#define media_entity_to_video_device(__entity) \ + container_of(__entity, struct video_device, entity) /** * to_video_device - Returns a &struct video_device from the diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index ebf00e07a515..17cb27df1b81 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * v4l2-dv-timings - Internal header with dv-timings helper functions * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #ifndef __V4L2_DV_TIMINGS_H @@ -225,5 +212,26 @@ static inline bool can_reduce_fps(struct v4l2_bt_timings *bt) return false; } +/** + * struct v4l2_hdmi_rx_colorimetry - describes the HDMI colorimetry information + * @colorspace: enum v4l2_colorspace, the colorspace + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding + * @quantization: enum v4l2_quantization, colorspace quantization + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + */ +struct v4l2_hdmi_colorimetry { + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + enum v4l2_xfer_func xfer_func; +}; + +struct hdmi_avi_infoframe; +struct hdmi_vendor_infoframe; + +struct v4l2_hdmi_colorimetry +v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi, + const struct hdmi_vendor_infoframe *hdmi, + unsigned int height); #endif diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 62633e7d2630..ea73fef8bdc0 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -22,6 +22,7 @@ #define V4L2_FH_H #include <linux/fs.h> +#include <linux/kconfig.h> #include <linux/list.h> #include <linux/videodev2.h> diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h index d2125f0cc7cd..595c3ba05f23 100644 --- a/include/media/v4l2-rect.h +++ b/include/media/v4l2-rect.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * v4l2-rect.h - v4l2_rect helper functions * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _V4L2_RECT_H_ diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 980a86c08fce..9102d6ca566e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -224,6 +224,9 @@ struct v4l2_subdev_core_ops { * struct v4l2_subdev_tuner_ops - Callbacks used when v4l device was opened * in radio mode. * + * @standby: puts the tuner in standby mode. It will be woken up + * automatically the next time it is used. + * * @s_radio: callback that switches the tuner to radio mode. * drivers should explicitly call it when a tuner ops should * operate on radio mode, before being able to handle it. @@ -268,6 +271,7 @@ struct v4l2_subdev_core_ops { * } */ struct v4l2_subdev_tuner_ops { + int (*standby)(struct v4l2_subdev *sd); int (*s_radio)(struct v4l2_subdev *sd); int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); @@ -393,10 +397,6 @@ struct v4l2_mbus_frame_desc { * * @g_pixelaspect: callback to return the pixelaspect ratio. * - * @g_parm: callback for VIDIOC_G_PARM() ioctl handler code. - * - * @s_parm: callback for VIDIOC_S_PARM() ioctl handler code. - * * @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL() * ioctl handler code. * @@ -434,8 +434,6 @@ struct v4l2_subdev_video_ops { int (*g_input_status)(struct v4l2_subdev *sd, u32 *status); int (*s_stream)(struct v4l2_subdev *sd, int enable); int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect); - int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); - int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); int (*g_frame_interval)(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); int (*s_frame_interval)(struct v4l2_subdev *sd, @@ -867,6 +865,13 @@ struct v4l2_subdev { struct v4l2_subdev_platform_data *pdata; }; + +/** + * media_entity_to_v4l2_subdev - Returns a &struct v4l2_subdev from + * the &struct media_entity embedded in it. + * + * @ent: pointer to &struct media_entity. + */ #define media_entity_to_v4l2_subdev(ent) \ ({ \ typeof(ent) __me_sd_ent = (ent); \ @@ -876,14 +881,20 @@ struct v4l2_subdev { NULL; \ }) +/** + * vdev_to_v4l2_subdev - Returns a &struct v4l2_subdev from + * the &struct video_device embedded on it. + * + * @vdev: pointer to &struct video_device + */ #define vdev_to_v4l2_subdev(vdev) \ ((struct v4l2_subdev *)video_get_drvdata(vdev)) /** * struct v4l2_subdev_fh - Used for storing subdev information per file handle * - * @vfh: pointer to struct v4l2_fh - * @pad: pointer to v4l2_subdev_pad_config + * @vfh: pointer to &struct v4l2_fh + * @pad: pointer to &struct v4l2_subdev_pad_config */ struct v4l2_subdev_fh { struct v4l2_fh vfh; @@ -892,23 +903,70 @@ struct v4l2_subdev_fh { #endif }; +/** + * to_v4l2_subdev_fh - Returns a &struct v4l2_subdev_fh from + * the &struct v4l2_fh embedded on it. + * + * @fh: pointer to &struct v4l2_fh + */ #define to_v4l2_subdev_fh(fh) \ container_of(fh, struct v4l2_subdev_fh, vfh) #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -#define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name) \ - static inline struct rtype * \ - fun_name(struct v4l2_subdev *sd, \ - struct v4l2_subdev_pad_config *cfg, \ - unsigned int pad) \ - { \ - BUG_ON(pad >= sd->entity.num_pads); \ - return &cfg[pad].field_name; \ - } - -__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, v4l2_subdev_get_try_format, try_fmt) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_crop, try_crop) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_compose, try_compose) + +/** + * v4l2_subdev_get_try_format - ancillary routine to call + * &struct v4l2_subdev_pad_config->try_fmt + * + * @sd: pointer to &struct v4l2_subdev + * @cfg: pointer to &struct v4l2_subdev_pad_config array. + * @pad: index of the pad in the @cfg array. + */ +static inline struct v4l2_mbus_framefmt +*v4l2_subdev_get_try_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad) +{ + if (WARN_ON(pad >= sd->entity.num_pads)) + pad = 0; + return &cfg[pad].try_fmt; +} + +/** + * v4l2_subdev_get_try_crop - ancillary routine to call + * &struct v4l2_subdev_pad_config->try_crop + * + * @sd: pointer to &struct v4l2_subdev + * @cfg: pointer to &struct v4l2_subdev_pad_config array. + * @pad: index of the pad in the @cfg array. + */ +static inline struct v4l2_rect +*v4l2_subdev_get_try_crop(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad) +{ + if (WARN_ON(pad >= sd->entity.num_pads)) + pad = 0; + return &cfg[pad].try_crop; +} + +/** + * v4l2_subdev_get_try_crop - ancillary routine to call + * &struct v4l2_subdev_pad_config->try_compose + * + * @sd: pointer to &struct v4l2_subdev + * @cfg: pointer to &struct v4l2_subdev_pad_config array. + * @pad: index of the pad in the @cfg array. + */ +static inline struct v4l2_rect +*v4l2_subdev_get_try_compose(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad) +{ + if (WARN_ON(pad >= sd->entity.num_pads)) + pad = 0; + return &cfg[pad].try_compose; +} #endif extern const struct v4l2_file_operations v4l2_subdev_fops; @@ -1016,9 +1074,16 @@ void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops); -/* - * Call an ops of a v4l2_subdev, doing the right checks against - * NULL pointers. +/** + * v4l2_subdev_call - call an operation of a v4l2_subdev. + * + * @sd: pointer to the &struct v4l2_subdev + * @o: name of the element at &struct v4l2_subdev_ops that contains @f. + * Each element there groups a set of callbacks functions. + * @f: callback function that will be called if @cond matches. + * The callback functions are defined in groups, according to + * each element at &struct v4l2_subdev_ops. + * @args...: arguments for @f. * * Example: err = v4l2_subdev_call(sd, video, s_std, norm); */ @@ -1034,6 +1099,14 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, __result; \ }) +/** + * v4l2_subdev_has_op - Checks if a subdev defines a certain operation. + * + * @sd: pointer to the &struct v4l2_subdev + * @o: The group of callback functions in &struct v4l2_subdev_ops + * which @f is a part of. + * @f: callback function to be checked for its existence. + */ #define v4l2_subdev_has_op(sd, o, f) \ ((sd)->ops->o && (sd)->ops->o->f) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 5b6c541e4e1b..f6818f732f34 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -296,6 +296,9 @@ struct vb2_buffer { /** * struct vb2_ops - driver-specific callbacks. * + * These operations are not called from interrupt context except where + * mentioned specifically. + * * @queue_setup: called from VIDIOC_REQBUFS() and VIDIOC_CREATE_BUFS() * handlers before memory allocation. It can be called * twice: if the original number of requested buffers @@ -358,12 +361,12 @@ struct vb2_buffer { * driver can return an error if hardware fails, in that * case all buffers that have been already given by * the @buf_queue callback are to be returned by the driver - * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED. - * If you need a minimum number of buffers before you can - * start streaming, then set - * &vb2_queue->min_buffers_needed. If that is non-zero then - * @start_streaming won't be called until at least that - * many buffers have been queued up by userspace. + * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED + * or %VB2_BUF_STATE_REQUEUEING. If you need a minimum + * number of buffers before you can start streaming, then + * set &vb2_queue->min_buffers_needed. If that is non-zero + * then @start_streaming won't be called until at least + * that many buffers have been queued up by userspace. * @stop_streaming: called when 'streaming' state must be disabled; driver * should stop any DMA transactions or wait until they * finish and give back all buffers it got from &buf_queue @@ -601,10 +604,9 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); * @state: state of the buffer, as defined by &enum vb2_buffer_state. * Either %VB2_BUF_STATE_DONE if the operation finished * successfully, %VB2_BUF_STATE_ERROR if the operation finished - * with an error or %VB2_BUF_STATE_QUEUED if the driver wants to - * requeue buffers. If start_streaming fails then it should return - * buffers with state %VB2_BUF_STATE_QUEUED to put them back into - * the queue. + * with an error or any of %VB2_BUF_STATE_QUEUED or + * %VB2_BUF_STATE_REQUEUEING if the driver wants to + * requeue buffers (see below). * * This function should be called by the driver after a hardware operation on * a buffer is finished and the buffer may be returned to userspace. The driver @@ -613,9 +615,14 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); * to the driver by &vb2_ops->buf_queue can be passed to this function. * * While streaming a buffer can only be returned in state DONE or ERROR. - * The start_streaming op can also return them in case the DMA engine cannot - * be started for some reason. In that case the buffers should be returned with - * state QUEUED. + * The &vb2_ops->start_streaming op can also return them in case the DMA engine + * cannot be started for some reason. In that case the buffers should be + * returned with state QUEUED or REQUEUEING to put them back into the queue. + * + * %VB2_BUF_STATE_REQUEUEING is like %VB2_BUF_STATE_QUEUED, but it also calls + * &vb2_ops->buf_queue to queue buffers back to the driver. Note that calling + * vb2_buffer_done(..., VB2_BUF_STATE_REQUEUEING) from interrupt context will + * result in &vb2_ops->buf_queue being called in interrupt context as well. */ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state); diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h index 28e8a2a86e16..8997d5068c08 100644 --- a/include/uapi/linux/cec-funcs.h +++ b/include/uapi/linux/cec-funcs.h @@ -3,35 +3,6 @@ * cec - HDMI Consumer Electronics Control message functions * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _CEC_UAPI_FUNCS_H diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index b51fbe1941a7..20fe091b7e96 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -3,35 +3,6 @@ * cec - HDMI Consumer Electronics Control public header * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _CEC_UAPI_H diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h index f5bf06ecd87d..f189931042a7 100644 --- a/include/uapi/linux/lirc.h +++ b/include/uapi/linux/lirc.h @@ -185,6 +185,7 @@ struct lirc_scancode { * @RC_PROTO_SHARP: Sharp protocol * @RC_PROTO_XMP: XMP protocol * @RC_PROTO_CEC: CEC protocol + * @RC_PROTO_IMON: iMon Pad protocol */ enum rc_proto { RC_PROTO_UNKNOWN = 0, @@ -210,6 +211,7 @@ enum rc_proto { RC_PROTO_SHARP = 20, RC_PROTO_XMP = 21, RC_PROTO_CEC = 22, + RC_PROTO_IMON = 23, }; #endif diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index b9b9446095e9..c7e9a5cba24e 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_MEDIA_H @@ -42,108 +38,66 @@ struct media_device_info { __u32 reserved[31]; }; -#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31) - -/* - * Initial value to be used when a new entity is created - * Drivers should change it to something useful - */ -#define MEDIA_ENT_F_UNKNOWN 0x00000000 - /* * Base number ranges for entity functions * - * NOTE: those ranges and entity function number are phased just to - * make it easier to maintain this file. Userspace should not rely on - * the ranges to identify a group of function types, as newer - * functions can be added with any name within the full u32 range. - */ -#define MEDIA_ENT_F_BASE 0x00000000 -#define MEDIA_ENT_F_OLD_BASE 0x00010000 -#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000 - -/* - * DVB entities + * NOTE: Userspace should not rely on these ranges to identify a group + * of function types, as newer functions can be added with any name within + * the full u32 range. + * + * Some older functions use the MEDIA_ENT_F_OLD_*_BASE range. Do not + * change this, this is for backwards compatibility. When adding new + * functions always use MEDIA_ENT_F_BASE. */ -#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 0x00001) -#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 0x00002) -#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 0x00003) -#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 0x00004) +#define MEDIA_ENT_F_BASE 0x00000000 +#define MEDIA_ENT_F_OLD_BASE 0x00010000 +#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000 /* - * I/O entities + * Initial value to be used when a new entity is created + * Drivers should change it to something useful. */ -#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 0x01001) -#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 0x01002) -#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 0x01003) +#define MEDIA_ENT_F_UNKNOWN MEDIA_ENT_F_BASE /* - * Analog TV IF-PLL decoders - * - * It is a responsibility of the master/bridge drivers to create links - * for MEDIA_ENT_F_IF_VID_DECODER and MEDIA_ENT_F_IF_AUD_DECODER. + * Subdevs are initialized with MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN in order + * to preserve backward compatibility. Drivers must change to the proper + * subdev type before registering the entity. */ -#define MEDIA_ENT_F_IF_VID_DECODER (MEDIA_ENT_F_BASE + 0x02001) -#define MEDIA_ENT_F_IF_AUD_DECODER (MEDIA_ENT_F_BASE + 0x02002) +#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE /* - * Audio Entity Functions + * DVB entity functions */ -#define MEDIA_ENT_F_AUDIO_CAPTURE (MEDIA_ENT_F_BASE + 0x03001) -#define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002) -#define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003) +#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 0x00001) +#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 0x00002) +#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 0x00003) +#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 0x00004) /* - * Processing entities + * I/O entity functions */ -#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001) -#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002) -#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003) -#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004) -#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005) -#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006) +#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1) +#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 0x01001) +#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 0x01002) +#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 0x01003) /* - * Switch and bridge entitites + * Sensor functions */ -#define MEDIA_ENT_F_VID_MUX (MEDIA_ENT_F_BASE + 0x5001) -#define MEDIA_ENT_F_VID_IF_BRIDGE (MEDIA_ENT_F_BASE + 0x5002) +#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1) +#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2) +#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3) /* - * Connectors + * Video decoder functions */ -/* It is a responsibility of the entity drivers to add connectors and links */ -#ifdef __KERNEL__ - /* - * For now, it should not be used in userspace, as some - * definitions may change - */ - -#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 0x30001) -#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 0x30002) -#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 0x30003) - -#endif +#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4) +#define MEDIA_ENT_F_DTV_DECODER (MEDIA_ENT_F_BASE + 0x6001) /* - * Don't touch on those. The ranges MEDIA_ENT_F_OLD_BASE and - * MEDIA_ENT_F_OLD_SUBDEV_BASE are kept to keep backward compatibility - * with the legacy v1 API.The number range is out of range by purpose: - * several previously reserved numbers got excluded from this range. + * Digital TV, analog TV, radio and/or software defined radio tuner functions. * - * Subdevs are initialized with MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN, - * in order to preserve backward compatibility. - * Drivers must change to the proper subdev type before - * registering the entity. - */ - -#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1) - -#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1) -#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2) -#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3) -#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4) -/* * It is a responsibility of the master/bridge drivers to add connectors * and links for MEDIA_ENT_F_TUNER. Please notice that some old tuners * may require the usage of separate I2C chips to decode analog TV signals, @@ -151,49 +105,46 @@ struct media_device_info { * On such cases, the IF-PLL staging is mapped via one or two entities: * MEDIA_ENT_F_IF_VID_DECODER and/or MEDIA_ENT_F_IF_AUD_DECODER. */ -#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5) +#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5) -#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE +/* + * Analog TV IF-PLL decoder functions + * + * It is a responsibility of the master/bridge drivers to create links + * for MEDIA_ENT_F_IF_VID_DECODER and MEDIA_ENT_F_IF_AUD_DECODER. + */ +#define MEDIA_ENT_F_IF_VID_DECODER (MEDIA_ENT_F_BASE + 0x02001) +#define MEDIA_ENT_F_IF_AUD_DECODER (MEDIA_ENT_F_BASE + 0x02002) -#if !defined(__KERNEL__) || defined(__NEED_MEDIA_LEGACY_API) +/* + * Audio entity functions + */ +#define MEDIA_ENT_F_AUDIO_CAPTURE (MEDIA_ENT_F_BASE + 0x03001) +#define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002) +#define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003) /* - * Legacy symbols used to avoid userspace compilation breakages - * - * Those symbols map the entity function into types and should be - * used only on legacy programs for legacy hardware. Don't rely - * on those for MEDIA_IOC_G_TOPOLOGY. + * Processing entity functions */ -#define MEDIA_ENT_TYPE_SHIFT 16 -#define MEDIA_ENT_TYPE_MASK 0x00ff0000 -#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff - -/* End of the old subdev reserved numberspace */ -#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_T_DEVNODE | \ - MEDIA_ENT_SUBTYPE_MASK) - -#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE -#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L -#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) -#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) - -#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN -#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L -#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN -#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR -#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH -#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS -#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER -#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER +#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001) +#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002) +#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003) +#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004) +#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005) +#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006) -/* Obsolete symbol for media_version, no longer used in the kernel */ -#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0) -#endif +/* + * Switch and bridge entity functions + */ +#define MEDIA_ENT_F_VID_MUX (MEDIA_ENT_F_BASE + 0x5001) +#define MEDIA_ENT_F_VID_IF_BRIDGE (MEDIA_ENT_F_BASE + 0x5002) /* Entity flags */ -#define MEDIA_ENT_FL_DEFAULT (1 << 0) -#define MEDIA_ENT_FL_CONNECTOR (1 << 1) +#define MEDIA_ENT_FL_DEFAULT (1 << 0) +#define MEDIA_ENT_FL_CONNECTOR (1 << 1) + +/* OR with the entity id value to find the next entity */ +#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31) struct media_entity_desc { __u32 id; @@ -214,7 +165,7 @@ struct media_entity_desc { __u32 minor; } dev; -#if 1 +#if !defined(__KERNEL__) /* * TODO: this shouldn't have been added without * actual drivers that use this. When the first real driver @@ -225,24 +176,17 @@ struct media_entity_desc { * contain the subdevice information. In addition, struct dev * can only refer to a single device, and not to multiple (e.g. * pcm and mixer devices). - * - * So for now mark this as a to do. */ struct { __u32 card; __u32 device; __u32 subdevice; } alsa; -#endif -#if 1 /* * DEPRECATED: previous node specifications. Kept just to - * avoid breaking compilation, but media_entity_desc.dev - * should be used instead. In particular, alsa and dvb - * fields below are wrong: for all devnodes, there should - * be just major/minor inside the struct, as this is enough - * to represent any devnode, no matter what type. + * avoid breaking compilation. Use media_entity_desc.dev + * instead. */ struct { __u32 major; @@ -261,9 +205,9 @@ struct media_entity_desc { }; }; -#define MEDIA_PAD_FL_SINK (1 << 0) -#define MEDIA_PAD_FL_SOURCE (1 << 1) -#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2) +#define MEDIA_PAD_FL_SINK (1 << 0) +#define MEDIA_PAD_FL_SOURCE (1 << 1) +#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2) struct media_pad_desc { __u32 entity; /* entity ID */ @@ -272,13 +216,13 @@ struct media_pad_desc { __u32 reserved[2]; }; -#define MEDIA_LNK_FL_ENABLED (1 << 0) -#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) -#define MEDIA_LNK_FL_DYNAMIC (1 << 2) +#define MEDIA_LNK_FL_ENABLED (1 << 0) +#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) +#define MEDIA_LNK_FL_DYNAMIC (1 << 2) -#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28) -# define MEDIA_LNK_FL_DATA_LINK (0 << 28) -# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28) +#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28) +# define MEDIA_LNK_FL_DATA_LINK (0 << 28) +# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28) struct media_link_desc { struct media_pad_desc source; @@ -298,57 +242,47 @@ struct media_links_enum { /* Interface type ranges */ -#define MEDIA_INTF_T_DVB_BASE 0x00000100 -#define MEDIA_INTF_T_V4L_BASE 0x00000200 -#define MEDIA_INTF_T_ALSA_BASE 0x00000300 +#define MEDIA_INTF_T_DVB_BASE 0x00000100 +#define MEDIA_INTF_T_V4L_BASE 0x00000200 /* Interface types */ -#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE) -#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1) -#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2) -#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3) -#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4) - -#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE) -#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1) -#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2) -#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3) -#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4) -#define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5) - -#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE) -#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1) -#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2) -#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3) -#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4) -#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5) -#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6) -#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7) +#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE) +#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1) +#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2) +#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3) +#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4) + +#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE) +#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1) +#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2) +#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3) +#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4) +#define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5) + +#if defined(__KERNEL__) /* - * MC next gen API definitions + * Connector functions * - * NOTE: The declarations below are close to the MC RFC for the Media - * Controller, the next generation. Yet, there are a few adjustments - * to do, as we want to be able to have a functional API before - * the MC properties change. Those will be properly marked below. - * Please also notice that I removed "num_pads", "num_links", - * from the proposal, as a proper userspace application will likely - * use lists for pads/links, just as we intend to do in Kernelspace. - * The API definition should be freed from fields that are bound to - * some specific data structure. + * For now these should not be used in userspace, as some definitions may + * change. * - * FIXME: Currently, I opted to name the new types as "media_v2", as this - * won't cause any conflict with the Kernelspace namespace, nor with - * the previous kAPI media_*_desc namespace. This can be changed - * later, before the adding this API upstream. + * It is the responsibility of the entity drivers to add connectors and links. */ +#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 0x30001) +#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 0x30002) +#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 0x30003) +#endif + +/* + * MC next gen API definitions + */ struct media_v2_entity { __u32 id; - char name[64]; /* FIXME: move to a property? (RFC says so) */ + char name[64]; __u32 function; /* Main function of the entity */ __u32 reserved[6]; } __attribute__ ((packed)); @@ -408,10 +342,62 @@ struct media_v2_topology { /* ioctls */ -#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info) -#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc) -#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum) -#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc) -#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology) +#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info) +#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc) +#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum) +#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc) +#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology) + +#if !defined(__KERNEL__) || defined(__NEED_MEDIA_LEGACY_API) + +/* + * Legacy symbols used to avoid userspace compilation breakages. + * Do not use any of this in new applications! + * + * Those symbols map the entity function into types and should be + * used only on legacy programs for legacy hardware. Don't rely + * on those for MEDIA_IOC_G_TOPOLOGY. + */ +#define MEDIA_ENT_TYPE_SHIFT 16 +#define MEDIA_ENT_TYPE_MASK 0x00ff0000 +#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff + +#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_F_OLD_BASE | \ + MEDIA_ENT_SUBTYPE_MASK) + +#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE +#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L +#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_F_OLD_BASE + 2) +#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_F_OLD_BASE + 3) +#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_F_OLD_BASE + 4) + +#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN +#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L +#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN +#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR +#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH +#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS +#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER +#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER + +/* + * There is still no ALSA support in the media controller. These + * defines should not have been added and we leave them here only + * in case some application tries to use these defines. + */ +#define MEDIA_INTF_T_ALSA_BASE 0x00000300 +#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE) +#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1) +#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2) +#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3) +#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4) +#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5) +#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6) +#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7) + +/* Obsolete symbol for media_version, no longer used in the kernel */ +#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0) + +#endif #endif /* __LINUX_MEDIA_H */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index cbbb750d87d1..8d473c979b61 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -589,6 +589,98 @@ enum v4l2_vp8_golden_frame_sel { #define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP (V4L2_CID_MPEG_BASE+510) #define V4L2_CID_MPEG_VIDEO_VPX_PROFILE (V4L2_CID_MPEG_BASE+511) +/* CIDs for HEVC encoding. */ + +#define V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (V4L2_CID_MPEG_BASE + 600) +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (V4L2_CID_MPEG_BASE + 601) +#define V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (V4L2_CID_MPEG_BASE + 602) +#define V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (V4L2_CID_MPEG_BASE + 603) +#define V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (V4L2_CID_MPEG_BASE + 604) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (V4L2_CID_MPEG_BASE + 605) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE (V4L2_CID_MPEG_BASE + 606) +enum v4l2_mpeg_video_hevc_hier_coding_type { + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B = 0, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P = 1, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (V4L2_CID_MPEG_BASE + 607) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (V4L2_CID_MPEG_BASE + 608) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (V4L2_CID_MPEG_BASE + 609) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (V4L2_CID_MPEG_BASE + 610) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (V4L2_CID_MPEG_BASE + 611) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (V4L2_CID_MPEG_BASE + 612) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (V4L2_CID_MPEG_BASE + 613) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (V4L2_CID_MPEG_BASE + 614) +#define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_MPEG_BASE + 615) +enum v4l2_mpeg_video_hevc_profile { + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN = 0, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE = 1, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 = 2, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_LEVEL (V4L2_CID_MPEG_BASE + 616) +enum v4l2_mpeg_video_hevc_level { + V4L2_MPEG_VIDEO_HEVC_LEVEL_1 = 0, + V4L2_MPEG_VIDEO_HEVC_LEVEL_2 = 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 = 2, + V4L2_MPEG_VIDEO_HEVC_LEVEL_3 = 3, + V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 = 4, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4 = 5, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 = 6, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5 = 7, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 = 8, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 = 9, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6 = 10, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 = 11, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 = 12, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (V4L2_CID_MPEG_BASE + 617) +#define V4L2_CID_MPEG_VIDEO_HEVC_TIER (V4L2_CID_MPEG_BASE + 618) +enum v4l2_mpeg_video_hevc_tier { + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN = 0, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH = 1, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (V4L2_CID_MPEG_BASE + 619) +#define V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE + 620) +enum v4l2_cid_mpeg_video_hevc_loop_filter_mode { + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED = 0, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED = 1, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 621) +#define V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 622) +#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE (V4L2_CID_MPEG_BASE + 623) +enum v4l2_cid_mpeg_video_hevc_refresh_type { + V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE = 0, + V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA = 1, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR = 2, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (V4L2_CID_MPEG_BASE + 624) +#define V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (V4L2_CID_MPEG_BASE + 625) +#define V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (V4L2_CID_MPEG_BASE + 626) +#define V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (V4L2_CID_MPEG_BASE + 627) +#define V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (V4L2_CID_MPEG_BASE + 628) +#define V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (V4L2_CID_MPEG_BASE + 629) +#define V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (V4L2_CID_MPEG_BASE + 630) +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (V4L2_CID_MPEG_BASE + 631) +#define V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT (V4L2_CID_MPEG_BASE + 632) +#define V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (V4L2_CID_MPEG_BASE + 633) +#define V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (V4L2_CID_MPEG_BASE + 634) +#define V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD (V4L2_CID_MPEG_BASE + 635) +enum v4l2_cid_mpeg_video_hevc_size_of_length_field { + V4L2_MPEG_VIDEO_HEVC_SIZE_0 = 0, + V4L2_MPEG_VIDEO_HEVC_SIZE_1 = 1, + V4L2_MPEG_VIDEO_HEVC_SIZE_2 = 2, + V4L2_MPEG_VIDEO_HEVC_SIZE_4 = 3, +}; +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (V4L2_CID_MPEG_BASE + 636) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (V4L2_CID_MPEG_BASE + 637) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (V4L2_CID_MPEG_BASE + 638) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (V4L2_CID_MPEG_BASE + 639) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (V4L2_CID_MPEG_BASE + 640) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (V4L2_CID_MPEG_BASE + 641) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (V4L2_CID_MPEG_BASE + 642) +#define V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (V4L2_CID_MPEG_BASE + 643) +#define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (V4L2_CID_MPEG_BASE + 644) + /* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ #define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) #define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) @@ -657,7 +749,6 @@ enum v4l2_mpeg_mfc51_video_force_frame_type { #define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54) - /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h index 6e20de63ec59..123a231001a8 100644 --- a/include/uapi/linux/v4l2-mediabus.h +++ b/include/uapi/linux/v4l2-mediabus.h @@ -18,8 +18,8 @@ /** * struct v4l2_mbus_framefmt - frame format on the media bus - * @width: frame width - * @height: frame height + * @width: image width + * @height: image height * @code: data format code (from enum v4l2_mbus_pixelcode) * @field: used interlacing type (from enum v4l2_field) * @colorspace: colorspace of the data (from enum v4l2_colorspace) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 982718965180..600877be5c22 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -635,6 +635,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ #define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */ #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') /* VP9 */ +#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* HEVC aka H.265 */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ |