media updates for v4.17-rc1
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJaw1yeAAoJEAhfPr2O5OEVDDgQAIYpin6obedJOm7zIm741Q0S fS2FL2pygyvHlVtU20ERHgvM6aD5tujekpDM4+GNgnq0aAabxvqBvdohmHQjyVSw FgszgY6kQSnI8S4Oy9RB8H/MFRq7Wz9Qf+KmJh0SfuUoMzBe2A40yLjYQ+sAMJr9 mm0ijxxRpFYikVtIBgKDbjnx6wdkOs12M7YlJuI8N/tMBHMt+p2EfvqcX6GF725i sgLGcMsTJr1sUSyY8vnM2pAlKfZL2tZqigx5f9sB4UM7uHSw/oL/a/8I+t6Mju1X J1BD3L7UtTpwqO9sAR5BsJQ+0pAkXNOF+eLGs2p9rx4sO0DOLKoUptMI+YryvE86 /SOlTskSSAeX/rBFyZJw1zv0/9mdGrHoyCy0q/lfDkD/mQkrUJDDZ7GPLqZ9rLUe 2cXn1xMWB/soeR70oTyew0D2SZkp6y4DQr0Rwje7V8/SOWMmJvhaVIWhVIP9ZrS6 AvCS7WUYTTVIX+td2glnLkJ5SaXXJyRYv8Utp/TUrYvCFOX7wsk7F0pRY4PE4PeZ BL7Bl8H9l3HGWWhdqPvw+ETdJgcbq/IwVUcpuuEPjkhDZEqHz//vzwoPt1nT4v6M gfqfaW5LaYuj0MYYqyxZMDwP3FWk4SsQ0NZzmaFs+yfE17bcWUMuf3ZVJtjmLxzk RUo0E/7RZsrw7LkCy0KF =bzhS -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
Коммит
ef1c4a6fa9
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
};
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ This part describes the CEC: Consumer Electronics Control
|
|||
|
||||
cec-intro
|
||||
cec-funcs
|
||||
cec-pin-error-inj
|
||||
cec-header
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
============
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}|
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
92
MAINTAINERS
92
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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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]),
|
||||
|
|
|
@ -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]),
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci)
|
||||
return NULL;
|
||||
if (!ci) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
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");
|
|
@ -20,26 +20,13 @@
|
|||
|
||||
struct cxd2099_cfg {
|
||||
u32 bitrate;
|
||||
u8 adr;
|
||||
u8 polarity;
|
||||
u8 clock_mode;
|
||||
|
||||
u32 max_i2c;
|
||||
|
||||
/* ptr to DVB CA struct */
|
||||
struct dvb_ca_en50221 **en;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
|
@ -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.
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
|
@ -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"
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче