Pull media updates from Mauro Carvalho Chehab: - remove of atomisp driver from staging, as nobody would have time to dedicate huge efforts to fix all the problems there. Also, we have a feeling that the driver may not even run the way it is. - move Zoran driver to staging, in order to be either fixed to use VB2 and the proper media kAPIs or to be removed - remove videobuf-dvb driver, with is unused for a while - some V4L2 documentation fixes/improvements - new sensor drivers: imx258 and ov7251 - a new driver was added to allow using I2C transparent drivers - several improvements at the ddbridge driver - several improvements at the ISDB pt1 driver, making it more coherent with the DVB framework - added a new platform driver for MIPI CSI-2 RX: cadence - now, all media drivers can be compiled on x86 with COMPILE_TEST - almost all media drivers now build on non-x86 architectures with COMPILE_TEST - lots of other random stuff: cleanups, support for new board models, bug fixes, etc * tag 'media/v4.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (464 commits) media: omap2: fix compile-testing with FB_OMAP2=m media: media/radio/Kconfig: add back RADIO_ISA media: v4l2-ioctl.c: fix missing unlock in __video_do_ioctl() media: pxa_camera: ignore -ENOIOCTLCMD from v4l2_subdev_call for s_power media: arch: sh: migor: Fix TW9910 PDN gpio media: staging: tegra-vde: Reset VDE regardless of memory client resetting failure media: marvel-ccic: mmp: select VIDEOBUF2_VMALLOC/DMA_CONTIG media: marvel-ccic: allow ccic and mmp drivers to coexist media: uvcvideo: Prevent setting unavailable flags media: ddbridge: conditionally enable fast TS for stv0910-equipped bridges media: dvb-frontends/stv0910: make TS speed configurable media: ddbridge/mci: add identifiers to function definition arguments media: ddbridge/mci: protect against out-of-bounds array access in stop() media: rc: ensure input/lirc device can be opened after register media: rc: nuvoton: Keep device enabled during reg init media: rc: nuvoton: Keep track of users on CIR enable/disable media: rc: nuvoton: Tweak the interrupt enabling dance media: uvcvideo: Support realtek's UVC 1.5 device media: uvcvideo: Fix driver reference counting media: gspca_zc3xx: Enable short exposure times for OV7648 ...
Unified · Split
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | What: /sys/class/rc/ |
| 2 | 2 | Date: Apr 2010 |
| 3 | 3 | KernelVersion: 2.6.35 |
| 4 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 4 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 5 | 5 | Description: |
| 6 | 6 | The rc/ class sub-directory belongs to the Remote Controller |
| 7 | 7 | core and provides a sysfs interface for configuring infrared |
| @@ -10,7 +10,7 @@ Description: · 2 unmodified lines | ||
| 10 | 10 | What: /sys/class/rc/rcN/ |
| 11 | 11 | Date: Apr 2010 |
| 12 | 12 | KernelVersion: 2.6.35 |
| 13 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 13 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 14 | 14 | Description: |
| 15 | 15 | A /sys/class/rc/rcN directory is created for each remote |
| 16 | 16 | control receiver device where N is the number of the receiver. |
| @@ -18,7 +18,7 @@ Description: · 1 unmodified line | ||
| 18 | 18 | What: /sys/class/rc/rcN/protocols |
| 19 | 19 | Date: Jun 2010 |
| 20 | 20 | KernelVersion: 2.6.36 |
| 21 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 21 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 22 | 22 | Description: |
| 23 | 23 | Reading this file returns a list of available protocols, |
| 24 | 24 | something like: |
| @@ -36,7 +36,7 @@ Description: · 11 unmodified lines | ||
| 36 | 36 | What: /sys/class/rc/rcN/filter |
| 37 | 37 | Date: Jan 2014 |
| 38 | 38 | KernelVersion: 3.15 |
| 39 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 39 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 40 | 40 | Description: |
| 41 | 41 | Sets the scancode filter expected value. |
| 42 | 42 | Use in combination with /sys/class/rc/rcN/filter_mask to set the |
| @@ -49,7 +49,7 @@ Description: · 6 unmodified lines | ||
| 49 | 49 | What: /sys/class/rc/rcN/filter_mask |
| 50 | 50 | Date: Jan 2014 |
| 51 | 51 | KernelVersion: 3.15 |
| 52 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 52 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 53 | 53 | Description: |
| 54 | 54 | Sets the scancode filter mask of bits to compare. |
| 55 | 55 | Use in combination with /sys/class/rc/rcN/filter to set the bits |
| @@ -64,7 +64,7 @@ Description: · 8 unmodified lines | ||
| 64 | 64 | What: /sys/class/rc/rcN/wakeup_protocols |
| 65 | 65 | Date: Feb 2017 |
| 66 | 66 | KernelVersion: 4.11 |
| 67 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 67 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 68 | 68 | Description: |
| 69 | 69 | Reading this file returns a list of available protocols to use |
| 70 | 70 | for the wakeup filter, something like: |
| @@ -83,7 +83,7 @@ Description: · 12 unmodified lines | ||
| 83 | 83 | What: /sys/class/rc/rcN/wakeup_filter |
| 84 | 84 | Date: Jan 2014 |
| 85 | 85 | KernelVersion: 3.15 |
| 86 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 86 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 87 | 87 | Description: |
| 88 | 88 | Sets the scancode wakeup filter expected value. |
| 89 | 89 | Use in combination with /sys/class/rc/rcN/wakeup_filter_mask to |
| @@ -98,7 +98,7 @@ Description: · 8 unmodified lines | ||
| 98 | 98 | What: /sys/class/rc/rcN/wakeup_filter_mask |
| 99 | 99 | Date: Jan 2014 |
| 100 | 100 | KernelVersion: 3.15 |
| 101 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 101 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 102 | 102 | Description: |
| 103 | 103 | Sets the scancode wakeup filter mask of bits to compare. |
| 104 | 104 | Use in combination with /sys/class/rc/rcN/wakeup_filter to set |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | What: /sys/class/rc/rcN/wakeup_data |
| 2 | 2 | Date: Mar 2016 |
| 3 | 3 | KernelVersion: 4.6 |
| 4 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 4 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 5 | 5 | Description: |
| 6 | 6 | Reading this file returns the stored CIR wakeup sequence. |
| 7 | 7 | It starts with a pulse, followed by a space, pulse etc. |
| @@ -77,7 +77,7 @@ Description: Read/Write attribute file that controls memory scrubbing. · 76 unmodified lines | ||
| 77 | 77 | |
| 78 | 78 | What: /sys/devices/system/edac/mc/mc*/max_location |
| 79 | 79 | Date: April 2012 |
| 80 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 80 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 81 | 81 | linux-edac@vger.kernel.org |
| 82 | 82 | Description: This attribute file displays the information about the last |
| 83 | 83 | available memory slot in this memory controller. It is used by |
| @@ -85,7 +85,7 @@ Description: This attribute file displays the information about the last · 1 unmodified line | ||
| 85 | 85 | |
| 86 | 86 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/size |
| 87 | 87 | Date: April 2012 |
| 88 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 88 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 89 | 89 | linux-edac@vger.kernel.org |
| 90 | 90 | Description: This attribute file will display the size of dimm or rank. |
| 91 | 91 | For dimm*/size, this is the size, in MB of the DIMM memory |
| @@ -96,14 +96,14 @@ Description: This attribute file will display the size of dimm or rank. · 4 unmodified lines | ||
| 96 | 96 | |
| 97 | 97 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_dev_type |
| 98 | 98 | Date: April 2012 |
| 99 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 99 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 100 | 100 | linux-edac@vger.kernel.org |
| 101 | 101 | Description: This attribute file will display what type of DRAM device is |
| 102 | 102 | being utilized on this DIMM (x1, x2, x4, x8, ...). |
| 103 | 103 | |
| 104 | 104 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_edac_mode |
| 105 | 105 | Date: April 2012 |
| 106 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 106 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 107 | 107 | linux-edac@vger.kernel.org |
| 108 | 108 | Description: This attribute file will display what type of Error detection |
| 109 | 109 | and correction is being utilized. For example: S4ECD4ED would |
| @@ -111,7 +111,7 @@ Description: This attribute file will display what type of Error detection · 1 unmodified line | ||
| 111 | 111 | |
| 112 | 112 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_label |
| 113 | 113 | Date: April 2012 |
| 114 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 114 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 115 | 115 | linux-edac@vger.kernel.org |
| 116 | 116 | Description: This control file allows this DIMM to have a label assigned |
| 117 | 117 | to it. With this label in the module, when errors occur |
| @@ -126,14 +126,14 @@ Description: This control file allows this DIMM to have a label assigned · 8 unmodified lines | ||
| 126 | 126 | |
| 127 | 127 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_location |
| 128 | 128 | Date: April 2012 |
| 129 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 129 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 130 | 130 | linux-edac@vger.kernel.org |
| 131 | 131 | Description: This attribute file will display the location (csrow/channel, |
| 132 | 132 | branch/channel/slot or channel/slot) of the dimm or rank. |
| 133 | 133 | |
| 134 | 134 | What: /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_mem_type |
| 135 | 135 | Date: April 2012 |
| 136 | −Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 136 | +Contact: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 137 | 137 | linux-edac@vger.kernel.org |
| 138 | 138 | Description: This attribute file will display what type of memory is |
| 139 | 139 | currently on this csrow. Normally, either buffered or |
| @@ -0,0 +1,100 @@ | ||
| 1 | +Cadence MIPI-CSI2 RX controller | |
| 2 | +=============================== | |
| 3 | + | |
| 4 | +The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI | |
| 5 | +lanes in input, and 4 different pixel streams in output. | |
| 6 | + | |
| 7 | +Required properties: | |
| 8 | + - compatible: must be set to "cdns,csi2rx" and an SoC-specific compatible | |
| 9 | + - reg: base address and size of the memory mapped region | |
| 10 | + - clocks: phandles to the clocks driving the controller | |
| 11 | + - clock-names: must contain: | |
| 12 | + * sys_clk: main clock | |
| 13 | + * p_clk: register bank clock | |
| 14 | + * pixel_if[0-3]_clk: pixel stream output clock, one for each stream | |
| 15 | + implemented in hardware, between 0 and 3 | |
| 16 | + | |
| 17 | +Optional properties: | |
| 18 | + - phys: phandle to the external D-PHY, phy-names must be provided | |
| 19 | + - phy-names: must contain "dphy", if the implementation uses an | |
| 20 | + external D-PHY | |
| 21 | + | |
| 22 | +Required subnodes: | |
| 23 | + - ports: A ports node with one port child node per device input and output | |
| 24 | + port, in accordance with the video interface bindings defined in | |
| 25 | + Documentation/devicetree/bindings/media/video-interfaces.txt. The | |
| 26 | + port nodes are numbered as follows: | |
| 27 | + | |
| 28 | + Port Description | |
| 29 | + ----------------------------- | |
| 30 | + 0 CSI-2 input | |
| 31 | + 1 Stream 0 output | |
| 32 | + 2 Stream 1 output | |
| 33 | + 3 Stream 2 output | |
| 34 | + 4 Stream 3 output | |
| 35 | + | |
| 36 | + The stream output port nodes are optional if they are not | |
| 37 | + connected to anything at the hardware level or implemented | |
| 38 | + in the design.Since there is only one endpoint per port, | |
| 39 | + the endpoints are not numbered. | |
| 40 | + | |
| 41 | + | |
| 42 | +Example: | |
| 43 | + | |
| 44 | +csi2rx: csi-bridge@0d060000 { | |
| 45 | + compatible = "cdns,csi2rx"; | |
| 46 | + reg = <0x0d060000 0x1000>; | |
| 47 | + clocks = <&byteclock>, <&byteclock> | |
| 48 | + <&coreclock>, <&coreclock>, | |
| 49 | + <&coreclock>, <&coreclock>; | |
| 50 | + clock-names = "sys_clk", "p_clk", | |
| 51 | + "pixel_if0_clk", "pixel_if1_clk", | |
| 52 | + "pixel_if2_clk", "pixel_if3_clk"; | |
| 53 | + | |
| 54 | + ports { | |
| 55 | + #address-cells = <1>; | |
| 56 | + #size-cells = <0>; | |
| 57 | + | |
| 58 | + port@0 { | |
| 59 | + reg = <0>; | |
| 60 | + | |
| 61 | + csi2rx_in_sensor: endpoint { | |
| 62 | + remote-endpoint = <&sensor_out_csi2rx>; | |
| 63 | + clock-lanes = <0>; | |
| 64 | + data-lanes = <1 2>; | |
| 65 | + }; | |
| 66 | + }; | |
| 67 | + | |
| 68 | + port@1 { | |
| 69 | + reg = <1>; | |
| 70 | + | |
| 71 | + csi2rx_out_grabber0: endpoint { | |
| 72 | + remote-endpoint = <&grabber0_in_csi2rx>; | |
| 73 | + }; | |
| 74 | + }; | |
| 75 | + | |
| 76 | + port@2 { | |
| 77 | + reg = <2>; | |
| 78 | + | |
| 79 | + csi2rx_out_grabber1: endpoint { | |
| 80 | + remote-endpoint = <&grabber1_in_csi2rx>; | |
| 81 | + }; | |
| 82 | + }; | |
| 83 | + | |
| 84 | + port@3 { | |
| 85 | + reg = <3>; | |
| 86 | + | |
| 87 | + csi2rx_out_grabber2: endpoint { | |
| 88 | + remote-endpoint = <&grabber2_in_csi2rx>; | |
| 89 | + }; | |
| 90 | + }; | |
| 91 | + | |
| 92 | + port@4 { | |
| 93 | + reg = <4>; | |
| 94 | + | |
| 95 | + csi2rx_out_grabber3: endpoint { | |
| 96 | + remote-endpoint = <&grabber3_in_csi2rx>; | |
| 97 | + }; | |
| 98 | + }; | |
| 99 | + }; | |
| 100 | +}; | |
| @@ -0,0 +1,98 @@ | ||
| 1 | +Cadence MIPI-CSI2 TX controller | |
| 2 | +=============================== | |
| 3 | + | |
| 4 | +The Cadence MIPI-CSI2 TX controller is a CSI-2 bridge supporting up to | |
| 5 | +4 CSI lanes in output, and up to 4 different pixel streams in input. | |
| 6 | + | |
| 7 | +Required properties: | |
| 8 | + - compatible: must be set to "cdns,csi2tx" | |
| 9 | + - reg: base address and size of the memory mapped region | |
| 10 | + - clocks: phandles to the clocks driving the controller | |
| 11 | + - clock-names: must contain: | |
| 12 | + * esc_clk: escape mode clock | |
| 13 | + * p_clk: register bank clock | |
| 14 | + * pixel_if[0-3]_clk: pixel stream output clock, one for each stream | |
| 15 | + implemented in hardware, between 0 and 3 | |
| 16 | + | |
| 17 | +Optional properties | |
| 18 | + - phys: phandle to the D-PHY. If it is set, phy-names need to be set | |
| 19 | + - phy-names: must contain "dphy" | |
| 20 | + | |
| 21 | +Required subnodes: | |
| 22 | + - ports: A ports node with one port child node per device input and output | |
| 23 | + port, in accordance with the video interface bindings defined in | |
| 24 | + Documentation/devicetree/bindings/media/video-interfaces.txt. The | |
| 25 | + port nodes are numbered as follows. | |
| 26 | + | |
| 27 | + Port Description | |
| 28 | + ----------------------------- | |
| 29 | + 0 CSI-2 output | |
| 30 | + 1 Stream 0 input | |
| 31 | + 2 Stream 1 input | |
| 32 | + 3 Stream 2 input | |
| 33 | + 4 Stream 3 input | |
| 34 | + | |
| 35 | + The stream input port nodes are optional if they are not | |
| 36 | + connected to anything at the hardware level or implemented | |
| 37 | + in the design. Since there is only one endpoint per port, | |
| 38 | + the endpoints are not numbered. | |
| 39 | + | |
| 40 | +Example: | |
| 41 | + | |
| 42 | +csi2tx: csi-bridge@0d0e1000 { | |
| 43 | + compatible = "cdns,csi2tx"; | |
| 44 | + reg = <0x0d0e1000 0x1000>; | |
| 45 | + clocks = <&byteclock>, <&byteclock>, | |
| 46 | + <&coreclock>, <&coreclock>, | |
| 47 | + <&coreclock>, <&coreclock>; | |
| 48 | + clock-names = "p_clk", "esc_clk", | |
| 49 | + "pixel_if0_clk", "pixel_if1_clk", | |
| 50 | + "pixel_if2_clk", "pixel_if3_clk"; | |
| 51 | + | |
| 52 | + ports { | |
| 53 | + #address-cells = <1>; | |
| 54 | + #size-cells = <0>; | |
| 55 | + | |
| 56 | + port@0 { | |
| 57 | + reg = <0>; | |
| 58 | + | |
| 59 | + csi2tx_out: endpoint { | |
| 60 | + remote-endpoint = <&remote_in>; | |
| 61 | + clock-lanes = <0>; | |
| 62 | + data-lanes = <1 2>; | |
| 63 | + }; | |
| 64 | + }; | |
| 65 | + | |
| 66 | + port@1 { | |
| 67 | + reg = <1>; | |
| 68 | + | |
| 69 | + csi2tx_in_stream0: endpoint { | |
| 70 | + remote-endpoint = <&stream0_out>; | |
| 71 | + }; | |
| 72 | + }; | |
| 73 | + | |
| 74 | + port@2 { | |
| 75 | + reg = <2>; | |
| 76 | + | |
| 77 | + csi2tx_in_stream1: endpoint { | |
| 78 | + remote-endpoint = <&stream1_out>; | |
| 79 | + }; | |
| 80 | + }; | |
| 81 | + | |
| 82 | + port@3 { | |
| 83 | + reg = <3>; | |
| 84 | + | |
| 85 | + csi2tx_in_stream2: endpoint { | |
| 86 | + remote-endpoint = <&stream2_out>; | |
| 87 | + }; | |
| 88 | + }; | |
| 89 | + | |
| 90 | + port@4 { | |
| 91 | + reg = <4>; | |
| 92 | + | |
| 93 | + csi2tx_in_stream3: endpoint { | |
| 94 | + remote-endpoint = <&stream3_out>; | |
| 95 | + }; | |
| 96 | + }; | |
| 97 | + }; | |
| 98 | +}; | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +* Omnivision 1/7.5-Inch B&W VGA CMOS Digital Image Sensor | |
| 2 | + | |
| 3 | +The Omnivision OV7251 is a 1/7.5-Inch CMOS active pixel digital image sensor | |
| 4 | +with an active array size of 640H x 480V. It is programmable through a serial | |
| 5 | +I2C interface. | |
| 6 | + | |
| 7 | +Required Properties: | |
| 8 | +- compatible: Value should be "ovti,ov7251". | |
| 9 | +- clocks: Reference to the xclk clock. | |
| 10 | +- clock-names: Should be "xclk". | |
| 11 | +- clock-frequency: Frequency of the xclk clock. | |
| 12 | +- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds | |
| 13 | + to the hardware pin XSHUTDOWN which is physically active low. | |
| 14 | +- vdddo-supply: Chip digital IO regulator. | |
| 15 | +- vdda-supply: Chip analog regulator. | |
| 16 | +- vddd-supply: Chip digital core regulator. | |
| 17 | + | |
| 18 | +The device node shall contain one 'port' child node with a single 'endpoint' | |
| 19 | +subnode for its digital output video port, in accordance with the video | |
| 20 | +interface bindings defined in | |
| 21 | +Documentation/devicetree/bindings/media/video-interfaces.txt. | |
| 22 | + | |
| 23 | +Example: | |
| 24 | + | |
| 25 | + &i2c1 { | |
| 26 | + ... | |
| 27 | + | |
| 28 | + ov7251: camera-sensor@60 { | |
| 29 | + compatible = "ovti,ov7251"; | |
| 30 | + reg = <0x60>; | |
| 31 | + | |
| 32 | + enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; | |
| 33 | + pinctrl-names = "default"; | |
| 34 | + pinctrl-0 = <&camera_bw_default>; | |
| 35 | + | |
| 36 | + clocks = <&clks 200>; | |
| 37 | + clock-names = "xclk"; | |
| 38 | + clock-frequency = <24000000>; | |
| 39 | + | |
| 40 | + vdddo-supply = <&camera_dovdd_1v8>; | |
| 41 | + vdda-supply = <&camera_avdd_2v8>; | |
| 42 | + vddd-supply = <&camera_dvdd_1v2>; | |
| 43 | + | |
| 44 | + port { | |
| 45 | + ov7251_ep: endpoint { | |
| 46 | + clock-lanes = <1>; | |
| 47 | + data-lanes = <0>; | |
| 48 | + remote-endpoint = <&csi0_ep>; | |
| 49 | + }; | |
| 50 | + }; | |
| 51 | + }; | |
| 52 | + }; | |
| @@ -0,0 +1,40 @@ | ||
| 1 | +* Omnivision OV7720/OV7725 CMOS sensor | |
| 2 | + | |
| 3 | +The Omnivision OV7720/OV7725 sensor supports multiple resolutions output, | |
| 4 | +such as VGA, QVGA, and any size scaling down from CIF to 40x30. It also can | |
| 5 | +support the YUV422, RGB565/555/444, GRB422 or raw RGB output formats. | |
| 6 | + | |
| 7 | +Required Properties: | |
| 8 | +- compatible: shall be one of | |
| 9 | + "ovti,ov7720" | |
| 10 | + "ovti,ov7725" | |
| 11 | +- clocks: reference to the xclk input clock. | |
| 12 | + | |
| 13 | +Optional Properties: | |
| 14 | +- reset-gpios: reference to the GPIO connected to the RSTB pin which is | |
| 15 | + active low, if any. | |
| 16 | +- powerdown-gpios: reference to the GPIO connected to the PWDN pin which is | |
| 17 | + active high, if any. | |
| 18 | + | |
| 19 | +The device node shall contain one 'port' child node with one child 'endpoint' | |
| 20 | +subnode for its digital output video port, in accordance with the video | |
| 21 | +interface bindings defined in Documentation/devicetree/bindings/media/ | |
| 22 | +video-interfaces.txt. | |
| 23 | + | |
| 24 | +Example: | |
| 25 | + | |
| 26 | +&i2c0 { | |
| 27 | + ov772x: camera@21 { | |
| 28 | + compatible = "ovti,ov7725"; | |
| 29 | + reg = <0x21>; | |
| 30 | + reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_LOW>; | |
| 31 | + powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_LOW>; | |
| 32 | + clocks = <&xclk>; | |
| 33 | + | |
| 34 | + port { | |
| 35 | + ov772x_0: endpoint { | |
| 36 | + remote-endpoint = <&vcap1_in0>; | |
| 37 | + }; | |
| 38 | + }; | |
| 39 | + }; | |
| 40 | +}; | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +* Panasonic AMG88xx | |
| 2 | + | |
| 3 | +The Panasonic family of AMG88xx Grid-Eye sensors allow recording | |
| 4 | +8x8 10Hz video which consists of thermal datapoints | |
| 5 | + | |
| 6 | +Required Properties: | |
| 7 | + - compatible : Must be "panasonic,amg88xx" | |
| 8 | + - reg : i2c address of the device | |
| 9 | + | |
| 10 | +Example: | |
| 11 | + | |
| 12 | + i2c0@1c22000 { | |
| 13 | + ... | |
| 14 | + amg88xx@69 { | |
| 15 | + compatible = "panasonic,amg88xx"; | |
| 16 | + reg = <0x69>; | |
| 17 | + }; | |
| 18 | + ... | |
| 19 | + }; | |
| @@ -2,20 +2,28 @@ Renesas R-Car Video Input driver (rcar_vin) · 1 unmodified line | ||
| 2 | 2 | ------------------------------------------- |
| 3 | 3 | |
| 4 | 4 | The rcar_vin device provides video input capabilities for the Renesas R-Car |
| 5 | −family of devices. The current blocks are always slaves and suppot one input | |
| 6 | −channel which can be either RGB, YUYV or BT656. | |
| 5 | +family of devices. | |
| 6 | + | |
| 7 | +Each VIN instance has a single parallel input that supports RGB and YUV video, | |
| 8 | +with both external synchronization and BT.656 synchronization for the latter. | |
| 9 | +Depending on the instance the VIN input is connected to external SoC pins, or | |
| 10 | +on Gen3 platforms to a CSI-2 receiver. | |
| 7 | 11 | |
| 8 | 12 | - compatible: Must be one or more of the following |
| 9 | − - "renesas,vin-r8a7795" for the R8A7795 device | |
| 10 | − - "renesas,vin-r8a7794" for the R8A7794 device | |
| 11 | − - "renesas,vin-r8a7793" for the R8A7793 device | |
| 12 | − - "renesas,vin-r8a7792" for the R8A7792 device | |
| 13 | − - "renesas,vin-r8a7791" for the R8A7791 device | |
| 14 | − - "renesas,vin-r8a7790" for the R8A7790 device | |
| 15 | − - "renesas,vin-r8a7779" for the R8A7779 device | |
| 13 | + - "renesas,vin-r8a7743" for the R8A7743 device | |
| 14 | + - "renesas,vin-r8a7745" for the R8A7745 device | |
| 16 | 15 | - "renesas,vin-r8a7778" for the R8A7778 device |
| 17 | − - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 compatible device. | |
| 18 | − - "renesas,rcar-gen3-vin" for a generic R-Car Gen3 compatible device. | |
| 16 | + - "renesas,vin-r8a7779" for the R8A7779 device | |
| 17 | + - "renesas,vin-r8a7790" for the R8A7790 device | |
| 18 | + - "renesas,vin-r8a7791" for the R8A7791 device | |
| 19 | + - "renesas,vin-r8a7792" for the R8A7792 device | |
| 20 | + - "renesas,vin-r8a7793" for the R8A7793 device | |
| 21 | + - "renesas,vin-r8a7794" for the R8A7794 device | |
| 22 | + - "renesas,vin-r8a7795" for the R8A7795 device | |
| 23 | + - "renesas,vin-r8a7796" for the R8A7796 device | |
| 24 | + - "renesas,vin-r8a77970" for the R8A77970 device | |
| 25 | + - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 or RZ/G1 compatible | |
| 26 | + device. | |
| 19 | 27 | |
| 20 | 28 | When compatible with the generic version nodes must list the |
| 21 | 29 | SoC-specific version corresponding to the platform first |
| @@ -28,21 +36,38 @@ channel which can be either RGB, YUYV or BT656. · 6 unmodified lines | ||
| 28 | 36 | Additionally, an alias named vinX will need to be created to specify |
| 29 | 37 | which video input device this is. |
| 30 | 38 | |
| 31 | −The per-board settings: | |
| 39 | +The per-board settings Gen2 platforms: | |
| 32 | 40 | - port sub-node describing a single endpoint connected to the vin |
| 33 | 41 | as described in video-interfaces.txt[1]. Only the first one will |
| 34 | 42 | be considered as each vin interface has one input port. |
| 35 | 43 | |
| 36 | − These settings are used to work out video input format and widths | |
| 37 | − into the system. | |
| 44 | +The per-board settings Gen3 platforms: | |
| 38 | 45 | |
| 46 | +Gen3 platforms can support both a single connected parallel input source | |
| 47 | +from external SoC pins (port0) and/or multiple parallel input sources | |
| 48 | +from local SoC CSI-2 receivers (port1) depending on SoC. | |
| 39 | 49 | |
| 40 | −Device node example | |
| 41 | −------------------- | |
| 50 | +- renesas,id - ID number of the VIN, VINx in the documentation. | |
| 51 | +- ports | |
| 52 | + - port 0 - sub-node describing a single endpoint connected to the VIN | |
| 53 | + from external SoC pins described in video-interfaces.txt[1]. | |
| 54 | + Describing more then one endpoint in port 0 is invalid. Only VIN | |
| 55 | + instances that are connected to external pins should have port 0. | |
| 56 | + - port 1 - sub-nodes describing one or more endpoints connected to | |
| 57 | + the VIN from local SoC CSI-2 receivers. The endpoint numbers must | |
| 58 | + use the following schema. | |
| 42 | 59 | |
| 43 | − aliases { | |
| 44 | − vin0 = &vin0; | |
| 45 | − }; | |
| 60 | + - Endpoint 0 - sub-node describing the endpoint connected to CSI20 | |
| 61 | + - Endpoint 1 - sub-node describing the endpoint connected to CSI21 | |
| 62 | + - Endpoint 2 - sub-node describing the endpoint connected to CSI40 | |
| 63 | + - Endpoint 3 - sub-node describing the endpoint connected to CSI41 | |
| 64 | + | |
| 65 | +Device node example for Gen2 platforms | |
| 66 | +-------------------------------------- | |
| 67 | + | |
| 68 | + aliases { | |
| 69 | + vin0 = &vin0; | |
| 70 | + }; | |
| 46 | 71 | |
| 47 | 72 | vin0: vin@e6ef0000 { |
| 48 | 73 | compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin"; |
| @@ -52,8 +77,8 @@ Device node example · 3 unmodified lines | ||
| 52 | 77 | status = "disabled"; |
| 53 | 78 | }; |
| 54 | 79 | |
| 55 | −Board setup example (vin1 composite video input) | |
| 56 | −------------------------------------------------ | |
| 80 | +Board setup example for Gen2 platforms (vin1 composite video input) | |
| 81 | +------------------------------------------------------------------- | |
| 57 | 82 | |
| 58 | 83 | &i2c2 { |
| 59 | 84 | status = "okay"; |
| @@ -92,6 +117,77 @@ Board setup example (vin1 composite video input) · 32 unmodified lines | ||
| 92 | 117 | }; |
| 93 | 118 | }; |
| 94 | 119 | |
| 120 | +Device node example for Gen3 platforms | |
| 121 | +-------------------------------------- | |
| 122 | + | |
| 123 | + vin0: video@e6ef0000 { | |
| 124 | + compatible = "renesas,vin-r8a7795"; | |
| 125 | + reg = <0 0xe6ef0000 0 0x1000>; | |
| 126 | + interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>; | |
| 127 | + clocks = <&cpg CPG_MOD 811>; | |
| 128 | + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; | |
| 129 | + resets = <&cpg 811>; | |
| 130 | + renesas,id = <0>; | |
| 131 | + | |
| 132 | + ports { | |
| 133 | + #address-cells = <1>; | |
| 134 | + #size-cells = <0>; | |
| 135 | + | |
| 136 | + port@1 { | |
| 137 | + #address-cells = <1>; | |
| 138 | + #size-cells = <0>; | |
| 139 | + | |
| 140 | + reg = <1>; | |
| 141 | + | |
| 142 | + vin0csi20: endpoint@0 { | |
| 143 | + reg = <0>; | |
| 144 | + remote-endpoint= <&csi20vin0>; | |
| 145 | + }; | |
| 146 | + vin0csi21: endpoint@1 { | |
| 147 | + reg = <1>; | |
| 148 | + remote-endpoint= <&csi21vin0>; | |
| 149 | + }; | |
| 150 | + vin0csi40: endpoint@2 { | |
| 151 | + reg = <2>; | |
| 152 | + remote-endpoint= <&csi40vin0>; | |
| 153 | + }; | |
| 154 | + }; | |
| 155 | + }; | |
| 156 | + }; | |
| 95 | 157 | |
| 158 | + csi20: csi2@fea80000 { | |
| 159 | + compatible = "renesas,r8a7795-csi2"; | |
| 160 | + reg = <0 0xfea80000 0 0x10000>; | |
| 161 | + interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; | |
| 162 | + clocks = <&cpg CPG_MOD 714>; | |
| 163 | + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; | |
| 164 | + resets = <&cpg 714>; | |
| 165 | + | |
| 166 | + ports { | |
| 167 | + #address-cells = <1>; | |
| 168 | + #size-cells = <0>; | |
| 169 | + | |
| 170 | + port@0 { | |
| 171 | + reg = <0>; | |
| 172 | + csi20_in: endpoint { | |
| 173 | + clock-lanes = <0>; | |
| 174 | + data-lanes = <1>; | |
| 175 | + remote-endpoint = <&adv7482_txb>; | |
| 176 | + }; | |
| 177 | + }; | |
| 178 | + | |
| 179 | + port@1 { | |
| 180 | + #address-cells = <1>; | |
| 181 | + #size-cells = <0>; | |
| 182 | + | |
| 183 | + reg = <1>; | |
| 184 | + | |
| 185 | + csi20vin0: endpoint@0 { | |
| 186 | + reg = <0>; | |
| 187 | + remote-endpoint = <&vin0csi20>; | |
| 188 | + }; | |
| 189 | + }; | |
| 190 | + }; | |
| 191 | + }; | |
| 96 | 192 | |
| 97 | 193 | [1] video-interfaces.txt common video media interface |
| @@ -2,14 +2,15 @@ Renesas Capture Engine Unit (CEU) · 1 unmodified line | ||
| 2 | 2 | ---------------------------------------------- |
| 3 | 3 | |
| 4 | 4 | The Capture Engine Unit is the image capture interface found in the Renesas |
| 5 | −SH Mobile and RZ SoCs. | |
| 5 | +SH Mobile, R-Mobile and RZ SoCs. | |
| 6 | 6 | |
| 7 | 7 | The interface supports a single parallel input with data bus width of 8 or 16 |
| 8 | 8 | bits. |
| 9 | 9 | |
| 10 | 10 | Required properties: |
| 11 | −- compatible: Shall be "renesas,r7s72100-ceu" for CEU units found in RZ/A1H | |
| 12 | − and RZ/A1M SoCs. | |
| 11 | +- compatible: Shall be one of the following values: | |
| 12 | + "renesas,r7s72100-ceu" for CEU units found in RZ/A1H and RZ/A1M SoCs | |
| 13 | + "renesas,r8a7740-ceu" for CEU units found in R-Mobile A1 R8A7740 SoCs | |
| 13 | 14 | - reg: Registers address base and size. |
| 14 | 15 | - interrupts: The interrupt specifier. |
| 15 | 16 | |
| @@ -0,0 +1,101 @@ | ||
| 1 | +Renesas R-Car MIPI CSI-2 | |
| 2 | +------------------------ | |
| 3 | + | |
| 4 | +The R-Car CSI-2 receiver device provides MIPI CSI-2 capabilities for the | |
| 5 | +Renesas R-Car family of devices. It is used in conjunction with the | |
| 6 | +R-Car VIN module, which provides the video capture capabilities. | |
| 7 | + | |
| 8 | +Mandatory properties | |
| 9 | +-------------------- | |
| 10 | + - compatible: Must be one or more of the following | |
| 11 | + - "renesas,r8a7795-csi2" for the R8A7795 device. | |
| 12 | + - "renesas,r8a7796-csi2" for the R8A7796 device. | |
| 13 | + - "renesas,r8a77965-csi2" for the R8A77965 device. | |
| 14 | + - "renesas,r8a77970-csi2" for the R8A77970 device. | |
| 15 | + | |
| 16 | + - reg: the register base and size for the device registers | |
| 17 | + - interrupts: the interrupt for the device | |
| 18 | + - clocks: reference to the parent clock | |
| 19 | + | |
| 20 | +The device node shall contain two 'port' child nodes according to the | |
| 21 | +bindings defined in Documentation/devicetree/bindings/media/ | |
| 22 | +video-interfaces.txt. port@0 shall connect to the CSI-2 source. port@1 | |
| 23 | +shall connect to all the R-Car VIN modules that have a hardware | |
| 24 | +connection to the CSI-2 receiver. | |
| 25 | + | |
| 26 | +- port@0- Video source (mandatory) | |
| 27 | + - endpoint@0 - sub-node describing the endpoint that is the video source | |
| 28 | + | |
| 29 | +- port@1 - VIN instances (optional) | |
| 30 | + - One endpoint sub-node for every R-Car VIN instance which is connected | |
| 31 | + to the R-Car CSI-2 receiver. | |
| 32 | + | |
| 33 | +Example: | |
| 34 | + | |
| 35 | + csi20: csi2@fea80000 { | |
| 36 | + compatible = "renesas,r8a7796-csi2"; | |
| 37 | + reg = <0 0xfea80000 0 0x10000>; | |
| 38 | + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; | |
| 39 | + clocks = <&cpg CPG_MOD 714>; | |
| 40 | + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; | |
| 41 | + resets = <&cpg 714>; | |
| 42 | + | |
| 43 | + ports { | |
| 44 | + #address-cells = <1>; | |
| 45 | + #size-cells = <0>; | |
| 46 | + | |
| 47 | + port@0 { | |
| 48 | + #address-cells = <1>; | |
| 49 | + #size-cells = <0>; | |
| 50 | + | |
| 51 | + reg = <0>; | |
| 52 | + | |
| 53 | + csi20_in: endpoint@0 { | |
| 54 | + reg = <0>; | |
| 55 | + clock-lanes = <0>; | |
| 56 | + data-lanes = <1>; | |
| 57 | + remote-endpoint = <&adv7482_txb>; | |
| 58 | + }; | |
| 59 | + }; | |
| 60 | + | |
| 61 | + port@1 { | |
| 62 | + #address-cells = <1>; | |
| 63 | + #size-cells = <0>; | |
| 64 | + | |
| 65 | + reg = <1>; | |
| 66 | + | |
| 67 | + csi20vin0: endpoint@0 { | |
| 68 | + reg = <0>; | |
| 69 | + remote-endpoint = <&vin0csi20>; | |
| 70 | + }; | |
| 71 | + csi20vin1: endpoint@1 { | |
| 72 | + reg = <1>; | |
| 73 | + remote-endpoint = <&vin1csi20>; | |
| 74 | + }; | |
| 75 | + csi20vin2: endpoint@2 { | |
| 76 | + reg = <2>; | |
| 77 | + remote-endpoint = <&vin2csi20>; | |
| 78 | + }; | |
| 79 | + csi20vin3: endpoint@3 { | |
| 80 | + reg = <3>; | |
| 81 | + remote-endpoint = <&vin3csi20>; | |
| 82 | + }; | |
| 83 | + csi20vin4: endpoint@4 { | |
| 84 | + reg = <4>; | |
| 85 | + remote-endpoint = <&vin4csi20>; | |
| 86 | + }; | |
| 87 | + csi20vin5: endpoint@5 { | |
| 88 | + reg = <5>; | |
| 89 | + remote-endpoint = <&vin5csi20>; | |
| 90 | + }; | |
| 91 | + csi20vin6: endpoint@6 { | |
| 92 | + reg = <6>; | |
| 93 | + remote-endpoint = <&vin6csi20>; | |
| 94 | + }; | |
| 95 | + csi20vin7: endpoint@7 { | |
| 96 | + reg = <7>; | |
| 97 | + remote-endpoint = <&vin7csi20>; | |
| 98 | + }; | |
| 99 | + }; | |
| 100 | + }; | |
| 101 | + }; | |
| @@ -246,7 +246,10 @@ CEC_TX_STATUS_LOW_DRIVE: · 245 unmodified lines | ||
| 246 | 246 | CEC_TX_STATUS_ERROR: |
| 247 | 247 | some unspecified error occurred: this can be one of ARB_LOST |
| 248 | 248 | or LOW_DRIVE if the hardware cannot differentiate or something |
| 249 | − else entirely. | |
| 249 | + else entirely. Some hardware only supports OK and FAIL as the | |
| 250 | + result of a transmit, i.e. there is no way to differentiate | |
| 251 | + between the different possible errors. In that case map FAIL | |
| 252 | + to CEC_TX_STATUS_NACK and not to CEC_TX_STATUS_ERROR. | |
| 250 | 253 | |
| 251 | 254 | CEC_TX_STATUS_MAX_RETRIES: |
| 252 | 255 | could not transmit the message after trying multiple times. |
| @@ -231,26 +231,32 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). · 230 unmodified lines | ||
| 231 | 231 | - ``CEC_TX_STATUS_OK`` |
| 232 | 232 | - 0x01 |
| 233 | 233 | - The message was transmitted successfully. This is mutually |
| 234 | − exclusive with :ref:`CEC_TX_STATUS_MAX_RETRIES <CEC-TX-STATUS-MAX-RETRIES>`. Other bits can still | |
| 235 | − be set if earlier attempts met with failure before the transmit | |
| 236 | − was eventually successful. | |
| 234 | + exclusive with :ref:`CEC_TX_STATUS_MAX_RETRIES <CEC-TX-STATUS-MAX-RETRIES>`. | |
| 235 | + Other bits can still be set if earlier attempts met with failure before | |
| 236 | + the transmit was eventually successful. | |
| 237 | 237 | * .. _`CEC-TX-STATUS-ARB-LOST`: |
| 238 | 238 | |
| 239 | 239 | - ``CEC_TX_STATUS_ARB_LOST`` |
| 240 | 240 | - 0x02 |
| 241 | − - CEC line arbitration was lost. | |
| 241 | + - CEC line arbitration was lost, i.e. another transmit started at the | |
| 242 | + same time with a higher priority. Optional status, not all hardware | |
| 243 | + can detect this error condition. | |
| 242 | 244 | * .. _`CEC-TX-STATUS-NACK`: |
| 243 | 245 | |
| 244 | 246 | - ``CEC_TX_STATUS_NACK`` |
| 245 | 247 | - 0x04 |
| 246 | − - Message was not acknowledged. | |
| 248 | + - Message was not acknowledged. Note that some hardware cannot tell apart | |
| 249 | + a 'Not Acknowledged' status from other error conditions, i.e. the result | |
| 250 | + of a transmit is just OK or FAIL. In that case this status will be | |
| 251 | + returned when the transmit failed. | |
| 247 | 252 | * .. _`CEC-TX-STATUS-LOW-DRIVE`: |
| 248 | 253 | |
| 249 | 254 | - ``CEC_TX_STATUS_LOW_DRIVE`` |
| 250 | 255 | - 0x08 |
| 251 | 256 | - Low drive was detected on the CEC bus. This indicates that a |
| 252 | 257 | follower detected an error on the bus and requests a |
| 253 | − retransmission. | |
| 258 | + retransmission. Optional status, not all hardware can detect this | |
| 259 | + error condition. | |
| 254 | 260 | * .. _`CEC-TX-STATUS-ERROR`: |
| 255 | 261 | |
| 256 | 262 | - ``CEC_TX_STATUS_ERROR`` |
| @@ -258,14 +264,14 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). · 1 unmodified line | ||
| 258 | 264 | - Some error occurred. This is used for any errors that do not fit |
| 259 | 265 | ``CEC_TX_STATUS_ARB_LOST`` or ``CEC_TX_STATUS_LOW_DRIVE``, either because |
| 260 | 266 | the hardware could not tell which error occurred, or because the hardware |
| 261 | − tested for other conditions besides those two. | |
| 267 | + tested for other conditions besides those two. Optional status. | |
| 262 | 268 | * .. _`CEC-TX-STATUS-MAX-RETRIES`: |
| 263 | 269 | |
| 264 | 270 | - ``CEC_TX_STATUS_MAX_RETRIES`` |
| 265 | 271 | - 0x20 |
| 266 | 272 | - The transmit failed after one or more retries. This status bit is |
| 267 | − mutually exclusive with :ref:`CEC_TX_STATUS_OK <CEC-TX-STATUS-OK>`. Other bits can still | |
| 268 | − be set to explain which failures were seen. | |
| 273 | + mutually exclusive with :ref:`CEC_TX_STATUS_OK <CEC-TX-STATUS-OK>`. | |
| 274 | + Other bits can still be set to explain which failures were seen. | |
| 269 | 275 | |
| 270 | 276 | |
| 271 | 277 | .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| |
| @@ -62,7 +62,7 @@ Authors: · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | - Original author of the Digital TV API documentation. |
| 64 | 64 | |
| 65 | −- Carvalho Chehab, Mauro <m.chehab@kernel.org> | |
| 65 | +- Carvalho Chehab, Mauro <mchehab+samsung@kernel.org> | |
| 66 | 66 | |
| 67 | 67 | - Ported document to Docbook XML, addition of DVBv5 API, documentation gaps fix. |
| 68 | 68 | |
| @@ -18,7 +18,7 @@ Example dmesg output upon a driver registering w/LIRC: · 17 unmodified lines | ||
| 18 | 18 | .. code-block:: none |
| 19 | 19 | |
| 20 | 20 | $ dmesg |grep lirc_dev |
| 21 | − rc rc0: lirc_dev: driver mceusb registered at minor = 0 | |
| 21 | + rc rc0: lirc_dev: driver mceusb registered at minor = 0, raw IR receiver, raw IR transmitter | |
| 22 | 22 | |
| 23 | 23 | What you should see for a chardev: |
| 24 | 24 | |
| @@ -1,19 +1,23 @@ | ||
| 1 | 1 | .. -*- coding: utf-8; mode: rst -*- |
| 2 | 2 | |
| 3 | 3 | .. _lirc_set_rec_timeout: |
| 4 | +.. _lirc_get_rec_timeout: | |
| 4 | 5 | |
| 5 | −************************** | |
| 6 | −ioctl LIRC_SET_REC_TIMEOUT | |
| 7 | −************************** | |
| 6 | +*************************************************** | |
| 7 | +ioctl LIRC_GET_REC_TIMEOUT and LIRC_SET_REC_TIMEOUT | |
| 8 | +*************************************************** | |
| 8 | 9 | |
| 9 | 10 | Name |
| 10 | 11 | ==== |
| 11 | 12 | |
| 12 | −LIRC_SET_REC_TIMEOUT - sets the integer value for IR inactivity timeout. | |
| 13 | +LIRC_GET_REC_TIMEOUT/LIRC_SET_REC_TIMEOUT - Get/set the integer value for IR inactivity timeout. | |
| 13 | 14 | |
| 14 | 15 | Synopsis |
| 15 | 16 | ======== |
| 16 | 17 | |
| 18 | +.. c:function:: int ioctl( int fd, LIRC_GET_REC_TIMEOUT, __u32 *timeout ) | |
| 19 | + :name: LIRC_GET_REC_TIMEOUT | |
| 20 | + | |
| 17 | 21 | .. c:function:: int ioctl( int fd, LIRC_SET_REC_TIMEOUT, __u32 *timeout ) |
| 18 | 22 | :name: LIRC_SET_REC_TIMEOUT |
| 19 | 23 | |
| @@ -30,7 +34,7 @@ Arguments · 10 unmodified lines | ||
| 30 | 34 | Description |
| 31 | 35 | =========== |
| 32 | 36 | |
| 33 | −Sets the integer value for IR inactivity timeout. | |
| 37 | +Get and set the integer value for IR inactivity timeout. | |
| 34 | 38 | |
| 35 | 39 | If supported by the hardware, setting it to 0 disables all hardware timeouts |
| 36 | 40 | and data should be reported as soon as possible. If the exact value |
| @@ -41,6 +41,6 @@ applicable to all devices. · 40 unmodified lines | ||
| 41 | 41 | extended-controls |
| 42 | 42 | format |
| 43 | 43 | planar-apis |
| 44 | − crop | |
| 45 | 44 | selection-api |
| 45 | + crop | |
| 46 | 46 | streaming-par |
| @@ -2,9 +2,18 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | .. _crop: |
| 4 | 4 | |
| 5 | −************************************* | |
| 6 | −Image Cropping, Insertion and Scaling | |
| 7 | −************************************* | |
| 5 | +***************************************************** | |
| 6 | +Image Cropping, Insertion and Scaling -- the CROP API | |
| 7 | +***************************************************** | |
| 8 | + | |
| 9 | +.. note:: | |
| 10 | + | |
| 11 | + The CROP API is mostly superseded by the newer :ref:`SELECTION API | |
| 12 | + <selection-api>`. The new API should be preferred in most cases, | |
| 13 | + with the exception of pixel aspect ratio detection, which is | |
| 14 | + implemented by :ref:`VIDIOC_CROPCAP <VIDIOC_CROPCAP>` and has no | |
| 15 | + equivalent in the SELECTION API. See :ref:`selection-vs-crop` for a | |
| 16 | + comparison of the two APIs. | |
| 8 | 17 | |
| 9 | 18 | Some video capture devices can sample a subsection of the picture and |
| 10 | 19 | shrink or enlarge it to an image of arbitrary size. We call these |
| @@ -42,10 +51,9 @@ where applicable) will be fixed in this case. · 31 unmodified lines | ||
| 42 | 51 | |
| 43 | 52 | .. note:: |
| 44 | 53 | |
| 45 | − All capture and output devices must support the | |
| 46 | − :ref:`VIDIOC_CROPCAP <VIDIOC_CROPCAP>` ioctl such that applications | |
| 47 | − can determine if scaling takes place. | |
| 48 | − | |
| 54 | + All capture and output devices that support the CROP or SELECTION | |
| 55 | + API will also support the :ref:`VIDIOC_CROPCAP <VIDIOC_CROPCAP>` | |
| 56 | + ioctl. | |
| 49 | 57 | |
| 50 | 58 | Cropping Structures |
| 51 | 59 | =================== |
| @@ -1,34 +0,0 @@ | ||
| 1 | −.. -*- coding: utf-8; mode: rst -*- | |
| 2 | − | |
| 3 | −******************************** | |
| 4 | −Comparison with old cropping API | |
| 5 | −******************************** | |
| 6 | − | |
| 7 | −The selection API was introduced to cope with deficiencies of previous | |
| 8 | −:ref:`API <crop>`, that was designed to control simple capture | |
| 9 | −devices. Later the cropping API was adopted by video output drivers. The | |
| 10 | −ioctls are used to select a part of the display were the video signal is | |
| 11 | −inserted. It should be considered as an API abuse because the described | |
| 12 | −operation is actually the composing. The selection API makes a clear | |
| 13 | −distinction between composing and cropping operations by setting the | |
| 14 | −appropriate targets. The V4L2 API lacks any support for composing to and | |
| 15 | −cropping from an image inside a memory buffer. The application could | |
| 16 | −configure a capture device to fill only a part of an image by abusing | |
| 17 | −V4L2 API. Cropping a smaller image from a larger one is achieved by | |
| 18 | −setting the field ``bytesperline`` at struct | |
| 19 | −:c:type:`v4l2_pix_format`. | |
| 20 | −Introducing an image offsets could be done by modifying field ``m_userptr`` | |
| 21 | −at struct | |
| 22 | −:c:type:`v4l2_buffer` before calling | |
| 23 | −:ref:`VIDIOC_QBUF`. Those operations should be avoided because they are not | |
| 24 | −portable (endianness), and do not work for macroblock and Bayer formats | |
| 25 | −and mmap buffers. The selection API deals with configuration of buffer | |
| 26 | −cropping/composing in a clear, intuitive and portable way. Next, with | |
| 27 | −the selection API the concepts of the padded target and constraints | |
| 28 | −flags are introduced. Finally, struct :c:type:`v4l2_crop` | |
| 29 | −and struct :c:type:`v4l2_cropcap` have no reserved | |
| 30 | −fields. Therefore there is no way to extend their functionality. The new | |
| 31 | −struct :c:type:`v4l2_selection` provides a lot of place | |
| 32 | −for future extensions. Driver developers are encouraged to implement | |
| 33 | −only selection API. The former cropping API would be simulated using the | |
| 34 | −new one. | |
| @@ -41,7 +41,7 @@ The driver may further adjust the requested size and/or position · 40 unmodified lines | ||
| 41 | 41 | according to hardware limitations. |
| 42 | 42 | |
| 43 | 43 | Each capture device has a default source rectangle, given by the |
| 44 | −``V4L2_SEL_TGT_CROP_DEFAULT`` target. This rectangle shall over what the | |
| 44 | +``V4L2_SEL_TGT_CROP_DEFAULT`` target. This rectangle shall cover what the | |
| 45 | 45 | driver writer considers the complete picture. Drivers shall set the |
| 46 | 46 | active crop rectangle to the default when the driver is first loaded, |
| 47 | 47 | but not later. |
File renamed without changes.
File renamed without changes.
File renamed without changes.
| @@ -0,0 +1,39 @@ | ||
| 1 | +.. -*- coding: utf-8; mode: rst -*- | |
| 2 | + | |
| 3 | +.. _selection-vs-crop: | |
| 4 | + | |
| 5 | +******************************** | |
| 6 | +Comparison with old cropping API | |
| 7 | +******************************** | |
| 8 | + | |
| 9 | +The selection API was introduced to cope with deficiencies of the | |
| 10 | +older :ref:`CROP API <crop>`, that was designed to control simple | |
| 11 | +capture devices. Later the cropping API was adopted by video output | |
| 12 | +drivers. The ioctls are used to select a part of the display were the | |
| 13 | +video signal is inserted. It should be considered as an API abuse | |
| 14 | +because the described operation is actually the composing. The | |
| 15 | +selection API makes a clear distinction between composing and cropping | |
| 16 | +operations by setting the appropriate targets. | |
| 17 | + | |
| 18 | +The CROP API lacks any support for composing to and cropping from an | |
| 19 | +image inside a memory buffer. The application could configure a | |
| 20 | +capture device to fill only a part of an image by abusing V4L2 | |
| 21 | +API. Cropping a smaller image from a larger one is achieved by setting | |
| 22 | +the field ``bytesperline`` at struct :c:type:`v4l2_pix_format`. | |
| 23 | +Introducing an image offsets could be done by modifying field | |
| 24 | +``m_userptr`` at struct :c:type:`v4l2_buffer` before calling | |
| 25 | +:ref:`VIDIOC_QBUF <VIDIOC_QBUF>`. Those operations should be avoided | |
| 26 | +because they are not portable (endianness), and do not work for | |
| 27 | +macroblock and Bayer formats and mmap buffers. | |
| 28 | + | |
| 29 | +The selection API deals with configuration of buffer | |
| 30 | +cropping/composing in a clear, intuitive and portable way. Next, with | |
| 31 | +the selection API the concepts of the padded target and constraints | |
| 32 | +flags are introduced. Finally, struct :c:type:`v4l2_crop` and struct | |
| 33 | +:c:type:`v4l2_cropcap` have no reserved fields. Therefore there is no | |
| 34 | +way to extend their functionality. The new struct | |
| 35 | +:c:type:`v4l2_selection` provides a lot of place for future | |
| 36 | +extensions. | |
| 37 | + | |
| 38 | +Driver developers are encouraged to implement only selection API. The | |
| 39 | +former cropping API would be simulated using the new one. | |
| @@ -2,15 +2,15 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | .. _selection-api: |
| 4 | 4 | |
| 5 | −API for cropping, composing and scaling | |
| 6 | −======================================= | |
| 5 | +Cropping, composing and scaling -- the SELECTION API | |
| 6 | +==================================================== | |
| 7 | 7 | |
| 8 | 8 | |
| 9 | 9 | .. toctree:: |
| 10 | 10 | :maxdepth: 1 |
| 11 | 11 | |
| 12 | − selection-api-002 | |
| 13 | − selection-api-003 | |
| 14 | − selection-api-004 | |
| 15 | − selection-api-005 | |
| 16 | − selection-api-006 | |
| 12 | + selection-api-intro.rst | |
| 13 | + selection-api-targets.rst | |
| 14 | + selection-api-configuration.rst | |
| 15 | + selection-api-vs-crop-api.rst | |
| 16 | + selection-api-examples.rst | |
| @@ -1128,11 +1128,11 @@ · 1127 unmodified lines | ||
| 1128 | 1128 | </text> |
| 1129 | 1129 | </g> |
| 1130 | 1130 | <text transform="matrix(.96106 0 0 1.0405 48.571 195.53)" x="2438.062" y="1368.429" enable-background="new" font-size="50" style="line-height:125%"> |
| 1131 | − <tspan x="2438.062" y="1368.429">COMPOSE_BONDS</tspan> | |
| 1131 | + <tspan x="2438.062" y="1368.429">COMPOSE_BOUNDS</tspan> | |
| 1132 | 1132 | </text> |
| 1133 | 1133 | <g font-size="40"> |
| 1134 | 1134 | <text transform="translate(48.571 195.53)" x="8.082" y="1438.896" enable-background="new" style="line-height:125%"> |
| 1135 | − <tspan x="8.082" y="1438.896" font-size="50">CROP_BONDS</tspan> | |
| 1135 | + <tspan x="8.082" y="1438.896" font-size="50">CROP_BOUNDS</tspan> | |
| 1136 | 1136 | </text> |
| 1137 | 1137 | <text transform="translate(48.571 195.53)" x="1455.443" y="-26.808" enable-background="new" style="line-height:125%"> |
| 1138 | 1138 | <tspan x="1455.443" y="-26.808" font-size="50">overscan area</tspan> |
| @@ -45,7 +45,7 @@ Authors, in alphabetical order: · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | - Subdev selections API. |
| 47 | 47 | |
| 48 | −- Carvalho Chehab, Mauro <m.chehab@kernel.org> | |
| 48 | +- Carvalho Chehab, Mauro <mchehab+samsung@kernel.org> | |
| 49 | 49 | |
| 50 | 50 | - Documented libv4l, designed and added v4l2grab example, Remote Controller chapter. |
| 51 | 51 | |
| @@ -186,7 +186,7 @@ cx23885 cards list · 185 unmodified lines | ||
| 186 | 186 | |
| 187 | 187 | * - 43 |
| 188 | 188 | - Hauppauge ImpactVCB-e |
| 189 | − - 0070:7133 | |
| 189 | + - 0070:7133, 0070:7137 | |
| 190 | 190 | |
| 191 | 191 | * - 44 |
| 192 | 192 | - DViCO FusionHDTV DVB-T Dual Express2 |
| @@ -243,3 +243,19 @@ cx23885 cards list · 50 unmodified lines | ||
| 243 | 243 | * - 57 |
| 244 | 244 | - Hauppauge WinTV-QuadHD-ATSC |
| 245 | 245 | - 0070:6a18, 0070:6b18 |
| 246 | + | |
| 247 | + * - 58 | |
| 248 | + - Hauppauge WinTV-HVR-1265(161111) | |
| 249 | + - 0070:2a18 | |
| 250 | + | |
| 251 | + * - 59 | |
| 252 | + - Hauppauge WinTV-Starburst2 | |
| 253 | + - 0070:f02a | |
| 254 | + | |
| 255 | + * - 60 | |
| 256 | + - Hauppauge WinTV-QuadHD-DVB(885) | |
| 257 | + - | |
| 258 | + | |
| 259 | + * - 61 | |
| 260 | + - Hauppauge WinTV-QuadHD-ATSC(885) | |
| 261 | + - | |
| @@ -391,7 +391,7 @@ EM28xx cards list · 390 unmodified lines | ||
| 391 | 391 | * - 94 |
| 392 | 392 | - PCTV tripleStick (292e) |
| 393 | 393 | - em28178 |
| 394 | − - 2013:025f, 2040:0264 | |
| 394 | + - 2013:025f, 2013:0264, 2040:0264, 2040:8264, 2040:8268, 2040:8268 | |
| 395 | 395 | * - 95 |
| 396 | 396 | - Leadtek VC100 |
| 397 | 397 | - em2861 |
| @@ -411,12 +411,16 @@ EM28xx cards list · 13 unmodified lines | ||
| 411 | 411 | * - 99 |
| 412 | 412 | - Hauppauge WinTV-dualHD DVB |
| 413 | 413 | - em28174 |
| 414 | − - 2040:0265 | |
| 414 | + - 2040:0265, 2040:8265 | |
| 415 | 415 | * - 100 |
| 416 | 416 | - Hauppauge WinTV-dualHD 01595 ATSC/QAM |
| 417 | 417 | - em28174 |
| 418 | − - 2040:026d | |
| 418 | + - 2040:026d, 2040:826d | |
| 419 | 419 | * - 101 |
| 420 | 420 | - Terratec Cinergy H6 rev. 2 |
| 421 | 421 | - em2884 |
| 422 | 422 | - 0ccd:10b2 |
| 423 | + * - 102 | |
| 424 | + - :ZOLID HYBRID TV STICK | |
| 425 | + - em2882 | |
| 426 | + - | |
| @@ -3147,6 +3147,13 @@ S: Supported · 3146 unmodified lines | ||
| 3147 | 3147 | F: Documentation/filesystems/caching/cachefiles.txt |
| 3148 | 3148 | F: fs/cachefiles/ |
| 3149 | 3149 | |
| 3150 | +CADENCE MIPI-CSI2 BRIDGES | |
| 3151 | +M: Maxime Ripard <maxime.ripard@bootlin.com> | |
| 3152 | +L: linux-media@vger.kernel.org | |
| 3153 | +S: Maintained | |
| 3154 | +F: Documentation/devicetree/bindings/media/cdns,*.txt | |
| 3155 | +F: drivers/media/platform/cadence/cdns-csi2* | |
| 3156 | + | |
| 3150 | 3157 | CADET FM/AM RADIO RECEIVER DRIVER |
| 3151 | 3158 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 3152 | 3159 | L: linux-media@vger.kernel.org |
| @@ -8894,6 +8901,7 @@ L: linux-media@vger.kernel.org · 5741 unmodified lines | ||
| 8894 | 8901 | L: linux-renesas-soc@vger.kernel.org |
| 8895 | 8902 | T: git git://linuxtv.org/media_tree.git |
| 8896 | 8903 | S: Supported |
| 8904 | +F: Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt | |
| 8897 | 8905 | F: Documentation/devicetree/bindings/media/rcar_vin.txt |
| 8898 | 8906 | F: drivers/media/platform/rcar-vin/ |
| 8899 | 8907 | |
| @@ -10450,6 +10458,7 @@ T: git git://linuxtv.org/media_tree.git · 1550 unmodified lines | ||
| 10450 | 10458 | S: Odd fixes |
| 10451 | 10459 | F: drivers/media/i2c/ov772x.c |
| 10452 | 10460 | F: include/media/i2c/ov772x.h |
| 10461 | +F: Documentation/devicetree/bindings/media/i2c/ov772x.txt | |
| 10453 | 10462 | |
| 10454 | 10463 | OMNIVISION OV7740 SENSOR DRIVER |
| 10455 | 10464 | M: Wenyou Yang <wenyou.yang@microchip.com> |
| @@ -13163,6 +13172,13 @@ S: Maintained · 2707 unmodified lines | ||
| 13163 | 13172 | F: drivers/ssb/ |
| 13164 | 13173 | F: include/linux/ssb/ |
| 13165 | 13174 | |
| 13175 | +SONY IMX258 SENSOR DRIVER | |
| 13176 | +M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 13177 | +L: linux-media@vger.kernel.org | |
| 13178 | +T: git git://linuxtv.org/media_tree.git | |
| 13179 | +S: Maintained | |
| 13180 | +F: drivers/media/i2c/imx258.c | |
| 13181 | + | |
| 13166 | 13182 | SONY IMX274 SENSOR DRIVER |
| 13167 | 13183 | M: Leon Luo <leonl@leopardimaging.com> |
| 13168 | 13184 | L: linux-media@vger.kernel.org |
| @@ -13379,13 +13395,6 @@ L: stable@vger.kernel.org · 210 unmodified lines | ||
| 13379 | 13395 | S: Supported |
| 13380 | 13396 | F: Documentation/process/stable-kernel-rules.rst |
| 13381 | 13397 | |
| 13382 | −STAGING - ATOMISP DRIVER | |
| 13383 | −M: Alan Cox <alan@linux.intel.com> | |
| 13384 | −M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 13385 | −L: linux-media@vger.kernel.org | |
| 13386 | −S: Maintained | |
| 13387 | −F: drivers/staging/media/atomisp/ | |
| 13388 | − | |
| 13389 | 13398 | STAGING - COMEDI |
| 13390 | 13399 | M: Ian Abbott <abbotti@mev.co.uk> |
| 13391 | 13400 | M: H Hartley Sweeten <hsweeten@visionengravers.com> |
| @@ -15048,6 +15057,12 @@ L: linux-media@vger.kernel.org · 1656 unmodified lines | ||
| 15048 | 15057 | S: Maintained |
| 15049 | 15058 | F: drivers/media/platform/video-mux.c |
| 15050 | 15059 | |
| 15060 | +VIDEO I2C POLLING DRIVER | |
| 15061 | +M: Matt Ranostay <matt.ranostay@konsulko.com> | |
| 15062 | +L: linux-media@vger.kernel.org | |
| 15063 | +S: Maintained | |
| 15064 | +F: drivers/media/i2c/video-i2c.c | |
| 15065 | + | |
| 15051 | 15066 | VIDEOBUF2 FRAMEWORK |
| 15052 | 15067 | M: Pawel Osciak <pawel@osciak.com> |
| 15053 | 15068 | M: Marek Szyprowski <m.szyprowski@samsung.com> |
| @@ -15745,7 +15760,7 @@ L: linux-media@vger.kernel.org · 691 unmodified lines | ||
| 15745 | 15760 | W: http://mjpeg.sourceforge.net/driver-zoran/ |
| 15746 | 15761 | T: hg https://linuxtv.org/hg/v4l-dvb |
| 15747 | 15762 | S: Odd Fixes |
| 15748 | −F: drivers/media/pci/zoran/ | |
| 15763 | +F: drivers/staging/media/zoran/ | |
| 15749 | 15764 | |
| 15750 | 15765 | ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER |
| 15751 | 15766 | M: Minchan Kim <minchan@kernel.org> |
| @@ -359,7 +359,7 @@ static struct gpiod_lookup_table ov7725_gpios = { · 358 unmodified lines | ||
| 359 | 359 | static struct gpiod_lookup_table tw9910_gpios = { |
| 360 | 360 | .dev_id = "0-0045", |
| 361 | 361 | .table = { |
| 362 | − GPIO_LOOKUP("sh7722_pfc", GPIO_PTT2, "pdn", GPIO_ACTIVE_HIGH), | |
| 362 | + GPIO_LOOKUP("sh7722_pfc", GPIO_PTT2, "pdn", GPIO_ACTIVE_LOW), | |
| 363 | 363 | GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW), |
| 364 | 364 | }, |
| 365 | 365 | }; |
| @@ -691,6 +691,52 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = { · 690 unmodified lines | ||
| 691 | 691 | .atomic_disable = rcar_du_crtc_atomic_disable, |
| 692 | 692 | }; |
| 693 | 693 | |
| 694 | +static struct drm_crtc_state * | |
| 695 | +rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc) | |
| 696 | +{ | |
| 697 | + struct rcar_du_crtc_state *state; | |
| 698 | + struct rcar_du_crtc_state *copy; | |
| 699 | + | |
| 700 | + if (WARN_ON(!crtc->state)) | |
| 701 | + return NULL; | |
| 702 | + | |
| 703 | + state = to_rcar_crtc_state(crtc->state); | |
| 704 | + copy = kmemdup(state, sizeof(*state), GFP_KERNEL); | |
| 705 | + if (copy == NULL) | |
| 706 | + return NULL; | |
| 707 | + | |
| 708 | + __drm_atomic_helper_crtc_duplicate_state(crtc, ©->state); | |
| 709 | + | |
| 710 | + return ©->state; | |
| 711 | +} | |
| 712 | + | |
| 713 | +static void rcar_du_crtc_atomic_destroy_state(struct drm_crtc *crtc, | |
| 714 | + struct drm_crtc_state *state) | |
| 715 | +{ | |
| 716 | + __drm_atomic_helper_crtc_destroy_state(state); | |
| 717 | + kfree(to_rcar_crtc_state(state)); | |
| 718 | +} | |
| 719 | + | |
| 720 | +static void rcar_du_crtc_reset(struct drm_crtc *crtc) | |
| 721 | +{ | |
| 722 | + struct rcar_du_crtc_state *state; | |
| 723 | + | |
| 724 | + if (crtc->state) { | |
| 725 | + rcar_du_crtc_atomic_destroy_state(crtc, crtc->state); | |
| 726 | + crtc->state = NULL; | |
| 727 | + } | |
| 728 | + | |
| 729 | + state = kzalloc(sizeof(*state), GFP_KERNEL); | |
| 730 | + if (state == NULL) | |
| 731 | + return; | |
| 732 | + | |
| 733 | + state->crc.source = VSP1_DU_CRC_NONE; | |
| 734 | + state->crc.index = 0; | |
| 735 | + | |
| 736 | + crtc->state = &state->state; | |
| 737 | + crtc->state->crtc = crtc; | |
| 738 | +} | |
| 739 | + | |
| 694 | 740 | static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc) |
| 695 | 741 | { |
| 696 | 742 | struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); |
| @@ -710,15 +756,111 @@ static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc) · 13 unmodified lines | ||
| 710 | 756 | rcrtc->vblank_enable = false; |
| 711 | 757 | } |
| 712 | 758 | |
| 713 | −static const struct drm_crtc_funcs crtc_funcs = { | |
| 714 | − .reset = drm_atomic_helper_crtc_reset, | |
| 759 | +static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc, | |
| 760 | + const char *source_name, | |
| 761 | + size_t *values_cnt) | |
| 762 | +{ | |
| 763 | + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); | |
| 764 | + struct drm_modeset_acquire_ctx ctx; | |
| 765 | + struct drm_crtc_state *crtc_state; | |
| 766 | + struct drm_atomic_state *state; | |
| 767 | + enum vsp1_du_crc_source source; | |
| 768 | + unsigned int index = 0; | |
| 769 | + unsigned int i; | |
| 770 | + int ret; | |
| 771 | + | |
| 772 | + /* | |
| 773 | + * Parse the source name. Supported values are "plane%u" to compute the | |
| 774 | + * CRC on an input plane (%u is the plane ID), and "auto" to compute the | |
| 775 | + * CRC on the composer (VSP) output. | |
| 776 | + */ | |
| 777 | + if (!source_name) { | |
| 778 | + source = VSP1_DU_CRC_NONE; | |
| 779 | + } else if (!strcmp(source_name, "auto")) { | |
| 780 | + source = VSP1_DU_CRC_OUTPUT; | |
| 781 | + } else if (strstarts(source_name, "plane")) { | |
| 782 | + source = VSP1_DU_CRC_PLANE; | |
| 783 | + | |
| 784 | + ret = kstrtouint(source_name + strlen("plane"), 10, &index); | |
| 785 | + if (ret < 0) | |
| 786 | + return ret; | |
| 787 | + | |
| 788 | + for (i = 0; i < rcrtc->vsp->num_planes; ++i) { | |
| 789 | + if (index == rcrtc->vsp->planes[i].plane.base.id) { | |
| 790 | + index = i; | |
| 791 | + break; | |
| 792 | + } | |
| 793 | + } | |
| 794 | + | |
| 795 | + if (i >= rcrtc->vsp->num_planes) | |
| 796 | + return -EINVAL; | |
| 797 | + } else { | |
| 798 | + return -EINVAL; | |
| 799 | + } | |
| 800 | + | |
| 801 | + *values_cnt = 1; | |
| 802 | + | |
| 803 | + /* Perform an atomic commit to set the CRC source. */ | |
| 804 | + drm_modeset_acquire_init(&ctx, 0); | |
| 805 | + | |
| 806 | + state = drm_atomic_state_alloc(crtc->dev); | |
| 807 | + if (!state) { | |
| 808 | + ret = -ENOMEM; | |
| 809 | + goto unlock; | |
| 810 | + } | |
| 811 | + | |
| 812 | + state->acquire_ctx = &ctx; | |
| 813 | + | |
| 814 | +retry: | |
| 815 | + crtc_state = drm_atomic_get_crtc_state(state, crtc); | |
| 816 | + if (!IS_ERR(crtc_state)) { | |
| 817 | + struct rcar_du_crtc_state *rcrtc_state; | |
| 818 | + | |
| 819 | + rcrtc_state = to_rcar_crtc_state(crtc_state); | |
| 820 | + rcrtc_state->crc.source = source; | |
| 821 | + rcrtc_state->crc.index = index; | |
| 822 | + | |
| 823 | + ret = drm_atomic_commit(state); | |
| 824 | + } else { | |
| 825 | + ret = PTR_ERR(crtc_state); | |
| 826 | + } | |
| 827 | + | |
| 828 | + if (ret == -EDEADLK) { | |
| 829 | + drm_atomic_state_clear(state); | |
| 830 | + drm_modeset_backoff(&ctx); | |
| 831 | + goto retry; | |
| 832 | + } | |
| 833 | + | |
| 834 | + drm_atomic_state_put(state); | |
| 835 | + | |
| 836 | +unlock: | |
| 837 | + drm_modeset_drop_locks(&ctx); | |
| 838 | + drm_modeset_acquire_fini(&ctx); | |
| 839 | + | |
| 840 | + return 0; | |
| 841 | +} | |
| 842 | + | |
| 843 | +static const struct drm_crtc_funcs crtc_funcs_gen2 = { | |
| 844 | + .reset = rcar_du_crtc_reset, | |
| 845 | + .destroy = drm_crtc_cleanup, | |
| 846 | + .set_config = drm_atomic_helper_set_config, | |
| 847 | + .page_flip = drm_atomic_helper_page_flip, | |
| 848 | + .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state, | |
| 849 | + .atomic_destroy_state = rcar_du_crtc_atomic_destroy_state, | |
| 850 | + .enable_vblank = rcar_du_crtc_enable_vblank, | |
| 851 | + .disable_vblank = rcar_du_crtc_disable_vblank, | |
| 852 | +}; | |
| 853 | + | |
| 854 | +static const struct drm_crtc_funcs crtc_funcs_gen3 = { | |
| 855 | + .reset = rcar_du_crtc_reset, | |
| 715 | 856 | .destroy = drm_crtc_cleanup, |
| 716 | 857 | .set_config = drm_atomic_helper_set_config, |
| 717 | 858 | .page_flip = drm_atomic_helper_page_flip, |
| 718 | − .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | |
| 719 | − .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | |
| 859 | + .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state, | |
| 860 | + .atomic_destroy_state = rcar_du_crtc_atomic_destroy_state, | |
| 720 | 861 | .enable_vblank = rcar_du_crtc_enable_vblank, |
| 721 | 862 | .disable_vblank = rcar_du_crtc_disable_vblank, |
| 863 | + .set_crc_source = rcar_du_crtc_set_crc_source, | |
| 722 | 864 | }; |
| 723 | 865 | |
| 724 | 866 | /* ----------------------------------------------------------------------------- |
| @@ -822,8 +964,10 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, · 97 unmodified lines | ||
| 822 | 964 | else |
| 823 | 965 | primary = &rgrp->planes[swindex % 2].plane; |
| 824 | 966 | |
| 825 | − ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary, | |
| 826 | − NULL, &crtc_funcs, NULL); | |
| 967 | + ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary, NULL, | |
| 968 | + rcdu->info->gen <= 2 ? | |
| 969 | + &crtc_funcs_gen2 : &crtc_funcs_gen3, | |
| 970 | + NULL); | |
| 827 | 971 | if (ret < 0) |
| 828 | 972 | return ret; |
| 829 | 973 | |
| @@ -21,6 +21,8 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <drm/drmP.h> |
| 22 | 22 | #include <drm/drm_crtc.h> |
| 23 | 23 | |
| 24 | +#include <media/vsp1.h> | |
| 25 | + | |
| 24 | 26 | struct rcar_du_group; |
| 25 | 27 | struct rcar_du_vsp; |
| 26 | 28 | |
| @@ -69,6 +71,19 @@ struct rcar_du_crtc { · 42 unmodified lines | ||
| 69 | 71 | |
| 70 | 72 | #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) |
| 71 | 73 | |
| 74 | +/** | |
| 75 | + * struct rcar_du_crtc_state - Driver-specific CRTC state | |
| 76 | + * @state: base DRM CRTC state | |
| 77 | + * @crc: CRC computation configuration | |
| 78 | + */ | |
| 79 | +struct rcar_du_crtc_state { | |
| 80 | + struct drm_crtc_state state; | |
| 81 | + | |
| 82 | + struct vsp1_du_crc_config crc; | |
| 83 | +}; | |
| 84 | + | |
| 85 | +#define to_rcar_crtc_state(s) container_of(s, struct rcar_du_crtc_state, state) | |
| 86 | + | |
| 72 | 87 | enum rcar_du_output { |
| 73 | 88 | RCAR_DU_OUTPUT_DPAD0, |
| 74 | 89 | RCAR_DU_OUTPUT_DPAD1, |
| @@ -32,7 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "rcar_du_kms.h" |
| 33 | 33 | #include "rcar_du_vsp.h" |
| 34 | 34 | |
| 35 | −static void rcar_du_vsp_complete(void *private, bool completed) | |
| 35 | +static void rcar_du_vsp_complete(void *private, bool completed, u32 crc) | |
| 36 | 36 | { |
| 37 | 37 | struct rcar_du_crtc *crtc = private; |
| 38 | 38 | |
| @@ -41,6 +41,8 @@ static void rcar_du_vsp_complete(void *private, bool completed) · 2 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | if (completed) |
| 43 | 43 | rcar_du_crtc_finish_page_flip(crtc); |
| 44 | + | |
| 45 | + drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc); | |
| 44 | 46 | } |
| 45 | 47 | |
| 46 | 48 | void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) |
| @@ -103,7 +105,13 @@ void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) · 56 unmodified lines | ||
| 103 | 105 | |
| 104 | 106 | void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) |
| 105 | 107 | { |
| 106 | − vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe); | |
| 108 | + struct vsp1_du_atomic_pipe_config cfg = { { 0, } }; | |
| 109 | + struct rcar_du_crtc_state *state; | |
| 110 | + | |
| 111 | + state = to_rcar_crtc_state(crtc->crtc.state); | |
| 112 | + cfg.crc = state->crc; | |
| 113 | + | |
| 114 | + vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); | |
| 107 | 115 | } |
| 108 | 116 | |
| 109 | 117 | /* Keep the two tables in sync. */ |
| @@ -78,13 +78,13 @@ config MEDIA_SDR_SUPPORT · 77 unmodified lines | ||
| 78 | 78 | Say Y when you have a software defined radio device. |
| 79 | 79 | |
| 80 | 80 | config MEDIA_CEC_SUPPORT |
| 81 | − bool "HDMI CEC support" | |
| 82 | − ---help--- | |
| 83 | − Enable support for HDMI CEC (Consumer Electronics Control), | |
| 84 | − which is an optional HDMI feature. | |
| 81 | + bool "HDMI CEC support" | |
| 82 | + ---help--- | |
| 83 | + Enable support for HDMI CEC (Consumer Electronics Control), | |
| 84 | + which is an optional HDMI feature. | |
| 85 | 85 | |
| 86 | − Say Y when you have an HDMI receiver, transmitter or a USB CEC | |
| 87 | − adapter that supports HDMI CEC. | |
| 86 | + Say Y when you have an HDMI receiver, transmitter or a USB CEC | |
| 87 | + adapter that supports HDMI CEC. | |
| 88 | 88 | |
| 89 | 89 | source "drivers/media/cec/Kconfig" |
| 90 | 90 | |
| @@ -339,12 +339,19 @@ static void cec_data_cancel(struct cec_data *data) · 338 unmodified lines | ||
| 339 | 339 | data->adap->transmit_queue_sz--; |
| 340 | 340 | } |
| 341 | 341 | |
| 342 | − /* Mark it as an error */ | |
| 343 | − data->msg.tx_ts = ktime_get_ns(); | |
| 344 | − data->msg.tx_status |= CEC_TX_STATUS_ERROR | | |
| 345 | − CEC_TX_STATUS_MAX_RETRIES; | |
| 346 | − data->msg.tx_error_cnt++; | |
| 347 | − data->attempts = 0; | |
| 342 | + if (data->msg.tx_status & CEC_TX_STATUS_OK) { | |
| 343 | + /* Mark the canceled RX as a timeout */ | |
| 344 | + data->msg.rx_ts = ktime_get_ns(); | |
| 345 | + data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; | |
| 346 | + } else { | |
| 347 | + /* Mark the canceled TX as an error */ | |
| 348 | + data->msg.tx_ts = ktime_get_ns(); | |
| 349 | + data->msg.tx_status |= CEC_TX_STATUS_ERROR | | |
| 350 | + CEC_TX_STATUS_MAX_RETRIES; | |
| 351 | + data->msg.tx_error_cnt++; | |
| 352 | + data->attempts = 0; | |
| 353 | + } | |
| 354 | + | |
| 348 | 355 | /* Queue transmitted message for monitoring purposes */ |
| 349 | 356 | cec_queue_msg_monitor(data->adap, &data->msg, 1); |
| 350 | 357 | |
| @@ -322,7 +322,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, · 321 unmodified lines | ||
| 322 | 322 | adap->rc->allowed_protocols = RC_PROTO_BIT_CEC; |
| 323 | 323 | adap->rc->priv = adap; |
| 324 | 324 | adap->rc->map_name = RC_MAP_CEC; |
| 325 | − adap->rc->timeout = MS_TO_NS(100); | |
| 325 | + adap->rc->timeout = MS_TO_NS(550); | |
| 326 | 326 | #endif |
| 327 | 327 | return adap; |
| 328 | 328 | } |
| @@ -81,10 +81,9 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 80 unmodified lines | ||
| 81 | 81 | u64 *error; |
| 82 | 82 | u8 *args; |
| 83 | 83 | bool has_op; |
| 84 | − u32 op; | |
| 84 | + u8 op; | |
| 85 | 85 | u8 mode; |
| 86 | 86 | u8 pos; |
| 87 | − u8 v; | |
| 88 | 87 | |
| 89 | 88 | p = skip_spaces(p); |
| 90 | 89 | token = strsep(&p, delims); |
| @@ -146,12 +145,18 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 55 unmodified lines | ||
| 146 | 145 | comma = strchr(token, ','); |
| 147 | 146 | if (comma) |
| 148 | 147 | *comma++ = '\0'; |
| 149 | − if (!strcmp(token, "any")) | |
| 150 | − op = CEC_ERROR_INJ_OP_ANY; | |
| 151 | − else if (!kstrtou8(token, 0, &v)) | |
| 152 | − op = v; | |
| 153 | − else | |
| 148 | + if (!strcmp(token, "any")) { | |
| 149 | + has_op = false; | |
| 150 | + error = pin->error_inj + CEC_ERROR_INJ_OP_ANY; | |
| 151 | + args = pin->error_inj_args[CEC_ERROR_INJ_OP_ANY]; | |
| 152 | + } else if (!kstrtou8(token, 0, &op)) { | |
| 153 | + has_op = true; | |
| 154 | + error = pin->error_inj + op; | |
| 155 | + args = pin->error_inj_args[op]; | |
| 156 | + } else { | |
| 154 | 157 | return false; |
| 158 | + } | |
| 159 | + | |
| 155 | 160 | mode = CEC_ERROR_INJ_MODE_ONCE; |
| 156 | 161 | if (comma) { |
| 157 | 162 | if (!strcmp(comma, "off")) |
| @@ -166,10 +171,6 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 8 unmodified lines | ||
| 166 | 171 | return false; |
| 167 | 172 | } |
| 168 | 173 | |
| 169 | − error = pin->error_inj + op; | |
| 170 | − args = pin->error_inj_args[op]; | |
| 171 | − has_op = op <= 0xff; | |
| 172 | − | |
| 173 | 174 | token = strsep(&p, delims); |
| 174 | 175 | if (p) { |
| 175 | 176 | p = skip_spaces(p); |
| @@ -203,16 +204,18 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 27 unmodified lines | ||
| 203 | 204 | mode_mask = CEC_ERROR_INJ_MODE_MASK << mode_offset; |
| 204 | 205 | arg_idx = cec_error_inj_cmds[i].arg_idx; |
| 205 | 206 | |
| 206 | − if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET || | |
| 207 | − mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET) | |
| 208 | − is_bit_pos = false; | |
| 209 | − | |
| 210 | 207 | if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET) { |
| 211 | 208 | if (has_op) |
| 212 | 209 | return false; |
| 213 | 210 | if (!has_pos) |
| 214 | 211 | pos = 0x0f; |
| 212 | + is_bit_pos = false; | |
| 213 | + } else if (mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET) { | |
| 214 | + if (!has_pos || !pos) | |
| 215 | + return false; | |
| 216 | + is_bit_pos = false; | |
| 215 | 217 | } |
| 218 | + | |
| 216 | 219 | if (arg_idx >= 0 && is_bit_pos) { |
| 217 | 220 | if (!has_pos || pos >= 160) |
| 218 | 221 | return false; |
| @@ -119,7 +119,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) · 118 unmodified lines | ||
| 119 | 119 | |
| 120 | 120 | if (pin->work_pin_events_dropped) { |
| 121 | 121 | pin->work_pin_events_dropped = false; |
| 122 | − v |= CEC_PIN_EVENT_FL_DROPPED; | |
| 122 | + ev |= CEC_PIN_EVENT_FL_DROPPED; | |
| 123 | 123 | } |
| 124 | 124 | pin->work_pin_events[pin->work_pin_events_wr] = ev; |
| 125 | 125 | pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); |
| @@ -495,7 +495,6 @@ static int airstar_atsc2_attach(struct flexcop_device *fc, · 494 unmodified lines | ||
| 495 | 495 | /* AirStar ATSC 3rd generation */ |
| 496 | 496 | #if FE_SUPPORTED(LGDT330X) |
| 497 | 497 | static struct lgdt330x_config air2pc_atsc_hd5000_config = { |
| 498 | − .demod_address = 0x59, | |
| 499 | 498 | .demod_chip = LGDT3303, |
| 500 | 499 | .serial_mpeg = 0x04, |
| 501 | 500 | .clock_polarity_flip = 1, |
| @@ -504,7 +503,8 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = { · 2 unmodified lines | ||
| 504 | 503 | static int airstar_atsc3_attach(struct flexcop_device *fc, |
| 505 | 504 | struct i2c_adapter *i2c) |
| 506 | 505 | { |
| 507 | − fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); | |
| 506 | + fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, | |
| 507 | + 0x59, i2c); | |
| 508 | 508 | if (!fc->fe) |
| 509 | 509 | return 0; |
| 510 | 510 | |
| @@ -105,40 +105,36 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, · 104 unmodified lines | ||
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, |
| 108 | − flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) | |
| 108 | + flexcop_access_op_t op, u8 chipaddr, | |
| 109 | + u8 start_addr, u8 *buf, u16 size) | |
| 109 | 110 | { |
| 110 | 111 | int ret; |
| 111 | − | |
| 112 | −#ifdef DUMP_I2C_MESSAGES | |
| 113 | − int i; | |
| 114 | −#endif | |
| 112 | + int len = size; | |
| 113 | + u8 *p; | |
| 114 | + u8 addr = start_addr; | |
| 115 | 115 | |
| 116 | 116 | u16 bytes_to_transfer; |
| 117 | 117 | flexcop_ibi_value r100; |
| 118 | 118 | |
| 119 | − deb_i2c("op = %d\n",op); | |
| 119 | + deb_i2c("port %d %s(%02x): register %02x, size: %d\n", | |
| 120 | + i2c->port, | |
| 121 | + op == FC_READ ? "rd" : "wr", | |
| 122 | + chipaddr, start_addr, size); | |
| 120 | 123 | r100.raw = 0; |
| 121 | 124 | r100.tw_sm_c_100.chipaddr = chipaddr; |
| 122 | 125 | r100.tw_sm_c_100.twoWS_rw = op; |
| 123 | 126 | r100.tw_sm_c_100.twoWS_port_reg = i2c->port; |
| 124 | 127 | |
| 125 | −#ifdef DUMP_I2C_MESSAGES | |
| 126 | − printk(KERN_DEBUG "%d ", i2c->port); | |
| 127 | − if (op == FC_READ) | |
| 128 | − printk(KERN_CONT "rd("); | |
| 129 | − else | |
| 130 | − printk(KERN_CONT "wr("); | |
| 131 | − printk(KERN_CONT "%02x): %02x ", chipaddr, addr); | |
| 132 | −#endif | |
| 133 | − | |
| 134 | 128 | /* in that case addr is the only value -> |
| 135 | 129 | * we write it twice as baseaddr and val0 |
| 136 | 130 | * BBTI is doing it like that for ISL6421 at least */ |
| 137 | 131 | if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { |
| 138 | − buf = &addr; | |
| 132 | + buf = &start_addr; | |
| 139 | 133 | len = 1; |
| 140 | 134 | } |
| 141 | 135 | |
| 136 | + p = buf; | |
| 137 | + | |
| 142 | 138 | while (len != 0) { |
| 143 | 139 | bytes_to_transfer = len > 4 ? 4 : len; |
| 144 | 140 | |
| @@ -146,26 +142,21 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, · 1 unmodified line | ||
| 146 | 142 | r100.tw_sm_c_100.baseaddr = addr; |
| 147 | 143 | |
| 148 | 144 | if (op == FC_READ) |
| 149 | − ret = flexcop_i2c_read4(i2c, r100, buf); | |
| 145 | + ret = flexcop_i2c_read4(i2c, r100, p); | |
| 150 | 146 | else |
| 151 | − ret = flexcop_i2c_write4(i2c->fc, r100, buf); | |
| 152 | − | |
| 153 | −#ifdef DUMP_I2C_MESSAGES | |
| 154 | − for (i = 0; i < bytes_to_transfer; i++) | |
| 155 | − printk(KERN_CONT "%02x ", buf[i]); | |
| 156 | −#endif | |
| 147 | + ret = flexcop_i2c_write4(i2c->fc, r100, p); | |
| 157 | 148 | |
| 158 | 149 | if (ret < 0) |
| 159 | 150 | return ret; |
| 160 | 151 | |
| 161 | − buf += bytes_to_transfer; | |
| 152 | + p += bytes_to_transfer; | |
| 162 | 153 | addr += bytes_to_transfer; |
| 163 | 154 | len -= bytes_to_transfer; |
| 164 | 155 | } |
| 165 | − | |
| 166 | −#ifdef DUMP_I2C_MESSAGES | |
| 167 | − printk(KERN_CONT "\n"); | |
| 168 | −#endif | |
| 156 | + deb_i2c_dump("port %d %s(%02x): register %02x: %*ph\n", | |
| 157 | + i2c->port, | |
| 158 | + op == FC_READ ? "rd" : "wr", | |
| 159 | + chipaddr, start_addr, size, buf); | |
| 169 | 160 | |
| 170 | 161 | return 0; |
| 171 | 162 | } |
| @@ -42,7 +42,7 @@ int b2c2_flexcop_debug; · 41 unmodified lines | ||
| 42 | 42 | EXPORT_SYMBOL_GPL(b2c2_flexcop_debug); |
| 43 | 43 | module_param_named(debug, b2c2_flexcop_debug, int, 0644); |
| 44 | 44 | MODULE_PARM_DESC(debug, |
| 45 | − "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." | |
| 45 | + "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg,64=i2cdump (|-able))." | |
| 46 | 46 | DEBSTATUS); |
| 47 | 47 | #undef DEBSTATUS |
| 48 | 48 | |
| @@ -26,5 +26,6 @@ extern int b2c2_flexcop_debug; · 25 unmodified lines | ||
| 26 | 26 | #define deb_ts(args...) dprintk(0x08, args) |
| 27 | 27 | #define deb_sram(args...) dprintk(0x10, args) |
| 28 | 28 | #define deb_rdump(args...) dprintk(0x20, args) |
| 29 | +#define deb_i2c_dump(args...) dprintk(0x40, args) | |
| 29 | 30 | |
| 30 | 31 | #endif |
| @@ -308,7 +308,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m · 307 unmodified lines | ||
| 308 | 308 | /* prepare the message(s), get number of u32s to transfer */ |
| 309 | 309 | count = saa7146_i2c_msg_prepare(msgs, num, buffer); |
| 310 | 310 | if ( 0 > count ) { |
| 311 | − err = -1; | |
| 311 | + err = -EIO; | |
| 312 | 312 | goto out; |
| 313 | 313 | } |
| 314 | 314 | |
| @@ -360,7 +360,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m · 45 unmodified lines | ||
| 360 | 360 | /* if any things had to be read, get the results */ |
| 361 | 361 | if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { |
| 362 | 362 | DEB_I2C("could not cleanup i2c-message\n"); |
| 363 | − err = -1; | |
| 363 | + err = -EIO; | |
| 364 | 364 | goto out; |
| 365 | 365 | } |
| 366 | 366 | |
| @@ -415,8 +415,8 @@ EXPORT_SYMBOL_GPL(smscore_get_board_id); · 414 unmodified lines | ||
| 415 | 415 | |
| 416 | 416 | struct smscore_registry_entry_t { |
| 417 | 417 | struct list_head entry; |
| 418 | − char devpath[32]; | |
| 419 | − int mode; | |
| 418 | + char devpath[32]; | |
| 419 | + int mode; | |
| 420 | 420 | enum sms_device_type_st type; |
| 421 | 421 | }; |
| 422 | 422 | |
| @@ -442,7 +442,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) · 19 unmodified lines | ||
| 442 | 442 | next != &g_smscore_registry; |
| 443 | 443 | next = next->next) { |
| 444 | 444 | entry = (struct smscore_registry_entry_t *) next; |
| 445 | − if (!strcmp(entry->devpath, devpath)) { | |
| 445 | + if (!strncmp(entry->devpath, devpath, sizeof(entry->devpath))) { | |
| 446 | 446 | kmutex_unlock(&g_smscore_registrylock); |
| 447 | 447 | return entry; |
| 448 | 448 | } |
| @@ -450,7 +450,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) · 1 unmodified line | ||
| 450 | 450 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
| 451 | 451 | if (entry) { |
| 452 | 452 | entry->mode = default_mode; |
| 453 | − strcpy(entry->devpath, devpath); | |
| 453 | + strlcpy(entry->devpath, devpath, sizeof(entry->devpath)); | |
| 454 | 454 | list_add(&entry->entry, &g_smscore_registry); |
| 455 | 455 | } else |
| 456 | 456 | pr_err("failed to create smscore_registry.\n"); |
| @@ -649,6 +649,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, · 192 unmodified lines | ||
| 649 | 649 | */ |
| 650 | 650 | int smscore_register_device(struct smsdevice_params_t *params, |
| 651 | 651 | struct smscore_device_t **coredev, |
| 652 | + gfp_t gfp_buf_flags, | |
| 652 | 653 | void *mdev) |
| 653 | 654 | { |
| 654 | 655 | struct smscore_device_t *dev; |
| @@ -661,6 +662,7 @@ int smscore_register_device(struct smsdevice_params_t *params, · 6 unmodified lines | ||
| 661 | 662 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
| 662 | 663 | dev->media_dev = mdev; |
| 663 | 664 | #endif |
| 665 | + dev->gfp_buf_flags = gfp_buf_flags; | |
| 664 | 666 | |
| 665 | 667 | /* init list entry so it could be safe in smscore_unregister_device */ |
| 666 | 668 | INIT_LIST_HEAD(&dev->entry); |
| @@ -697,7 +699,7 @@ int smscore_register_device(struct smsdevice_params_t *params, · 30 unmodified lines | ||
| 697 | 699 | buffer = dma_alloc_coherent(params->device, |
| 698 | 700 | dev->common_buffer_size, |
| 699 | 701 | &dev->common_buffer_phys, |
| 700 | − GFP_KERNEL | GFP_DMA); | |
| 702 | + GFP_KERNEL | dev->gfp_buf_flags); | |
| 701 | 703 | if (!buffer) { |
| 702 | 704 | smscore_unregister_device(dev); |
| 703 | 705 | return -ENOMEM; |
| @@ -733,7 +735,7 @@ int smscore_register_device(struct smsdevice_params_t *params, · 29 unmodified lines | ||
| 733 | 735 | dev->postload_handler = params->postload_handler; |
| 734 | 736 | |
| 735 | 737 | dev->device_flags = params->flags; |
| 736 | − strcpy(dev->devpath, params->devpath); | |
| 738 | + strlcpy(dev->devpath, params->devpath, sizeof(dev->devpath)); | |
| 737 | 739 | |
| 738 | 740 | smscore_registry_settype(dev->devpath, params->device_type); |
| 739 | 741 | |
| @@ -792,7 +794,7 @@ static int smscore_init_ir(struct smscore_device_t *coredev) · 52 unmodified lines | ||
| 792 | 794 | else { |
| 793 | 795 | buffer = kmalloc(sizeof(struct sms_msg_data2) + |
| 794 | 796 | SMS_DMA_ALIGNMENT, |
| 795 | − GFP_KERNEL | GFP_DMA); | |
| 797 | + GFP_KERNEL | coredev->gfp_buf_flags); | |
| 796 | 798 | if (buffer) { |
| 797 | 799 | struct sms_msg_data2 *msg = |
| 798 | 800 | (struct sms_msg_data2 *) |
| @@ -933,7 +935,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, · 134 unmodified lines | ||
| 933 | 935 | } |
| 934 | 936 | |
| 935 | 937 | /* PAGE_SIZE buffer shall be enough and dma aligned */ |
| 936 | − msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); | |
| 938 | + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | coredev->gfp_buf_flags); | |
| 937 | 939 | if (!msg) |
| 938 | 940 | return -ENOMEM; |
| 939 | 941 | |
| @@ -1168,7 +1170,7 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, · 228 unmodified lines | ||
| 1168 | 1170 | } |
| 1169 | 1171 | pr_debug("read fw %s, buffer size=0x%zx\n", fw_filename, fw->size); |
| 1170 | 1172 | fw_buf = kmalloc(ALIGN(fw->size + sizeof(struct sms_firmware), |
| 1171 | − SMS_ALLOC_ALIGNMENT), GFP_KERNEL | GFP_DMA); | |
| 1173 | + SMS_ALLOC_ALIGNMENT), GFP_KERNEL | coredev->gfp_buf_flags); | |
| 1172 | 1174 | if (!fw_buf) { |
| 1173 | 1175 | pr_err("failed to allocate firmware buffer\n"); |
| 1174 | 1176 | rc = -ENOMEM; |
| @@ -1260,7 +1262,7 @@ EXPORT_SYMBOL_GPL(smscore_unregister_device); · 85 unmodified lines | ||
| 1260 | 1262 | static int smscore_detect_mode(struct smscore_device_t *coredev) |
| 1261 | 1263 | { |
| 1262 | 1264 | void *buffer = kmalloc(sizeof(struct sms_msg_hdr) + SMS_DMA_ALIGNMENT, |
| 1263 | − GFP_KERNEL | GFP_DMA); | |
| 1265 | + GFP_KERNEL | coredev->gfp_buf_flags); | |
| 1264 | 1266 | struct sms_msg_hdr *msg = |
| 1265 | 1267 | (struct sms_msg_hdr *) SMS_ALIGN_ADDRESS(buffer); |
| 1266 | 1268 | int rc; |
| @@ -1309,7 +1311,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) · 42 unmodified lines | ||
| 1309 | 1311 | int rc = 0; |
| 1310 | 1312 | |
| 1311 | 1313 | buffer = kmalloc(sizeof(struct sms_msg_data) + |
| 1312 | − SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); | |
| 1314 | + SMS_DMA_ALIGNMENT, GFP_KERNEL | coredev->gfp_buf_flags); | |
| 1313 | 1315 | if (!buffer) |
| 1314 | 1316 | return -ENOMEM; |
| 1315 | 1317 | |
| @@ -1398,7 +1400,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) · 82 unmodified lines | ||
| 1398 | 1400 | coredev->device_flags &= ~SMS_DEVICE_NOT_READY; |
| 1399 | 1401 | |
| 1400 | 1402 | buffer = kmalloc(sizeof(struct sms_msg_data) + |
| 1401 | − SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); | |
| 1403 | + SMS_DMA_ALIGNMENT, GFP_KERNEL | coredev->gfp_buf_flags); | |
| 1402 | 1404 | if (buffer) { |
| 1403 | 1405 | struct sms_msg_data *msg = (struct sms_msg_data *) SMS_ALIGN_ADDRESS(buffer); |
| 1404 | 1406 | |
| @@ -1971,7 +1973,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, · 566 unmodified lines | ||
| 1971 | 1973 | total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); |
| 1972 | 1974 | |
| 1973 | 1975 | buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, |
| 1974 | − GFP_KERNEL | GFP_DMA); | |
| 1976 | + GFP_KERNEL | coredev->gfp_buf_flags); | |
| 1975 | 1977 | if (!buffer) |
| 1976 | 1978 | return -ENOMEM; |
| 1977 | 1979 | |
| @@ -2043,7 +2045,7 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, · 65 unmodified lines | ||
| 2043 | 2045 | (3 * sizeof(u32)); /* keep it 3 ! */ |
| 2044 | 2046 | |
| 2045 | 2047 | buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, |
| 2046 | − GFP_KERNEL | GFP_DMA); | |
| 2048 | + GFP_KERNEL | coredev->gfp_buf_flags); | |
| 2047 | 2049 | if (!buffer) |
| 2048 | 2050 | return -ENOMEM; |
| 2049 | 2051 | |
| @@ -2091,7 +2093,7 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, · 41 unmodified lines | ||
| 2091 | 2093 | total_len = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32)); |
| 2092 | 2094 | |
| 2093 | 2095 | buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, |
| 2094 | − GFP_KERNEL | GFP_DMA); | |
| 2096 | + GFP_KERNEL | coredev->gfp_buf_flags); | |
| 2095 | 2097 | if (!buffer) |
| 2096 | 2098 | return -ENOMEM; |
| 2097 | 2099 | |
| @@ -190,6 +190,8 @@ struct smscore_device_t { · 189 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | int mode, modes_supported; |
| 192 | 192 | |
| 193 | + gfp_t gfp_buf_flags; | |
| 194 | + | |
| 193 | 195 | /* host <--> device messages */ |
| 194 | 196 | struct completion version_ex_done, data_download_done, trigger_done; |
| 195 | 197 | struct completion data_validity_done, device_ready_done; |
| @@ -1125,6 +1127,7 @@ extern void smscore_unregister_hotplug(hotplug_t hotplug); · 929 unmodified lines | ||
| 1125 | 1127 | |
| 1126 | 1128 | extern int smscore_register_device(struct smsdevice_params_t *params, |
| 1127 | 1129 | struct smscore_device_t **coredev, |
| 1130 | + gfp_t gfp_buf_flags, | |
| 1128 | 1131 | void *mdev); |
| 1129 | 1132 | extern void smscore_unregister_device(struct smscore_device_t *coredev); |
| 1130 | 1133 | |
| @@ -35,7 +35,7 @@ void smsendian_handle_tx_message(void *buffer) · 34 unmodified lines | ||
| 35 | 35 | switch (msg->x_msg_header.msg_type) { |
| 36 | 36 | case MSG_SMS_DATA_DOWNLOAD_REQ: |
| 37 | 37 | { |
| 38 | − msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); | |
| 38 | + msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); | |
| 39 | 39 | break; |
| 40 | 40 | } |
| 41 | 41 | |
| @@ -44,7 +44,7 @@ void smsendian_handle_tx_message(void *buffer) · 2 unmodified lines | ||
| 44 | 44 | sizeof(struct sms_msg_hdr))/4; |
| 45 | 45 | |
| 46 | 46 | for (i = 0; i < msg_words; i++) |
| 47 | − msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); | |
| 47 | + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); | |
| 48 | 48 | |
| 49 | 49 | break; |
| 50 | 50 | } |
| @@ -64,7 +64,7 @@ void smsendian_handle_rx_message(void *buffer) · 13 unmodified lines | ||
| 64 | 64 | { |
| 65 | 65 | struct sms_version_res *ver = |
| 66 | 66 | (struct sms_version_res *) msg; |
| 67 | − ver->chip_model = le16_to_cpu(ver->chip_model); | |
| 67 | + ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model); | |
| 68 | 68 | break; |
| 69 | 69 | } |
| 70 | 70 | |
| @@ -81,7 +81,7 @@ void smsendian_handle_rx_message(void *buffer) · 10 unmodified lines | ||
| 81 | 81 | sizeof(struct sms_msg_hdr))/4; |
| 82 | 82 | |
| 83 | 83 | for (i = 0; i < msg_words; i++) |
| 84 | − msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); | |
| 84 | + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); | |
| 85 | 85 | |
| 86 | 86 | break; |
| 87 | 87 | } |
| @@ -95,9 +95,9 @@ void smsendian_handle_message_header(void *msg) · 7 unmodified lines | ||
| 95 | 95 | #ifdef __BIG_ENDIAN |
| 96 | 96 | struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; |
| 97 | 97 | |
| 98 | − phdr->msg_type = le16_to_cpu(phdr->msg_type); | |
| 99 | − phdr->msg_length = le16_to_cpu(phdr->msg_length); | |
| 100 | − phdr->msg_flags = le16_to_cpu(phdr->msg_flags); | |
| 98 | + phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type); | |
| 99 | + phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length); | |
| 100 | + phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags); | |
| 101 | 101 | #endif /* __BIG_ENDIAN */ |
| 102 | 102 | } |
| 103 | 103 | EXPORT_SYMBOL_GPL(smsendian_handle_message_header); |
| @@ -12,7 +12,6 @@ config VIDEOBUF2_MEMOPS · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | config VIDEOBUF2_DMA_CONTIG |
| 14 | 14 | tristate |
| 15 | − depends on HAS_DMA | |
| 16 | 15 | select VIDEOBUF2_CORE |
| 17 | 16 | select VIDEOBUF2_MEMOPS |
| 18 | 17 | select DMA_SHARED_BUFFER |
| @@ -25,7 +24,6 @@ config VIDEOBUF2_VMALLOC · 6 unmodified lines | ||
| 25 | 24 | |
| 26 | 25 | config VIDEOBUF2_DMA_SG |
| 27 | 26 | tristate |
| 28 | − depends on HAS_DMA | |
| 29 | 27 | select VIDEOBUF2_CORE |
| 30 | 28 | select VIDEOBUF2_MEMOPS |
| 31 | 29 | |
| @@ -916,9 +916,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) · 915 unmodified lines | ||
| 916 | 916 | dprintk(4, "done processing on buffer %d, state: %d\n", |
| 917 | 917 | vb->index, state); |
| 918 | 918 | |
| 919 | − /* sync buffers */ | |
| 920 | − for (plane = 0; plane < vb->num_planes; ++plane) | |
| 921 | − call_void_memop(vb, finish, vb->planes[plane].mem_priv); | |
| 919 | + if (state != VB2_BUF_STATE_QUEUED && | |
| 920 | + state != VB2_BUF_STATE_REQUEUEING) { | |
| 921 | + /* sync buffers */ | |
| 922 | + for (plane = 0; plane < vb->num_planes; ++plane) | |
| 923 | + call_void_memop(vb, finish, vb->planes[plane].mem_priv); | |
| 924 | + } | |
| 922 | 925 | |
| 923 | 926 | spin_lock_irqsave(&q->done_lock, flags); |
| 924 | 927 | if (state == VB2_BUF_STATE_QUEUED || |
| @@ -622,7 +622,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, · 621 unmodified lines | ||
| 622 | 622 | struct dmxdev_filter *filter, |
| 623 | 623 | struct dmxdev_feed *feed) |
| 624 | 624 | { |
| 625 | − ktime_t timeout = 0; | |
| 625 | + ktime_t timeout = ktime_set(0, 0); | |
| 626 | 626 | struct dmx_pes_filter_params *para = &filter->params.pes; |
| 627 | 627 | enum dmx_output otype; |
| 628 | 628 | int ret; |
| @@ -31,6 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | #include <linux/slab.h> |
| 32 | 32 | #include <linux/list.h> |
| 33 | 33 | #include <linux/module.h> |
| 34 | +#include <linux/nospec.h> | |
| 34 | 35 | #include <linux/vmalloc.h> |
| 35 | 36 | #include <linux/delay.h> |
| 36 | 37 | #include <linux/spinlock.h> |
| @@ -1476,6 +1477,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, · 1439 unmodified lines | ||
| 1476 | 1477 | |
| 1477 | 1478 | if (slot >= ca->slot_count) |
| 1478 | 1479 | return -EINVAL; |
| 1480 | + slot = array_index_nospec(slot, ca->slot_count); | |
| 1479 | 1481 | sl = &ca->slot_info[slot]; |
| 1480 | 1482 | |
| 1481 | 1483 | /* check if the slot is actually running */ |
| @@ -190,7 +190,7 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, · 189 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | static bool has_get_frontend(struct dvb_frontend *fe) |
| 192 | 192 | { |
| 193 | − return fe->ops.get_frontend != NULL; | |
| 193 | + return fe->ops.get_frontend; | |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | 196 | /* |
| @@ -272,11 +272,23 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, · 75 unmodified lines | ||
| 272 | 272 | |
| 273 | 273 | mutex_unlock(&events->mtx); |
| 274 | 274 | |
| 275 | − wake_up_interruptible (&events->wait_queue); | |
| 275 | + wake_up_interruptible(&events->wait_queue); | |
| 276 | +} | |
| 277 | + | |
| 278 | +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, | |
| 279 | + struct dvb_fe_events *events) | |
| 280 | +{ | |
| 281 | + int ret; | |
| 282 | + | |
| 283 | + up(&fepriv->sem); | |
| 284 | + ret = events->eventw != events->eventr; | |
| 285 | + down(&fepriv->sem); | |
| 286 | + | |
| 287 | + return ret; | |
| 276 | 288 | } |
| 277 | 289 | |
| 278 | 290 | static int dvb_frontend_get_event(struct dvb_frontend *fe, |
| 279 | − struct dvb_frontend_event *event, int flags) | |
| 291 | + struct dvb_frontend_event *event, int flags) | |
| 280 | 292 | { |
| 281 | 293 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
| 282 | 294 | struct dvb_fe_events *events = &fepriv->events; |
| @@ -294,13 +306,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, · 11 unmodified lines | ||
| 294 | 306 | if (flags & O_NONBLOCK) |
| 295 | 307 | return -EWOULDBLOCK; |
| 296 | 308 | |
| 297 | − up(&fepriv->sem); | |
| 298 | − | |
| 299 | − ret = wait_event_interruptible (events->wait_queue, | |
| 300 | − events->eventw != events->eventr); | |
| 301 | − | |
| 302 | − if (down_interruptible (&fepriv->sem)) | |
| 303 | − return -ERESTARTSYS; | |
| 309 | + ret = wait_event_interruptible(events->wait_queue, | |
| 310 | + dvb_frontend_test_event(fepriv, events)); | |
| 304 | 311 | |
| 305 | 312 | if (ret < 0) |
| 306 | 313 | return ret; |
| @@ -327,8 +334,8 @@ static void dvb_frontend_clear_events(struct dvb_frontend *fe) · 20 unmodified lines | ||
| 327 | 334 | static void dvb_frontend_init(struct dvb_frontend *fe) |
| 328 | 335 | { |
| 329 | 336 | dev_dbg(fe->dvb->device, |
| 330 | − "%s: initialising adapter %i frontend %i (%s)...\n", | |
| 331 | − __func__, fe->dvb->num, fe->id, fe->ops.info.name); | |
| 337 | + "%s: initialising adapter %i frontend %i (%s)...\n", | |
| 338 | + __func__, fe->dvb->num, fe->id, fe->ops.info.name); | |
| 332 | 339 | |
| 333 | 340 | if (fe->ops.init) |
| 334 | 341 | fe->ops.init(fe); |
| @@ -358,14 +365,14 @@ static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepr · 23 unmodified lines | ||
| 358 | 365 | dev_dbg(fe->dvb->device, "%s:\n", __func__); |
| 359 | 366 | |
| 360 | 367 | if (locked) |
| 361 | − (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; | |
| 368 | + (fepriv->quality) = (fepriv->quality * 220 + 36 * 256) / 256; | |
| 362 | 369 | else |
| 363 | 370 | (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; |
| 364 | 371 | |
| 365 | 372 | q2 = fepriv->quality - 128; |
| 366 | 373 | q2 *= q2; |
| 367 | 374 | |
| 368 | − fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); | |
| 375 | + fepriv->delay = fepriv->min_delay + q2 * HZ / (128 * 128); | |
| 369 | 376 | } |
| 370 | 377 | |
| 371 | 378 | /** |
| @@ -393,7 +400,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra · 21 unmodified lines | ||
| 393 | 400 | (c->inversion == INVERSION_AUTO)); |
| 394 | 401 | |
| 395 | 402 | /* setup parameters correctly */ |
| 396 | − while(!ready) { | |
| 403 | + while (!ready) { | |
| 397 | 404 | /* calculate the lnb_drift */ |
| 398 | 405 | fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; |
| 399 | 406 | |
| @@ -405,7 +412,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra · 5 unmodified lines | ||
| 405 | 412 | } |
| 406 | 413 | |
| 407 | 414 | /* perform inversion and +/- zigzag */ |
| 408 | − switch(fepriv->auto_sub_step) { | |
| 415 | + switch (fepriv->auto_sub_step) { | |
| 409 | 416 | case 0: |
| 410 | 417 | /* try with the current inversion and current drift setting */ |
| 411 | 418 | ready = 1; |
| @@ -450,11 +457,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra · 38 unmodified lines | ||
| 450 | 457 | return 1; |
| 451 | 458 | } |
| 452 | 459 | |
| 453 | − dev_dbg(fe->dvb->device, "%s: drift:%i inversion:%i auto_step:%i " \ | |
| 454 | − "auto_sub_step:%i started_auto_step:%i\n", | |
| 455 | − __func__, fepriv->lnb_drift, fepriv->inversion, | |
| 456 | − fepriv->auto_step, fepriv->auto_sub_step, | |
| 457 | − fepriv->started_auto_step); | |
| 460 | + dev_dbg(fe->dvb->device, | |
| 461 | + "%s: drift:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", | |
| 462 | + __func__, fepriv->lnb_drift, fepriv->inversion, | |
| 463 | + fepriv->auto_step, fepriv->auto_sub_step, | |
| 464 | + fepriv->started_auto_step); | |
| 458 | 465 | |
| 459 | 466 | /* set the frontend itself */ |
| 460 | 467 | c->frequency += fepriv->lnb_drift; |
| @@ -485,7 +492,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) · 24 unmodified lines | ||
| 485 | 492 | |
| 486 | 493 | /* if we've got no parameters, just keep idling */ |
| 487 | 494 | if (fepriv->state & FESTATE_IDLE) { |
| 488 | − fepriv->delay = 3*HZ; | |
| 495 | + fepriv->delay = 3 * HZ; | |
| 489 | 496 | fepriv->quality = 0; |
| 490 | 497 | return; |
| 491 | 498 | } |
| @@ -502,7 +509,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) · 10 unmodified lines | ||
| 502 | 509 | else |
| 503 | 510 | fepriv->state = FESTATE_TUNED; |
| 504 | 511 | } |
| 505 | − fepriv->delay = 3*HZ; | |
| 512 | + fepriv->delay = 3 * HZ; | |
| 506 | 513 | fepriv->quality = 0; |
| 507 | 514 | return; |
| 508 | 515 | } |
| @@ -591,7 +598,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) · 82 unmodified lines | ||
| 591 | 598 | } |
| 592 | 599 | fepriv->check_wrapped = 1; |
| 593 | 600 | |
| 594 | − /* if we've just retuned, enter the ZIGZAG_FAST state. | |
| 601 | + /* if we've just re-tuned, enter the ZIGZAG_FAST state. | |
| 595 | 602 | * This ensures we cannot return from an |
| 596 | 603 | * FE_SET_FRONTEND ioctl before the first frontend tune |
| 597 | 604 | * occurs */ |
| @@ -658,7 +665,7 @@ static int dvb_frontend_thread(void *data) · 60 unmodified lines | ||
| 658 | 665 | |
| 659 | 666 | fepriv->check_wrapped = 0; |
| 660 | 667 | fepriv->quality = 0; |
| 661 | − fepriv->delay = 3*HZ; | |
| 668 | + fepriv->delay = 3 * HZ; | |
| 662 | 669 | fepriv->status = 0; |
| 663 | 670 | fepriv->wakeup = 0; |
| 664 | 671 | fepriv->reinitialise = 0; |
| @@ -670,8 +677,9 @@ static int dvb_frontend_thread(void *data) · 5 unmodified lines | ||
| 670 | 677 | up(&fepriv->sem); /* is locked when we enter the thread... */ |
| 671 | 678 | restart: |
| 672 | 679 | wait_event_interruptible_timeout(fepriv->wait_queue, |
| 673 | − dvb_frontend_should_wakeup(fe) || kthread_should_stop() | |
| 674 | − || freezing(current), | |
| 680 | + dvb_frontend_should_wakeup(fe) || | |
| 681 | + kthread_should_stop() || | |
| 682 | + freezing(current), | |
| 675 | 683 | fepriv->delay); |
| 676 | 684 | |
| 677 | 685 | if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { |
| @@ -820,8 +828,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) · 142 unmodified lines | ||
| 820 | 828 | /* paranoia check in case a signal arrived */ |
| 821 | 829 | if (fepriv->thread) |
| 822 | 830 | dev_warn(fe->dvb->device, |
| 823 | − "dvb_frontend_stop: warning: thread %p won't exit\n", | |
| 824 | − fepriv->thread); | |
| 831 | + "dvb_frontend_stop: warning: thread %p won't exit\n", | |
| 832 | + fepriv->thread); | |
| 825 | 833 | } |
| 826 | 834 | |
| 827 | 835 | /* |
| @@ -858,12 +866,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) · 30 unmodified lines | ||
| 858 | 866 | if (fe->exit == DVB_FE_NO_EXIT) |
| 859 | 867 | return 0; |
| 860 | 868 | else |
| 861 | − dvb_frontend_stop (fe); | |
| 869 | + dvb_frontend_stop(fe); | |
| 862 | 870 | } |
| 863 | 871 | |
| 864 | 872 | if (signal_pending(current)) |
| 865 | 873 | return -EINTR; |
| 866 | − if (down_interruptible (&fepriv->sem)) | |
| 874 | + if (down_interruptible(&fepriv->sem)) | |
| 867 | 875 | return -EINTR; |
| 868 | 876 | |
| 869 | 877 | fepriv->state = FESTATE_IDLE; |
| @@ -872,12 +880,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) · 2 unmodified lines | ||
| 872 | 880 | mb(); |
| 873 | 881 | |
| 874 | 882 | fe_thread = kthread_run(dvb_frontend_thread, fe, |
| 875 | − "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); | |
| 883 | + "kdvb-ad-%i-fe-%i", fe->dvb->num, fe->id); | |
| 876 | 884 | if (IS_ERR(fe_thread)) { |
| 877 | 885 | ret = PTR_ERR(fe_thread); |
| 878 | 886 | dev_warn(fe->dvb->device, |
| 879 | − "dvb_frontend_start: failed to start kthread (%d)\n", | |
| 880 | − ret); | |
| 887 | + "dvb_frontend_start: failed to start kthread (%d)\n", | |
| 888 | + ret); | |
| 881 | 889 | up(&fepriv->sem); |
| 882 | 890 | return ret; |
| 883 | 891 | } |
| @@ -886,7 +894,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe) · 2 unmodified lines | ||
| 886 | 894 | } |
| 887 | 895 | |
| 888 | 896 | static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, |
| 889 | − u32 *freq_min, u32 *freq_max) | |
| 897 | + u32 *freq_min, u32 *freq_max) | |
| 890 | 898 | { |
| 891 | 899 | *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); |
| 892 | 900 | |
| @@ -898,8 +906,9 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, · 5 unmodified lines | ||
| 898 | 906 | *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); |
| 899 | 907 | |
| 900 | 908 | if (*freq_min == 0 || *freq_max == 0) |
| 901 | − dev_warn(fe->dvb->device, "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", | |
| 902 | − fe->dvb->num, fe->id); | |
| 909 | + dev_warn(fe->dvb->device, | |
| 910 | + "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", | |
| 911 | + fe->dvb->num, fe->id); | |
| 903 | 912 | } |
| 904 | 913 | |
| 905 | 914 | static int dvb_frontend_check_parameters(struct dvb_frontend *fe) |
| @@ -913,8 +922,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) · 7 unmodified lines | ||
| 913 | 922 | if ((freq_min && c->frequency < freq_min) || |
| 914 | 923 | (freq_max && c->frequency > freq_max)) { |
| 915 | 924 | dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", |
| 916 | − fe->dvb->num, fe->id, c->frequency, | |
| 917 | − freq_min, freq_max); | |
| 925 | + fe->dvb->num, fe->id, c->frequency, | |
| 926 | + freq_min, freq_max); | |
| 918 | 927 | return -EINVAL; |
| 919 | 928 | } |
| 920 | 929 | |
| @@ -930,9 +939,9 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) · 9 unmodified lines | ||
| 930 | 939 | (fe->ops.info.symbol_rate_max && |
| 931 | 940 | c->symbol_rate > fe->ops.info.symbol_rate_max)) { |
| 932 | 941 | dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", |
| 933 | − fe->dvb->num, fe->id, c->symbol_rate, | |
| 934 | − fe->ops.info.symbol_rate_min, | |
| 935 | − fe->ops.info.symbol_rate_max); | |
| 942 | + fe->dvb->num, fe->id, c->symbol_rate, | |
| 943 | + fe->ops.info.symbol_rate_min, | |
| 944 | + fe->ops.info.symbol_rate_max); | |
| 936 | 945 | return -EINVAL; |
| 937 | 946 | } |
| 938 | 947 | default: |
| @@ -953,7 +962,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) · 14 unmodified lines | ||
| 953 | 962 | c->delivery_system = delsys; |
| 954 | 963 | |
| 955 | 964 | dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n", |
| 956 | − __func__, c->delivery_system); | |
| 965 | + __func__, c->delivery_system); | |
| 957 | 966 | |
| 958 | 967 | c->transmission_mode = TRANSMISSION_MODE_AUTO; |
| 959 | 968 | c->bandwidth_hz = 0; /* AUTO */ |
| @@ -973,7 +982,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) · 13 unmodified lines | ||
| 973 | 982 | c->isdbt_sb_subchannel = 0; |
| 974 | 983 | c->isdbt_sb_segment_idx = 0; |
| 975 | 984 | c->isdbt_sb_segment_count = 0; |
| 976 | − c->isdbt_layer_enabled = 0; | |
| 985 | + c->isdbt_layer_enabled = 7; /* All layers (A,B,C) */ | |
| 977 | 986 | for (i = 0; i < 3; i++) { |
| 978 | 987 | c->layer[i].fec = FEC_AUTO; |
| 979 | 988 | c->layer[i].modulation = QAM_AUTO; |
| @@ -1178,8 +1187,8 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe, · 198 unmodified lines | ||
| 1178 | 1187 | break; |
| 1179 | 1188 | case DVBV3_UNKNOWN: |
| 1180 | 1189 | dev_err(fe->dvb->device, |
| 1181 | − "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 1182 | − __func__, c->delivery_system); | |
| 1190 | + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 1191 | + __func__, c->delivery_system); | |
| 1183 | 1192 | return -EINVAL; |
| 1184 | 1193 | } |
| 1185 | 1194 | |
| @@ -1200,8 +1209,8 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, · 14 unmodified lines | ||
| 1200 | 1209 | switch (dvbv3_type(c->delivery_system)) { |
| 1201 | 1210 | case DVBV3_UNKNOWN: |
| 1202 | 1211 | dev_err(fe->dvb->device, |
| 1203 | − "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 1204 | − __func__, c->delivery_system); | |
| 1212 | + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 1213 | + __func__, c->delivery_system); | |
| 1205 | 1214 | return -EINVAL; |
| 1206 | 1215 | case DVBV3_QPSK: |
| 1207 | 1216 | dev_dbg(fe->dvb->device, "%s: Preparing QPSK req\n", __func__); |
| @@ -1293,7 +1302,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe, · 85 unmodified lines | ||
| 1293 | 1302 | { |
| 1294 | 1303 | int ncaps; |
| 1295 | 1304 | |
| 1296 | − switch(tvp->cmd) { | |
| 1305 | + switch (tvp->cmd) { | |
| 1297 | 1306 | case DTV_ENUM_DELSYS: |
| 1298 | 1307 | ncaps = 0; |
| 1299 | 1308 | while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { |
| @@ -1622,8 +1631,8 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, · 322 unmodified lines | ||
| 1622 | 1631 | if (fe->ops.delsys[ncaps] == desired_system) { |
| 1623 | 1632 | c->delivery_system = desired_system; |
| 1624 | 1633 | dev_dbg(fe->dvb->device, |
| 1625 | − "%s: Changing delivery system to %d\n", | |
| 1626 | − __func__, desired_system); | |
| 1634 | + "%s: Changing delivery system to %d\n", | |
| 1635 | + __func__, desired_system); | |
| 1627 | 1636 | return 0; |
| 1628 | 1637 | } |
| 1629 | 1638 | ncaps++; |
| @@ -1715,8 +1724,8 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) · 85 unmodified lines | ||
| 1715 | 1724 | */ |
| 1716 | 1725 | if (is_dvbv3_delsys(c->delivery_system)) { |
| 1717 | 1726 | dev_dbg(fe->dvb->device, |
| 1718 | − "%s: Using delivery system to %d\n", | |
| 1719 | − __func__, c->delivery_system); | |
| 1727 | + "%s: Using delivery system to %d\n", | |
| 1728 | + __func__, c->delivery_system); | |
| 1720 | 1729 | return 0; |
| 1721 | 1730 | } |
| 1722 | 1731 | |
| @@ -1756,8 +1765,8 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) · 33 unmodified lines | ||
| 1756 | 1765 | * Zero on success, negative errno on failure. |
| 1757 | 1766 | */ |
| 1758 | 1767 | static int dtv_property_process_set(struct dvb_frontend *fe, |
| 1759 | − struct file *file, | |
| 1760 | − u32 cmd, u32 data) | |
| 1768 | + struct file *file, | |
| 1769 | + u32 cmd, u32 data) | |
| 1761 | 1770 | { |
| 1762 | 1771 | int r = 0; |
| 1763 | 1772 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| @@ -1765,11 +1774,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, · 1 unmodified line | ||
| 1765 | 1774 | /** Dump DTV command name and value*/ |
| 1766 | 1775 | if (!cmd || cmd > DTV_MAX_COMMAND) |
| 1767 | 1776 | dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n", |
| 1768 | − __func__, cmd); | |
| 1777 | + __func__, cmd); | |
| 1769 | 1778 | else |
| 1770 | 1779 | dev_dbg(fe->dvb->device, |
| 1771 | − "%s: SET cmd 0x%08x (%s) to 0x%08x\n", | |
| 1772 | − __func__, cmd, dtv_cmds[cmd].name, data); | |
| 1780 | + "%s: SET cmd 0x%08x (%s) to 0x%08x\n", | |
| 1781 | + __func__, cmd, dtv_cmds[cmd].name, data); | |
| 1773 | 1782 | switch (cmd) { |
| 1774 | 1783 | case DTV_CLEAR: |
| 1775 | 1784 | /* |
| @@ -1819,12 +1828,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, · 43 unmodified lines | ||
| 1819 | 1828 | case DTV_VOLTAGE: |
| 1820 | 1829 | c->voltage = data; |
| 1821 | 1830 | r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, |
| 1822 | − (void *)c->voltage); | |
| 1831 | + (void *)c->voltage); | |
| 1823 | 1832 | break; |
| 1824 | 1833 | case DTV_TONE: |
| 1825 | 1834 | c->sectone = data; |
| 1826 | 1835 | r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, |
| 1827 | − (void *)c->sectone); | |
| 1836 | + (void *)c->sectone); | |
| 1828 | 1837 | break; |
| 1829 | 1838 | case DTV_CODE_RATE_HP: |
| 1830 | 1839 | c->code_rate_HP = data; |
| @@ -2045,8 +2054,8 @@ static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd, · 214 unmodified lines | ||
| 2045 | 2054 | |
| 2046 | 2055 | for (i = 0; i < tvps->num; i++) { |
| 2047 | 2056 | err = dtv_property_process_set(fe, file, |
| 2048 | − (tvp + i)->cmd, | |
| 2049 | − (tvp + i)->u.data); | |
| 2057 | + (tvp + i)->cmd, | |
| 2058 | + (tvp + i)->u.data); | |
| 2050 | 2059 | if (err < 0) { |
| 2051 | 2060 | kfree(tvp); |
| 2052 | 2061 | return err; |
| @@ -2265,7 +2274,6 @@ static int dtv_set_frontend(struct dvb_frontend *fe) · 212 unmodified lines | ||
| 2265 | 2274 | return 0; |
| 2266 | 2275 | } |
| 2267 | 2276 | |
| 2268 | − | |
| 2269 | 2277 | static int dvb_frontend_handle_ioctl(struct file *file, |
| 2270 | 2278 | unsigned int cmd, void *parg) |
| 2271 | 2279 | { |
| @@ -2300,8 +2308,8 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 28 unmodified lines | ||
| 2300 | 2308 | |
| 2301 | 2309 | for (i = 0; i < tvps->num; i++) { |
| 2302 | 2310 | err = dtv_property_process_set(fe, file, |
| 2303 | − (tvp + i)->cmd, | |
| 2304 | − (tvp + i)->u.data); | |
| 2311 | + (tvp + i)->cmd, | |
| 2312 | + (tvp + i)->u.data); | |
| 2305 | 2313 | if (err < 0) { |
| 2306 | 2314 | kfree(tvp); |
| 2307 | 2315 | return err; |
| @@ -2365,7 +2373,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 57 unmodified lines | ||
| 2365 | 2373 | } |
| 2366 | 2374 | |
| 2367 | 2375 | case FE_GET_INFO: { |
| 2368 | − struct dvb_frontend_info* info = parg; | |
| 2376 | + struct dvb_frontend_info *info = parg; | |
| 2369 | 2377 | |
| 2370 | 2378 | memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); |
| 2371 | 2379 | dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); |
| @@ -2396,12 +2404,12 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 24 unmodified lines | ||
| 2396 | 2404 | break; |
| 2397 | 2405 | default: |
| 2398 | 2406 | dev_err(fe->dvb->device, |
| 2399 | − "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 2400 | − __func__, c->delivery_system); | |
| 2407 | + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", | |
| 2408 | + __func__, c->delivery_system); | |
| 2401 | 2409 | fe->ops.info.type = FE_OFDM; |
| 2402 | 2410 | } |
| 2403 | 2411 | dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", |
| 2404 | − __func__, c->delivery_system, fe->ops.info.type); | |
| 2412 | + __func__, c->delivery_system, fe->ops.info.type); | |
| 2405 | 2413 | |
| 2406 | 2414 | /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ |
| 2407 | 2415 | if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) |
| @@ -2417,7 +2425,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 9 unmodified lines | ||
| 2417 | 2425 | * that user get signal state from previous tuning */ |
| 2418 | 2426 | if (fepriv->state == FESTATE_RETUNE || |
| 2419 | 2427 | fepriv->state == FESTATE_ERROR) { |
| 2420 | − err=0; | |
| 2428 | + err = 0; | |
| 2421 | 2429 | *status = 0; |
| 2422 | 2430 | break; |
| 2423 | 2431 | } |
| @@ -2485,11 +2493,11 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 61 unmodified lines | ||
| 2485 | 2493 | |
| 2486 | 2494 | case FE_ENABLE_HIGH_LNB_VOLTAGE: |
| 2487 | 2495 | if (fe->ops.enable_high_lnb_voltage) |
| 2488 | − err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); | |
| 2496 | + err = fe->ops.enable_high_lnb_voltage(fe, (long)parg); | |
| 2489 | 2497 | break; |
| 2490 | 2498 | |
| 2491 | 2499 | case FE_SET_FRONTEND_TUNE_MODE: |
| 2492 | − fepriv->tune_mode_flags = (unsigned long) parg; | |
| 2500 | + fepriv->tune_mode_flags = (unsigned long)parg; | |
| 2493 | 2501 | err = 0; |
| 2494 | 2502 | break; |
| 2495 | 2503 | |
| @@ -2518,11 +2526,12 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 22 unmodified lines | ||
| 2518 | 2526 | * initialization, so parg is 8 bits and does not |
| 2519 | 2527 | * include the initialization or start bit |
| 2520 | 2528 | */ |
| 2521 | − unsigned long swcmd = ((unsigned long) parg) << 1; | |
| 2529 | + unsigned long swcmd = ((unsigned long)parg) << 1; | |
| 2522 | 2530 | ktime_t nexttime; |
| 2523 | 2531 | ktime_t tv[10]; |
| 2524 | 2532 | int i; |
| 2525 | 2533 | u8 last = 1; |
| 2534 | + | |
| 2526 | 2535 | if (dvb_frontend_debug) |
| 2527 | 2536 | dprintk("%s switch command: 0x%04lx\n", |
| 2528 | 2537 | __func__, swcmd); |
| @@ -2537,7 +2546,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 8 unmodified lines | ||
| 2537 | 2546 | |
| 2538 | 2547 | for (i = 0; i < 9; i++) { |
| 2539 | 2548 | if (dvb_frontend_debug) |
| 2540 | − tv[i+1] = ktime_get_boottime(); | |
| 2549 | + tv[i + 1] = ktime_get_boottime(); | |
| 2541 | 2550 | if ((swcmd & 0x01) != last) { |
| 2542 | 2551 | /* set voltage to (last ? 13V : 18V) */ |
| 2543 | 2552 | fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); |
| @@ -2552,7 +2561,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 8 unmodified lines | ||
| 2552 | 2561 | __func__, fe->dvb->num); |
| 2553 | 2562 | for (i = 1; i < 10; i++) |
| 2554 | 2563 | pr_info("%d: %d\n", i, |
| 2555 | − (int) ktime_us_delta(tv[i], tv[i-1])); | |
| 2564 | + (int)ktime_us_delta(tv[i], tv[i - 1])); | |
| 2556 | 2565 | } |
| 2557 | 2566 | err = 0; |
| 2558 | 2567 | fepriv->state = FESTATE_DISEQC; |
| @@ -2611,7 +2620,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 52 unmodified lines | ||
| 2611 | 2620 | err = dtv_set_frontend(fe); |
| 2612 | 2621 | break; |
| 2613 | 2622 | case FE_GET_EVENT: |
| 2614 | − err = dvb_frontend_get_event (fe, parg, file->f_flags); | |
| 2623 | + err = dvb_frontend_get_event(fe, parg, file->f_flags); | |
| 2615 | 2624 | break; |
| 2616 | 2625 | |
| 2617 | 2626 | case FE_GET_FRONTEND: { |
| @@ -2634,7 +2643,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, · 16 unmodified lines | ||
| 2634 | 2643 | return err; |
| 2635 | 2644 | } |
| 2636 | 2645 | |
| 2637 | − | |
| 2638 | 2646 | static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) |
| 2639 | 2647 | { |
| 2640 | 2648 | struct dvb_device *dvbdev = file->private_data; |
| @@ -2643,7 +2651,7 @@ static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *w · 2 unmodified lines | ||
| 2643 | 2651 | |
| 2644 | 2652 | dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__); |
| 2645 | 2653 | |
| 2646 | − poll_wait (file, &fepriv->events.wait_queue, wait); | |
| 2654 | + poll_wait(file, &fepriv->events.wait_queue, wait); | |
| 2647 | 2655 | |
| 2648 | 2656 | if (fepriv->events.eventw != fepriv->events.eventr) |
| 2649 | 2657 | return (EPOLLIN | EPOLLRDNORM | EPOLLPRI); |
| @@ -2664,9 +2672,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 14 unmodified lines | ||
| 2664 | 2672 | return -ENODEV; |
| 2665 | 2673 | |
| 2666 | 2674 | if (adapter->mfe_shared) { |
| 2667 | − mutex_lock (&adapter->mfe_lock); | |
| 2675 | + mutex_lock(&adapter->mfe_lock); | |
| 2668 | 2676 | |
| 2669 | − if (adapter->mfe_dvbdev == NULL) | |
| 2677 | + if (!adapter->mfe_dvbdev) | |
| 2670 | 2678 | adapter->mfe_dvbdev = dvbdev; |
| 2671 | 2679 | |
| 2672 | 2680 | else if (adapter->mfe_dvbdev != dvbdev) { |
| @@ -2678,23 +2686,23 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 5 unmodified lines | ||
| 2678 | 2686 | *mfepriv = mfe->frontend_priv; |
| 2679 | 2687 | int mferetry = (dvb_mfe_wait_time << 1); |
| 2680 | 2688 | |
| 2681 | − mutex_unlock (&adapter->mfe_lock); | |
| 2689 | + mutex_unlock(&adapter->mfe_lock); | |
| 2682 | 2690 | while (mferetry-- && (mfedev->users != -1 || |
| 2683 | − mfepriv->thread != NULL)) { | |
| 2684 | − if(msleep_interruptible(500)) { | |
| 2685 | − if(signal_pending(current)) | |
| 2691 | + mfepriv->thread)) { | |
| 2692 | + if (msleep_interruptible(500)) { | |
| 2693 | + if (signal_pending(current)) | |
| 2686 | 2694 | return -EINTR; |
| 2687 | 2695 | } |
| 2688 | 2696 | } |
| 2689 | 2697 | |
| 2690 | − mutex_lock (&adapter->mfe_lock); | |
| 2691 | − if(adapter->mfe_dvbdev != dvbdev) { | |
| 2698 | + mutex_lock(&adapter->mfe_lock); | |
| 2699 | + if (adapter->mfe_dvbdev != dvbdev) { | |
| 2692 | 2700 | mfedev = adapter->mfe_dvbdev; |
| 2693 | 2701 | mfe = mfedev->priv; |
| 2694 | 2702 | mfepriv = mfe->frontend_priv; |
| 2695 | 2703 | if (mfedev->users != -1 || |
| 2696 | − mfepriv->thread != NULL) { | |
| 2697 | − mutex_unlock (&adapter->mfe_lock); | |
| 2704 | + mfepriv->thread) { | |
| 2705 | + mutex_unlock(&adapter->mfe_lock); | |
| 2698 | 2706 | return -EBUSY; |
| 2699 | 2707 | } |
| 2700 | 2708 | adapter->mfe_dvbdev = dvbdev; |
| @@ -2715,7 +2723,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 14 unmodified lines | ||
| 2715 | 2723 | fepriv->reinitialise = 1; |
| 2716 | 2724 | } |
| 2717 | 2725 | |
| 2718 | − if ((ret = dvb_generic_open (inode, file)) < 0) | |
| 2726 | + if ((ret = dvb_generic_open(inode, file)) < 0) | |
| 2719 | 2727 | goto err1; |
| 2720 | 2728 | |
| 2721 | 2729 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { |
| @@ -2725,6 +2733,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 3 unmodified lines | ||
| 2725 | 2733 | fepriv->voltage = -1; |
| 2726 | 2734 | |
| 2727 | 2735 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
| 2736 | + mutex_lock(&fe->dvb->mdev_lock); | |
| 2728 | 2737 | if (fe->dvb->mdev) { |
| 2729 | 2738 | mutex_lock(&fe->dvb->mdev->graph_mutex); |
| 2730 | 2739 | if (fe->dvb->mdev->enable_source) |
| @@ -2733,13 +2742,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 2 unmodified lines | ||
| 2733 | 2742 | &fepriv->pipe); |
| 2734 | 2743 | mutex_unlock(&fe->dvb->mdev->graph_mutex); |
| 2735 | 2744 | if (ret) { |
| 2745 | + mutex_unlock(&fe->dvb->mdev_lock); | |
| 2736 | 2746 | dev_err(fe->dvb->device, |
| 2737 | 2747 | "Tuner is busy. Error %d\n", ret); |
| 2738 | 2748 | goto err2; |
| 2739 | 2749 | } |
| 2740 | 2750 | } |
| 2751 | + mutex_unlock(&fe->dvb->mdev_lock); | |
| 2741 | 2752 | #endif |
| 2742 | − ret = dvb_frontend_start (fe); | |
| 2753 | + ret = dvb_frontend_start(fe); | |
| 2743 | 2754 | if (ret) |
| 2744 | 2755 | goto err3; |
| 2745 | 2756 | |
| @@ -2750,17 +2761,19 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 4 unmodified lines | ||
| 2750 | 2761 | dvb_frontend_get(fe); |
| 2751 | 2762 | |
| 2752 | 2763 | if (adapter->mfe_shared) |
| 2753 | − mutex_unlock (&adapter->mfe_lock); | |
| 2764 | + mutex_unlock(&adapter->mfe_lock); | |
| 2754 | 2765 | return ret; |
| 2755 | 2766 | |
| 2756 | 2767 | err3: |
| 2757 | 2768 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
| 2769 | + mutex_lock(&fe->dvb->mdev_lock); | |
| 2758 | 2770 | if (fe->dvb->mdev) { |
| 2759 | 2771 | mutex_lock(&fe->dvb->mdev->graph_mutex); |
| 2760 | 2772 | if (fe->dvb->mdev->disable_source) |
| 2761 | 2773 | fe->dvb->mdev->disable_source(dvbdev->entity); |
| 2762 | 2774 | mutex_unlock(&fe->dvb->mdev->graph_mutex); |
| 2763 | 2775 | } |
| 2776 | + mutex_unlock(&fe->dvb->mdev_lock); | |
| 2764 | 2777 | err2: |
| 2765 | 2778 | #endif |
| 2766 | 2779 | dvb_generic_release(inode, file); |
| @@ -2769,7 +2782,7 @@ err1: · 2 unmodified lines | ||
| 2769 | 2782 | fe->ops.ts_bus_ctrl(fe, 0); |
| 2770 | 2783 | err0: |
| 2771 | 2784 | if (adapter->mfe_shared) |
| 2772 | − mutex_unlock (&adapter->mfe_lock); | |
| 2785 | + mutex_unlock(&adapter->mfe_lock); | |
| 2773 | 2786 | return ret; |
| 2774 | 2787 | } |
| 2775 | 2788 | |
| @@ -2787,17 +2800,19 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) · 11 unmodified lines | ||
| 2787 | 2800 | mb(); |
| 2788 | 2801 | } |
| 2789 | 2802 | |
| 2790 | − ret = dvb_generic_release (inode, file); | |
| 2803 | + ret = dvb_generic_release(inode, file); | |
| 2791 | 2804 | |
| 2792 | 2805 | if (dvbdev->users == -1) { |
| 2793 | 2806 | wake_up(&fepriv->wait_queue); |
| 2794 | 2807 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB |
| 2808 | + mutex_lock(&fe->dvb->mdev_lock); | |
| 2795 | 2809 | if (fe->dvb->mdev) { |
| 2796 | 2810 | mutex_lock(&fe->dvb->mdev->graph_mutex); |
| 2797 | 2811 | if (fe->dvb->mdev->disable_source) |
| 2798 | 2812 | fe->dvb->mdev->disable_source(dvbdev->entity); |
| 2799 | 2813 | mutex_unlock(&fe->dvb->mdev->graph_mutex); |
| 2800 | 2814 | } |
| 2815 | + mutex_unlock(&fe->dvb->mdev_lock); | |
| 2801 | 2816 | #endif |
| 2802 | 2817 | if (fe->exit != DVB_FE_NO_EXIT) |
| 2803 | 2818 | wake_up(&dvbdev->wait_queue); |
| @@ -2827,7 +2842,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) · 23 unmodified lines | ||
| 2827 | 2842 | int ret = 0; |
| 2828 | 2843 | |
| 2829 | 2844 | dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, |
| 2830 | − fe->id); | |
| 2845 | + fe->id); | |
| 2831 | 2846 | |
| 2832 | 2847 | if (fe->ops.tuner_ops.suspend) |
| 2833 | 2848 | ret = fe->ops.tuner_ops.suspend(fe); |
| @@ -2847,7 +2862,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe) · 13 unmodified lines | ||
| 2847 | 2862 | int ret = 0; |
| 2848 | 2863 | |
| 2849 | 2864 | dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, |
| 2850 | − fe->id); | |
| 2865 | + fe->id); | |
| 2851 | 2866 | |
| 2852 | 2867 | fe->exit = DVB_FE_DEVICE_RESUME; |
| 2853 | 2868 | if (fe->ops.init) |
| @@ -2871,14 +2886,14 @@ int dvb_frontend_resume(struct dvb_frontend *fe) · 17 unmodified lines | ||
| 2871 | 2886 | } |
| 2872 | 2887 | EXPORT_SYMBOL(dvb_frontend_resume); |
| 2873 | 2888 | |
| 2874 | −int dvb_register_frontend(struct dvb_adapter* dvb, | |
| 2875 | − struct dvb_frontend* fe) | |
| 2889 | +int dvb_register_frontend(struct dvb_adapter *dvb, | |
| 2890 | + struct dvb_frontend *fe) | |
| 2876 | 2891 | { |
| 2877 | 2892 | struct dvb_frontend_private *fepriv; |
| 2878 | 2893 | const struct dvb_device dvbdev_template = { |
| 2879 | 2894 | .users = ~0, |
| 2880 | 2895 | .writers = 1, |
| 2881 | − .readers = (~0)-1, | |
| 2896 | + .readers = (~0) - 1, | |
| 2882 | 2897 | .fops = &dvb_frontend_fops, |
| 2883 | 2898 | #if defined(CONFIG_MEDIA_CONTROLLER_DVB) |
| 2884 | 2899 | .name = fe->ops.info.name, |
| @@ -2891,7 +2906,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, · 6 unmodified lines | ||
| 2891 | 2906 | return -ERESTARTSYS; |
| 2892 | 2907 | |
| 2893 | 2908 | fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); |
| 2894 | − if (fe->frontend_priv == NULL) { | |
| 2909 | + if (!fe->frontend_priv) { | |
| 2895 | 2910 | mutex_unlock(&frontend_mutex); |
| 2896 | 2911 | return -ENOMEM; |
| 2897 | 2912 | } |
| @@ -2907,18 +2922,18 @@ int dvb_register_frontend(struct dvb_adapter* dvb, · 9 unmodified lines | ||
| 2907 | 2922 | dvb_frontend_get(fe); |
| 2908 | 2923 | |
| 2909 | 2924 | sema_init(&fepriv->sem, 1); |
| 2910 | − init_waitqueue_head (&fepriv->wait_queue); | |
| 2911 | − init_waitqueue_head (&fepriv->events.wait_queue); | |
| 2925 | + init_waitqueue_head(&fepriv->wait_queue); | |
| 2926 | + init_waitqueue_head(&fepriv->events.wait_queue); | |
| 2912 | 2927 | mutex_init(&fepriv->events.mtx); |
| 2913 | 2928 | fe->dvb = dvb; |
| 2914 | 2929 | fepriv->inversion = INVERSION_OFF; |
| 2915 | 2930 | |
| 2916 | 2931 | dev_info(fe->dvb->device, |
| 2917 | − "DVB: registering adapter %i frontend %i (%s)...\n", | |
| 2918 | − fe->dvb->num, fe->id, fe->ops.info.name); | |
| 2932 | + "DVB: registering adapter %i frontend %i (%s)...\n", | |
| 2933 | + fe->dvb->num, fe->id, fe->ops.info.name); | |
| 2919 | 2934 | |
| 2920 | − dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, | |
| 2921 | − fe, DVB_DEVICE_FRONTEND, 0); | |
| 2935 | + dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, | |
| 2936 | + fe, DVB_DEVICE_FRONTEND, 0); | |
| 2922 | 2937 | |
| 2923 | 2938 | /* |
| 2924 | 2939 | * Initialize the cache to the proper values according with the |
| @@ -2933,9 +2948,10 @@ int dvb_register_frontend(struct dvb_adapter* dvb, · 8 unmodified lines | ||
| 2933 | 2948 | } |
| 2934 | 2949 | EXPORT_SYMBOL(dvb_register_frontend); |
| 2935 | 2950 | |
| 2936 | −int dvb_unregister_frontend(struct dvb_frontend* fe) | |
| 2951 | +int dvb_unregister_frontend(struct dvb_frontend *fe) | |
| 2937 | 2952 | { |
| 2938 | 2953 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
| 2954 | + | |
| 2939 | 2955 | dev_dbg(fe->dvb->device, "%s:\n", __func__); |
| 2940 | 2956 | |
| 2941 | 2957 | mutex_lock(&frontend_mutex); |
| @@ -2960,7 +2976,7 @@ static void dvb_frontend_invoke_release(struct dvb_frontend *fe, · 18 unmodified lines | ||
| 2960 | 2976 | } |
| 2961 | 2977 | } |
| 2962 | 2978 | |
| 2963 | −void dvb_frontend_detach(struct dvb_frontend* fe) | |
| 2979 | +void dvb_frontend_detach(struct dvb_frontend *fe) | |
| 2964 | 2980 | { |
| 2965 | 2981 | dvb_frontend_invoke_release(fe, fe->ops.release_sec); |
| 2966 | 2982 | dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); |
| @@ -1005,7 +1005,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, · 1004 unmodified lines | ||
| 1005 | 1005 | return 0; |
| 1006 | 1006 | } |
| 1007 | 1007 | |
| 1008 | −static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) | |
| 1008 | +static netdev_tx_t dvb_net_tx(struct sk_buff *skb, struct net_device *dev) | |
| 1009 | 1009 | { |
| 1010 | 1010 | dev_kfree_skb(skb); |
| 1011 | 1011 | return NETDEV_TX_OK; |
| @@ -859,6 +859,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, · 858 unmodified lines | ||
| 859 | 859 | adap->mfe_dvbdev = NULL; |
| 860 | 860 | mutex_init (&adap->mfe_lock); |
| 861 | 861 | |
| 862 | +#ifdef CONFIG_MEDIA_CONTROLLER_DVB | |
| 863 | + mutex_init(&adap->mdev_lock); | |
| 864 | +#endif | |
| 865 | + | |
| 862 | 866 | list_add_tail (&adap->list_head, &dvb_adapter_list); |
| 863 | 867 | |
| 864 | 868 | mutex_unlock(&dvbdev_register_lock); |
| @@ -903,7 +903,7 @@ comment "Common Interface (EN50221) controller drivers" · 902 unmodified lines | ||
| 903 | 903 | depends on DVB_CORE |
| 904 | 904 | |
| 905 | 905 | config DVB_CXD2099 |
| 906 | − tristate "CXD2099AR Common Interface driver" | |
| 906 | + tristate "Sony CXD2099AR Common Interface driver" | |
| 907 | 907 | depends on DVB_CORE && I2C |
| 908 | 908 | select REGMAP_I2C |
| 909 | 909 | default m if !MEDIA_SUBDRV_AUTOSELECT |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Abilis Systems Single DVB-T Receiver |
| 3 | − * Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@samsung.com> | |
| 3 | + * Copyright (C) 2014 Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
| 4 | 4 | * |
| 5 | 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | 6 | * it under the terms of the GNU General Public License as published by |
| @@ -280,14 +280,12 @@ static void setup_decoder_defaults(struct au8522_state *state, bool is_svideo) · 279 unmodified lines | ||
| 280 | 280 | AU8522_TOREGAAGC_REG0E5H_CVBS); |
| 281 | 281 | au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS); |
| 282 | 282 | |
| 283 | − if (is_svideo) { | |
| 284 | − /* Despite what the table says, for the HVR-950q we still need | |
| 285 | − to be in CVBS mode for the S-Video input (reason unknown). */ | |
| 286 | − /* filter_coef_type = 3; */ | |
| 287 | − filter_coef_type = 5; | |
| 288 | − } else { | |
| 289 | − filter_coef_type = 5; | |
| 290 | − } | |
| 283 | + /* | |
| 284 | + * Despite what the table says, for the HVR-950q we still need | |
| 285 | + * to be in CVBS mode for the S-Video input (reason unknown). | |
| 286 | + */ | |
| 287 | + /* filter_coef_type = 3; */ | |
| 288 | + filter_coef_type = 5; | |
| 291 | 289 | |
| 292 | 290 | /* Load the Video Decoder Filter Coefficients */ |
| 293 | 291 | for (i = 0; i < NUM_FILTER_COEF; i++) { |
| @@ -1456,7 +1456,7 @@ static int cx24116_tune(struct dvb_frontend *fe, bool re_tune, · 1455 unmodified lines | ||
| 1456 | 1456 | return cx24116_read_status(fe, status); |
| 1457 | 1457 | } |
| 1458 | 1458 | |
| 1459 | −static int cx24116_get_algo(struct dvb_frontend *fe) | |
| 1459 | +static enum dvbfe_algo cx24116_get_algo(struct dvb_frontend *fe) | |
| 1460 | 1460 | { |
| 1461 | 1461 | return DVBFE_ALGO_HW; |
| 1462 | 1462 | } |
| @@ -1555,7 +1555,7 @@ static int cx24117_tune(struct dvb_frontend *fe, bool re_tune, · 1554 unmodified lines | ||
| 1555 | 1555 | return cx24117_read_status(fe, status); |
| 1556 | 1556 | } |
| 1557 | 1557 | |
| 1558 | −static int cx24117_get_algo(struct dvb_frontend *fe) | |
| 1558 | +static enum dvbfe_algo cx24117_get_algo(struct dvb_frontend *fe) | |
| 1559 | 1559 | { |
| 1560 | 1560 | return DVBFE_ALGO_HW; |
| 1561 | 1561 | } |
| @@ -1491,7 +1491,7 @@ static int cx24120_tune(struct dvb_frontend *fe, bool re_tune, · 1490 unmodified lines | ||
| 1491 | 1491 | return cx24120_read_status(fe, status); |
| 1492 | 1492 | } |
| 1493 | 1493 | |
| 1494 | −static int cx24120_get_algo(struct dvb_frontend *fe) | |
| 1494 | +static enum dvbfe_algo cx24120_get_algo(struct dvb_frontend *fe) | |
| 1495 | 1495 | { |
| 1496 | 1496 | return DVBFE_ALGO_HW; |
| 1497 | 1497 | } |
| @@ -1005,7 +1005,7 @@ static int cx24123_tune(struct dvb_frontend *fe, · 1004 unmodified lines | ||
| 1005 | 1005 | return retval; |
| 1006 | 1006 | } |
| 1007 | 1007 | |
| 1008 | −static int cx24123_get_algo(struct dvb_frontend *fe) | |
| 1008 | +static enum dvbfe_algo cx24123_get_algo(struct dvb_frontend *fe) | |
| 1009 | 1009 | { |
| 1010 | 1010 | return DVBFE_ALGO_HW; |
| 1011 | 1011 | } |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | /* |
| 2 | − * cxd2099.c: Driver for the CXD2099AR Common Interface Controller | |
| 2 | + * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller | |
| 3 | 3 | * |
| 4 | 4 | * Copyright (C) 2010-2013 Digital Devices GmbH |
| 5 | 5 | * |
| @@ -699,6 +699,6 @@ static struct i2c_driver cxd2099_driver = { · 693 unmodified lines | ||
| 699 | 699 | |
| 700 | 700 | module_i2c_driver(cxd2099_driver); |
| 701 | 701 | |
| 702 | −MODULE_DESCRIPTION("CXD2099AR Common Interface controller driver"); | |
| 702 | +MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver"); | |
| 703 | 703 | MODULE_AUTHOR("Ralph Metzler"); |
| 704 | 704 | MODULE_LICENSE("GPL"); |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | /* |
| 2 | − * cxd2099.h: Driver for the CXD2099AR Common Interface Controller | |
| 2 | + * cxd2099.h: Driver for the Sony CXD2099AR Common Interface Controller | |
| 3 | 3 | * |
| 4 | 4 | * Copyright (C) 2010-2011 Digital Devices GmbH |
| 5 | 5 | * |
| @@ -403,7 +403,7 @@ error: · 402 unmodified lines | ||
| 403 | 403 | return DVBFE_ALGO_SEARCH_ERROR; |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | −static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) | |
| 406 | +static enum dvbfe_algo cxd2820r_get_frontend_algo(struct dvb_frontend *fe) | |
| 407 | 407 | { |
| 408 | 408 | return DVBFE_ALGO_CUSTOM; |
| 409 | 409 | } |
| @@ -7,6 +7,6 @@ · 6 unmodified lines | ||
| 7 | 7 | * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation |
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | −#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.4" | |
| 10 | +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.5" | |
| 11 | 11 | |
| 12 | −#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-01-17" | |
| 12 | +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-04-25" | |
| @@ -520,6 +520,15 @@ static int cxd2880_init(struct dvb_frontend *fe) · 519 unmodified lines | ||
| 520 | 520 | pr_err("cxd2880 integ init failed %d\n", ret); |
| 521 | 521 | return ret; |
| 522 | 522 | } |
| 523 | + | |
| 524 | + ret = cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, | |
| 525 | + CXD2880_TNRDMD_CFG_TSPIN_CURRENT, | |
| 526 | + 0x00); | |
| 527 | + if (ret) { | |
| 528 | + mutex_unlock(priv->spi_mutex); | |
| 529 | + pr_err("cxd2880 set config failed %d\n", ret); | |
| 530 | + return ret; | |
| 531 | + } | |
| 523 | 532 | mutex_unlock(priv->spi_mutex); |
| 524 | 533 | |
| 525 | 534 | pr_debug("OK.\n"); |
| @@ -1126,7 +1135,7 @@ static int cxd2880_get_stats(struct dvb_frontend *fe, · 600 unmodified lines | ||
| 1126 | 1135 | priv = fe->demodulator_priv; |
| 1127 | 1136 | c = &fe->dtv_property_cache; |
| 1128 | 1137 | |
| 1129 | − if (!(status & FE_HAS_LOCK)) { | |
| 1138 | + if (!(status & FE_HAS_LOCK) || !(status & FE_HAS_CARRIER)) { | |
| 1130 | 1139 | c->pre_bit_error.len = 1; |
| 1131 | 1140 | c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 1132 | 1141 | c->pre_bit_count.len = 1; |
| @@ -1345,7 +1354,8 @@ static int cxd2880_read_status(struct dvb_frontend *fe, · 212 unmodified lines | ||
| 1345 | 1354 | |
| 1346 | 1355 | pr_debug("status %d\n", *status); |
| 1347 | 1356 | |
| 1348 | − if (priv->s == 0 && (*status & FE_HAS_LOCK)) { | |
| 1357 | + if (priv->s == 0 && (*status & FE_HAS_LOCK) && | |
| 1358 | + (*status & FE_HAS_CARRIER)) { | |
| 1349 | 1359 | mutex_lock(priv->spi_mutex); |
| 1350 | 1360 | if (c->delivery_system == SYS_DVBT) { |
| 1351 | 1361 | ret = cxd2880_set_ber_per_period_t(fe); |
| @@ -533,6 +533,45 @@ static const struct dvb_pll_desc dvb_pll_alps_tdee4 = { · 532 unmodified lines | ||
| 533 | 533 | } |
| 534 | 534 | }; |
| 535 | 535 | |
| 536 | +/* Infineon TUA6034 ISDB-T, used in Friio */ | |
| 537 | +/* CP cur. 50uA, AGC takeover: 103dBuV, PORT3 on */ | |
| 538 | +static const struct dvb_pll_desc dvb_pll_tua6034_friio = { | |
| 539 | + .name = "Infineon TUA6034 ISDB-T (Friio)", | |
| 540 | + .min = 90000000, | |
| 541 | + .max = 770000000, | |
| 542 | + .iffreq = 57000000, | |
| 543 | + .initdata = (u8[]){ 4, 0x9a, 0x50, 0xb2, 0x08 }, | |
| 544 | + .sleepdata = (u8[]){ 4, 0x9a, 0x70, 0xb3, 0x0b }, | |
| 545 | + .count = 3, | |
| 546 | + .entries = { | |
| 547 | + { 170000000, 142857, 0xba, 0x09 }, | |
| 548 | + { 470000000, 142857, 0xba, 0x0a }, | |
| 549 | + { 770000000, 142857, 0xb2, 0x08 }, | |
| 550 | + } | |
| 551 | +}; | |
| 552 | + | |
| 553 | +/* Philips TDA6651 ISDB-T, used in Earthsoft PT1 */ | |
| 554 | +static const struct dvb_pll_desc dvb_pll_tda665x_earth_pt1 = { | |
| 555 | + .name = "Philips TDA6651 ISDB-T (EarthSoft PT1)", | |
| 556 | + .min = 90000000, | |
| 557 | + .max = 770000000, | |
| 558 | + .iffreq = 57000000, | |
| 559 | + .initdata = (u8[]){ 5, 0x0e, 0x7f, 0xc1, 0x80, 0x80 }, | |
| 560 | + .count = 10, | |
| 561 | + .entries = { | |
| 562 | + { 140000000, 142857, 0xc1, 0x81 }, | |
| 563 | + { 170000000, 142857, 0xc1, 0xa1 }, | |
| 564 | + { 220000000, 142857, 0xc1, 0x62 }, | |
| 565 | + { 330000000, 142857, 0xc1, 0xa2 }, | |
| 566 | + { 402000000, 142857, 0xc1, 0xe2 }, | |
| 567 | + { 450000000, 142857, 0xc1, 0x64 }, | |
| 568 | + { 550000000, 142857, 0xc1, 0x84 }, | |
| 569 | + { 600000000, 142857, 0xc1, 0xa4 }, | |
| 570 | + { 700000000, 142857, 0xc1, 0xc4 }, | |
| 571 | + { 770000000, 142857, 0xc1, 0xe4 }, | |
| 572 | + } | |
| 573 | +}; | |
| 574 | + | |
| 536 | 575 | /* ----------------------------------------------------------- */ |
| 537 | 576 | |
| 538 | 577 | static const struct dvb_pll_desc *pll_list[] = { |
| @@ -556,6 +595,8 @@ static const struct dvb_pll_desc *pll_list[] = { · 17 unmodified lines | ||
| 556 | 595 | [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0, |
| 557 | 596 | [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132, |
| 558 | 597 | [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112, |
| 598 | + [DVB_PLL_TUA6034_FRIIO] = &dvb_pll_tua6034_friio, | |
| 599 | + [DVB_PLL_TDA665X_EARTH_PT1] = &dvb_pll_tda665x_earth_pt1, | |
| 559 | 600 | }; |
| 560 | 601 | |
| 561 | 602 | /* ----------------------------------------------------------- */ |
| @@ -827,6 +868,75 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, · 265 unmodified lines | ||
| 827 | 868 | } |
| 828 | 869 | EXPORT_SYMBOL(dvb_pll_attach); |
| 829 | 870 | |
| 871 | + | |
| 872 | +static int | |
| 873 | +dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) | |
| 874 | +{ | |
| 875 | + struct dvb_pll_config *cfg; | |
| 876 | + struct dvb_frontend *fe; | |
| 877 | + unsigned int desc_id; | |
| 878 | + | |
| 879 | + cfg = client->dev.platform_data; | |
| 880 | + fe = cfg->fe; | |
| 881 | + i2c_set_clientdata(client, fe); | |
| 882 | + desc_id = (unsigned int) id->driver_data; | |
| 883 | + | |
| 884 | + if (!dvb_pll_attach(fe, client->addr, client->adapter, desc_id)) | |
| 885 | + return -ENOMEM; | |
| 886 | + | |
| 887 | + dev_info(&client->dev, "DVB Simple Tuner attached.\n"); | |
| 888 | + return 0; | |
| 889 | +} | |
| 890 | + | |
| 891 | +static int dvb_pll_remove(struct i2c_client *client) | |
| 892 | +{ | |
| 893 | + struct dvb_frontend *fe; | |
| 894 | + | |
| 895 | + fe = i2c_get_clientdata(client); | |
| 896 | + dvb_pll_release(fe); | |
| 897 | + return 0; | |
| 898 | +} | |
| 899 | + | |
| 900 | + | |
| 901 | +static const struct i2c_device_id dvb_pll_id[] = { | |
| 902 | + {"dtt7579", DVB_PLL_THOMSON_DTT7579}, | |
| 903 | + {"dtt759x", DVB_PLL_THOMSON_DTT759X}, | |
| 904 | + {"z201", DVB_PLL_LG_Z201}, | |
| 905 | + {"unknown_1", DVB_PLL_UNKNOWN_1}, | |
| 906 | + {"tua6010xs", DVB_PLL_TUA6010XS}, | |
| 907 | + {"env57h1xd5", DVB_PLL_ENV57H1XD5}, | |
| 908 | + {"tua6034", DVB_PLL_TUA6034}, | |
| 909 | + {"tda665x", DVB_PLL_TDA665X}, | |
| 910 | + {"tded4", DVB_PLL_TDED4}, | |
| 911 | + {"tdhu2", DVB_PLL_TDHU2}, | |
| 912 | + {"tbmv", DVB_PLL_SAMSUNG_TBMV}, | |
| 913 | + {"sd1878_tda8261", DVB_PLL_PHILIPS_SD1878_TDA8261}, | |
| 914 | + {"opera1", DVB_PLL_OPERA1}, | |
| 915 | + {"dtos403ih102a", DVB_PLL_SAMSUNG_DTOS403IH102A}, | |
| 916 | + {"tdtc9251dh0", DVB_PLL_SAMSUNG_TDTC9251DH0}, | |
| 917 | + {"tbdu18132", DVB_PLL_SAMSUNG_TBDU18132}, | |
| 918 | + {"tbmu24112", DVB_PLL_SAMSUNG_TBMU24112}, | |
| 919 | + {"tdee4", DVB_PLL_TDEE4}, | |
| 920 | + {"dtt7520x", DVB_PLL_THOMSON_DTT7520X}, | |
| 921 | + {"tua6034_friio", DVB_PLL_TUA6034_FRIIO}, | |
| 922 | + {"tda665x_earthpt1", DVB_PLL_TDA665X_EARTH_PT1}, | |
| 923 | + {} | |
| 924 | +}; | |
| 925 | + | |
| 926 | + | |
| 927 | +MODULE_DEVICE_TABLE(i2c, dvb_pll_id); | |
| 928 | + | |
| 929 | +static struct i2c_driver dvb_pll_driver = { | |
| 930 | + .driver = { | |
| 931 | + .name = "dvb_pll", | |
| 932 | + }, | |
| 933 | + .probe = dvb_pll_probe, | |
| 934 | + .remove = dvb_pll_remove, | |
| 935 | + .id_table = dvb_pll_id, | |
| 936 | +}; | |
| 937 | + | |
| 938 | +module_i2c_driver(dvb_pll_driver); | |
| 939 | + | |
| 830 | 940 | MODULE_DESCRIPTION("dvb pll library"); |
| 831 | 941 | MODULE_AUTHOR("Gerd Knorr"); |
| 832 | 942 | MODULE_LICENSE("GPL"); |
| @@ -29,6 +29,12 @@ · 28 unmodified lines | ||
| 29 | 29 | #define DVB_PLL_SAMSUNG_TBMU24112 17 |
| 30 | 30 | #define DVB_PLL_TDEE4 18 |
| 31 | 31 | #define DVB_PLL_THOMSON_DTT7520X 19 |
| 32 | +#define DVB_PLL_TUA6034_FRIIO 20 | |
| 33 | +#define DVB_PLL_TDA665X_EARTH_PT1 21 | |
| 34 | + | |
| 35 | +struct dvb_pll_config { | |
| 36 | + struct dvb_frontend *fe; | |
| 37 | +}; | |
| 32 | 38 | |
| 33 | 39 | #if IS_REACHABLE(CONFIG_DVB_PLL) |
| 34 | 40 | /** |
| @@ -546,7 +546,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, · 545 unmodified lines | ||
| 546 | 546 | |
| 547 | 547 | /* Responds to all reads with 0 */ |
| 548 | 548 | if (l64781_readreg(state, 0x1a) != 0) { |
| 549 | − dprintk("Read 1 returned unexpcted value\n"); | |
| 549 | + dprintk("Read 1 returned unexpected value\n"); | |
| 550 | 550 | goto error; |
| 551 | 551 | } |
| 552 | 552 | |
| @@ -555,7 +555,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, · 2 unmodified lines | ||
| 555 | 555 | |
| 556 | 556 | /* Responds with register default value */ |
| 557 | 557 | if (l64781_readreg(state, 0x1a) != 0xa1) { |
| 558 | − dprintk("Read 2 returned unexpcted value\n"); | |
| 558 | + dprintk("Read 2 returned unexpected value\n"); | |
| 559 | 559 | goto error; |
| 560 | 560 | } |
| 561 | 561 | |
| @@ -1784,7 +1784,7 @@ static int lgdt3306a_get_tune_settings(struct dvb_frontend *fe, · 1783 unmodified lines | ||
| 1784 | 1784 | return 0; |
| 1785 | 1785 | } |
| 1786 | 1786 | |
| 1787 | −static int lgdt3306a_search(struct dvb_frontend *fe) | |
| 1787 | +static enum dvbfe_search lgdt3306a_search(struct dvb_frontend *fe) | |
| 1788 | 1788 | { |
| 1789 | 1789 | enum fe_status status = 0; |
| 1790 | 1790 | int ret; |
| @@ -47,50 +47,50 @@ · 46 unmodified lines | ||
| 47 | 47 | |
| 48 | 48 | static int debug; |
| 49 | 49 | module_param(debug, int, 0644); |
| 50 | −MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); | |
| 51 | −#define dprintk(args...) \ | |
| 52 | −do { \ | |
| 53 | −if (debug) printk(KERN_DEBUG "lgdt330x: " args); \ | |
| 50 | +MODULE_PARM_DESC(debug, "Turn on/off lgdt330x frontend debugging (default:off)."); | |
| 51 | + | |
| 52 | +#define dprintk(state, fmt, arg...) do { \ | |
| 53 | + if (debug) \ | |
| 54 | + dev_printk(KERN_DEBUG, &state->client->dev, fmt, ##arg);\ | |
| 54 | 55 | } while (0) |
| 55 | 56 | |
| 56 | −struct lgdt330x_state | |
| 57 | −{ | |
| 58 | − struct i2c_adapter* i2c; | |
| 57 | +struct lgdt330x_state { | |
| 58 | + struct i2c_client *client; | |
| 59 | 59 | |
| 60 | 60 | /* Configuration settings */ |
| 61 | − const struct lgdt330x_config* config; | |
| 61 | + struct lgdt330x_config config; | |
| 62 | 62 | |
| 63 | 63 | struct dvb_frontend frontend; |
| 64 | 64 | |
| 65 | 65 | /* Demodulator private data */ |
| 66 | 66 | enum fe_modulation current_modulation; |
| 67 | − u32 snr; /* Result of last SNR calculation */ | |
| 67 | + u32 snr; /* Result of last SNR calculation */ | |
| 68 | + u16 ucblocks; | |
| 69 | + unsigned long last_stats_time; | |
| 68 | 70 | |
| 69 | 71 | /* Tuner private data */ |
| 70 | 72 | u32 current_frequency; |
| 71 | 73 | }; |
| 72 | 74 | |
| 73 | −static int i2c_write_demod_bytes (struct lgdt330x_state* state, | |
| 74 | − u8 *buf, /* data bytes to send */ | |
| 75 | − int len /* number of bytes to send */ ) | |
| 75 | +static int i2c_write_demod_bytes(struct lgdt330x_state *state, | |
| 76 | + const u8 *buf, /* data bytes to send */ | |
| 77 | + int len /* number of bytes to send */) | |
| 76 | 78 | { |
| 77 | − struct i2c_msg msg = | |
| 78 | − { .addr = state->config->demod_address, | |
| 79 | − .flags = 0, | |
| 80 | − .buf = buf, | |
| 81 | − .len = 2 }; | |
| 82 | 79 | int i; |
| 83 | 80 | int err; |
| 84 | 81 | |
| 85 | − for (i=0; i<len-1; i+=2){ | |
| 86 | − if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | |
| 87 | − printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err); | |
| 82 | + for (i = 0; i < len - 1; i += 2) { | |
| 83 | + err = i2c_master_send(state->client, buf, 2); | |
| 84 | + if (err != 2) { | |
| 85 | + dev_warn(&state->client->dev, | |
| 86 | + "%s: error (addr %02x <- %02x, err = %i)\n", | |
| 87 | + __func__, buf[0], buf[1], err); | |
| 88 | 88 | if (err < 0) |
| 89 | 89 | return err; |
| 90 | 90 | else |
| 91 | 91 | return -EREMOTEIO; |
| 92 | 92 | } |
| 93 | − msg.buf += 2; | |
| 93 | + buf += 2; | |
| 94 | 94 | } |
| 95 | 95 | return 0; |
| 96 | 96 | } |
| @@ -99,21 +99,30 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state, · 2 unmodified lines | ||
| 99 | 99 | * This routine writes the register (reg) to the demod bus |
| 100 | 100 | * then reads the data returned for (len) bytes. |
| 101 | 101 | */ |
| 102 | − | |
| 103 | 102 | static int i2c_read_demod_bytes(struct lgdt330x_state *state, |
| 104 | 103 | enum I2C_REG reg, u8 *buf, int len) |
| 105 | 104 | { |
| 106 | − u8 wr [] = { reg }; | |
| 107 | − struct i2c_msg msg [] = { | |
| 108 | − { .addr = state->config->demod_address, | |
| 109 | − .flags = 0, .buf = wr, .len = 1 }, | |
| 110 | − { .addr = state->config->demod_address, | |
| 111 | − .flags = I2C_M_RD, .buf = buf, .len = len }, | |
| 105 | + u8 wr[] = { reg }; | |
| 106 | + struct i2c_msg msg[] = { | |
| 107 | + { | |
| 108 | + .addr = state->client->addr, | |
| 109 | + .flags = 0, | |
| 110 | + .buf = wr, | |
| 111 | + .len = 1 | |
| 112 | + }, { | |
| 113 | + .addr = state->client->addr, | |
| 114 | + .flags = I2C_M_RD, | |
| 115 | + .buf = buf, | |
| 116 | + .len = len | |
| 117 | + }, | |
| 112 | 118 | }; |
| 113 | 119 | int ret; |
| 114 | − ret = i2c_transfer(state->i2c, msg, 2); | |
| 120 | + | |
| 121 | + ret = i2c_transfer(state->client->adapter, msg, 2); | |
| 115 | 122 | if (ret != 2) { |
| 116 | − printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); | |
| 123 | + dev_warn(&state->client->dev, | |
| 124 | + "%s: addr 0x%02x select 0x%02x error (ret == %i)\n", | |
| 125 | + __func__, state->client->addr, reg, ret); | |
| 117 | 126 | if (ret >= 0) |
| 118 | 127 | ret = -EIO; |
| 119 | 128 | } else { |
| @@ -123,19 +132,21 @@ static int i2c_read_demod_bytes(struct lgdt330x_state *state, · 3 unmodified lines | ||
| 123 | 132 | } |
| 124 | 133 | |
| 125 | 134 | /* Software reset */ |
| 126 | −static int lgdt3302_SwReset(struct lgdt330x_state* state) | |
| 135 | +static int lgdt3302_sw_reset(struct lgdt330x_state *state) | |
| 127 | 136 | { |
| 128 | 137 | u8 ret; |
| 129 | 138 | u8 reset[] = { |
| 130 | 139 | IRQ_MASK, |
| 131 | − 0x00 /* bit 6 is active low software reset | |
| 132 | − * bits 5-0 are 1 to mask interrupts */ | |
| 140 | + /* | |
| 141 | + * bit 6 is active low software reset | |
| 142 | + * bits 5-0 are 1 to mask interrupts | |
| 143 | + */ | |
| 144 | + 0x00 | |
| 133 | 145 | }; |
| 134 | 146 | |
| 135 | 147 | ret = i2c_write_demod_bytes(state, |
| 136 | 148 | reset, sizeof(reset)); |
| 137 | 149 | if (ret == 0) { |
| 138 | − | |
| 139 | 150 | /* force reset high (inactive) and unmask interrupts */ |
| 140 | 151 | reset[1] = 0x7f; |
| 141 | 152 | ret = i2c_write_demod_bytes(state, |
| @@ -144,7 +155,7 @@ static int lgdt3302_SwReset(struct lgdt330x_state* state) · 2 unmodified lines | ||
| 144 | 155 | return ret; |
| 145 | 156 | } |
| 146 | 157 | |
| 147 | −static int lgdt3303_SwReset(struct lgdt330x_state* state) | |
| 158 | +static int lgdt3303_sw_reset(struct lgdt330x_state *state) | |
| 148 | 159 | { |
| 149 | 160 | u8 ret; |
| 150 | 161 | u8 reset[] = { |
| @@ -155,7 +166,6 @@ static int lgdt3303_SwReset(struct lgdt330x_state* state) · 4 unmodified lines | ||
| 155 | 166 | ret = i2c_write_demod_bytes(state, |
| 156 | 167 | reset, sizeof(reset)); |
| 157 | 168 | if (ret == 0) { |
| 158 | − | |
| 159 | 169 | /* force reset high (inactive) */ |
| 160 | 170 | reset[1] = 0x01; |
| 161 | 171 | ret = i2c_write_demod_bytes(state, |
| @@ -164,81 +174,94 @@ static int lgdt3303_SwReset(struct lgdt330x_state* state) · 2 unmodified lines | ||
| 164 | 174 | return ret; |
| 165 | 175 | } |
| 166 | 176 | |
| 167 | −static int lgdt330x_SwReset(struct lgdt330x_state* state) | |
| 177 | +static int lgdt330x_sw_reset(struct lgdt330x_state *state) | |
| 168 | 178 | { |
| 169 | − switch (state->config->demod_chip) { | |
| 179 | + switch (state->config.demod_chip) { | |
| 170 | 180 | case LGDT3302: |
| 171 | − return lgdt3302_SwReset(state); | |
| 181 | + return lgdt3302_sw_reset(state); | |
| 172 | 182 | case LGDT3303: |
| 173 | − return lgdt3303_SwReset(state); | |
| 183 | + return lgdt3303_sw_reset(state); | |
| 174 | 184 | default: |
| 175 | 185 | return -ENODEV; |
| 176 | 186 | } |
| 177 | 187 | } |
| 178 | 188 | |
| 179 | −static int lgdt330x_init(struct dvb_frontend* fe) | |
| 189 | +static int lgdt330x_init(struct dvb_frontend *fe) | |
| 180 | 190 | { |
| 181 | − /* Hardware reset is done using gpio[0] of cx23880x chip. | |
| 182 | − * I'd like to do it here, but don't know how to find chip address. | |
| 183 | − * cx88-cards.c arranges for the reset bit to be inactive (high). | |
| 184 | − * Maybe there needs to be a callable function in cx88-core or | |
| 185 | − * the caller of this function needs to do it. */ | |
| 186 | − | |
| 191 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 192 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 193 | + char *chip_name; | |
| 194 | + int err; | |
| 187 | 195 | /* |
| 188 | 196 | * Array of byte pairs <address, value> |
| 189 | 197 | * to initialize each different chip |
| 190 | 198 | */ |
| 191 | − static u8 lgdt3302_init_data[] = { | |
| 192 | − /* Use 50MHz parameter values from spec sheet since xtal is 50 */ | |
| 193 | − /* Change the value of NCOCTFV[25:0] of carrier | |
| 194 | − recovery center frequency register */ | |
| 199 | + static const u8 lgdt3302_init_data[] = { | |
| 200 | + /* Use 50MHz param values from spec sheet since xtal is 50 */ | |
| 201 | + /* | |
| 202 | + * Change the value of NCOCTFV[25:0] of carrier | |
| 203 | + * recovery center frequency register | |
| 204 | + */ | |
| 195 | 205 | VSB_CARRIER_FREQ0, 0x00, |
| 196 | 206 | VSB_CARRIER_FREQ1, 0x87, |
| 197 | 207 | VSB_CARRIER_FREQ2, 0x8e, |
| 198 | 208 | VSB_CARRIER_FREQ3, 0x01, |
| 199 | − /* Change the TPCLK pin polarity | |
| 200 | − data is valid on falling clock */ | |
| 209 | + /* | |
| 210 | + * Change the TPCLK pin polarity | |
| 211 | + * data is valid on falling clock | |
| 212 | + */ | |
| 201 | 213 | DEMUX_CONTROL, 0xfb, |
| 202 | − /* Change the value of IFBW[11:0] of | |
| 203 | − AGC IF/RF loop filter bandwidth register */ | |
| 214 | + /* | |
| 215 | + * Change the value of IFBW[11:0] of | |
| 216 | + * AGC IF/RF loop filter bandwidth register | |
| 217 | + */ | |
| 204 | 218 | AGC_RF_BANDWIDTH0, 0x40, |
| 205 | 219 | AGC_RF_BANDWIDTH1, 0x93, |
| 206 | 220 | AGC_RF_BANDWIDTH2, 0x00, |
| 207 | − /* Change the value of bit 6, 'nINAGCBY' and | |
| 208 | − 'NSSEL[1:0] of ACG function control register 2 */ | |
| 221 | + /* | |
| 222 | + * Change the value of bit 6, 'nINAGCBY' and | |
| 223 | + * 'NSSEL[1:0] of ACG function control register 2 | |
| 224 | + */ | |
| 209 | 225 | AGC_FUNC_CTRL2, 0xc6, |
| 210 | − /* Change the value of bit 6 'RFFIX' | |
| 211 | − of AGC function control register 3 */ | |
| 226 | + /* | |
| 227 | + * Change the value of bit 6 'RFFIX' | |
| 228 | + * of AGC function control register 3 | |
| 229 | + */ | |
| 212 | 230 | AGC_FUNC_CTRL3, 0x40, |
| 213 | − /* Set the value of 'INLVTHD' register 0x2a/0x2c | |
| 214 | − to 0x7fe */ | |
| 231 | + /* | |
| 232 | + * Set the value of 'INLVTHD' register 0x2a/0x2c | |
| 233 | + * to 0x7fe | |
| 234 | + */ | |
| 215 | 235 | AGC_DELAY0, 0x07, |
| 216 | 236 | AGC_DELAY2, 0xfe, |
| 217 | − /* Change the value of IAGCBW[15:8] | |
| 218 | − of inner AGC loop filter bandwidth */ | |
| 237 | + /* | |
| 238 | + * Change the value of IAGCBW[15:8] | |
| 239 | + * of inner AGC loop filter bandwidth | |
| 240 | + */ | |
| 219 | 241 | AGC_LOOP_BANDWIDTH0, 0x08, |
| 220 | 242 | AGC_LOOP_BANDWIDTH1, 0x9a |
| 221 | 243 | }; |
| 222 | − | |
| 223 | − static u8 lgdt3303_init_data[] = { | |
| 244 | + static const u8 lgdt3303_init_data[] = { | |
| 224 | 245 | 0x4c, 0x14 |
| 225 | 246 | }; |
| 226 | − | |
| 227 | − static u8 flip_1_lgdt3303_init_data[] = { | |
| 247 | + static const u8 flip_1_lgdt3303_init_data[] = { | |
| 228 | 248 | 0x4c, 0x14, |
| 229 | 249 | 0x87, 0xf3 |
| 230 | 250 | }; |
| 231 | − | |
| 232 | − static u8 flip_2_lgdt3303_init_data[] = { | |
| 251 | + static const u8 flip_2_lgdt3303_init_data[] = { | |
| 233 | 252 | 0x4c, 0x14, |
| 234 | 253 | 0x87, 0xda |
| 235 | 254 | }; |
| 236 | 255 | |
| 237 | − struct lgdt330x_state* state = fe->demodulator_priv; | |
| 238 | − char *chip_name; | |
| 239 | − int err; | |
| 256 | + /* | |
| 257 | + * Hardware reset is done using gpio[0] of cx23880x chip. | |
| 258 | + * I'd like to do it here, but don't know how to find chip address. | |
| 259 | + * cx88-cards.c arranges for the reset bit to be inactive (high). | |
| 260 | + * Maybe there needs to be a callable function in cx88-core or | |
| 261 | + * the caller of this function needs to do it. | |
| 262 | + */ | |
| 240 | 263 | |
| 241 | − switch (state->config->demod_chip) { | |
| 264 | + switch (state->config.demod_chip) { | |
| 242 | 265 | case LGDT3302: |
| 243 | 266 | chip_name = "LGDT3302"; |
| 244 | 267 | err = i2c_write_demod_bytes(state, lgdt3302_init_data, |
| @@ -246,16 +269,16 @@ static int lgdt330x_init(struct dvb_frontend* fe) · 1 unmodified line | ||
| 246 | 269 | break; |
| 247 | 270 | case LGDT3303: |
| 248 | 271 | chip_name = "LGDT3303"; |
| 249 | − switch (state->config->clock_polarity_flip) { | |
| 272 | + switch (state->config.clock_polarity_flip) { | |
| 250 | 273 | case 2: |
| 251 | 274 | err = i2c_write_demod_bytes(state, |
| 252 | − flip_2_lgdt3303_init_data, | |
| 253 | − sizeof(flip_2_lgdt3303_init_data)); | |
| 275 | + flip_2_lgdt3303_init_data, | |
| 276 | + sizeof(flip_2_lgdt3303_init_data)); | |
| 254 | 277 | break; |
| 255 | 278 | case 1: |
| 256 | 279 | err = i2c_write_demod_bytes(state, |
| 257 | − flip_1_lgdt3303_init_data, | |
| 258 | − sizeof(flip_1_lgdt3303_init_data)); | |
| 280 | + flip_1_lgdt3303_init_data, | |
| 281 | + sizeof(flip_1_lgdt3303_init_data)); | |
| 259 | 282 | break; |
| 260 | 283 | case 0: |
| 261 | 284 | default: |
| @@ -265,70 +288,55 @@ static int lgdt330x_init(struct dvb_frontend* fe) · 3 unmodified lines | ||
| 265 | 288 | break; |
| 266 | 289 | default: |
| 267 | 290 | chip_name = "undefined"; |
| 268 | − printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); | |
| 291 | + dev_warn(&state->client->dev, | |
| 292 | + "Only LGDT3302 and LGDT3303 are supported chips.\n"); | |
| 269 | 293 | err = -ENODEV; |
| 270 | 294 | } |
| 271 | − dprintk("%s entered as %s\n", __func__, chip_name); | |
| 295 | + dprintk(state, "Initialized the %s chip\n", chip_name); | |
| 272 | 296 | if (err < 0) |
| 273 | 297 | return err; |
| 274 | − return lgdt330x_SwReset(state); | |
| 275 | −} | |
| 276 | 298 | |
| 277 | −static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) | |
| 278 | −{ | |
| 279 | − *ber = 0; /* Not supplied by the demod chips */ | |
| 280 | − return 0; | |
| 299 | + p->cnr.len = 1; | |
| 300 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 301 | + p->block_error.len = 1; | |
| 302 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 303 | + p->block_count.len = 1; | |
| 304 | + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 305 | + state->last_stats_time = 0; | |
| 306 | + | |
| 307 | + return lgdt330x_sw_reset(state); | |
| 281 | 308 | } |
| 282 | 309 | |
| 283 | −static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | |
| 310 | +static int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |
| 284 | 311 | { |
| 285 | − struct lgdt330x_state* state = fe->demodulator_priv; | |
| 286 | − int err; | |
| 287 | − u8 buf[2]; | |
| 312 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 288 | 313 | |
| 289 | − *ucblocks = 0; | |
| 314 | + *ucblocks = state->ucblocks; | |
| 290 | 315 | |
| 291 | − switch (state->config->demod_chip) { | |
| 292 | − case LGDT3302: | |
| 293 | − err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, | |
| 294 | − buf, sizeof(buf)); | |
| 295 | − break; | |
| 296 | − case LGDT3303: | |
| 297 | − err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, | |
| 298 | − buf, sizeof(buf)); | |
| 299 | − break; | |
| 300 | − default: | |
| 301 | − printk(KERN_WARNING | |
| 302 | − "Only LGDT3302 and LGDT3303 are supported chips.\n"); | |
| 303 | − err = -ENODEV; | |
| 304 | − } | |
| 305 | − if (err < 0) | |
| 306 | − return err; | |
| 307 | − | |
| 308 | − *ucblocks = (buf[0] << 8) | buf[1]; | |
| 309 | 316 | return 0; |
| 310 | 317 | } |
| 311 | 318 | |
| 312 | 319 | static int lgdt330x_set_parameters(struct dvb_frontend *fe) |
| 313 | 320 | { |
| 314 | 321 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 322 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 315 | 323 | /* |
| 316 | 324 | * Array of byte pairs <address, value> |
| 317 | 325 | * to initialize 8VSB for lgdt3303 chip 50 MHz IF |
| 318 | 326 | */ |
| 319 | − static u8 lgdt3303_8vsb_44_data[] = { | |
| 327 | + static const u8 lgdt3303_8vsb_44_data[] = { | |
| 320 | 328 | 0x04, 0x00, |
| 321 | 329 | 0x0d, 0x40, |
| 322 | 330 | 0x0e, 0x87, |
| 323 | 331 | 0x0f, 0x8e, |
| 324 | 332 | 0x10, 0x01, |
| 325 | − 0x47, 0x8b }; | |
| 326 | − | |
| 333 | + 0x47, 0x8b | |
| 334 | + }; | |
| 327 | 335 | /* |
| 328 | 336 | * Array of byte pairs <address, value> |
| 329 | 337 | * to initialize QAM for lgdt3303 chip |
| 330 | 338 | */ |
| 331 | − static u8 lgdt3303_qam_data[] = { | |
| 339 | + static const u8 lgdt3303_qam_data[] = { | |
| 332 | 340 | 0x04, 0x00, |
| 333 | 341 | 0x0d, 0x00, |
| 334 | 342 | 0x0e, 0x00, |
| @@ -339,98 +347,105 @@ static int lgdt330x_set_parameters(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 339 | 347 | 0x48, 0x66, |
| 340 | 348 | 0x4d, 0x1a, |
| 341 | 349 | 0x49, 0x08, |
| 342 | − 0x4a, 0x9b }; | |
| 343 | − | |
| 344 | − struct lgdt330x_state* state = fe->demodulator_priv; | |
| 345 | − | |
| 346 | − static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; | |
| 350 | + 0x4a, 0x9b | |
| 351 | + }; | |
| 352 | + u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; | |
| 347 | 353 | |
| 348 | 354 | int err = 0; |
| 349 | 355 | /* Change only if we are actually changing the modulation */ |
| 350 | 356 | if (state->current_modulation != p->modulation) { |
| 351 | 357 | switch (p->modulation) { |
| 352 | 358 | case VSB_8: |
| 353 | − dprintk("%s: VSB_8 MODE\n", __func__); | |
| 359 | + dprintk(state, "VSB_8 MODE\n"); | |
| 354 | 360 | |
| 355 | 361 | /* Select VSB mode */ |
| 356 | 362 | top_ctrl_cfg[1] = 0x03; |
| 357 | 363 | |
| 358 | 364 | /* Select ANT connector if supported by card */ |
| 359 | − if (state->config->pll_rf_set) | |
| 360 | − state->config->pll_rf_set(fe, 1); | |
| 365 | + if (state->config.pll_rf_set) | |
| 366 | + state->config.pll_rf_set(fe, 1); | |
| 361 | 367 | |
| 362 | − if (state->config->demod_chip == LGDT3303) { | |
| 363 | − err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, | |
| 368 | + if (state->config.demod_chip == LGDT3303) { | |
| 369 | + err = i2c_write_demod_bytes(state, | |
| 370 | + lgdt3303_8vsb_44_data, | |
| 364 | 371 | sizeof(lgdt3303_8vsb_44_data)); |
| 365 | 372 | } |
| 366 | 373 | break; |
| 367 | 374 | |
| 368 | 375 | case QAM_64: |
| 369 | − dprintk("%s: QAM_64 MODE\n", __func__); | |
| 376 | + dprintk(state, "QAM_64 MODE\n"); | |
| 370 | 377 | |
| 371 | 378 | /* Select QAM_64 mode */ |
| 372 | 379 | top_ctrl_cfg[1] = 0x00; |
| 373 | 380 | |
| 374 | 381 | /* Select CABLE connector if supported by card */ |
| 375 | − if (state->config->pll_rf_set) | |
| 376 | − state->config->pll_rf_set(fe, 0); | |
| 382 | + if (state->config.pll_rf_set) | |
| 383 | + state->config.pll_rf_set(fe, 0); | |
| 377 | 384 | |
| 378 | − if (state->config->demod_chip == LGDT3303) { | |
| 379 | − err = i2c_write_demod_bytes(state, lgdt3303_qam_data, | |
| 380 | − sizeof(lgdt3303_qam_data)); | |
| 385 | + if (state->config.demod_chip == LGDT3303) { | |
| 386 | + err = i2c_write_demod_bytes(state, | |
| 387 | + lgdt3303_qam_data, | |
| 388 | + sizeof(lgdt3303_qam_data)); | |
| 381 | 389 | } |
| 382 | 390 | break; |
| 383 | 391 | |
| 384 | 392 | case QAM_256: |
| 385 | − dprintk("%s: QAM_256 MODE\n", __func__); | |
| 393 | + dprintk(state, "QAM_256 MODE\n"); | |
| 386 | 394 | |
| 387 | 395 | /* Select QAM_256 mode */ |
| 388 | 396 | top_ctrl_cfg[1] = 0x01; |
| 389 | 397 | |
| 390 | 398 | /* Select CABLE connector if supported by card */ |
| 391 | − if (state->config->pll_rf_set) | |
| 392 | − state->config->pll_rf_set(fe, 0); | |
| 399 | + if (state->config.pll_rf_set) | |
| 400 | + state->config.pll_rf_set(fe, 0); | |
| 393 | 401 | |
| 394 | − if (state->config->demod_chip == LGDT3303) { | |
| 395 | − err = i2c_write_demod_bytes(state, lgdt3303_qam_data, | |
| 396 | − sizeof(lgdt3303_qam_data)); | |
| 402 | + if (state->config.demod_chip == LGDT3303) { | |
| 403 | + err = i2c_write_demod_bytes(state, | |
| 404 | + lgdt3303_qam_data, | |
| 405 | + sizeof(lgdt3303_qam_data)); | |
| 397 | 406 | } |
| 398 | 407 | break; |
| 399 | 408 | default: |
| 400 | − printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation); | |
| 409 | + dev_warn(&state->client->dev, | |
| 410 | + "%s: Modulation type(%d) UNSUPPORTED\n", | |
| 411 | + __func__, p->modulation); | |
| 401 | 412 | return -1; |
| 402 | 413 | } |
| 403 | 414 | if (err < 0) |
| 404 | − printk(KERN_WARNING "lgdt330x: %s: error blasting bytes to lgdt3303 for modulation type(%d)\n", | |
| 405 | − __func__, p->modulation); | |
| 415 | + dev_warn(&state->client->dev, | |
| 416 | + "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n", | |
| 417 | + __func__, p->modulation); | |
| 406 | 418 | |
| 407 | 419 | /* |
| 408 | − * select serial or parallel MPEG harware interface | |
| 420 | + * select serial or parallel MPEG hardware interface | |
| 409 | 421 | * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 |
| 410 | 422 | * Parallel: 0x00 |
| 411 | 423 | */ |
| 412 | − top_ctrl_cfg[1] |= state->config->serial_mpeg; | |
| 424 | + top_ctrl_cfg[1] |= state->config.serial_mpeg; | |
| 413 | 425 | |
| 414 | 426 | /* Select the requested mode */ |
| 415 | 427 | i2c_write_demod_bytes(state, top_ctrl_cfg, |
| 416 | 428 | sizeof(top_ctrl_cfg)); |
| 417 | − if (state->config->set_ts_params) | |
| 418 | − state->config->set_ts_params(fe, 0); | |
| 429 | + if (state->config.set_ts_params) | |
| 430 | + state->config.set_ts_params(fe, 0); | |
| 419 | 431 | state->current_modulation = p->modulation; |
| 420 | 432 | } |
| 421 | 433 | |
| 422 | 434 | /* Tune to the specified frequency */ |
| 423 | 435 | if (fe->ops.tuner_ops.set_params) { |
| 424 | 436 | fe->ops.tuner_ops.set_params(fe); |
| 425 | − if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | |
| 437 | + if (fe->ops.i2c_gate_ctrl) | |
| 438 | + fe->ops.i2c_gate_ctrl(fe, 0); | |
| 426 | 439 | } |
| 427 | 440 | |
| 428 | 441 | /* Keep track of the new frequency */ |
| 429 | − /* FIXME this is the wrong way to do this... */ | |
| 430 | − /* The tuner is shared with the video4linux analog API */ | |
| 442 | + /* | |
| 443 | + * FIXME this is the wrong way to do this... | |
| 444 | + * The tuner is shared with the video4linux analog API | |
| 445 | + */ | |
| 431 | 446 | state->current_frequency = p->frequency; |
| 432 | 447 | |
| 433 | − lgdt330x_SwReset(state); | |
| 448 | + lgdt330x_sw_reset(state); | |
| 434 | 449 | return 0; |
| 435 | 450 | } |
| 436 | 451 | |
| @@ -443,20 +458,191 @@ static int lgdt330x_get_frontend(struct dvb_frontend *fe, · 6 unmodified lines | ||
| 443 | 458 | return 0; |
| 444 | 459 | } |
| 445 | 460 | |
| 461 | +/* | |
| 462 | + * Calculate SNR estimation (scaled by 2^24) | |
| 463 | + * | |
| 464 | + * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM | |
| 465 | + * equations from LGDT3303 datasheet. VSB is the same between the '02 | |
| 466 | + * and '03, so maybe QAM is too? Perhaps someone with a newer datasheet | |
| 467 | + * that has QAM information could verify? | |
| 468 | + * | |
| 469 | + * For 8-VSB: (two ways, take your pick) | |
| 470 | + * LGDT3302: | |
| 471 | + * SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) | |
| 472 | + * LGDT3303: | |
| 473 | + * SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) | |
| 474 | + * LGDT3302 & LGDT3303: | |
| 475 | + * SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) | |
| 476 | + * For 64-QAM: | |
| 477 | + * SNR = 10 * log10( 688128 / MSEQAM) | |
| 478 | + * For 256-QAM: | |
| 479 | + * SNR = 10 * log10( 696320 / MSEQAM) | |
| 480 | + * | |
| 481 | + * We re-write the snr equation as: | |
| 482 | + * SNR * 2^24 = 10*(c - intlog10(MSE)) | |
| 483 | + * Where for 256-QAM, c = log10(696320) * 2^24, and so on. | |
| 484 | + */ | |
| 485 | +static u32 calculate_snr(u32 mse, u32 c) | |
| 486 | +{ | |
| 487 | + if (mse == 0) /* No signal */ | |
| 488 | + return 0; | |
| 489 | + | |
| 490 | + mse = intlog10(mse); | |
| 491 | + if (mse > c) { | |
| 492 | + /* | |
| 493 | + * Negative SNR, which is possible, but realisticly the | |
| 494 | + * demod will lose lock before the signal gets this bad. | |
| 495 | + * The API only allows for unsigned values, so just return 0 | |
| 496 | + */ | |
| 497 | + return 0; | |
| 498 | + } | |
| 499 | + return 10 * (c - mse); | |
| 500 | +} | |
| 501 | + | |
| 502 | +static int lgdt3302_read_snr(struct dvb_frontend *fe) | |
| 503 | +{ | |
| 504 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 505 | + u8 buf[5]; /* read data buffer */ | |
| 506 | + u32 noise; /* noise value */ | |
| 507 | + u32 c; /* per-modulation SNR calculation constant */ | |
| 508 | + | |
| 509 | + switch (state->current_modulation) { | |
| 510 | + case VSB_8: | |
| 511 | + i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); | |
| 512 | +#ifdef USE_EQMSE | |
| 513 | + /* Use Equalizer Mean-Square Error Register */ | |
| 514 | + /* SNR for ranges from -15.61 to +41.58 */ | |
| 515 | + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; | |
| 516 | + c = 69765745; /* log10(25*24^2)*2^24 */ | |
| 517 | +#else | |
| 518 | + /* Use Phase Tracker Mean-Square Error Register */ | |
| 519 | + /* SNR for ranges from -13.11 to +44.08 */ | |
| 520 | + noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4]; | |
| 521 | + c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 522 | +#endif | |
| 523 | + break; | |
| 524 | + case QAM_64: | |
| 525 | + case QAM_256: | |
| 526 | + i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | |
| 527 | + noise = ((buf[0] & 3) << 8) | buf[1]; | |
| 528 | + c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | |
| 529 | + /* log10(688128)*2^24 and log10(696320)*2^24 */ | |
| 530 | + break; | |
| 531 | + default: | |
| 532 | + dev_err(&state->client->dev, | |
| 533 | + "%s: Modulation set to unsupported value\n", | |
| 534 | + __func__); | |
| 535 | + | |
| 536 | + state->snr = 0; | |
| 537 | + | |
| 538 | + return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | |
| 539 | + } | |
| 540 | + | |
| 541 | + state->snr = calculate_snr(noise, c); | |
| 542 | + | |
| 543 | + dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise, | |
| 544 | + state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); | |
| 545 | + | |
| 546 | + return 0; | |
| 547 | +} | |
| 548 | + | |
| 549 | +static int lgdt3303_read_snr(struct dvb_frontend *fe) | |
| 550 | +{ | |
| 551 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 552 | + u8 buf[5]; /* read data buffer */ | |
| 553 | + u32 noise; /* noise value */ | |
| 554 | + u32 c; /* per-modulation SNR calculation constant */ | |
| 555 | + | |
| 556 | + switch (state->current_modulation) { | |
| 557 | + case VSB_8: | |
| 558 | + i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); | |
| 559 | +#ifdef USE_EQMSE | |
| 560 | + /* Use Equalizer Mean-Square Error Register */ | |
| 561 | + /* SNR for ranges from -16.12 to +44.08 */ | |
| 562 | + noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; | |
| 563 | + c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 564 | +#else | |
| 565 | + /* Use Phase Tracker Mean-Square Error Register */ | |
| 566 | + /* SNR for ranges from -13.11 to +44.08 */ | |
| 567 | + noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; | |
| 568 | + c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 569 | +#endif | |
| 570 | + break; | |
| 571 | + case QAM_64: | |
| 572 | + case QAM_256: | |
| 573 | + i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | |
| 574 | + noise = (buf[0] << 8) | buf[1]; | |
| 575 | + c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | |
| 576 | + /* log10(688128)*2^24 and log10(696320)*2^24 */ | |
| 577 | + break; | |
| 578 | + default: | |
| 579 | + dev_err(&state->client->dev, | |
| 580 | + "%s: Modulation set to unsupported value\n", | |
| 581 | + __func__); | |
| 582 | + state->snr = 0; | |
| 583 | + return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | |
| 584 | + } | |
| 585 | + | |
| 586 | + state->snr = calculate_snr(noise, c); | |
| 587 | + | |
| 588 | + dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise, | |
| 589 | + state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); | |
| 590 | + | |
| 591 | + return 0; | |
| 592 | +} | |
| 593 | + | |
| 594 | +static int lgdt330x_read_snr(struct dvb_frontend *fe, u16 *snr) | |
| 595 | +{ | |
| 596 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 597 | + | |
| 598 | + *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ | |
| 599 | + | |
| 600 | + return 0; | |
| 601 | +} | |
| 602 | + | |
| 603 | +static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | |
| 604 | +{ | |
| 605 | + /* Calculate Strength from SNR up to 35dB */ | |
| 606 | + /* | |
| 607 | + * Even though the SNR can go higher than 35dB, there is some comfort | |
| 608 | + * factor in having a range of strong signals that can show at 100% | |
| 609 | + */ | |
| 610 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 611 | + u16 snr; | |
| 612 | + int ret; | |
| 613 | + | |
| 614 | + ret = fe->ops.read_snr(fe, &snr); | |
| 615 | + if (ret != 0) | |
| 616 | + return ret; | |
| 617 | + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | |
| 618 | + /* scale the range 0 - 35*2^24 into 0 - 65535 */ | |
| 619 | + if (state->snr >= 8960 * 0x10000) | |
| 620 | + *strength = 0xffff; | |
| 621 | + else | |
| 622 | + *strength = state->snr / 8960; | |
| 623 | + | |
| 624 | + return 0; | |
| 625 | +} | |
| 626 | + | |
| 627 | + | |
| 446 | 628 | static int lgdt3302_read_status(struct dvb_frontend *fe, |
| 447 | 629 | enum fe_status *status) |
| 448 | 630 | { |
| 449 | − struct lgdt330x_state* state = fe->demodulator_priv; | |
| 631 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 632 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 450 | 633 | u8 buf[3]; |
| 634 | + int err; | |
| 451 | 635 | |
| 452 | 636 | *status = 0; /* Reset status result */ |
| 453 | 637 | |
| 454 | 638 | /* AGC status register */ |
| 455 | 639 | i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); |
| 456 | − dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); | |
| 457 | − if ((buf[0] & 0x0c) == 0x8){ | |
| 458 | − /* Test signal does not exist flag */ | |
| 459 | − /* as well as the AGC lock flag. */ | |
| 640 | + dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); | |
| 641 | + if ((buf[0] & 0x0c) == 0x8) { | |
| 642 | + /* | |
| 643 | + * Test signal does not exist flag | |
| 644 | + * as well as the AGC lock flag. | |
| 645 | + */ | |
| 460 | 646 | *status |= FE_HAS_SIGNAL; |
| 461 | 647 | } |
| 462 | 648 | |
| @@ -465,25 +651,24 @@ static int lgdt3302_read_status(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 465 | 651 | * to see that status bit in the IRQ_STATUS register. |
| 466 | 652 | * This is done in SwReset(); |
| 467 | 653 | */ |
| 654 | + | |
| 468 | 655 | /* signal status */ |
| 469 | 656 | i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); |
| 470 | − dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]); | |
| 471 | − | |
| 657 | + dprintk(state, | |
| 658 | + "TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", | |
| 659 | + buf[0], buf[1], buf[2]); | |
| 472 | 660 | |
| 473 | 661 | /* sync status */ |
| 474 | − if ((buf[2] & 0x03) == 0x01) { | |
| 662 | + if ((buf[2] & 0x03) == 0x01) | |
| 475 | 663 | *status |= FE_HAS_SYNC; |
| 476 | − } | |
| 477 | 664 | |
| 478 | 665 | /* FEC error status */ |
| 479 | − if ((buf[2] & 0x0c) == 0x08) { | |
| 480 | − *status |= FE_HAS_LOCK; | |
| 481 | − *status |= FE_HAS_VITERBI; | |
| 482 | − } | |
| 666 | + if ((buf[2] & 0x0c) == 0x08) | |
| 667 | + *status |= FE_HAS_LOCK | FE_HAS_VITERBI; | |
| 483 | 668 | |
| 484 | 669 | /* Carrier Recovery Lock Status Register */ |
| 485 | 670 | i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); |
| 486 | − dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); | |
| 671 | + dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]); | |
| 487 | 672 | switch (state->current_modulation) { |
| 488 | 673 | case QAM_256: |
| 489 | 674 | case QAM_64: |
| @@ -496,7 +681,48 @@ static int lgdt3302_read_status(struct dvb_frontend *fe, · 6 unmodified lines | ||
| 496 | 681 | *status |= FE_HAS_CARRIER; |
| 497 | 682 | break; |
| 498 | 683 | default: |
| 499 | − printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); | |
| 684 | + dev_warn(&state->client->dev, | |
| 685 | + "%s: Modulation set to unsupported value\n", | |
| 686 | + __func__); | |
| 687 | + } | |
| 688 | + | |
| 689 | + if (!(*status & FE_HAS_LOCK)) { | |
| 690 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 691 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 692 | + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 693 | + return 0; | |
| 694 | + } | |
| 695 | + | |
| 696 | + if (state->last_stats_time && | |
| 697 | + time_is_after_jiffies(state->last_stats_time)) | |
| 698 | + return 0; | |
| 699 | + | |
| 700 | + state->last_stats_time = jiffies + msecs_to_jiffies(1000); | |
| 701 | + | |
| 702 | + err = lgdt3302_read_snr(fe); | |
| 703 | + if (!err) { | |
| 704 | + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 705 | + p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24; | |
| 706 | + } else { | |
| 707 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 708 | + } | |
| 709 | + | |
| 710 | + err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, | |
| 711 | + buf, sizeof(buf)); | |
| 712 | + if (!err) { | |
| 713 | + state->ucblocks = (buf[0] << 8) | buf[1]; | |
| 714 | + | |
| 715 | + dprintk(state, "UCB = 0x%02x\n", state->ucblocks); | |
| 716 | + | |
| 717 | + p->block_error.stat[0].uvalue += state->ucblocks; | |
| 718 | + /* FIXME: what's the basis for block count */ | |
| 719 | + p->block_count.stat[0].uvalue += 10000; | |
| 720 | + | |
| 721 | + p->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 722 | + p->block_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 723 | + } else { | |
| 724 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 725 | + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 500 | 726 | } |
| 501 | 727 | |
| 502 | 728 | return 0; |
| @@ -505,9 +731,10 @@ static int lgdt3302_read_status(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 505 | 731 | static int lgdt3303_read_status(struct dvb_frontend *fe, |
| 506 | 732 | enum fe_status *status) |
| 507 | 733 | { |
| 508 | − struct lgdt330x_state* state = fe->demodulator_priv; | |
| 509 | − int err; | |
| 734 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 735 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 510 | 736 | u8 buf[3]; |
| 737 | + int err; | |
| 511 | 738 | |
| 512 | 739 | *status = 0; /* Reset status result */ |
| 513 | 740 | |
| @@ -516,16 +743,18 @@ static int lgdt3303_read_status(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 516 | 743 | if (err < 0) |
| 517 | 744 | return err; |
| 518 | 745 | |
| 519 | − dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); | |
| 520 | − if ((buf[0] & 0x21) == 0x01){ | |
| 521 | − /* Test input signal does not exist flag */ | |
| 522 | − /* as well as the AGC lock flag. */ | |
| 746 | + dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); | |
| 747 | + if ((buf[0] & 0x21) == 0x01) { | |
| 748 | + /* | |
| 749 | + * Test input signal does not exist flag | |
| 750 | + * as well as the AGC lock flag. | |
| 751 | + */ | |
| 523 | 752 | *status |= FE_HAS_SIGNAL; |
| 524 | 753 | } |
| 525 | 754 | |
| 526 | 755 | /* Carrier Recovery Lock Status Register */ |
| 527 | 756 | i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); |
| 528 | − dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); | |
| 757 | + dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]); | |
| 529 | 758 | switch (state->current_modulation) { |
| 530 | 759 | case QAM_256: |
| 531 | 760 | case QAM_64: |
| @@ -535,6 +764,8 @@ static int lgdt3303_read_status(struct dvb_frontend *fe, · 3 unmodified lines | ||
| 535 | 764 | else |
| 536 | 765 | break; |
| 537 | 766 | i2c_read_demod_bytes(state, 0x8a, buf, 1); |
| 767 | + dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]); | |
| 768 | + | |
| 538 | 769 | if ((buf[0] & 0x04) == 0x04) |
| 539 | 770 | *status |= FE_HAS_SYNC; |
| 540 | 771 | if ((buf[0] & 0x01) == 0x01) |
| @@ -548,168 +779,64 @@ static int lgdt3303_read_status(struct dvb_frontend *fe, · 7 unmodified lines | ||
| 548 | 779 | else |
| 549 | 780 | break; |
| 550 | 781 | i2c_read_demod_bytes(state, 0x38, buf, 1); |
| 782 | + dprintk(state, "8-VSB LOCK = 0x%02x\n", buf[0]); | |
| 783 | + | |
| 551 | 784 | if ((buf[0] & 0x02) == 0x00) |
| 552 | 785 | *status |= FE_HAS_SYNC; |
| 553 | − if ((buf[0] & 0x01) == 0x01) { | |
| 554 | − *status |= FE_HAS_LOCK; | |
| 555 | − *status |= FE_HAS_VITERBI; | |
| 556 | − } | |
| 786 | + if ((buf[0] & 0xfd) == 0x01) | |
| 787 | + *status |= FE_HAS_VITERBI | FE_HAS_LOCK; | |
| 557 | 788 | break; |
| 558 | 789 | default: |
| 559 | − printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); | |
| 790 | + dev_warn(&state->client->dev, | |
| 791 | + "%s: Modulation set to unsupported value\n", | |
| 792 | + __func__); | |
| 560 | 793 | } |
| 561 | − return 0; | |
| 562 | −} | |
| 563 | − | |
| 564 | −/* Calculate SNR estimation (scaled by 2^24) | |
| 565 | − | |
| 566 | − 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM | |
| 567 | − equations from LGDT3303 datasheet. VSB is the same between the '02 | |
| 568 | − and '03, so maybe QAM is too? Perhaps someone with a newer datasheet | |
| 569 | − that has QAM information could verify? | |
| 570 | − | |
| 571 | − For 8-VSB: (two ways, take your pick) | |
| 572 | − LGDT3302: | |
| 573 | − SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) | |
| 574 | − LGDT3303: | |
| 575 | − SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) | |
| 576 | − LGDT3302 & LGDT3303: | |
| 577 | − SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) | |
| 578 | − For 64-QAM: | |
| 579 | − SNR = 10 * log10( 688128 / MSEQAM) | |
| 580 | − For 256-QAM: | |
| 581 | − SNR = 10 * log10( 696320 / MSEQAM) | |
| 582 | − | |
| 583 | − We re-write the snr equation as: | |
| 584 | − SNR * 2^24 = 10*(c - intlog10(MSE)) | |
| 585 | − Where for 256-QAM, c = log10(696320) * 2^24, and so on. */ | |
| 586 | 794 | |
| 587 | −static u32 calculate_snr(u32 mse, u32 c) | |
| 588 | −{ | |
| 589 | − if (mse == 0) /* No signal */ | |
| 795 | + if (!(*status & FE_HAS_LOCK)) { | |
| 796 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 797 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 798 | + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 590 | 799 | return 0; |
| 800 | + } | |
| 591 | 801 | |
| 592 | − mse = intlog10(mse); | |
| 593 | − if (mse > c) { | |
| 594 | − /* Negative SNR, which is possible, but realisticly the | |
| 595 | − demod will lose lock before the signal gets this bad. The | |
| 596 | − API only allows for unsigned values, so just return 0 */ | |
| 802 | + if (state->last_stats_time && | |
| 803 | + time_is_after_jiffies(state->last_stats_time)) | |
| 597 | 804 | return 0; |
| 598 | − } | |
| 599 | − return 10*(c - mse); | |
| 600 | −} | |
| 601 | 805 | |
| 602 | −static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) | |
| 603 | −{ | |
| 604 | − struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
| 605 | − u8 buf[5]; /* read data buffer */ | |
| 606 | − u32 noise; /* noise value */ | |
| 607 | − u32 c; /* per-modulation SNR calculation constant */ | |
| 806 | + state->last_stats_time = jiffies + msecs_to_jiffies(1000); | |
| 608 | 807 | |
| 609 | − switch(state->current_modulation) { | |
| 610 | − case VSB_8: | |
| 611 | − i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); | |
| 612 | −#ifdef USE_EQMSE | |
| 613 | − /* Use Equalizer Mean-Square Error Register */ | |
| 614 | − /* SNR for ranges from -15.61 to +41.58 */ | |
| 615 | − noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; | |
| 616 | − c = 69765745; /* log10(25*24^2)*2^24 */ | |
| 617 | −#else | |
| 618 | − /* Use Phase Tracker Mean-Square Error Register */ | |
| 619 | − /* SNR for ranges from -13.11 to +44.08 */ | |
| 620 | − noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; | |
| 621 | − c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 622 | −#endif | |
| 623 | − break; | |
| 624 | − case QAM_64: | |
| 625 | − case QAM_256: | |
| 626 | − i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | |
| 627 | − noise = ((buf[0] & 3) << 8) | buf[1]; | |
| 628 | − c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | |
| 629 | − /* log10(688128)*2^24 and log10(696320)*2^24 */ | |
| 630 | − break; | |
| 631 | − default: | |
| 632 | − printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", | |
| 633 | − __func__); | |
| 634 | − return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | |
| 808 | + err = lgdt3303_read_snr(fe); | |
| 809 | + if (!err) { | |
| 810 | + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 811 | + p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24; | |
| 812 | + } else { | |
| 813 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 635 | 814 | } |
| 636 | 815 | |
| 637 | − state->snr = calculate_snr(noise, c); | |
| 638 | − *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ | |
| 639 | − | |
| 640 | − dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, | |
| 641 | − state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); | |
| 816 | + err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, | |
| 817 | + buf, sizeof(buf)); | |
| 818 | + if (!err) { | |
| 819 | + state->ucblocks = (buf[0] << 8) | buf[1]; | |
| 642 | 820 | |
| 643 | − return 0; | |
| 644 | −} | |
| 821 | + dprintk(state, "UCB = 0x%02x\n", state->ucblocks); | |
| 645 | 822 | |
| 646 | −static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) | |
| 647 | −{ | |
| 648 | − struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
| 649 | − u8 buf[5]; /* read data buffer */ | |
| 650 | − u32 noise; /* noise value */ | |
| 651 | − u32 c; /* per-modulation SNR calculation constant */ | |
| 823 | + p->block_error.stat[0].uvalue += state->ucblocks; | |
| 824 | + /* FIXME: what's the basis for block count */ | |
| 825 | + p->block_count.stat[0].uvalue += 10000; | |
| 652 | 826 | |
| 653 | − switch(state->current_modulation) { | |
| 654 | − case VSB_8: | |
| 655 | − i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); | |
| 656 | −#ifdef USE_EQMSE | |
| 657 | − /* Use Equalizer Mean-Square Error Register */ | |
| 658 | − /* SNR for ranges from -16.12 to +44.08 */ | |
| 659 | − noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; | |
| 660 | − c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 661 | −#else | |
| 662 | − /* Use Phase Tracker Mean-Square Error Register */ | |
| 663 | − /* SNR for ranges from -13.11 to +44.08 */ | |
| 664 | − noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; | |
| 665 | − c = 73957994; /* log10(25*32^2)*2^24 */ | |
| 666 | −#endif | |
| 667 | − break; | |
| 668 | − case QAM_64: | |
| 669 | − case QAM_256: | |
| 670 | − i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | |
| 671 | − noise = (buf[0] << 8) | buf[1]; | |
| 672 | − c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | |
| 673 | − /* log10(688128)*2^24 and log10(696320)*2^24 */ | |
| 674 | − break; | |
| 675 | − default: | |
| 676 | − printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", | |
| 677 | − __func__); | |
| 678 | − return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | |
| 827 | + p->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 828 | + p->block_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 829 | + } else { | |
| 830 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 831 | + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 679 | 832 | } |
| 680 | 833 | |
| 681 | − state->snr = calculate_snr(noise, c); | |
| 682 | − *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ | |
| 683 | − | |
| 684 | − dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, | |
| 685 | − state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); | |
| 686 | − | |
| 687 | 834 | return 0; |
| 688 | 835 | } |
| 689 | 836 | |
| 690 | −static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) | |
| 691 | −{ | |
| 692 | − /* Calculate Strength from SNR up to 35dB */ | |
| 693 | − /* Even though the SNR can go higher than 35dB, there is some comfort */ | |
| 694 | − /* factor in having a range of strong signals that can show at 100% */ | |
| 695 | − struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
| 696 | − u16 snr; | |
| 697 | − int ret; | |
| 698 | − | |
| 699 | − ret = fe->ops.read_snr(fe, &snr); | |
| 700 | − if (ret != 0) | |
| 701 | − return ret; | |
| 702 | − /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | |
| 703 | − /* scale the range 0 - 35*2^24 into 0 - 65535 */ | |
| 704 | − if (state->snr >= 8960 * 0x10000) | |
| 705 | − *strength = 0xffff; | |
| 706 | − else | |
| 707 | − *strength = state->snr / 8960; | |
| 708 | − | |
| 709 | − return 0; | |
| 710 | −} | |
| 711 | − | |
| 712 | −static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) | |
| 837 | +static int | |
| 838 | +lgdt330x_get_tune_settings(struct dvb_frontend *fe, | |
| 839 | + struct dvb_frontend_tune_settings *fe_tune_settings) | |
| 713 | 840 | { |
| 714 | 841 | /* I have no idea about this - it may not be needed */ |
| 715 | 842 | fe_tune_settings->min_delay_ms = 500; |
| @@ -718,43 +845,63 @@ static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronte · 2 unmodified lines | ||
| 718 | 845 | return 0; |
| 719 | 846 | } |
| 720 | 847 | |
| 721 | −static void lgdt330x_release(struct dvb_frontend* fe) | |
| 848 | +static void lgdt330x_release(struct dvb_frontend *fe) | |
| 722 | 849 | { |
| 723 | − struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
| 724 | − kfree(state); | |
| 850 | + struct lgdt330x_state *state = fe->demodulator_priv; | |
| 851 | + struct i2c_client *client = state->client; | |
| 852 | + | |
| 853 | + dev_dbg(&client->dev, "\n"); | |
| 854 | + | |
| 855 | + i2c_unregister_device(client); | |
| 856 | +} | |
| 857 | + | |
| 858 | +static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client) | |
| 859 | +{ | |
| 860 | + struct lgdt330x_state *state = i2c_get_clientdata(client); | |
| 861 | + | |
| 862 | + dev_dbg(&client->dev, "\n"); | |
| 863 | + | |
| 864 | + return &state->frontend; | |
| 725 | 865 | } |
| 726 | 866 | |
| 727 | 867 | static const struct dvb_frontend_ops lgdt3302_ops; |
| 728 | 868 | static const struct dvb_frontend_ops lgdt3303_ops; |
| 729 | 869 | |
| 730 | −struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, | |
| 731 | − struct i2c_adapter* i2c) | |
| 870 | +static int lgdt330x_probe(struct i2c_client *client, | |
| 871 | + const struct i2c_device_id *id) | |
| 732 | 872 | { |
| 733 | − struct lgdt330x_state* state = NULL; | |
| 873 | + struct lgdt330x_state *state = NULL; | |
| 734 | 874 | u8 buf[1]; |
| 735 | 875 | |
| 736 | 876 | /* Allocate memory for the internal state */ |
| 737 | − state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); | |
| 738 | − if (state == NULL) | |
| 877 | + state = kzalloc(sizeof(*state), GFP_KERNEL); | |
| 878 | + if (!state) | |
| 739 | 879 | goto error; |
| 740 | 880 | |
| 741 | 881 | /* Setup the state */ |
| 742 | − state->config = config; | |
| 743 | − state->i2c = i2c; | |
| 882 | + memcpy(&state->config, client->dev.platform_data, | |
| 883 | + sizeof(state->config)); | |
| 884 | + i2c_set_clientdata(client, state); | |
| 885 | + state->client = client; | |
| 744 | 886 | |
| 745 | 887 | /* Create dvb_frontend */ |
| 746 | − switch (config->demod_chip) { | |
| 888 | + switch (state->config.demod_chip) { | |
| 747 | 889 | case LGDT3302: |
| 748 | − memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); | |
| 890 | + memcpy(&state->frontend.ops, &lgdt3302_ops, | |
| 891 | + sizeof(struct dvb_frontend_ops)); | |
| 749 | 892 | break; |
| 750 | 893 | case LGDT3303: |
| 751 | − memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); | |
| 894 | + memcpy(&state->frontend.ops, &lgdt3303_ops, | |
| 895 | + sizeof(struct dvb_frontend_ops)); | |
| 752 | 896 | break; |
| 753 | 897 | default: |
| 754 | 898 | goto error; |
| 755 | 899 | } |
| 756 | 900 | state->frontend.demodulator_priv = state; |
| 757 | 901 | |
| 902 | + /* Setup get frontend callback */ | |
| 903 | + state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend; | |
| 904 | + | |
| 758 | 905 | /* Verify communication with demod chip */ |
| 759 | 906 | if (i2c_read_demod_bytes(state, 2, buf, 1)) |
| 760 | 907 | goto error; |
| @@ -762,21 +909,44 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, · 1 unmodified line | ||
| 762 | 909 | state->current_frequency = -1; |
| 763 | 910 | state->current_modulation = -1; |
| 764 | 911 | |
| 765 | − return &state->frontend; | |
| 912 | + dev_info(&state->client->dev, | |
| 913 | + "Demod loaded for LGDT330%s chip\n", | |
| 914 | + state->config.demod_chip == LGDT3302 ? "2" : "3"); | |
| 915 | + | |
| 916 | + return 0; | |
| 766 | 917 | |
| 767 | 918 | error: |
| 768 | 919 | kfree(state); |
| 769 | − dprintk("%s: ERROR\n",__func__); | |
| 770 | − return NULL; | |
| 920 | + if (debug) | |
| 921 | + dev_printk(KERN_DEBUG, &client->dev, "Error loading lgdt330x driver\n"); | |
| 922 | + return -ENODEV; | |
| 923 | +} | |
| 924 | +struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config, | |
| 925 | + u8 demod_address, | |
| 926 | + struct i2c_adapter *i2c) | |
| 927 | +{ | |
| 928 | + struct i2c_client *client; | |
| 929 | + struct i2c_board_info board_info = {}; | |
| 930 | + struct lgdt330x_config config = *_config; | |
| 931 | + | |
| 932 | + strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type)); | |
| 933 | + board_info.addr = demod_address; | |
| 934 | + board_info.platform_data = &config; | |
| 935 | + client = i2c_new_device(i2c, &board_info); | |
| 936 | + if (!client || !client->dev.driver) | |
| 937 | + return NULL; | |
| 938 | + | |
| 939 | + return lgdt330x_get_dvb_frontend(client); | |
| 771 | 940 | } |
| 941 | +EXPORT_SYMBOL(lgdt330x_attach); | |
| 772 | 942 | |
| 773 | 943 | static const struct dvb_frontend_ops lgdt3302_ops = { |
| 774 | 944 | .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, |
| 775 | 945 | .info = { |
| 776 | − .name= "LG Electronics LGDT3302 VSB/QAM Frontend", | |
| 777 | − .frequency_min= 54000000, | |
| 778 | − .frequency_max= 858000000, | |
| 779 | − .frequency_stepsize= 62500, | |
| 946 | + .name = "LG Electronics LGDT3302 VSB/QAM Frontend", | |
| 947 | + .frequency_min = 54000000, | |
| 948 | + .frequency_max = 858000000, | |
| 949 | + .frequency_stepsize = 62500, | |
| 780 | 950 | .symbol_rate_min = 5056941, /* QAM 64 */ |
| 781 | 951 | .symbol_rate_max = 10762000, /* VSB 8 */ |
| 782 | 952 | .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB |
| @@ -786,9 +956,8 @@ static const struct dvb_frontend_ops lgdt3302_ops = { · 3 unmodified lines | ||
| 786 | 956 | .get_frontend = lgdt330x_get_frontend, |
| 787 | 957 | .get_tune_settings = lgdt330x_get_tune_settings, |
| 788 | 958 | .read_status = lgdt3302_read_status, |
| 789 | − .read_ber = lgdt330x_read_ber, | |
| 790 | 959 | .read_signal_strength = lgdt330x_read_signal_strength, |
| 791 | − .read_snr = lgdt3302_read_snr, | |
| 960 | + .read_snr = lgdt330x_read_snr, | |
| 792 | 961 | .read_ucblocks = lgdt330x_read_ucblocks, |
| 793 | 962 | .release = lgdt330x_release, |
| 794 | 963 | }; |
| @@ -796,10 +965,10 @@ static const struct dvb_frontend_ops lgdt3302_ops = { · 1 unmodified line | ||
| 796 | 965 | static const struct dvb_frontend_ops lgdt3303_ops = { |
| 797 | 966 | .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, |
| 798 | 967 | .info = { |
| 799 | − .name= "LG Electronics LGDT3303 VSB/QAM Frontend", | |
| 800 | − .frequency_min= 54000000, | |
| 801 | − .frequency_max= 858000000, | |
| 802 | − .frequency_stepsize= 62500, | |
| 968 | + .name = "LG Electronics LGDT3303 VSB/QAM Frontend", | |
| 969 | + .frequency_min = 54000000, | |
| 970 | + .frequency_max = 858000000, | |
| 971 | + .frequency_stepsize = 62500, | |
| 803 | 972 | .symbol_rate_min = 5056941, /* QAM 64 */ |
| 804 | 973 | .symbol_rate_max = 10762000, /* VSB 8 */ |
| 805 | 974 | .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB |
| @@ -809,15 +978,42 @@ static const struct dvb_frontend_ops lgdt3303_ops = { · 3 unmodified lines | ||
| 809 | 978 | .get_frontend = lgdt330x_get_frontend, |
| 810 | 979 | .get_tune_settings = lgdt330x_get_tune_settings, |
| 811 | 980 | .read_status = lgdt3303_read_status, |
| 812 | − .read_ber = lgdt330x_read_ber, | |
| 813 | 981 | .read_signal_strength = lgdt330x_read_signal_strength, |
| 814 | − .read_snr = lgdt3303_read_snr, | |
| 982 | + .read_snr = lgdt330x_read_snr, | |
| 815 | 983 | .read_ucblocks = lgdt330x_read_ucblocks, |
| 816 | 984 | .release = lgdt330x_release, |
| 817 | 985 | }; |
| 818 | 986 | |
| 987 | +static int lgdt330x_remove(struct i2c_client *client) | |
| 988 | +{ | |
| 989 | + struct lgdt330x_state *state = i2c_get_clientdata(client); | |
| 990 | + | |
| 991 | + dev_dbg(&client->dev, "\n"); | |
| 992 | + | |
| 993 | + kfree(state); | |
| 994 | + | |
| 995 | + return 0; | |
| 996 | +} | |
| 997 | + | |
| 998 | +static const struct i2c_device_id lgdt330x_id_table[] = { | |
| 999 | + {"lgdt330x", 0}, | |
| 1000 | + {} | |
| 1001 | +}; | |
| 1002 | +MODULE_DEVICE_TABLE(i2c, lgdt330x_id_table); | |
| 1003 | + | |
| 1004 | +static struct i2c_driver lgdt330x_driver = { | |
| 1005 | + .driver = { | |
| 1006 | + .name = "lgdt330x", | |
| 1007 | + .suppress_bind_attrs = true, | |
| 1008 | + }, | |
| 1009 | + .probe = lgdt330x_probe, | |
| 1010 | + .remove = lgdt330x_remove, | |
| 1011 | + .id_table = lgdt330x_id_table, | |
| 1012 | +}; | |
| 1013 | + | |
| 1014 | +module_i2c_driver(lgdt330x_driver); | |
| 1015 | + | |
| 1016 | + | |
| 819 | 1017 | MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); |
| 820 | 1018 | MODULE_AUTHOR("Wilson Michaels"); |
| 821 | 1019 | MODULE_LICENSE("GPL"); |
| 822 | − | |
| 823 | −EXPORT_SYMBOL(lgdt330x_attach); | |
| @@ -26,34 +26,41 @@ typedef enum lg_chip_t { · 25 unmodified lines | ||
| 26 | 26 | LGDT3303 |
| 27 | 27 | }lg_chip_type; |
| 28 | 28 | |
| 29 | +/** | |
| 30 | + * struct lgdt330x_config - contains lgdt330x configuration | |
| 31 | + * | |
| 32 | + * @demod_chip: LG demodulator chip LGDT3302 or LGDT3303 | |
| 33 | + * @serial_mpeg: MPEG hardware interface - 0:parallel 1:serial | |
| 34 | + * @pll_rf_set: Callback function to set PLL interface | |
| 35 | + * @set_ts_params: Callback function to set device param for start_dma | |
| 36 | + * @clock_polarity_flip: | |
| 37 | + * Flip the polarity of the mpeg data transfer clock using alternate | |
| 38 | + * init data. | |
| 39 | + * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled | |
| 40 | + * @get_dvb_frontend: | |
| 41 | + * returns the frontend associated with this I2C client. | |
| 42 | + * Filled by the driver. | |
| 43 | + */ | |
| 29 | 44 | struct lgdt330x_config |
| 30 | 45 | { |
| 31 | − /* The demodulator's i2c address */ | |
| 32 | − u8 demod_address; | |
| 33 | − | |
| 34 | − /* LG demodulator chip LGDT3302 or LGDT3303 */ | |
| 35 | 46 | lg_chip_type demod_chip; |
| 36 | − | |
| 37 | − /* MPEG hardware interface - 0:parallel 1:serial */ | |
| 38 | 47 | int serial_mpeg; |
| 39 | − | |
| 40 | − /* PLL interface */ | |
| 41 | 48 | int (*pll_rf_set) (struct dvb_frontend* fe, int index); |
| 42 | − | |
| 43 | − /* Need to set device param for start_dma */ | |
| 44 | 49 | int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); |
| 45 | − | |
| 46 | − /* Flip the polarity of the mpeg data transfer clock using alternate init data | |
| 47 | − * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */ | |
| 48 | 50 | int clock_polarity_flip; |
| 51 | + | |
| 52 | + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); | |
| 49 | 53 | }; |
| 50 | 54 | |
| 51 | 55 | #if IS_REACHABLE(CONFIG_DVB_LGDT330X) |
| 52 | −extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, | |
| 53 | − struct i2c_adapter* i2c); | |
| 56 | +struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *config, | |
| 57 | + u8 demod_address, | |
| 58 | + struct i2c_adapter *i2c); | |
| 54 | 59 | #else |
| 55 | −static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, | |
| 56 | − struct i2c_adapter* i2c) | |
| 60 | +static inline | |
| 61 | +struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *config, | |
| 62 | + u8 demod_address, | |
| 63 | + struct i2c_adapter *i2c) | |
| 57 | 64 | { |
| 58 | 65 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
| 59 | 66 | return NULL; |
| @@ -2055,7 +2055,7 @@ static void mb86a20s_release(struct dvb_frontend *fe) · 2054 unmodified lines | ||
| 2055 | 2055 | kfree(state); |
| 2056 | 2056 | } |
| 2057 | 2057 | |
| 2058 | −static int mb86a20s_get_frontend_algo(struct dvb_frontend *fe) | |
| 2058 | +static enum dvbfe_algo mb86a20s_get_frontend_algo(struct dvb_frontend *fe) | |
| 2059 | 2059 | { |
| 2060 | 2060 | return DVBFE_ALGO_HW; |
| 2061 | 2061 | } |
| @@ -375,7 +375,7 @@ static void release(struct dvb_frontend *fe) · 374 unmodified lines | ||
| 375 | 375 | kfree(state); |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | −static int get_algo(struct dvb_frontend *fe) | |
| 378 | +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) | |
| 379 | 379 | { |
| 380 | 380 | return DVBFE_ALGO_HW; |
| 381 | 381 | } |
| @@ -464,7 +464,7 @@ static int s921_tune(struct dvb_frontend *fe, · 463 unmodified lines | ||
| 464 | 464 | return rc; |
| 465 | 465 | } |
| 466 | 466 | |
| 467 | −static int s921_get_algo(struct dvb_frontend *fe) | |
| 467 | +static enum dvbfe_algo s921_get_algo(struct dvb_frontend *fe) | |
| 468 | 468 | { |
| 469 | 469 | return DVBFE_ALGO_HW; |
| 470 | 470 | } |
| @@ -1200,7 +1200,6 @@ static int probe(struct stv *state) · 1199 unmodified lines | ||
| 1200 | 1200 | write_reg(state, RSTV0910_P1_TSCFGM, 0xC0); /* Manual speed */ |
| 1201 | 1201 | write_reg(state, RSTV0910_P1_TSCFGL, 0x20); |
| 1202 | 1202 | |
| 1203 | − /* Speed = 67.5 MHz */ | |
| 1204 | 1203 | write_reg(state, RSTV0910_P1_TSSPEED, state->tsspeed); |
| 1205 | 1204 | |
| 1206 | 1205 | write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01); |
| @@ -1208,7 +1207,6 @@ static int probe(struct stv *state) · 1 unmodified line | ||
| 1208 | 1207 | write_reg(state, RSTV0910_P2_TSCFGM, 0xC0); /* Manual speed */ |
| 1209 | 1208 | write_reg(state, RSTV0910_P2_TSCFGL, 0x20); |
| 1210 | 1209 | |
| 1211 | − /* Speed = 67.5 MHz */ | |
| 1212 | 1210 | write_reg(state, RSTV0910_P2_TSSPEED, state->tsspeed); |
| 1213 | 1211 | |
| 1214 | 1212 | /* Reset stream merger */ |
| @@ -1220,6 +1218,12 @@ static int probe(struct stv *state) · 5 unmodified lines | ||
| 1220 | 1218 | write_reg(state, RSTV0910_P1_I2CRPT, state->i2crpt); |
| 1221 | 1219 | write_reg(state, RSTV0910_P2_I2CRPT, state->i2crpt); |
| 1222 | 1220 | |
| 1221 | + write_reg(state, RSTV0910_P1_TSINSDELM, 0x17); | |
| 1222 | + write_reg(state, RSTV0910_P1_TSINSDELL, 0xff); | |
| 1223 | + | |
| 1224 | + write_reg(state, RSTV0910_P2_TSINSDELM, 0x17); | |
| 1225 | + write_reg(state, RSTV0910_P2_TSINSDELL, 0xff); | |
| 1226 | + | |
| 1223 | 1227 | init_diseqc(state); |
| 1224 | 1228 | return 0; |
| 1225 | 1229 | } |
| @@ -1320,7 +1324,7 @@ static int read_snr(struct dvb_frontend *fe) · 94 unmodified lines | ||
| 1320 | 1324 | |
| 1321 | 1325 | if (!get_signal_to_noise(state, &snrval)) { |
| 1322 | 1326 | p->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
| 1323 | − p->cnr.stat[0].uvalue = 100 * snrval; /* fix scale */ | |
| 1327 | + p->cnr.stat[0].svalue = 100 * snrval; /* fix scale */ | |
| 1324 | 1328 | } else { |
| 1325 | 1329 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 1326 | 1330 | } |
| @@ -1633,7 +1637,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune, · 306 unmodified lines | ||
| 1633 | 1637 | return 0; |
| 1634 | 1638 | } |
| 1635 | 1639 | |
| 1636 | −static int get_algo(struct dvb_frontend *fe) | |
| 1640 | +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) | |
| 1637 | 1641 | { |
| 1638 | 1642 | return DVBFE_ALGO_HW; |
| 1639 | 1643 | } |
| @@ -1784,7 +1788,8 @@ struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c, · 144 unmodified lines | ||
| 1784 | 1788 | state->tscfgh = 0x20 | (cfg->parallel ? 0 : 0x40); |
| 1785 | 1789 | state->tsgeneral = (cfg->parallel == 2) ? 0x02 : 0x00; |
| 1786 | 1790 | state->i2crpt = 0x0A | ((cfg->rptlvl & 0x07) << 4); |
| 1787 | − state->tsspeed = 0x28; | |
| 1791 | + /* use safe tsspeed value if unspecified through stv0910_cfg */ | |
| 1792 | + state->tsspeed = (cfg->tsspeed ? cfg->tsspeed : 0x28); | |
| 1788 | 1793 | state->nr = nr; |
| 1789 | 1794 | state->regoff = state->nr ? 0 : 0x200; |
| 1790 | 1795 | state->search_range = 16000000; |
| @@ -10,6 +10,7 @@ struct stv0910_cfg { · 9 unmodified lines | ||
| 10 | 10 | u8 parallel; |
| 11 | 11 | u8 rptlvl; |
| 12 | 12 | u8 single; |
| 13 | + u8 tsspeed; | |
| 13 | 14 | }; |
| 14 | 15 | |
| 15 | 16 | #if IS_REACHABLE(CONFIG_DVB_STV0910) |
| @@ -1,17 +1,8 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * Toshiba TC90522 Demodulator |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | |
| 17 | 8 | /* |
| @@ -352,7 +343,7 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe, · 334 unmodified lines | ||
| 352 | 343 | mode = 1; |
| 353 | 344 | ret = reg_read(state, 0xb0, val, 1); |
| 354 | 345 | if (ret == 0) { |
| 355 | − mode = (val[0] & 0xc0) >> 2; | |
| 346 | + mode = (val[0] & 0xc0) >> 6; | |
| 356 | 347 | c->transmission_mode = tm_conv[mode]; |
| 357 | 348 | c->guard_interval = (val[0] & 0x30) >> 4; |
| 358 | 349 | } |
| @@ -379,7 +370,7 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe, · 20 unmodified lines | ||
| 379 | 370 | } |
| 380 | 371 | |
| 381 | 372 | /* layer B */ |
| 382 | − v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6; | |
| 373 | + v = (val[3] & 0x03) << 2 | (val[4] & 0xc0) >> 6; | |
| 383 | 374 | if (v == 0x0f) |
| 384 | 375 | c->layer[1].segment_count = 0; |
| 385 | 376 | else { |
| @@ -1,17 +1,8 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 1 | 2 | /* |
| 2 | 3 | * Toshiba TC90522 Demodulator |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | |
| 17 | 8 | /* |
| @@ -575,6 +575,17 @@ config VIDEO_APTINA_PLL · 574 unmodified lines | ||
| 575 | 575 | config VIDEO_SMIAPP_PLL |
| 576 | 576 | tristate |
| 577 | 577 | |
| 578 | +config VIDEO_IMX258 | |
| 579 | + tristate "Sony IMX258 sensor support" | |
| 580 | + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 581 | + depends on MEDIA_CAMERA_SUPPORT | |
| 582 | + ---help--- | |
| 583 | + This is a Video4Linux2 sensor-level driver for the Sony | |
| 584 | + IMX258 camera. | |
| 585 | + | |
| 586 | + To compile this driver as a module, choose M here: the | |
| 587 | + module will be called imx258. | |
| 588 | + | |
| 578 | 589 | config VIDEO_IMX274 |
| 579 | 590 | tristate "Sony IMX274 sensor support" |
| 580 | 591 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
| @@ -688,6 +699,18 @@ config VIDEO_OV5695 · 107 unmodified lines | ||
| 688 | 699 | To compile this driver as a module, choose M here: the |
| 689 | 700 | module will be called ov5695. |
| 690 | 701 | |
| 702 | +config VIDEO_OV7251 | |
| 703 | + tristate "OmniVision OV7251 sensor support" | |
| 704 | + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 705 | + depends on MEDIA_CAMERA_SUPPORT | |
| 706 | + select V4L2_FWNODE | |
| 707 | + help | |
| 708 | + This is a Video4Linux2 sensor-level driver for the OmniVision | |
| 709 | + OV7251 camera. | |
| 710 | + | |
| 711 | + To compile this driver as a module, choose M here: the | |
| 712 | + module will be called ov7251. | |
| 713 | + | |
| 691 | 714 | config VIDEO_OV772X |
| 692 | 715 | tristate "OmniVision OV772x sensor support" |
| 693 | 716 | depends on I2C && VIDEO_V4L2 |
| @@ -974,6 +997,19 @@ config VIDEO_M52790 · 280 unmodified lines | ||
| 974 | 997 | |
| 975 | 998 | To compile this driver as a module, choose M here: the |
| 976 | 999 | module will be called m52790. |
| 1000 | + | |
| 1001 | +config VIDEO_I2C | |
| 1002 | + tristate "I2C transport video support" | |
| 1003 | + depends on VIDEO_V4L2 && I2C | |
| 1004 | + select VIDEOBUF2_VMALLOC | |
| 1005 | + ---help--- | |
| 1006 | + Enable the I2C transport video support which supports the | |
| 1007 | + following: | |
| 1008 | + * Panasonic AMG88xx Grid-Eye Sensors | |
| 1009 | + | |
| 1010 | + To compile this driver as a module, choose M here: the | |
| 1011 | + module will be called video-i2c | |
| 1012 | + | |
| 977 | 1013 | endmenu |
| 978 | 1014 | |
| 979 | 1015 | menu "Sensors used on soc_camera driver" |
| @@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_OV5647) += ov5647.o · 69 unmodified lines | ||
| 70 | 70 | obj-$(CONFIG_VIDEO_OV5670) += ov5670.o |
| 71 | 71 | obj-$(CONFIG_VIDEO_OV5695) += ov5695.o |
| 72 | 72 | obj-$(CONFIG_VIDEO_OV6650) += ov6650.o |
| 73 | +obj-$(CONFIG_VIDEO_OV7251) += ov7251.o | |
| 73 | 74 | obj-$(CONFIG_VIDEO_OV7640) += ov7640.o |
| 74 | 75 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
| 75 | 76 | obj-$(CONFIG_VIDEO_OV772X) += ov772x.o |
| @@ -96,9 +97,11 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o · 20 unmodified lines | ||
| 96 | 97 | obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o |
| 97 | 98 | obj-$(CONFIG_VIDEO_AK881X) += ak881x.o |
| 98 | 99 | obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o |
| 100 | +obj-$(CONFIG_VIDEO_I2C) += video-i2c.o | |
| 99 | 101 | obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o |
| 100 | 102 | obj-$(CONFIG_VIDEO_OV2659) += ov2659.o |
| 101 | 103 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o |
| 104 | +obj-$(CONFIG_VIDEO_IMX258) += imx258.o | |
| 102 | 105 | obj-$(CONFIG_VIDEO_IMX274) += imx274.o |
| 103 | 106 | |
| 104 | 107 | obj-$(CONFIG_SDR_MAX2175) += max2175.o |
| @@ -321,17 +321,17 @@ static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = { · 320 unmodified lines | ||
| 321 | 321 | static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe) |
| 322 | 322 | { |
| 323 | 323 | struct v4l2_subdev *tx; |
| 324 | − unsigned int width, height, fps; | |
| 325 | 324 | |
| 326 | 325 | tx = adv748x_get_remote_sd(&afe->pads[ADV748X_AFE_SOURCE]); |
| 327 | 326 | if (!tx) |
| 328 | 327 | return -ENOLINK; |
| 329 | 328 | |
| 330 | − width = 720; | |
| 331 | − height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576; | |
| 332 | − fps = afe->curr_norm & V4L2_STD_525_60 ? 30 : 25; | |
| 333 | − | |
| 334 | − return adv748x_csi2_set_pixelrate(tx, width * height * fps); | |
| 329 | + /* | |
| 330 | + * The ADV748x ADC sampling frequency is twice the externally supplied | |
| 331 | + * clock whose frequency is required to be 28.63636 MHz. It oversamples | |
| 332 | + * with a factor of 4 resulting in a pixel rate of 14.3180180 MHz. | |
| 333 | + */ | |
| 334 | + return adv748x_csi2_set_pixelrate(tx, 14318180); | |
| 335 | 335 | } |
| 336 | 336 | |
| 337 | 337 | static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, |
| @@ -402,8 +402,6 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi) · 401 unmodified lines | ||
| 402 | 402 | { |
| 403 | 403 | struct v4l2_subdev *tx; |
| 404 | 404 | struct v4l2_dv_timings timings; |
| 405 | − struct v4l2_bt_timings *bt = &timings.bt; | |
| 406 | − unsigned int fps; | |
| 407 | 405 | |
| 408 | 406 | tx = adv748x_get_remote_sd(&hdmi->pads[ADV748X_HDMI_SOURCE]); |
| 409 | 407 | if (!tx) |
| @@ -411,11 +409,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi) · 1 unmodified line | ||
| 411 | 409 | |
| 412 | 410 | adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings); |
| 413 | 411 | |
| 414 | − fps = DIV_ROUND_CLOSEST_ULL(bt->pixelclock, | |
| 415 | − V4L2_DV_BT_FRAME_WIDTH(bt) * | |
| 416 | − V4L2_DV_BT_FRAME_HEIGHT(bt)); | |
| 417 | − | |
| 418 | − return adv748x_csi2_set_pixelrate(tx, bt->width * bt->height * fps); | |
| 412 | + return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock); | |
| 419 | 413 | } |
| 420 | 414 | |
| 421 | 415 | static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd, |
| @@ -732,8 +732,8 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) · 731 unmodified lines | ||
| 732 | 732 | /* power up cec section */ |
| 733 | 733 | adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); |
| 734 | 734 | /* legacy mode and clear all rx buffers */ |
| 735 | + adv7511_cec_write(sd, 0x4a, 0x00); | |
| 735 | 736 | adv7511_cec_write(sd, 0x4a, 0x07); |
| 736 | − adv7511_cec_write(sd, 0x4a, 0); | |
| 737 | 737 | adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ |
| 738 | 738 | /* enabled irqs: */ |
| 739 | 739 | /* tx: ready */ |
| @@ -831,8 +831,8 @@ static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, · 91 unmodified lines | ||
| 831 | 831 | */ |
| 832 | 832 | adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); |
| 833 | 833 | |
| 834 | − /* blocking, clear cec tx irq status */ | |
| 835 | − adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38); | |
| 834 | + /* clear cec tx irq status */ | |
| 835 | + adv7511_wr(sd, 0x97, 0x38); | |
| 836 | 836 | |
| 837 | 837 | /* write data */ |
| 838 | 838 | for (i = 0; i < len; i++) |
| @@ -917,9 +917,6 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) · 78 unmodified lines | ||
| 917 | 917 | else if (adv7511_have_hotplug(sd)) |
| 918 | 918 | irqs |= MASK_ADV7511_EDID_RDY_INT; |
| 919 | 919 | |
| 920 | − adv7511_wr_and_or(sd, 0x95, 0xc0, | |
| 921 | − (state->cec_enabled_adap && enable) ? 0x39 : 0x00); | |
| 922 | − | |
| 923 | 920 | /* |
| 924 | 921 | * This i2c write can fail (approx. 1 in 1000 writes). But it |
| 925 | 922 | * is essential that this register is correct, so retry it |
| @@ -933,9 +930,11 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) · 7 unmodified lines | ||
| 933 | 930 | irqs_rd = adv7511_rd(sd, 0x94); |
| 934 | 931 | } while (retries-- && irqs_rd != irqs); |
| 935 | 932 | |
| 936 | − if (irqs_rd == irqs) | |
| 937 | − return; | |
| 938 | − v4l2_err(sd, "Could not set interrupts: hw failure?\n"); | |
| 933 | + if (irqs_rd != irqs) | |
| 934 | + v4l2_err(sd, "Could not set interrupts: hw failure?\n"); | |
| 935 | + | |
| 936 | + adv7511_wr_and_or(sd, 0x95, 0xc0, | |
| 937 | + (state->cec_enabled_adap && enable) ? 0x39 : 0x00); | |
| 939 | 938 | } |
| 940 | 939 | |
| 941 | 940 | /* Interrupt handler */ |
| @@ -982,8 +981,8 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) · 40 unmodified lines | ||
| 982 | 981 | for (i = 0; i < msg.len; i++) |
| 983 | 982 | msg.msg[i] = adv7511_cec_read(sd, i + 0x15); |
| 984 | 983 | |
| 985 | − adv7511_cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */ | |
| 986 | − adv7511_cec_write(sd, 0x4a, 0); | |
| 984 | + adv7511_cec_write(sd, 0x4a, 0); /* toggle to re-enable rx 1 */ | |
| 985 | + adv7511_cec_write(sd, 0x4a, 1); | |
| 987 | 986 | cec_received_msg(state->cec_adap, &msg); |
| 988 | 987 | } |
| 989 | 988 | } |
| @@ -1778,6 +1777,7 @@ static void adv7511_init_setup(struct v4l2_subdev *sd) · 788 unmodified lines | ||
| 1778 | 1777 | |
| 1779 | 1778 | /* legacy mode */ |
| 1780 | 1779 | adv7511_cec_write(sd, 0x4a, 0x00); |
| 1780 | + adv7511_cec_write(sd, 0x4a, 0x07); | |
| 1781 | 1781 | |
| 1782 | 1782 | if (cec_clk % 750000 != 0) |
| 1783 | 1783 | v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", |
| @@ -0,0 +1,1318 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// Copyright (C) 2018 Intel Corporation | |
| 3 | + | |
| 4 | +#include <linux/acpi.h> | |
| 5 | +#include <linux/delay.h> | |
| 6 | +#include <linux/i2c.h> | |
| 7 | +#include <linux/module.h> | |
| 8 | +#include <linux/pm_runtime.h> | |
| 9 | +#include <media/v4l2-ctrls.h> | |
| 10 | +#include <media/v4l2-device.h> | |
| 11 | +#include <asm/unaligned.h> | |
| 12 | + | |
| 13 | +#define IMX258_REG_VALUE_08BIT 1 | |
| 14 | +#define IMX258_REG_VALUE_16BIT 2 | |
| 15 | + | |
| 16 | +#define IMX258_REG_MODE_SELECT 0x0100 | |
| 17 | +#define IMX258_MODE_STANDBY 0x00 | |
| 18 | +#define IMX258_MODE_STREAMING 0x01 | |
| 19 | + | |
| 20 | +/* Chip ID */ | |
| 21 | +#define IMX258_REG_CHIP_ID 0x0016 | |
| 22 | +#define IMX258_CHIP_ID 0x0258 | |
| 23 | + | |
| 24 | +/* V_TIMING internal */ | |
| 25 | +#define IMX258_VTS_30FPS 0x0c98 | |
| 26 | +#define IMX258_VTS_30FPS_2K 0x0638 | |
| 27 | +#define IMX258_VTS_30FPS_VGA 0x034c | |
| 28 | +#define IMX258_VTS_MAX 0xffff | |
| 29 | + | |
| 30 | +/*Frame Length Line*/ | |
| 31 | +#define IMX258_FLL_MIN 0x08a6 | |
| 32 | +#define IMX258_FLL_MAX 0xffff | |
| 33 | +#define IMX258_FLL_STEP 1 | |
| 34 | +#define IMX258_FLL_DEFAULT 0x0c98 | |
| 35 | + | |
| 36 | +/* HBLANK control - read only */ | |
| 37 | +#define IMX258_PPL_DEFAULT 5352 | |
| 38 | + | |
| 39 | +/* Exposure control */ | |
| 40 | +#define IMX258_REG_EXPOSURE 0x0202 | |
| 41 | +#define IMX258_EXPOSURE_MIN 4 | |
| 42 | +#define IMX258_EXPOSURE_STEP 1 | |
| 43 | +#define IMX258_EXPOSURE_DEFAULT 0x640 | |
| 44 | +#define IMX258_EXPOSURE_MAX 65535 | |
| 45 | + | |
| 46 | +/* Analog gain control */ | |
| 47 | +#define IMX258_REG_ANALOG_GAIN 0x0204 | |
| 48 | +#define IMX258_ANA_GAIN_MIN 0 | |
| 49 | +#define IMX258_ANA_GAIN_MAX 0x1fff | |
| 50 | +#define IMX258_ANA_GAIN_STEP 1 | |
| 51 | +#define IMX258_ANA_GAIN_DEFAULT 0x0 | |
| 52 | + | |
| 53 | +/* Digital gain control */ | |
| 54 | +#define IMX258_REG_GR_DIGITAL_GAIN 0x020e | |
| 55 | +#define IMX258_REG_R_DIGITAL_GAIN 0x0210 | |
| 56 | +#define IMX258_REG_B_DIGITAL_GAIN 0x0212 | |
| 57 | +#define IMX258_REG_GB_DIGITAL_GAIN 0x0214 | |
| 58 | +#define IMX258_DGTL_GAIN_MIN 0 | |
| 59 | +#define IMX258_DGTL_GAIN_MAX 4096 /* Max = 0xFFF */ | |
| 60 | +#define IMX258_DGTL_GAIN_DEFAULT 1024 | |
| 61 | +#define IMX258_DGTL_GAIN_STEP 1 | |
| 62 | + | |
| 63 | +/* Test Pattern Control */ | |
| 64 | +#define IMX258_REG_TEST_PATTERN 0x0600 | |
| 65 | +#define IMX258_TEST_PATTERN_DISABLE 0 | |
| 66 | +#define IMX258_TEST_PATTERN_SOLID_COLOR 1 | |
| 67 | +#define IMX258_TEST_PATTERN_COLOR_BARS 2 | |
| 68 | +#define IMX258_TEST_PATTERN_GREY_COLOR 3 | |
| 69 | +#define IMX258_TEST_PATTERN_PN9 4 | |
| 70 | + | |
| 71 | +/* Orientation */ | |
| 72 | +#define REG_MIRROR_FLIP_CONTROL 0x0101 | |
| 73 | +#define REG_CONFIG_MIRROR_FLIP 0x03 | |
| 74 | +#define REG_CONFIG_FLIP_TEST_PATTERN 0x02 | |
| 75 | + | |
| 76 | +struct imx258_reg { | |
| 77 | + u16 address; | |
| 78 | + u8 val; | |
| 79 | +}; | |
| 80 | + | |
| 81 | +struct imx258_reg_list { | |
| 82 | + u32 num_of_regs; | |
| 83 | + const struct imx258_reg *regs; | |
| 84 | +}; | |
| 85 | + | |
| 86 | +/* Link frequency config */ | |
| 87 | +struct imx258_link_freq_config { | |
| 88 | + u32 pixels_per_line; | |
| 89 | + | |
| 90 | + /* PLL registers for this link frequency */ | |
| 91 | + struct imx258_reg_list reg_list; | |
| 92 | +}; | |
| 93 | + | |
| 94 | +/* Mode : resolution and related config&values */ | |
| 95 | +struct imx258_mode { | |
| 96 | + /* Frame width */ | |
| 97 | + u32 width; | |
| 98 | + /* Frame height */ | |
| 99 | + u32 height; | |
| 100 | + | |
| 101 | + /* V-timing */ | |
| 102 | + u32 vts_def; | |
| 103 | + u32 vts_min; | |
| 104 | + | |
| 105 | + /* Index of Link frequency config to be used */ | |
| 106 | + u32 link_freq_index; | |
| 107 | + /* Default register values */ | |
| 108 | + struct imx258_reg_list reg_list; | |
| 109 | +}; | |
| 110 | + | |
| 111 | +/* 4208x3118 needs 1267Mbps/lane, 4 lanes */ | |
| 112 | +static const struct imx258_reg mipi_data_rate_1267mbps[] = { | |
| 113 | + { 0x0301, 0x05 }, | |
| 114 | + { 0x0303, 0x02 }, | |
| 115 | + { 0x0305, 0x03 }, | |
| 116 | + { 0x0306, 0x00 }, | |
| 117 | + { 0x0307, 0xC6 }, | |
| 118 | + { 0x0309, 0x0A }, | |
| 119 | + { 0x030B, 0x01 }, | |
| 120 | + { 0x030D, 0x02 }, | |
| 121 | + { 0x030E, 0x00 }, | |
| 122 | + { 0x030F, 0xD8 }, | |
| 123 | + { 0x0310, 0x00 }, | |
| 124 | + { 0x0820, 0x13 }, | |
| 125 | + { 0x0821, 0x4C }, | |
| 126 | + { 0x0822, 0xCC }, | |
| 127 | + { 0x0823, 0xCC }, | |
| 128 | +}; | |
| 129 | + | |
| 130 | +static const struct imx258_reg mipi_data_rate_640mbps[] = { | |
| 131 | + { 0x0301, 0x05 }, | |
| 132 | + { 0x0303, 0x02 }, | |
| 133 | + { 0x0305, 0x03 }, | |
| 134 | + { 0x0306, 0x00 }, | |
| 135 | + { 0x0307, 0x64 }, | |
| 136 | + { 0x0309, 0x0A }, | |
| 137 | + { 0x030B, 0x01 }, | |
| 138 | + { 0x030D, 0x02 }, | |
| 139 | + { 0x030E, 0x00 }, | |
| 140 | + { 0x030F, 0xD8 }, | |
| 141 | + { 0x0310, 0x00 }, | |
| 142 | + { 0x0820, 0x0A }, | |
| 143 | + { 0x0821, 0x00 }, | |
| 144 | + { 0x0822, 0x00 }, | |
| 145 | + { 0x0823, 0x00 }, | |
| 146 | +}; | |
| 147 | + | |
| 148 | +static const struct imx258_reg mode_4208x3118_regs[] = { | |
| 149 | + { 0x0136, 0x13 }, | |
| 150 | + { 0x0137, 0x33 }, | |
| 151 | + { 0x3051, 0x00 }, | |
| 152 | + { 0x3052, 0x00 }, | |
| 153 | + { 0x4E21, 0x14 }, | |
| 154 | + { 0x6B11, 0xCF }, | |
| 155 | + { 0x7FF0, 0x08 }, | |
| 156 | + { 0x7FF1, 0x0F }, | |
| 157 | + { 0x7FF2, 0x08 }, | |
| 158 | + { 0x7FF3, 0x1B }, | |
| 159 | + { 0x7FF4, 0x23 }, | |
| 160 | + { 0x7FF5, 0x60 }, | |
| 161 | + { 0x7FF6, 0x00 }, | |
| 162 | + { 0x7FF7, 0x01 }, | |
| 163 | + { 0x7FF8, 0x00 }, | |
| 164 | + { 0x7FF9, 0x78 }, | |
| 165 | + { 0x7FFA, 0x00 }, | |
| 166 | + { 0x7FFB, 0x00 }, | |
| 167 | + { 0x7FFC, 0x00 }, | |
| 168 | + { 0x7FFD, 0x00 }, | |
| 169 | + { 0x7FFE, 0x00 }, | |
| 170 | + { 0x7FFF, 0x03 }, | |
| 171 | + { 0x7F76, 0x03 }, | |
| 172 | + { 0x7F77, 0xFE }, | |
| 173 | + { 0x7FA8, 0x03 }, | |
| 174 | + { 0x7FA9, 0xFE }, | |
| 175 | + { 0x7B24, 0x81 }, | |
| 176 | + { 0x7B25, 0x00 }, | |
| 177 | + { 0x6564, 0x07 }, | |
| 178 | + { 0x6B0D, 0x41 }, | |
| 179 | + { 0x653D, 0x04 }, | |
| 180 | + { 0x6B05, 0x8C }, | |
| 181 | + { 0x6B06, 0xF9 }, | |
| 182 | + { 0x6B08, 0x65 }, | |
| 183 | + { 0x6B09, 0xFC }, | |
| 184 | + { 0x6B0A, 0xCF }, | |
| 185 | + { 0x6B0B, 0xD2 }, | |
| 186 | + { 0x6700, 0x0E }, | |
| 187 | + { 0x6707, 0x0E }, | |
| 188 | + { 0x9104, 0x00 }, | |
| 189 | + { 0x4648, 0x7F }, | |
| 190 | + { 0x7420, 0x00 }, | |
| 191 | + { 0x7421, 0x1C }, | |
| 192 | + { 0x7422, 0x00 }, | |
| 193 | + { 0x7423, 0xD7 }, | |
| 194 | + { 0x5F04, 0x00 }, | |
| 195 | + { 0x5F05, 0xED }, | |
| 196 | + { 0x0112, 0x0A }, | |
| 197 | + { 0x0113, 0x0A }, | |
| 198 | + { 0x0114, 0x03 }, | |
| 199 | + { 0x0342, 0x14 }, | |
| 200 | + { 0x0343, 0xE8 }, | |
| 201 | + { 0x0340, 0x0C }, | |
| 202 | + { 0x0341, 0x50 }, | |
| 203 | + { 0x0344, 0x00 }, | |
| 204 | + { 0x0345, 0x00 }, | |
| 205 | + { 0x0346, 0x00 }, | |
| 206 | + { 0x0347, 0x00 }, | |
| 207 | + { 0x0348, 0x10 }, | |
| 208 | + { 0x0349, 0x6F }, | |
| 209 | + { 0x034A, 0x0C }, | |
| 210 | + { 0x034B, 0x2E }, | |
| 211 | + { 0x0381, 0x01 }, | |
| 212 | + { 0x0383, 0x01 }, | |
| 213 | + { 0x0385, 0x01 }, | |
| 214 | + { 0x0387, 0x01 }, | |
| 215 | + { 0x0900, 0x00 }, | |
| 216 | + { 0x0901, 0x11 }, | |
| 217 | + { 0x0401, 0x00 }, | |
| 218 | + { 0x0404, 0x00 }, | |
| 219 | + { 0x0405, 0x10 }, | |
| 220 | + { 0x0408, 0x00 }, | |
| 221 | + { 0x0409, 0x00 }, | |
| 222 | + { 0x040A, 0x00 }, | |
| 223 | + { 0x040B, 0x00 }, | |
| 224 | + { 0x040C, 0x10 }, | |
| 225 | + { 0x040D, 0x70 }, | |
| 226 | + { 0x040E, 0x0C }, | |
| 227 | + { 0x040F, 0x30 }, | |
| 228 | + { 0x3038, 0x00 }, | |
| 229 | + { 0x303A, 0x00 }, | |
| 230 | + { 0x303B, 0x10 }, | |
| 231 | + { 0x300D, 0x00 }, | |
| 232 | + { 0x034C, 0x10 }, | |
| 233 | + { 0x034D, 0x70 }, | |
| 234 | + { 0x034E, 0x0C }, | |
| 235 | + { 0x034F, 0x30 }, | |
| 236 | + { 0x0350, 0x01 }, | |
| 237 | + { 0x0202, 0x0C }, | |
| 238 | + { 0x0203, 0x46 }, | |
| 239 | + { 0x0204, 0x00 }, | |
| 240 | + { 0x0205, 0x00 }, | |
| 241 | + { 0x020E, 0x01 }, | |
| 242 | + { 0x020F, 0x00 }, | |
| 243 | + { 0x0210, 0x01 }, | |
| 244 | + { 0x0211, 0x00 }, | |
| 245 | + { 0x0212, 0x01 }, | |
| 246 | + { 0x0213, 0x00 }, | |
| 247 | + { 0x0214, 0x01 }, | |
| 248 | + { 0x0215, 0x00 }, | |
| 249 | + { 0x7BCD, 0x00 }, | |
| 250 | + { 0x94DC, 0x20 }, | |
| 251 | + { 0x94DD, 0x20 }, | |
| 252 | + { 0x94DE, 0x20 }, | |
| 253 | + { 0x95DC, 0x20 }, | |
| 254 | + { 0x95DD, 0x20 }, | |
| 255 | + { 0x95DE, 0x20 }, | |
| 256 | + { 0x7FB0, 0x00 }, | |
| 257 | + { 0x9010, 0x3E }, | |
| 258 | + { 0x9419, 0x50 }, | |
| 259 | + { 0x941B, 0x50 }, | |
| 260 | + { 0x9519, 0x50 }, | |
| 261 | + { 0x951B, 0x50 }, | |
| 262 | + { 0x3030, 0x00 }, | |
| 263 | + { 0x3032, 0x00 }, | |
| 264 | + { 0x0220, 0x00 }, | |
| 265 | +}; | |
| 266 | + | |
| 267 | +static const struct imx258_reg mode_2104_1560_regs[] = { | |
| 268 | + { 0x0136, 0x13 }, | |
| 269 | + { 0x0137, 0x33 }, | |
| 270 | + { 0x3051, 0x00 }, | |
| 271 | + { 0x3052, 0x00 }, | |
| 272 | + { 0x4E21, 0x14 }, | |
| 273 | + { 0x6B11, 0xCF }, | |
| 274 | + { 0x7FF0, 0x08 }, | |
| 275 | + { 0x7FF1, 0x0F }, | |
| 276 | + { 0x7FF2, 0x08 }, | |
| 277 | + { 0x7FF3, 0x1B }, | |
| 278 | + { 0x7FF4, 0x23 }, | |
| 279 | + { 0x7FF5, 0x60 }, | |
| 280 | + { 0x7FF6, 0x00 }, | |
| 281 | + { 0x7FF7, 0x01 }, | |
| 282 | + { 0x7FF8, 0x00 }, | |
| 283 | + { 0x7FF9, 0x78 }, | |
| 284 | + { 0x7FFA, 0x00 }, | |
| 285 | + { 0x7FFB, 0x00 }, | |
| 286 | + { 0x7FFC, 0x00 }, | |
| 287 | + { 0x7FFD, 0x00 }, | |
| 288 | + { 0x7FFE, 0x00 }, | |
| 289 | + { 0x7FFF, 0x03 }, | |
| 290 | + { 0x7F76, 0x03 }, | |
| 291 | + { 0x7F77, 0xFE }, | |
| 292 | + { 0x7FA8, 0x03 }, | |
| 293 | + { 0x7FA9, 0xFE }, | |
| 294 | + { 0x7B24, 0x81 }, | |
| 295 | + { 0x7B25, 0x00 }, | |
| 296 | + { 0x6564, 0x07 }, | |
| 297 | + { 0x6B0D, 0x41 }, | |
| 298 | + { 0x653D, 0x04 }, | |
| 299 | + { 0x6B05, 0x8C }, | |
| 300 | + { 0x6B06, 0xF9 }, | |
| 301 | + { 0x6B08, 0x65 }, | |
| 302 | + { 0x6B09, 0xFC }, | |
| 303 | + { 0x6B0A, 0xCF }, | |
| 304 | + { 0x6B0B, 0xD2 }, | |
| 305 | + { 0x6700, 0x0E }, | |
| 306 | + { 0x6707, 0x0E }, | |
| 307 | + { 0x9104, 0x00 }, | |
| 308 | + { 0x4648, 0x7F }, | |
| 309 | + { 0x7420, 0x00 }, | |
| 310 | + { 0x7421, 0x1C }, | |
| 311 | + { 0x7422, 0x00 }, | |
| 312 | + { 0x7423, 0xD7 }, | |
| 313 | + { 0x5F04, 0x00 }, | |
| 314 | + { 0x5F05, 0xED }, | |
| 315 | + { 0x0112, 0x0A }, | |
| 316 | + { 0x0113, 0x0A }, | |
| 317 | + { 0x0114, 0x03 }, | |
| 318 | + { 0x0342, 0x14 }, | |
| 319 | + { 0x0343, 0xE8 }, | |
| 320 | + { 0x0340, 0x06 }, | |
| 321 | + { 0x0341, 0x38 }, | |
| 322 | + { 0x0344, 0x00 }, | |
| 323 | + { 0x0345, 0x00 }, | |
| 324 | + { 0x0346, 0x00 }, | |
| 325 | + { 0x0347, 0x00 }, | |
| 326 | + { 0x0348, 0x10 }, | |
| 327 | + { 0x0349, 0x6F }, | |
| 328 | + { 0x034A, 0x0C }, | |
| 329 | + { 0x034B, 0x2E }, | |
| 330 | + { 0x0381, 0x01 }, | |
| 331 | + { 0x0383, 0x01 }, | |
| 332 | + { 0x0385, 0x01 }, | |
| 333 | + { 0x0387, 0x01 }, | |
| 334 | + { 0x0900, 0x01 }, | |
| 335 | + { 0x0901, 0x12 }, | |
| 336 | + { 0x0401, 0x01 }, | |
| 337 | + { 0x0404, 0x00 }, | |
| 338 | + { 0x0405, 0x20 }, | |
| 339 | + { 0x0408, 0x00 }, | |
| 340 | + { 0x0409, 0x02 }, | |
| 341 | + { 0x040A, 0x00 }, | |
| 342 | + { 0x040B, 0x00 }, | |
| 343 | + { 0x040C, 0x10 }, | |
| 344 | + { 0x040D, 0x6A }, | |
| 345 | + { 0x040E, 0x06 }, | |
| 346 | + { 0x040F, 0x18 }, | |
| 347 | + { 0x3038, 0x00 }, | |
| 348 | + { 0x303A, 0x00 }, | |
| 349 | + { 0x303B, 0x10 }, | |
| 350 | + { 0x300D, 0x00 }, | |
| 351 | + { 0x034C, 0x08 }, | |
| 352 | + { 0x034D, 0x38 }, | |
| 353 | + { 0x034E, 0x06 }, | |
| 354 | + { 0x034F, 0x18 }, | |
| 355 | + { 0x0350, 0x01 }, | |
| 356 | + { 0x0202, 0x06 }, | |
| 357 | + { 0x0203, 0x2E }, | |
| 358 | + { 0x0204, 0x00 }, | |
| 359 | + { 0x0205, 0x00 }, | |
| 360 | + { 0x020E, 0x01 }, | |
| 361 | + { 0x020F, 0x00 }, | |
| 362 | + { 0x0210, 0x01 }, | |
| 363 | + { 0x0211, 0x00 }, | |
| 364 | + { 0x0212, 0x01 }, | |
| 365 | + { 0x0213, 0x00 }, | |
| 366 | + { 0x0214, 0x01 }, | |
| 367 | + { 0x0215, 0x00 }, | |
| 368 | + { 0x7BCD, 0x01 }, | |
| 369 | + { 0x94DC, 0x20 }, | |
| 370 | + { 0x94DD, 0x20 }, | |
| 371 | + { 0x94DE, 0x20 }, | |
| 372 | + { 0x95DC, 0x20 }, | |
| 373 | + { 0x95DD, 0x20 }, | |
| 374 | + { 0x95DE, 0x20 }, | |
| 375 | + { 0x7FB0, 0x00 }, | |
| 376 | + { 0x9010, 0x3E }, | |
| 377 | + { 0x9419, 0x50 }, | |
| 378 | + { 0x941B, 0x50 }, | |
| 379 | + { 0x9519, 0x50 }, | |
| 380 | + { 0x951B, 0x50 }, | |
| 381 | + { 0x3030, 0x00 }, | |
| 382 | + { 0x3032, 0x00 }, | |
| 383 | + { 0x0220, 0x00 }, | |
| 384 | +}; | |
| 385 | + | |
| 386 | +static const struct imx258_reg mode_1048_780_regs[] = { | |
| 387 | + { 0x0136, 0x13 }, | |
| 388 | + { 0x0137, 0x33 }, | |
| 389 | + { 0x3051, 0x00 }, | |
| 390 | + { 0x3052, 0x00 }, | |
| 391 | + { 0x4E21, 0x14 }, | |
| 392 | + { 0x6B11, 0xCF }, | |
| 393 | + { 0x7FF0, 0x08 }, | |
| 394 | + { 0x7FF1, 0x0F }, | |
| 395 | + { 0x7FF2, 0x08 }, | |
| 396 | + { 0x7FF3, 0x1B }, | |
| 397 | + { 0x7FF4, 0x23 }, | |
| 398 | + { 0x7FF5, 0x60 }, | |
| 399 | + { 0x7FF6, 0x00 }, | |
| 400 | + { 0x7FF7, 0x01 }, | |
| 401 | + { 0x7FF8, 0x00 }, | |
| 402 | + { 0x7FF9, 0x78 }, | |
| 403 | + { 0x7FFA, 0x00 }, | |
| 404 | + { 0x7FFB, 0x00 }, | |
| 405 | + { 0x7FFC, 0x00 }, | |
| 406 | + { 0x7FFD, 0x00 }, | |
| 407 | + { 0x7FFE, 0x00 }, | |
| 408 | + { 0x7FFF, 0x03 }, | |
| 409 | + { 0x7F76, 0x03 }, | |
| 410 | + { 0x7F77, 0xFE }, | |
| 411 | + { 0x7FA8, 0x03 }, | |
| 412 | + { 0x7FA9, 0xFE }, | |
| 413 | + { 0x7B24, 0x81 }, | |
| 414 | + { 0x7B25, 0x00 }, | |
| 415 | + { 0x6564, 0x07 }, | |
| 416 | + { 0x6B0D, 0x41 }, | |
| 417 | + { 0x653D, 0x04 }, | |
| 418 | + { 0x6B05, 0x8C }, | |
| 419 | + { 0x6B06, 0xF9 }, | |
| 420 | + { 0x6B08, 0x65 }, | |
| 421 | + { 0x6B09, 0xFC }, | |
| 422 | + { 0x6B0A, 0xCF }, | |
| 423 | + { 0x6B0B, 0xD2 }, | |
| 424 | + { 0x6700, 0x0E }, | |
| 425 | + { 0x6707, 0x0E }, | |
| 426 | + { 0x9104, 0x00 }, | |
| 427 | + { 0x4648, 0x7F }, | |
| 428 | + { 0x7420, 0x00 }, | |
| 429 | + { 0x7421, 0x1C }, | |
| 430 | + { 0x7422, 0x00 }, | |
| 431 | + { 0x7423, 0xD7 }, | |
| 432 | + { 0x5F04, 0x00 }, | |
| 433 | + { 0x5F05, 0xED }, | |
| 434 | + { 0x0112, 0x0A }, | |
| 435 | + { 0x0113, 0x0A }, | |
| 436 | + { 0x0114, 0x03 }, | |
| 437 | + { 0x0342, 0x14 }, | |
| 438 | + { 0x0343, 0xE8 }, | |
| 439 | + { 0x0340, 0x03 }, | |
| 440 | + { 0x0341, 0x4C }, | |
| 441 | + { 0x0344, 0x00 }, | |
| 442 | + { 0x0345, 0x00 }, | |
| 443 | + { 0x0346, 0x00 }, | |
| 444 | + { 0x0347, 0x00 }, | |
| 445 | + { 0x0348, 0x10 }, | |
| 446 | + { 0x0349, 0x6F }, | |
| 447 | + { 0x034A, 0x0C }, | |
| 448 | + { 0x034B, 0x2E }, | |
| 449 | + { 0x0381, 0x01 }, | |
| 450 | + { 0x0383, 0x01 }, | |
| 451 | + { 0x0385, 0x01 }, | |
| 452 | + { 0x0387, 0x01 }, | |
| 453 | + { 0x0900, 0x01 }, | |
| 454 | + { 0x0901, 0x14 }, | |
| 455 | + { 0x0401, 0x01 }, | |
| 456 | + { 0x0404, 0x00 }, | |
| 457 | + { 0x0405, 0x40 }, | |
| 458 | + { 0x0408, 0x00 }, | |
| 459 | + { 0x0409, 0x06 }, | |
| 460 | + { 0x040A, 0x00 }, | |
| 461 | + { 0x040B, 0x00 }, | |
| 462 | + { 0x040C, 0x10 }, | |
| 463 | + { 0x040D, 0x64 }, | |
| 464 | + { 0x040E, 0x03 }, | |
| 465 | + { 0x040F, 0x0C }, | |
| 466 | + { 0x3038, 0x00 }, | |
| 467 | + { 0x303A, 0x00 }, | |
| 468 | + { 0x303B, 0x10 }, | |
| 469 | + { 0x300D, 0x00 }, | |
| 470 | + { 0x034C, 0x04 }, | |
| 471 | + { 0x034D, 0x18 }, | |
| 472 | + { 0x034E, 0x03 }, | |
| 473 | + { 0x034F, 0x0C }, | |
| 474 | + { 0x0350, 0x01 }, | |
| 475 | + { 0x0202, 0x03 }, | |
| 476 | + { 0x0203, 0x42 }, | |
| 477 | + { 0x0204, 0x00 }, | |
| 478 | + { 0x0205, 0x00 }, | |
| 479 | + { 0x020E, 0x01 }, | |
| 480 | + { 0x020F, 0x00 }, | |
| 481 | + { 0x0210, 0x01 }, | |
| 482 | + { 0x0211, 0x00 }, | |
| 483 | + { 0x0212, 0x01 }, | |
| 484 | + { 0x0213, 0x00 }, | |
| 485 | + { 0x0214, 0x01 }, | |
| 486 | + { 0x0215, 0x00 }, | |
| 487 | + { 0x7BCD, 0x00 }, | |
| 488 | + { 0x94DC, 0x20 }, | |
| 489 | + { 0x94DD, 0x20 }, | |
| 490 | + { 0x94DE, 0x20 }, | |
| 491 | + { 0x95DC, 0x20 }, | |
| 492 | + { 0x95DD, 0x20 }, | |
| 493 | + { 0x95DE, 0x20 }, | |
| 494 | + { 0x7FB0, 0x00 }, | |
| 495 | + { 0x9010, 0x3E }, | |
| 496 | + { 0x9419, 0x50 }, | |
| 497 | + { 0x941B, 0x50 }, | |
| 498 | + { 0x9519, 0x50 }, | |
| 499 | + { 0x951B, 0x50 }, | |
| 500 | + { 0x3030, 0x00 }, | |
| 501 | + { 0x3032, 0x00 }, | |
| 502 | + { 0x0220, 0x00 }, | |
| 503 | +}; | |
| 504 | + | |
| 505 | +static const char * const imx258_test_pattern_menu[] = { | |
| 506 | + "Disabled", | |
| 507 | + "Color Bars", | |
| 508 | + "Solid Color", | |
| 509 | + "Grey Color Bars", | |
| 510 | + "PN9" | |
| 511 | +}; | |
| 512 | + | |
| 513 | +static const int imx258_test_pattern_val[] = { | |
| 514 | + IMX258_TEST_PATTERN_DISABLE, | |
| 515 | + IMX258_TEST_PATTERN_COLOR_BARS, | |
| 516 | + IMX258_TEST_PATTERN_SOLID_COLOR, | |
| 517 | + IMX258_TEST_PATTERN_GREY_COLOR, | |
| 518 | + IMX258_TEST_PATTERN_PN9, | |
| 519 | +}; | |
| 520 | + | |
| 521 | +/* Configurations for supported link frequencies */ | |
| 522 | +#define IMX258_LINK_FREQ_634MHZ 633600000ULL | |
| 523 | +#define IMX258_LINK_FREQ_320MHZ 320000000ULL | |
| 524 | + | |
| 525 | +enum { | |
| 526 | + IMX258_LINK_FREQ_1267MBPS, | |
| 527 | + IMX258_LINK_FREQ_640MBPS, | |
| 528 | +}; | |
| 529 | + | |
| 530 | +/* | |
| 531 | + * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample | |
| 532 | + * data rate => double data rate; number of lanes => 4; bits per pixel => 10 | |
| 533 | + */ | |
| 534 | +static u64 link_freq_to_pixel_rate(u64 f) | |
| 535 | +{ | |
| 536 | + f *= 2 * 4; | |
| 537 | + do_div(f, 10); | |
| 538 | + | |
| 539 | + return f; | |
| 540 | +} | |
| 541 | + | |
| 542 | +/* Menu items for LINK_FREQ V4L2 control */ | |
| 543 | +static const s64 link_freq_menu_items[] = { | |
| 544 | + IMX258_LINK_FREQ_634MHZ, | |
| 545 | + IMX258_LINK_FREQ_320MHZ, | |
| 546 | +}; | |
| 547 | + | |
| 548 | +/* Link frequency configs */ | |
| 549 | +static const struct imx258_link_freq_config link_freq_configs[] = { | |
| 550 | + [IMX258_LINK_FREQ_1267MBPS] = { | |
| 551 | + .pixels_per_line = IMX258_PPL_DEFAULT, | |
| 552 | + .reg_list = { | |
| 553 | + .num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps), | |
| 554 | + .regs = mipi_data_rate_1267mbps, | |
| 555 | + } | |
| 556 | + }, | |
| 557 | + [IMX258_LINK_FREQ_640MBPS] = { | |
| 558 | + .pixels_per_line = IMX258_PPL_DEFAULT, | |
| 559 | + .reg_list = { | |
| 560 | + .num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps), | |
| 561 | + .regs = mipi_data_rate_640mbps, | |
| 562 | + } | |
| 563 | + }, | |
| 564 | +}; | |
| 565 | + | |
| 566 | +/* Mode configs */ | |
| 567 | +static const struct imx258_mode supported_modes[] = { | |
| 568 | + { | |
| 569 | + .width = 4208, | |
| 570 | + .height = 3118, | |
| 571 | + .vts_def = IMX258_VTS_30FPS, | |
| 572 | + .vts_min = IMX258_VTS_30FPS, | |
| 573 | + .reg_list = { | |
| 574 | + .num_of_regs = ARRAY_SIZE(mode_4208x3118_regs), | |
| 575 | + .regs = mode_4208x3118_regs, | |
| 576 | + }, | |
| 577 | + .link_freq_index = IMX258_LINK_FREQ_1267MBPS, | |
| 578 | + }, | |
| 579 | + { | |
| 580 | + .width = 2104, | |
| 581 | + .height = 1560, | |
| 582 | + .vts_def = IMX258_VTS_30FPS_2K, | |
| 583 | + .vts_min = IMX258_VTS_30FPS_2K, | |
| 584 | + .reg_list = { | |
| 585 | + .num_of_regs = ARRAY_SIZE(mode_2104_1560_regs), | |
| 586 | + .regs = mode_2104_1560_regs, | |
| 587 | + }, | |
| 588 | + .link_freq_index = IMX258_LINK_FREQ_640MBPS, | |
| 589 | + }, | |
| 590 | + { | |
| 591 | + .width = 1048, | |
| 592 | + .height = 780, | |
| 593 | + .vts_def = IMX258_VTS_30FPS_VGA, | |
| 594 | + .vts_min = IMX258_VTS_30FPS_VGA, | |
| 595 | + .reg_list = { | |
| 596 | + .num_of_regs = ARRAY_SIZE(mode_1048_780_regs), | |
| 597 | + .regs = mode_1048_780_regs, | |
| 598 | + }, | |
| 599 | + .link_freq_index = IMX258_LINK_FREQ_640MBPS, | |
| 600 | + }, | |
| 601 | +}; | |
| 602 | + | |
| 603 | +struct imx258 { | |
| 604 | + struct v4l2_subdev sd; | |
| 605 | + struct media_pad pad; | |
| 606 | + | |
| 607 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 608 | + /* V4L2 Controls */ | |
| 609 | + struct v4l2_ctrl *link_freq; | |
| 610 | + struct v4l2_ctrl *pixel_rate; | |
| 611 | + struct v4l2_ctrl *vblank; | |
| 612 | + struct v4l2_ctrl *hblank; | |
| 613 | + struct v4l2_ctrl *exposure; | |
| 614 | + | |
| 615 | + /* Current mode */ | |
| 616 | + const struct imx258_mode *cur_mode; | |
| 617 | + | |
| 618 | + /* | |
| 619 | + * Mutex for serialized access: | |
| 620 | + * Protect sensor module set pad format and start/stop streaming safely. | |
| 621 | + */ | |
| 622 | + struct mutex mutex; | |
| 623 | + | |
| 624 | + /* Streaming on/off */ | |
| 625 | + bool streaming; | |
| 626 | +}; | |
| 627 | + | |
| 628 | +static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd) | |
| 629 | +{ | |
| 630 | + return container_of(_sd, struct imx258, sd); | |
| 631 | +} | |
| 632 | + | |
| 633 | +/* Read registers up to 2 at a time */ | |
| 634 | +static int imx258_read_reg(struct imx258 *imx258, u16 reg, u32 len, u32 *val) | |
| 635 | +{ | |
| 636 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 637 | + struct i2c_msg msgs[2]; | |
| 638 | + u8 addr_buf[2] = { reg >> 8, reg & 0xff }; | |
| 639 | + u8 data_buf[4] = { 0, }; | |
| 640 | + int ret; | |
| 641 | + | |
| 642 | + if (len > 4) | |
| 643 | + return -EINVAL; | |
| 644 | + | |
| 645 | + /* Write register address */ | |
| 646 | + msgs[0].addr = client->addr; | |
| 647 | + msgs[0].flags = 0; | |
| 648 | + msgs[0].len = ARRAY_SIZE(addr_buf); | |
| 649 | + msgs[0].buf = addr_buf; | |
| 650 | + | |
| 651 | + /* Read data from register */ | |
| 652 | + msgs[1].addr = client->addr; | |
| 653 | + msgs[1].flags = I2C_M_RD; | |
| 654 | + msgs[1].len = len; | |
| 655 | + msgs[1].buf = &data_buf[4 - len]; | |
| 656 | + | |
| 657 | + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | |
| 658 | + if (ret != ARRAY_SIZE(msgs)) | |
| 659 | + return -EIO; | |
| 660 | + | |
| 661 | + *val = get_unaligned_be32(data_buf); | |
| 662 | + | |
| 663 | + return 0; | |
| 664 | +} | |
| 665 | + | |
| 666 | +/* Write registers up to 2 at a time */ | |
| 667 | +static int imx258_write_reg(struct imx258 *imx258, u16 reg, u32 len, u32 val) | |
| 668 | +{ | |
| 669 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 670 | + u8 buf[6]; | |
| 671 | + | |
| 672 | + if (len > 4) | |
| 673 | + return -EINVAL; | |
| 674 | + | |
| 675 | + put_unaligned_be16(reg, buf); | |
| 676 | + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); | |
| 677 | + if (i2c_master_send(client, buf, len + 2) != len + 2) | |
| 678 | + return -EIO; | |
| 679 | + | |
| 680 | + return 0; | |
| 681 | +} | |
| 682 | + | |
| 683 | +/* Write a list of registers */ | |
| 684 | +static int imx258_write_regs(struct imx258 *imx258, | |
| 685 | + const struct imx258_reg *regs, u32 len) | |
| 686 | +{ | |
| 687 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 688 | + unsigned int i; | |
| 689 | + int ret; | |
| 690 | + | |
| 691 | + for (i = 0; i < len; i++) { | |
| 692 | + ret = imx258_write_reg(imx258, regs[i].address, 1, | |
| 693 | + regs[i].val); | |
| 694 | + if (ret) { | |
| 695 | + dev_err_ratelimited( | |
| 696 | + &client->dev, | |
| 697 | + "Failed to write reg 0x%4.4x. error = %d\n", | |
| 698 | + regs[i].address, ret); | |
| 699 | + | |
| 700 | + return ret; | |
| 701 | + } | |
| 702 | + } | |
| 703 | + | |
| 704 | + return 0; | |
| 705 | +} | |
| 706 | + | |
| 707 | +/* Open sub-device */ | |
| 708 | +static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 709 | +{ | |
| 710 | + struct v4l2_mbus_framefmt *try_fmt = | |
| 711 | + v4l2_subdev_get_try_format(sd, fh->pad, 0); | |
| 712 | + | |
| 713 | + /* Initialize try_fmt */ | |
| 714 | + try_fmt->width = supported_modes[0].width; | |
| 715 | + try_fmt->height = supported_modes[0].height; | |
| 716 | + try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 717 | + try_fmt->field = V4L2_FIELD_NONE; | |
| 718 | + | |
| 719 | + return 0; | |
| 720 | +} | |
| 721 | + | |
| 722 | +static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val) | |
| 723 | +{ | |
| 724 | + int ret; | |
| 725 | + | |
| 726 | + ret = imx258_write_reg(imx258, IMX258_REG_GR_DIGITAL_GAIN, | |
| 727 | + IMX258_REG_VALUE_16BIT, | |
| 728 | + val); | |
| 729 | + if (ret) | |
| 730 | + return ret; | |
| 731 | + ret = imx258_write_reg(imx258, IMX258_REG_GB_DIGITAL_GAIN, | |
| 732 | + IMX258_REG_VALUE_16BIT, | |
| 733 | + val); | |
| 734 | + if (ret) | |
| 735 | + return ret; | |
| 736 | + ret = imx258_write_reg(imx258, IMX258_REG_R_DIGITAL_GAIN, | |
| 737 | + IMX258_REG_VALUE_16BIT, | |
| 738 | + val); | |
| 739 | + if (ret) | |
| 740 | + return ret; | |
| 741 | + ret = imx258_write_reg(imx258, IMX258_REG_B_DIGITAL_GAIN, | |
| 742 | + IMX258_REG_VALUE_16BIT, | |
| 743 | + val); | |
| 744 | + if (ret) | |
| 745 | + return ret; | |
| 746 | + return 0; | |
| 747 | +} | |
| 748 | + | |
| 749 | +static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 750 | +{ | |
| 751 | + struct imx258 *imx258 = | |
| 752 | + container_of(ctrl->handler, struct imx258, ctrl_handler); | |
| 753 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 754 | + int ret = 0; | |
| 755 | + | |
| 756 | + /* | |
| 757 | + * Applying V4L2 control value only happens | |
| 758 | + * when power is up for streaming | |
| 759 | + */ | |
| 760 | + if (pm_runtime_get_if_in_use(&client->dev) == 0) | |
| 761 | + return 0; | |
| 762 | + | |
| 763 | + switch (ctrl->id) { | |
| 764 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 765 | + ret = imx258_write_reg(imx258, IMX258_REG_ANALOG_GAIN, | |
| 766 | + IMX258_REG_VALUE_16BIT, | |
| 767 | + ctrl->val); | |
| 768 | + break; | |
| 769 | + case V4L2_CID_EXPOSURE: | |
| 770 | + ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE, | |
| 771 | + IMX258_REG_VALUE_16BIT, | |
| 772 | + ctrl->val); | |
| 773 | + break; | |
| 774 | + case V4L2_CID_DIGITAL_GAIN: | |
| 775 | + ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT, | |
| 776 | + ctrl->val); | |
| 777 | + break; | |
| 778 | + case V4L2_CID_TEST_PATTERN: | |
| 779 | + ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN, | |
| 780 | + IMX258_REG_VALUE_16BIT, | |
| 781 | + imx258_test_pattern_val[ctrl->val]); | |
| 782 | + | |
| 783 | + ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, | |
| 784 | + IMX258_REG_VALUE_08BIT, | |
| 785 | + ctrl->val == imx258_test_pattern_val | |
| 786 | + [IMX258_TEST_PATTERN_DISABLE] ? | |
| 787 | + REG_CONFIG_MIRROR_FLIP : | |
| 788 | + REG_CONFIG_FLIP_TEST_PATTERN); | |
| 789 | + break; | |
| 790 | + default: | |
| 791 | + dev_info(&client->dev, | |
| 792 | + "ctrl(id:0x%x,val:0x%x) is not handled\n", | |
| 793 | + ctrl->id, ctrl->val); | |
| 794 | + ret = -EINVAL; | |
| 795 | + break; | |
| 796 | + } | |
| 797 | + | |
| 798 | + pm_runtime_put(&client->dev); | |
| 799 | + | |
| 800 | + return ret; | |
| 801 | +} | |
| 802 | + | |
| 803 | +static const struct v4l2_ctrl_ops imx258_ctrl_ops = { | |
| 804 | + .s_ctrl = imx258_set_ctrl, | |
| 805 | +}; | |
| 806 | + | |
| 807 | +static int imx258_enum_mbus_code(struct v4l2_subdev *sd, | |
| 808 | + struct v4l2_subdev_pad_config *cfg, | |
| 809 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 810 | +{ | |
| 811 | + /* Only one bayer order(GRBG) is supported */ | |
| 812 | + if (code->index > 0) | |
| 813 | + return -EINVAL; | |
| 814 | + | |
| 815 | + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 816 | + | |
| 817 | + return 0; | |
| 818 | +} | |
| 819 | + | |
| 820 | +static int imx258_enum_frame_size(struct v4l2_subdev *sd, | |
| 821 | + struct v4l2_subdev_pad_config *cfg, | |
| 822 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 823 | +{ | |
| 824 | + if (fse->index >= ARRAY_SIZE(supported_modes)) | |
| 825 | + return -EINVAL; | |
| 826 | + | |
| 827 | + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) | |
| 828 | + return -EINVAL; | |
| 829 | + | |
| 830 | + fse->min_width = supported_modes[fse->index].width; | |
| 831 | + fse->max_width = fse->min_width; | |
| 832 | + fse->min_height = supported_modes[fse->index].height; | |
| 833 | + fse->max_height = fse->min_height; | |
| 834 | + | |
| 835 | + return 0; | |
| 836 | +} | |
| 837 | + | |
| 838 | +static void imx258_update_pad_format(const struct imx258_mode *mode, | |
| 839 | + struct v4l2_subdev_format *fmt) | |
| 840 | +{ | |
| 841 | + fmt->format.width = mode->width; | |
| 842 | + fmt->format.height = mode->height; | |
| 843 | + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 844 | + fmt->format.field = V4L2_FIELD_NONE; | |
| 845 | +} | |
| 846 | + | |
| 847 | +static int __imx258_get_pad_format(struct imx258 *imx258, | |
| 848 | + struct v4l2_subdev_pad_config *cfg, | |
| 849 | + struct v4l2_subdev_format *fmt) | |
| 850 | +{ | |
| 851 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 852 | + fmt->format = *v4l2_subdev_get_try_format(&imx258->sd, cfg, | |
| 853 | + fmt->pad); | |
| 854 | + else | |
| 855 | + imx258_update_pad_format(imx258->cur_mode, fmt); | |
| 856 | + | |
| 857 | + return 0; | |
| 858 | +} | |
| 859 | + | |
| 860 | +static int imx258_get_pad_format(struct v4l2_subdev *sd, | |
| 861 | + struct v4l2_subdev_pad_config *cfg, | |
| 862 | + struct v4l2_subdev_format *fmt) | |
| 863 | +{ | |
| 864 | + struct imx258 *imx258 = to_imx258(sd); | |
| 865 | + int ret; | |
| 866 | + | |
| 867 | + mutex_lock(&imx258->mutex); | |
| 868 | + ret = __imx258_get_pad_format(imx258, cfg, fmt); | |
| 869 | + mutex_unlock(&imx258->mutex); | |
| 870 | + | |
| 871 | + return ret; | |
| 872 | +} | |
| 873 | + | |
| 874 | +static int imx258_set_pad_format(struct v4l2_subdev *sd, | |
| 875 | + struct v4l2_subdev_pad_config *cfg, | |
| 876 | + struct v4l2_subdev_format *fmt) | |
| 877 | +{ | |
| 878 | + struct imx258 *imx258 = to_imx258(sd); | |
| 879 | + const struct imx258_mode *mode; | |
| 880 | + struct v4l2_mbus_framefmt *framefmt; | |
| 881 | + s32 vblank_def; | |
| 882 | + s32 vblank_min; | |
| 883 | + s64 h_blank; | |
| 884 | + s64 pixel_rate; | |
| 885 | + s64 link_freq; | |
| 886 | + | |
| 887 | + mutex_lock(&imx258->mutex); | |
| 888 | + | |
| 889 | + /* Only one raw bayer(GBRG) order is supported */ | |
| 890 | + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 891 | + | |
| 892 | + mode = v4l2_find_nearest_size(supported_modes, | |
| 893 | + ARRAY_SIZE(supported_modes), width, height, | |
| 894 | + fmt->format.width, fmt->format.height); | |
| 895 | + imx258_update_pad_format(mode, fmt); | |
| 896 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 897 | + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); | |
| 898 | + *framefmt = fmt->format; | |
| 899 | + } else { | |
| 900 | + imx258->cur_mode = mode; | |
| 901 | + __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); | |
| 902 | + | |
| 903 | + link_freq = link_freq_menu_items[mode->link_freq_index]; | |
| 904 | + pixel_rate = link_freq_to_pixel_rate(link_freq); | |
| 905 | + __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); | |
| 906 | + /* Update limits and set FPS to default */ | |
| 907 | + vblank_def = imx258->cur_mode->vts_def - | |
| 908 | + imx258->cur_mode->height; | |
| 909 | + vblank_min = imx258->cur_mode->vts_min - | |
| 910 | + imx258->cur_mode->height; | |
| 911 | + __v4l2_ctrl_modify_range( | |
| 912 | + imx258->vblank, vblank_min, | |
| 913 | + IMX258_VTS_MAX - imx258->cur_mode->height, 1, | |
| 914 | + vblank_def); | |
| 915 | + __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def); | |
| 916 | + h_blank = | |
| 917 | + link_freq_configs[mode->link_freq_index].pixels_per_line | |
| 918 | + - imx258->cur_mode->width; | |
| 919 | + __v4l2_ctrl_modify_range(imx258->hblank, h_blank, | |
| 920 | + h_blank, 1, h_blank); | |
| 921 | + } | |
| 922 | + | |
| 923 | + mutex_unlock(&imx258->mutex); | |
| 924 | + | |
| 925 | + return 0; | |
| 926 | +} | |
| 927 | + | |
| 928 | +/* Start streaming */ | |
| 929 | +static int imx258_start_streaming(struct imx258 *imx258) | |
| 930 | +{ | |
| 931 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 932 | + const struct imx258_reg_list *reg_list; | |
| 933 | + int ret, link_freq_index; | |
| 934 | + | |
| 935 | + /* Setup PLL */ | |
| 936 | + link_freq_index = imx258->cur_mode->link_freq_index; | |
| 937 | + reg_list = &link_freq_configs[link_freq_index].reg_list; | |
| 938 | + ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | |
| 939 | + if (ret) { | |
| 940 | + dev_err(&client->dev, "%s failed to set plls\n", __func__); | |
| 941 | + return ret; | |
| 942 | + } | |
| 943 | + | |
| 944 | + /* Apply default values of current mode */ | |
| 945 | + reg_list = &imx258->cur_mode->reg_list; | |
| 946 | + ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | |
| 947 | + if (ret) { | |
| 948 | + dev_err(&client->dev, "%s failed to set mode\n", __func__); | |
| 949 | + return ret; | |
| 950 | + } | |
| 951 | + | |
| 952 | + /* Set Orientation be 180 degree */ | |
| 953 | + ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, | |
| 954 | + IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP); | |
| 955 | + if (ret) { | |
| 956 | + dev_err(&client->dev, "%s failed to set orientation\n", | |
| 957 | + __func__); | |
| 958 | + return ret; | |
| 959 | + } | |
| 960 | + | |
| 961 | + /* Apply customized values from user */ | |
| 962 | + ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler); | |
| 963 | + if (ret) | |
| 964 | + return ret; | |
| 965 | + | |
| 966 | + /* set stream on register */ | |
| 967 | + return imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | |
| 968 | + IMX258_REG_VALUE_08BIT, | |
| 969 | + IMX258_MODE_STREAMING); | |
| 970 | +} | |
| 971 | + | |
| 972 | +/* Stop streaming */ | |
| 973 | +static int imx258_stop_streaming(struct imx258 *imx258) | |
| 974 | +{ | |
| 975 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 976 | + int ret; | |
| 977 | + | |
| 978 | + /* set stream off register */ | |
| 979 | + ret = imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | |
| 980 | + IMX258_REG_VALUE_08BIT, IMX258_MODE_STANDBY); | |
| 981 | + if (ret) | |
| 982 | + dev_err(&client->dev, "%s failed to set stream\n", __func__); | |
| 983 | + | |
| 984 | + /* | |
| 985 | + * Return success even if it was an error, as there is nothing the | |
| 986 | + * caller can do about it. | |
| 987 | + */ | |
| 988 | + return 0; | |
| 989 | +} | |
| 990 | + | |
| 991 | +static int imx258_set_stream(struct v4l2_subdev *sd, int enable) | |
| 992 | +{ | |
| 993 | + struct imx258 *imx258 = to_imx258(sd); | |
| 994 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 995 | + int ret = 0; | |
| 996 | + | |
| 997 | + mutex_lock(&imx258->mutex); | |
| 998 | + if (imx258->streaming == enable) { | |
| 999 | + mutex_unlock(&imx258->mutex); | |
| 1000 | + return 0; | |
| 1001 | + } | |
| 1002 | + | |
| 1003 | + if (enable) { | |
| 1004 | + ret = pm_runtime_get_sync(&client->dev); | |
| 1005 | + if (ret < 0) { | |
| 1006 | + pm_runtime_put_noidle(&client->dev); | |
| 1007 | + goto err_unlock; | |
| 1008 | + } | |
| 1009 | + | |
| 1010 | + /* | |
| 1011 | + * Apply default & customized values | |
| 1012 | + * and then start streaming. | |
| 1013 | + */ | |
| 1014 | + ret = imx258_start_streaming(imx258); | |
| 1015 | + if (ret) | |
| 1016 | + goto err_rpm_put; | |
| 1017 | + } else { | |
| 1018 | + imx258_stop_streaming(imx258); | |
| 1019 | + pm_runtime_put(&client->dev); | |
| 1020 | + } | |
| 1021 | + | |
| 1022 | + imx258->streaming = enable; | |
| 1023 | + mutex_unlock(&imx258->mutex); | |
| 1024 | + | |
| 1025 | + return ret; | |
| 1026 | + | |
| 1027 | +err_rpm_put: | |
| 1028 | + pm_runtime_put(&client->dev); | |
| 1029 | +err_unlock: | |
| 1030 | + mutex_unlock(&imx258->mutex); | |
| 1031 | + | |
| 1032 | + return ret; | |
| 1033 | +} | |
| 1034 | + | |
| 1035 | +static int __maybe_unused imx258_suspend(struct device *dev) | |
| 1036 | +{ | |
| 1037 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1038 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1039 | + struct imx258 *imx258 = to_imx258(sd); | |
| 1040 | + | |
| 1041 | + if (imx258->streaming) | |
| 1042 | + imx258_stop_streaming(imx258); | |
| 1043 | + | |
| 1044 | + return 0; | |
| 1045 | +} | |
| 1046 | + | |
| 1047 | +static int __maybe_unused imx258_resume(struct device *dev) | |
| 1048 | +{ | |
| 1049 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1050 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1051 | + struct imx258 *imx258 = to_imx258(sd); | |
| 1052 | + int ret; | |
| 1053 | + | |
| 1054 | + if (imx258->streaming) { | |
| 1055 | + ret = imx258_start_streaming(imx258); | |
| 1056 | + if (ret) | |
| 1057 | + goto error; | |
| 1058 | + } | |
| 1059 | + | |
| 1060 | + return 0; | |
| 1061 | + | |
| 1062 | +error: | |
| 1063 | + imx258_stop_streaming(imx258); | |
| 1064 | + imx258->streaming = 0; | |
| 1065 | + return ret; | |
| 1066 | +} | |
| 1067 | + | |
| 1068 | +/* Verify chip ID */ | |
| 1069 | +static int imx258_identify_module(struct imx258 *imx258) | |
| 1070 | +{ | |
| 1071 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 1072 | + int ret; | |
| 1073 | + u32 val; | |
| 1074 | + | |
| 1075 | + ret = imx258_read_reg(imx258, IMX258_REG_CHIP_ID, | |
| 1076 | + IMX258_REG_VALUE_16BIT, &val); | |
| 1077 | + if (ret) { | |
| 1078 | + dev_err(&client->dev, "failed to read chip id %x\n", | |
| 1079 | + IMX258_CHIP_ID); | |
| 1080 | + return ret; | |
| 1081 | + } | |
| 1082 | + | |
| 1083 | + if (val != IMX258_CHIP_ID) { | |
| 1084 | + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", | |
| 1085 | + IMX258_CHIP_ID, val); | |
| 1086 | + return -EIO; | |
| 1087 | + } | |
| 1088 | + | |
| 1089 | + return 0; | |
| 1090 | +} | |
| 1091 | + | |
| 1092 | +static const struct v4l2_subdev_video_ops imx258_video_ops = { | |
| 1093 | + .s_stream = imx258_set_stream, | |
| 1094 | +}; | |
| 1095 | + | |
| 1096 | +static const struct v4l2_subdev_pad_ops imx258_pad_ops = { | |
| 1097 | + .enum_mbus_code = imx258_enum_mbus_code, | |
| 1098 | + .get_fmt = imx258_get_pad_format, | |
| 1099 | + .set_fmt = imx258_set_pad_format, | |
| 1100 | + .enum_frame_size = imx258_enum_frame_size, | |
| 1101 | +}; | |
| 1102 | + | |
| 1103 | +static const struct v4l2_subdev_ops imx258_subdev_ops = { | |
| 1104 | + .video = &imx258_video_ops, | |
| 1105 | + .pad = &imx258_pad_ops, | |
| 1106 | +}; | |
| 1107 | + | |
| 1108 | +static const struct v4l2_subdev_internal_ops imx258_internal_ops = { | |
| 1109 | + .open = imx258_open, | |
| 1110 | +}; | |
| 1111 | + | |
| 1112 | +/* Initialize control handlers */ | |
| 1113 | +static int imx258_init_controls(struct imx258 *imx258) | |
| 1114 | +{ | |
| 1115 | + struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 1116 | + struct v4l2_ctrl_handler *ctrl_hdlr; | |
| 1117 | + s64 vblank_def; | |
| 1118 | + s64 vblank_min; | |
| 1119 | + s64 pixel_rate_min; | |
| 1120 | + s64 pixel_rate_max; | |
| 1121 | + int ret; | |
| 1122 | + | |
| 1123 | + ctrl_hdlr = &imx258->ctrl_handler; | |
| 1124 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); | |
| 1125 | + if (ret) | |
| 1126 | + return ret; | |
| 1127 | + | |
| 1128 | + mutex_init(&imx258->mutex); | |
| 1129 | + ctrl_hdlr->lock = &imx258->mutex; | |
| 1130 | + imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, | |
| 1131 | + &imx258_ctrl_ops, | |
| 1132 | + V4L2_CID_LINK_FREQ, | |
| 1133 | + ARRAY_SIZE(link_freq_menu_items) - 1, | |
| 1134 | + 0, | |
| 1135 | + link_freq_menu_items); | |
| 1136 | + | |
| 1137 | + if (imx258->link_freq) | |
| 1138 | + imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1139 | + | |
| 1140 | + pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); | |
| 1141 | + pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]); | |
| 1142 | + /* By default, PIXEL_RATE is read only */ | |
| 1143 | + imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1144 | + V4L2_CID_PIXEL_RATE, | |
| 1145 | + pixel_rate_min, pixel_rate_max, | |
| 1146 | + 1, pixel_rate_max); | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height; | |
| 1150 | + vblank_min = imx258->cur_mode->vts_min - imx258->cur_mode->height; | |
| 1151 | + imx258->vblank = v4l2_ctrl_new_std( | |
| 1152 | + ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_VBLANK, | |
| 1153 | + vblank_min, | |
| 1154 | + IMX258_VTS_MAX - imx258->cur_mode->height, 1, | |
| 1155 | + vblank_def); | |
| 1156 | + | |
| 1157 | + if (imx258->vblank) | |
| 1158 | + imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1159 | + | |
| 1160 | + imx258->hblank = v4l2_ctrl_new_std( | |
| 1161 | + ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK, | |
| 1162 | + IMX258_PPL_DEFAULT - imx258->cur_mode->width, | |
| 1163 | + IMX258_PPL_DEFAULT - imx258->cur_mode->width, | |
| 1164 | + 1, | |
| 1165 | + IMX258_PPL_DEFAULT - imx258->cur_mode->width); | |
| 1166 | + | |
| 1167 | + if (imx258->hblank) | |
| 1168 | + imx258->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1169 | + | |
| 1170 | + imx258->exposure = v4l2_ctrl_new_std( | |
| 1171 | + ctrl_hdlr, &imx258_ctrl_ops, | |
| 1172 | + V4L2_CID_EXPOSURE, IMX258_EXPOSURE_MIN, | |
| 1173 | + IMX258_EXPOSURE_MAX, IMX258_EXPOSURE_STEP, | |
| 1174 | + IMX258_EXPOSURE_DEFAULT); | |
| 1175 | + | |
| 1176 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, | |
| 1177 | + IMX258_ANA_GAIN_MIN, IMX258_ANA_GAIN_MAX, | |
| 1178 | + IMX258_ANA_GAIN_STEP, IMX258_ANA_GAIN_DEFAULT); | |
| 1179 | + | |
| 1180 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_DIGITAL_GAIN, | |
| 1181 | + IMX258_DGTL_GAIN_MIN, IMX258_DGTL_GAIN_MAX, | |
| 1182 | + IMX258_DGTL_GAIN_STEP, | |
| 1183 | + IMX258_DGTL_GAIN_DEFAULT); | |
| 1184 | + | |
| 1185 | + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1186 | + V4L2_CID_TEST_PATTERN, | |
| 1187 | + ARRAY_SIZE(imx258_test_pattern_menu) - 1, | |
| 1188 | + 0, 0, imx258_test_pattern_menu); | |
| 1189 | + | |
| 1190 | + if (ctrl_hdlr->error) { | |
| 1191 | + ret = ctrl_hdlr->error; | |
| 1192 | + dev_err(&client->dev, "%s control init failed (%d)\n", | |
| 1193 | + __func__, ret); | |
| 1194 | + goto error; | |
| 1195 | + } | |
| 1196 | + | |
| 1197 | + imx258->sd.ctrl_handler = ctrl_hdlr; | |
| 1198 | + | |
| 1199 | + return 0; | |
| 1200 | + | |
| 1201 | +error: | |
| 1202 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1203 | + mutex_destroy(&imx258->mutex); | |
| 1204 | + | |
| 1205 | + return ret; | |
| 1206 | +} | |
| 1207 | + | |
| 1208 | +static void imx258_free_controls(struct imx258 *imx258) | |
| 1209 | +{ | |
| 1210 | + v4l2_ctrl_handler_free(imx258->sd.ctrl_handler); | |
| 1211 | + mutex_destroy(&imx258->mutex); | |
| 1212 | +} | |
| 1213 | + | |
| 1214 | +static int imx258_probe(struct i2c_client *client) | |
| 1215 | +{ | |
| 1216 | + struct imx258 *imx258; | |
| 1217 | + int ret; | |
| 1218 | + u32 val = 0; | |
| 1219 | + | |
| 1220 | + device_property_read_u32(&client->dev, "clock-frequency", &val); | |
| 1221 | + if (val != 19200000) | |
| 1222 | + return -EINVAL; | |
| 1223 | + | |
| 1224 | + imx258 = devm_kzalloc(&client->dev, sizeof(*imx258), GFP_KERNEL); | |
| 1225 | + if (!imx258) | |
| 1226 | + return -ENOMEM; | |
| 1227 | + | |
| 1228 | + /* Initialize subdev */ | |
| 1229 | + v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); | |
| 1230 | + | |
| 1231 | + /* Check module identity */ | |
| 1232 | + ret = imx258_identify_module(imx258); | |
| 1233 | + if (ret) | |
| 1234 | + return ret; | |
| 1235 | + | |
| 1236 | + /* Set default mode to max resolution */ | |
| 1237 | + imx258->cur_mode = &supported_modes[0]; | |
| 1238 | + | |
| 1239 | + ret = imx258_init_controls(imx258); | |
| 1240 | + if (ret) | |
| 1241 | + return ret; | |
| 1242 | + | |
| 1243 | + /* Initialize subdev */ | |
| 1244 | + imx258->sd.internal_ops = &imx258_internal_ops; | |
| 1245 | + imx258->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1246 | + imx258->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1247 | + | |
| 1248 | + /* Initialize source pad */ | |
| 1249 | + imx258->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1250 | + | |
| 1251 | + ret = media_entity_pads_init(&imx258->sd.entity, 1, &imx258->pad); | |
| 1252 | + if (ret) | |
| 1253 | + goto error_handler_free; | |
| 1254 | + | |
| 1255 | + ret = v4l2_async_register_subdev_sensor_common(&imx258->sd); | |
| 1256 | + if (ret < 0) | |
| 1257 | + goto error_media_entity; | |
| 1258 | + | |
| 1259 | + pm_runtime_set_active(&client->dev); | |
| 1260 | + pm_runtime_enable(&client->dev); | |
| 1261 | + pm_runtime_idle(&client->dev); | |
| 1262 | + | |
| 1263 | + return 0; | |
| 1264 | + | |
| 1265 | +error_media_entity: | |
| 1266 | + media_entity_cleanup(&imx258->sd.entity); | |
| 1267 | + | |
| 1268 | +error_handler_free: | |
| 1269 | + imx258_free_controls(imx258); | |
| 1270 | + | |
| 1271 | + return ret; | |
| 1272 | +} | |
| 1273 | + | |
| 1274 | +static int imx258_remove(struct i2c_client *client) | |
| 1275 | +{ | |
| 1276 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1277 | + struct imx258 *imx258 = to_imx258(sd); | |
| 1278 | + | |
| 1279 | + v4l2_async_unregister_subdev(sd); | |
| 1280 | + media_entity_cleanup(&sd->entity); | |
| 1281 | + imx258_free_controls(imx258); | |
| 1282 | + | |
| 1283 | + pm_runtime_disable(&client->dev); | |
| 1284 | + pm_runtime_set_suspended(&client->dev); | |
| 1285 | + | |
| 1286 | + return 0; | |
| 1287 | +} | |
| 1288 | + | |
| 1289 | +static const struct dev_pm_ops imx258_pm_ops = { | |
| 1290 | + SET_SYSTEM_SLEEP_PM_OPS(imx258_suspend, imx258_resume) | |
| 1291 | +}; | |
| 1292 | + | |
| 1293 | +#ifdef CONFIG_ACPI | |
| 1294 | +static const struct acpi_device_id imx258_acpi_ids[] = { | |
| 1295 | + { "SONY258A" }, | |
| 1296 | + { /* sentinel */ } | |
| 1297 | +}; | |
| 1298 | + | |
| 1299 | +MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids); | |
| 1300 | +#endif | |
| 1301 | + | |
| 1302 | +static struct i2c_driver imx258_i2c_driver = { | |
| 1303 | + .driver = { | |
| 1304 | + .name = "imx258", | |
| 1305 | + .pm = &imx258_pm_ops, | |
| 1306 | + .acpi_match_table = ACPI_PTR(imx258_acpi_ids), | |
| 1307 | + }, | |
| 1308 | + .probe_new = imx258_probe, | |
| 1309 | + .remove = imx258_remove, | |
| 1310 | +}; | |
| 1311 | + | |
| 1312 | +module_i2c_driver(imx258_i2c_driver); | |
| 1313 | + | |
| 1314 | +MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>"); | |
| 1315 | +MODULE_AUTHOR("Chiang, Alan <alanx.chiang@intel.com>"); | |
| 1316 | +MODULE_AUTHOR("Chen, Jason <jasonx.z.chen@intel.com>"); | |
| 1317 | +MODULE_DESCRIPTION("Sony IMX258 sensor driver"); | |
| 1318 | +MODULE_LICENSE("GPL v2"); | |
| @@ -87,7 +87,7 @@ · 86 unmodified lines | ||
| 87 | 87 | #define IMX274_SHR_LIMIT_CONST (4) |
| 88 | 88 | |
| 89 | 89 | /* |
| 90 | − * Constants for sensor reset delay | |
| 90 | + * Min and max sensor reset delay (microseconds) | |
| 91 | 91 | */ |
| 92 | 92 | #define IMX274_RESET_DELAY1 (2000) |
| 93 | 93 | #define IMX274_RESET_DELAY2 (2200) |
| @@ -107,15 +107,15 @@ · 13 unmodified lines | ||
| 107 | 107 | /* |
| 108 | 108 | * IMX274 register definitions |
| 109 | 109 | */ |
| 110 | −#define IMX274_FRAME_LENGTH_ADDR_1 0x30FA /* VMAX, MSB */ | |
| 111 | −#define IMX274_FRAME_LENGTH_ADDR_2 0x30F9 /* VMAX */ | |
| 112 | −#define IMX274_FRAME_LENGTH_ADDR_3 0x30F8 /* VMAX, LSB */ | |
| 110 | +#define IMX274_SHR_REG_MSB 0x300D /* SHR */ | |
| 111 | +#define IMX274_SHR_REG_LSB 0x300C /* SHR */ | |
| 113 | 112 | #define IMX274_SVR_REG_MSB 0x300F /* SVR */ |
| 114 | 113 | #define IMX274_SVR_REG_LSB 0x300E /* SVR */ |
| 114 | +#define IMX274_VMAX_REG_1 0x30FA /* VMAX, MSB */ | |
| 115 | +#define IMX274_VMAX_REG_2 0x30F9 /* VMAX */ | |
| 116 | +#define IMX274_VMAX_REG_3 0x30F8 /* VMAX, LSB */ | |
| 115 | 117 | #define IMX274_HMAX_REG_MSB 0x30F7 /* HMAX */ |
| 116 | 118 | #define IMX274_HMAX_REG_LSB 0x30F6 /* HMAX */ |
| 117 | −#define IMX274_COARSE_TIME_ADDR_MSB 0x300D /* SHR */ | |
| 118 | −#define IMX274_COARSE_TIME_ADDR_LSB 0x300C /* SHR */ | |
| 119 | 119 | #define IMX274_ANALOG_GAIN_ADDR_LSB 0x300A /* ANALOG GAIN LSB */ |
| 120 | 120 | #define IMX274_ANALOG_GAIN_ADDR_MSB 0x300B /* ANALOG GAIN MSB */ |
| 121 | 121 | #define IMX274_DIGITAL_GAIN_REG 0x3012 /* Digital Gain */ |
| @@ -144,22 +144,13 @@ enum imx274_mode { · 22 unmodified lines | ||
| 144 | 144 | IMX274_MODE_3840X2160, |
| 145 | 145 | IMX274_MODE_1920X1080, |
| 146 | 146 | IMX274_MODE_1280X720, |
| 147 | − | |
| 148 | − IMX274_MODE_START_STREAM_1, | |
| 149 | − IMX274_MODE_START_STREAM_2, | |
| 150 | − IMX274_MODE_START_STREAM_3, | |
| 151 | − IMX274_MODE_START_STREAM_4, | |
| 152 | − IMX274_MODE_STOP_STREAM | |
| 153 | 147 | }; |
| 154 | 148 | |
| 155 | 149 | /* |
| 156 | 150 | * imx274 format related structure |
| 157 | 151 | */ |
| 158 | 152 | struct imx274_frmfmt { |
| 159 | − u32 mbus_code; | |
| 160 | − enum v4l2_colorspace colorspace; | |
| 161 | 153 | struct v4l2_frmsize_discrete size; |
| 162 | − enum imx274_mode mode; | |
| 163 | 154 | }; |
| 164 | 155 | |
| 165 | 156 | /* |
| @@ -489,24 +480,15 @@ static const struct reg_8 *mode_table[] = { · 323 unmodified lines | ||
| 489 | 480 | [IMX274_MODE_3840X2160] = imx274_mode1_3840x2160_raw10, |
| 490 | 481 | [IMX274_MODE_1920X1080] = imx274_mode3_1920x1080_raw10, |
| 491 | 482 | [IMX274_MODE_1280X720] = imx274_mode5_1280x720_raw10, |
| 492 | − | |
| 493 | − [IMX274_MODE_START_STREAM_1] = imx274_start_1, | |
| 494 | − [IMX274_MODE_START_STREAM_2] = imx274_start_2, | |
| 495 | − [IMX274_MODE_START_STREAM_3] = imx274_start_3, | |
| 496 | − [IMX274_MODE_START_STREAM_4] = imx274_start_4, | |
| 497 | − [IMX274_MODE_STOP_STREAM] = imx274_stop, | |
| 498 | 483 | }; |
| 499 | 484 | |
| 500 | 485 | /* |
| 501 | 486 | * imx274 format related structure |
| 502 | 487 | */ |
| 503 | 488 | static const struct imx274_frmfmt imx274_formats[] = { |
| 504 | − {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {3840, 2160}, | |
| 505 | − IMX274_MODE_3840X2160}, | |
| 506 | − {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1920, 1080}, | |
| 507 | − IMX274_MODE_1920X1080}, | |
| 508 | − {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1280, 720}, | |
| 509 | − IMX274_MODE_1280X720}, | |
| 489 | + { {3840, 2160} }, | |
| 490 | + { {1920, 1080} }, | |
| 491 | + { {1280, 720} }, | |
| 510 | 492 | }; |
| 511 | 493 | |
| 512 | 494 | /* |
| @@ -737,11 +719,11 @@ static int imx274_mode_regs(struct stimx274 *priv, int mode) · 224 unmodified lines | ||
| 737 | 719 | { |
| 738 | 720 | int err = 0; |
| 739 | 721 | |
| 740 | − err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_1]); | |
| 722 | + err = imx274_write_table(priv, imx274_start_1); | |
| 741 | 723 | if (err) |
| 742 | 724 | return err; |
| 743 | 725 | |
| 744 | − err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_2]); | |
| 726 | + err = imx274_write_table(priv, imx274_start_2); | |
| 745 | 727 | if (err) |
| 746 | 728 | return err; |
| 747 | 729 | |
| @@ -766,7 +748,7 @@ static int imx274_start_stream(struct stimx274 *priv) · 18 unmodified lines | ||
| 766 | 748 | * give it 1 extra ms for margin |
| 767 | 749 | */ |
| 768 | 750 | msleep_range(11); |
| 769 | − err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_3]); | |
| 751 | + err = imx274_write_table(priv, imx274_start_3); | |
| 770 | 752 | if (err) |
| 771 | 753 | return err; |
| 772 | 754 | |
| @@ -776,7 +758,7 @@ static int imx274_start_stream(struct stimx274 *priv) · 3 unmodified lines | ||
| 776 | 758 | * give it 1 extra ms for margin |
| 777 | 759 | */ |
| 778 | 760 | msleep_range(8); |
| 779 | − err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_4]); | |
| 761 | + err = imx274_write_table(priv, imx274_start_4); | |
| 780 | 762 | if (err) |
| 781 | 763 | return err; |
| 782 | 764 | |
| @@ -890,9 +872,8 @@ static int imx274_set_fmt(struct v4l2_subdev *sd, · 107 unmodified lines | ||
| 890 | 872 | int index; |
| 891 | 873 | |
| 892 | 874 | dev_dbg(&client->dev, |
| 893 | − "%s: width = %d height = %d code = %d mbus_code = %d\n", | |
| 894 | − __func__, fmt->width, fmt->height, fmt->code, | |
| 895 | − imx274_formats[imx274->mode_index].mbus_code); | |
| 875 | + "%s: width = %d height = %d code = %d\n", | |
| 876 | + __func__, fmt->width, fmt->height, fmt->code); | |
| 896 | 877 | |
| 897 | 878 | mutex_lock(&imx274->lock); |
| 898 | 879 | |
| @@ -971,7 +952,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd, · 72 unmodified lines | ||
| 971 | 952 | if (!ret) { |
| 972 | 953 | /* |
| 973 | 954 | * exposure time range is decided by frame interval |
| 974 | − * need to update it after frame interal changes | |
| 955 | + * need to update it after frame interval changes | |
| 975 | 956 | */ |
| 976 | 957 | min = IMX274_MIN_EXPOSURE_TIME; |
| 977 | 958 | max = fi->interval.numerator * 1000000 |
| @@ -984,7 +965,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd, · 6 unmodified lines | ||
| 984 | 965 | } |
| 985 | 966 | |
| 986 | 967 | /* update exposure time accordingly */ |
| 987 | − imx274_set_exposure(imx274, imx274->ctrls.exposure->val); | |
| 968 | + imx274_set_exposure(imx274, ctrl->val); | |
| 988 | 969 | |
| 989 | 970 | dev_dbg(&imx274->client->dev, "set frame interval to %uus\n", |
| 990 | 971 | fi->interval.numerator * 1000000 |
| @@ -1088,8 +1069,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) · 97 unmodified lines | ||
| 1088 | 1069 | goto fail; |
| 1089 | 1070 | } else { |
| 1090 | 1071 | /* stop stream */ |
| 1091 | − ret = imx274_write_table(imx274, | |
| 1092 | − mode_table[IMX274_MODE_STOP_STREAM]); | |
| 1072 | + ret = imx274_write_table(imx274, imx274_stop); | |
| 1093 | 1073 | if (ret) |
| 1094 | 1074 | goto fail; |
| 1095 | 1075 | } |
| @@ -1133,15 +1113,15 @@ static int imx274_get_frame_length(struct stimx274 *priv, u32 *val) · 37 unmodified lines | ||
| 1133 | 1113 | svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; |
| 1134 | 1114 | |
| 1135 | 1115 | /* vmax */ |
| 1136 | − err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_3, ®_val[0]); | |
| 1116 | + err = imx274_read_reg(priv, IMX274_VMAX_REG_3, ®_val[0]); | |
| 1137 | 1117 | if (err) |
| 1138 | 1118 | goto fail; |
| 1139 | 1119 | |
| 1140 | − err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_2, ®_val[1]); | |
| 1120 | + err = imx274_read_reg(priv, IMX274_VMAX_REG_2, ®_val[1]); | |
| 1141 | 1121 | if (err) |
| 1142 | 1122 | goto fail; |
| 1143 | 1123 | |
| 1144 | − err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_1, ®_val[2]); | |
| 1124 | + err = imx274_read_reg(priv, IMX274_VMAX_REG_1, ®_val[2]); | |
| 1145 | 1125 | if (err) |
| 1146 | 1126 | goto fail; |
| 1147 | 1127 | |
| @@ -1300,10 +1280,10 @@ fail: · 152 unmodified lines | ||
| 1300 | 1280 | static inline void imx274_calculate_coarse_time_regs(struct reg_8 regs[2], |
| 1301 | 1281 | u32 coarse_time) |
| 1302 | 1282 | { |
| 1303 | − regs->addr = IMX274_COARSE_TIME_ADDR_MSB; | |
| 1283 | + regs->addr = IMX274_SHR_REG_MSB; | |
| 1304 | 1284 | regs->val = (coarse_time >> IMX274_SHIFT_8_BITS) |
| 1305 | 1285 | & IMX274_MASK_LSB_8_BITS; |
| 1306 | − (regs + 1)->addr = IMX274_COARSE_TIME_ADDR_LSB; | |
| 1286 | + (regs + 1)->addr = IMX274_SHR_REG_LSB; | |
| 1307 | 1287 | (regs + 1)->val = (coarse_time) & IMX274_MASK_LSB_8_BITS; |
| 1308 | 1288 | } |
| 1309 | 1289 | |
| @@ -1471,13 +1451,13 @@ static int imx274_set_test_pattern(struct stimx274 *priv, int val) · 161 unmodified lines | ||
| 1471 | 1451 | static inline void imx274_calculate_frame_length_regs(struct reg_8 regs[3], |
| 1472 | 1452 | u32 frame_length) |
| 1473 | 1453 | { |
| 1474 | − regs->addr = IMX274_FRAME_LENGTH_ADDR_1; | |
| 1454 | + regs->addr = IMX274_VMAX_REG_1; | |
| 1475 | 1455 | regs->val = (frame_length >> IMX274_SHIFT_16_BITS) |
| 1476 | 1456 | & IMX274_MASK_LSB_4_BITS; |
| 1477 | − (regs + 1)->addr = IMX274_FRAME_LENGTH_ADDR_2; | |
| 1457 | + (regs + 1)->addr = IMX274_VMAX_REG_2; | |
| 1478 | 1458 | (regs + 1)->val = (frame_length >> IMX274_SHIFT_8_BITS) |
| 1479 | 1459 | & IMX274_MASK_LSB_8_BITS; |
| 1480 | − (regs + 2)->addr = IMX274_FRAME_LENGTH_ADDR_3; | |
| 1460 | + (regs + 2)->addr = IMX274_VMAX_REG_3; | |
| 1481 | 1461 | (regs + 2)->val = (frame_length) & IMX274_MASK_LSB_8_BITS; |
| 1482 | 1462 | } |
| 1483 | 1463 | |
| @@ -1786,7 +1766,7 @@ static int imx274_remove(struct i2c_client *client) · 302 unmodified lines | ||
| 1786 | 1766 | struct stimx274 *imx274 = to_imx274(sd); |
| 1787 | 1767 | |
| 1788 | 1768 | /* stop stream */ |
| 1789 | − imx274_write_table(imx274, mode_table[IMX274_MODE_STOP_STREAM]); | |
| 1769 | + imx274_write_table(imx274, imx274_stop); | |
| 1790 | 1770 | |
| 1791 | 1771 | v4l2_async_unregister_subdev(sd); |
| 1792 | 1772 | v4l2_ctrl_handler_free(&imx274->ctrls.handler); |
| @@ -739,6 +739,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) · 738 unmodified lines | ||
| 739 | 739 | struct rc_dev *rc = NULL; |
| 740 | 740 | struct i2c_adapter *adap = client->adapter; |
| 741 | 741 | unsigned short addr = client->addr; |
| 742 | + bool probe_tx = (id->driver_data & FLAG_TX) != 0; | |
| 742 | 743 | int err; |
| 743 | 744 | |
| 744 | 745 | if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) { |
| @@ -800,6 +801,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) · 55 unmodified lines | ||
| 800 | 801 | rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | |
| 801 | 802 | RC_PROTO_BIT_RC6_6A_32; |
| 802 | 803 | ir_codes = RC_MAP_HAUPPAUGE; |
| 804 | + probe_tx = true; | |
| 803 | 805 | break; |
| 804 | 806 | } |
| 805 | 807 | |
| @@ -892,7 +894,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) · 86 unmodified lines | ||
| 892 | 894 | |
| 893 | 895 | INIT_DELAYED_WORK(&ir->work, ir_work); |
| 894 | 896 | |
| 895 | − if (id->driver_data & FLAG_TX) { | |
| 897 | + if (probe_tx) { | |
| 896 | 898 | ir->tx_c = i2c_new_dummy(client->adapter, 0x70); |
| 897 | 899 | if (!ir->tx_c) { |
| 898 | 900 | dev_err(&client->dev, "failed to setup tx i2c address"); |
| @@ -1796,7 +1796,6 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); · 1795 unmodified lines | ||
| 1796 | 1796 | static struct i2c_driver ov13858_i2c_driver = { |
| 1797 | 1797 | .driver = { |
| 1798 | 1798 | .name = "ov13858", |
| 1799 | − .owner = THIS_MODULE, | |
| 1800 | 1799 | .pm = &ov13858_pm_ops, |
| 1801 | 1800 | .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), |
| 1802 | 1801 | }, |
| @@ -307,6 +307,10 @@ struct ov2640_priv { · 306 unmodified lines | ||
| 307 | 307 | |
| 308 | 308 | struct gpio_desc *resetb_gpio; |
| 309 | 309 | struct gpio_desc *pwdn_gpio; |
| 310 | + | |
| 311 | + struct mutex lock; /* lock to protect streaming and power_count */ | |
| 312 | + bool streaming; | |
| 313 | + int power_count; | |
| 310 | 314 | }; |
| 311 | 315 | |
| 312 | 316 | /* |
| @@ -709,9 +713,20 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) · 396 unmodified lines | ||
| 709 | 713 | struct v4l2_subdev *sd = |
| 710 | 714 | &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; |
| 711 | 715 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 716 | + struct ov2640_priv *priv = to_ov2640(client); | |
| 712 | 717 | u8 val; |
| 713 | 718 | int ret; |
| 714 | 719 | |
| 720 | + /* v4l2_ctrl_lock() locks our own mutex */ | |
| 721 | + | |
| 722 | + /* | |
| 723 | + * If the device is not powered up by the host driver, do not apply any | |
| 724 | + * controls to H/W at this time. Instead the controls will be restored | |
| 725 | + * when the streaming is started. | |
| 726 | + */ | |
| 727 | + if (!priv->power_count) | |
| 728 | + return 0; | |
| 729 | + | |
| 715 | 730 | ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); |
| 716 | 731 | if (ret < 0) |
| 717 | 732 | return ret; |
| @@ -763,12 +778,9 @@ static int ov2640_s_register(struct v4l2_subdev *sd, · 45 unmodified lines | ||
| 763 | 778 | } |
| 764 | 779 | #endif |
| 765 | 780 | |
| 766 | −static int ov2640_s_power(struct v4l2_subdev *sd, int on) | |
| 781 | +static void ov2640_set_power(struct ov2640_priv *priv, int on) | |
| 767 | 782 | { |
| 768 | 783 | #ifdef CONFIG_GPIOLIB |
| 769 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 770 | − struct ov2640_priv *priv = to_ov2640(client); | |
| 771 | − | |
| 772 | 784 | if (priv->pwdn_gpio) |
| 773 | 785 | gpiod_direction_output(priv->pwdn_gpio, !on); |
| 774 | 786 | if (on && priv->resetb_gpio) { |
| @@ -778,6 +790,25 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on) · 3 unmodified lines | ||
| 778 | 790 | gpiod_set_value(priv->resetb_gpio, 0); |
| 779 | 791 | } |
| 780 | 792 | #endif |
| 793 | +} | |
| 794 | + | |
| 795 | +static int ov2640_s_power(struct v4l2_subdev *sd, int on) | |
| 796 | +{ | |
| 797 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 798 | + struct ov2640_priv *priv = to_ov2640(client); | |
| 799 | + | |
| 800 | + mutex_lock(&priv->lock); | |
| 801 | + | |
| 802 | + /* | |
| 803 | + * If the power count is modified from 0 to != 0 or from != 0 to 0, | |
| 804 | + * update the power state. | |
| 805 | + */ | |
| 806 | + if (priv->power_count == !on) | |
| 807 | + ov2640_set_power(priv, on); | |
| 808 | + priv->power_count += on ? 1 : -1; | |
| 809 | + WARN_ON(priv->power_count < 0); | |
| 810 | + mutex_unlock(&priv->lock); | |
| 811 | + | |
| 781 | 812 | return 0; |
| 782 | 813 | } |
| 783 | 814 | |
| @@ -798,16 +829,13 @@ static const struct ov2640_win_size *ov2640_select_win(u32 width, u32 height) · 14 unmodified lines | ||
| 798 | 829 | static int ov2640_set_params(struct i2c_client *client, |
| 799 | 830 | const struct ov2640_win_size *win, u32 code) |
| 800 | 831 | { |
| 801 | − struct ov2640_priv *priv = to_ov2640(client); | |
| 802 | 832 | const struct regval_list *selected_cfmt_regs; |
| 803 | 833 | u8 val; |
| 804 | 834 | int ret; |
| 805 | 835 | |
| 806 | − /* select win */ | |
| 807 | − priv->win = win; | |
| 836 | + if (!win) | |
| 837 | + return -EINVAL; | |
| 808 | 838 | |
| 809 | − /* select format */ | |
| 810 | − priv->cfmt_code = 0; | |
| 811 | 839 | switch (code) { |
| 812 | 840 | case MEDIA_BUS_FMT_RGB565_2X8_BE: |
| 813 | 841 | dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); |
| @@ -846,13 +874,13 @@ static int ov2640_set_params(struct i2c_client *client, · 32 unmodified lines | ||
| 846 | 874 | goto err; |
| 847 | 875 | |
| 848 | 876 | /* select preamble */ |
| 849 | − dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name); | |
| 877 | + dev_dbg(&client->dev, "%s: Set size to %s", __func__, win->name); | |
| 850 | 878 | ret = ov2640_write_array(client, ov2640_size_change_preamble_regs); |
| 851 | 879 | if (ret < 0) |
| 852 | 880 | goto err; |
| 853 | 881 | |
| 854 | 882 | /* set size win */ |
| 855 | − ret = ov2640_write_array(client, priv->win->regs); | |
| 883 | + ret = ov2640_write_array(client, win->regs); | |
| 856 | 884 | if (ret < 0) |
| 857 | 885 | goto err; |
| 858 | 886 | |
| @@ -872,14 +900,11 @@ static int ov2640_set_params(struct i2c_client *client, · 13 unmodified lines | ||
| 872 | 900 | if (ret < 0) |
| 873 | 901 | goto err; |
| 874 | 902 | |
| 875 | − priv->cfmt_code = code; | |
| 876 | − | |
| 877 | 903 | return 0; |
| 878 | 904 | |
| 879 | 905 | err: |
| 880 | 906 | dev_err(&client->dev, "%s: Error %d", __func__, ret); |
| 881 | 907 | ov2640_reset(client); |
| 882 | − priv->win = NULL; | |
| 883 | 908 | |
| 884 | 909 | return ret; |
| 885 | 910 | } |
| @@ -915,11 +940,15 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, · 29 unmodified lines | ||
| 915 | 940 | { |
| 916 | 941 | struct v4l2_mbus_framefmt *mf = &format->format; |
| 917 | 942 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 943 | + struct ov2640_priv *priv = to_ov2640(client); | |
| 918 | 944 | const struct ov2640_win_size *win; |
| 945 | + int ret = 0; | |
| 919 | 946 | |
| 920 | 947 | if (format->pad) |
| 921 | 948 | return -EINVAL; |
| 922 | 949 | |
| 950 | + mutex_lock(&priv->lock); | |
| 951 | + | |
| 923 | 952 | /* select suitable win */ |
| 924 | 953 | win = ov2640_select_win(mf->width, mf->height); |
| 925 | 954 | mf->width = win->width; |
| @@ -941,10 +970,24 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, · 15 unmodified lines | ||
| 941 | 970 | break; |
| 942 | 971 | } |
| 943 | 972 | |
| 944 | − if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 945 | − return ov2640_set_params(client, win, mf->code); | |
| 946 | − cfg->try_fmt = *mf; | |
| 947 | − return 0; | |
| 973 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 974 | + struct ov2640_priv *priv = to_ov2640(client); | |
| 975 | + | |
| 976 | + if (priv->streaming) { | |
| 977 | + ret = -EBUSY; | |
| 978 | + goto out; | |
| 979 | + } | |
| 980 | + /* select win */ | |
| 981 | + priv->win = win; | |
| 982 | + /* select format */ | |
| 983 | + priv->cfmt_code = mf->code; | |
| 984 | + } else { | |
| 985 | + cfg->try_fmt = *mf; | |
| 986 | + } | |
| 987 | +out: | |
| 988 | + mutex_unlock(&priv->lock); | |
| 989 | + | |
| 990 | + return ret; | |
| 948 | 991 | } |
| 949 | 992 | |
| 950 | 993 | static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, |
| @@ -979,6 +1022,28 @@ static int ov2640_get_selection(struct v4l2_subdev *sd, · 28 unmodified lines | ||
| 979 | 1022 | } |
| 980 | 1023 | } |
| 981 | 1024 | |
| 1025 | +static int ov2640_s_stream(struct v4l2_subdev *sd, int on) | |
| 1026 | +{ | |
| 1027 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 1028 | + struct ov2640_priv *priv = to_ov2640(client); | |
| 1029 | + int ret = 0; | |
| 1030 | + | |
| 1031 | + mutex_lock(&priv->lock); | |
| 1032 | + if (priv->streaming == !on) { | |
| 1033 | + if (on) { | |
| 1034 | + ret = ov2640_set_params(client, priv->win, | |
| 1035 | + priv->cfmt_code); | |
| 1036 | + if (!ret) | |
| 1037 | + ret = __v4l2_ctrl_handler_setup(&priv->hdl); | |
| 1038 | + } | |
| 1039 | + } | |
| 1040 | + if (!ret) | |
| 1041 | + priv->streaming = on; | |
| 1042 | + mutex_unlock(&priv->lock); | |
| 1043 | + | |
| 1044 | + return ret; | |
| 1045 | +} | |
| 1046 | + | |
| 982 | 1047 | static int ov2640_video_probe(struct i2c_client *client) |
| 983 | 1048 | { |
| 984 | 1049 | struct ov2640_priv *priv = to_ov2640(client); |
| @@ -1014,8 +1079,6 @@ static int ov2640_video_probe(struct i2c_client *client) · 29 unmodified lines | ||
| 1014 | 1079 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
| 1015 | 1080 | devname, pid, ver, midh, midl); |
| 1016 | 1081 | |
| 1017 | − ret = v4l2_ctrl_handler_setup(&priv->hdl); | |
| 1018 | − | |
| 1019 | 1082 | done: |
| 1020 | 1083 | ov2640_s_power(&priv->subdev, 0); |
| 1021 | 1084 | return ret; |
| @@ -1040,9 +1103,14 @@ static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { · 18 unmodified lines | ||
| 1040 | 1103 | .set_fmt = ov2640_set_fmt, |
| 1041 | 1104 | }; |
| 1042 | 1105 | |
| 1106 | +static const struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | |
| 1107 | + .s_stream = ov2640_s_stream, | |
| 1108 | +}; | |
| 1109 | + | |
| 1043 | 1110 | static const struct v4l2_subdev_ops ov2640_subdev_ops = { |
| 1044 | 1111 | .core = &ov2640_subdev_core_ops, |
| 1045 | 1112 | .pad = &ov2640_subdev_pad_ops, |
| 1113 | + .video = &ov2640_subdev_video_ops, | |
| 1046 | 1114 | }; |
| 1047 | 1115 | |
| 1048 | 1116 | static int ov2640_probe_dt(struct i2c_client *client, |
| @@ -1116,7 +1184,9 @@ static int ov2640_probe(struct i2c_client *client, · 67 unmodified lines | ||
| 1116 | 1184 | |
| 1117 | 1185 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); |
| 1118 | 1186 | priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
| 1187 | + mutex_init(&priv->lock); | |
| 1119 | 1188 | v4l2_ctrl_handler_init(&priv->hdl, 2); |
| 1189 | + priv->hdl.lock = &priv->lock; | |
| 1120 | 1190 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, |
| 1121 | 1191 | V4L2_CID_VFLIP, 0, 1, 1, 0); |
| 1122 | 1192 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, |
| @@ -1150,6 +1220,7 @@ err_videoprobe: · 27 unmodified lines | ||
| 1150 | 1220 | media_entity_cleanup(&priv->subdev.entity); |
| 1151 | 1221 | err_hdl: |
| 1152 | 1222 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1223 | + mutex_destroy(&priv->lock); | |
| 1153 | 1224 | err_clk: |
| 1154 | 1225 | clk_disable_unprepare(priv->clk); |
| 1155 | 1226 | return ret; |
| @@ -1161,6 +1232,7 @@ static int ov2640_remove(struct i2c_client *client) · 5 unmodified lines | ||
| 1161 | 1232 | |
| 1162 | 1233 | v4l2_async_unregister_subdev(&priv->subdev); |
| 1163 | 1234 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1235 | + mutex_destroy(&priv->lock); | |
| 1164 | 1236 | media_entity_cleanup(&priv->subdev.entity); |
| 1165 | 1237 | v4l2_device_unregister_subdev(&priv->subdev); |
| 1166 | 1238 | clk_disable_unprepare(priv->clk); |
| @@ -60,6 +60,8 @@ · 59 unmodified lines | ||
| 60 | 60 | #define OV5640_REG_AEC_PK_MANUAL 0x3503 |
| 61 | 61 | #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a |
| 62 | 62 | #define OV5640_REG_AEC_PK_VTS 0x350c |
| 63 | +#define OV5640_REG_TIMING_DVPHO 0x3808 | |
| 64 | +#define OV5640_REG_TIMING_DVPVO 0x380a | |
| 63 | 65 | #define OV5640_REG_TIMING_HTS 0x380c |
| 64 | 66 | #define OV5640_REG_TIMING_VTS 0x380e |
| 65 | 67 | #define OV5640_REG_TIMING_TC_REG21 0x3821 |
| @@ -91,6 +93,9 @@ · 25 unmodified lines | ||
| 91 | 93 | #define OV5640_REG_SDE_CTRL5 0x5585 |
| 92 | 94 | #define OV5640_REG_AVG_READOUT 0x56a1 |
| 93 | 95 | |
| 96 | +#define OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT 1 | |
| 97 | +#define OV5640_SCLK_ROOT_DIVIDER_DEFAULT 2 | |
| 98 | + | |
| 94 | 99 | enum ov5640_mode_id { |
| 95 | 100 | OV5640_MODE_QCIF_176_144 = 0, |
| 96 | 101 | OV5640_MODE_QVGA_320_240, |
| @@ -165,8 +170,10 @@ struct reg_value { · 68 unmodified lines | ||
| 165 | 170 | struct ov5640_mode_info { |
| 166 | 171 | enum ov5640_mode_id id; |
| 167 | 172 | enum ov5640_downsize_mode dn_mode; |
| 168 | − u32 width; | |
| 169 | − u32 height; | |
| 173 | + u32 hact; | |
| 174 | + u32 htot; | |
| 175 | + u32 vact; | |
| 176 | + u32 vtot; | |
| 170 | 177 | const struct reg_value *reg_data; |
| 171 | 178 | u32 reg_data_size; |
| 172 | 179 | }; |
| @@ -187,6 +194,7 @@ struct ov5640_ctrls { · 14 unmodified lines | ||
| 187 | 194 | struct v4l2_ctrl *gain; |
| 188 | 195 | }; |
| 189 | 196 | struct v4l2_ctrl *brightness; |
| 197 | + struct v4l2_ctrl *light_freq; | |
| 190 | 198 | struct v4l2_ctrl *saturation; |
| 191 | 199 | struct v4l2_ctrl *contrast; |
| 192 | 200 | struct v4l2_ctrl *hue; |
| @@ -248,7 +256,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { · 55 unmodified lines | ||
| 248 | 256 | {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, |
| 249 | 257 | {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, |
| 250 | 258 | {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, |
| 251 | − {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, | |
| 259 | + {0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0}, | |
| 252 | 260 | {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, |
| 253 | 261 | {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, |
| 254 | 262 | {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, |
| @@ -265,9 +273,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { · 10 unmodified lines | ||
| 265 | 273 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 266 | 274 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 267 | 275 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 268 | − {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 269 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 270 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 276 | + {0x3810, 0x00, 0, 0}, | |
| 271 | 277 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 272 | 278 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 273 | 279 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -339,9 +345,7 @@ static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = { · 65 unmodified lines | ||
| 339 | 345 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 340 | 346 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 341 | 347 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 342 | − {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 343 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 344 | − {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 348 | + {0x3810, 0x00, 0, 0}, | |
| 345 | 349 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 346 | 350 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 347 | 351 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -360,9 +364,7 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = { · 12 unmodified lines | ||
| 360 | 364 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 361 | 365 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 362 | 366 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 363 | − {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 364 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 365 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 367 | + {0x3810, 0x00, 0, 0}, | |
| 366 | 368 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 367 | 369 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 368 | 370 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -381,9 +383,7 @@ static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { · 12 unmodified lines | ||
| 381 | 383 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 382 | 384 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 383 | 385 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 384 | − {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 385 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 386 | − {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 386 | + {0x3810, 0x00, 0, 0}, | |
| 387 | 387 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 388 | 388 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 389 | 389 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -393,8 +393,7 @@ static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { · 3 unmodified lines | ||
| 393 | 393 | {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, |
| 394 | 394 | {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, |
| 395 | 395 | {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, |
| 396 | − {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, | |
| 397 | − {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0}, | |
| 396 | + {0x3035, 0x12, 0, 0}, | |
| 398 | 397 | }; |
| 399 | 398 | |
| 400 | 399 | static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { |
| @@ -404,9 +403,7 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { · 3 unmodified lines | ||
| 404 | 403 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 405 | 404 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 406 | 405 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 407 | − {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 408 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 409 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 406 | + {0x3810, 0x00, 0, 0}, | |
| 410 | 407 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 411 | 408 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 412 | 409 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -415,8 +412,7 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { · 2 unmodified lines | ||
| 415 | 412 | {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, |
| 416 | 413 | {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, |
| 417 | 414 | {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, |
| 418 | − {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0}, | |
| 419 | − {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, | |
| 415 | + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, | |
| 420 | 416 | }; |
| 421 | 417 | |
| 422 | 418 | static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { |
| @@ -426,9 +422,7 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { · 3 unmodified lines | ||
| 426 | 422 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 427 | 423 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 428 | 424 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 429 | − {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, | |
| 430 | − {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 431 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 425 | + {0x3810, 0x00, 0, 0}, | |
| 432 | 426 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 433 | 427 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 434 | 428 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -447,9 +441,7 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { · 12 unmodified lines | ||
| 447 | 441 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 448 | 442 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 449 | 443 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 450 | − {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, | |
| 451 | − {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 452 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 444 | + {0x3810, 0x00, 0, 0}, | |
| 453 | 445 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 454 | 446 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 455 | 447 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -468,9 +460,7 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { · 12 unmodified lines | ||
| 468 | 460 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 469 | 461 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 470 | 462 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 471 | − {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, | |
| 472 | − {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 473 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 463 | + {0x3810, 0x00, 0, 0}, | |
| 474 | 464 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 475 | 465 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 476 | 466 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -489,9 +479,7 @@ static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { · 12 unmodified lines | ||
| 489 | 479 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 490 | 480 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 491 | 481 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 492 | − {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, | |
| 493 | − {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 494 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 482 | + {0x3810, 0x00, 0, 0}, | |
| 495 | 483 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 496 | 484 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 497 | 485 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -510,9 +498,7 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { · 12 unmodified lines | ||
| 510 | 498 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 511 | 499 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 512 | 500 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 513 | − {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 514 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 515 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 501 | + {0x3810, 0x00, 0, 0}, | |
| 516 | 502 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, |
| 517 | 503 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 518 | 504 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -531,9 +517,7 @@ static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { · 12 unmodified lines | ||
| 531 | 517 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 532 | 518 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 533 | 519 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 534 | − {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, | |
| 535 | − {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 536 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 520 | + {0x3810, 0x00, 0, 0}, | |
| 537 | 521 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, |
| 538 | 522 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 539 | 523 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -552,9 +536,7 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { · 12 unmodified lines | ||
| 552 | 536 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 553 | 537 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 554 | 538 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 555 | − {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, | |
| 556 | − {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 557 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 539 | + {0x3810, 0x00, 0, 0}, | |
| 558 | 540 | {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 559 | 541 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 560 | 542 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -573,9 +555,7 @@ static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = { · 12 unmodified lines | ||
| 573 | 555 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 574 | 556 | {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 575 | 557 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, |
| 576 | − {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, | |
| 577 | − {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, | |
| 578 | − {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 558 | + {0x3810, 0x00, 0, 0}, | |
| 579 | 559 | {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, |
| 580 | 560 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 581 | 561 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -595,9 +575,7 @@ static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = { · 13 unmodified lines | ||
| 595 | 575 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 596 | 576 | {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 597 | 577 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, |
| 598 | − {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, | |
| 599 | − {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, | |
| 600 | − {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 578 | + {0x3810, 0x00, 0, 0}, | |
| 601 | 579 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, |
| 602 | 580 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 603 | 581 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, |
| @@ -617,9 +595,7 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = { · 13 unmodified lines | ||
| 617 | 595 | {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 618 | 596 | {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 619 | 597 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, |
| 620 | − {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, | |
| 621 | − {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, | |
| 622 | − {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 598 | + {0x3810, 0x00, 0, 0}, | |
| 623 | 599 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, |
| 624 | 600 | {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, |
| 625 | 601 | {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, |
| @@ -639,9 +615,7 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { · 13 unmodified lines | ||
| 639 | 615 | {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 640 | 616 | {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 641 | 617 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, |
| 642 | − {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, | |
| 643 | − {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, | |
| 644 | − {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 618 | + {0x3810, 0x00, 0, 0}, | |
| 645 | 619 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, |
| 646 | 620 | {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, |
| 647 | 621 | {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -655,10 +629,8 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { · 7 unmodified lines | ||
| 655 | 629 | {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, |
| 656 | 630 | {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, |
| 657 | 631 | {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, |
| 658 | − {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, | |
| 659 | − {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, | |
| 660 | − {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, | |
| 661 | − {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, | |
| 632 | + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, | |
| 633 | + {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, | |
| 662 | 634 | {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, |
| 663 | 635 | {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, |
| 664 | 636 | {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, |
| @@ -676,9 +648,7 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { · 11 unmodified lines | ||
| 676 | 648 | {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 677 | 649 | {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 678 | 650 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, |
| 679 | − {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, | |
| 680 | − {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, | |
| 681 | − {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 651 | + {0x3810, 0x00, 0, 0}, | |
| 682 | 652 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, |
| 683 | 653 | {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, |
| 684 | 654 | {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -692,10 +662,8 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { · 7 unmodified lines | ||
| 692 | 662 | {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, |
| 693 | 663 | {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, |
| 694 | 664 | {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, |
| 695 | − {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, | |
| 696 | − {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, | |
| 697 | − {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, | |
| 698 | − {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, | |
| 665 | + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, | |
| 666 | + {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, | |
| 699 | 667 | {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, |
| 700 | 668 | {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, |
| 701 | 669 | {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, |
| @@ -712,9 +680,7 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { · 10 unmodified lines | ||
| 712 | 680 | {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, |
| 713 | 681 | {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, |
| 714 | 682 | {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, |
| 715 | − {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, | |
| 716 | − {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, | |
| 717 | − {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, | |
| 683 | + {0x3810, 0x00, 0, 0}, | |
| 718 | 684 | {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, |
| 719 | 685 | {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, |
| 720 | 686 | {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, |
| @@ -728,66 +694,84 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { · 7 unmodified lines | ||
| 728 | 694 | |
| 729 | 695 | /* power-on sensor init reg table */ |
| 730 | 696 | static const struct ov5640_mode_info ov5640_mode_init_data = { |
| 731 | − 0, SUBSAMPLING, 640, 480, ov5640_init_setting_30fps_VGA, | |
| 697 | + 0, SUBSAMPLING, 640, 1896, 480, 984, | |
| 698 | + ov5640_init_setting_30fps_VGA, | |
| 732 | 699 | ARRAY_SIZE(ov5640_init_setting_30fps_VGA), |
| 733 | 700 | }; |
| 734 | 701 | |
| 735 | 702 | static const struct ov5640_mode_info |
| 736 | 703 | ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = { |
| 737 | 704 | { |
| 738 | − {OV5640_MODE_QCIF_176_144, SUBSAMPLING, 176, 144, | |
| 705 | + {OV5640_MODE_QCIF_176_144, SUBSAMPLING, | |
| 706 | + 176, 1896, 144, 984, | |
| 739 | 707 | ov5640_setting_15fps_QCIF_176_144, |
| 740 | 708 | ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, |
| 741 | − {OV5640_MODE_QVGA_320_240, SUBSAMPLING, 320, 240, | |
| 709 | + {OV5640_MODE_QVGA_320_240, SUBSAMPLING, | |
| 710 | + 320, 1896, 240, 984, | |
| 742 | 711 | ov5640_setting_15fps_QVGA_320_240, |
| 743 | 712 | ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, |
| 744 | − {OV5640_MODE_VGA_640_480, SUBSAMPLING, 640, 480, | |
| 713 | + {OV5640_MODE_VGA_640_480, SUBSAMPLING, | |
| 714 | + 640, 1896, 480, 1080, | |
| 745 | 715 | ov5640_setting_15fps_VGA_640_480, |
| 746 | 716 | ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, |
| 747 | − {OV5640_MODE_NTSC_720_480, SUBSAMPLING, 720, 480, | |
| 717 | + {OV5640_MODE_NTSC_720_480, SUBSAMPLING, | |
| 718 | + 720, 1896, 480, 984, | |
| 748 | 719 | ov5640_setting_15fps_NTSC_720_480, |
| 749 | 720 | ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, |
| 750 | − {OV5640_MODE_PAL_720_576, SUBSAMPLING, 720, 576, | |
| 721 | + {OV5640_MODE_PAL_720_576, SUBSAMPLING, | |
| 722 | + 720, 1896, 576, 984, | |
| 751 | 723 | ov5640_setting_15fps_PAL_720_576, |
| 752 | 724 | ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, |
| 753 | − {OV5640_MODE_XGA_1024_768, SUBSAMPLING, 1024, 768, | |
| 725 | + {OV5640_MODE_XGA_1024_768, SUBSAMPLING, | |
| 726 | + 1024, 1896, 768, 1080, | |
| 754 | 727 | ov5640_setting_15fps_XGA_1024_768, |
| 755 | 728 | ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, |
| 756 | − {OV5640_MODE_720P_1280_720, SUBSAMPLING, 1280, 720, | |
| 729 | + {OV5640_MODE_720P_1280_720, SUBSAMPLING, | |
| 730 | + 1280, 1892, 720, 740, | |
| 757 | 731 | ov5640_setting_15fps_720P_1280_720, |
| 758 | 732 | ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, |
| 759 | − {OV5640_MODE_1080P_1920_1080, SCALING, 1920, 1080, | |
| 733 | + {OV5640_MODE_1080P_1920_1080, SCALING, | |
| 734 | + 1920, 2500, 1080, 1120, | |
| 760 | 735 | ov5640_setting_15fps_1080P_1920_1080, |
| 761 | 736 | ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, |
| 762 | − {OV5640_MODE_QSXGA_2592_1944, SCALING, 2592, 1944, | |
| 737 | + {OV5640_MODE_QSXGA_2592_1944, SCALING, | |
| 738 | + 2592, 2844, 1944, 1968, | |
| 763 | 739 | ov5640_setting_15fps_QSXGA_2592_1944, |
| 764 | 740 | ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, |
| 765 | 741 | }, { |
| 766 | − {OV5640_MODE_QCIF_176_144, SUBSAMPLING, 176, 144, | |
| 742 | + {OV5640_MODE_QCIF_176_144, SUBSAMPLING, | |
| 743 | + 176, 1896, 144, 984, | |
| 767 | 744 | ov5640_setting_30fps_QCIF_176_144, |
| 768 | 745 | ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, |
| 769 | − {OV5640_MODE_QVGA_320_240, SUBSAMPLING, 320, 240, | |
| 746 | + {OV5640_MODE_QVGA_320_240, SUBSAMPLING, | |
| 747 | + 320, 1896, 240, 984, | |
| 770 | 748 | ov5640_setting_30fps_QVGA_320_240, |
| 771 | 749 | ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, |
| 772 | − {OV5640_MODE_VGA_640_480, SUBSAMPLING, 640, 480, | |
| 750 | + {OV5640_MODE_VGA_640_480, SUBSAMPLING, | |
| 751 | + 640, 1896, 480, 1080, | |
| 773 | 752 | ov5640_setting_30fps_VGA_640_480, |
| 774 | 753 | ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, |
| 775 | − {OV5640_MODE_NTSC_720_480, SUBSAMPLING, 720, 480, | |
| 754 | + {OV5640_MODE_NTSC_720_480, SUBSAMPLING, | |
| 755 | + 720, 1896, 480, 984, | |
| 776 | 756 | ov5640_setting_30fps_NTSC_720_480, |
| 777 | 757 | ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, |
| 778 | − {OV5640_MODE_PAL_720_576, SUBSAMPLING, 720, 576, | |
| 758 | + {OV5640_MODE_PAL_720_576, SUBSAMPLING, | |
| 759 | + 720, 1896, 576, 984, | |
| 779 | 760 | ov5640_setting_30fps_PAL_720_576, |
| 780 | 761 | ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, |
| 781 | − {OV5640_MODE_XGA_1024_768, SUBSAMPLING, 1024, 768, | |
| 762 | + {OV5640_MODE_XGA_1024_768, SUBSAMPLING, | |
| 763 | + 1024, 1896, 768, 1080, | |
| 782 | 764 | ov5640_setting_30fps_XGA_1024_768, |
| 783 | 765 | ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, |
| 784 | − {OV5640_MODE_720P_1280_720, SUBSAMPLING, 1280, 720, | |
| 766 | + {OV5640_MODE_720P_1280_720, SUBSAMPLING, | |
| 767 | + 1280, 1892, 720, 740, | |
| 785 | 768 | ov5640_setting_30fps_720P_1280_720, |
| 786 | 769 | ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, |
| 787 | − {OV5640_MODE_1080P_1920_1080, SCALING, 1920, 1080, | |
| 770 | + {OV5640_MODE_1080P_1920_1080, SCALING, | |
| 771 | + 1920, 2500, 1080, 1120, | |
| 788 | 772 | ov5640_setting_30fps_1080P_1920_1080, |
| 789 | 773 | ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, |
| 790 | − {OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, | |
| 774 | + {OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0}, | |
| 791 | 775 | }, |
| 792 | 776 | }; |
| 793 | 777 | |
| @@ -1377,6 +1361,30 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) · 583 unmodified lines | ||
| 1377 | 1361 | return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); |
| 1378 | 1362 | } |
| 1379 | 1363 | |
| 1364 | +static int ov5640_set_timings(struct ov5640_dev *sensor, | |
| 1365 | + const struct ov5640_mode_info *mode) | |
| 1366 | +{ | |
| 1367 | + int ret; | |
| 1368 | + | |
| 1369 | + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); | |
| 1370 | + if (ret < 0) | |
| 1371 | + return ret; | |
| 1372 | + | |
| 1373 | + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); | |
| 1374 | + if (ret < 0) | |
| 1375 | + return ret; | |
| 1376 | + | |
| 1377 | + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); | |
| 1378 | + if (ret < 0) | |
| 1379 | + return ret; | |
| 1380 | + | |
| 1381 | + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); | |
| 1382 | + if (ret < 0) | |
| 1383 | + return ret; | |
| 1384 | + | |
| 1385 | + return 0; | |
| 1386 | +} | |
| 1387 | + | |
| 1380 | 1388 | static const struct ov5640_mode_info * |
| 1381 | 1389 | ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, |
| 1382 | 1390 | int width, int height, bool nearest) |
| @@ -1390,10 +1398,10 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, · 7 unmodified lines | ||
| 1390 | 1398 | if (!mode->reg_data) |
| 1391 | 1399 | continue; |
| 1392 | 1400 | |
| 1393 | − if ((nearest && mode->width <= width && | |
| 1394 | − mode->height <= height) || | |
| 1395 | − (!nearest && mode->width == width && | |
| 1396 | − mode->height == height)) | |
| 1401 | + if ((nearest && mode->hact <= width && | |
| 1402 | + mode->vact <= height) || | |
| 1403 | + (!nearest && mode->hact == width && | |
| 1404 | + mode->vact == height)) | |
| 1397 | 1405 | break; |
| 1398 | 1406 | } |
| 1399 | 1407 | |
| @@ -1568,7 +1576,8 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, · 168 unmodified lines | ||
| 1568 | 1576 | * change mode directly |
| 1569 | 1577 | */ |
| 1570 | 1578 | static int ov5640_set_mode_direct(struct ov5640_dev *sensor, |
| 1571 | − const struct ov5640_mode_info *mode) | |
| 1579 | + const struct ov5640_mode_info *mode, | |
| 1580 | + s32 exposure) | |
| 1572 | 1581 | { |
| 1573 | 1582 | int ret; |
| 1574 | 1583 | |
| @@ -1584,7 +1593,8 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, · 9 unmodified lines | ||
| 1584 | 1593 | ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 1); |
| 1585 | 1594 | if (ret) |
| 1586 | 1595 | return ret; |
| 1587 | − return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, V4L2_EXPOSURE_AUTO); | |
| 1596 | + | |
| 1597 | + return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, exposure); | |
| 1588 | 1598 | } |
| 1589 | 1599 | |
| 1590 | 1600 | static int ov5640_set_mode(struct ov5640_dev *sensor, |
| @@ -1592,6 +1602,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor, · 1 unmodified line | ||
| 1592 | 1602 | { |
| 1593 | 1603 | const struct ov5640_mode_info *mode = sensor->current_mode; |
| 1594 | 1604 | enum ov5640_downsize_mode dn_mode, orig_dn_mode; |
| 1605 | + s32 exposure; | |
| 1595 | 1606 | int ret; |
| 1596 | 1607 | |
| 1597 | 1608 | dn_mode = mode->dn_mode; |
| @@ -1601,7 +1612,9 @@ static int ov5640_set_mode(struct ov5640_dev *sensor, · 3 unmodified lines | ||
| 1601 | 1612 | ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 0); |
| 1602 | 1613 | if (ret) |
| 1603 | 1614 | return ret; |
| 1604 | − ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, V4L2_EXPOSURE_MANUAL); | |
| 1615 | + | |
| 1616 | + exposure = sensor->ctrls.auto_exp->val; | |
| 1617 | + ret = ov5640_set_exposure(sensor, V4L2_EXPOSURE_MANUAL); | |
| 1605 | 1618 | if (ret) |
| 1606 | 1619 | return ret; |
| 1607 | 1620 | |
| @@ -1617,9 +1630,13 @@ static int ov5640_set_mode(struct ov5640_dev *sensor, · 9 unmodified lines | ||
| 1617 | 1630 | * change inside subsampling or scaling |
| 1618 | 1631 | * download firmware directly |
| 1619 | 1632 | */ |
| 1620 | − ret = ov5640_set_mode_direct(sensor, mode); | |
| 1633 | + ret = ov5640_set_mode_direct(sensor, mode, exposure); | |
| 1621 | 1634 | } |
| 1622 | 1635 | |
| 1636 | + if (ret < 0) | |
| 1637 | + return ret; | |
| 1638 | + | |
| 1639 | + ret = ov5640_set_timings(sensor, mode); | |
| 1623 | 1640 | if (ret < 0) |
| 1624 | 1641 | return ret; |
| 1625 | 1642 | |
| @@ -1654,6 +1671,12 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) · 28 unmodified lines | ||
| 1654 | 1671 | if (ret < 0) |
| 1655 | 1672 | return ret; |
| 1656 | 1673 | |
| 1674 | + ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, | |
| 1675 | + (ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) | | |
| 1676 | + ilog2(OV5640_SCLK_ROOT_DIVIDER_DEFAULT)); | |
| 1677 | + if (ret) | |
| 1678 | + return ret; | |
| 1679 | + | |
| 1657 | 1680 | /* now restore the last capture mode */ |
| 1658 | 1681 | ret = ov5640_set_mode(sensor, &ov5640_mode_init_data); |
| 1659 | 1682 | if (ret < 0) |
| @@ -1871,8 +1894,8 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, · 211 unmodified lines | ||
| 1871 | 1894 | mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); |
| 1872 | 1895 | if (!mode) |
| 1873 | 1896 | return -EINVAL; |
| 1874 | − fmt->width = mode->width; | |
| 1875 | − fmt->height = mode->height; | |
| 1897 | + fmt->width = mode->hact; | |
| 1898 | + fmt->height = mode->vact; | |
| 1876 | 1899 | |
| 1877 | 1900 | if (new_mode) |
| 1878 | 1901 | *new_mode = mode; |
| @@ -2155,6 +2178,21 @@ static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) · 276 unmodified lines | ||
| 2155 | 2178 | 0xa4, value ? 0xa4 : 0); |
| 2156 | 2179 | } |
| 2157 | 2180 | |
| 2181 | +static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) | |
| 2182 | +{ | |
| 2183 | + int ret; | |
| 2184 | + | |
| 2185 | + ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), | |
| 2186 | + (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? | |
| 2187 | + 0 : BIT(7)); | |
| 2188 | + if (ret) | |
| 2189 | + return ret; | |
| 2190 | + | |
| 2191 | + return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), | |
| 2192 | + (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? | |
| 2193 | + BIT(2) : 0); | |
| 2194 | +} | |
| 2195 | + | |
| 2158 | 2196 | static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 2159 | 2197 | { |
| 2160 | 2198 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); |
| @@ -2223,6 +2261,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) · 62 unmodified lines | ||
| 2223 | 2261 | case V4L2_CID_TEST_PATTERN: |
| 2224 | 2262 | ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); |
| 2225 | 2263 | break; |
| 2264 | + case V4L2_CID_POWER_LINE_FREQUENCY: | |
| 2265 | + ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); | |
| 2266 | + break; | |
| 2226 | 2267 | default: |
| 2227 | 2268 | ret = -EINVAL; |
| 2228 | 2269 | break; |
| @@ -2285,6 +2326,12 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) · 56 unmodified lines | ||
| 2285 | 2326 | ARRAY_SIZE(test_pattern_menu) - 1, |
| 2286 | 2327 | 0, 0, test_pattern_menu); |
| 2287 | 2328 | |
| 2329 | + ctrls->light_freq = | |
| 2330 | + v4l2_ctrl_new_std_menu(hdl, ops, | |
| 2331 | + V4L2_CID_POWER_LINE_FREQUENCY, | |
| 2332 | + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | |
| 2333 | + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); | |
| 2334 | + | |
| 2288 | 2335 | if (hdl->error) { |
| 2289 | 2336 | ret = hdl->error; |
| 2290 | 2337 | goto free_ctrls; |
| @@ -2315,10 +2362,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, · 24 unmodified lines | ||
| 2315 | 2362 | return -EINVAL; |
| 2316 | 2363 | |
| 2317 | 2364 | fse->min_width = |
| 2318 | − ov5640_mode_data[0][fse->index].width; | |
| 2365 | + ov5640_mode_data[0][fse->index].hact; | |
| 2319 | 2366 | fse->max_width = fse->min_width; |
| 2320 | 2367 | fse->min_height = |
| 2321 | − ov5640_mode_data[0][fse->index].height; | |
| 2368 | + ov5640_mode_data[0][fse->index].vact; | |
| 2322 | 2369 | fse->max_height = fse->min_height; |
| 2323 | 2370 | |
| 2324 | 2371 | return 0; |
| @@ -2382,14 +2429,14 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, · 57 unmodified lines | ||
| 2382 | 2429 | mode = sensor->current_mode; |
| 2383 | 2430 | |
| 2384 | 2431 | frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, |
| 2385 | − mode->width, mode->height); | |
| 2432 | + mode->hact, mode->vact); | |
| 2386 | 2433 | if (frame_rate < 0) |
| 2387 | 2434 | frame_rate = OV5640_15_FPS; |
| 2388 | 2435 | |
| 2389 | 2436 | sensor->current_fr = frame_rate; |
| 2390 | 2437 | sensor->frame_interval = fi->interval; |
| 2391 | − sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->width, | |
| 2392 | − mode->height, true); | |
| 2438 | + sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->hact, | |
| 2439 | + mode->vact, true); | |
| 2393 | 2440 | sensor->pending_mode_change = true; |
| 2394 | 2441 | out: |
| 2395 | 2442 | mutex_unlock(&sensor->lock); |
| @@ -2536,8 +2583,8 @@ static int ov5640_probe(struct i2c_client *client, · 140 unmodified lines | ||
| 2536 | 2583 | |
| 2537 | 2584 | sensor->ae_target = 52; |
| 2538 | 2585 | |
| 2539 | − endpoint = fwnode_graph_get_next_endpoint( | |
| 2540 | − of_fwnode_handle(client->dev.of_node), NULL); | |
| 2586 | + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), | |
| 2587 | + NULL); | |
| 2541 | 2588 | if (!endpoint) { |
| 2542 | 2589 | dev_err(dev, "endpoint node not found\n"); |
| 2543 | 2590 | return -EINVAL; |
| @@ -600,11 +600,13 @@ static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val) · 599 unmodified lines | ||
| 600 | 600 | regbuf[2] = val; |
| 601 | 601 | |
| 602 | 602 | ret = i2c_master_send(ov5645->i2c_client, regbuf, 3); |
| 603 | − if (ret < 0) | |
| 603 | + if (ret < 0) { | |
| 604 | 604 | dev_err(ov5645->dev, "%s: write reg error %d: reg=%x, val=%x\n", |
| 605 | 605 | __func__, ret, reg, val); |
| 606 | + return ret; | |
| 607 | + } | |
| 606 | 608 | |
| 607 | − return ret; | |
| 609 | + return 0; | |
| 608 | 610 | } |
| 609 | 611 | |
| 610 | 612 | static int ov5645_read_reg(struct ov5645 *ov5645, u16 reg, u8 *val) |
| @@ -1385,7 +1385,6 @@ MODULE_DEVICE_TABLE(of, ov5695_of_match); · 1384 unmodified lines | ||
| 1385 | 1385 | static struct i2c_driver ov5695_i2c_driver = { |
| 1386 | 1386 | .driver = { |
| 1387 | 1387 | .name = "ov5695", |
| 1388 | − .owner = THIS_MODULE, | |
| 1389 | 1388 | .pm = &ov5695_pm_ops, |
| 1390 | 1389 | .of_match_table = of_match_ptr(ov5695_of_match), |
| 1391 | 1390 | }, |
| @@ -0,0 +1,1503 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Driver for the OV7251 camera sensor. | |
| 4 | + * | |
| 5 | + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. | |
| 6 | + * Copyright (c) 2017-2018, Linaro Ltd. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/bitops.h> | |
| 10 | +#include <linux/clk.h> | |
| 11 | +#include <linux/delay.h> | |
| 12 | +#include <linux/device.h> | |
| 13 | +#include <linux/gpio/consumer.h> | |
| 14 | +#include <linux/i2c.h> | |
| 15 | +#include <linux/init.h> | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/regulator/consumer.h> | |
| 18 | +#include <linux/slab.h> | |
| 19 | +#include <linux/types.h> | |
| 20 | +#include <media/v4l2-ctrls.h> | |
| 21 | +#include <media/v4l2-fwnode.h> | |
| 22 | +#include <media/v4l2-subdev.h> | |
| 23 | + | |
| 24 | +#define OV7251_SC_MODE_SELECT 0x0100 | |
| 25 | +#define OV7251_SC_MODE_SELECT_SW_STANDBY 0x0 | |
| 26 | +#define OV7251_SC_MODE_SELECT_STREAMING 0x1 | |
| 27 | + | |
| 28 | +#define OV7251_CHIP_ID_HIGH 0x300a | |
| 29 | +#define OV7251_CHIP_ID_HIGH_BYTE 0x77 | |
| 30 | +#define OV7251_CHIP_ID_LOW 0x300b | |
| 31 | +#define OV7251_CHIP_ID_LOW_BYTE 0x50 | |
| 32 | +#define OV7251_SC_GP_IO_IN1 0x3029 | |
| 33 | +#define OV7251_AEC_EXPO_0 0x3500 | |
| 34 | +#define OV7251_AEC_EXPO_1 0x3501 | |
| 35 | +#define OV7251_AEC_EXPO_2 0x3502 | |
| 36 | +#define OV7251_AEC_AGC_ADJ_0 0x350a | |
| 37 | +#define OV7251_AEC_AGC_ADJ_1 0x350b | |
| 38 | +#define OV7251_TIMING_FORMAT1 0x3820 | |
| 39 | +#define OV7251_TIMING_FORMAT1_VFLIP BIT(2) | |
| 40 | +#define OV7251_TIMING_FORMAT2 0x3821 | |
| 41 | +#define OV7251_TIMING_FORMAT2_MIRROR BIT(2) | |
| 42 | +#define OV7251_PRE_ISP_00 0x5e00 | |
| 43 | +#define OV7251_PRE_ISP_00_TEST_PATTERN BIT(7) | |
| 44 | + | |
| 45 | +struct reg_value { | |
| 46 | + u16 reg; | |
| 47 | + u8 val; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +struct ov7251_mode_info { | |
| 51 | + u32 width; | |
| 52 | + u32 height; | |
| 53 | + const struct reg_value *data; | |
| 54 | + u32 data_size; | |
| 55 | + u32 pixel_clock; | |
| 56 | + u32 link_freq; | |
| 57 | + u16 exposure_max; | |
| 58 | + u16 exposure_def; | |
| 59 | + struct v4l2_fract timeperframe; | |
| 60 | +}; | |
| 61 | + | |
| 62 | +struct ov7251 { | |
| 63 | + struct i2c_client *i2c_client; | |
| 64 | + struct device *dev; | |
| 65 | + struct v4l2_subdev sd; | |
| 66 | + struct media_pad pad; | |
| 67 | + struct v4l2_fwnode_endpoint ep; | |
| 68 | + struct v4l2_mbus_framefmt fmt; | |
| 69 | + struct v4l2_rect crop; | |
| 70 | + struct clk *xclk; | |
| 71 | + u32 xclk_freq; | |
| 72 | + | |
| 73 | + struct regulator *io_regulator; | |
| 74 | + struct regulator *core_regulator; | |
| 75 | + struct regulator *analog_regulator; | |
| 76 | + | |
| 77 | + const struct ov7251_mode_info *current_mode; | |
| 78 | + | |
| 79 | + struct v4l2_ctrl_handler ctrls; | |
| 80 | + struct v4l2_ctrl *pixel_clock; | |
| 81 | + struct v4l2_ctrl *link_freq; | |
| 82 | + struct v4l2_ctrl *exposure; | |
| 83 | + struct v4l2_ctrl *gain; | |
| 84 | + | |
| 85 | + /* Cached register values */ | |
| 86 | + u8 aec_pk_manual; | |
| 87 | + u8 pre_isp_00; | |
| 88 | + u8 timing_format1; | |
| 89 | + u8 timing_format2; | |
| 90 | + | |
| 91 | + struct mutex lock; /* lock to protect power state, ctrls and mode */ | |
| 92 | + bool power_on; | |
| 93 | + | |
| 94 | + struct gpio_desc *enable_gpio; | |
| 95 | +}; | |
| 96 | + | |
| 97 | +static inline struct ov7251 *to_ov7251(struct v4l2_subdev *sd) | |
| 98 | +{ | |
| 99 | + return container_of(sd, struct ov7251, sd); | |
| 100 | +} | |
| 101 | + | |
| 102 | +static const struct reg_value ov7251_global_init_setting[] = { | |
| 103 | + { 0x0103, 0x01 }, | |
| 104 | + { 0x303b, 0x02 }, | |
| 105 | +}; | |
| 106 | + | |
| 107 | +static const struct reg_value ov7251_setting_vga_30fps[] = { | |
| 108 | + { 0x3005, 0x00 }, | |
| 109 | + { 0x3012, 0xc0 }, | |
| 110 | + { 0x3013, 0xd2 }, | |
| 111 | + { 0x3014, 0x04 }, | |
| 112 | + { 0x3016, 0xf0 }, | |
| 113 | + { 0x3017, 0xf0 }, | |
| 114 | + { 0x3018, 0xf0 }, | |
| 115 | + { 0x301a, 0xf0 }, | |
| 116 | + { 0x301b, 0xf0 }, | |
| 117 | + { 0x301c, 0xf0 }, | |
| 118 | + { 0x3023, 0x05 }, | |
| 119 | + { 0x3037, 0xf0 }, | |
| 120 | + { 0x3098, 0x04 }, /* pll2 pre divider */ | |
| 121 | + { 0x3099, 0x28 }, /* pll2 multiplier */ | |
| 122 | + { 0x309a, 0x05 }, /* pll2 sys divider */ | |
| 123 | + { 0x309b, 0x04 }, /* pll2 adc divider */ | |
| 124 | + { 0x309d, 0x00 }, /* pll2 divider */ | |
| 125 | + { 0x30b0, 0x0a }, /* pll1 pix divider */ | |
| 126 | + { 0x30b1, 0x01 }, /* pll1 divider */ | |
| 127 | + { 0x30b3, 0x64 }, /* pll1 multiplier */ | |
| 128 | + { 0x30b4, 0x03 }, /* pll1 pre divider */ | |
| 129 | + { 0x30b5, 0x05 }, /* pll1 mipi divider */ | |
| 130 | + { 0x3106, 0xda }, | |
| 131 | + { 0x3503, 0x07 }, | |
| 132 | + { 0x3509, 0x10 }, | |
| 133 | + { 0x3600, 0x1c }, | |
| 134 | + { 0x3602, 0x62 }, | |
| 135 | + { 0x3620, 0xb7 }, | |
| 136 | + { 0x3622, 0x04 }, | |
| 137 | + { 0x3626, 0x21 }, | |
| 138 | + { 0x3627, 0x30 }, | |
| 139 | + { 0x3630, 0x44 }, | |
| 140 | + { 0x3631, 0x35 }, | |
| 141 | + { 0x3634, 0x60 }, | |
| 142 | + { 0x3636, 0x00 }, | |
| 143 | + { 0x3662, 0x01 }, | |
| 144 | + { 0x3663, 0x70 }, | |
| 145 | + { 0x3664, 0x50 }, | |
| 146 | + { 0x3666, 0x0a }, | |
| 147 | + { 0x3669, 0x1a }, | |
| 148 | + { 0x366a, 0x00 }, | |
| 149 | + { 0x366b, 0x50 }, | |
| 150 | + { 0x3673, 0x01 }, | |
| 151 | + { 0x3674, 0xff }, | |
| 152 | + { 0x3675, 0x03 }, | |
| 153 | + { 0x3705, 0xc1 }, | |
| 154 | + { 0x3709, 0x40 }, | |
| 155 | + { 0x373c, 0x08 }, | |
| 156 | + { 0x3742, 0x00 }, | |
| 157 | + { 0x3757, 0xb3 }, | |
| 158 | + { 0x3788, 0x00 }, | |
| 159 | + { 0x37a8, 0x01 }, | |
| 160 | + { 0x37a9, 0xc0 }, | |
| 161 | + { 0x3800, 0x00 }, | |
| 162 | + { 0x3801, 0x04 }, | |
| 163 | + { 0x3802, 0x00 }, | |
| 164 | + { 0x3803, 0x04 }, | |
| 165 | + { 0x3804, 0x02 }, | |
| 166 | + { 0x3805, 0x8b }, | |
| 167 | + { 0x3806, 0x01 }, | |
| 168 | + { 0x3807, 0xeb }, | |
| 169 | + { 0x3808, 0x02 }, /* width high */ | |
| 170 | + { 0x3809, 0x80 }, /* width low */ | |
| 171 | + { 0x380a, 0x01 }, /* height high */ | |
| 172 | + { 0x380b, 0xe0 }, /* height low */ | |
| 173 | + { 0x380c, 0x03 }, /* total horiz timing high */ | |
| 174 | + { 0x380d, 0xa0 }, /* total horiz timing low */ | |
| 175 | + { 0x380e, 0x06 }, /* total vertical timing high */ | |
| 176 | + { 0x380f, 0xbc }, /* total vertical timing low */ | |
| 177 | + { 0x3810, 0x00 }, | |
| 178 | + { 0x3811, 0x04 }, | |
| 179 | + { 0x3812, 0x00 }, | |
| 180 | + { 0x3813, 0x05 }, | |
| 181 | + { 0x3814, 0x11 }, | |
| 182 | + { 0x3815, 0x11 }, | |
| 183 | + { 0x3820, 0x40 }, | |
| 184 | + { 0x3821, 0x00 }, | |
| 185 | + { 0x382f, 0x0e }, | |
| 186 | + { 0x3832, 0x00 }, | |
| 187 | + { 0x3833, 0x05 }, | |
| 188 | + { 0x3834, 0x00 }, | |
| 189 | + { 0x3835, 0x0c }, | |
| 190 | + { 0x3837, 0x00 }, | |
| 191 | + { 0x3b80, 0x00 }, | |
| 192 | + { 0x3b81, 0xa5 }, | |
| 193 | + { 0x3b82, 0x10 }, | |
| 194 | + { 0x3b83, 0x00 }, | |
| 195 | + { 0x3b84, 0x08 }, | |
| 196 | + { 0x3b85, 0x00 }, | |
| 197 | + { 0x3b86, 0x01 }, | |
| 198 | + { 0x3b87, 0x00 }, | |
| 199 | + { 0x3b88, 0x00 }, | |
| 200 | + { 0x3b89, 0x00 }, | |
| 201 | + { 0x3b8a, 0x00 }, | |
| 202 | + { 0x3b8b, 0x05 }, | |
| 203 | + { 0x3b8c, 0x00 }, | |
| 204 | + { 0x3b8d, 0x00 }, | |
| 205 | + { 0x3b8e, 0x00 }, | |
| 206 | + { 0x3b8f, 0x1a }, | |
| 207 | + { 0x3b94, 0x05 }, | |
| 208 | + { 0x3b95, 0xf2 }, | |
| 209 | + { 0x3b96, 0x40 }, | |
| 210 | + { 0x3c00, 0x89 }, | |
| 211 | + { 0x3c01, 0x63 }, | |
| 212 | + { 0x3c02, 0x01 }, | |
| 213 | + { 0x3c03, 0x00 }, | |
| 214 | + { 0x3c04, 0x00 }, | |
| 215 | + { 0x3c05, 0x03 }, | |
| 216 | + { 0x3c06, 0x00 }, | |
| 217 | + { 0x3c07, 0x06 }, | |
| 218 | + { 0x3c0c, 0x01 }, | |
| 219 | + { 0x3c0d, 0xd0 }, | |
| 220 | + { 0x3c0e, 0x02 }, | |
| 221 | + { 0x3c0f, 0x0a }, | |
| 222 | + { 0x4001, 0x42 }, | |
| 223 | + { 0x4004, 0x04 }, | |
| 224 | + { 0x4005, 0x00 }, | |
| 225 | + { 0x404e, 0x01 }, | |
| 226 | + { 0x4300, 0xff }, | |
| 227 | + { 0x4301, 0x00 }, | |
| 228 | + { 0x4315, 0x00 }, | |
| 229 | + { 0x4501, 0x48 }, | |
| 230 | + { 0x4600, 0x00 }, | |
| 231 | + { 0x4601, 0x4e }, | |
| 232 | + { 0x4801, 0x0f }, | |
| 233 | + { 0x4806, 0x0f }, | |
| 234 | + { 0x4819, 0xaa }, | |
| 235 | + { 0x4823, 0x3e }, | |
| 236 | + { 0x4837, 0x19 }, | |
| 237 | + { 0x4a0d, 0x00 }, | |
| 238 | + { 0x4a47, 0x7f }, | |
| 239 | + { 0x4a49, 0xf0 }, | |
| 240 | + { 0x4a4b, 0x30 }, | |
| 241 | + { 0x5000, 0x85 }, | |
| 242 | + { 0x5001, 0x80 }, | |
| 243 | +}; | |
| 244 | + | |
| 245 | +static const struct reg_value ov7251_setting_vga_60fps[] = { | |
| 246 | + { 0x3005, 0x00 }, | |
| 247 | + { 0x3012, 0xc0 }, | |
| 248 | + { 0x3013, 0xd2 }, | |
| 249 | + { 0x3014, 0x04 }, | |
| 250 | + { 0x3016, 0x10 }, | |
| 251 | + { 0x3017, 0x00 }, | |
| 252 | + { 0x3018, 0x00 }, | |
| 253 | + { 0x301a, 0x00 }, | |
| 254 | + { 0x301b, 0x00 }, | |
| 255 | + { 0x301c, 0x00 }, | |
| 256 | + { 0x3023, 0x05 }, | |
| 257 | + { 0x3037, 0xf0 }, | |
| 258 | + { 0x3098, 0x04 }, /* pll2 pre divider */ | |
| 259 | + { 0x3099, 0x28 }, /* pll2 multiplier */ | |
| 260 | + { 0x309a, 0x05 }, /* pll2 sys divider */ | |
| 261 | + { 0x309b, 0x04 }, /* pll2 adc divider */ | |
| 262 | + { 0x309d, 0x00 }, /* pll2 divider */ | |
| 263 | + { 0x30b0, 0x0a }, /* pll1 pix divider */ | |
| 264 | + { 0x30b1, 0x01 }, /* pll1 divider */ | |
| 265 | + { 0x30b3, 0x64 }, /* pll1 multiplier */ | |
| 266 | + { 0x30b4, 0x03 }, /* pll1 pre divider */ | |
| 267 | + { 0x30b5, 0x05 }, /* pll1 mipi divider */ | |
| 268 | + { 0x3106, 0xda }, | |
| 269 | + { 0x3503, 0x07 }, | |
| 270 | + { 0x3509, 0x10 }, | |
| 271 | + { 0x3600, 0x1c }, | |
| 272 | + { 0x3602, 0x62 }, | |
| 273 | + { 0x3620, 0xb7 }, | |
| 274 | + { 0x3622, 0x04 }, | |
| 275 | + { 0x3626, 0x21 }, | |
| 276 | + { 0x3627, 0x30 }, | |
| 277 | + { 0x3630, 0x44 }, | |
| 278 | + { 0x3631, 0x35 }, | |
| 279 | + { 0x3634, 0x60 }, | |
| 280 | + { 0x3636, 0x00 }, | |
| 281 | + { 0x3662, 0x01 }, | |
| 282 | + { 0x3663, 0x70 }, | |
| 283 | + { 0x3664, 0x50 }, | |
| 284 | + { 0x3666, 0x0a }, | |
| 285 | + { 0x3669, 0x1a }, | |
| 286 | + { 0x366a, 0x00 }, | |
| 287 | + { 0x366b, 0x50 }, | |
| 288 | + { 0x3673, 0x01 }, | |
| 289 | + { 0x3674, 0xff }, | |
| 290 | + { 0x3675, 0x03 }, | |
| 291 | + { 0x3705, 0xc1 }, | |
| 292 | + { 0x3709, 0x40 }, | |
| 293 | + { 0x373c, 0x08 }, | |
| 294 | + { 0x3742, 0x00 }, | |
| 295 | + { 0x3757, 0xb3 }, | |
| 296 | + { 0x3788, 0x00 }, | |
| 297 | + { 0x37a8, 0x01 }, | |
| 298 | + { 0x37a9, 0xc0 }, | |
| 299 | + { 0x3800, 0x00 }, | |
| 300 | + { 0x3801, 0x04 }, | |
| 301 | + { 0x3802, 0x00 }, | |
| 302 | + { 0x3803, 0x04 }, | |
| 303 | + { 0x3804, 0x02 }, | |
| 304 | + { 0x3805, 0x8b }, | |
| 305 | + { 0x3806, 0x01 }, | |
| 306 | + { 0x3807, 0xeb }, | |
| 307 | + { 0x3808, 0x02 }, /* width high */ | |
| 308 | + { 0x3809, 0x80 }, /* width low */ | |
| 309 | + { 0x380a, 0x01 }, /* height high */ | |
| 310 | + { 0x380b, 0xe0 }, /* height low */ | |
| 311 | + { 0x380c, 0x03 }, /* total horiz timing high */ | |
| 312 | + { 0x380d, 0xa0 }, /* total horiz timing low */ | |
| 313 | + { 0x380e, 0x03 }, /* total vertical timing high */ | |
| 314 | + { 0x380f, 0x5c }, /* total vertical timing low */ | |
| 315 | + { 0x3810, 0x00 }, | |
| 316 | + { 0x3811, 0x04 }, | |
| 317 | + { 0x3812, 0x00 }, | |
| 318 | + { 0x3813, 0x05 }, | |
| 319 | + { 0x3814, 0x11 }, | |
| 320 | + { 0x3815, 0x11 }, | |
| 321 | + { 0x3820, 0x40 }, | |
| 322 | + { 0x3821, 0x00 }, | |
| 323 | + { 0x382f, 0x0e }, | |
| 324 | + { 0x3832, 0x00 }, | |
| 325 | + { 0x3833, 0x05 }, | |
| 326 | + { 0x3834, 0x00 }, | |
| 327 | + { 0x3835, 0x0c }, | |
| 328 | + { 0x3837, 0x00 }, | |
| 329 | + { 0x3b80, 0x00 }, | |
| 330 | + { 0x3b81, 0xa5 }, | |
| 331 | + { 0x3b82, 0x10 }, | |
| 332 | + { 0x3b83, 0x00 }, | |
| 333 | + { 0x3b84, 0x08 }, | |
| 334 | + { 0x3b85, 0x00 }, | |
| 335 | + { 0x3b86, 0x01 }, | |
| 336 | + { 0x3b87, 0x00 }, | |
| 337 | + { 0x3b88, 0x00 }, | |
| 338 | + { 0x3b89, 0x00 }, | |
| 339 | + { 0x3b8a, 0x00 }, | |
| 340 | + { 0x3b8b, 0x05 }, | |
| 341 | + { 0x3b8c, 0x00 }, | |
| 342 | + { 0x3b8d, 0x00 }, | |
| 343 | + { 0x3b8e, 0x00 }, | |
| 344 | + { 0x3b8f, 0x1a }, | |
| 345 | + { 0x3b94, 0x05 }, | |
| 346 | + { 0x3b95, 0xf2 }, | |
| 347 | + { 0x3b96, 0x40 }, | |
| 348 | + { 0x3c00, 0x89 }, | |
| 349 | + { 0x3c01, 0x63 }, | |
| 350 | + { 0x3c02, 0x01 }, | |
| 351 | + { 0x3c03, 0x00 }, | |
| 352 | + { 0x3c04, 0x00 }, | |
| 353 | + { 0x3c05, 0x03 }, | |
| 354 | + { 0x3c06, 0x00 }, | |
| 355 | + { 0x3c07, 0x06 }, | |
| 356 | + { 0x3c0c, 0x01 }, | |
| 357 | + { 0x3c0d, 0xd0 }, | |
| 358 | + { 0x3c0e, 0x02 }, | |
| 359 | + { 0x3c0f, 0x0a }, | |
| 360 | + { 0x4001, 0x42 }, | |
| 361 | + { 0x4004, 0x04 }, | |
| 362 | + { 0x4005, 0x00 }, | |
| 363 | + { 0x404e, 0x01 }, | |
| 364 | + { 0x4300, 0xff }, | |
| 365 | + { 0x4301, 0x00 }, | |
| 366 | + { 0x4315, 0x00 }, | |
| 367 | + { 0x4501, 0x48 }, | |
| 368 | + { 0x4600, 0x00 }, | |
| 369 | + { 0x4601, 0x4e }, | |
| 370 | + { 0x4801, 0x0f }, | |
| 371 | + { 0x4806, 0x0f }, | |
| 372 | + { 0x4819, 0xaa }, | |
| 373 | + { 0x4823, 0x3e }, | |
| 374 | + { 0x4837, 0x19 }, | |
| 375 | + { 0x4a0d, 0x00 }, | |
| 376 | + { 0x4a47, 0x7f }, | |
| 377 | + { 0x4a49, 0xf0 }, | |
| 378 | + { 0x4a4b, 0x30 }, | |
| 379 | + { 0x5000, 0x85 }, | |
| 380 | + { 0x5001, 0x80 }, | |
| 381 | +}; | |
| 382 | + | |
| 383 | +static const struct reg_value ov7251_setting_vga_90fps[] = { | |
| 384 | + { 0x3005, 0x00 }, | |
| 385 | + { 0x3012, 0xc0 }, | |
| 386 | + { 0x3013, 0xd2 }, | |
| 387 | + { 0x3014, 0x04 }, | |
| 388 | + { 0x3016, 0x10 }, | |
| 389 | + { 0x3017, 0x00 }, | |
| 390 | + { 0x3018, 0x00 }, | |
| 391 | + { 0x301a, 0x00 }, | |
| 392 | + { 0x301b, 0x00 }, | |
| 393 | + { 0x301c, 0x00 }, | |
| 394 | + { 0x3023, 0x05 }, | |
| 395 | + { 0x3037, 0xf0 }, | |
| 396 | + { 0x3098, 0x04 }, /* pll2 pre divider */ | |
| 397 | + { 0x3099, 0x28 }, /* pll2 multiplier */ | |
| 398 | + { 0x309a, 0x05 }, /* pll2 sys divider */ | |
| 399 | + { 0x309b, 0x04 }, /* pll2 adc divider */ | |
| 400 | + { 0x309d, 0x00 }, /* pll2 divider */ | |
| 401 | + { 0x30b0, 0x0a }, /* pll1 pix divider */ | |
| 402 | + { 0x30b1, 0x01 }, /* pll1 divider */ | |
| 403 | + { 0x30b3, 0x64 }, /* pll1 multiplier */ | |
| 404 | + { 0x30b4, 0x03 }, /* pll1 pre divider */ | |
| 405 | + { 0x30b5, 0x05 }, /* pll1 mipi divider */ | |
| 406 | + { 0x3106, 0xda }, | |
| 407 | + { 0x3503, 0x07 }, | |
| 408 | + { 0x3509, 0x10 }, | |
| 409 | + { 0x3600, 0x1c }, | |
| 410 | + { 0x3602, 0x62 }, | |
| 411 | + { 0x3620, 0xb7 }, | |
| 412 | + { 0x3622, 0x04 }, | |
| 413 | + { 0x3626, 0x21 }, | |
| 414 | + { 0x3627, 0x30 }, | |
| 415 | + { 0x3630, 0x44 }, | |
| 416 | + { 0x3631, 0x35 }, | |
| 417 | + { 0x3634, 0x60 }, | |
| 418 | + { 0x3636, 0x00 }, | |
| 419 | + { 0x3662, 0x01 }, | |
| 420 | + { 0x3663, 0x70 }, | |
| 421 | + { 0x3664, 0x50 }, | |
| 422 | + { 0x3666, 0x0a }, | |
| 423 | + { 0x3669, 0x1a }, | |
| 424 | + { 0x366a, 0x00 }, | |
| 425 | + { 0x366b, 0x50 }, | |
| 426 | + { 0x3673, 0x01 }, | |
| 427 | + { 0x3674, 0xff }, | |
| 428 | + { 0x3675, 0x03 }, | |
| 429 | + { 0x3705, 0xc1 }, | |
| 430 | + { 0x3709, 0x40 }, | |
| 431 | + { 0x373c, 0x08 }, | |
| 432 | + { 0x3742, 0x00 }, | |
| 433 | + { 0x3757, 0xb3 }, | |
| 434 | + { 0x3788, 0x00 }, | |
| 435 | + { 0x37a8, 0x01 }, | |
| 436 | + { 0x37a9, 0xc0 }, | |
| 437 | + { 0x3800, 0x00 }, | |
| 438 | + { 0x3801, 0x04 }, | |
| 439 | + { 0x3802, 0x00 }, | |
| 440 | + { 0x3803, 0x04 }, | |
| 441 | + { 0x3804, 0x02 }, | |
| 442 | + { 0x3805, 0x8b }, | |
| 443 | + { 0x3806, 0x01 }, | |
| 444 | + { 0x3807, 0xeb }, | |
| 445 | + { 0x3808, 0x02 }, /* width high */ | |
| 446 | + { 0x3809, 0x80 }, /* width low */ | |
| 447 | + { 0x380a, 0x01 }, /* height high */ | |
| 448 | + { 0x380b, 0xe0 }, /* height low */ | |
| 449 | + { 0x380c, 0x03 }, /* total horiz timing high */ | |
| 450 | + { 0x380d, 0xa0 }, /* total horiz timing low */ | |
| 451 | + { 0x380e, 0x02 }, /* total vertical timing high */ | |
| 452 | + { 0x380f, 0x3c }, /* total vertical timing low */ | |
| 453 | + { 0x3810, 0x00 }, | |
| 454 | + { 0x3811, 0x04 }, | |
| 455 | + { 0x3812, 0x00 }, | |
| 456 | + { 0x3813, 0x05 }, | |
| 457 | + { 0x3814, 0x11 }, | |
| 458 | + { 0x3815, 0x11 }, | |
| 459 | + { 0x3820, 0x40 }, | |
| 460 | + { 0x3821, 0x00 }, | |
| 461 | + { 0x382f, 0x0e }, | |
| 462 | + { 0x3832, 0x00 }, | |
| 463 | + { 0x3833, 0x05 }, | |
| 464 | + { 0x3834, 0x00 }, | |
| 465 | + { 0x3835, 0x0c }, | |
| 466 | + { 0x3837, 0x00 }, | |
| 467 | + { 0x3b80, 0x00 }, | |
| 468 | + { 0x3b81, 0xa5 }, | |
| 469 | + { 0x3b82, 0x10 }, | |
| 470 | + { 0x3b83, 0x00 }, | |
| 471 | + { 0x3b84, 0x08 }, | |
| 472 | + { 0x3b85, 0x00 }, | |
| 473 | + { 0x3b86, 0x01 }, | |
| 474 | + { 0x3b87, 0x00 }, | |
| 475 | + { 0x3b88, 0x00 }, | |
| 476 | + { 0x3b89, 0x00 }, | |
| 477 | + { 0x3b8a, 0x00 }, | |
| 478 | + { 0x3b8b, 0x05 }, | |
| 479 | + { 0x3b8c, 0x00 }, | |
| 480 | + { 0x3b8d, 0x00 }, | |
| 481 | + { 0x3b8e, 0x00 }, | |
| 482 | + { 0x3b8f, 0x1a }, | |
| 483 | + { 0x3b94, 0x05 }, | |
| 484 | + { 0x3b95, 0xf2 }, | |
| 485 | + { 0x3b96, 0x40 }, | |
| 486 | + { 0x3c00, 0x89 }, | |
| 487 | + { 0x3c01, 0x63 }, | |
| 488 | + { 0x3c02, 0x01 }, | |
| 489 | + { 0x3c03, 0x00 }, | |
| 490 | + { 0x3c04, 0x00 }, | |
| 491 | + { 0x3c05, 0x03 }, | |
| 492 | + { 0x3c06, 0x00 }, | |
| 493 | + { 0x3c07, 0x06 }, | |
| 494 | + { 0x3c0c, 0x01 }, | |
| 495 | + { 0x3c0d, 0xd0 }, | |
| 496 | + { 0x3c0e, 0x02 }, | |
| 497 | + { 0x3c0f, 0x0a }, | |
| 498 | + { 0x4001, 0x42 }, | |
| 499 | + { 0x4004, 0x04 }, | |
| 500 | + { 0x4005, 0x00 }, | |
| 501 | + { 0x404e, 0x01 }, | |
| 502 | + { 0x4300, 0xff }, | |
| 503 | + { 0x4301, 0x00 }, | |
| 504 | + { 0x4315, 0x00 }, | |
| 505 | + { 0x4501, 0x48 }, | |
| 506 | + { 0x4600, 0x00 }, | |
| 507 | + { 0x4601, 0x4e }, | |
| 508 | + { 0x4801, 0x0f }, | |
| 509 | + { 0x4806, 0x0f }, | |
| 510 | + { 0x4819, 0xaa }, | |
| 511 | + { 0x4823, 0x3e }, | |
| 512 | + { 0x4837, 0x19 }, | |
| 513 | + { 0x4a0d, 0x00 }, | |
| 514 | + { 0x4a47, 0x7f }, | |
| 515 | + { 0x4a49, 0xf0 }, | |
| 516 | + { 0x4a4b, 0x30 }, | |
| 517 | + { 0x5000, 0x85 }, | |
| 518 | + { 0x5001, 0x80 }, | |
| 519 | +}; | |
| 520 | + | |
| 521 | +static const s64 link_freq[] = { | |
| 522 | + 240000000, | |
| 523 | +}; | |
| 524 | + | |
| 525 | +static const struct ov7251_mode_info ov7251_mode_info_data[] = { | |
| 526 | + { | |
| 527 | + .width = 640, | |
| 528 | + .height = 480, | |
| 529 | + .data = ov7251_setting_vga_30fps, | |
| 530 | + .data_size = ARRAY_SIZE(ov7251_setting_vga_30fps), | |
| 531 | + .pixel_clock = 48000000, | |
| 532 | + .link_freq = 0, /* an index in link_freq[] */ | |
| 533 | + .exposure_max = 1704, | |
| 534 | + .exposure_def = 504, | |
| 535 | + .timeperframe = { | |
| 536 | + .numerator = 100, | |
| 537 | + .denominator = 3000 | |
| 538 | + } | |
| 539 | + }, | |
| 540 | + { | |
| 541 | + .width = 640, | |
| 542 | + .height = 480, | |
| 543 | + .data = ov7251_setting_vga_60fps, | |
| 544 | + .data_size = ARRAY_SIZE(ov7251_setting_vga_60fps), | |
| 545 | + .pixel_clock = 48000000, | |
| 546 | + .link_freq = 0, /* an index in link_freq[] */ | |
| 547 | + .exposure_max = 840, | |
| 548 | + .exposure_def = 504, | |
| 549 | + .timeperframe = { | |
| 550 | + .numerator = 100, | |
| 551 | + .denominator = 6014 | |
| 552 | + } | |
| 553 | + }, | |
| 554 | + { | |
| 555 | + .width = 640, | |
| 556 | + .height = 480, | |
| 557 | + .data = ov7251_setting_vga_90fps, | |
| 558 | + .data_size = ARRAY_SIZE(ov7251_setting_vga_90fps), | |
| 559 | + .pixel_clock = 48000000, | |
| 560 | + .link_freq = 0, /* an index in link_freq[] */ | |
| 561 | + .exposure_max = 552, | |
| 562 | + .exposure_def = 504, | |
| 563 | + .timeperframe = { | |
| 564 | + .numerator = 100, | |
| 565 | + .denominator = 9043 | |
| 566 | + } | |
| 567 | + }, | |
| 568 | +}; | |
| 569 | + | |
| 570 | +static int ov7251_regulators_enable(struct ov7251 *ov7251) | |
| 571 | +{ | |
| 572 | + int ret; | |
| 573 | + | |
| 574 | + /* OV7251 power up sequence requires core regulator | |
| 575 | + * to be enabled not earlier than io regulator | |
| 576 | + */ | |
| 577 | + | |
| 578 | + ret = regulator_enable(ov7251->io_regulator); | |
| 579 | + if (ret < 0) { | |
| 580 | + dev_err(ov7251->dev, "set io voltage failed\n"); | |
| 581 | + return ret; | |
| 582 | + } | |
| 583 | + | |
| 584 | + ret = regulator_enable(ov7251->analog_regulator); | |
| 585 | + if (ret) { | |
| 586 | + dev_err(ov7251->dev, "set analog voltage failed\n"); | |
| 587 | + goto err_disable_io; | |
| 588 | + } | |
| 589 | + | |
| 590 | + ret = regulator_enable(ov7251->core_regulator); | |
| 591 | + if (ret) { | |
| 592 | + dev_err(ov7251->dev, "set core voltage failed\n"); | |
| 593 | + goto err_disable_analog; | |
| 594 | + } | |
| 595 | + | |
| 596 | + return 0; | |
| 597 | + | |
| 598 | +err_disable_analog: | |
| 599 | + regulator_disable(ov7251->analog_regulator); | |
| 600 | + | |
| 601 | +err_disable_io: | |
| 602 | + regulator_disable(ov7251->io_regulator); | |
| 603 | + | |
| 604 | + return ret; | |
| 605 | +} | |
| 606 | + | |
| 607 | +static void ov7251_regulators_disable(struct ov7251 *ov7251) | |
| 608 | +{ | |
| 609 | + int ret; | |
| 610 | + | |
| 611 | + ret = regulator_disable(ov7251->core_regulator); | |
| 612 | + if (ret < 0) | |
| 613 | + dev_err(ov7251->dev, "core regulator disable failed\n"); | |
| 614 | + | |
| 615 | + ret = regulator_disable(ov7251->analog_regulator); | |
| 616 | + if (ret < 0) | |
| 617 | + dev_err(ov7251->dev, "analog regulator disable failed\n"); | |
| 618 | + | |
| 619 | + ret = regulator_disable(ov7251->io_regulator); | |
| 620 | + if (ret < 0) | |
| 621 | + dev_err(ov7251->dev, "io regulator disable failed\n"); | |
| 622 | +} | |
| 623 | + | |
| 624 | +static int ov7251_write_reg(struct ov7251 *ov7251, u16 reg, u8 val) | |
| 625 | +{ | |
| 626 | + u8 regbuf[3]; | |
| 627 | + int ret; | |
| 628 | + | |
| 629 | + regbuf[0] = reg >> 8; | |
| 630 | + regbuf[1] = reg & 0xff; | |
| 631 | + regbuf[2] = val; | |
| 632 | + | |
| 633 | + ret = i2c_master_send(ov7251->i2c_client, regbuf, 3); | |
| 634 | + if (ret < 0) { | |
| 635 | + dev_err(ov7251->dev, "%s: write reg error %d: reg=%x, val=%x\n", | |
| 636 | + __func__, ret, reg, val); | |
| 637 | + return ret; | |
| 638 | + } | |
| 639 | + | |
| 640 | + return 0; | |
| 641 | +} | |
| 642 | + | |
| 643 | +static int ov7251_write_seq_regs(struct ov7251 *ov7251, u16 reg, u8 *val, | |
| 644 | + u8 num) | |
| 645 | +{ | |
| 646 | + u8 regbuf[5]; | |
| 647 | + u8 nregbuf = sizeof(reg) + num * sizeof(*val); | |
| 648 | + int ret = 0; | |
| 649 | + | |
| 650 | + if (nregbuf > sizeof(regbuf)) | |
| 651 | + return -EINVAL; | |
| 652 | + | |
| 653 | + regbuf[0] = reg >> 8; | |
| 654 | + regbuf[1] = reg & 0xff; | |
| 655 | + | |
| 656 | + memcpy(regbuf + 2, val, num); | |
| 657 | + | |
| 658 | + ret = i2c_master_send(ov7251->i2c_client, regbuf, nregbuf); | |
| 659 | + if (ret < 0) { | |
| 660 | + dev_err(ov7251->dev, | |
| 661 | + "%s: write seq regs error %d: first reg=%x\n", | |
| 662 | + __func__, ret, reg); | |
| 663 | + return ret; | |
| 664 | + } | |
| 665 | + | |
| 666 | + return 0; | |
| 667 | +} | |
| 668 | + | |
| 669 | +static int ov7251_read_reg(struct ov7251 *ov7251, u16 reg, u8 *val) | |
| 670 | +{ | |
| 671 | + u8 regbuf[2]; | |
| 672 | + int ret; | |
| 673 | + | |
| 674 | + regbuf[0] = reg >> 8; | |
| 675 | + regbuf[1] = reg & 0xff; | |
| 676 | + | |
| 677 | + ret = i2c_master_send(ov7251->i2c_client, regbuf, 2); | |
| 678 | + if (ret < 0) { | |
| 679 | + dev_err(ov7251->dev, "%s: write reg error %d: reg=%x\n", | |
| 680 | + __func__, ret, reg); | |
| 681 | + return ret; | |
| 682 | + } | |
| 683 | + | |
| 684 | + ret = i2c_master_recv(ov7251->i2c_client, val, 1); | |
| 685 | + if (ret < 0) { | |
| 686 | + dev_err(ov7251->dev, "%s: read reg error %d: reg=%x\n", | |
| 687 | + __func__, ret, reg); | |
| 688 | + return ret; | |
| 689 | + } | |
| 690 | + | |
| 691 | + return 0; | |
| 692 | +} | |
| 693 | + | |
| 694 | +static int ov7251_set_exposure(struct ov7251 *ov7251, s32 exposure) | |
| 695 | +{ | |
| 696 | + u16 reg; | |
| 697 | + u8 val[3]; | |
| 698 | + | |
| 699 | + reg = OV7251_AEC_EXPO_0; | |
| 700 | + val[0] = (exposure & 0xf000) >> 12; /* goes to OV7251_AEC_EXPO_0 */ | |
| 701 | + val[1] = (exposure & 0x0ff0) >> 4; /* goes to OV7251_AEC_EXPO_1 */ | |
| 702 | + val[2] = (exposure & 0x000f) << 4; /* goes to OV7251_AEC_EXPO_2 */ | |
| 703 | + | |
| 704 | + return ov7251_write_seq_regs(ov7251, reg, val, 3); | |
| 705 | +} | |
| 706 | + | |
| 707 | +static int ov7251_set_gain(struct ov7251 *ov7251, s32 gain) | |
| 708 | +{ | |
| 709 | + u16 reg; | |
| 710 | + u8 val[2]; | |
| 711 | + | |
| 712 | + reg = OV7251_AEC_AGC_ADJ_0; | |
| 713 | + val[0] = (gain & 0x0300) >> 8; /* goes to OV7251_AEC_AGC_ADJ_0 */ | |
| 714 | + val[1] = gain & 0xff; /* goes to OV7251_AEC_AGC_ADJ_1 */ | |
| 715 | + | |
| 716 | + return ov7251_write_seq_regs(ov7251, reg, val, 2); | |
| 717 | +} | |
| 718 | + | |
| 719 | +static int ov7251_set_register_array(struct ov7251 *ov7251, | |
| 720 | + const struct reg_value *settings, | |
| 721 | + unsigned int num_settings) | |
| 722 | +{ | |
| 723 | + unsigned int i; | |
| 724 | + int ret; | |
| 725 | + | |
| 726 | + for (i = 0; i < num_settings; ++i, ++settings) { | |
| 727 | + ret = ov7251_write_reg(ov7251, settings->reg, settings->val); | |
| 728 | + if (ret < 0) | |
| 729 | + return ret; | |
| 730 | + } | |
| 731 | + | |
| 732 | + return 0; | |
| 733 | +} | |
| 734 | + | |
| 735 | +static int ov7251_set_power_on(struct ov7251 *ov7251) | |
| 736 | +{ | |
| 737 | + int ret; | |
| 738 | + u32 wait_us; | |
| 739 | + | |
| 740 | + ret = ov7251_regulators_enable(ov7251); | |
| 741 | + if (ret < 0) | |
| 742 | + return ret; | |
| 743 | + | |
| 744 | + ret = clk_prepare_enable(ov7251->xclk); | |
| 745 | + if (ret < 0) { | |
| 746 | + dev_err(ov7251->dev, "clk prepare enable failed\n"); | |
| 747 | + ov7251_regulators_disable(ov7251); | |
| 748 | + return ret; | |
| 749 | + } | |
| 750 | + | |
| 751 | + gpiod_set_value_cansleep(ov7251->enable_gpio, 1); | |
| 752 | + | |
| 753 | + /* wait at least 65536 external clock cycles */ | |
| 754 | + wait_us = DIV_ROUND_UP(65536 * 1000, | |
| 755 | + DIV_ROUND_UP(ov7251->xclk_freq, 1000)); | |
| 756 | + usleep_range(wait_us, wait_us + 1000); | |
| 757 | + | |
| 758 | + return 0; | |
| 759 | +} | |
| 760 | + | |
| 761 | +static void ov7251_set_power_off(struct ov7251 *ov7251) | |
| 762 | +{ | |
| 763 | + clk_disable_unprepare(ov7251->xclk); | |
| 764 | + gpiod_set_value_cansleep(ov7251->enable_gpio, 0); | |
| 765 | + ov7251_regulators_disable(ov7251); | |
| 766 | +} | |
| 767 | + | |
| 768 | +static int ov7251_s_power(struct v4l2_subdev *sd, int on) | |
| 769 | +{ | |
| 770 | + struct ov7251 *ov7251 = to_ov7251(sd); | |
| 771 | + int ret = 0; | |
| 772 | + | |
| 773 | + mutex_lock(&ov7251->lock); | |
| 774 | + | |
| 775 | + /* If the power state is not modified - no work to do. */ | |
| 776 | + if (ov7251->power_on == !!on) | |
| 777 | + goto exit; | |
| 778 | + | |
| 779 | + if (on) { | |
| 780 | + ret = ov7251_set_power_on(ov7251); | |
| 781 | + if (ret < 0) | |
| 782 | + goto exit; | |
| 783 | + | |
| 784 | + ret = ov7251_set_register_array(ov7251, | |
| 785 | + ov7251_global_init_setting, | |
| 786 | + ARRAY_SIZE(ov7251_global_init_setting)); | |
| 787 | + if (ret < 0) { | |
| 788 | + dev_err(ov7251->dev, "could not set init registers\n"); | |
| 789 | + ov7251_set_power_off(ov7251); | |
| 790 | + goto exit; | |
| 791 | + } | |
| 792 | + | |
| 793 | + ov7251->power_on = true; | |
| 794 | + } else { | |
| 795 | + ov7251_set_power_off(ov7251); | |
| 796 | + ov7251->power_on = false; | |
| 797 | + } | |
| 798 | + | |
| 799 | +exit: | |
| 800 | + mutex_unlock(&ov7251->lock); | |
| 801 | + | |
| 802 | + return ret; | |
| 803 | +} | |
| 804 | + | |
| 805 | +static int ov7251_set_hflip(struct ov7251 *ov7251, s32 value) | |
| 806 | +{ | |
| 807 | + u8 val = ov7251->timing_format2; | |
| 808 | + int ret; | |
| 809 | + | |
| 810 | + if (value) | |
| 811 | + val |= OV7251_TIMING_FORMAT2_MIRROR; | |
| 812 | + else | |
| 813 | + val &= ~OV7251_TIMING_FORMAT2_MIRROR; | |
| 814 | + | |
| 815 | + ret = ov7251_write_reg(ov7251, OV7251_TIMING_FORMAT2, val); | |
| 816 | + if (!ret) | |
| 817 | + ov7251->timing_format2 = val; | |
| 818 | + | |
| 819 | + return ret; | |
| 820 | +} | |
| 821 | + | |
| 822 | +static int ov7251_set_vflip(struct ov7251 *ov7251, s32 value) | |
| 823 | +{ | |
| 824 | + u8 val = ov7251->timing_format1; | |
| 825 | + int ret; | |
| 826 | + | |
| 827 | + if (value) | |
| 828 | + val |= OV7251_TIMING_FORMAT1_VFLIP; | |
| 829 | + else | |
| 830 | + val &= ~OV7251_TIMING_FORMAT1_VFLIP; | |
| 831 | + | |
| 832 | + ret = ov7251_write_reg(ov7251, OV7251_TIMING_FORMAT1, val); | |
| 833 | + if (!ret) | |
| 834 | + ov7251->timing_format1 = val; | |
| 835 | + | |
| 836 | + return ret; | |
| 837 | +} | |
| 838 | + | |
| 839 | +static int ov7251_set_test_pattern(struct ov7251 *ov7251, s32 value) | |
| 840 | +{ | |
| 841 | + u8 val = ov7251->pre_isp_00; | |
| 842 | + int ret; | |
| 843 | + | |
| 844 | + if (value) | |
| 845 | + val |= OV7251_PRE_ISP_00_TEST_PATTERN; | |
| 846 | + else | |
| 847 | + val &= ~OV7251_PRE_ISP_00_TEST_PATTERN; | |
| 848 | + | |
| 849 | + ret = ov7251_write_reg(ov7251, OV7251_PRE_ISP_00, val); | |
| 850 | + if (!ret) | |
| 851 | + ov7251->pre_isp_00 = val; | |
| 852 | + | |
| 853 | + return ret; | |
| 854 | +} | |
| 855 | + | |
| 856 | +static const char * const ov7251_test_pattern_menu[] = { | |
| 857 | + "Disabled", | |
| 858 | + "Vertical Pattern Bars", | |
| 859 | +}; | |
| 860 | + | |
| 861 | +static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 862 | +{ | |
| 863 | + struct ov7251 *ov7251 = container_of(ctrl->handler, | |
| 864 | + struct ov7251, ctrls); | |
| 865 | + int ret; | |
| 866 | + | |
| 867 | + /* v4l2_ctrl_lock() locks our mutex */ | |
| 868 | + | |
| 869 | + if (!ov7251->power_on) | |
| 870 | + return 0; | |
| 871 | + | |
| 872 | + switch (ctrl->id) { | |
| 873 | + case V4L2_CID_EXPOSURE: | |
| 874 | + ret = ov7251_set_exposure(ov7251, ctrl->val); | |
| 875 | + break; | |
| 876 | + case V4L2_CID_GAIN: | |
| 877 | + ret = ov7251_set_gain(ov7251, ctrl->val); | |
| 878 | + break; | |
| 879 | + case V4L2_CID_TEST_PATTERN: | |
| 880 | + ret = ov7251_set_test_pattern(ov7251, ctrl->val); | |
| 881 | + break; | |
| 882 | + case V4L2_CID_HFLIP: | |
| 883 | + ret = ov7251_set_hflip(ov7251, ctrl->val); | |
| 884 | + break; | |
| 885 | + case V4L2_CID_VFLIP: | |
| 886 | + ret = ov7251_set_vflip(ov7251, ctrl->val); | |
| 887 | + break; | |
| 888 | + default: | |
| 889 | + ret = -EINVAL; | |
| 890 | + break; | |
| 891 | + } | |
| 892 | + | |
| 893 | + return ret; | |
| 894 | +} | |
| 895 | + | |
| 896 | +static const struct v4l2_ctrl_ops ov7251_ctrl_ops = { | |
| 897 | + .s_ctrl = ov7251_s_ctrl, | |
| 898 | +}; | |
| 899 | + | |
| 900 | +static int ov7251_enum_mbus_code(struct v4l2_subdev *sd, | |
| 901 | + struct v4l2_subdev_pad_config *cfg, | |
| 902 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 903 | +{ | |
| 904 | + if (code->index > 0) | |
| 905 | + return -EINVAL; | |
| 906 | + | |
| 907 | + code->code = MEDIA_BUS_FMT_Y10_1X10; | |
| 908 | + | |
| 909 | + return 0; | |
| 910 | +} | |
| 911 | + | |
| 912 | +static int ov7251_enum_frame_size(struct v4l2_subdev *subdev, | |
| 913 | + struct v4l2_subdev_pad_config *cfg, | |
| 914 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 915 | +{ | |
| 916 | + if (fse->code != MEDIA_BUS_FMT_Y10_1X10) | |
| 917 | + return -EINVAL; | |
| 918 | + | |
| 919 | + if (fse->index >= ARRAY_SIZE(ov7251_mode_info_data)) | |
| 920 | + return -EINVAL; | |
| 921 | + | |
| 922 | + fse->min_width = ov7251_mode_info_data[fse->index].width; | |
| 923 | + fse->max_width = ov7251_mode_info_data[fse->index].width; | |
| 924 | + fse->min_height = ov7251_mode_info_data[fse->index].height; | |
| 925 | + fse->max_height = ov7251_mode_info_data[fse->index].height; | |
| 926 | + | |
| 927 | + return 0; | |
| 928 | +} | |
| 929 | + | |
| 930 | +static int ov7251_enum_frame_ival(struct v4l2_subdev *subdev, | |
| 931 | + struct v4l2_subdev_pad_config *cfg, | |
| 932 | + struct v4l2_subdev_frame_interval_enum *fie) | |
| 933 | +{ | |
| 934 | + unsigned int index = fie->index; | |
| 935 | + unsigned int i; | |
| 936 | + | |
| 937 | + for (i = 0; i < ARRAY_SIZE(ov7251_mode_info_data); i++) { | |
| 938 | + if (fie->width != ov7251_mode_info_data[i].width || | |
| 939 | + fie->height != ov7251_mode_info_data[i].height) | |
| 940 | + continue; | |
| 941 | + | |
| 942 | + if (index-- == 0) { | |
| 943 | + fie->interval = ov7251_mode_info_data[i].timeperframe; | |
| 944 | + return 0; | |
| 945 | + } | |
| 946 | + } | |
| 947 | + | |
| 948 | + return -EINVAL; | |
| 949 | +} | |
| 950 | + | |
| 951 | +static struct v4l2_mbus_framefmt * | |
| 952 | +__ov7251_get_pad_format(struct ov7251 *ov7251, | |
| 953 | + struct v4l2_subdev_pad_config *cfg, | |
| 954 | + unsigned int pad, | |
| 955 | + enum v4l2_subdev_format_whence which) | |
| 956 | +{ | |
| 957 | + switch (which) { | |
| 958 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 959 | + return v4l2_subdev_get_try_format(&ov7251->sd, cfg, pad); | |
| 960 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 961 | + return &ov7251->fmt; | |
| 962 | + default: | |
| 963 | + return NULL; | |
| 964 | + } | |
| 965 | +} | |
| 966 | + | |
| 967 | +static int ov7251_get_format(struct v4l2_subdev *sd, | |
| 968 | + struct v4l2_subdev_pad_config *cfg, | |
| 969 | + struct v4l2_subdev_format *format) | |
| 970 | +{ | |
| 971 | + struct ov7251 *ov7251 = to_ov7251(sd); | |
| 972 | + | |
| 973 | + mutex_lock(&ov7251->lock); | |
| 974 | + format->format = *__ov7251_get_pad_format(ov7251, cfg, format->pad, | |
| 975 | + format->which); | |
| 976 | + mutex_unlock(&ov7251->lock); | |
| 977 | + | |
| 978 | + return 0; | |
| 979 | +} | |
| 980 | + | |
| 981 | +static struct v4l2_rect * | |
| 982 | +__ov7251_get_pad_crop(struct ov7251 *ov7251, struct v4l2_subdev_pad_config *cfg, | |
| 983 | + unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 984 | +{ | |
| 985 | + switch (which) { | |
| 986 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 987 | + return v4l2_subdev_get_try_crop(&ov7251->sd, cfg, pad); | |
| 988 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 989 | + return &ov7251->crop; | |
| 990 | + default: | |
| 991 | + return NULL; | |
| 992 | + } | |
| 993 | +} | |
| 994 | + | |
| 995 | +static inline u32 avg_fps(const struct v4l2_fract *t) | |
| 996 | +{ | |
| 997 | + return (t->denominator + (t->numerator >> 1)) / t->numerator; | |
| 998 | +} | |
| 999 | + | |
| 1000 | +static const struct ov7251_mode_info * | |
| 1001 | +ov7251_find_mode_by_ival(struct ov7251 *ov7251, struct v4l2_fract *timeperframe) | |
| 1002 | +{ | |
| 1003 | + const struct ov7251_mode_info *mode = ov7251->current_mode; | |
| 1004 | + unsigned int fps_req = avg_fps(timeperframe); | |
| 1005 | + unsigned int max_dist_match = (unsigned int) -1; | |
| 1006 | + unsigned int i, n = 0; | |
| 1007 | + | |
| 1008 | + for (i = 0; i < ARRAY_SIZE(ov7251_mode_info_data); i++) { | |
| 1009 | + unsigned int dist; | |
| 1010 | + unsigned int fps_tmp; | |
| 1011 | + | |
| 1012 | + if (mode->width != ov7251_mode_info_data[i].width || | |
| 1013 | + mode->height != ov7251_mode_info_data[i].height) | |
| 1014 | + continue; | |
| 1015 | + | |
| 1016 | + fps_tmp = avg_fps(&ov7251_mode_info_data[i].timeperframe); | |
| 1017 | + | |
| 1018 | + dist = abs(fps_req - fps_tmp); | |
| 1019 | + | |
| 1020 | + if (dist < max_dist_match) { | |
| 1021 | + n = i; | |
| 1022 | + max_dist_match = dist; | |
| 1023 | + } | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + return &ov7251_mode_info_data[n]; | |
| 1027 | +} | |
| 1028 | + | |
| 1029 | +static int ov7251_set_format(struct v4l2_subdev *sd, | |
| 1030 | + struct v4l2_subdev_pad_config *cfg, | |
| 1031 | + struct v4l2_subdev_format *format) | |
| 1032 | +{ | |
| 1033 | + struct ov7251 *ov7251 = to_ov7251(sd); | |
| 1034 | + struct v4l2_mbus_framefmt *__format; | |
| 1035 | + struct v4l2_rect *__crop; | |
| 1036 | + const struct ov7251_mode_info *new_mode; | |
| 1037 | + int ret = 0; | |
| 1038 | + | |
| 1039 | + mutex_lock(&ov7251->lock); | |
| 1040 | + | |
| 1041 | + __crop = __ov7251_get_pad_crop(ov7251, cfg, format->pad, format->which); | |
| 1042 | + | |
| 1043 | + new_mode = v4l2_find_nearest_size(ov7251_mode_info_data, | |
| 1044 | + ARRAY_SIZE(ov7251_mode_info_data), | |
| 1045 | + width, height, | |
| 1046 | + format->format.width, format->format.height); | |
| 1047 | + | |
| 1048 | + __crop->width = new_mode->width; | |
| 1049 | + __crop->height = new_mode->height; | |
| 1050 | + | |
| 1051 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 1052 | + ret = __v4l2_ctrl_s_ctrl_int64(ov7251->pixel_clock, | |
| 1053 | + new_mode->pixel_clock); | |
| 1054 | + if (ret < 0) | |
| 1055 | + goto exit; | |
| 1056 | + | |
| 1057 | + ret = __v4l2_ctrl_s_ctrl(ov7251->link_freq, | |
| 1058 | + new_mode->link_freq); | |
| 1059 | + if (ret < 0) | |
| 1060 | + goto exit; | |
| 1061 | + | |
| 1062 | + ret = __v4l2_ctrl_modify_range(ov7251->exposure, | |
| 1063 | + 1, new_mode->exposure_max, | |
| 1064 | + 1, new_mode->exposure_def); | |
| 1065 | + if (ret < 0) | |
| 1066 | + goto exit; | |
| 1067 | + | |
| 1068 | + ret = __v4l2_ctrl_s_ctrl(ov7251->exposure, | |
| 1069 | + new_mode->exposure_def); | |
| 1070 | + if (ret < 0) | |
| 1071 | + goto exit; | |
| 1072 | + | |
| 1073 | + ret = __v4l2_ctrl_s_ctrl(ov7251->gain, 16); | |
| 1074 | + if (ret < 0) | |
| 1075 | + goto exit; | |
| 1076 | + | |
| 1077 | + ov7251->current_mode = new_mode; | |
| 1078 | + } | |
| 1079 | + | |
| 1080 | + __format = __ov7251_get_pad_format(ov7251, cfg, format->pad, | |
| 1081 | + format->which); | |
| 1082 | + __format->width = __crop->width; | |
| 1083 | + __format->height = __crop->height; | |
| 1084 | + __format->code = MEDIA_BUS_FMT_Y10_1X10; | |
| 1085 | + __format->field = V4L2_FIELD_NONE; | |
| 1086 | + __format->colorspace = V4L2_COLORSPACE_SRGB; | |
| 1087 | + __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace); | |
| 1088 | + __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, | |
| 1089 | + __format->colorspace, __format->ycbcr_enc); | |
| 1090 | + __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace); | |
| 1091 | + | |
| 1092 | + format->format = *__format; | |
| 1093 | + | |
| 1094 | +exit: | |
| 1095 | + mutex_unlock(&ov7251->lock); | |
| 1096 | + | |
| 1097 | + return ret; | |
| 1098 | +} | |
| 1099 | + | |
| 1100 | +static int ov7251_entity_init_cfg(struct v4l2_subdev *subdev, | |
| 1101 | + struct v4l2_subdev_pad_config *cfg) | |
| 1102 | +{ | |
| 1103 | + struct v4l2_subdev_format fmt = { | |
| 1104 | + .which = cfg ? V4L2_SUBDEV_FORMAT_TRY | |
| 1105 | + : V4L2_SUBDEV_FORMAT_ACTIVE, | |
| 1106 | + .format = { | |
| 1107 | + .width = 640, | |
| 1108 | + .height = 480 | |
| 1109 | + } | |
| 1110 | + }; | |
| 1111 | + | |
| 1112 | + ov7251_set_format(subdev, cfg, &fmt); | |
| 1113 | + | |
| 1114 | + return 0; | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +static int ov7251_get_selection(struct v4l2_subdev *sd, | |
| 1118 | + struct v4l2_subdev_pad_config *cfg, | |
| 1119 | + struct v4l2_subdev_selection *sel) | |
| 1120 | +{ | |
| 1121 | + struct ov7251 *ov7251 = to_ov7251(sd); | |
| 1122 | + | |
| 1123 | + if (sel->target != V4L2_SEL_TGT_CROP) | |
| 1124 | + return -EINVAL; | |
| 1125 | + | |
| 1126 | + mutex_lock(&ov7251->lock); | |
| 1127 | + sel->r = *__ov7251_get_pad_crop(ov7251, cfg, sel->pad, | |
| 1128 | + sel->which); | |
| 1129 | + mutex_unlock(&ov7251->lock); | |
| 1130 | + | |
| 1131 | + return 0; | |
| 1132 | +} | |
| 1133 | + | |
| 1134 | +static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 1135 | +{ | |
| 1136 | + struct ov7251 *ov7251 = to_ov7251(subdev); | |
| 1137 | + int ret; | |
| 1138 | + | |
| 1139 | + mutex_lock(&ov7251->lock); | |
| 1140 | + | |
| 1141 | + if (enable) { | |
| 1142 | + ret = ov7251_set_register_array(ov7251, | |
| 1143 | + ov7251->current_mode->data, | |
| 1144 | + ov7251->current_mode->data_size); | |
| 1145 | + if (ret < 0) { | |
| 1146 | + dev_err(ov7251->dev, "could not set mode %dx%d\n", | |
| 1147 | + ov7251->current_mode->width, | |
| 1148 | + ov7251->current_mode->height); | |
| 1149 | + goto exit; | |
| 1150 | + } | |
| 1151 | + ret = __v4l2_ctrl_handler_setup(&ov7251->ctrls); | |
| 1152 | + if (ret < 0) { | |
| 1153 | + dev_err(ov7251->dev, "could not sync v4l2 controls\n"); | |
| 1154 | + goto exit; | |
| 1155 | + } | |
| 1156 | + ret = ov7251_write_reg(ov7251, OV7251_SC_MODE_SELECT, | |
| 1157 | + OV7251_SC_MODE_SELECT_STREAMING); | |
| 1158 | + } else { | |
| 1159 | + ret = ov7251_write_reg(ov7251, OV7251_SC_MODE_SELECT, | |
| 1160 | + OV7251_SC_MODE_SELECT_SW_STANDBY); | |
| 1161 | + } | |
| 1162 | + | |
| 1163 | +exit: | |
| 1164 | + mutex_unlock(&ov7251->lock); | |
| 1165 | + | |
| 1166 | + return ret; | |
| 1167 | +} | |
| 1168 | + | |
| 1169 | +static int ov7251_get_frame_interval(struct v4l2_subdev *subdev, | |
| 1170 | + struct v4l2_subdev_frame_interval *fi) | |
| 1171 | +{ | |
| 1172 | + struct ov7251 *ov7251 = to_ov7251(subdev); | |
| 1173 | + | |
| 1174 | + mutex_lock(&ov7251->lock); | |
| 1175 | + fi->interval = ov7251->current_mode->timeperframe; | |
| 1176 | + mutex_unlock(&ov7251->lock); | |
| 1177 | + | |
| 1178 | + return 0; | |
| 1179 | +} | |
| 1180 | + | |
| 1181 | +static int ov7251_set_frame_interval(struct v4l2_subdev *subdev, | |
| 1182 | + struct v4l2_subdev_frame_interval *fi) | |
| 1183 | +{ | |
| 1184 | + struct ov7251 *ov7251 = to_ov7251(subdev); | |
| 1185 | + const struct ov7251_mode_info *new_mode; | |
| 1186 | + int ret = 0; | |
| 1187 | + | |
| 1188 | + mutex_lock(&ov7251->lock); | |
| 1189 | + new_mode = ov7251_find_mode_by_ival(ov7251, &fi->interval); | |
| 1190 | + | |
| 1191 | + if (new_mode != ov7251->current_mode) { | |
| 1192 | + ret = __v4l2_ctrl_s_ctrl_int64(ov7251->pixel_clock, | |
| 1193 | + new_mode->pixel_clock); | |
| 1194 | + if (ret < 0) | |
| 1195 | + goto exit; | |
| 1196 | + | |
| 1197 | + ret = __v4l2_ctrl_s_ctrl(ov7251->link_freq, | |
| 1198 | + new_mode->link_freq); | |
| 1199 | + if (ret < 0) | |
| 1200 | + goto exit; | |
| 1201 | + | |
| 1202 | + ret = __v4l2_ctrl_modify_range(ov7251->exposure, | |
| 1203 | + 1, new_mode->exposure_max, | |
| 1204 | + 1, new_mode->exposure_def); | |
| 1205 | + if (ret < 0) | |
| 1206 | + goto exit; | |
| 1207 | + | |
| 1208 | + ret = __v4l2_ctrl_s_ctrl(ov7251->exposure, | |
| 1209 | + new_mode->exposure_def); | |
| 1210 | + if (ret < 0) | |
| 1211 | + goto exit; | |
| 1212 | + | |
| 1213 | + ret = __v4l2_ctrl_s_ctrl(ov7251->gain, 16); | |
| 1214 | + if (ret < 0) | |
| 1215 | + goto exit; | |
| 1216 | + | |
| 1217 | + ov7251->current_mode = new_mode; | |
| 1218 | + } | |
| 1219 | + | |
| 1220 | + fi->interval = ov7251->current_mode->timeperframe; | |
| 1221 | + | |
| 1222 | +exit: | |
| 1223 | + mutex_unlock(&ov7251->lock); | |
| 1224 | + | |
| 1225 | + return ret; | |
| 1226 | +} | |
| 1227 | + | |
| 1228 | +static const struct v4l2_subdev_core_ops ov7251_core_ops = { | |
| 1229 | + .s_power = ov7251_s_power, | |
| 1230 | +}; | |
| 1231 | + | |
| 1232 | +static const struct v4l2_subdev_video_ops ov7251_video_ops = { | |
| 1233 | + .s_stream = ov7251_s_stream, | |
| 1234 | + .g_frame_interval = ov7251_get_frame_interval, | |
| 1235 | + .s_frame_interval = ov7251_set_frame_interval, | |
| 1236 | +}; | |
| 1237 | + | |
| 1238 | +static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = { | |
| 1239 | + .init_cfg = ov7251_entity_init_cfg, | |
| 1240 | + .enum_mbus_code = ov7251_enum_mbus_code, | |
| 1241 | + .enum_frame_size = ov7251_enum_frame_size, | |
| 1242 | + .enum_frame_interval = ov7251_enum_frame_ival, | |
| 1243 | + .get_fmt = ov7251_get_format, | |
| 1244 | + .set_fmt = ov7251_set_format, | |
| 1245 | + .get_selection = ov7251_get_selection, | |
| 1246 | +}; | |
| 1247 | + | |
| 1248 | +static const struct v4l2_subdev_ops ov7251_subdev_ops = { | |
| 1249 | + .core = &ov7251_core_ops, | |
| 1250 | + .video = &ov7251_video_ops, | |
| 1251 | + .pad = &ov7251_subdev_pad_ops, | |
| 1252 | +}; | |
| 1253 | + | |
| 1254 | +static int ov7251_probe(struct i2c_client *client) | |
| 1255 | +{ | |
| 1256 | + struct device *dev = &client->dev; | |
| 1257 | + struct fwnode_handle *endpoint; | |
| 1258 | + struct ov7251 *ov7251; | |
| 1259 | + u8 chip_id_high, chip_id_low, chip_rev; | |
| 1260 | + int ret; | |
| 1261 | + | |
| 1262 | + ov7251 = devm_kzalloc(dev, sizeof(struct ov7251), GFP_KERNEL); | |
| 1263 | + if (!ov7251) | |
| 1264 | + return -ENOMEM; | |
| 1265 | + | |
| 1266 | + ov7251->i2c_client = client; | |
| 1267 | + ov7251->dev = dev; | |
| 1268 | + | |
| 1269 | + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); | |
| 1270 | + if (!endpoint) { | |
| 1271 | + dev_err(dev, "endpoint node not found\n"); | |
| 1272 | + return -EINVAL; | |
| 1273 | + } | |
| 1274 | + | |
| 1275 | + ret = v4l2_fwnode_endpoint_parse(endpoint, &ov7251->ep); | |
| 1276 | + fwnode_handle_put(endpoint); | |
| 1277 | + if (ret < 0) { | |
| 1278 | + dev_err(dev, "parsing endpoint node failed\n"); | |
| 1279 | + return ret; | |
| 1280 | + } | |
| 1281 | + | |
| 1282 | + if (ov7251->ep.bus_type != V4L2_MBUS_CSI2) { | |
| 1283 | + dev_err(dev, "invalid bus type (%u), must be CSI2 (%u)\n", | |
| 1284 | + ov7251->ep.bus_type, V4L2_MBUS_CSI2); | |
| 1285 | + return -EINVAL; | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + /* get system clock (xclk) */ | |
| 1289 | + ov7251->xclk = devm_clk_get(dev, "xclk"); | |
| 1290 | + if (IS_ERR(ov7251->xclk)) { | |
| 1291 | + dev_err(dev, "could not get xclk"); | |
| 1292 | + return PTR_ERR(ov7251->xclk); | |
| 1293 | + } | |
| 1294 | + | |
| 1295 | + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", | |
| 1296 | + &ov7251->xclk_freq); | |
| 1297 | + if (ret) { | |
| 1298 | + dev_err(dev, "could not get xclk frequency\n"); | |
| 1299 | + return ret; | |
| 1300 | + } | |
| 1301 | + | |
| 1302 | + /* external clock must be 24MHz, allow 1% tolerance */ | |
| 1303 | + if (ov7251->xclk_freq < 23760000 || ov7251->xclk_freq > 24240000) { | |
| 1304 | + dev_err(dev, "external clock frequency %u is not supported\n", | |
| 1305 | + ov7251->xclk_freq); | |
| 1306 | + return -EINVAL; | |
| 1307 | + } | |
| 1308 | + | |
| 1309 | + ret = clk_set_rate(ov7251->xclk, ov7251->xclk_freq); | |
| 1310 | + if (ret) { | |
| 1311 | + dev_err(dev, "could not set xclk frequency\n"); | |
| 1312 | + return ret; | |
| 1313 | + } | |
| 1314 | + | |
| 1315 | + ov7251->io_regulator = devm_regulator_get(dev, "vdddo"); | |
| 1316 | + if (IS_ERR(ov7251->io_regulator)) { | |
| 1317 | + dev_err(dev, "cannot get io regulator\n"); | |
| 1318 | + return PTR_ERR(ov7251->io_regulator); | |
| 1319 | + } | |
| 1320 | + | |
| 1321 | + ov7251->core_regulator = devm_regulator_get(dev, "vddd"); | |
| 1322 | + if (IS_ERR(ov7251->core_regulator)) { | |
| 1323 | + dev_err(dev, "cannot get core regulator\n"); | |
| 1324 | + return PTR_ERR(ov7251->core_regulator); | |
| 1325 | + } | |
| 1326 | + | |
| 1327 | + ov7251->analog_regulator = devm_regulator_get(dev, "vdda"); | |
| 1328 | + if (IS_ERR(ov7251->analog_regulator)) { | |
| 1329 | + dev_err(dev, "cannot get analog regulator\n"); | |
| 1330 | + return PTR_ERR(ov7251->analog_regulator); | |
| 1331 | + } | |
| 1332 | + | |
| 1333 | + ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); | |
| 1334 | + if (IS_ERR(ov7251->enable_gpio)) { | |
| 1335 | + dev_err(dev, "cannot get enable gpio\n"); | |
| 1336 | + return PTR_ERR(ov7251->enable_gpio); | |
| 1337 | + } | |
| 1338 | + | |
| 1339 | + mutex_init(&ov7251->lock); | |
| 1340 | + | |
| 1341 | + v4l2_ctrl_handler_init(&ov7251->ctrls, 7); | |
| 1342 | + ov7251->ctrls.lock = &ov7251->lock; | |
| 1343 | + | |
| 1344 | + v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, | |
| 1345 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 1346 | + v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, | |
| 1347 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 1348 | + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, | |
| 1349 | + V4L2_CID_EXPOSURE, 1, 32, 1, 32); | |
| 1350 | + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, | |
| 1351 | + V4L2_CID_GAIN, 16, 1023, 1, 16); | |
| 1352 | + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, | |
| 1353 | + V4L2_CID_TEST_PATTERN, | |
| 1354 | + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, | |
| 1355 | + 0, 0, ov7251_test_pattern_menu); | |
| 1356 | + ov7251->pixel_clock = v4l2_ctrl_new_std(&ov7251->ctrls, | |
| 1357 | + &ov7251_ctrl_ops, | |
| 1358 | + V4L2_CID_PIXEL_RATE, | |
| 1359 | + 1, INT_MAX, 1, 1); | |
| 1360 | + ov7251->link_freq = v4l2_ctrl_new_int_menu(&ov7251->ctrls, | |
| 1361 | + &ov7251_ctrl_ops, | |
| 1362 | + V4L2_CID_LINK_FREQ, | |
| 1363 | + ARRAY_SIZE(link_freq) - 1, | |
| 1364 | + 0, link_freq); | |
| 1365 | + if (ov7251->link_freq) | |
| 1366 | + ov7251->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1367 | + | |
| 1368 | + ov7251->sd.ctrl_handler = &ov7251->ctrls; | |
| 1369 | + | |
| 1370 | + if (ov7251->ctrls.error) { | |
| 1371 | + dev_err(dev, "%s: control initialization error %d\n", | |
| 1372 | + __func__, ov7251->ctrls.error); | |
| 1373 | + ret = ov7251->ctrls.error; | |
| 1374 | + goto free_ctrl; | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops); | |
| 1378 | + ov7251->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1379 | + ov7251->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1380 | + ov7251->sd.dev = &client->dev; | |
| 1381 | + ov7251->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1382 | + | |
| 1383 | + ret = media_entity_pads_init(&ov7251->sd.entity, 1, &ov7251->pad); | |
| 1384 | + if (ret < 0) { | |
| 1385 | + dev_err(dev, "could not register media entity\n"); | |
| 1386 | + goto free_ctrl; | |
| 1387 | + } | |
| 1388 | + | |
| 1389 | + ret = ov7251_s_power(&ov7251->sd, true); | |
| 1390 | + if (ret < 0) { | |
| 1391 | + dev_err(dev, "could not power up OV7251\n"); | |
| 1392 | + goto free_entity; | |
| 1393 | + } | |
| 1394 | + | |
| 1395 | + ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_HIGH, &chip_id_high); | |
| 1396 | + if (ret < 0 || chip_id_high != OV7251_CHIP_ID_HIGH_BYTE) { | |
| 1397 | + dev_err(dev, "could not read ID high\n"); | |
| 1398 | + ret = -ENODEV; | |
| 1399 | + goto power_down; | |
| 1400 | + } | |
| 1401 | + ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_LOW, &chip_id_low); | |
| 1402 | + if (ret < 0 || chip_id_low != OV7251_CHIP_ID_LOW_BYTE) { | |
| 1403 | + dev_err(dev, "could not read ID low\n"); | |
| 1404 | + ret = -ENODEV; | |
| 1405 | + goto power_down; | |
| 1406 | + } | |
| 1407 | + | |
| 1408 | + ret = ov7251_read_reg(ov7251, OV7251_SC_GP_IO_IN1, &chip_rev); | |
| 1409 | + if (ret < 0) { | |
| 1410 | + dev_err(dev, "could not read revision\n"); | |
| 1411 | + ret = -ENODEV; | |
| 1412 | + goto power_down; | |
| 1413 | + } | |
| 1414 | + chip_rev >>= 4; | |
| 1415 | + | |
| 1416 | + dev_info(dev, "OV7251 revision %x (%s) detected at address 0x%02x\n", | |
| 1417 | + chip_rev, | |
| 1418 | + chip_rev == 0x4 ? "1A / 1B" : | |
| 1419 | + chip_rev == 0x5 ? "1C / 1D" : | |
| 1420 | + chip_rev == 0x6 ? "1E" : | |
| 1421 | + chip_rev == 0x7 ? "1F" : "unknown", | |
| 1422 | + client->addr); | |
| 1423 | + | |
| 1424 | + ret = ov7251_read_reg(ov7251, OV7251_PRE_ISP_00, | |
| 1425 | + &ov7251->pre_isp_00); | |
| 1426 | + if (ret < 0) { | |
| 1427 | + dev_err(dev, "could not read test pattern value\n"); | |
| 1428 | + ret = -ENODEV; | |
| 1429 | + goto power_down; | |
| 1430 | + } | |
| 1431 | + | |
| 1432 | + ret = ov7251_read_reg(ov7251, OV7251_TIMING_FORMAT1, | |
| 1433 | + &ov7251->timing_format1); | |
| 1434 | + if (ret < 0) { | |
| 1435 | + dev_err(dev, "could not read vflip value\n"); | |
| 1436 | + ret = -ENODEV; | |
| 1437 | + goto power_down; | |
| 1438 | + } | |
| 1439 | + | |
| 1440 | + ret = ov7251_read_reg(ov7251, OV7251_TIMING_FORMAT2, | |
| 1441 | + &ov7251->timing_format2); | |
| 1442 | + if (ret < 0) { | |
| 1443 | + dev_err(dev, "could not read hflip value\n"); | |
| 1444 | + ret = -ENODEV; | |
| 1445 | + goto power_down; | |
| 1446 | + } | |
| 1447 | + | |
| 1448 | + ov7251_s_power(&ov7251->sd, false); | |
| 1449 | + | |
| 1450 | + ret = v4l2_async_register_subdev(&ov7251->sd); | |
| 1451 | + if (ret < 0) { | |
| 1452 | + dev_err(dev, "could not register v4l2 device\n"); | |
| 1453 | + goto free_entity; | |
| 1454 | + } | |
| 1455 | + | |
| 1456 | + ov7251_entity_init_cfg(&ov7251->sd, NULL); | |
| 1457 | + | |
| 1458 | + return 0; | |
| 1459 | + | |
| 1460 | +power_down: | |
| 1461 | + ov7251_s_power(&ov7251->sd, false); | |
| 1462 | +free_entity: | |
| 1463 | + media_entity_cleanup(&ov7251->sd.entity); | |
| 1464 | +free_ctrl: | |
| 1465 | + v4l2_ctrl_handler_free(&ov7251->ctrls); | |
| 1466 | + mutex_destroy(&ov7251->lock); | |
| 1467 | + | |
| 1468 | + return ret; | |
| 1469 | +} | |
| 1470 | + | |
| 1471 | +static int ov7251_remove(struct i2c_client *client) | |
| 1472 | +{ | |
| 1473 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1474 | + struct ov7251 *ov7251 = to_ov7251(sd); | |
| 1475 | + | |
| 1476 | + v4l2_async_unregister_subdev(&ov7251->sd); | |
| 1477 | + media_entity_cleanup(&ov7251->sd.entity); | |
| 1478 | + v4l2_ctrl_handler_free(&ov7251->ctrls); | |
| 1479 | + mutex_destroy(&ov7251->lock); | |
| 1480 | + | |
| 1481 | + return 0; | |
| 1482 | +} | |
| 1483 | + | |
| 1484 | +static const struct of_device_id ov7251_of_match[] = { | |
| 1485 | + { .compatible = "ovti,ov7251" }, | |
| 1486 | + { /* sentinel */ } | |
| 1487 | +}; | |
| 1488 | +MODULE_DEVICE_TABLE(of, ov7251_of_match); | |
| 1489 | + | |
| 1490 | +static struct i2c_driver ov7251_i2c_driver = { | |
| 1491 | + .driver = { | |
| 1492 | + .of_match_table = ov7251_of_match, | |
| 1493 | + .name = "ov7251", | |
| 1494 | + }, | |
| 1495 | + .probe_new = ov7251_probe, | |
| 1496 | + .remove = ov7251_remove, | |
| 1497 | +}; | |
| 1498 | + | |
| 1499 | +module_i2c_driver(ov7251_i2c_driver); | |
| 1500 | + | |
| 1501 | +MODULE_DESCRIPTION("Omnivision OV7251 Camera Driver"); | |
| 1502 | +MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); | |
| 1503 | +MODULE_LICENSE("GPL v2"); | |
| @@ -1035,7 +1035,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, · 1034 unmodified lines | ||
| 1035 | 1035 | |
| 1036 | 1036 | /* Set COM8. */ |
| 1037 | 1037 | if (priv->band_filter) { |
| 1038 | − ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); | |
| 1038 | + ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); | |
| 1039 | 1039 | if (!ret) |
| 1040 | 1040 | ret = ov772x_mask_set(client, BDBASE, |
| 1041 | 1041 | 0xff, 256 - priv->band_filter); |
| @@ -953,7 +953,7 @@ static int ov7740_init_controls(struct ov7740 *ov7740) · 952 unmodified lines | ||
| 953 | 953 | struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler; |
| 954 | 954 | int ret; |
| 955 | 955 | |
| 956 | − ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2); | |
| 956 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); | |
| 957 | 957 | if (ret < 0) |
| 958 | 958 | return ret; |
| 959 | 959 | |
| @@ -980,27 +980,39 @@ static int ov7740_init_controls(struct ov7740 *ov7740) · 20 unmodified lines | ||
| 980 | 980 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
| 981 | 981 | ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, |
| 982 | 982 | V4L2_CID_VFLIP, 0, 1, 1, 0); |
| 983 | + | |
| 983 | 984 | ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, |
| 984 | 985 | V4L2_CID_GAIN, 0, 1023, 1, 500); |
| 986 | + if (ov7740->gain) | |
| 987 | + ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; | |
| 988 | + | |
| 985 | 989 | ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, |
| 986 | 990 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); |
| 991 | + | |
| 987 | 992 | ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, |
| 988 | 993 | V4L2_CID_EXPOSURE, 0, 65535, 1, 500); |
| 994 | + if (ov7740->exposure) | |
| 995 | + ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; | |
| 996 | + | |
| 989 | 997 | ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr, |
| 990 | 998 | &ov7740_ctrl_ops, |
| 991 | 999 | V4L2_CID_EXPOSURE_AUTO, |
| 992 | 1000 | V4L2_EXPOSURE_MANUAL, 0, |
| 993 | 1001 | V4L2_EXPOSURE_AUTO); |
| 994 | 1002 | |
| 995 | − ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; | |
| 996 | − ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; | |
| 997 | − | |
| 998 | 1003 | v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false); |
| 999 | 1004 | v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); |
| 1000 | 1005 | v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, |
| 1001 | 1006 | V4L2_EXPOSURE_MANUAL, false); |
| 1002 | 1007 | v4l2_ctrl_cluster(2, &ov7740->hflip); |
| 1003 | 1008 | |
| 1009 | + if (ctrl_hdlr->error) { | |
| 1010 | + ret = ctrl_hdlr->error; | |
| 1011 | + dev_err(&client->dev, "controls initialisation failed (%d)\n", | |
| 1012 | + ret); | |
| 1013 | + goto error; | |
| 1014 | + } | |
| 1015 | + | |
| 1004 | 1016 | ret = v4l2_ctrl_handler_setup(ctrl_hdlr); |
| 1005 | 1017 | if (ret) { |
| 1006 | 1018 | dev_err(&client->dev, "%s control init failed (%d)\n", |
| @@ -1074,7 +1086,7 @@ static int ov7740_probe(struct i2c_client *client, · 67 unmodified lines | ||
| 1074 | 1086 | |
| 1075 | 1087 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
| 1076 | 1088 | sd->internal_ops = &ov7740_subdev_internal_ops; |
| 1077 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1089 | + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1078 | 1090 | #endif |
| 1079 | 1091 | |
| 1080 | 1092 | #if defined(CONFIG_MEDIA_CONTROLLER) |
| @@ -1001,7 +1001,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, · 1000 unmodified lines | ||
| 1001 | 1001 | if (rval) |
| 1002 | 1002 | goto out; |
| 1003 | 1003 | |
| 1004 | − for (i = 0; i < 1000; i++) { | |
| 1004 | + for (i = 1000; i > 0; i--) { | |
| 1005 | 1005 | rval = smiapp_read( |
| 1006 | 1006 | sensor, |
| 1007 | 1007 | SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); |
| @@ -1012,11 +1012,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, · 4 unmodified lines | ||
| 1012 | 1012 | if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) |
| 1013 | 1013 | break; |
| 1014 | 1014 | |
| 1015 | − if (--i == 0) { | |
| 1016 | − rval = -ETIMEDOUT; | |
| 1017 | − goto out; | |
| 1018 | − } | |
| 1019 | − | |
| 1015 | + } | |
| 1016 | + if (!i) { | |
| 1017 | + rval = -ETIMEDOUT; | |
| 1018 | + goto out; | |
| 1020 | 1019 | } |
| 1021 | 1020 | |
| 1022 | 1021 | for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { |
| @@ -2569,7 +2569,7 @@ static int tda1997x_probe(struct i2c_client *client, · 2568 unmodified lines | ||
| 2569 | 2569 | snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", |
| 2570 | 2570 | id->name, i2c_adapter_id(client->adapter), |
| 2571 | 2571 | client->addr); |
| 2572 | − sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 2572 | + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 2573 | 2573 | sd->entity.function = MEDIA_ENT_F_DTV_DECODER; |
| 2574 | 2574 | sd->entity.ops = &tda1997x_media_ops; |
| 2575 | 2575 | |
| @@ -2723,7 +2723,7 @@ static int tda1997x_probe(struct i2c_client *client, · 147 unmodified lines | ||
| 2723 | 2723 | state->pads); |
| 2724 | 2724 | if (ret) { |
| 2725 | 2725 | v4l_err(client, "failed entity_init: %d", ret); |
| 2726 | − goto err_free_mutex; | |
| 2726 | + goto err_free_handler; | |
| 2727 | 2727 | } |
| 2728 | 2728 | |
| 2729 | 2729 | ret = v4l2_async_register_subdev(sd); |
| @@ -319,136 +319,136 @@ struct i2c_reg_value { · 318 unmodified lines | ||
| 319 | 319 | /* Default values as sugested at TVP5150AM1 datasheet */ |
| 320 | 320 | static const struct i2c_reg_value tvp5150_init_default[] = { |
| 321 | 321 | { /* 0x00 */ |
| 322 | − TVP5150_VD_IN_SRC_SEL_1,0x00 | |
| 322 | + TVP5150_VD_IN_SRC_SEL_1, 0x00 | |
| 323 | 323 | }, |
| 324 | 324 | { /* 0x01 */ |
| 325 | − TVP5150_ANAL_CHL_CTL,0x15 | |
| 325 | + TVP5150_ANAL_CHL_CTL, 0x15 | |
| 326 | 326 | }, |
| 327 | 327 | { /* 0x02 */ |
| 328 | − TVP5150_OP_MODE_CTL,0x00 | |
| 328 | + TVP5150_OP_MODE_CTL, 0x00 | |
| 329 | 329 | }, |
| 330 | 330 | { /* 0x03 */ |
| 331 | − TVP5150_MISC_CTL,0x01 | |
| 331 | + TVP5150_MISC_CTL, 0x01 | |
| 332 | 332 | }, |
| 333 | 333 | { /* 0x06 */ |
| 334 | − TVP5150_COLOR_KIL_THSH_CTL,0x10 | |
| 334 | + TVP5150_COLOR_KIL_THSH_CTL, 0x10 | |
| 335 | 335 | }, |
| 336 | 336 | { /* 0x07 */ |
| 337 | − TVP5150_LUMA_PROC_CTL_1,0x60 | |
| 337 | + TVP5150_LUMA_PROC_CTL_1, 0x60 | |
| 338 | 338 | }, |
| 339 | 339 | { /* 0x08 */ |
| 340 | − TVP5150_LUMA_PROC_CTL_2,0x00 | |
| 340 | + TVP5150_LUMA_PROC_CTL_2, 0x00 | |
| 341 | 341 | }, |
| 342 | 342 | { /* 0x09 */ |
| 343 | − TVP5150_BRIGHT_CTL,0x80 | |
| 343 | + TVP5150_BRIGHT_CTL, 0x80 | |
| 344 | 344 | }, |
| 345 | 345 | { /* 0x0a */ |
| 346 | − TVP5150_SATURATION_CTL,0x80 | |
| 346 | + TVP5150_SATURATION_CTL, 0x80 | |
| 347 | 347 | }, |
| 348 | 348 | { /* 0x0b */ |
| 349 | − TVP5150_HUE_CTL,0x00 | |
| 349 | + TVP5150_HUE_CTL, 0x00 | |
| 350 | 350 | }, |
| 351 | 351 | { /* 0x0c */ |
| 352 | − TVP5150_CONTRAST_CTL,0x80 | |
| 352 | + TVP5150_CONTRAST_CTL, 0x80 | |
| 353 | 353 | }, |
| 354 | 354 | { /* 0x0d */ |
| 355 | − TVP5150_DATA_RATE_SEL,0x47 | |
| 355 | + TVP5150_DATA_RATE_SEL, 0x47 | |
| 356 | 356 | }, |
| 357 | 357 | { /* 0x0e */ |
| 358 | − TVP5150_LUMA_PROC_CTL_3,0x00 | |
| 358 | + TVP5150_LUMA_PROC_CTL_3, 0x00 | |
| 359 | 359 | }, |
| 360 | 360 | { /* 0x0f */ |
| 361 | − TVP5150_CONF_SHARED_PIN,0x08 | |
| 361 | + TVP5150_CONF_SHARED_PIN, 0x08 | |
| 362 | 362 | }, |
| 363 | 363 | { /* 0x11 */ |
| 364 | − TVP5150_ACT_VD_CROP_ST_MSB,0x00 | |
| 364 | + TVP5150_ACT_VD_CROP_ST_MSB, 0x00 | |
| 365 | 365 | }, |
| 366 | 366 | { /* 0x12 */ |
| 367 | − TVP5150_ACT_VD_CROP_ST_LSB,0x00 | |
| 367 | + TVP5150_ACT_VD_CROP_ST_LSB, 0x00 | |
| 368 | 368 | }, |
| 369 | 369 | { /* 0x13 */ |
| 370 | − TVP5150_ACT_VD_CROP_STP_MSB,0x00 | |
| 370 | + TVP5150_ACT_VD_CROP_STP_MSB, 0x00 | |
| 371 | 371 | }, |
| 372 | 372 | { /* 0x14 */ |
| 373 | − TVP5150_ACT_VD_CROP_STP_LSB,0x00 | |
| 373 | + TVP5150_ACT_VD_CROP_STP_LSB, 0x00 | |
| 374 | 374 | }, |
| 375 | 375 | { /* 0x15 */ |
| 376 | − TVP5150_GENLOCK,0x01 | |
| 376 | + TVP5150_GENLOCK, 0x01 | |
| 377 | 377 | }, |
| 378 | 378 | { /* 0x16 */ |
| 379 | − TVP5150_HORIZ_SYNC_START,0x80 | |
| 379 | + TVP5150_HORIZ_SYNC_START, 0x80 | |
| 380 | 380 | }, |
| 381 | 381 | { /* 0x18 */ |
| 382 | − TVP5150_VERT_BLANKING_START,0x00 | |
| 382 | + TVP5150_VERT_BLANKING_START, 0x00 | |
| 383 | 383 | }, |
| 384 | 384 | { /* 0x19 */ |
| 385 | − TVP5150_VERT_BLANKING_STOP,0x00 | |
| 385 | + TVP5150_VERT_BLANKING_STOP, 0x00 | |
| 386 | 386 | }, |
| 387 | 387 | { /* 0x1a */ |
| 388 | − TVP5150_CHROMA_PROC_CTL_1,0x0c | |
| 388 | + TVP5150_CHROMA_PROC_CTL_1, 0x0c | |
| 389 | 389 | }, |
| 390 | 390 | { /* 0x1b */ |
| 391 | − TVP5150_CHROMA_PROC_CTL_2,0x14 | |
| 391 | + TVP5150_CHROMA_PROC_CTL_2, 0x14 | |
| 392 | 392 | }, |
| 393 | 393 | { /* 0x1c */ |
| 394 | − TVP5150_INT_RESET_REG_B,0x00 | |
| 394 | + TVP5150_INT_RESET_REG_B, 0x00 | |
| 395 | 395 | }, |
| 396 | 396 | { /* 0x1d */ |
| 397 | − TVP5150_INT_ENABLE_REG_B,0x00 | |
| 397 | + TVP5150_INT_ENABLE_REG_B, 0x00 | |
| 398 | 398 | }, |
| 399 | 399 | { /* 0x1e */ |
| 400 | − TVP5150_INTT_CONFIG_REG_B,0x00 | |
| 400 | + TVP5150_INTT_CONFIG_REG_B, 0x00 | |
| 401 | 401 | }, |
| 402 | 402 | { /* 0x28 */ |
| 403 | − TVP5150_VIDEO_STD,0x00 | |
| 403 | + TVP5150_VIDEO_STD, 0x00 | |
| 404 | 404 | }, |
| 405 | 405 | { /* 0x2e */ |
| 406 | − TVP5150_MACROVISION_ON_CTR,0x0f | |
| 406 | + TVP5150_MACROVISION_ON_CTR, 0x0f | |
| 407 | 407 | }, |
| 408 | 408 | { /* 0x2f */ |
| 409 | − TVP5150_MACROVISION_OFF_CTR,0x01 | |
| 409 | + TVP5150_MACROVISION_OFF_CTR, 0x01 | |
| 410 | 410 | }, |
| 411 | 411 | { /* 0xbb */ |
| 412 | − TVP5150_TELETEXT_FIL_ENA,0x00 | |
| 412 | + TVP5150_TELETEXT_FIL_ENA, 0x00 | |
| 413 | 413 | }, |
| 414 | 414 | { /* 0xc0 */ |
| 415 | − TVP5150_INT_STATUS_REG_A,0x00 | |
| 415 | + TVP5150_INT_STATUS_REG_A, 0x00 | |
| 416 | 416 | }, |
| 417 | 417 | { /* 0xc1 */ |
| 418 | − TVP5150_INT_ENABLE_REG_A,0x00 | |
| 418 | + TVP5150_INT_ENABLE_REG_A, 0x00 | |
| 419 | 419 | }, |
| 420 | 420 | { /* 0xc2 */ |
| 421 | − TVP5150_INT_CONF,0x04 | |
| 421 | + TVP5150_INT_CONF, 0x04 | |
| 422 | 422 | }, |
| 423 | 423 | { /* 0xc8 */ |
| 424 | − TVP5150_FIFO_INT_THRESHOLD,0x80 | |
| 424 | + TVP5150_FIFO_INT_THRESHOLD, 0x80 | |
| 425 | 425 | }, |
| 426 | 426 | { /* 0xc9 */ |
| 427 | − TVP5150_FIFO_RESET,0x00 | |
| 427 | + TVP5150_FIFO_RESET, 0x00 | |
| 428 | 428 | }, |
| 429 | 429 | { /* 0xca */ |
| 430 | − TVP5150_LINE_NUMBER_INT,0x00 | |
| 430 | + TVP5150_LINE_NUMBER_INT, 0x00 | |
| 431 | 431 | }, |
| 432 | 432 | { /* 0xcb */ |
| 433 | − TVP5150_PIX_ALIGN_REG_LOW,0x4e | |
| 433 | + TVP5150_PIX_ALIGN_REG_LOW, 0x4e | |
| 434 | 434 | }, |
| 435 | 435 | { /* 0xcc */ |
| 436 | − TVP5150_PIX_ALIGN_REG_HIGH,0x00 | |
| 436 | + TVP5150_PIX_ALIGN_REG_HIGH, 0x00 | |
| 437 | 437 | }, |
| 438 | 438 | { /* 0xcd */ |
| 439 | − TVP5150_FIFO_OUT_CTRL,0x01 | |
| 439 | + TVP5150_FIFO_OUT_CTRL, 0x01 | |
| 440 | 440 | }, |
| 441 | 441 | { /* 0xcf */ |
| 442 | − TVP5150_FULL_FIELD_ENA,0x00 | |
| 442 | + TVP5150_FULL_FIELD_ENA, 0x00 | |
| 443 | 443 | }, |
| 444 | 444 | { /* 0xd0 */ |
| 445 | − TVP5150_LINE_MODE_INI,0x00 | |
| 445 | + TVP5150_LINE_MODE_INI, 0x00 | |
| 446 | 446 | }, |
| 447 | 447 | { /* 0xfc */ |
| 448 | − TVP5150_FULL_FIELD_MODE_REG,0x7f | |
| 448 | + TVP5150_FULL_FIELD_MODE_REG, 0x7f | |
| 449 | 449 | }, |
| 450 | 450 | { /* end of data */ |
| 451 | − 0xff,0xff | |
| 451 | + 0xff, 0xff | |
| 452 | 452 | } |
| 453 | 453 | }; |
| 454 | 454 | |
| @@ -456,27 +456,27 @@ static const struct i2c_reg_value tvp5150_init_default[] = { · 1 unmodified line | ||
| 456 | 456 | static const struct i2c_reg_value tvp5150_init_enable[] = { |
| 457 | 457 | { |
| 458 | 458 | TVP5150_CONF_SHARED_PIN, 2 |
| 459 | − },{ /* Automatic offset and AGC enabled */ | |
| 459 | + }, { /* Automatic offset and AGC enabled */ | |
| 460 | 460 | TVP5150_ANAL_CHL_CTL, 0x15 |
| 461 | − },{ /* Activate YCrCb output 0x9 or 0xd ? */ | |
| 461 | + }, { /* Activate YCrCb output 0x9 or 0xd ? */ | |
| 462 | 462 | TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL | |
| 463 | 463 | TVP5150_MISC_CTL_INTREQ_OE | |
| 464 | 464 | TVP5150_MISC_CTL_YCBCR_OE | |
| 465 | 465 | TVP5150_MISC_CTL_SYNC_OE | |
| 466 | 466 | TVP5150_MISC_CTL_VBLANK | |
| 467 | 467 | TVP5150_MISC_CTL_CLOCK_OE, |
| 468 | − },{ /* Activates video std autodetection for all standards */ | |
| 468 | + }, { /* Activates video std autodetection for all standards */ | |
| 469 | 469 | TVP5150_AUTOSW_MSK, 0x0 |
| 470 | − },{ /* Default format: 0x47. For 4:2:2: 0x40 */ | |
| 470 | + }, { /* Default format: 0x47. For 4:2:2: 0x40 */ | |
| 471 | 471 | TVP5150_DATA_RATE_SEL, 0x47 |
| 472 | − },{ | |
| 472 | + }, { | |
| 473 | 473 | TVP5150_CHROMA_PROC_CTL_1, 0x0c |
| 474 | − },{ | |
| 474 | + }, { | |
| 475 | 475 | TVP5150_CHROMA_PROC_CTL_2, 0x54 |
| 476 | − },{ /* Non documented, but initialized on WinTV USB2 */ | |
| 476 | + }, { /* Non documented, but initialized on WinTV USB2 */ | |
| 477 | 477 | 0x27, 0x20 |
| 478 | − },{ | |
| 479 | − 0xff,0xff | |
| 478 | + }, { | |
| 479 | + 0xff, 0xff | |
| 480 | 480 | } |
| 481 | 481 | }; |
| 482 | 482 | |
| @@ -500,78 +500,80 @@ struct i2c_vbi_ram_value { · 17 unmodified lines | ||
| 500 | 500 | * and so on. There are 16 possible locations from 0 to 15. |
| 501 | 501 | */ |
| 502 | 502 | |
| 503 | −static struct i2c_vbi_ram_value vbi_ram_default[] = | |
| 504 | −{ | |
| 505 | − /* FIXME: Current api doesn't handle all VBI types, those not | |
| 506 | − yet supported are placed under #if 0 */ | |
| 503 | +static struct i2c_vbi_ram_value vbi_ram_default[] = { | |
| 504 | + | |
| 505 | + /* | |
| 506 | + * FIXME: Current api doesn't handle all VBI types, those not | |
| 507 | + * yet supported are placed under #if 0 | |
| 508 | + */ | |
| 507 | 509 | #if 0 |
| 508 | 510 | [0] = {0x010, /* Teletext, SECAM, WST System A */ |
| 509 | − {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, | |
| 511 | + {V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1}, | |
| 510 | 512 | { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, |
| 511 | 513 | 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } |
| 512 | 514 | }, |
| 513 | 515 | #endif |
| 514 | 516 | [1] = {0x030, /* Teletext, PAL, WST System B */ |
| 515 | − {V4L2_SLICED_TELETEXT_B,6,22,1}, | |
| 517 | + {V4L2_SLICED_TELETEXT_B, 6, 22, 1}, | |
| 516 | 518 | { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, |
| 517 | 519 | 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } |
| 518 | 520 | }, |
| 519 | 521 | #if 0 |
| 520 | 522 | [2] = {0x050, /* Teletext, PAL, WST System C */ |
| 521 | − {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, | |
| 523 | + {V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1}, | |
| 522 | 524 | { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, |
| 523 | 525 | 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } |
| 524 | 526 | }, |
| 525 | 527 | [3] = {0x070, /* Teletext, NTSC, WST System B */ |
| 526 | − {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, | |
| 528 | + {V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1}, | |
| 527 | 529 | { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, |
| 528 | 530 | 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } |
| 529 | 531 | }, |
| 530 | 532 | [4] = {0x090, /* Tetetext, NTSC NABTS System C */ |
| 531 | − {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, | |
| 533 | + {V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1}, | |
| 532 | 534 | { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, |
| 533 | 535 | 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } |
| 534 | 536 | }, |
| 535 | 537 | [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ |
| 536 | − {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, | |
| 538 | + {V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1}, | |
| 537 | 539 | { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, |
| 538 | 540 | 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } |
| 539 | 541 | }, |
| 540 | 542 | [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ |
| 541 | − {V4L2_SLICED_CAPTION_625,22,22,1}, | |
| 543 | + {V4L2_SLICED_CAPTION_625, 22, 22, 1}, | |
| 542 | 544 | { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, |
| 543 | 545 | 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } |
| 544 | 546 | }, |
| 545 | 547 | #endif |
| 546 | 548 | [7] = {0x0f0, /* Closed Caption, NTSC */ |
| 547 | − {V4L2_SLICED_CAPTION_525,21,21,1}, | |
| 549 | + {V4L2_SLICED_CAPTION_525, 21, 21, 1}, | |
| 548 | 550 | { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, |
| 549 | 551 | 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } |
| 550 | 552 | }, |
| 551 | 553 | [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ |
| 552 | − {V4L2_SLICED_WSS_625,23,23,1}, | |
| 554 | + {V4L2_SLICED_WSS_625, 23, 23, 1}, | |
| 553 | 555 | { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, |
| 554 | 556 | 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } |
| 555 | 557 | }, |
| 556 | 558 | #if 0 |
| 557 | 559 | [9] = {0x130, /* Wide Screen Signal, NTSC C */ |
| 558 | − {V4L2_SLICED_WSS_525,20,20,1}, | |
| 560 | + {V4L2_SLICED_WSS_525, 20, 20, 1}, | |
| 559 | 561 | { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, |
| 560 | 562 | 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } |
| 561 | 563 | }, |
| 562 | 564 | [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ |
| 563 | − {V4l2_SLICED_VITC_625,6,22,0}, | |
| 565 | + {V4l2_SLICED_VITC_625, 6, 22, 0}, | |
| 564 | 566 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, |
| 565 | 567 | 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } |
| 566 | 568 | }, |
| 567 | 569 | [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ |
| 568 | − {V4l2_SLICED_VITC_525,10,20,0}, | |
| 570 | + {V4l2_SLICED_VITC_525, 10, 20, 0}, | |
| 569 | 571 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, |
| 570 | 572 | 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } |
| 571 | 573 | }, |
| 572 | 574 | #endif |
| 573 | 575 | [12] = {0x190, /* Video Program System (VPS), PAL */ |
| 574 | − {V4L2_SLICED_VPS,16,16,0}, | |
| 576 | + {V4L2_SLICED_VPS, 16, 16, 0}, | |
| 575 | 577 | { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, |
| 576 | 578 | 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } |
| 577 | 579 | }, |
| @@ -623,7 +625,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, · 45 unmodified lines | ||
| 623 | 625 | int line, i; |
| 624 | 626 | |
| 625 | 627 | dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); |
| 626 | − memset(cap, 0, sizeof *cap); | |
| 628 | + memset(cap, 0, sizeof(*cap)); | |
| 627 | 629 | |
| 628 | 630 | for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { |
| 629 | 631 | const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; |
| @@ -655,7 +657,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, · 25 unmodified lines | ||
| 655 | 657 | * MSB = field2 |
| 656 | 658 | */ |
| 657 | 659 | static int tvp5150_set_vbi(struct v4l2_subdev *sd, |
| 658 | − unsigned int type,u8 flags, int line, | |
| 660 | + unsigned int type, u8 flags, int line, | |
| 659 | 661 | const int fields) |
| 660 | 662 | { |
| 661 | 663 | struct tvp5150 *decoder = to_tvp5150(sd); |
| @@ -1101,11 +1103,14 @@ static int tvp5150_s_routing(struct v4l2_subdev *sd, · 439 unmodified lines | ||
| 1101 | 1103 | |
| 1102 | 1104 | static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) |
| 1103 | 1105 | { |
| 1104 | − /* this is for capturing 36 raw vbi lines | |
| 1105 | − if there's a way to cut off the beginning 2 vbi lines | |
| 1106 | − with the tvp5150 then the vbi line count could be lowered | |
| 1107 | − to 17 lines/field again, although I couldn't find a register | |
| 1108 | − which could do that cropping */ | |
| 1106 | + /* | |
| 1107 | + * this is for capturing 36 raw vbi lines | |
| 1108 | + * if there's a way to cut off the beginning 2 vbi lines | |
| 1109 | + * with the tvp5150 then the vbi line count could be lowered | |
| 1110 | + * to 17 lines/field again, although I couldn't find a register | |
| 1111 | + * which could do that cropping | |
| 1112 | + */ | |
| 1113 | + | |
| 1109 | 1114 | if (fmt->sample_format == V4L2_PIX_FMT_GREY) |
| 1110 | 1115 | tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); |
| 1111 | 1116 | if (fmt->count[0] == 18 && fmt->count[1] == 18) { |
| @@ -0,0 +1,564 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * video-i2c.c - Support for I2C transport video devices | |
| 4 | + * | |
| 5 | + * Copyright (C) 2018 Matt Ranostay <matt.ranostay@konsulko.com> | |
| 6 | + * | |
| 7 | + * Supported: | |
| 8 | + * - Panasonic AMG88xx Grid-Eye Sensors | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <linux/delay.h> | |
| 12 | +#include <linux/freezer.h> | |
| 13 | +#include <linux/kthread.h> | |
| 14 | +#include <linux/i2c.h> | |
| 15 | +#include <linux/list.h> | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/mutex.h> | |
| 18 | +#include <linux/of_device.h> | |
| 19 | +#include <linux/sched.h> | |
| 20 | +#include <linux/slab.h> | |
| 21 | +#include <linux/videodev2.h> | |
| 22 | +#include <media/v4l2-common.h> | |
| 23 | +#include <media/v4l2-device.h> | |
| 24 | +#include <media/v4l2-event.h> | |
| 25 | +#include <media/v4l2-fh.h> | |
| 26 | +#include <media/v4l2-ioctl.h> | |
| 27 | +#include <media/videobuf2-v4l2.h> | |
| 28 | +#include <media/videobuf2-vmalloc.h> | |
| 29 | + | |
| 30 | +#define VIDEO_I2C_DRIVER "video-i2c" | |
| 31 | + | |
| 32 | +struct video_i2c_chip; | |
| 33 | + | |
| 34 | +struct video_i2c_buffer { | |
| 35 | + struct vb2_v4l2_buffer vb; | |
| 36 | + struct list_head list; | |
| 37 | +}; | |
| 38 | + | |
| 39 | +struct video_i2c_data { | |
| 40 | + struct i2c_client *client; | |
| 41 | + const struct video_i2c_chip *chip; | |
| 42 | + struct mutex lock; | |
| 43 | + spinlock_t slock; | |
| 44 | + unsigned int sequence; | |
| 45 | + struct mutex queue_lock; | |
| 46 | + | |
| 47 | + struct v4l2_device v4l2_dev; | |
| 48 | + struct video_device vdev; | |
| 49 | + struct vb2_queue vb_vidq; | |
| 50 | + | |
| 51 | + struct task_struct *kthread_vid_cap; | |
| 52 | + struct list_head vid_cap_active; | |
| 53 | +}; | |
| 54 | + | |
| 55 | +static const struct v4l2_fmtdesc amg88xx_format = { | |
| 56 | + .pixelformat = V4L2_PIX_FMT_Y12, | |
| 57 | +}; | |
| 58 | + | |
| 59 | +static const struct v4l2_frmsize_discrete amg88xx_size = { | |
| 60 | + .width = 8, | |
| 61 | + .height = 8, | |
| 62 | +}; | |
| 63 | + | |
| 64 | +struct video_i2c_chip { | |
| 65 | + /* video dimensions */ | |
| 66 | + const struct v4l2_fmtdesc *format; | |
| 67 | + const struct v4l2_frmsize_discrete *size; | |
| 68 | + | |
| 69 | + /* max frames per second */ | |
| 70 | + unsigned int max_fps; | |
| 71 | + | |
| 72 | + /* pixel buffer size */ | |
| 73 | + unsigned int buffer_size; | |
| 74 | + | |
| 75 | + /* pixel size in bits */ | |
| 76 | + unsigned int bpp; | |
| 77 | + | |
| 78 | + /* xfer function */ | |
| 79 | + int (*xfer)(struct video_i2c_data *data, char *buf); | |
| 80 | +}; | |
| 81 | + | |
| 82 | +static int amg88xx_xfer(struct video_i2c_data *data, char *buf) | |
| 83 | +{ | |
| 84 | + struct i2c_client *client = data->client; | |
| 85 | + struct i2c_msg msg[2]; | |
| 86 | + u8 reg = 0x80; | |
| 87 | + int ret; | |
| 88 | + | |
| 89 | + msg[0].addr = client->addr; | |
| 90 | + msg[0].flags = 0; | |
| 91 | + msg[0].len = 1; | |
| 92 | + msg[0].buf = (char *)® | |
| 93 | + | |
| 94 | + msg[1].addr = client->addr; | |
| 95 | + msg[1].flags = I2C_M_RD; | |
| 96 | + msg[1].len = data->chip->buffer_size; | |
| 97 | + msg[1].buf = (char *)buf; | |
| 98 | + | |
| 99 | + ret = i2c_transfer(client->adapter, msg, 2); | |
| 100 | + | |
| 101 | + return (ret == 2) ? 0 : -EIO; | |
| 102 | +} | |
| 103 | + | |
| 104 | +#define AMG88XX 0 | |
| 105 | + | |
| 106 | +static const struct video_i2c_chip video_i2c_chip[] = { | |
| 107 | + [AMG88XX] = { | |
| 108 | + .size = &amg88xx_size, | |
| 109 | + .format = &amg88xx_format, | |
| 110 | + .max_fps = 10, | |
| 111 | + .buffer_size = 128, | |
| 112 | + .bpp = 16, | |
| 113 | + .xfer = &amg88xx_xfer, | |
| 114 | + }, | |
| 115 | +}; | |
| 116 | + | |
| 117 | +static const struct v4l2_file_operations video_i2c_fops = { | |
| 118 | + .owner = THIS_MODULE, | |
| 119 | + .open = v4l2_fh_open, | |
| 120 | + .release = vb2_fop_release, | |
| 121 | + .poll = vb2_fop_poll, | |
| 122 | + .read = vb2_fop_read, | |
| 123 | + .mmap = vb2_fop_mmap, | |
| 124 | + .unlocked_ioctl = video_ioctl2, | |
| 125 | +}; | |
| 126 | + | |
| 127 | +static int queue_setup(struct vb2_queue *vq, | |
| 128 | + unsigned int *nbuffers, unsigned int *nplanes, | |
| 129 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 130 | +{ | |
| 131 | + struct video_i2c_data *data = vb2_get_drv_priv(vq); | |
| 132 | + unsigned int size = data->chip->buffer_size; | |
| 133 | + | |
| 134 | + if (vq->num_buffers + *nbuffers < 2) | |
| 135 | + *nbuffers = 2; | |
| 136 | + | |
| 137 | + if (*nplanes) | |
| 138 | + return sizes[0] < size ? -EINVAL : 0; | |
| 139 | + | |
| 140 | + *nplanes = 1; | |
| 141 | + sizes[0] = size; | |
| 142 | + | |
| 143 | + return 0; | |
| 144 | +} | |
| 145 | + | |
| 146 | +static int buffer_prepare(struct vb2_buffer *vb) | |
| 147 | +{ | |
| 148 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 149 | + struct video_i2c_data *data = vb2_get_drv_priv(vb->vb2_queue); | |
| 150 | + unsigned int size = data->chip->buffer_size; | |
| 151 | + | |
| 152 | + if (vb2_plane_size(vb, 0) < size) | |
| 153 | + return -EINVAL; | |
| 154 | + | |
| 155 | + vbuf->field = V4L2_FIELD_NONE; | |
| 156 | + vb2_set_plane_payload(vb, 0, size); | |
| 157 | + | |
| 158 | + return 0; | |
| 159 | +} | |
| 160 | + | |
| 161 | +static void buffer_queue(struct vb2_buffer *vb) | |
| 162 | +{ | |
| 163 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 164 | + struct video_i2c_data *data = vb2_get_drv_priv(vb->vb2_queue); | |
| 165 | + struct video_i2c_buffer *buf = | |
| 166 | + container_of(vbuf, struct video_i2c_buffer, vb); | |
| 167 | + | |
| 168 | + spin_lock(&data->slock); | |
| 169 | + list_add_tail(&buf->list, &data->vid_cap_active); | |
| 170 | + spin_unlock(&data->slock); | |
| 171 | +} | |
| 172 | + | |
| 173 | +static int video_i2c_thread_vid_cap(void *priv) | |
| 174 | +{ | |
| 175 | + struct video_i2c_data *data = priv; | |
| 176 | + unsigned int delay = msecs_to_jiffies(1000 / data->chip->max_fps); | |
| 177 | + | |
| 178 | + set_freezable(); | |
| 179 | + | |
| 180 | + do { | |
| 181 | + unsigned long start_jiffies = jiffies; | |
| 182 | + struct video_i2c_buffer *vid_cap_buf = NULL; | |
| 183 | + int schedule_delay; | |
| 184 | + | |
| 185 | + try_to_freeze(); | |
| 186 | + | |
| 187 | + spin_lock(&data->slock); | |
| 188 | + | |
| 189 | + if (!list_empty(&data->vid_cap_active)) { | |
| 190 | + vid_cap_buf = list_last_entry(&data->vid_cap_active, | |
| 191 | + struct video_i2c_buffer, list); | |
| 192 | + list_del(&vid_cap_buf->list); | |
| 193 | + } | |
| 194 | + | |
| 195 | + spin_unlock(&data->slock); | |
| 196 | + | |
| 197 | + if (vid_cap_buf) { | |
| 198 | + struct vb2_buffer *vb2_buf = &vid_cap_buf->vb.vb2_buf; | |
| 199 | + void *vbuf = vb2_plane_vaddr(vb2_buf, 0); | |
| 200 | + int ret; | |
| 201 | + | |
| 202 | + ret = data->chip->xfer(data, vbuf); | |
| 203 | + vb2_buf->timestamp = ktime_get_ns(); | |
| 204 | + vid_cap_buf->vb.sequence = data->sequence++; | |
| 205 | + vb2_buffer_done(vb2_buf, ret ? | |
| 206 | + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); | |
| 207 | + } | |
| 208 | + | |
| 209 | + schedule_delay = delay - (jiffies - start_jiffies); | |
| 210 | + | |
| 211 | + if (time_after(jiffies, start_jiffies + delay)) | |
| 212 | + schedule_delay = delay; | |
| 213 | + | |
| 214 | + schedule_timeout_interruptible(schedule_delay); | |
| 215 | + } while (!kthread_should_stop()); | |
| 216 | + | |
| 217 | + return 0; | |
| 218 | +} | |
| 219 | + | |
| 220 | +static void video_i2c_del_list(struct vb2_queue *vq, enum vb2_buffer_state state) | |
| 221 | +{ | |
| 222 | + struct video_i2c_data *data = vb2_get_drv_priv(vq); | |
| 223 | + struct video_i2c_buffer *buf, *tmp; | |
| 224 | + | |
| 225 | + spin_lock(&data->slock); | |
| 226 | + | |
| 227 | + list_for_each_entry_safe(buf, tmp, &data->vid_cap_active, list) { | |
| 228 | + list_del(&buf->list); | |
| 229 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 230 | + } | |
| 231 | + | |
| 232 | + spin_unlock(&data->slock); | |
| 233 | +} | |
| 234 | + | |
| 235 | +static int start_streaming(struct vb2_queue *vq, unsigned int count) | |
| 236 | +{ | |
| 237 | + struct video_i2c_data *data = vb2_get_drv_priv(vq); | |
| 238 | + | |
| 239 | + if (data->kthread_vid_cap) | |
| 240 | + return 0; | |
| 241 | + | |
| 242 | + data->sequence = 0; | |
| 243 | + data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data, | |
| 244 | + "%s-vid-cap", data->v4l2_dev.name); | |
| 245 | + if (!IS_ERR(data->kthread_vid_cap)) | |
| 246 | + return 0; | |
| 247 | + | |
| 248 | + video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED); | |
| 249 | + | |
| 250 | + return PTR_ERR(data->kthread_vid_cap); | |
| 251 | +} | |
| 252 | + | |
| 253 | +static void stop_streaming(struct vb2_queue *vq) | |
| 254 | +{ | |
| 255 | + struct video_i2c_data *data = vb2_get_drv_priv(vq); | |
| 256 | + | |
| 257 | + if (data->kthread_vid_cap == NULL) | |
| 258 | + return; | |
| 259 | + | |
| 260 | + kthread_stop(data->kthread_vid_cap); | |
| 261 | + data->kthread_vid_cap = NULL; | |
| 262 | + | |
| 263 | + video_i2c_del_list(vq, VB2_BUF_STATE_ERROR); | |
| 264 | +} | |
| 265 | + | |
| 266 | +static struct vb2_ops video_i2c_video_qops = { | |
| 267 | + .queue_setup = queue_setup, | |
| 268 | + .buf_prepare = buffer_prepare, | |
| 269 | + .buf_queue = buffer_queue, | |
| 270 | + .start_streaming = start_streaming, | |
| 271 | + .stop_streaming = stop_streaming, | |
| 272 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 273 | + .wait_finish = vb2_ops_wait_finish, | |
| 274 | +}; | |
| 275 | + | |
| 276 | +static int video_i2c_querycap(struct file *file, void *priv, | |
| 277 | + struct v4l2_capability *vcap) | |
| 278 | +{ | |
| 279 | + struct video_i2c_data *data = video_drvdata(file); | |
| 280 | + struct i2c_client *client = data->client; | |
| 281 | + | |
| 282 | + strlcpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver)); | |
| 283 | + strlcpy(vcap->card, data->vdev.name, sizeof(vcap->card)); | |
| 284 | + | |
| 285 | + sprintf(vcap->bus_info, "I2C:%d-%d", client->adapter->nr, client->addr); | |
| 286 | + | |
| 287 | + return 0; | |
| 288 | +} | |
| 289 | + | |
| 290 | +static int video_i2c_g_input(struct file *file, void *fh, unsigned int *inp) | |
| 291 | +{ | |
| 292 | + *inp = 0; | |
| 293 | + | |
| 294 | + return 0; | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int video_i2c_s_input(struct file *file, void *fh, unsigned int inp) | |
| 298 | +{ | |
| 299 | + return (inp > 0) ? -EINVAL : 0; | |
| 300 | +} | |
| 301 | + | |
| 302 | +static int video_i2c_enum_input(struct file *file, void *fh, | |
| 303 | + struct v4l2_input *vin) | |
| 304 | +{ | |
| 305 | + if (vin->index > 0) | |
| 306 | + return -EINVAL; | |
| 307 | + | |
| 308 | + strlcpy(vin->name, "Camera", sizeof(vin->name)); | |
| 309 | + | |
| 310 | + vin->type = V4L2_INPUT_TYPE_CAMERA; | |
| 311 | + | |
| 312 | + return 0; | |
| 313 | +} | |
| 314 | + | |
| 315 | +static int video_i2c_enum_fmt_vid_cap(struct file *file, void *fh, | |
| 316 | + struct v4l2_fmtdesc *fmt) | |
| 317 | +{ | |
| 318 | + struct video_i2c_data *data = video_drvdata(file); | |
| 319 | + enum v4l2_buf_type type = fmt->type; | |
| 320 | + | |
| 321 | + if (fmt->index > 0) | |
| 322 | + return -EINVAL; | |
| 323 | + | |
| 324 | + *fmt = *data->chip->format; | |
| 325 | + fmt->type = type; | |
| 326 | + | |
| 327 | + return 0; | |
| 328 | +} | |
| 329 | + | |
| 330 | +static int video_i2c_enum_framesizes(struct file *file, void *fh, | |
| 331 | + struct v4l2_frmsizeenum *fsize) | |
| 332 | +{ | |
| 333 | + const struct video_i2c_data *data = video_drvdata(file); | |
| 334 | + const struct v4l2_frmsize_discrete *size = data->chip->size; | |
| 335 | + | |
| 336 | + /* currently only one frame size is allowed */ | |
| 337 | + if (fsize->index > 0) | |
| 338 | + return -EINVAL; | |
| 339 | + | |
| 340 | + if (fsize->pixel_format != data->chip->format->pixelformat) | |
| 341 | + return -EINVAL; | |
| 342 | + | |
| 343 | + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | |
| 344 | + fsize->discrete.width = size->width; | |
| 345 | + fsize->discrete.height = size->height; | |
| 346 | + | |
| 347 | + return 0; | |
| 348 | +} | |
| 349 | + | |
| 350 | +static int video_i2c_enum_frameintervals(struct file *file, void *priv, | |
| 351 | + struct v4l2_frmivalenum *fe) | |
| 352 | +{ | |
| 353 | + const struct video_i2c_data *data = video_drvdata(file); | |
| 354 | + const struct v4l2_frmsize_discrete *size = data->chip->size; | |
| 355 | + | |
| 356 | + if (fe->index > 0) | |
| 357 | + return -EINVAL; | |
| 358 | + | |
| 359 | + if (fe->width != size->width || fe->height != size->height) | |
| 360 | + return -EINVAL; | |
| 361 | + | |
| 362 | + fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; | |
| 363 | + fe->discrete.numerator = 1; | |
| 364 | + fe->discrete.denominator = data->chip->max_fps; | |
| 365 | + | |
| 366 | + return 0; | |
| 367 | +} | |
| 368 | + | |
| 369 | +static int video_i2c_try_fmt_vid_cap(struct file *file, void *fh, | |
| 370 | + struct v4l2_format *fmt) | |
| 371 | +{ | |
| 372 | + const struct video_i2c_data *data = video_drvdata(file); | |
| 373 | + const struct v4l2_frmsize_discrete *size = data->chip->size; | |
| 374 | + struct v4l2_pix_format *pix = &fmt->fmt.pix; | |
| 375 | + unsigned int bpp = data->chip->bpp / 8; | |
| 376 | + | |
| 377 | + pix->width = size->width; | |
| 378 | + pix->height = size->height; | |
| 379 | + pix->pixelformat = data->chip->format->pixelformat; | |
| 380 | + pix->field = V4L2_FIELD_NONE; | |
| 381 | + pix->bytesperline = pix->width * bpp; | |
| 382 | + pix->sizeimage = pix->bytesperline * pix->height; | |
| 383 | + pix->colorspace = V4L2_COLORSPACE_RAW; | |
| 384 | + | |
| 385 | + return 0; | |
| 386 | +} | |
| 387 | + | |
| 388 | +static int video_i2c_s_fmt_vid_cap(struct file *file, void *fh, | |
| 389 | + struct v4l2_format *fmt) | |
| 390 | +{ | |
| 391 | + struct video_i2c_data *data = video_drvdata(file); | |
| 392 | + | |
| 393 | + if (vb2_is_busy(&data->vb_vidq)) | |
| 394 | + return -EBUSY; | |
| 395 | + | |
| 396 | + return video_i2c_try_fmt_vid_cap(file, fh, fmt); | |
| 397 | +} | |
| 398 | + | |
| 399 | +static int video_i2c_g_parm(struct file *filp, void *priv, | |
| 400 | + struct v4l2_streamparm *parm) | |
| 401 | +{ | |
| 402 | + struct video_i2c_data *data = video_drvdata(filp); | |
| 403 | + | |
| 404 | + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 405 | + return -EINVAL; | |
| 406 | + | |
| 407 | + parm->parm.capture.readbuffers = 1; | |
| 408 | + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | |
| 409 | + parm->parm.capture.timeperframe.numerator = 1; | |
| 410 | + parm->parm.capture.timeperframe.denominator = data->chip->max_fps; | |
| 411 | + | |
| 412 | + return 0; | |
| 413 | +} | |
| 414 | + | |
| 415 | +static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = { | |
| 416 | + .vidioc_querycap = video_i2c_querycap, | |
| 417 | + .vidioc_g_input = video_i2c_g_input, | |
| 418 | + .vidioc_s_input = video_i2c_s_input, | |
| 419 | + .vidioc_enum_input = video_i2c_enum_input, | |
| 420 | + .vidioc_enum_fmt_vid_cap = video_i2c_enum_fmt_vid_cap, | |
| 421 | + .vidioc_enum_framesizes = video_i2c_enum_framesizes, | |
| 422 | + .vidioc_enum_frameintervals = video_i2c_enum_frameintervals, | |
| 423 | + .vidioc_g_fmt_vid_cap = video_i2c_try_fmt_vid_cap, | |
| 424 | + .vidioc_s_fmt_vid_cap = video_i2c_s_fmt_vid_cap, | |
| 425 | + .vidioc_g_parm = video_i2c_g_parm, | |
| 426 | + .vidioc_s_parm = video_i2c_g_parm, | |
| 427 | + .vidioc_try_fmt_vid_cap = video_i2c_try_fmt_vid_cap, | |
| 428 | + .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
| 429 | + .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
| 430 | + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
| 431 | + .vidioc_querybuf = vb2_ioctl_querybuf, | |
| 432 | + .vidioc_qbuf = vb2_ioctl_qbuf, | |
| 433 | + .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
| 434 | + .vidioc_streamon = vb2_ioctl_streamon, | |
| 435 | + .vidioc_streamoff = vb2_ioctl_streamoff, | |
| 436 | +}; | |
| 437 | + | |
| 438 | +static void video_i2c_release(struct video_device *vdev) | |
| 439 | +{ | |
| 440 | + kfree(video_get_drvdata(vdev)); | |
| 441 | +} | |
| 442 | + | |
| 443 | +static int video_i2c_probe(struct i2c_client *client, | |
| 444 | + const struct i2c_device_id *id) | |
| 445 | +{ | |
| 446 | + struct video_i2c_data *data; | |
| 447 | + struct v4l2_device *v4l2_dev; | |
| 448 | + struct vb2_queue *queue; | |
| 449 | + int ret = -ENODEV; | |
| 450 | + | |
| 451 | + data = kzalloc(sizeof(*data), GFP_KERNEL); | |
| 452 | + if (!data) | |
| 453 | + return -ENOMEM; | |
| 454 | + | |
| 455 | + if (dev_fwnode(&client->dev)) | |
| 456 | + data->chip = device_get_match_data(&client->dev); | |
| 457 | + else if (id) | |
| 458 | + data->chip = &video_i2c_chip[id->driver_data]; | |
| 459 | + else | |
| 460 | + goto error_free_device; | |
| 461 | + | |
| 462 | + data->client = client; | |
| 463 | + v4l2_dev = &data->v4l2_dev; | |
| 464 | + strlcpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name)); | |
| 465 | + | |
| 466 | + ret = v4l2_device_register(&client->dev, v4l2_dev); | |
| 467 | + if (ret < 0) | |
| 468 | + goto error_free_device; | |
| 469 | + | |
| 470 | + mutex_init(&data->lock); | |
| 471 | + mutex_init(&data->queue_lock); | |
| 472 | + | |
| 473 | + queue = &data->vb_vidq; | |
| 474 | + queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
| 475 | + queue->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR | VB2_READ; | |
| 476 | + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | |
| 477 | + queue->drv_priv = data; | |
| 478 | + queue->buf_struct_size = sizeof(struct video_i2c_buffer); | |
| 479 | + queue->min_buffers_needed = 1; | |
| 480 | + queue->ops = &video_i2c_video_qops; | |
| 481 | + queue->mem_ops = &vb2_vmalloc_memops; | |
| 482 | + | |
| 483 | + ret = vb2_queue_init(queue); | |
| 484 | + if (ret < 0) | |
| 485 | + goto error_unregister_device; | |
| 486 | + | |
| 487 | + data->vdev.queue = queue; | |
| 488 | + data->vdev.queue->lock = &data->queue_lock; | |
| 489 | + | |
| 490 | + snprintf(data->vdev.name, sizeof(data->vdev.name), | |
| 491 | + "I2C %d-%d Transport Video", | |
| 492 | + client->adapter->nr, client->addr); | |
| 493 | + | |
| 494 | + data->vdev.v4l2_dev = v4l2_dev; | |
| 495 | + data->vdev.fops = &video_i2c_fops; | |
| 496 | + data->vdev.lock = &data->lock; | |
| 497 | + data->vdev.ioctl_ops = &video_i2c_ioctl_ops; | |
| 498 | + data->vdev.release = video_i2c_release; | |
| 499 | + data->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | | |
| 500 | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | |
| 501 | + | |
| 502 | + spin_lock_init(&data->slock); | |
| 503 | + INIT_LIST_HEAD(&data->vid_cap_active); | |
| 504 | + | |
| 505 | + video_set_drvdata(&data->vdev, data); | |
| 506 | + i2c_set_clientdata(client, data); | |
| 507 | + | |
| 508 | + ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1); | |
| 509 | + if (ret < 0) | |
| 510 | + goto error_unregister_device; | |
| 511 | + | |
| 512 | + return 0; | |
| 513 | + | |
| 514 | +error_unregister_device: | |
| 515 | + v4l2_device_unregister(v4l2_dev); | |
| 516 | + mutex_destroy(&data->lock); | |
| 517 | + mutex_destroy(&data->queue_lock); | |
| 518 | + | |
| 519 | +error_free_device: | |
| 520 | + kfree(data); | |
| 521 | + | |
| 522 | + return ret; | |
| 523 | +} | |
| 524 | + | |
| 525 | +static int video_i2c_remove(struct i2c_client *client) | |
| 526 | +{ | |
| 527 | + struct video_i2c_data *data = i2c_get_clientdata(client); | |
| 528 | + | |
| 529 | + video_unregister_device(&data->vdev); | |
| 530 | + v4l2_device_unregister(&data->v4l2_dev); | |
| 531 | + | |
| 532 | + mutex_destroy(&data->lock); | |
| 533 | + mutex_destroy(&data->queue_lock); | |
| 534 | + | |
| 535 | + return 0; | |
| 536 | +} | |
| 537 | + | |
| 538 | +static const struct i2c_device_id video_i2c_id_table[] = { | |
| 539 | + { "amg88xx", AMG88XX }, | |
| 540 | + {} | |
| 541 | +}; | |
| 542 | +MODULE_DEVICE_TABLE(i2c, video_i2c_id_table); | |
| 543 | + | |
| 544 | +static const struct of_device_id video_i2c_of_match[] = { | |
| 545 | + { .compatible = "panasonic,amg88xx", .data = &video_i2c_chip[AMG88XX] }, | |
| 546 | + {} | |
| 547 | +}; | |
| 548 | +MODULE_DEVICE_TABLE(of, video_i2c_of_match); | |
| 549 | + | |
| 550 | +static struct i2c_driver video_i2c_driver = { | |
| 551 | + .driver = { | |
| 552 | + .name = VIDEO_I2C_DRIVER, | |
| 553 | + .of_match_table = video_i2c_of_match, | |
| 554 | + }, | |
| 555 | + .probe = video_i2c_probe, | |
| 556 | + .remove = video_i2c_remove, | |
| 557 | + .id_table = video_i2c_id_table, | |
| 558 | +}; | |
| 559 | + | |
| 560 | +module_i2c_driver(video_i2c_driver); | |
| 561 | + | |
| 562 | +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); | |
| 563 | +MODULE_DESCRIPTION("I2C transport video support"); | |
| 564 | +MODULE_LICENSE("GPL v2"); | |
| @@ -54,9 +54,10 @@ static int media_device_close(struct file *filp) · 53 unmodified lines | ||
| 54 | 54 | return 0; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | −static int media_device_get_info(struct media_device *dev, | |
| 58 | − struct media_device_info *info) | |
| 57 | +static long media_device_get_info(struct media_device *dev, void *arg) | |
| 59 | 58 | { |
| 59 | + struct media_device_info *info = arg; | |
| 60 | + | |
| 60 | 61 | memset(info, 0, sizeof(*info)); |
| 61 | 62 | |
| 62 | 63 | if (dev->driver_name[0]) |
| @@ -93,9 +94,9 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) · 30 unmodified lines | ||
| 93 | 94 | return NULL; |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | −static long media_device_enum_entities(struct media_device *mdev, | |
| 97 | − struct media_entity_desc *entd) | |
| 97 | +static long media_device_enum_entities(struct media_device *mdev, void *arg) | |
| 98 | 98 | { |
| 99 | + struct media_entity_desc *entd = arg; | |
| 99 | 100 | struct media_entity *ent; |
| 100 | 101 | |
| 101 | 102 | ent = find_entity(mdev, entd->id); |
| @@ -146,9 +147,9 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, · 44 unmodified lines | ||
| 146 | 147 | upad->flags = kpad->flags; |
| 147 | 148 | } |
| 148 | 149 | |
| 149 | −static long media_device_enum_links(struct media_device *mdev, | |
| 150 | − struct media_links_enum *links) | |
| 150 | +static long media_device_enum_links(struct media_device *mdev, void *arg) | |
| 151 | 151 | { |
| 152 | + struct media_links_enum *links = arg; | |
| 152 | 153 | struct media_entity *entity; |
| 153 | 154 | |
| 154 | 155 | entity = find_entity(mdev, links->entity); |
| @@ -195,9 +196,9 @@ static long media_device_enum_links(struct media_device *mdev, · 40 unmodified lines | ||
| 195 | 196 | return 0; |
| 196 | 197 | } |
| 197 | 198 | |
| 198 | −static long media_device_setup_link(struct media_device *mdev, | |
| 199 | − struct media_link_desc *linkd) | |
| 199 | +static long media_device_setup_link(struct media_device *mdev, void *arg) | |
| 200 | 200 | { |
| 201 | + struct media_link_desc *linkd = arg; | |
| 201 | 202 | struct media_link *link = NULL; |
| 202 | 203 | struct media_entity *source; |
| 203 | 204 | struct media_entity *sink; |
| @@ -225,9 +226,9 @@ static long media_device_setup_link(struct media_device *mdev, · 21 unmodified lines | ||
| 225 | 226 | return __media_entity_setup_link(link, linkd->flags); |
| 226 | 227 | } |
| 227 | 228 | |
| 228 | −static long media_device_get_topology(struct media_device *mdev, | |
| 229 | − struct media_v2_topology *topo) | |
| 229 | +static long media_device_get_topology(struct media_device *mdev, void *arg) | |
| 230 | 230 | { |
| 231 | + struct media_v2_topology *topo = arg; | |
| 231 | 232 | struct media_entity *entity; |
| 232 | 233 | struct media_interface *intf; |
| 233 | 234 | struct media_pad *pad; |
| @@ -279,7 +279,7 @@ static int smssdio_probe(struct sdio_func *func, · 278 unmodified lines | ||
| 279 | 279 | goto free; |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | − ret = smscore_register_device(¶ms, &smsdev->coredev, NULL); | |
| 282 | + ret = smscore_register_device(¶ms, &smsdev->coredev, GFP_DMA, NULL); | |
| 283 | 283 | if (ret < 0) |
| 284 | 284 | goto free; |
| 285 | 285 | |
| @@ -16,7 +16,6 @@ source "drivers/media/pci/sta2x11/Kconfig" · 15 unmodified lines | ||
| 16 | 16 | source "drivers/media/pci/tw5864/Kconfig" |
| 17 | 17 | source "drivers/media/pci/tw68/Kconfig" |
| 18 | 18 | source "drivers/media/pci/tw686x/Kconfig" |
| 19 | −source "drivers/media/pci/zoran/Kconfig" | |
| 20 | 19 | endif |
| 21 | 20 | |
| 22 | 21 | if MEDIA_ANALOG_TV_SUPPORT |
| @@ -18,7 +18,6 @@ obj-y += ttpci/ \ · 17 unmodified lines | ||
| 18 | 18 | intel/ |
| 19 | 19 | |
| 20 | 20 | obj-$(CONFIG_VIDEO_IVTV) += ivtv/ |
| 21 | −obj-$(CONFIG_VIDEO_ZORAN) += zoran/ | |
| 22 | 21 | obj-$(CONFIG_VIDEO_CX18) += cx18/ |
| 23 | 22 | obj-$(CONFIG_VIDEO_CX23885) += cx23885/ |
| 24 | 23 | obj-$(CONFIG_VIDEO_CX25821) += cx25821/ |
| @@ -189,20 +189,21 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, · 188 unmodified lines | ||
| 189 | 189 | yoffset -= sg_dma_len(ysg); |
| 190 | 190 | ysg = sg_next(ysg); |
| 191 | 191 | } |
| 192 | − while (uoffset && uoffset >= sg_dma_len(usg)) { | |
| 193 | − uoffset -= sg_dma_len(usg); | |
| 194 | − usg = sg_next(usg); | |
| 195 | − } | |
| 196 | − while (voffset && voffset >= sg_dma_len(vsg)) { | |
| 197 | − voffset -= sg_dma_len(vsg); | |
| 198 | − vsg = sg_next(vsg); | |
| 199 | − } | |
| 200 | 192 | |
| 201 | 193 | /* calculate max number of bytes we can write */ |
| 202 | 194 | ylen = todo; |
| 203 | 195 | if (yoffset + ylen > sg_dma_len(ysg)) |
| 204 | 196 | ylen = sg_dma_len(ysg) - yoffset; |
| 205 | 197 | if (chroma) { |
| 198 | + while (uoffset && uoffset >= sg_dma_len(usg)) { | |
| 199 | + uoffset -= sg_dma_len(usg); | |
| 200 | + usg = sg_next(usg); | |
| 201 | + } | |
| 202 | + while (voffset && voffset >= sg_dma_len(vsg)) { | |
| 203 | + voffset -= sg_dma_len(vsg); | |
| 204 | + vsg = sg_next(vsg); | |
| 205 | + } | |
| 206 | + | |
| 206 | 207 | if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) |
| 207 | 208 | ylen = (sg_dma_len(usg) - uoffset) << hshift; |
| 208 | 209 | if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) |
| @@ -1657,7 +1657,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, · 1656 unmodified lines | ||
| 1657 | 1657 | return 0; |
| 1658 | 1658 | } |
| 1659 | 1659 | |
| 1660 | −static int dst_get_tuning_algo(struct dvb_frontend *fe) | |
| 1660 | +static enum dvbfe_algo dst_get_tuning_algo(struct dvb_frontend *fe) | |
| 1661 | 1661 | { |
| 1662 | 1662 | return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; |
| 1663 | 1663 | } |
| @@ -575,7 +575,6 @@ static struct mt352_config digitv_alps_tded4_config = { · 574 unmodified lines | ||
| 575 | 575 | }; |
| 576 | 576 | |
| 577 | 577 | static struct lgdt330x_config tdvs_tua6034_config = { |
| 578 | − .demod_address = 0x0e, | |
| 579 | 578 | .demod_chip = LGDT3303, |
| 580 | 579 | .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ |
| 581 | 580 | }; |
| @@ -614,7 +613,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) · 32 unmodified lines | ||
| 614 | 613 | |
| 615 | 614 | case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: |
| 616 | 615 | lgdt330x_reset(card); |
| 617 | − card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); | |
| 616 | + card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, | |
| 617 | + 0x0e, card->i2c_adapter); | |
| 618 | 618 | if (card->fe != NULL) { |
| 619 | 619 | dvb_attach(simple_tuner_attach, card->fe, |
| 620 | 620 | card->i2c_adapter, 0x61, |
| @@ -422,19 +422,30 @@ static void cx23885_wakeup(struct cx23885_tsport *port, · 421 unmodified lines | ||
| 422 | 422 | struct cx23885_dmaqueue *q, u32 count) |
| 423 | 423 | { |
| 424 | 424 | struct cx23885_buffer *buf; |
| 425 | − | |
| 426 | − if (list_empty(&q->active)) | |
| 427 | − return; | |
| 428 | − buf = list_entry(q->active.next, | |
| 429 | − struct cx23885_buffer, queue); | |
| 430 | − | |
| 431 | − buf->vb.vb2_buf.timestamp = ktime_get_ns(); | |
| 432 | − buf->vb.sequence = q->count++; | |
| 433 | − dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, | |
| 434 | − buf->vb.vb2_buf.index, | |
| 435 | − count, q->count); | |
| 436 | − list_del(&buf->queue); | |
| 437 | − vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); | |
| 425 | + int count_delta; | |
| 426 | + int max_buf_done = 5; /* service maximum five buffers */ | |
| 427 | + | |
| 428 | + do { | |
| 429 | + if (list_empty(&q->active)) | |
| 430 | + return; | |
| 431 | + buf = list_entry(q->active.next, | |
| 432 | + struct cx23885_buffer, queue); | |
| 433 | + | |
| 434 | + buf->vb.vb2_buf.timestamp = ktime_get_ns(); | |
| 435 | + buf->vb.sequence = q->count++; | |
| 436 | + if (count != (q->count % 65536)) { | |
| 437 | + dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, | |
| 438 | + buf->vb.vb2_buf.index, count, q->count); | |
| 439 | + } else { | |
| 440 | + dprintk(7, "[%p/%d] wakeup reg=%d buf=%d\n", buf, | |
| 441 | + buf->vb.vb2_buf.index, count, q->count); | |
| 442 | + } | |
| 443 | + list_del(&buf->queue); | |
| 444 | + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); | |
| 445 | + max_buf_done--; | |
| 446 | + /* count register is 16 bits so apply modulo appropriately */ | |
| 447 | + count_delta = ((int)count - (int)(q->count % 65536)); | |
| 448 | + } while ((count_delta > 0) && (max_buf_done > 0)); | |
| 438 | 449 | } |
| 439 | 450 | |
| 440 | 451 | int cx23885_sram_channel_setup(struct cx23885_dev *dev, |
| @@ -590,6 +601,25 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, · 149 unmodified lines | ||
| 590 | 601 | } |
| 591 | 602 | } |
| 592 | 603 | |
| 604 | +static void cx23885_clear_bridge_error(struct cx23885_dev *dev) | |
| 605 | +{ | |
| 606 | + uint32_t reg1_val = cx_read(TC_REQ); /* read-only */ | |
| 607 | + uint32_t reg2_val = cx_read(TC_REQ_SET); | |
| 608 | + | |
| 609 | + if (reg1_val && reg2_val) { | |
| 610 | + cx_write(TC_REQ, reg1_val); | |
| 611 | + cx_write(TC_REQ_SET, reg2_val); | |
| 612 | + cx_read(VID_B_DMA); | |
| 613 | + cx_read(VBI_B_DMA); | |
| 614 | + cx_read(VID_C_DMA); | |
| 615 | + cx_read(VBI_C_DMA); | |
| 616 | + | |
| 617 | + dev_info(&dev->pci->dev, | |
| 618 | + "dma in progress detected 0x%08x 0x%08x, clearing\n", | |
| 619 | + reg1_val, reg2_val); | |
| 620 | + } | |
| 621 | +} | |
| 622 | + | |
| 593 | 623 | static void cx23885_shutdown(struct cx23885_dev *dev) |
| 594 | 624 | { |
| 595 | 625 | /* disable RISC controller */ |
| @@ -635,6 +665,8 @@ static void cx23885_reset(struct cx23885_dev *dev) · 39 unmodified lines | ||
| 635 | 665 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); |
| 636 | 666 | cx_write(PAD_CTRL, 0x00500300); |
| 637 | 667 | |
| 668 | + /* clear dma in progress */ | |
| 669 | + cx23885_clear_bridge_error(dev); | |
| 638 | 670 | mdelay(100); |
| 639 | 671 | |
| 640 | 672 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], |
| @@ -651,6 +683,11 @@ static void cx23885_reset(struct cx23885_dev *dev) · 10 unmodified lines | ||
| 651 | 683 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); |
| 652 | 684 | |
| 653 | 685 | cx23885_gpio_setup(dev); |
| 686 | + | |
| 687 | + cx23885_irq_get_mask(dev); | |
| 688 | + | |
| 689 | + /* clear dma in progress */ | |
| 690 | + cx23885_clear_bridge_error(dev); | |
| 654 | 691 | } |
| 655 | 692 | |
| 656 | 693 | |
| @@ -665,6 +702,8 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) · 8 unmodified lines | ||
| 665 | 702 | if (dev->bridge == CX23885_BRIDGE_885) |
| 666 | 703 | cx_clear(RDR_TLCTL0, 1 << 4); |
| 667 | 704 | |
| 705 | + /* clear dma in progress */ | |
| 706 | + cx23885_clear_bridge_error(dev); | |
| 668 | 707 | return 0; |
| 669 | 708 | } |
| 670 | 709 | |
| @@ -1329,6 +1368,18 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) · 658 unmodified lines | ||
| 1329 | 1368 | port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); |
| 1330 | 1369 | dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, |
| 1331 | 1370 | port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); |
| 1371 | + dprintk(1, "%s() ts_int_status(0x%08X) 0x%08x\n", __func__, | |
| 1372 | + port->reg_ts_int_stat, cx_read(port->reg_ts_int_stat)); | |
| 1373 | + dprintk(1, "%s() PCI_INT_STAT 0x%08X\n", __func__, | |
| 1374 | + cx_read(PCI_INT_STAT)); | |
| 1375 | + dprintk(1, "%s() VID_B_INT_MSTAT 0x%08X\n", __func__, | |
| 1376 | + cx_read(VID_B_INT_MSTAT)); | |
| 1377 | + dprintk(1, "%s() VID_B_INT_SSTAT 0x%08X\n", __func__, | |
| 1378 | + cx_read(VID_B_INT_SSTAT)); | |
| 1379 | + dprintk(1, "%s() VID_C_INT_MSTAT 0x%08X\n", __func__, | |
| 1380 | + cx_read(VID_C_INT_MSTAT)); | |
| 1381 | + dprintk(1, "%s() VID_C_INT_SSTAT 0x%08X\n", __func__, | |
| 1382 | + cx_read(VID_C_INT_SSTAT)); | |
| 1332 | 1383 | } |
| 1333 | 1384 | |
| 1334 | 1385 | int cx23885_start_dma(struct cx23885_tsport *port, |
| @@ -1341,6 +1392,9 @@ int cx23885_start_dma(struct cx23885_tsport *port, · 6 unmodified lines | ||
| 1341 | 1392 | dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, |
| 1342 | 1393 | dev->width, dev->height, dev->field); |
| 1343 | 1394 | |
| 1395 | + /* clear dma in progress */ | |
| 1396 | + cx23885_clear_bridge_error(dev); | |
| 1397 | + | |
| 1344 | 1398 | /* Stop the fifo and risc engine for this port */ |
| 1345 | 1399 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); |
| 1346 | 1400 | |
| @@ -1410,8 +1464,15 @@ int cx23885_start_dma(struct cx23885_tsport *port, · 63 unmodified lines | ||
| 1410 | 1464 | reg = reg | 0xa; |
| 1411 | 1465 | cx_write(PAD_CTRL, reg); |
| 1412 | 1466 | |
| 1413 | − /* FIXME and these two registers should be documented. */ | |
| 1467 | + /* Sets MOE_CLK_DIS to disable MoE clock */ | |
| 1468 | + /* sets MCLK_DLY_SEL/BCLK_DLY_SEL to 1 buffer delay each */ | |
| 1414 | 1469 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); |
| 1470 | + | |
| 1471 | + /* ALT_GPIO_ALT_SET: GPIO[0] | |
| 1472 | + * IR_ALT_TX_SEL: GPIO[1] | |
| 1473 | + * GPIO1_ALT_SEL: VIP_656_DATA[0] | |
| 1474 | + * GPIO0_ALT_SEL: VIP_656_CLK | |
| 1475 | + */ | |
| 1415 | 1476 | cx_write(ALT_PIN_OUT_SEL, 0x10100045); |
| 1416 | 1477 | } |
| 1417 | 1478 | |
| @@ -1421,16 +1482,26 @@ int cx23885_start_dma(struct cx23885_tsport *port, · 3 unmodified lines | ||
| 1421 | 1482 | case CX23885_BRIDGE_888: |
| 1422 | 1483 | /* enable irqs */ |
| 1423 | 1484 | dprintk(1, "%s() enabling TS int's and DMA\n", __func__); |
| 1485 | + /* clear dma in progress */ | |
| 1486 | + cx23885_clear_bridge_error(dev); | |
| 1424 | 1487 | cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); |
| 1425 | 1488 | cx_set(port->reg_dma_ctl, port->dma_ctl_val); |
| 1489 | + | |
| 1490 | + /* clear dma in progress */ | |
| 1491 | + cx23885_clear_bridge_error(dev); | |
| 1426 | 1492 | cx23885_irq_add(dev, port->pci_irqmask); |
| 1427 | 1493 | cx23885_irq_enable_all(dev); |
| 1494 | + | |
| 1495 | + /* clear dma in progress */ | |
| 1496 | + cx23885_clear_bridge_error(dev); | |
| 1428 | 1497 | break; |
| 1429 | 1498 | default: |
| 1430 | 1499 | BUG(); |
| 1431 | 1500 | } |
| 1432 | 1501 | |
| 1433 | 1502 | cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ |
| 1503 | + /* clear dma in progress */ | |
| 1504 | + cx23885_clear_bridge_error(dev); | |
| 1434 | 1505 | |
| 1435 | 1506 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) |
| 1436 | 1507 | cx23885_av_clk(dev, 1); |
| @@ -1438,6 +1509,11 @@ int cx23885_start_dma(struct cx23885_tsport *port, · 1 unmodified line | ||
| 1438 | 1509 | if (debug > 4) |
| 1439 | 1510 | cx23885_tsport_reg_dump(port); |
| 1440 | 1511 | |
| 1512 | + cx23885_irq_get_mask(dev); | |
| 1513 | + | |
| 1514 | + /* clear dma in progress */ | |
| 1515 | + cx23885_clear_bridge_error(dev); | |
| 1516 | + | |
| 1441 | 1517 | return 0; |
| 1442 | 1518 | } |
| 1443 | 1519 | |
| @@ -1445,15 +1521,28 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) · 1 unmodified line | ||
| 1445 | 1521 | { |
| 1446 | 1522 | struct cx23885_dev *dev = port->dev; |
| 1447 | 1523 | u32 reg; |
| 1524 | + int delay = 0; | |
| 1525 | + uint32_t reg1_val; | |
| 1526 | + uint32_t reg2_val; | |
| 1448 | 1527 | |
| 1449 | 1528 | dprintk(1, "%s()\n", __func__); |
| 1450 | 1529 | |
| 1451 | 1530 | /* Stop interrupts and DMA */ |
| 1452 | 1531 | cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); |
| 1453 | 1532 | cx_clear(port->reg_dma_ctl, port->dma_ctl_val); |
| 1533 | + /* just in case wait for any dma to complete before allowing dealloc */ | |
| 1534 | + mdelay(20); | |
| 1535 | + for (delay = 0; delay < 100; delay++) { | |
| 1536 | + reg1_val = cx_read(TC_REQ); | |
| 1537 | + reg2_val = cx_read(TC_REQ_SET); | |
| 1538 | + if (reg1_val == 0 || reg2_val == 0) | |
| 1539 | + break; | |
| 1540 | + mdelay(1); | |
| 1541 | + } | |
| 1542 | + dev_dbg(&dev->pci->dev, "delay=%d reg1=0x%08x reg2=0x%08x\n", | |
| 1543 | + delay, reg1_val, reg2_val); | |
| 1454 | 1544 | |
| 1455 | 1545 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { |
| 1456 | − | |
| 1457 | 1546 | reg = cx_read(PAD_CTRL); |
| 1458 | 1547 | |
| 1459 | 1548 | /* Set TS1_OE */ |
| @@ -1464,7 +1553,6 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) · 4 unmodified lines | ||
| 1464 | 1553 | cx_write(PAD_CTRL, reg); |
| 1465 | 1554 | cx_write(port->reg_src_sel, 0); |
| 1466 | 1555 | cx_write(port->reg_gen_ctrl, 8); |
| 1467 | − | |
| 1468 | 1556 | } |
| 1469 | 1557 | |
| 1470 | 1558 | if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) |
| @@ -1693,6 +1781,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) · 222 unmodified lines | ||
| 1693 | 1781 | |
| 1694 | 1782 | pci_status = cx_read(PCI_INT_STAT); |
| 1695 | 1783 | pci_mask = cx23885_irq_get_mask(dev); |
| 1784 | + if ((pci_status & pci_mask) == 0) { | |
| 1785 | + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", | |
| 1786 | + pci_status, pci_mask); | |
| 1787 | + goto out; | |
| 1788 | + } | |
| 1789 | + | |
| 1696 | 1790 | vida_status = cx_read(VID_A_INT_STAT); |
| 1697 | 1791 | vida_mask = cx_read(VID_A_INT_MSK); |
| 1698 | 1792 | audint_status = cx_read(AUDIO_INT_INT_STAT); |
| @@ -1702,7 +1796,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) · 3 unmodified lines | ||
| 1702 | 1796 | ts2_status = cx_read(VID_C_INT_STAT); |
| 1703 | 1797 | ts2_mask = cx_read(VID_C_INT_MSK); |
| 1704 | 1798 | |
| 1705 | − if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) | |
| 1799 | + if (((pci_status & pci_mask) == 0) && | |
| 1800 | + ((ts2_status & ts2_mask) == 0) && | |
| 1801 | + ((ts1_status & ts1_mask) == 0)) | |
| 1706 | 1802 | goto out; |
| 1707 | 1803 | |
| 1708 | 1804 | vida_count = cx_read(VID_A_GPCNT); |
| @@ -1829,7 +1925,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) · 120 unmodified lines | ||
| 1829 | 1925 | } |
| 1830 | 1926 | |
| 1831 | 1927 | if (handled) |
| 1832 | − cx_write(PCI_INT_STAT, pci_status); | |
| 1928 | + cx_write(PCI_INT_STAT, pci_status & pci_mask); | |
| 1833 | 1929 | out: |
| 1834 | 1930 | return IRQ_RETVAL(handled); |
| 1835 | 1931 | } |
| @@ -252,7 +252,6 @@ static struct mt2131_config hauppauge_generic_tunerconfig = { · 251 unmodified lines | ||
| 252 | 252 | }; |
| 253 | 253 | |
| 254 | 254 | static struct lgdt330x_config fusionhdtv_5_express = { |
| 255 | − .demod_address = 0x0e, | |
| 256 | 255 | .demod_chip = LGDT3303, |
| 257 | 256 | .serial_mpeg = 0x40, |
| 258 | 257 | }; |
| @@ -1321,8 +1320,9 @@ static int dvb_register(struct cx23885_tsport *port) · 1062 unmodified lines | ||
| 1321 | 1320 | case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: |
| 1322 | 1321 | i2c_bus = &dev->i2c_bus[0]; |
| 1323 | 1322 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, |
| 1324 | − &fusionhdtv_5_express, | |
| 1325 | − &i2c_bus->i2c_adap); | |
| 1323 | + &fusionhdtv_5_express, | |
| 1324 | + 0x0e, | |
| 1325 | + &i2c_bus->i2c_adap); | |
| 1326 | 1326 | if (fe0->dvb.frontend == NULL) |
| 1327 | 1327 | break; |
| 1328 | 1328 | dvb_attach(simple_tuner_attach, fe0->dvb.frontend, |
| @@ -288,6 +288,18 @@ Channel manager Data Structure entry = 20 DWORD · 287 unmodified lines | ||
| 288 | 288 | #define AUDIO_EXT_INT_MSTAT 0x00040068 |
| 289 | 289 | #define AUDIO_EXT_INT_SSTAT 0x0004006C |
| 290 | 290 | |
| 291 | +/* Bits [7:0] set in both TC_REQ and TC_REQ_SET | |
| 292 | + * indicate a stall in the RISC engine for a | |
| 293 | + * particular rider traffic class. This causes | |
| 294 | + * the 885 and 888 bridges (unknown about 887) | |
| 295 | + * to become inoperable. Setting bits in | |
| 296 | + * TC_REQ_SET resets the corresponding bits | |
| 297 | + * in TC_REQ (and TC_REQ_SET) allowing | |
| 298 | + * operation to continue. | |
| 299 | + */ | |
| 300 | +#define TC_REQ 0x00040090 | |
| 301 | +#define TC_REQ_SET 0x00040094 | |
| 302 | + | |
| 291 | 303 | #define RDR_CFG0 0x00050000 |
| 292 | 304 | #define RDR_CFG1 0x00050004 |
| 293 | 305 | #define RDR_CFG2 0x00050008 |
| @@ -386,6 +398,8 @@ Channel manager Data Structure entry = 20 DWORD · 92 unmodified lines | ||
| 386 | 398 | #define VID_B_PIXEL_FRMT 0x00130184 |
| 387 | 399 | |
| 388 | 400 | /* Video C Interface */ |
| 401 | +#define VID_C_DMA 0x00130200 | |
| 402 | +#define VBI_C_DMA 0x00130208 | |
| 389 | 403 | #define VID_C_GPCNT 0x00130220 |
| 390 | 404 | #define VID_C_GPCNT_CTL 0x00130230 |
| 391 | 405 | #define VBI_C_GPCNT_CTL 0x00130234 |
| @@ -411,21 +411,18 @@ static int lgdt330x_set_ts_param(struct dvb_frontend *fe, int is_punctured) · 410 unmodified lines | ||
| 411 | 411 | } |
| 412 | 412 | |
| 413 | 413 | static struct lgdt330x_config fusionhdtv_3_gold = { |
| 414 | − .demod_address = 0x0e, | |
| 415 | 414 | .demod_chip = LGDT3302, |
| 416 | 415 | .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */ |
| 417 | 416 | .set_ts_params = lgdt330x_set_ts_param, |
| 418 | 417 | }; |
| 419 | 418 | |
| 420 | 419 | static const struct lgdt330x_config fusionhdtv_5_gold = { |
| 421 | − .demod_address = 0x0e, | |
| 422 | 420 | .demod_chip = LGDT3303, |
| 423 | 421 | .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ |
| 424 | 422 | .set_ts_params = lgdt330x_set_ts_param, |
| 425 | 423 | }; |
| 426 | 424 | |
| 427 | 425 | static const struct lgdt330x_config pchdtv_hd5500 = { |
| 428 | − .demod_address = 0x59, | |
| 429 | 426 | .demod_chip = LGDT3303, |
| 430 | 427 | .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ |
| 431 | 428 | .set_ts_params = lgdt330x_set_ts_param, |
| @@ -1237,6 +1234,7 @@ static int dvb_register(struct cx8802_dev *dev) · 805 unmodified lines | ||
| 1237 | 1234 | fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; |
| 1238 | 1235 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, |
| 1239 | 1236 | &fusionhdtv_3_gold, |
| 1237 | + 0x0e, | |
| 1240 | 1238 | &core->i2c_adap); |
| 1241 | 1239 | if (fe0->dvb.frontend) { |
| 1242 | 1240 | if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, |
| @@ -1255,6 +1253,7 @@ static int dvb_register(struct cx8802_dev *dev) · 12 unmodified lines | ||
| 1255 | 1253 | mdelay(200); |
| 1256 | 1254 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, |
| 1257 | 1255 | &fusionhdtv_3_gold, |
| 1256 | + 0x0e, | |
| 1258 | 1257 | &core->i2c_adap); |
| 1259 | 1258 | if (fe0->dvb.frontend) { |
| 1260 | 1259 | if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, |
| @@ -1273,6 +1272,7 @@ static int dvb_register(struct cx8802_dev *dev) · 12 unmodified lines | ||
| 1273 | 1272 | mdelay(200); |
| 1274 | 1273 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, |
| 1275 | 1274 | &fusionhdtv_5_gold, |
| 1275 | + 0x0e, | |
| 1276 | 1276 | &core->i2c_adap); |
| 1277 | 1277 | if (fe0->dvb.frontend) { |
| 1278 | 1278 | if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, |
| @@ -1294,6 +1294,7 @@ static int dvb_register(struct cx8802_dev *dev) · 15 unmodified lines | ||
| 1294 | 1294 | mdelay(200); |
| 1295 | 1295 | fe0->dvb.frontend = dvb_attach(lgdt330x_attach, |
| 1296 | 1296 | &pchdtv_hd5500, |
| 1297 | + 0x59, | |
| 1297 | 1298 | &core->i2c_adap); |
| 1298 | 1299 | if (fe0->dvb.frontend) { |
| 1299 | 1300 | if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, |
| @@ -180,7 +180,8 @@ static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) · 179 unmodified lines | ||
| 180 | 180 | struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); |
| 181 | 181 | |
| 182 | 182 | cx88_ir_handle_key(ir); |
| 183 | − missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000LL); | |
| 183 | + missed = hrtimer_forward_now(&ir->timer, | |
| 184 | + ktime_set(0, ir->polling * 1000000)); | |
| 184 | 185 | if (missed > 1) |
| 185 | 186 | ir_dprintk("Missed ticks %ld\n", missed - 1); |
| 186 | 187 | |
| @@ -200,7 +201,8 @@ static int __cx88_ir_start(void *priv) · 13 unmodified lines | ||
| 200 | 201 | if (ir->polling) { |
| 201 | 202 | hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 202 | 203 | ir->timer.function = cx88_ir_work; |
| 203 | − hrtimer_start(&ir->timer, ir->polling * 1000000LL, | |
| 204 | + hrtimer_start(&ir->timer, | |
| 205 | + ktime_set(0, ir->polling * 1000000), | |
| 204 | 206 | HRTIMER_MODE_REL); |
| 205 | 207 | } |
| 206 | 208 | if (ir->sampling) { |
| @@ -632,8 +634,9 @@ void cx88_i2c_init_ir(struct cx88_core *core) · 425 unmodified lines | ||
| 632 | 634 | memset(&core->init_data, 0, sizeof(core->init_data)); |
| 633 | 635 | |
| 634 | 636 | if (*addrp == 0x71) { |
| 635 | − /* Hauppauge XVR */ | |
| 636 | − core->init_data.name = "cx88 Hauppauge XVR remote"; | |
| 637 | + /* Hauppauge Z8F0811 */ | |
| 638 | + strlcpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE); | |
| 639 | + core->init_data.name = core->board.name; | |
| 637 | 640 | core->init_data.ir_codes = RC_MAP_HAUPPAUGE; |
| 638 | 641 | core->init_data.type = RC_PROTO_BIT_RC5 | |
| 639 | 642 | RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32; |
| @@ -178,7 +178,6 @@ static void buffer_queue(struct vb2_buffer *vb) · 177 unmodified lines | ||
| 178 | 178 | |
| 179 | 179 | if (list_empty(&q->active)) { |
| 180 | 180 | list_add_tail(&buf->list, &q->active); |
| 181 | − cx8800_start_vbi_dma(dev, q, buf); | |
| 182 | 181 | dprintk(2, "[%p/%d] vbi_queue - first active\n", |
| 183 | 182 | buf, buf->vb.vb2_buf.index); |
| 184 | 183 | |
| @@ -14,6 +14,7 @@ config DVB_DDBRIDGE · 13 unmodified lines | ||
| 14 | 14 | select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT |
| 15 | 15 | select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT |
| 16 | 16 | select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT |
| 17 | + select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT | |
| 17 | 18 | ---help--- |
| 18 | 19 | Support for cards with the Digital Devices PCI express bridge: |
| 19 | 20 | - Octopus PCIe Bridge |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | # |
| 5 | 5 | |
| 6 | 6 | ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-ci.o \ |
| 7 | − ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o | |
| 7 | + ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o ddbridge-mci.o | |
| 8 | 8 | |
| 9 | 9 | obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o |
| 10 | 10 | |
| @@ -164,7 +164,7 @@ static struct dvb_ca_en50221 en_templ = { · 163 unmodified lines | ||
| 164 | 164 | |
| 165 | 165 | static void ci_attach(struct ddb_port *port) |
| 166 | 166 | { |
| 167 | − struct ddb_ci *ci = NULL; | |
| 167 | + struct ddb_ci *ci; | |
| 168 | 168 | |
| 169 | 169 | ci = kzalloc(sizeof(*ci), GFP_KERNEL); |
| 170 | 170 | if (!ci) |
| @@ -54,6 +54,7 @@ · 53 unmodified lines | ||
| 54 | 54 | #include "stv6111.h" |
| 55 | 55 | #include "lnbh25.h" |
| 56 | 56 | #include "cxd2099.h" |
| 57 | +#include "dvb_dummy_fe.h" | |
| 57 | 58 | |
| 58 | 59 | /****************************************************************************/ |
| 59 | 60 | |
| @@ -68,11 +69,53 @@ module_param(adapter_alloc, int, 0444); · 8 unmodified lines | ||
| 68 | 69 | MODULE_PARM_DESC(adapter_alloc, |
| 69 | 70 | "0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all"); |
| 70 | 71 | |
| 72 | +static int ci_bitrate = 70000; | |
| 73 | +module_param(ci_bitrate, int, 0444); | |
| 74 | +MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI."); | |
| 75 | + | |
| 76 | +static int ts_loop = -1; | |
| 77 | +module_param(ts_loop, int, 0444); | |
| 78 | +MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop"); | |
| 79 | + | |
| 80 | +static int xo2_speed = 2; | |
| 81 | +module_param(xo2_speed, int, 0444); | |
| 82 | +MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); | |
| 83 | + | |
| 84 | +#ifdef __arm__ | |
| 85 | +static int alt_dma = 1; | |
| 86 | +#else | |
| 87 | +static int alt_dma; | |
| 88 | +#endif | |
| 89 | +module_param(alt_dma, int, 0444); | |
| 90 | +MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling"); | |
| 91 | + | |
| 92 | +static int no_init; | |
| 93 | +module_param(no_init, int, 0444); | |
| 94 | +MODULE_PARM_DESC(no_init, "do not initialize most devices"); | |
| 95 | + | |
| 96 | +static int stv0910_single; | |
| 97 | +module_param(stv0910_single, int, 0444); | |
| 98 | +MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods"); | |
| 99 | + | |
| 100 | +static int dma_buf_num = 8; | |
| 101 | +module_param(dma_buf_num, int, 0444); | |
| 102 | +MODULE_PARM_DESC(dma_buf_num, "Number of DMA buffers, possible values: 8-32"); | |
| 103 | + | |
| 104 | +static int dma_buf_size = 21; | |
| 105 | +module_param(dma_buf_size, int, 0444); | |
| 106 | +MODULE_PARM_DESC(dma_buf_size, | |
| 107 | + "DMA buffer size as multiple of 128*47, possible values: 1-43"); | |
| 108 | + | |
| 109 | +static int dummy_tuner; | |
| 110 | +module_param(dummy_tuner, int, 0444); | |
| 111 | +MODULE_PARM_DESC(dummy_tuner, | |
| 112 | + "attach dummy tuner to port 0 on Octopus V3 or Octopus Mini cards"); | |
| 113 | + | |
| 71 | 114 | /****************************************************************************/ |
| 72 | 115 | |
| 73 | 116 | static DEFINE_MUTEX(redirect_lock); |
| 74 | 117 | |
| 75 | −struct workqueue_struct *ddb_wq; | |
| 118 | +static struct workqueue_struct *ddb_wq; | |
| 76 | 119 | |
| 77 | 120 | static struct ddb *ddbs[DDB_MAX_ADAPTER]; |
| 78 | 121 | |
| @@ -80,6 +123,16 @@ static struct ddb *ddbs[DDB_MAX_ADAPTER]; · 1 unmodified line | ||
| 80 | 123 | /****************************************************************************/ |
| 81 | 124 | /****************************************************************************/ |
| 82 | 125 | |
| 126 | +struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr, | |
| 127 | + void (*handler)(void *), void *data) | |
| 128 | +{ | |
| 129 | + struct ddb_irq *irq = &dev->link[link].irq[nr]; | |
| 130 | + | |
| 131 | + irq->handler = handler; | |
| 132 | + irq->data = data; | |
| 133 | + return irq; | |
| 134 | +} | |
| 135 | + | |
| 83 | 136 | static void ddb_set_dma_table(struct ddb_io *io) |
| 84 | 137 | { |
| 85 | 138 | struct ddb *dev = io->port->dev; |
| @@ -410,13 +463,11 @@ static void ddb_output_start(struct ddb_output *output) · 324 unmodified lines | ||
| 410 | 463 | struct ddb *dev = output->port->dev; |
| 411 | 464 | u32 con = 0x11c, con2 = 0; |
| 412 | 465 | |
| 413 | − if (output->dma) { | |
| 414 | − spin_lock_irq(&output->dma->lock); | |
| 415 | − output->dma->cbuf = 0; | |
| 416 | − output->dma->coff = 0; | |
| 417 | − output->dma->stat = 0; | |
| 418 | − ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); | |
| 419 | − } | |
| 466 | + spin_lock_irq(&output->dma->lock); | |
| 467 | + output->dma->cbuf = 0; | |
| 468 | + output->dma->coff = 0; | |
| 469 | + output->dma->stat = 0; | |
| 470 | + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); | |
| 420 | 471 | |
| 421 | 472 | if (output->port->input[0]->port->class == DDB_PORT_LOOP) |
| 422 | 473 | con = (1UL << 13) | 0x14; |
| @@ -429,36 +480,29 @@ static void ddb_output_start(struct ddb_output *output) · 6 unmodified lines | ||
| 429 | 480 | ddbwritel(dev, con, TS_CONTROL(output)); |
| 430 | 481 | ddbwritel(dev, con2, TS_CONTROL2(output)); |
| 431 | 482 | |
| 432 | − if (output->dma) { | |
| 433 | − ddbwritel(dev, output->dma->bufval, | |
| 434 | − DMA_BUFFER_SIZE(output->dma)); | |
| 435 | − ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma)); | |
| 436 | − ddbwritel(dev, 1, DMA_BASE_READ); | |
| 437 | − ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma)); | |
| 438 | − } | |
| 483 | + ddbwritel(dev, output->dma->bufval, | |
| 484 | + DMA_BUFFER_SIZE(output->dma)); | |
| 485 | + ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma)); | |
| 486 | + ddbwritel(dev, 1, DMA_BASE_READ); | |
| 487 | + ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma)); | |
| 439 | 488 | |
| 440 | 489 | ddbwritel(dev, con | 1, TS_CONTROL(output)); |
| 441 | 490 | |
| 442 | − if (output->dma) { | |
| 443 | − output->dma->running = 1; | |
| 444 | − spin_unlock_irq(&output->dma->lock); | |
| 445 | − } | |
| 491 | + output->dma->running = 1; | |
| 492 | + spin_unlock_irq(&output->dma->lock); | |
| 446 | 493 | } |
| 447 | 494 | |
| 448 | 495 | static void ddb_output_stop(struct ddb_output *output) |
| 449 | 496 | { |
| 450 | 497 | struct ddb *dev = output->port->dev; |
| 451 | 498 | |
| 452 | − if (output->dma) | |
| 453 | − spin_lock_irq(&output->dma->lock); | |
| 499 | + spin_lock_irq(&output->dma->lock); | |
| 454 | 500 | |
| 455 | 501 | ddbwritel(dev, 0, TS_CONTROL(output)); |
| 456 | 502 | |
| 457 | − if (output->dma) { | |
| 458 | − ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); | |
| 459 | − output->dma->running = 0; | |
| 460 | − spin_unlock_irq(&output->dma->lock); | |
| 461 | − } | |
| 503 | + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); | |
| 504 | + output->dma->running = 0; | |
| 505 | + spin_unlock_irq(&output->dma->lock); | |
| 462 | 506 | } |
| 463 | 507 | |
| 464 | 508 | static void ddb_input_stop(struct ddb_input *input) |
| @@ -466,45 +510,42 @@ static void ddb_input_stop(struct ddb_input *input) · 1 unmodified line | ||
| 466 | 510 | struct ddb *dev = input->port->dev; |
| 467 | 511 | u32 tag = DDB_LINK_TAG(input->port->lnr); |
| 468 | 512 | |
| 469 | − if (input->dma) | |
| 470 | − spin_lock_irq(&input->dma->lock); | |
| 513 | + spin_lock_irq(&input->dma->lock); | |
| 514 | + | |
| 471 | 515 | ddbwritel(dev, 0, tag | TS_CONTROL(input)); |
| 472 | − if (input->dma) { | |
| 473 | − ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); | |
| 474 | − input->dma->running = 0; | |
| 475 | − spin_unlock_irq(&input->dma->lock); | |
| 476 | − } | |
| 516 | + | |
| 517 | + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); | |
| 518 | + input->dma->running = 0; | |
| 519 | + spin_unlock_irq(&input->dma->lock); | |
| 477 | 520 | } |
| 478 | 521 | |
| 479 | 522 | static void ddb_input_start(struct ddb_input *input) |
| 480 | 523 | { |
| 481 | 524 | struct ddb *dev = input->port->dev; |
| 482 | 525 | |
| 483 | − if (input->dma) { | |
| 484 | − spin_lock_irq(&input->dma->lock); | |
| 485 | − input->dma->cbuf = 0; | |
| 486 | − input->dma->coff = 0; | |
| 487 | − input->dma->stat = 0; | |
| 488 | − ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); | |
| 489 | − } | |
| 526 | + spin_lock_irq(&input->dma->lock); | |
| 527 | + input->dma->cbuf = 0; | |
| 528 | + input->dma->coff = 0; | |
| 529 | + input->dma->stat = 0; | |
| 530 | + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); | |
| 531 | + | |
| 490 | 532 | ddbwritel(dev, 0, TS_CONTROL(input)); |
| 491 | 533 | ddbwritel(dev, 2, TS_CONTROL(input)); |
| 492 | 534 | ddbwritel(dev, 0, TS_CONTROL(input)); |
| 493 | 535 | |
| 494 | − if (input->dma) { | |
| 495 | − ddbwritel(dev, input->dma->bufval, | |
| 496 | − DMA_BUFFER_SIZE(input->dma)); | |
| 497 | − ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma)); | |
| 498 | − ddbwritel(dev, 1, DMA_BASE_WRITE); | |
| 499 | − ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma)); | |
| 500 | − } | |
| 536 | + ddbwritel(dev, input->dma->bufval, | |
| 537 | + DMA_BUFFER_SIZE(input->dma)); | |
| 538 | + ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma)); | |
| 539 | + ddbwritel(dev, 1, DMA_BASE_WRITE); | |
| 540 | + ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma)); | |
| 501 | 541 | |
| 502 | 542 | ddbwritel(dev, 0x09, TS_CONTROL(input)); |
| 503 | 543 | |
| 504 | − if (input->dma) { | |
| 505 | − input->dma->running = 1; | |
| 506 | − spin_unlock_irq(&input->dma->lock); | |
| 507 | − } | |
| 544 | + if (input->port->type == DDB_TUNER_DUMMY) | |
| 545 | + ddbwritel(dev, 0x000fff01, TS_CONTROL2(input)); | |
| 546 | + | |
| 547 | + input->dma->running = 1; | |
| 548 | + spin_unlock_irq(&input->dma->lock); | |
| 508 | 549 | } |
| 509 | 550 | |
| 510 | 551 | static void ddb_input_start_all(struct ddb_input *input) |
| @@ -549,12 +590,12 @@ static u32 ddb_output_free(struct ddb_output *output) · 38 unmodified lines | ||
| 549 | 590 | |
| 550 | 591 | if (output->dma->cbuf != idx) { |
| 551 | 592 | if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && |
| 552 | − (output->dma->size - output->dma->coff <= 188)) | |
| 593 | + (output->dma->size - output->dma->coff <= (2 * 188))) | |
| 553 | 594 | return 0; |
| 554 | 595 | return 188; |
| 555 | 596 | } |
| 556 | 597 | diff = off - output->dma->coff; |
| 557 | − if (diff <= 0 || diff > 188) | |
| 598 | + if (diff <= 0 || diff > (2 * 188)) | |
| 558 | 599 | return 188; |
| 559 | 600 | return 0; |
| 560 | 601 | } |
| @@ -1142,6 +1183,7 @@ static const struct stv0910_cfg stv0910_p = { · 581 unmodified lines | ||
| 1142 | 1183 | .parallel = 1, |
| 1143 | 1184 | .rptlvl = 4, |
| 1144 | 1185 | .clk = 30000000, |
| 1186 | + .tsspeed = 0x28, | |
| 1145 | 1187 | }; |
| 1146 | 1188 | |
| 1147 | 1189 | static const struct lnbh25_config lnbh25_cfg = { |
| @@ -1149,7 +1191,7 @@ static const struct lnbh25_config lnbh25_cfg = { · 1 unmodified line | ||
| 1149 | 1191 | .data2_config = LNBH25_TEN |
| 1150 | 1192 | }; |
| 1151 | 1193 | |
| 1152 | −static int demod_attach_stv0910(struct ddb_input *input, int type) | |
| 1194 | +static int demod_attach_stv0910(struct ddb_input *input, int type, int tsfast) | |
| 1153 | 1195 | { |
| 1154 | 1196 | struct i2c_adapter *i2c = &input->port->i2c->adap; |
| 1155 | 1197 | struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; |
| @@ -1162,6 +1204,12 @@ static int demod_attach_stv0910(struct ddb_input *input, int type) · 6 unmodified lines | ||
| 1162 | 1204 | |
| 1163 | 1205 | if (type) |
| 1164 | 1206 | cfg.parallel = 2; |
| 1207 | + | |
| 1208 | + if (tsfast) { | |
| 1209 | + dev_info(dev, "Enabling stv0910 higher speed TS\n"); | |
| 1210 | + cfg.tsspeed = 0x10; | |
| 1211 | + } | |
| 1212 | + | |
| 1165 | 1213 | dvb->fe = dvb_attach(stv0910_attach, i2c, &cfg, (input->nr & 1)); |
| 1166 | 1214 | if (!dvb->fe) { |
| 1167 | 1215 | cfg.adr = 0x6c; |
| @@ -1208,6 +1256,20 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type) · 40 unmodified lines | ||
| 1208 | 1256 | return 0; |
| 1209 | 1257 | } |
| 1210 | 1258 | |
| 1259 | +static int demod_attach_dummy(struct ddb_input *input) | |
| 1260 | +{ | |
| 1261 | + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; | |
| 1262 | + struct device *dev = input->port->dev->dev; | |
| 1263 | + | |
| 1264 | + dvb->fe = dvb_attach(dvb_dummy_fe_qam_attach); | |
| 1265 | + if (!dvb->fe) { | |
| 1266 | + dev_err(dev, "QAM dummy attach failed!\n"); | |
| 1267 | + return -ENODEV; | |
| 1268 | + } | |
| 1269 | + | |
| 1270 | + return 0; | |
| 1271 | +} | |
| 1272 | + | |
| 1211 | 1273 | static int start_feed(struct dvb_demux_feed *dvbdmxfeed) |
| 1212 | 1274 | { |
| 1213 | 1275 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; |
| @@ -1383,7 +1445,25 @@ static int dvb_input_attach(struct ddb_input *input) · 169 unmodified lines | ||
| 1383 | 1445 | struct ddb_port *port = input->port; |
| 1384 | 1446 | struct dvb_adapter *adap = dvb->adap; |
| 1385 | 1447 | struct dvb_demux *dvbdemux = &dvb->demux; |
| 1386 | − int par = 0, osc24 = 0; | |
| 1448 | + struct ddb_ids *devids = &input->port->dev->link[input->port->lnr].ids; | |
| 1449 | + int par = 0, osc24 = 0, tsfast = 0; | |
| 1450 | + | |
| 1451 | + /* | |
| 1452 | + * Determine if bridges with stv0910 demods can run with fast TS and | |
| 1453 | + * thus support high bandwidth transponders. | |
| 1454 | + * STV0910_PR and STV0910_P tuner types covers all relevant bridges, | |
| 1455 | + * namely the CineS2 V7(A) and the Octopus CI S2 Pro/Advanced. All | |
| 1456 | + * DuoFlex S2 V4(A) have type=DDB_TUNER_DVBS_STV0910 without any suffix | |
| 1457 | + * and are limited by the serial link to the bridge, thus won't work | |
| 1458 | + * in fast TS mode. | |
| 1459 | + */ | |
| 1460 | + if (port->nr == 0 && | |
| 1461 | + (port->type == DDB_TUNER_DVBS_STV0910_PR || | |
| 1462 | + port->type == DDB_TUNER_DVBS_STV0910_P)) { | |
| 1463 | + /* fast TS on port 0 requires FPGA version >= 1.7 */ | |
| 1464 | + if ((devids->hwid & 0x00ffffff) >= 0x00010007) | |
| 1465 | + tsfast = 1; | |
| 1466 | + } | |
| 1387 | 1467 | |
| 1388 | 1468 | dvb->attached = 0x01; |
| 1389 | 1469 | |
| @@ -1440,19 +1520,19 @@ static int dvb_input_attach(struct ddb_input *input) · 50 unmodified lines | ||
| 1440 | 1520 | goto err_tuner; |
| 1441 | 1521 | break; |
| 1442 | 1522 | case DDB_TUNER_DVBS_STV0910: |
| 1443 | − if (demod_attach_stv0910(input, 0) < 0) | |
| 1523 | + if (demod_attach_stv0910(input, 0, tsfast) < 0) | |
| 1444 | 1524 | goto err_detach; |
| 1445 | 1525 | if (tuner_attach_stv6111(input, 0) < 0) |
| 1446 | 1526 | goto err_tuner; |
| 1447 | 1527 | break; |
| 1448 | 1528 | case DDB_TUNER_DVBS_STV0910_PR: |
| 1449 | − if (demod_attach_stv0910(input, 1) < 0) | |
| 1529 | + if (demod_attach_stv0910(input, 1, tsfast) < 0) | |
| 1450 | 1530 | goto err_detach; |
| 1451 | 1531 | if (tuner_attach_stv6111(input, 1) < 0) |
| 1452 | 1532 | goto err_tuner; |
| 1453 | 1533 | break; |
| 1454 | 1534 | case DDB_TUNER_DVBS_STV0910_P: |
| 1455 | − if (demod_attach_stv0910(input, 0) < 0) | |
| 1535 | + if (demod_attach_stv0910(input, 0, tsfast) < 0) | |
| 1456 | 1536 | goto err_detach; |
| 1457 | 1537 | if (tuner_attach_stv6111(input, 1) < 0) |
| 1458 | 1538 | goto err_tuner; |
| @@ -1500,6 +1580,14 @@ static int dvb_input_attach(struct ddb_input *input) · 41 unmodified lines | ||
| 1500 | 1580 | if (tuner_attach_tda18212(input, port->type) < 0) |
| 1501 | 1581 | goto err_tuner; |
| 1502 | 1582 | break; |
| 1583 | + case DDB_TUNER_DUMMY: | |
| 1584 | + if (demod_attach_dummy(input) < 0) | |
| 1585 | + goto err_detach; | |
| 1586 | + break; | |
| 1587 | + case DDB_TUNER_MCI: | |
| 1588 | + if (ddb_fe_attach_mci(input) < 0) | |
| 1589 | + goto err_detach; | |
| 1590 | + break; | |
| 1503 | 1591 | default: |
| 1504 | 1592 | return 0; |
| 1505 | 1593 | } |
| @@ -1762,6 +1850,15 @@ static void ddb_port_probe(struct ddb_port *port) · 256 unmodified lines | ||
| 1762 | 1850 | |
| 1763 | 1851 | /* Handle missing ports and ports without I2C */ |
| 1764 | 1852 | |
| 1853 | + if (dummy_tuner && !port->nr && | |
| 1854 | + dev->link[0].ids.device == 0x0005) { | |
| 1855 | + port->name = "DUMMY"; | |
| 1856 | + port->class = DDB_PORT_TUNER; | |
| 1857 | + port->type = DDB_TUNER_DUMMY; | |
| 1858 | + port->type_name = "DUMMY"; | |
| 1859 | + return; | |
| 1860 | + } | |
| 1861 | + | |
| 1765 | 1862 | if (port->nr == ts_loop) { |
| 1766 | 1863 | port->name = "TS LOOP"; |
| 1767 | 1864 | port->class = DDB_PORT_LOOP; |
| @@ -1786,6 +1883,16 @@ static void ddb_port_probe(struct ddb_port *port) · 18 unmodified lines | ||
| 1786 | 1883 | return; |
| 1787 | 1884 | } |
| 1788 | 1885 | |
| 1886 | + if (dev->link[l].info->type == DDB_OCTOPUS_MCI) { | |
| 1887 | + if (port->nr >= dev->link[l].info->mci) | |
| 1888 | + return; | |
| 1889 | + port->name = "DUAL MCI"; | |
| 1890 | + port->type_name = "MCI"; | |
| 1891 | + port->class = DDB_PORT_TUNER; | |
| 1892 | + port->type = DDB_TUNER_MCI; | |
| 1893 | + return; | |
| 1894 | + } | |
| 1895 | + | |
| 1789 | 1896 | if (port->nr > 1 && dev->link[l].info->type == DDB_OCTOPUS_CI) { |
| 1790 | 1897 | port->name = "CI internal"; |
| 1791 | 1898 | port->type_name = "INTERNAL"; |
| @@ -2081,39 +2188,39 @@ static void input_work(struct work_struct *work) · 289 unmodified lines | ||
| 2081 | 2188 | spin_unlock_irqrestore(&dma->lock, flags); |
| 2082 | 2189 | } |
| 2083 | 2190 | |
| 2084 | −static void input_handler(unsigned long data) | |
| 2191 | +static void input_handler(void *data) | |
| 2085 | 2192 | { |
| 2086 | 2193 | struct ddb_input *input = (struct ddb_input *)data; |
| 2087 | 2194 | struct ddb_dma *dma = input->dma; |
| 2088 | 2195 | |
| 2089 | − /* | |
| 2090 | − * If there is no input connected, input_tasklet() will | |
| 2091 | − * just copy pointers and ACK. So, there is no need to go | |
| 2092 | − * through the tasklet scheduler. | |
| 2093 | − */ | |
| 2094 | − if (input->redi) | |
| 2095 | − queue_work(ddb_wq, &dma->work); | |
| 2096 | − else | |
| 2097 | − input_work(&dma->work); | |
| 2196 | + queue_work(ddb_wq, &dma->work); | |
| 2098 | 2197 | } |
| 2099 | 2198 | |
| 2100 | −static void output_handler(unsigned long data) | |
| 2199 | +static void output_work(struct work_struct *work) | |
| 2101 | 2200 | { |
| 2102 | − struct ddb_output *output = (struct ddb_output *)data; | |
| 2103 | − struct ddb_dma *dma = output->dma; | |
| 2201 | + struct ddb_dma *dma = container_of(work, struct ddb_dma, work); | |
| 2202 | + struct ddb_output *output = (struct ddb_output *)dma->io; | |
| 2104 | 2203 | struct ddb *dev = output->port->dev; |
| 2204 | + unsigned long flags; | |
| 2105 | 2205 | |
| 2106 | − spin_lock(&dma->lock); | |
| 2107 | − if (!dma->running) { | |
| 2108 | − spin_unlock(&dma->lock); | |
| 2109 | − return; | |
| 2110 | − } | |
| 2206 | + spin_lock_irqsave(&dma->lock, flags); | |
| 2207 | + if (!dma->running) | |
| 2208 | + goto unlock_exit; | |
| 2111 | 2209 | dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); |
| 2112 | 2210 | dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); |
| 2113 | 2211 | if (output->redi) |
| 2114 | 2212 | output_ack_input(output, output->redi); |
| 2115 | 2213 | wake_up(&dma->wq); |
| 2116 | − spin_unlock(&dma->lock); | |
| 2214 | +unlock_exit: | |
| 2215 | + spin_unlock_irqrestore(&dma->lock, flags); | |
| 2216 | +} | |
| 2217 | + | |
| 2218 | +static void output_handler(void *data) | |
| 2219 | +{ | |
| 2220 | + struct ddb_output *output = (struct ddb_output *)data; | |
| 2221 | + struct ddb_dma *dma = output->dma; | |
| 2222 | + | |
| 2223 | + queue_work(ddb_wq, &dma->work); | |
| 2117 | 2224 | } |
| 2118 | 2225 | |
| 2119 | 2226 | /****************************************************************************/ |
| @@ -2146,18 +2253,19 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out) · 26 unmodified lines | ||
| 2146 | 2253 | spin_lock_init(&dma->lock); |
| 2147 | 2254 | init_waitqueue_head(&dma->wq); |
| 2148 | 2255 | if (out) { |
| 2256 | + INIT_WORK(&dma->work, output_work); | |
| 2149 | 2257 | dma->regs = rm->odma->base + rm->odma->size * nr; |
| 2150 | 2258 | dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr; |
| 2151 | − dma->num = OUTPUT_DMA_BUFS; | |
| 2152 | − dma->size = OUTPUT_DMA_SIZE; | |
| 2153 | − dma->div = OUTPUT_DMA_IRQ_DIV; | |
| 2259 | + dma->num = dma_buf_num; | |
| 2260 | + dma->size = dma_buf_size * 128 * 47; | |
| 2261 | + dma->div = 1; | |
| 2154 | 2262 | } else { |
| 2155 | 2263 | INIT_WORK(&dma->work, input_work); |
| 2156 | 2264 | dma->regs = rm->idma->base + rm->idma->size * nr; |
| 2157 | 2265 | dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr; |
| 2158 | − dma->num = INPUT_DMA_BUFS; | |
| 2159 | − dma->size = INPUT_DMA_SIZE; | |
| 2160 | − dma->div = INPUT_DMA_IRQ_DIV; | |
| 2266 | + dma->num = dma_buf_num; | |
| 2267 | + dma->size = dma_buf_size * 128 * 47; | |
| 2268 | + dma->div = 1; | |
| 2161 | 2269 | } |
| 2162 | 2270 | ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); |
| 2163 | 2271 | dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n", |
| @@ -2190,8 +2298,7 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) · 26 unmodified lines | ||
| 2190 | 2298 | dev_dbg(dev->dev, "init link %u, input %u, handler %u\n", |
| 2191 | 2299 | port->lnr, nr, dma_nr + base); |
| 2192 | 2300 | |
| 2193 | − dev->handler[0][dma_nr + base] = input_handler; | |
| 2194 | − dev->handler_data[0][dma_nr + base] = (unsigned long)input; | |
| 2301 | + ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input); | |
| 2195 | 2302 | ddb_dma_init(input, dma_nr, 0); |
| 2196 | 2303 | } |
| 2197 | 2304 | } |
| @@ -2216,8 +2323,7 @@ static void ddb_output_init(struct ddb_port *port, int nr) · 18 unmodified lines | ||
| 2216 | 2323 | const struct ddb_regmap *rm0 = io_regmap(output, 0); |
| 2217 | 2324 | u32 base = rm0->irq_base_odma; |
| 2218 | 2325 | |
| 2219 | − dev->handler[0][nr + base] = output_handler; | |
| 2220 | − dev->handler_data[0][nr + base] = (unsigned long)output; | |
| 2326 | + ddb_irq_set(dev, 0, nr + base, &output_handler, output); | |
| 2221 | 2327 | ddb_dma_init(output, nr, 1); |
| 2222 | 2328 | } |
| 2223 | 2329 | } |
| @@ -2329,6 +2435,7 @@ void ddb_ports_init(struct ddb *dev) · 105 unmodified lines | ||
| 2329 | 2435 | break; |
| 2330 | 2436 | case DDB_OCTOPUS_MAX: |
| 2331 | 2437 | case DDB_OCTOPUS_MAX_CT: |
| 2438 | + case DDB_OCTOPUS_MCI: | |
| 2332 | 2439 | ddb_input_init(port, 2 * i, 0, 2 * p); |
| 2333 | 2440 | ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1); |
| 2334 | 2441 | break; |
| @@ -2361,73 +2468,62 @@ void ddb_ports_release(struct ddb *dev) · 26 unmodified lines | ||
| 2361 | 2468 | /****************************************************************************/ |
| 2362 | 2469 | |
| 2363 | 2470 | #define IRQ_HANDLE(_nr) \ |
| 2364 | − do { if ((s & (1UL << ((_nr) & 0x1f))) && dev->handler[0][_nr]) \ | |
| 2365 | − dev->handler[0][_nr](dev->handler_data[0][_nr]); } \ | |
| 2471 | + do { if ((s & (1UL << ((_nr) & 0x1f))) && \ | |
| 2472 | + dev->link[0].irq[_nr].handler) \ | |
| 2473 | + dev->link[0].irq[_nr].handler(dev->link[0].irq[_nr].data); } \ | |
| 2366 | 2474 | while (0) |
| 2367 | 2475 | |
| 2476 | +#define IRQ_HANDLE_NIBBLE(_shift) { \ | |
| 2477 | + if (s & (0x0000000f << ((_shift) & 0x1f))) { \ | |
| 2478 | + IRQ_HANDLE(0 + (_shift)); \ | |
| 2479 | + IRQ_HANDLE(1 + (_shift)); \ | |
| 2480 | + IRQ_HANDLE(2 + (_shift)); \ | |
| 2481 | + IRQ_HANDLE(3 + (_shift)); \ | |
| 2482 | + } \ | |
| 2483 | +} | |
| 2484 | + | |
| 2485 | +#define IRQ_HANDLE_BYTE(_shift) { \ | |
| 2486 | + if (s & (0x000000ff << ((_shift) & 0x1f))) { \ | |
| 2487 | + IRQ_HANDLE(0 + (_shift)); \ | |
| 2488 | + IRQ_HANDLE(1 + (_shift)); \ | |
| 2489 | + IRQ_HANDLE(2 + (_shift)); \ | |
| 2490 | + IRQ_HANDLE(3 + (_shift)); \ | |
| 2491 | + IRQ_HANDLE(4 + (_shift)); \ | |
| 2492 | + IRQ_HANDLE(5 + (_shift)); \ | |
| 2493 | + IRQ_HANDLE(6 + (_shift)); \ | |
| 2494 | + IRQ_HANDLE(7 + (_shift)); \ | |
| 2495 | + } \ | |
| 2496 | +} | |
| 2497 | + | |
| 2368 | 2498 | static void irq_handle_msg(struct ddb *dev, u32 s) |
| 2369 | 2499 | { |
| 2370 | 2500 | dev->i2c_irq++; |
| 2371 | − IRQ_HANDLE(0); | |
| 2372 | − IRQ_HANDLE(1); | |
| 2373 | − IRQ_HANDLE(2); | |
| 2374 | − IRQ_HANDLE(3); | |
| 2501 | + IRQ_HANDLE_NIBBLE(0); | |
| 2375 | 2502 | } |
| 2376 | 2503 | |
| 2377 | 2504 | static void irq_handle_io(struct ddb *dev, u32 s) |
| 2378 | 2505 | { |
| 2379 | 2506 | dev->ts_irq++; |
| 2380 | − if ((s & 0x000000f0)) { | |
| 2381 | − IRQ_HANDLE(4); | |
| 2382 | − IRQ_HANDLE(5); | |
| 2383 | − IRQ_HANDLE(6); | |
| 2384 | − IRQ_HANDLE(7); | |
| 2385 | − } | |
| 2386 | − if ((s & 0x0000ff00)) { | |
| 2387 | − IRQ_HANDLE(8); | |
| 2388 | − IRQ_HANDLE(9); | |
| 2389 | − IRQ_HANDLE(10); | |
| 2390 | − IRQ_HANDLE(11); | |
| 2391 | − IRQ_HANDLE(12); | |
| 2392 | − IRQ_HANDLE(13); | |
| 2393 | − IRQ_HANDLE(14); | |
| 2394 | − IRQ_HANDLE(15); | |
| 2395 | − } | |
| 2396 | − if ((s & 0x00ff0000)) { | |
| 2397 | − IRQ_HANDLE(16); | |
| 2398 | − IRQ_HANDLE(17); | |
| 2399 | − IRQ_HANDLE(18); | |
| 2400 | − IRQ_HANDLE(19); | |
| 2401 | − IRQ_HANDLE(20); | |
| 2402 | − IRQ_HANDLE(21); | |
| 2403 | − IRQ_HANDLE(22); | |
| 2404 | − IRQ_HANDLE(23); | |
| 2405 | − } | |
| 2406 | − if ((s & 0xff000000)) { | |
| 2407 | − IRQ_HANDLE(24); | |
| 2408 | − IRQ_HANDLE(25); | |
| 2409 | − IRQ_HANDLE(26); | |
| 2410 | − IRQ_HANDLE(27); | |
| 2411 | − IRQ_HANDLE(28); | |
| 2412 | − IRQ_HANDLE(29); | |
| 2413 | − IRQ_HANDLE(30); | |
| 2414 | − IRQ_HANDLE(31); | |
| 2415 | − } | |
| 2507 | + IRQ_HANDLE_NIBBLE(4); | |
| 2508 | + IRQ_HANDLE_BYTE(8); | |
| 2509 | + IRQ_HANDLE_BYTE(16); | |
| 2510 | + IRQ_HANDLE_BYTE(24); | |
| 2416 | 2511 | } |
| 2417 | 2512 | |
| 2418 | 2513 | irqreturn_t ddb_irq_handler0(int irq, void *dev_id) |
| 2419 | 2514 | { |
| 2420 | 2515 | struct ddb *dev = (struct ddb *)dev_id; |
| 2421 | − u32 s = ddbreadl(dev, INTERRUPT_STATUS); | |
| 2516 | + u32 mask = 0x8fffff00; | |
| 2517 | + u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS); | |
| 2422 | 2518 | |
| 2519 | + if (!s) | |
| 2520 | + return IRQ_NONE; | |
| 2423 | 2521 | do { |
| 2424 | 2522 | if (s & 0x80000000) |
| 2425 | 2523 | return IRQ_NONE; |
| 2426 | − if (!(s & 0xfffff00)) | |
| 2427 | − return IRQ_NONE; | |
| 2428 | − ddbwritel(dev, s & 0xfffff00, INTERRUPT_ACK); | |
| 2524 | + ddbwritel(dev, s, INTERRUPT_ACK); | |
| 2429 | 2525 | irq_handle_io(dev, s); |
| 2430 | − } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); | |
| 2526 | + } while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS))); | |
| 2431 | 2527 | |
| 2432 | 2528 | return IRQ_HANDLED; |
| 2433 | 2529 | } |
| @@ -2435,16 +2531,17 @@ irqreturn_t ddb_irq_handler0(int irq, void *dev_id) · 1 unmodified line | ||
| 2435 | 2531 | irqreturn_t ddb_irq_handler1(int irq, void *dev_id) |
| 2436 | 2532 | { |
| 2437 | 2533 | struct ddb *dev = (struct ddb *)dev_id; |
| 2438 | − u32 s = ddbreadl(dev, INTERRUPT_STATUS); | |
| 2534 | + u32 mask = 0x8000000f; | |
| 2535 | + u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS); | |
| 2439 | 2536 | |
| 2537 | + if (!s) | |
| 2538 | + return IRQ_NONE; | |
| 2440 | 2539 | do { |
| 2441 | 2540 | if (s & 0x80000000) |
| 2442 | 2541 | return IRQ_NONE; |
| 2443 | − if (!(s & 0x0000f)) | |
| 2444 | − return IRQ_NONE; | |
| 2445 | − ddbwritel(dev, s & 0x0000f, INTERRUPT_ACK); | |
| 2542 | + ddbwritel(dev, s, INTERRUPT_ACK); | |
| 2446 | 2543 | irq_handle_msg(dev, s); |
| 2447 | − } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); | |
| 2544 | + } while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS))); | |
| 2448 | 2545 | |
| 2449 | 2546 | return IRQ_HANDLED; |
| 2450 | 2547 | } |
| @@ -3027,7 +3124,7 @@ static struct class ddb_class = { · 576 unmodified lines | ||
| 3027 | 3124 | .devnode = ddb_devnode, |
| 3028 | 3125 | }; |
| 3029 | 3126 | |
| 3030 | −int ddb_class_create(void) | |
| 3127 | +static int ddb_class_create(void) | |
| 3031 | 3128 | { |
| 3032 | 3129 | ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); |
| 3033 | 3130 | if (ddb_major < 0) |
| @@ -3037,7 +3134,7 @@ int ddb_class_create(void) · 3 unmodified lines | ||
| 3037 | 3134 | return 0; |
| 3038 | 3135 | } |
| 3039 | 3136 | |
| 3040 | −void ddb_class_destroy(void) | |
| 3137 | +static void ddb_class_destroy(void) | |
| 3041 | 3138 | { |
| 3042 | 3139 | class_unregister(&ddb_class); |
| 3043 | 3140 | unregister_chrdev(ddb_major, DDB_NAME); |
| @@ -3173,7 +3270,7 @@ static void tempmon_setfan(struct ddb_link *link) · 129 unmodified lines | ||
| 3173 | 3270 | ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL); |
| 3174 | 3271 | } |
| 3175 | 3272 | |
| 3176 | −static void temp_handler(unsigned long data) | |
| 3273 | +static void temp_handler(void *data) | |
| 3177 | 3274 | { |
| 3178 | 3275 | struct ddb_link *link = (struct ddb_link *)data; |
| 3179 | 3276 | |
| @@ -3196,8 +3293,7 @@ static int tempmon_init(struct ddb_link *link, int first_time) · 16 unmodified lines | ||
| 3196 | 3293 | memcpy(link->temp_tab, temperature_table, |
| 3197 | 3294 | sizeof(temperature_table)); |
| 3198 | 3295 | } |
| 3199 | − dev->handler[l][link->info->tempmon_irq] = temp_handler; | |
| 3200 | − dev->handler_data[l][link->info->tempmon_irq] = (unsigned long)link; | |
| 3296 | + ddb_irq_set(dev, l, link->info->tempmon_irq, temp_handler, link); | |
| 3201 | 3297 | ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN | |
| 3202 | 3298 | TEMPMON_CONTROL_INTENABLE), |
| 3203 | 3299 | TEMPMON_CONTROL); |
| @@ -3309,3 +3405,38 @@ void ddb_unmap(struct ddb *dev) · 105 unmodified lines | ||
| 3309 | 3405 | iounmap(dev->regs); |
| 3310 | 3406 | vfree(dev); |
| 3311 | 3407 | } |
| 3408 | + | |
| 3409 | +int ddb_exit_ddbridge(int stage, int error) | |
| 3410 | +{ | |
| 3411 | + switch (stage) { | |
| 3412 | + default: | |
| 3413 | + case 2: | |
| 3414 | + destroy_workqueue(ddb_wq); | |
| 3415 | + /* fall-through */ | |
| 3416 | + case 1: | |
| 3417 | + ddb_class_destroy(); | |
| 3418 | + break; | |
| 3419 | + } | |
| 3420 | + | |
| 3421 | + return error; | |
| 3422 | +} | |
| 3423 | + | |
| 3424 | +int ddb_init_ddbridge(void) | |
| 3425 | +{ | |
| 3426 | + if (dma_buf_num < 8) | |
| 3427 | + dma_buf_num = 8; | |
| 3428 | + if (dma_buf_num > 32) | |
| 3429 | + dma_buf_num = 32; | |
| 3430 | + if (dma_buf_size < 1) | |
| 3431 | + dma_buf_size = 1; | |
| 3432 | + if (dma_buf_size > 43) | |
| 3433 | + dma_buf_size = 43; | |
| 3434 | + | |
| 3435 | + if (ddb_class_create() < 0) | |
| 3436 | + return -1; | |
| 3437 | + ddb_wq = alloc_workqueue("ddbridge", 0, 0); | |
| 3438 | + if (!ddb_wq) | |
| 3439 | + return ddb_exit_ddbridge(1, -1); | |
| 3440 | + | |
| 3441 | + return 0; | |
| 3442 | +} | |
| @@ -311,6 +311,16 @@ static const struct ddb_info ddb_s2_48 = { · 310 unmodified lines | ||
| 311 | 311 | .tempmon_irq = 24, |
| 312 | 312 | }; |
| 313 | 313 | |
| 314 | +static const struct ddb_info ddb_s2x_48 = { | |
| 315 | + .type = DDB_OCTOPUS_MCI, | |
| 316 | + .name = "Digital Devices MAX SX8", | |
| 317 | + .regmap = &octopus_map, | |
| 318 | + .port_num = 4, | |
| 319 | + .i2c_mask = 0x00, | |
| 320 | + .tempmon_irq = 24, | |
| 321 | + .mci = 4 | |
| 322 | +}; | |
| 323 | + | |
| 314 | 324 | /****************************************************************************/ |
| 315 | 325 | /****************************************************************************/ |
| 316 | 326 | /****************************************************************************/ |
| @@ -346,6 +356,7 @@ static const struct ddb_device_id ddb_device_ids[] = { · 29 unmodified lines | ||
| 346 | 356 | DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8), |
| 347 | 357 | DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8), |
| 348 | 358 | DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8), |
| 359 | + DDB_DEVID(0x0009, 0x0025, ddb_s2x_48), | |
| 349 | 360 | DDB_DEVID(0x0006, 0x0039, ddb_ctv7), |
| 350 | 361 | DDB_DEVID(0x0011, 0x0040, ddb_ci), |
| 351 | 362 | DDB_DEVID(0x0011, 0x0041, ddb_cis), |
| @@ -147,7 +147,7 @@ void ddb_i2c_release(struct ddb *dev) · 146 unmodified lines | ||
| 147 | 147 | } |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | −static void i2c_handler(unsigned long priv) | |
| 150 | +static void i2c_handler(void *priv) | |
| 151 | 151 | { |
| 152 | 152 | struct ddb_i2c *i2c = (struct ddb_i2c *)priv; |
| 153 | 153 | |
| @@ -210,8 +210,7 @@ int ddb_i2c_init(struct ddb *dev) · 56 unmodified lines | ||
| 210 | 210 | if (!(dev->link[l].info->i2c_mask & (1 << i))) |
| 211 | 211 | continue; |
| 212 | 212 | i2c = &dev->i2c[num]; |
| 213 | − dev->handler_data[l][i + base] = (unsigned long)i2c; | |
| 214 | − dev->handler[l][i + base] = i2c_handler; | |
| 213 | + ddb_irq_set(dev, l, i + base, i2c_handler, i2c); | |
| 215 | 214 | stat = ddb_i2c_add(dev, i2c, regmap, l, i, num); |
| 216 | 215 | if (stat) |
| 217 | 216 | break; |
| @@ -55,34 +55,6 @@ MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable"); · 54 unmodified lines | ||
| 55 | 55 | #endif |
| 56 | 56 | #endif |
| 57 | 57 | |
| 58 | −int ci_bitrate = 70000; | |
| 59 | −module_param(ci_bitrate, int, 0444); | |
| 60 | −MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI."); | |
| 61 | − | |
| 62 | −int ts_loop = -1; | |
| 63 | −module_param(ts_loop, int, 0444); | |
| 64 | −MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop"); | |
| 65 | − | |
| 66 | −int xo2_speed = 2; | |
| 67 | −module_param(xo2_speed, int, 0444); | |
| 68 | −MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); | |
| 69 | − | |
| 70 | −#ifdef __arm__ | |
| 71 | −int alt_dma = 1; | |
| 72 | −#else | |
| 73 | −int alt_dma; | |
| 74 | −#endif | |
| 75 | −module_param(alt_dma, int, 0444); | |
| 76 | −MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling"); | |
| 77 | − | |
| 78 | −int no_init; | |
| 79 | −module_param(no_init, int, 0444); | |
| 80 | −MODULE_PARM_DESC(no_init, "do not initialize most devices"); | |
| 81 | − | |
| 82 | −int stv0910_single; | |
| 83 | −module_param(stv0910_single, int, 0444); | |
| 84 | −MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods"); | |
| 85 | − | |
| 86 | 58 | /****************************************************************************/ |
| 87 | 59 | /****************************************************************************/ |
| 88 | 60 | /****************************************************************************/ |
| @@ -93,18 +65,22 @@ static void ddb_irq_disable(struct ddb *dev) · 4 unmodified lines | ||
| 93 | 65 | ddbwritel(dev, 0, MSI1_ENABLE); |
| 94 | 66 | } |
| 95 | 67 | |
| 96 | −static void ddb_irq_exit(struct ddb *dev) | |
| 68 | +static void ddb_msi_exit(struct ddb *dev) | |
| 97 | 69 | { |
| 98 | − ddb_irq_disable(dev); | |
| 99 | − if (dev->msi == 2) | |
| 100 | − free_irq(dev->pdev->irq + 1, dev); | |
| 101 | − free_irq(dev->pdev->irq, dev); | |
| 102 | 70 | #ifdef CONFIG_PCI_MSI |
| 103 | 71 | if (dev->msi) |
| 104 | − pci_disable_msi(dev->pdev); | |
| 72 | + pci_free_irq_vectors(dev->pdev); | |
| 105 | 73 | #endif |
| 106 | 74 | } |
| 107 | 75 | |
| 76 | +static void ddb_irq_exit(struct ddb *dev) | |
| 77 | +{ | |
| 78 | + ddb_irq_disable(dev); | |
| 79 | + if (dev->msi == 2) | |
| 80 | + free_irq(pci_irq_vector(dev->pdev, 1), dev); | |
| 81 | + free_irq(pci_irq_vector(dev->pdev, 0), dev); | |
| 82 | +} | |
| 83 | + | |
| 108 | 84 | static void ddb_remove(struct pci_dev *pdev) |
| 109 | 85 | { |
| 110 | 86 | struct ddb *dev = (struct ddb *)pci_get_drvdata(pdev); |
| @@ -114,6 +90,7 @@ static void ddb_remove(struct pci_dev *pdev) · 3 unmodified lines | ||
| 114 | 90 | ddb_i2c_release(dev); |
| 115 | 91 | |
| 116 | 92 | ddb_irq_exit(dev); |
| 93 | + ddb_msi_exit(dev); | |
| 117 | 94 | ddb_ports_release(dev); |
| 118 | 95 | ddb_buffers_free(dev); |
| 119 | 96 | |
| @@ -128,7 +105,8 @@ static void ddb_irq_msi(struct ddb *dev, int nr) · 8 unmodified lines | ||
| 128 | 105 | int stat; |
| 129 | 106 | |
| 130 | 107 | if (msi && pci_msi_enabled()) { |
| 131 | − stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI); | |
| 108 | + stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, | |
| 109 | + PCI_IRQ_MSI | PCI_IRQ_MSIX); | |
| 132 | 110 | if (stat >= 1) { |
| 133 | 111 | dev->msi = stat; |
| 134 | 112 | dev_info(dev->dev, "using %d MSI interrupt(s)\n", |
| @@ -160,21 +138,24 @@ static int ddb_irq_init(struct ddb *dev) · 25 unmodified lines | ||
| 160 | 138 | if (dev->msi) |
| 161 | 139 | irq_flag = 0; |
| 162 | 140 | if (dev->msi == 2) { |
| 163 | − stat = request_irq(dev->pdev->irq, ddb_irq_handler0, | |
| 164 | − irq_flag, "ddbridge", (void *)dev); | |
| 141 | + stat = request_irq(pci_irq_vector(dev->pdev, 0), | |
| 142 | + ddb_irq_handler0, irq_flag, "ddbridge", | |
| 143 | + (void *)dev); | |
| 165 | 144 | if (stat < 0) |
| 166 | 145 | return stat; |
| 167 | − stat = request_irq(dev->pdev->irq + 1, ddb_irq_handler1, | |
| 168 | − irq_flag, "ddbridge", (void *)dev); | |
| 146 | + stat = request_irq(pci_irq_vector(dev->pdev, 1), | |
| 147 | + ddb_irq_handler1, irq_flag, "ddbridge", | |
| 148 | + (void *)dev); | |
| 169 | 149 | if (stat < 0) { |
| 170 | − free_irq(dev->pdev->irq, dev); | |
| 150 | + free_irq(pci_irq_vector(dev->pdev, 0), dev); | |
| 171 | 151 | return stat; |
| 172 | 152 | } |
| 173 | 153 | } else |
| 174 | 154 | #endif |
| 175 | 155 | { |
| 176 | − stat = request_irq(dev->pdev->irq, ddb_irq_handler, | |
| 177 | − irq_flag, "ddbridge", (void *)dev); | |
| 156 | + stat = request_irq(pci_irq_vector(dev->pdev, 0), | |
| 157 | + ddb_irq_handler, irq_flag, "ddbridge", | |
| 158 | + (void *)dev); | |
| 178 | 159 | if (stat < 0) |
| 179 | 160 | return stat; |
| 180 | 161 | } |
| @@ -217,6 +198,7 @@ static int ddb_probe(struct pci_dev *pdev, · 36 unmodified lines | ||
| 217 | 198 | dev->link[0].ids.device = id->device; |
| 218 | 199 | dev->link[0].ids.subvendor = id->subvendor; |
| 219 | 200 | dev->link[0].ids.subdevice = pdev->subsystem_device; |
| 201 | + dev->link[0].ids.devid = (id->device << 16) | id->vendor; | |
| 220 | 202 | |
| 221 | 203 | dev->link[0].dev = dev; |
| 222 | 204 | dev->link[0].info = get_ddb_info(id->vendor, id->device, |
| @@ -258,8 +240,7 @@ static int ddb_probe(struct pci_dev *pdev, · 35 unmodified lines | ||
| 258 | 240 | ddb_irq_exit(dev); |
| 259 | 241 | fail0: |
| 260 | 242 | dev_err(&pdev->dev, "fail0\n"); |
| 261 | − if (dev->msi) | |
| 262 | − pci_disable_msi(dev->pdev); | |
| 243 | + ddb_msi_exit(dev); | |
| 263 | 244 | fail: |
| 264 | 245 | dev_err(&pdev->dev, "fail\n"); |
| 265 | 246 | |
| @@ -283,6 +264,7 @@ static const struct pci_device_id ddb_id_table[] = { · 17 unmodified lines | ||
| 283 | 264 | DDB_DEVICE_ANY(0x0006), |
| 284 | 265 | DDB_DEVICE_ANY(0x0007), |
| 285 | 266 | DDB_DEVICE_ANY(0x0008), |
| 267 | + DDB_DEVICE_ANY(0x0009), | |
| 286 | 268 | DDB_DEVICE_ANY(0x0011), |
| 287 | 269 | DDB_DEVICE_ANY(0x0012), |
| 288 | 270 | DDB_DEVICE_ANY(0x0013), |
| @@ -310,32 +292,25 @@ static struct pci_driver ddb_pci_driver = { · 21 unmodified lines | ||
| 310 | 292 | |
| 311 | 293 | static __init int module_init_ddbridge(void) |
| 312 | 294 | { |
| 313 | − int stat = -1; | |
| 295 | + int stat; | |
| 314 | 296 | |
| 315 | 297 | pr_info("Digital Devices PCIE bridge driver " |
| 316 | 298 | DDBRIDGE_VERSION |
| 317 | 299 | ", Copyright (C) 2010-17 Digital Devices GmbH\n"); |
| 318 | − if (ddb_class_create() < 0) | |
| 319 | − return -1; | |
| 320 | − ddb_wq = create_workqueue("ddbridge"); | |
| 321 | − if (!ddb_wq) | |
| 322 | − goto exit1; | |
| 300 | + stat = ddb_init_ddbridge(); | |
| 301 | + if (stat < 0) | |
| 302 | + return stat; | |
| 323 | 303 | stat = pci_register_driver(&ddb_pci_driver); |
| 324 | 304 | if (stat < 0) |
| 325 | − goto exit2; | |
| 326 | − return stat; | |
| 327 | −exit2: | |
| 328 | − destroy_workqueue(ddb_wq); | |
| 329 | −exit1: | |
| 330 | − ddb_class_destroy(); | |
| 305 | + ddb_exit_ddbridge(0, stat); | |
| 306 | + | |
| 331 | 307 | return stat; |
| 332 | 308 | } |
| 333 | 309 | |
| 334 | 310 | static __exit void module_exit_ddbridge(void) |
| 335 | 311 | { |
| 336 | 312 | pci_unregister_driver(&ddb_pci_driver); |
| 337 | − destroy_workqueue(ddb_wq); | |
| 338 | − ddb_class_destroy(); | |
| 313 | + ddb_exit_ddbridge(0, 0); | |
| 339 | 314 | } |
| 340 | 315 | |
| 341 | 316 | module_init(module_init_ddbridge); |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include "ddbridge.h" |
| 34 | 34 | #include "ddbridge-regs.h" |
| 35 | 35 | #include "ddbridge-io.h" |
| 36 | +#include "ddbridge-mci.h" | |
| 36 | 37 | |
| 37 | 38 | #include "ddbridge-max.h" |
| 38 | 39 | #include "mxl5xx.h" |
| @@ -452,3 +453,44 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input) · 413 unmodified lines | ||
| 452 | 453 | dvb->input = tuner; |
| 453 | 454 | return 0; |
| 454 | 455 | } |
| 456 | + | |
| 457 | +/******************************************************************************/ | |
| 458 | +/* MAX MCI related functions */ | |
| 459 | + | |
| 460 | +int ddb_fe_attach_mci(struct ddb_input *input) | |
| 461 | +{ | |
| 462 | + struct ddb *dev = input->port->dev; | |
| 463 | + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; | |
| 464 | + struct ddb_port *port = input->port; | |
| 465 | + struct ddb_link *link = &dev->link[port->lnr]; | |
| 466 | + int demod, tuner; | |
| 467 | + | |
| 468 | + demod = input->nr; | |
| 469 | + tuner = demod & 3; | |
| 470 | + if (fmode == 3) | |
| 471 | + tuner = 0; | |
| 472 | + dvb->fe = ddb_mci_attach(input, 0, demod, &dvb->set_input); | |
| 473 | + if (!dvb->fe) { | |
| 474 | + dev_err(dev->dev, "No MAXSX8 found!\n"); | |
| 475 | + return -ENODEV; | |
| 476 | + } | |
| 477 | + if (!dvb->set_input) { | |
| 478 | + dev_err(dev->dev, "No MCI set_input function pointer!\n"); | |
| 479 | + return -ENODEV; | |
| 480 | + } | |
| 481 | + if (input->nr < 4) { | |
| 482 | + lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT); | |
| 483 | + lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF); | |
| 484 | + } | |
| 485 | + ddb_lnb_init_fmode(dev, link, fmode); | |
| 486 | + | |
| 487 | + dvb->fe->ops.set_voltage = max_set_voltage; | |
| 488 | + dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage; | |
| 489 | + dvb->fe->ops.set_tone = max_set_tone; | |
| 490 | + dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd; | |
| 491 | + dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd; | |
| 492 | + dvb->fe->ops.diseqc_send_burst = max_send_burst; | |
| 493 | + dvb->fe->sec_priv = input; | |
| 494 | + dvb->input = tuner; | |
| 495 | + return 0; | |
| 496 | +} | |
| @@ -25,5 +25,6 @@ · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm); |
| 27 | 27 | int ddb_fe_attach_mxl5xx(struct ddb_input *input); |
| 28 | +int ddb_fe_attach_mci(struct ddb_input *input); | |
| 28 | 29 | |
| 29 | 30 | #endif /* _DDBRIDGE_MAX_H */ |
| @@ -0,0 +1,551 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * ddbridge-mci.c: Digital Devices microcode interface | |
| 4 | + * | |
| 5 | + * Copyright (C) 2017 Digital Devices GmbH | |
| 6 | + * Ralph Metzler <rjkm@metzlerbros.de> | |
| 7 | + * Marcus Metzler <mocm@metzlerbros.de> | |
| 8 | + * | |
| 9 | + * This program is free software; you can redistribute it and/or | |
| 10 | + * modify it under the terms of the GNU General Public License | |
| 11 | + * version 2 only, as published by the Free Software Foundation. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#include "ddbridge.h" | |
| 20 | +#include "ddbridge-io.h" | |
| 21 | +#include "ddbridge-mci.h" | |
| 22 | + | |
| 23 | +static LIST_HEAD(mci_list); | |
| 24 | + | |
| 25 | +static const u32 MCLK = (1550000000 / 12); | |
| 26 | +static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6); | |
| 27 | +static const u32 MAX_LDPC_BITRATE = (720000000); | |
| 28 | + | |
| 29 | +struct mci_base { | |
| 30 | + struct list_head mci_list; | |
| 31 | + void *key; | |
| 32 | + struct ddb_link *link; | |
| 33 | + struct completion completion; | |
| 34 | + | |
| 35 | + struct device *dev; | |
| 36 | + struct mutex tuner_lock; /* concurrent tuner access lock */ | |
| 37 | + u8 adr; | |
| 38 | + struct mutex mci_lock; /* concurrent MCI access lock */ | |
| 39 | + int count; | |
| 40 | + | |
| 41 | + u8 tuner_use_count[MCI_TUNER_MAX]; | |
| 42 | + u8 assigned_demod[MCI_DEMOD_MAX]; | |
| 43 | + u32 used_ldpc_bitrate[MCI_DEMOD_MAX]; | |
| 44 | + u8 demod_in_use[MCI_DEMOD_MAX]; | |
| 45 | + u32 iq_mode; | |
| 46 | +}; | |
| 47 | + | |
| 48 | +struct mci { | |
| 49 | + struct mci_base *base; | |
| 50 | + struct dvb_frontend fe; | |
| 51 | + int nr; | |
| 52 | + int demod; | |
| 53 | + int tuner; | |
| 54 | + int first_time_lock; | |
| 55 | + int started; | |
| 56 | + struct mci_result signal_info; | |
| 57 | + | |
| 58 | + u32 bb_mode; | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static int mci_reset(struct mci *state) | |
| 62 | +{ | |
| 63 | + struct ddb_link *link = state->base->link; | |
| 64 | + u32 status = 0; | |
| 65 | + u32 timeout = 40; | |
| 66 | + | |
| 67 | + ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL); | |
| 68 | + ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */ | |
| 69 | + msleep(300); | |
| 70 | + ddblwritel(link, 0, MCI_CONTROL); | |
| 71 | + | |
| 72 | + while (1) { | |
| 73 | + status = ddblreadl(link, MCI_CONTROL); | |
| 74 | + if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) | |
| 75 | + break; | |
| 76 | + if (--timeout == 0) | |
| 77 | + break; | |
| 78 | + msleep(50); | |
| 79 | + } | |
| 80 | + if ((status & MCI_CONTROL_READY) == 0) | |
| 81 | + return -1; | |
| 82 | + if (link->ids.device == 0x0009) | |
| 83 | + ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); | |
| 84 | + return 0; | |
| 85 | +} | |
| 86 | + | |
| 87 | +static int mci_config(struct mci *state, u32 config) | |
| 88 | +{ | |
| 89 | + struct ddb_link *link = state->base->link; | |
| 90 | + | |
| 91 | + if (link->ids.device != 0x0009) | |
| 92 | + return -EINVAL; | |
| 93 | + ddblwritel(link, config, SX8_TSCONFIG); | |
| 94 | + return 0; | |
| 95 | +} | |
| 96 | + | |
| 97 | +static int _mci_cmd_unlocked(struct mci *state, | |
| 98 | + u32 *cmd, u32 cmd_len, | |
| 99 | + u32 *res, u32 res_len) | |
| 100 | +{ | |
| 101 | + struct ddb_link *link = state->base->link; | |
| 102 | + u32 i, val; | |
| 103 | + unsigned long stat; | |
| 104 | + | |
| 105 | + val = ddblreadl(link, MCI_CONTROL); | |
| 106 | + if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) | |
| 107 | + return -EIO; | |
| 108 | + if (cmd && cmd_len) | |
| 109 | + for (i = 0; i < cmd_len; i++) | |
| 110 | + ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); | |
| 111 | + val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); | |
| 112 | + ddblwritel(link, val, MCI_CONTROL); | |
| 113 | + | |
| 114 | + stat = wait_for_completion_timeout(&state->base->completion, HZ); | |
| 115 | + if (stat == 0) { | |
| 116 | + dev_warn(state->base->dev, "MCI-%d: MCI timeout\n", state->nr); | |
| 117 | + return -EIO; | |
| 118 | + } | |
| 119 | + if (res && res_len) | |
| 120 | + for (i = 0; i < res_len; i++) | |
| 121 | + res[i] = ddblreadl(link, MCI_RESULT + i * 4); | |
| 122 | + return 0; | |
| 123 | +} | |
| 124 | + | |
| 125 | +static int mci_cmd(struct mci *state, | |
| 126 | + struct mci_command *command, | |
| 127 | + struct mci_result *result) | |
| 128 | +{ | |
| 129 | + int stat; | |
| 130 | + | |
| 131 | + mutex_lock(&state->base->mci_lock); | |
| 132 | + stat = _mci_cmd_unlocked(state, | |
| 133 | + (u32 *)command, sizeof(*command) / sizeof(u32), | |
| 134 | + (u32 *)result, sizeof(*result) / sizeof(u32)); | |
| 135 | + mutex_unlock(&state->base->mci_lock); | |
| 136 | + return stat; | |
| 137 | +} | |
| 138 | + | |
| 139 | +static void mci_handler(void *priv) | |
| 140 | +{ | |
| 141 | + struct mci_base *base = (struct mci_base *)priv; | |
| 142 | + | |
| 143 | + complete(&base->completion); | |
| 144 | +} | |
| 145 | + | |
| 146 | +static void release(struct dvb_frontend *fe) | |
| 147 | +{ | |
| 148 | + struct mci *state = fe->demodulator_priv; | |
| 149 | + | |
| 150 | + state->base->count--; | |
| 151 | + if (state->base->count == 0) { | |
| 152 | + list_del(&state->base->mci_list); | |
| 153 | + kfree(state->base); | |
| 154 | + } | |
| 155 | + kfree(state); | |
| 156 | +} | |
| 157 | + | |
| 158 | +static int read_status(struct dvb_frontend *fe, enum fe_status *status) | |
| 159 | +{ | |
| 160 | + int stat; | |
| 161 | + struct mci *state = fe->demodulator_priv; | |
| 162 | + struct mci_command cmd; | |
| 163 | + struct mci_result res; | |
| 164 | + | |
| 165 | + cmd.command = MCI_CMD_GETSTATUS; | |
| 166 | + cmd.demod = state->demod; | |
| 167 | + stat = mci_cmd(state, &cmd, &res); | |
| 168 | + if (stat) | |
| 169 | + return stat; | |
| 170 | + *status = 0x00; | |
| 171 | + if (res.status == SX8_DEMOD_WAIT_MATYPE) | |
| 172 | + *status = 0x0f; | |
| 173 | + if (res.status == SX8_DEMOD_LOCKED) | |
| 174 | + *status = 0x1f; | |
| 175 | + return stat; | |
| 176 | +} | |
| 177 | + | |
| 178 | +static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) | |
| 179 | +{ | |
| 180 | + struct mci *state = fe->demodulator_priv; | |
| 181 | + struct mci_command cmd; | |
| 182 | + | |
| 183 | + memset(&cmd, 0, sizeof(cmd)); | |
| 184 | + cmd.tuner = state->tuner; | |
| 185 | + cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; | |
| 186 | + return mci_cmd(state, &cmd, NULL); | |
| 187 | +} | |
| 188 | + | |
| 189 | +static int stop(struct dvb_frontend *fe) | |
| 190 | +{ | |
| 191 | + struct mci *state = fe->demodulator_priv; | |
| 192 | + struct mci_command cmd; | |
| 193 | + u32 input = state->tuner; | |
| 194 | + | |
| 195 | + memset(&cmd, 0, sizeof(cmd)); | |
| 196 | + if (state->demod != DEMOD_UNUSED) { | |
| 197 | + cmd.command = MCI_CMD_STOP; | |
| 198 | + cmd.demod = state->demod; | |
| 199 | + mci_cmd(state, &cmd, NULL); | |
| 200 | + if (state->base->iq_mode) { | |
| 201 | + cmd.command = MCI_CMD_STOP; | |
| 202 | + cmd.demod = state->demod; | |
| 203 | + cmd.output = 0; | |
| 204 | + mci_cmd(state, &cmd, NULL); | |
| 205 | + mci_config(state, SX8_TSCONFIG_MODE_NORMAL); | |
| 206 | + } | |
| 207 | + } | |
| 208 | + mutex_lock(&state->base->tuner_lock); | |
| 209 | + state->base->tuner_use_count[input]--; | |
| 210 | + if (!state->base->tuner_use_count[input]) | |
| 211 | + mci_set_tuner(fe, input, 0); | |
| 212 | + if (state->demod < MCI_DEMOD_MAX) | |
| 213 | + state->base->demod_in_use[state->demod] = 0; | |
| 214 | + state->base->used_ldpc_bitrate[state->nr] = 0; | |
| 215 | + state->demod = DEMOD_UNUSED; | |
| 216 | + state->base->assigned_demod[state->nr] = DEMOD_UNUSED; | |
| 217 | + state->base->iq_mode = 0; | |
| 218 | + mutex_unlock(&state->base->tuner_lock); | |
| 219 | + state->started = 0; | |
| 220 | + return 0; | |
| 221 | +} | |
| 222 | + | |
| 223 | +static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) | |
| 224 | +{ | |
| 225 | + struct mci *state = fe->demodulator_priv; | |
| 226 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 227 | + u32 used_ldpc_bitrate = 0, free_ldpc_bitrate; | |
| 228 | + u32 used_demods = 0; | |
| 229 | + struct mci_command cmd; | |
| 230 | + u32 input = state->tuner; | |
| 231 | + u32 bits_per_symbol = 0; | |
| 232 | + int i, stat = 0; | |
| 233 | + | |
| 234 | + if (p->symbol_rate >= (MCLK / 2)) | |
| 235 | + flags &= ~1; | |
| 236 | + if ((flags & 3) == 0) | |
| 237 | + return -EINVAL; | |
| 238 | + | |
| 239 | + if (flags & 2) { | |
| 240 | + u32 tmp = modmask; | |
| 241 | + | |
| 242 | + bits_per_symbol = 1; | |
| 243 | + while (tmp & 1) { | |
| 244 | + tmp >>= 1; | |
| 245 | + bits_per_symbol++; | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + mutex_lock(&state->base->tuner_lock); | |
| 250 | + if (state->base->iq_mode) { | |
| 251 | + stat = -EBUSY; | |
| 252 | + goto unlock; | |
| 253 | + } | |
| 254 | + for (i = 0; i < MCI_DEMOD_MAX; i++) { | |
| 255 | + used_ldpc_bitrate += state->base->used_ldpc_bitrate[i]; | |
| 256 | + if (state->base->demod_in_use[i]) | |
| 257 | + used_demods++; | |
| 258 | + } | |
| 259 | + if (used_ldpc_bitrate >= MAX_LDPC_BITRATE || | |
| 260 | + ((ts_config & SX8_TSCONFIG_MODE_MASK) > | |
| 261 | + SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) { | |
| 262 | + stat = -EBUSY; | |
| 263 | + goto unlock; | |
| 264 | + } | |
| 265 | + free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate; | |
| 266 | + if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE) | |
| 267 | + free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE; | |
| 268 | + | |
| 269 | + while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate) | |
| 270 | + bits_per_symbol--; | |
| 271 | + | |
| 272 | + if (bits_per_symbol < 2) { | |
| 273 | + stat = -EBUSY; | |
| 274 | + goto unlock; | |
| 275 | + } | |
| 276 | + i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7; | |
| 277 | + while (i >= 0 && state->base->demod_in_use[i]) | |
| 278 | + i--; | |
| 279 | + if (i < 0) { | |
| 280 | + stat = -EBUSY; | |
| 281 | + goto unlock; | |
| 282 | + } | |
| 283 | + state->base->demod_in_use[i] = 1; | |
| 284 | + state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate | |
| 285 | + * bits_per_symbol; | |
| 286 | + state->demod = i; | |
| 287 | + state->base->assigned_demod[state->nr] = i; | |
| 288 | + | |
| 289 | + if (!state->base->tuner_use_count[input]) | |
| 290 | + mci_set_tuner(fe, input, 1); | |
| 291 | + state->base->tuner_use_count[input]++; | |
| 292 | + state->base->iq_mode = (ts_config > 1); | |
| 293 | +unlock: | |
| 294 | + mutex_unlock(&state->base->tuner_lock); | |
| 295 | + if (stat) | |
| 296 | + return stat; | |
| 297 | + memset(&cmd, 0, sizeof(cmd)); | |
| 298 | + | |
| 299 | + if (state->base->iq_mode) { | |
| 300 | + cmd.command = SX8_CMD_SELECT_IQOUT; | |
| 301 | + cmd.demod = state->demod; | |
| 302 | + cmd.output = 0; | |
| 303 | + mci_cmd(state, &cmd, NULL); | |
| 304 | + mci_config(state, ts_config); | |
| 305 | + } | |
| 306 | + if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000) | |
| 307 | + flags |= 0x80; | |
| 308 | + dev_dbg(state->base->dev, "MCI-%d: tuner=%d demod=%d\n", | |
| 309 | + state->nr, state->tuner, state->demod); | |
| 310 | + cmd.command = MCI_CMD_SEARCH_DVBS; | |
| 311 | + cmd.dvbs2_search.flags = flags; | |
| 312 | + cmd.dvbs2_search.s2_modulation_mask = | |
| 313 | + modmask & ((1 << (bits_per_symbol - 1)) - 1); | |
| 314 | + cmd.dvbs2_search.retry = 2; | |
| 315 | + cmd.dvbs2_search.frequency = p->frequency * 1000; | |
| 316 | + cmd.dvbs2_search.symbol_rate = p->symbol_rate; | |
| 317 | + cmd.dvbs2_search.scrambling_sequence_index = | |
| 318 | + p->scrambling_sequence_index; | |
| 319 | + cmd.dvbs2_search.input_stream_id = | |
| 320 | + (p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0; | |
| 321 | + cmd.tuner = state->tuner; | |
| 322 | + cmd.demod = state->demod; | |
| 323 | + cmd.output = state->nr; | |
| 324 | + if (p->stream_id == 0x80000000) | |
| 325 | + cmd.output |= 0x80; | |
| 326 | + stat = mci_cmd(state, &cmd, NULL); | |
| 327 | + if (stat) | |
| 328 | + stop(fe); | |
| 329 | + return stat; | |
| 330 | +} | |
| 331 | + | |
| 332 | +static int start_iq(struct dvb_frontend *fe, u32 ts_config) | |
| 333 | +{ | |
| 334 | + struct mci *state = fe->demodulator_priv; | |
| 335 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 336 | + u32 used_demods = 0; | |
| 337 | + struct mci_command cmd; | |
| 338 | + u32 input = state->tuner; | |
| 339 | + int i, stat = 0; | |
| 340 | + | |
| 341 | + mutex_lock(&state->base->tuner_lock); | |
| 342 | + if (state->base->iq_mode) { | |
| 343 | + stat = -EBUSY; | |
| 344 | + goto unlock; | |
| 345 | + } | |
| 346 | + for (i = 0; i < MCI_DEMOD_MAX; i++) | |
| 347 | + if (state->base->demod_in_use[i]) | |
| 348 | + used_demods++; | |
| 349 | + if (used_demods > 0) { | |
| 350 | + stat = -EBUSY; | |
| 351 | + goto unlock; | |
| 352 | + } | |
| 353 | + state->demod = 0; | |
| 354 | + state->base->assigned_demod[state->nr] = 0; | |
| 355 | + if (!state->base->tuner_use_count[input]) | |
| 356 | + mci_set_tuner(fe, input, 1); | |
| 357 | + state->base->tuner_use_count[input]++; | |
| 358 | + state->base->iq_mode = (ts_config > 1); | |
| 359 | +unlock: | |
| 360 | + mutex_unlock(&state->base->tuner_lock); | |
| 361 | + if (stat) | |
| 362 | + return stat; | |
| 363 | + | |
| 364 | + memset(&cmd, 0, sizeof(cmd)); | |
| 365 | + cmd.command = SX8_CMD_START_IQ; | |
| 366 | + cmd.dvbs2_search.frequency = p->frequency * 1000; | |
| 367 | + cmd.dvbs2_search.symbol_rate = p->symbol_rate; | |
| 368 | + cmd.tuner = state->tuner; | |
| 369 | + cmd.demod = state->demod; | |
| 370 | + cmd.output = 7; | |
| 371 | + mci_config(state, ts_config); | |
| 372 | + stat = mci_cmd(state, &cmd, NULL); | |
| 373 | + if (stat) | |
| 374 | + stop(fe); | |
| 375 | + return stat; | |
| 376 | +} | |
| 377 | + | |
| 378 | +static int set_parameters(struct dvb_frontend *fe) | |
| 379 | +{ | |
| 380 | + int stat = 0; | |
| 381 | + struct mci *state = fe->demodulator_priv; | |
| 382 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 383 | + u32 ts_config, iq_mode = 0, isi; | |
| 384 | + | |
| 385 | + if (state->started) | |
| 386 | + stop(fe); | |
| 387 | + | |
| 388 | + isi = p->stream_id; | |
| 389 | + if (isi != NO_STREAM_ID_FILTER) | |
| 390 | + iq_mode = (isi & 0x30000000) >> 28; | |
| 391 | + | |
| 392 | + switch (iq_mode) { | |
| 393 | + case 1: | |
| 394 | + ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); | |
| 395 | + break; | |
| 396 | + case 2: | |
| 397 | + ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); | |
| 398 | + break; | |
| 399 | + default: | |
| 400 | + ts_config = SX8_TSCONFIG_MODE_NORMAL; | |
| 401 | + break; | |
| 402 | + } | |
| 403 | + | |
| 404 | + if (iq_mode != 2) { | |
| 405 | + u32 flags = 3; | |
| 406 | + u32 mask = 3; | |
| 407 | + | |
| 408 | + if (p->modulation == APSK_16 || | |
| 409 | + p->modulation == APSK_32) { | |
| 410 | + flags = 2; | |
| 411 | + mask = 15; | |
| 412 | + } | |
| 413 | + stat = start(fe, flags, mask, ts_config); | |
| 414 | + } else { | |
| 415 | + stat = start_iq(fe, ts_config); | |
| 416 | + } | |
| 417 | + | |
| 418 | + if (!stat) { | |
| 419 | + state->started = 1; | |
| 420 | + state->first_time_lock = 1; | |
| 421 | + state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL; | |
| 422 | + } | |
| 423 | + | |
| 424 | + return stat; | |
| 425 | +} | |
| 426 | + | |
| 427 | +static int tune(struct dvb_frontend *fe, bool re_tune, | |
| 428 | + unsigned int mode_flags, | |
| 429 | + unsigned int *delay, enum fe_status *status) | |
| 430 | +{ | |
| 431 | + int r; | |
| 432 | + | |
| 433 | + if (re_tune) { | |
| 434 | + r = set_parameters(fe); | |
| 435 | + if (r) | |
| 436 | + return r; | |
| 437 | + } | |
| 438 | + r = read_status(fe, status); | |
| 439 | + if (r) | |
| 440 | + return r; | |
| 441 | + | |
| 442 | + if (*status & FE_HAS_LOCK) | |
| 443 | + return 0; | |
| 444 | + *delay = HZ / 10; | |
| 445 | + return 0; | |
| 446 | +} | |
| 447 | + | |
| 448 | +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) | |
| 449 | +{ | |
| 450 | + return DVBFE_ALGO_HW; | |
| 451 | +} | |
| 452 | + | |
| 453 | +static int set_input(struct dvb_frontend *fe, int input) | |
| 454 | +{ | |
| 455 | + struct mci *state = fe->demodulator_priv; | |
| 456 | + | |
| 457 | + state->tuner = input; | |
| 458 | + dev_dbg(state->base->dev, "MCI-%d: input=%d\n", state->nr, input); | |
| 459 | + return 0; | |
| 460 | +} | |
| 461 | + | |
| 462 | +static struct dvb_frontend_ops mci_ops = { | |
| 463 | + .delsys = { SYS_DVBS, SYS_DVBS2 }, | |
| 464 | + .info = { | |
| 465 | + .name = "Digital Devices MaxSX8 MCI DVB-S/S2/S2X", | |
| 466 | + .frequency_min = 950000, | |
| 467 | + .frequency_max = 2150000, | |
| 468 | + .frequency_stepsize = 0, | |
| 469 | + .frequency_tolerance = 0, | |
| 470 | + .symbol_rate_min = 100000, | |
| 471 | + .symbol_rate_max = 100000000, | |
| 472 | + .caps = FE_CAN_INVERSION_AUTO | | |
| 473 | + FE_CAN_FEC_AUTO | | |
| 474 | + FE_CAN_QPSK | | |
| 475 | + FE_CAN_2G_MODULATION | | |
| 476 | + FE_CAN_MULTISTREAM, | |
| 477 | + }, | |
| 478 | + .get_frontend_algo = get_algo, | |
| 479 | + .tune = tune, | |
| 480 | + .release = release, | |
| 481 | + .read_status = read_status, | |
| 482 | +}; | |
| 483 | + | |
| 484 | +static struct mci_base *match_base(void *key) | |
| 485 | +{ | |
| 486 | + struct mci_base *p; | |
| 487 | + | |
| 488 | + list_for_each_entry(p, &mci_list, mci_list) | |
| 489 | + if (p->key == key) | |
| 490 | + return p; | |
| 491 | + return NULL; | |
| 492 | +} | |
| 493 | + | |
| 494 | +static int probe(struct mci *state) | |
| 495 | +{ | |
| 496 | + mci_reset(state); | |
| 497 | + return 0; | |
| 498 | +} | |
| 499 | + | |
| 500 | +struct dvb_frontend | |
| 501 | +*ddb_mci_attach(struct ddb_input *input, | |
| 502 | + int mci_type, int nr, | |
| 503 | + int (**fn_set_input)(struct dvb_frontend *fe, int input)) | |
| 504 | +{ | |
| 505 | + struct ddb_port *port = input->port; | |
| 506 | + struct ddb *dev = port->dev; | |
| 507 | + struct ddb_link *link = &dev->link[port->lnr]; | |
| 508 | + struct mci_base *base; | |
| 509 | + struct mci *state; | |
| 510 | + void *key = mci_type ? (void *)port : (void *)link; | |
| 511 | + | |
| 512 | + state = kzalloc(sizeof(*state), GFP_KERNEL); | |
| 513 | + if (!state) | |
| 514 | + return NULL; | |
| 515 | + | |
| 516 | + base = match_base(key); | |
| 517 | + if (base) { | |
| 518 | + base->count++; | |
| 519 | + state->base = base; | |
| 520 | + } else { | |
| 521 | + base = kzalloc(sizeof(*base), GFP_KERNEL); | |
| 522 | + if (!base) | |
| 523 | + goto fail; | |
| 524 | + base->key = key; | |
| 525 | + base->count = 1; | |
| 526 | + base->link = link; | |
| 527 | + base->dev = dev->dev; | |
| 528 | + mutex_init(&base->mci_lock); | |
| 529 | + mutex_init(&base->tuner_lock); | |
| 530 | + ddb_irq_set(dev, link->nr, 0, mci_handler, base); | |
| 531 | + init_completion(&base->completion); | |
| 532 | + state->base = base; | |
| 533 | + if (probe(state) < 0) { | |
| 534 | + kfree(base); | |
| 535 | + goto fail; | |
| 536 | + } | |
| 537 | + list_add(&base->mci_list, &mci_list); | |
| 538 | + } | |
| 539 | + state->fe.ops = mci_ops; | |
| 540 | + state->fe.demodulator_priv = state; | |
| 541 | + state->nr = nr; | |
| 542 | + *fn_set_input = set_input; | |
| 543 | + | |
| 544 | + state->tuner = nr; | |
| 545 | + state->demod = nr; | |
| 546 | + | |
| 547 | + return &state->fe; | |
| 548 | +fail: | |
| 549 | + kfree(state); | |
| 550 | + return NULL; | |
| 551 | +} | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * ddbridge-mci.h: Digital Devices micro code interface | |
| 4 | + * | |
| 5 | + * Copyright (C) 2017 Digital Devices GmbH | |
| 6 | + * Marcus Metzler <mocm@metzlerbros.de> | |
| 7 | + * Ralph Metzler <rjkm@metzlerbros.de> | |
| 8 | + * | |
| 9 | + * This program is free software; you can redistribute it and/or | |
| 10 | + * modify it under the terms of the GNU General Public License | |
| 11 | + * version 2 only, as published by the Free Software Foundation. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#ifndef _DDBRIDGE_MCI_H_ | |
| 20 | +#define _DDBRIDGE_MCI_H_ | |
| 21 | + | |
| 22 | +#define MCI_DEMOD_MAX 8 | |
| 23 | +#define MCI_TUNER_MAX 4 | |
| 24 | +#define DEMOD_UNUSED (0xFF) | |
| 25 | + | |
| 26 | +#define MCI_CONTROL (0x500) | |
| 27 | +#define MCI_COMMAND (0x600) | |
| 28 | +#define MCI_RESULT (0x680) | |
| 29 | + | |
| 30 | +#define MCI_COMMAND_SIZE (0x80) | |
| 31 | +#define MCI_RESULT_SIZE (0x80) | |
| 32 | + | |
| 33 | +#define MCI_CONTROL_START_COMMAND (0x00000001) | |
| 34 | +#define MCI_CONTROL_ENABLE_DONE_INTERRUPT (0x00000002) | |
| 35 | +#define MCI_CONTROL_RESET (0x00008000) | |
| 36 | +#define MCI_CONTROL_READY (0x00010000) | |
| 37 | + | |
| 38 | +#define SX8_TSCONFIG (0x280) | |
| 39 | + | |
| 40 | +#define SX8_TSCONFIG_MODE_MASK (0x00000003) | |
| 41 | +#define SX8_TSCONFIG_MODE_OFF (0x00000000) | |
| 42 | +#define SX8_TSCONFIG_MODE_NORMAL (0x00000001) | |
| 43 | +#define SX8_TSCONFIG_MODE_IQ (0x00000003) | |
| 44 | + | |
| 45 | +#define SX8_TSCONFIG_TSHEADER (0x00000004) | |
| 46 | +#define SX8_TSCONFIG_BURST (0x00000008) | |
| 47 | + | |
| 48 | +#define SX8_TSCONFIG_BURSTSIZE_MASK (0x00000030) | |
| 49 | +#define SX8_TSCONFIG_BURSTSIZE_2K (0x00000000) | |
| 50 | +#define SX8_TSCONFIG_BURSTSIZE_4K (0x00000010) | |
| 51 | +#define SX8_TSCONFIG_BURSTSIZE_8K (0x00000020) | |
| 52 | +#define SX8_TSCONFIG_BURSTSIZE_16K (0x00000030) | |
| 53 | + | |
| 54 | +#define SX8_DEMOD_STOPPED (0) | |
| 55 | +#define SX8_DEMOD_IQ_MODE (1) | |
| 56 | +#define SX8_DEMOD_WAIT_SIGNAL (2) | |
| 57 | +#define SX8_DEMOD_WAIT_MATYPE (3) | |
| 58 | +#define SX8_DEMOD_TIMEOUT (14) | |
| 59 | +#define SX8_DEMOD_LOCKED (15) | |
| 60 | + | |
| 61 | +#define MCI_CMD_STOP (0x01) | |
| 62 | +#define MCI_CMD_GETSTATUS (0x02) | |
| 63 | +#define MCI_CMD_GETSIGNALINFO (0x03) | |
| 64 | +#define MCI_CMD_RFPOWER (0x04) | |
| 65 | + | |
| 66 | +#define MCI_CMD_SEARCH_DVBS (0x10) | |
| 67 | + | |
| 68 | +#define MCI_CMD_GET_IQSYMBOL (0x30) | |
| 69 | + | |
| 70 | +#define SX8_CMD_INPUT_ENABLE (0x40) | |
| 71 | +#define SX8_CMD_INPUT_DISABLE (0x41) | |
| 72 | +#define SX8_CMD_START_IQ (0x42) | |
| 73 | +#define SX8_CMD_STOP_IQ (0x43) | |
| 74 | +#define SX8_CMD_SELECT_IQOUT (0x44) | |
| 75 | +#define SX8_CMD_SELECT_TSOUT (0x45) | |
| 76 | + | |
| 77 | +#define SX8_ERROR_UNSUPPORTED (0x80) | |
| 78 | + | |
| 79 | +#define SX8_SUCCESS(status) (status < SX8_ERROR_UNSUPPORTED) | |
| 80 | + | |
| 81 | +#define SX8_CMD_DIAG_READ8 (0xE0) | |
| 82 | +#define SX8_CMD_DIAG_READ32 (0xE1) | |
| 83 | +#define SX8_CMD_DIAG_WRITE8 (0xE2) | |
| 84 | +#define SX8_CMD_DIAG_WRITE32 (0xE3) | |
| 85 | + | |
| 86 | +#define SX8_CMD_DIAG_READRF (0xE8) | |
| 87 | +#define SX8_CMD_DIAG_WRITERF (0xE9) | |
| 88 | + | |
| 89 | +struct mci_command { | |
| 90 | + union { | |
| 91 | + u32 command_word; | |
| 92 | + struct { | |
| 93 | + u8 command; | |
| 94 | + u8 tuner; | |
| 95 | + u8 demod; | |
| 96 | + u8 output; | |
| 97 | + }; | |
| 98 | + }; | |
| 99 | + union { | |
| 100 | + u32 params[31]; | |
| 101 | + struct { | |
| 102 | + u8 flags; | |
| 103 | + u8 s2_modulation_mask; | |
| 104 | + u8 rsvd1; | |
| 105 | + u8 retry; | |
| 106 | + u32 frequency; | |
| 107 | + u32 symbol_rate; | |
| 108 | + u8 input_stream_id; | |
| 109 | + u8 rsvd2[3]; | |
| 110 | + u32 scrambling_sequence_index; | |
| 111 | + } dvbs2_search; | |
| 112 | + }; | |
| 113 | +}; | |
| 114 | + | |
| 115 | +struct mci_result { | |
| 116 | + union { | |
| 117 | + u32 status_word; | |
| 118 | + struct { | |
| 119 | + u8 status; | |
| 120 | + u8 rsvd; | |
| 121 | + u16 time; | |
| 122 | + }; | |
| 123 | + }; | |
| 124 | + union { | |
| 125 | + u32 result[27]; | |
| 126 | + struct { | |
| 127 | + u8 standard; | |
| 128 | + /* puncture rate for DVB-S */ | |
| 129 | + u8 pls_code; | |
| 130 | + /* 7-6: rolloff, 5-2: rsrvd, 1:short, 0:pilots */ | |
| 131 | + u8 roll_off; | |
| 132 | + u8 rsvd; | |
| 133 | + u32 frequency; | |
| 134 | + u32 symbol_rate; | |
| 135 | + s16 channel_power; | |
| 136 | + s16 band_power; | |
| 137 | + s16 signal_to_noise; | |
| 138 | + s16 rsvd2; | |
| 139 | + u32 packet_errors; | |
| 140 | + u32 ber_numerator; | |
| 141 | + u32 ber_denominator; | |
| 142 | + } dvbs2_signal_info; | |
| 143 | + struct { | |
| 144 | + u8 i_symbol; | |
| 145 | + u8 q_symbol; | |
| 146 | + } dvbs2_signal_iq; | |
| 147 | + }; | |
| 148 | + u32 version[4]; | |
| 149 | +}; | |
| 150 | + | |
| 151 | +struct dvb_frontend | |
| 152 | +*ddb_mci_attach(struct ddb_input *input, | |
| 153 | + int mci_type, int nr, | |
| 154 | + int (**fn_set_input)(struct dvb_frontend *fe, int input)); | |
| 155 | + | |
| 156 | +#endif /* _DDBRIDGE_MCI_H_ */ | |
| @@ -17,6 +17,9 @@ · 16 unmodified lines | ||
| 17 | 17 | * http://www.gnu.org/copyleft/gpl.html |
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | +#ifndef __DDBRIDGE_REGS_H__ | |
| 21 | +#define __DDBRIDGE_REGS_H__ | |
| 22 | + | |
| 20 | 23 | /* ------------------------------------------------------------------------- */ |
| 21 | 24 | /* SPI Controller */ |
| 22 | 25 | |
| @@ -154,3 +157,4 @@ · 131 unmodified lines | ||
| 154 | 157 | #define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10) |
| 155 | 158 | #define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14) |
| 156 | 159 | |
| 160 | +#endif /* __DDBRIDGE_REGS_H__ */ | |
| @@ -63,7 +63,7 @@ · 62 unmodified lines | ||
| 63 | 63 | #include <media/dvb_ca_en50221.h> |
| 64 | 64 | #include <media/dvb_net.h> |
| 65 | 65 | |
| 66 | −#define DDBRIDGE_VERSION "0.9.32-integrated" | |
| 66 | +#define DDBRIDGE_VERSION "0.9.33-integrated" | |
| 67 | 67 | |
| 68 | 68 | #define DDB_MAX_I2C 32 |
| 69 | 69 | #define DDB_MAX_PORT 32 |
| @@ -112,11 +112,12 @@ struct ddb_ids { · 42 unmodified lines | ||
| 112 | 112 | |
| 113 | 113 | struct ddb_info { |
| 114 | 114 | int type; |
| 115 | −#define DDB_NONE 0 | |
| 116 | −#define DDB_OCTOPUS 1 | |
| 117 | −#define DDB_OCTOPUS_CI 2 | |
| 118 | −#define DDB_OCTOPUS_MAX 5 | |
| 115 | +#define DDB_NONE 0 | |
| 116 | +#define DDB_OCTOPUS 1 | |
| 117 | +#define DDB_OCTOPUS_CI 2 | |
| 118 | +#define DDB_OCTOPUS_MAX 5 | |
| 119 | 119 | #define DDB_OCTOPUS_MAX_CT 6 |
| 120 | +#define DDB_OCTOPUS_MCI 9 | |
| 120 | 121 | char *name; |
| 121 | 122 | u32 i2c_mask; |
| 122 | 123 | u8 port_num; |
| @@ -133,23 +134,12 @@ struct ddb_info { · 10 unmodified lines | ||
| 133 | 134 | #define TS_QUIRK_REVERSED 2 |
| 134 | 135 | #define TS_QUIRK_ALT_OSC 8 |
| 135 | 136 | u32 tempmon_irq; |
| 137 | + u8 mci; | |
| 136 | 138 | const struct ddb_regmap *regmap; |
| 137 | 139 | }; |
| 138 | 140 | |
| 139 | −/* DMA_SIZE MUST be smaller than 256k and | |
| 140 | − * MUST be divisible by 188 and 128 !!! | |
| 141 | − */ | |
| 142 | − | |
| 143 | 141 | #define DMA_MAX_BUFS 32 /* hardware table limit */ |
| 144 | 142 | |
| 145 | −#define INPUT_DMA_BUFS 8 | |
| 146 | −#define INPUT_DMA_SIZE (128 * 47 * 21) | |
| 147 | −#define INPUT_DMA_IRQ_DIV 1 | |
| 148 | − | |
| 149 | −#define OUTPUT_DMA_BUFS 8 | |
| 150 | −#define OUTPUT_DMA_SIZE (128 * 47 * 21) | |
| 151 | −#define OUTPUT_DMA_IRQ_DIV 1 | |
| 152 | − | |
| 153 | 143 | struct ddb; |
| 154 | 144 | struct ddb_port; |
| 155 | 145 | |
| @@ -248,6 +238,7 @@ struct ddb_port { · 92 unmodified lines | ||
| 248 | 238 | char *name; |
| 249 | 239 | char *type_name; |
| 250 | 240 | u32 type; |
| 241 | +#define DDB_TUNER_DUMMY 0xffffffff | |
| 251 | 242 | #define DDB_TUNER_NONE 0 |
| 252 | 243 | #define DDB_TUNER_DVBS_ST 1 |
| 253 | 244 | #define DDB_TUNER_DVBS_ST_AA 2 |
| @@ -264,6 +255,7 @@ struct ddb_port { · 10 unmodified lines | ||
| 264 | 255 | #define DDB_CI_EXTERNAL_XO2_B 13 |
| 265 | 256 | #define DDB_TUNER_DVBS_STV0910_PR 14 |
| 266 | 257 | #define DDB_TUNER_DVBC2T2I_SONY_P 15 |
| 258 | +#define DDB_TUNER_MCI 16 | |
| 267 | 259 | |
| 268 | 260 | #define DDB_TUNER_XO2 32 |
| 269 | 261 | #define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0) |
| @@ -305,6 +297,11 @@ struct ddb_lnb { · 35 unmodified lines | ||
| 305 | 297 | u32 fmode; |
| 306 | 298 | }; |
| 307 | 299 | |
| 300 | +struct ddb_irq { | |
| 301 | + void (*handler)(void *); | |
| 302 | + void *data; | |
| 303 | +}; | |
| 304 | + | |
| 308 | 305 | struct ddb_link { |
| 309 | 306 | struct ddb *dev; |
| 310 | 307 | const struct ddb_info *info; |
| @@ -319,6 +316,7 @@ struct ddb_link { · 8 unmodified lines | ||
| 319 | 316 | spinlock_t temp_lock; /* lock temp chip access */ |
| 320 | 317 | int overtemperature_error; |
| 321 | 318 | u8 temp_tab[11]; |
| 319 | + struct ddb_irq irq[256]; | |
| 322 | 320 | }; |
| 323 | 321 | |
| 324 | 322 | struct ddb { |
| @@ -343,9 +341,6 @@ struct ddb { · 18 unmodified lines | ||
| 343 | 341 | struct ddb_dma idma[DDB_MAX_INPUT]; |
| 344 | 342 | struct ddb_dma odma[DDB_MAX_OUTPUT]; |
| 345 | 343 | |
| 346 | − void (*handler[4][256])(unsigned long); | |
| 347 | − unsigned long handler_data[4][256]; | |
| 348 | − | |
| 349 | 344 | struct device *ddb_dev; |
| 350 | 345 | u32 ddb_dev_users; |
| 351 | 346 | u32 nr; |
| @@ -368,16 +363,9 @@ int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len); · 16 unmodified lines | ||
| 368 | 363 | |
| 369 | 364 | /****************************************************************************/ |
| 370 | 365 | |
| 371 | −/* ddbridge-main.c (modparams) */ | |
| 372 | −extern int ci_bitrate; | |
| 373 | −extern int ts_loop; | |
| 374 | −extern int xo2_speed; | |
| 375 | −extern int alt_dma; | |
| 376 | −extern int no_init; | |
| 377 | −extern int stv0910_single; | |
| 378 | −extern struct workqueue_struct *ddb_wq; | |
| 379 | − | |
| 380 | 366 | /* ddbridge-core.c */ |
| 367 | +struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr, | |
| 368 | + void (*handler)(void *), void *data); | |
| 381 | 369 | void ddb_ports_detach(struct ddb *dev); |
| 382 | 370 | void ddb_ports_release(struct ddb *dev); |
| 383 | 371 | void ddb_buffers_free(struct ddb *dev); |
| @@ -389,9 +377,9 @@ void ddb_ports_init(struct ddb *dev); · 5 unmodified lines | ||
| 389 | 377 | int ddb_buffers_alloc(struct ddb *dev); |
| 390 | 378 | int ddb_ports_attach(struct ddb *dev); |
| 391 | 379 | int ddb_device_create(struct ddb *dev); |
| 392 | −int ddb_class_create(void); | |
| 393 | −void ddb_class_destroy(void); | |
| 394 | 380 | int ddb_init(struct ddb *dev); |
| 395 | 381 | void ddb_unmap(struct ddb *dev); |
| 382 | +int ddb_exit_ddbridge(int stage, int error); | |
| 383 | +int ddb_init_ddbridge(void); | |
| 396 | 384 | |
| 397 | 385 | #endif /* DDBRIDGE_H */ |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config VIDEO_DT3155 |
| 2 | 2 | tristate "DT3155 frame grabber" |
| 3 | 3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 |
| 4 | − depends on HAS_DMA | |
| 5 | 4 | select VIDEOBUF2_DMA_CONTIG |
| 6 | 5 | default n |
| 7 | 6 | ---help--- |
| @@ -2,18 +2,16 @@ config VIDEO_IPU3_CIO2 · 1 unmodified line | ||
| 2 | 2 | tristate "Intel ipu3-cio2 driver" |
| 3 | 3 | depends on VIDEO_V4L2 && PCI |
| 4 | 4 | depends on VIDEO_V4L2_SUBDEV_API |
| 5 | − depends on X86 || COMPILE_TEST | |
| 5 | + depends on (X86 && ACPI) || COMPILE_TEST | |
| 6 | 6 | depends on MEDIA_CONTROLLER |
| 7 | − depends on HAS_DMA | |
| 8 | − depends on ACPI | |
| 9 | 7 | select V4L2_FWNODE |
| 10 | 8 | select VIDEOBUF2_DMA_SG |
| 11 | 9 | |
| 12 | 10 | ---help--- |
| 13 | − This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel | |
| 14 | − Skylake and Kaby Lake SoCs and used for capturing images and | |
| 15 | − video from a camera sensor. | |
| 11 | + This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel | |
| 12 | + Skylake and Kaby Lake SoCs and used for capturing images and | |
| 13 | + video from a camera sensor. | |
| 16 | 14 | |
| 17 | − Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2 | |
| 18 | − connected camera. | |
| 19 | − The module will be called ipu3-cio2. | |
| 15 | + Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2 | |
| 16 | + connected camera. | |
| 17 | + The module will be called ipu3-cio2. | |
| @@ -640,18 +640,10 @@ static const char *const cio2_port_errs[] = { · 639 unmodified lines | ||
| 640 | 640 | "PKT2LONG", |
| 641 | 641 | }; |
| 642 | 642 | |
| 643 | −static irqreturn_t cio2_irq(int irq, void *cio2_ptr) | |
| 643 | +static void cio2_irq_handle_once(struct cio2_device *cio2, u32 int_status) | |
| 644 | 644 | { |
| 645 | − struct cio2_device *cio2 = cio2_ptr; | |
| 646 | 645 | void __iomem *const base = cio2->base; |
| 647 | 646 | struct device *dev = &cio2->pci_dev->dev; |
| 648 | − u32 int_status, int_clear; | |
| 649 | − | |
| 650 | − int_status = readl(base + CIO2_REG_INT_STS); | |
| 651 | − int_clear = int_status; | |
| 652 | − | |
| 653 | − if (!int_status) | |
| 654 | − return IRQ_NONE; | |
| 655 | 647 | |
| 656 | 648 | if (int_status & CIO2_INT_IOOE) { |
| 657 | 649 | /* |
| @@ -770,9 +762,29 @@ static irqreturn_t cio2_irq(int irq, void *cio2_ptr) · 112 unmodified lines | ||
| 770 | 762 | int_status &= ~(CIO2_INT_IOIE | CIO2_INT_IOIRQ); |
| 771 | 763 | } |
| 772 | 764 | |
| 773 | − writel(int_clear, base + CIO2_REG_INT_STS); | |
| 774 | 765 | if (int_status) |
| 775 | 766 | dev_warn(dev, "unknown interrupt 0x%x on INT\n", int_status); |
| 767 | +} | |
| 768 | + | |
| 769 | +static irqreturn_t cio2_irq(int irq, void *cio2_ptr) | |
| 770 | +{ | |
| 771 | + struct cio2_device *cio2 = cio2_ptr; | |
| 772 | + void __iomem *const base = cio2->base; | |
| 773 | + struct device *dev = &cio2->pci_dev->dev; | |
| 774 | + u32 int_status; | |
| 775 | + | |
| 776 | + int_status = readl(base + CIO2_REG_INT_STS); | |
| 777 | + dev_dbg(dev, "isr enter - interrupt status 0x%x\n", int_status); | |
| 778 | + if (!int_status) | |
| 779 | + return IRQ_NONE; | |
| 780 | + | |
| 781 | + do { | |
| 782 | + writel(int_status, base + CIO2_REG_INT_STS); | |
| 783 | + cio2_irq_handle_once(cio2, int_status); | |
| 784 | + int_status = readl(base + CIO2_REG_INT_STS); | |
| 785 | + if (int_status) | |
| 786 | + dev_dbg(dev, "pending status 0x%x\n", int_status); | |
| 787 | + } while (int_status); | |
| 776 | 788 | |
| 777 | 789 | return IRQ_HANDLED; |
| 778 | 790 | } |
| @@ -92,6 +92,7 @@ static void mantis_uart_work(struct work_struct *work) · 91 unmodified lines | ||
| 92 | 92 | { |
| 93 | 93 | struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); |
| 94 | 94 | u32 stat; |
| 95 | + unsigned long timeout; | |
| 95 | 96 | |
| 96 | 97 | stat = mmread(MANTIS_UART_STAT); |
| 97 | 98 | |
| @@ -102,9 +103,15 @@ static void mantis_uart_work(struct work_struct *work) · 4 unmodified lines | ||
| 102 | 103 | * MANTIS_UART_RXFIFO_DATA is only set if at least |
| 103 | 104 | * config->bytes + 1 bytes are in the FIFO. |
| 104 | 105 | */ |
| 106 | + | |
| 107 | + /* FIXME: is 10ms good enough ? */ | |
| 108 | + timeout = jiffies + msecs_to_jiffies(10); | |
| 105 | 109 | while (stat & MANTIS_UART_RXFIFO_DATA) { |
| 106 | 110 | mantis_uart_read(mantis); |
| 107 | 111 | stat = mmread(MANTIS_UART_STAT); |
| 112 | + | |
| 113 | + if (!time_is_after_jiffies(timeout)) | |
| 114 | + break; | |
| 108 | 115 | } |
| 109 | 116 | |
| 110 | 117 | /* re-enable UART (RX) interrupt */ |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | config VIDEO_MEYE |
| 2 | 2 | tristate "Sony Vaio Picturebook Motion Eye Video For Linux" |
| 3 | − depends on PCI && SONY_LAPTOP && VIDEO_V4L2 | |
| 3 | + depends on PCI && VIDEO_V4L2 | |
| 4 | + depends on SONY_LAPTOP || COMPILE_TEST | |
| 4 | 5 | ---help--- |
| 5 | 6 | This is the video4linux driver for the Motion Eye camera found |
| 6 | 7 | in the Vaio Picturebook laptops. Please read the material in |
| @@ -137,11 +137,6 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) · 136 unmodified lines | ||
| 137 | 137 | chan->dev->card_info->tuner_config[chan->number]; |
| 138 | 138 | const struct stv6110x_devctl *ctl; |
| 139 | 139 | |
| 140 | − if (chan->number < 2) | |
| 141 | − i2c = &chan->dev->channel[0].i2c_adapter; | |
| 142 | − else | |
| 143 | − i2c = &chan->dev->channel[1].i2c_adapter; | |
| 144 | − | |
| 145 | 140 | ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); |
| 146 | 141 | if (ctl == NULL) { |
| 147 | 142 | dev_err(pdev, "No STV6110X found!\n"); |
| @@ -304,14 +299,6 @@ static int demod_attach_stv0900(struct ngene_channel *chan) · 156 unmodified lines | ||
| 304 | 299 | struct stv090x_config *feconf = (struct stv090x_config *) |
| 305 | 300 | chan->dev->card_info->fe_config[chan->number]; |
| 306 | 301 | |
| 307 | − /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ | |
| 308 | − /* Note: Both adapters share the same i2c bus, but the demod */ | |
| 309 | − /* driver requires that each demod has its own i2c adapter */ | |
| 310 | − if (chan->number < 2) | |
| 311 | − i2c = &chan->dev->channel[0].i2c_adapter; | |
| 312 | − else | |
| 313 | − i2c = &chan->dev->channel[1].i2c_adapter; | |
| 314 | − | |
| 315 | 302 | chan->fe = dvb_attach(stv090x_attach, feconf, i2c, |
| 316 | 303 | (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 |
| 317 | 304 | : STV090x_DEMODULATOR_1); |
| @@ -340,6 +327,7 @@ static struct stv0910_cfg stv0910_p = { · 22 unmodified lines | ||
| 340 | 327 | .parallel = 1, |
| 341 | 328 | .rptlvl = 4, |
| 342 | 329 | .clk = 30000000, |
| 330 | + .tsspeed = 0x28, | |
| 343 | 331 | }; |
| 344 | 332 | |
| 345 | 333 | static struct lnbh25_config lnbh25_cfg = { |
| @@ -721,7 +709,6 @@ static int cineS2_probe(struct ngene_channel *chan) · 375 unmodified lines | ||
| 721 | 709 | |
| 722 | 710 | |
| 723 | 711 | static struct lgdt330x_config aver_m780 = { |
| 724 | − .demod_address = 0xb2 >> 1, | |
| 725 | 712 | .demod_chip = LGDT3303, |
| 726 | 713 | .serial_mpeg = 0x00, /* PARALLEL */ |
| 727 | 714 | .clock_polarity_flip = 1, |
| @@ -738,7 +725,8 @@ static int demod_attach_lg330x(struct ngene_channel *chan) · 10 unmodified lines | ||
| 738 | 725 | { |
| 739 | 726 | struct device *pdev = &chan->dev->pci_dev->dev; |
| 740 | 727 | |
| 741 | − chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); | |
| 728 | + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, | |
| 729 | + 0xb2 >> 1, &chan->i2c_adapter); | |
| 742 | 730 | if (chan->fe == NULL) { |
| 743 | 731 | dev_err(pdev, "No LGDT330x found!\n"); |
| 744 | 732 | return -ENODEV; |
| @@ -40,7 +40,7 @@ · 39 unmodified lines | ||
| 40 | 40 | |
| 41 | 41 | static int ci_tsfix = 1; |
| 42 | 42 | module_param(ci_tsfix, int, 0444); |
| 43 | −MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); | |
| 43 | +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifts in conjunction with CI expansions (default: 1/enabled)"); | |
| 44 | 44 | |
| 45 | 45 | /****************************************************************************/ |
| 46 | 46 | /* COMMAND API interface ****************************************************/ |
| @@ -1,6 +1,9 @@ | ||
| 1 | 1 | config DVB_PT1 |
| 2 | 2 | tristate "PT1 cards" |
| 3 | 3 | depends on DVB_CORE && PCI && I2C |
| 4 | + select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT | |
| 5 | + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT | |
| 6 | + select MEDIA_TUNER_QM1D1B0004 if MEDIA_SUBDRV_AUTOSELECT | |
| 4 | 7 | help |
| 5 | 8 | Support for Earthsoft PT1 PCI cards. |
| 6 | 9 | |
| @@ -1,5 +1,6 @@ | ||
| 1 | −earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o | |
| 1 | +earth-pt1-objs := pt1.o | |
| 2 | 2 | |
| 3 | 3 | obj-$(CONFIG_DVB_PT1) += earth-pt1.o |
| 4 | 4 | |
| 5 | 5 | ccflags-y += -Idrivers/media/dvb-frontends |
| 6 | +ccflags-y += -Idrivers/media/tuners | |
| @@ -18,7 +18,10 @@ · 17 unmodified lines | ||
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | 20 | #include <linux/kernel.h> |
| 21 | +#include <linux/sched.h> | |
| 21 | 22 | #include <linux/sched/signal.h> |
| 23 | +#include <linux/hrtimer.h> | |
| 24 | +#include <linux/delay.h> | |
| 22 | 25 | #include <linux/module.h> |
| 23 | 26 | #include <linux/slab.h> |
| 24 | 27 | #include <linux/vmalloc.h> |
| @@ -26,6 +29,8 @@ · 1 unmodified line | ||
| 26 | 29 | #include <linux/kthread.h> |
| 27 | 30 | #include <linux/freezer.h> |
| 28 | 31 | #include <linux/ratelimit.h> |
| 32 | +#include <linux/string.h> | |
| 33 | +#include <linux/i2c.h> | |
| 29 | 34 | |
| 30 | 35 | #include <media/dvbdev.h> |
| 31 | 36 | #include <media/dvb_demux.h> |
| @@ -33,8 +38,9 @@ · 1 unmodified line | ||
| 33 | 38 | #include <media/dvb_net.h> |
| 34 | 39 | #include <media/dvb_frontend.h> |
| 35 | 40 | |
| 36 | −#include "va1j5jf8007t.h" | |
| 37 | −#include "va1j5jf8007s.h" | |
| 41 | +#include "tc90522.h" | |
| 42 | +#include "qm1d1b0004.h" | |
| 43 | +#include "dvb-pll.h" | |
| 38 | 44 | |
| 39 | 45 | #define DRIVER_NAME "earth-pt1" |
| 40 | 46 | |
| @@ -63,6 +69,11 @@ struct pt1_table { · 22 unmodified lines | ||
| 63 | 69 | struct pt1_buffer bufs[PT1_NR_BUFS]; |
| 64 | 70 | }; |
| 65 | 71 | |
| 72 | +enum pt1_fe_clk { | |
| 73 | + PT1_FE_CLK_20MHZ, /* PT1 */ | |
| 74 | + PT1_FE_CLK_25MHZ, /* PT2 */ | |
| 75 | +}; | |
| 76 | + | |
| 66 | 77 | #define PT1_NR_ADAPS 4 |
| 67 | 78 | |
| 68 | 79 | struct pt1_adapter; |
| @@ -81,6 +92,8 @@ struct pt1 { · 12 unmodified lines | ||
| 81 | 92 | struct mutex lock; |
| 82 | 93 | int power; |
| 83 | 94 | int reset; |
| 95 | + | |
| 96 | + enum pt1_fe_clk fe_clk; | |
| 84 | 97 | }; |
| 85 | 98 | |
| 86 | 99 | struct pt1_adapter { |
| @@ -97,6 +110,8 @@ struct pt1_adapter { · 10 unmodified lines | ||
| 97 | 110 | int users; |
| 98 | 111 | struct dmxdev dmxdev; |
| 99 | 112 | struct dvb_frontend *fe; |
| 113 | + struct i2c_client *demod_i2c_client; | |
| 114 | + struct i2c_client *tuner_i2c_client; | |
| 100 | 115 | int (*orig_set_voltage)(struct dvb_frontend *fe, |
| 101 | 116 | enum fe_sec_voltage voltage); |
| 102 | 117 | int (*orig_sleep)(struct dvb_frontend *fe); |
| @@ -106,6 +121,145 @@ struct pt1_adapter { · 3 unmodified lines | ||
| 106 | 121 | int sleep; |
| 107 | 122 | }; |
| 108 | 123 | |
| 124 | +union pt1_tuner_config { | |
| 125 | + struct qm1d1b0004_config qm1d1b0004; | |
| 126 | + struct dvb_pll_config tda6651; | |
| 127 | +}; | |
| 128 | + | |
| 129 | +struct pt1_config { | |
| 130 | + struct i2c_board_info demod_info; | |
| 131 | + struct tc90522_config demod_cfg; | |
| 132 | + | |
| 133 | + struct i2c_board_info tuner_info; | |
| 134 | + union pt1_tuner_config tuner_cfg; | |
| 135 | +}; | |
| 136 | + | |
| 137 | +static const struct pt1_config pt1_configs[PT1_NR_ADAPS] = { | |
| 138 | + { | |
| 139 | + .demod_info = { | |
| 140 | + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x1b), | |
| 141 | + }, | |
| 142 | + .tuner_info = { | |
| 143 | + I2C_BOARD_INFO("qm1d1b0004", 0x60), | |
| 144 | + }, | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + .demod_info = { | |
| 148 | + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x1a), | |
| 149 | + }, | |
| 150 | + .tuner_info = { | |
| 151 | + I2C_BOARD_INFO("tda665x_earthpt1", 0x61), | |
| 152 | + }, | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + .demod_info = { | |
| 156 | + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x19), | |
| 157 | + }, | |
| 158 | + .tuner_info = { | |
| 159 | + I2C_BOARD_INFO("qm1d1b0004", 0x60), | |
| 160 | + }, | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + .demod_info = { | |
| 164 | + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18), | |
| 165 | + }, | |
| 166 | + .tuner_info = { | |
| 167 | + I2C_BOARD_INFO("tda665x_earthpt1", 0x61), | |
| 168 | + }, | |
| 169 | + }, | |
| 170 | +}; | |
| 171 | + | |
| 172 | +static const u8 va1j5jf8007s_20mhz_configs[][2] = { | |
| 173 | + {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, | |
| 174 | + {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, | |
| 175 | + {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, | |
| 176 | + {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
| 177 | +}; | |
| 178 | + | |
| 179 | +static const u8 va1j5jf8007s_25mhz_configs[][2] = { | |
| 180 | + {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, | |
| 181 | + {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, | |
| 182 | + {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, | |
| 183 | + {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
| 184 | +}; | |
| 185 | + | |
| 186 | +static const u8 va1j5jf8007t_20mhz_configs[][2] = { | |
| 187 | + {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, | |
| 188 | + {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, | |
| 189 | + {0x3b, 0x11}, {0x3c, 0x3f}, | |
| 190 | + {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, | |
| 191 | + {0xef, 0x01} | |
| 192 | +}; | |
| 193 | + | |
| 194 | +static const u8 va1j5jf8007t_25mhz_configs[][2] = { | |
| 195 | + {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, | |
| 196 | + {0x3a, 0x04}, {0x3b, 0x11}, {0x3c, 0x3f}, {0x5c, 0x40}, {0x5f, 0x80}, | |
| 197 | + {0x75, 0x0a}, {0x76, 0x4c}, {0x77, 0x03}, {0xef, 0x01} | |
| 198 | +}; | |
| 199 | + | |
| 200 | +static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk) | |
| 201 | +{ | |
| 202 | + int ret; | |
| 203 | + u8 buf[2] = {0x01, 0x80}; | |
| 204 | + bool is_sat; | |
| 205 | + const u8 (*cfg_data)[2]; | |
| 206 | + int i, len; | |
| 207 | + | |
| 208 | + ret = i2c_master_send(cl, buf, 2); | |
| 209 | + if (ret < 0) | |
| 210 | + return ret; | |
| 211 | + usleep_range(30000, 50000); | |
| 212 | + | |
| 213 | + is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT, | |
| 214 | + strlen(TC90522_I2C_DEV_SAT)); | |
| 215 | + if (is_sat) { | |
| 216 | + struct i2c_msg msg[2]; | |
| 217 | + u8 wbuf, rbuf; | |
| 218 | + | |
| 219 | + wbuf = 0x07; | |
| 220 | + msg[0].addr = cl->addr; | |
| 221 | + msg[0].flags = 0; | |
| 222 | + msg[0].len = 1; | |
| 223 | + msg[0].buf = &wbuf; | |
| 224 | + | |
| 225 | + msg[1].addr = cl->addr; | |
| 226 | + msg[1].flags = I2C_M_RD; | |
| 227 | + msg[1].len = 1; | |
| 228 | + msg[1].buf = &rbuf; | |
| 229 | + ret = i2c_transfer(cl->adapter, msg, 2); | |
| 230 | + if (ret < 0) | |
| 231 | + return ret; | |
| 232 | + if (rbuf != 0x41) | |
| 233 | + return -EIO; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /* frontend init */ | |
| 237 | + if (clk == PT1_FE_CLK_20MHZ) { | |
| 238 | + if (is_sat) { | |
| 239 | + cfg_data = va1j5jf8007s_20mhz_configs; | |
| 240 | + len = ARRAY_SIZE(va1j5jf8007s_20mhz_configs); | |
| 241 | + } else { | |
| 242 | + cfg_data = va1j5jf8007t_20mhz_configs; | |
| 243 | + len = ARRAY_SIZE(va1j5jf8007t_20mhz_configs); | |
| 244 | + } | |
| 245 | + } else { | |
| 246 | + if (is_sat) { | |
| 247 | + cfg_data = va1j5jf8007s_25mhz_configs; | |
| 248 | + len = ARRAY_SIZE(va1j5jf8007s_25mhz_configs); | |
| 249 | + } else { | |
| 250 | + cfg_data = va1j5jf8007t_25mhz_configs; | |
| 251 | + len = ARRAY_SIZE(va1j5jf8007t_25mhz_configs); | |
| 252 | + } | |
| 253 | + } | |
| 254 | + | |
| 255 | + for (i = 0; i < len; i++) { | |
| 256 | + ret = i2c_master_send(cl, cfg_data[i], 2); | |
| 257 | + if (ret < 0) | |
| 258 | + return ret; | |
| 259 | + } | |
| 260 | + return 0; | |
| 261 | +} | |
| 262 | + | |
| 109 | 263 | static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) |
| 110 | 264 | { |
| 111 | 265 | writel(data, pt1->regs + reg * 4); |
| @@ -171,7 +325,7 @@ static int pt1_unlock(struct pt1 *pt1) · 59 unmodified lines | ||
| 171 | 325 | for (i = 0; i < 3; i++) { |
| 172 | 326 | if (pt1_read_reg(pt1, 0) & 0x80000000) |
| 173 | 327 | return 0; |
| 174 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 328 | + usleep_range(1000, 2000); | |
| 175 | 329 | } |
| 176 | 330 | dev_err(&pt1->pdev->dev, "could not unlock\n"); |
| 177 | 331 | return -EIO; |
| @@ -185,7 +339,7 @@ static int pt1_reset_pci(struct pt1 *pt1) · 7 unmodified lines | ||
| 185 | 339 | for (i = 0; i < 10; i++) { |
| 186 | 340 | if (pt1_read_reg(pt1, 0) & 0x00000001) |
| 187 | 341 | return 0; |
| 188 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 342 | + usleep_range(1000, 2000); | |
| 189 | 343 | } |
| 190 | 344 | dev_err(&pt1->pdev->dev, "could not reset PCI\n"); |
| 191 | 345 | return -EIO; |
| @@ -199,7 +353,7 @@ static int pt1_reset_ram(struct pt1 *pt1) · 7 unmodified lines | ||
| 199 | 353 | for (i = 0; i < 10; i++) { |
| 200 | 354 | if (pt1_read_reg(pt1, 0) & 0x00000002) |
| 201 | 355 | return 0; |
| 202 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 356 | + usleep_range(1000, 2000); | |
| 203 | 357 | } |
| 204 | 358 | dev_err(&pt1->pdev->dev, "could not reset RAM\n"); |
| 205 | 359 | return -EIO; |
| @@ -216,7 +370,7 @@ static int pt1_do_enable_ram(struct pt1 *pt1) · 10 unmodified lines | ||
| 216 | 370 | if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) |
| 217 | 371 | return 0; |
| 218 | 372 | } |
| 219 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 373 | + usleep_range(1000, 2000); | |
| 220 | 374 | } |
| 221 | 375 | dev_err(&pt1->pdev->dev, "could not enable RAM\n"); |
| 222 | 376 | return -EIO; |
| @@ -226,7 +380,7 @@ static int pt1_enable_ram(struct pt1 *pt1) · 3 unmodified lines | ||
| 226 | 380 | { |
| 227 | 381 | int i, ret; |
| 228 | 382 | int phase; |
| 229 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 383 | + usleep_range(1000, 2000); | |
| 230 | 384 | phase = pt1->pdev->device == 0x211a ? 128 : 166; |
| 231 | 385 | for (i = 0; i < phase; i++) { |
| 232 | 386 | ret = pt1_do_enable_ram(pt1); |
| @@ -311,16 +465,31 @@ static int pt1_thread(void *data) · 78 unmodified lines | ||
| 311 | 465 | { |
| 312 | 466 | struct pt1 *pt1; |
| 313 | 467 | struct pt1_buffer_page *page; |
| 468 | + bool was_frozen; | |
| 469 | + | |
| 470 | +#define PT1_FETCH_DELAY 10 | |
| 471 | +#define PT1_FETCH_DELAY_DELTA 2 | |
| 314 | 472 | |
| 315 | 473 | pt1 = data; |
| 316 | 474 | set_freezable(); |
| 317 | 475 | |
| 318 | − while (!kthread_should_stop()) { | |
| 319 | − try_to_freeze(); | |
| 476 | + while (!kthread_freezable_should_stop(&was_frozen)) { | |
| 477 | + if (was_frozen) { | |
| 478 | + int i; | |
| 479 | + | |
| 480 | + for (i = 0; i < PT1_NR_ADAPS; i++) | |
| 481 | + pt1_set_stream(pt1, i, !!pt1->adaps[i]->users); | |
| 482 | + } | |
| 320 | 483 | |
| 321 | 484 | page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; |
| 322 | 485 | if (!pt1_filter(pt1, page)) { |
| 323 | − schedule_timeout_interruptible((HZ + 999) / 1000); | |
| 486 | + ktime_t delay; | |
| 487 | + | |
| 488 | + delay = ktime_set(0, PT1_FETCH_DELAY * NSEC_PER_MSEC); | |
| 489 | + set_current_state(TASK_INTERRUPTIBLE); | |
| 490 | + schedule_hrtimeout_range(&delay, | |
| 491 | + PT1_FETCH_DELAY_DELTA * NSEC_PER_MSEC, | |
| 492 | + HRTIMER_MODE_REL); | |
| 324 | 493 | continue; |
| 325 | 494 | } |
| 326 | 495 | |
| @@ -556,7 +725,7 @@ pt1_update_power(struct pt1 *pt1) · 229 unmodified lines | ||
| 556 | 725 | adap = pt1->adaps[i]; |
| 557 | 726 | switch (adap->voltage) { |
| 558 | 727 | case SEC_VOLTAGE_13: /* actually 11V */ |
| 559 | − bits |= 1 << 1; | |
| 728 | + bits |= 1 << 2; | |
| 560 | 729 | break; |
| 561 | 730 | case SEC_VOLTAGE_18: /* actually 15V */ |
| 562 | 731 | bits |= 1 << 1 | 1 << 2; |
| @@ -589,30 +758,33 @@ static int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) · 26 unmodified lines | ||
| 589 | 758 | static int pt1_sleep(struct dvb_frontend *fe) |
| 590 | 759 | { |
| 591 | 760 | struct pt1_adapter *adap; |
| 761 | + int ret; | |
| 592 | 762 | |
| 593 | 763 | adap = container_of(fe->dvb, struct pt1_adapter, adap); |
| 594 | − adap->sleep = 1; | |
| 595 | − pt1_update_power(adap->pt1); | |
| 596 | 764 | |
| 765 | + ret = 0; | |
| 597 | 766 | if (adap->orig_sleep) |
| 598 | − return adap->orig_sleep(fe); | |
| 599 | − else | |
| 600 | − return 0; | |
| 767 | + ret = adap->orig_sleep(fe); | |
| 768 | + | |
| 769 | + adap->sleep = 1; | |
| 770 | + pt1_update_power(adap->pt1); | |
| 771 | + return ret; | |
| 601 | 772 | } |
| 602 | 773 | |
| 603 | 774 | static int pt1_wakeup(struct dvb_frontend *fe) |
| 604 | 775 | { |
| 605 | 776 | struct pt1_adapter *adap; |
| 777 | + int ret; | |
| 606 | 778 | |
| 607 | 779 | adap = container_of(fe->dvb, struct pt1_adapter, adap); |
| 608 | 780 | adap->sleep = 0; |
| 609 | 781 | pt1_update_power(adap->pt1); |
| 610 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 782 | + usleep_range(1000, 2000); | |
| 611 | 783 | |
| 612 | − if (adap->orig_init) | |
| 613 | − return adap->orig_init(fe); | |
| 614 | − else | |
| 615 | − return 0; | |
| 784 | + ret = config_demod(adap->demod_i2c_client, adap->pt1->fe_clk); | |
| 785 | + if (ret == 0 && adap->orig_init) | |
| 786 | + ret = adap->orig_init(fe); | |
| 787 | + return ret; | |
| 616 | 788 | } |
| 617 | 789 | |
| 618 | 790 | static void pt1_free_adapter(struct pt1_adapter *adap) |
| @@ -735,6 +907,8 @@ err: · 116 unmodified lines | ||
| 735 | 907 | static void pt1_cleanup_frontend(struct pt1_adapter *adap) |
| 736 | 908 | { |
| 737 | 909 | dvb_unregister_frontend(adap->fe); |
| 910 | + dvb_module_release(adap->tuner_i2c_client); | |
| 911 | + dvb_module_release(adap->demod_i2c_client); | |
| 738 | 912 | } |
| 739 | 913 | |
| 740 | 914 | static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) |
| @@ -763,112 +937,70 @@ static void pt1_cleanup_frontends(struct pt1 *pt1) · 22 unmodified lines | ||
| 763 | 937 | pt1_cleanup_frontend(pt1->adaps[i]); |
| 764 | 938 | } |
| 765 | 939 | |
| 766 | −struct pt1_config { | |
| 767 | − struct va1j5jf8007s_config va1j5jf8007s_config; | |
| 768 | − struct va1j5jf8007t_config va1j5jf8007t_config; | |
| 769 | −}; | |
| 770 | − | |
| 771 | −static const struct pt1_config pt1_configs[2] = { | |
| 772 | − { | |
| 773 | − { | |
| 774 | − .demod_address = 0x1b, | |
| 775 | − .frequency = VA1J5JF8007S_20MHZ, | |
| 776 | − }, | |
| 777 | − { | |
| 778 | − .demod_address = 0x1a, | |
| 779 | − .frequency = VA1J5JF8007T_20MHZ, | |
| 780 | − }, | |
| 781 | − }, { | |
| 782 | − { | |
| 783 | − .demod_address = 0x19, | |
| 784 | − .frequency = VA1J5JF8007S_20MHZ, | |
| 785 | − }, | |
| 786 | − { | |
| 787 | − .demod_address = 0x18, | |
| 788 | − .frequency = VA1J5JF8007T_20MHZ, | |
| 789 | − }, | |
| 790 | − }, | |
| 791 | −}; | |
| 792 | − | |
| 793 | −static const struct pt1_config pt2_configs[2] = { | |
| 794 | − { | |
| 795 | − { | |
| 796 | − .demod_address = 0x1b, | |
| 797 | − .frequency = VA1J5JF8007S_25MHZ, | |
| 798 | − }, | |
| 799 | − { | |
| 800 | − .demod_address = 0x1a, | |
| 801 | − .frequency = VA1J5JF8007T_25MHZ, | |
| 802 | − }, | |
| 803 | − }, { | |
| 804 | − { | |
| 805 | − .demod_address = 0x19, | |
| 806 | − .frequency = VA1J5JF8007S_25MHZ, | |
| 807 | − }, | |
| 808 | − { | |
| 809 | − .demod_address = 0x18, | |
| 810 | − .frequency = VA1J5JF8007T_25MHZ, | |
| 811 | − }, | |
| 812 | − }, | |
| 813 | −}; | |
| 814 | − | |
| 815 | 940 | static int pt1_init_frontends(struct pt1 *pt1) |
| 816 | 941 | { |
| 817 | − int i, j; | |
| 818 | − struct i2c_adapter *i2c_adap; | |
| 819 | − const struct pt1_config *configs, *config; | |
| 820 | − struct dvb_frontend *fe[4]; | |
| 942 | + int i; | |
| 821 | 943 | int ret; |
| 822 | 944 | |
| 823 | − i = 0; | |
| 824 | − j = 0; | |
| 825 | − | |
| 826 | − i2c_adap = &pt1->i2c_adap; | |
| 827 | − configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs; | |
| 828 | − do { | |
| 829 | − config = &configs[i / 2]; | |
| 830 | − | |
| 831 | − fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config, | |
| 832 | − i2c_adap); | |
| 833 | − if (!fe[i]) { | |
| 834 | − ret = -ENODEV; /* This does not sound nice... */ | |
| 835 | − goto err; | |
| 836 | − } | |
| 837 | − i++; | |
| 838 | − | |
| 839 | − fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config, | |
| 840 | − i2c_adap); | |
| 841 | − if (!fe[i]) { | |
| 842 | − ret = -ENODEV; | |
| 843 | − goto err; | |
| 945 | + for (i = 0; i < ARRAY_SIZE(pt1_configs); i++) { | |
| 946 | + const struct i2c_board_info *info; | |
| 947 | + struct tc90522_config dcfg; | |
| 948 | + struct i2c_client *cl; | |
| 949 | + | |
| 950 | + info = &pt1_configs[i].demod_info; | |
| 951 | + dcfg = pt1_configs[i].demod_cfg; | |
| 952 | + dcfg.tuner_i2c = NULL; | |
| 953 | + | |
| 954 | + ret = -ENODEV; | |
| 955 | + cl = dvb_module_probe("tc90522", info->type, &pt1->i2c_adap, | |
| 956 | + info->addr, &dcfg); | |
| 957 | + if (!cl) | |
| 958 | + goto fe_unregister; | |
| 959 | + pt1->adaps[i]->demod_i2c_client = cl; | |
| 960 | + | |
| 961 | + if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, | |
| 962 | + strlen(TC90522_I2C_DEV_SAT))) { | |
| 963 | + struct qm1d1b0004_config tcfg; | |
| 964 | + | |
| 965 | + info = &pt1_configs[i].tuner_info; | |
| 966 | + tcfg = pt1_configs[i].tuner_cfg.qm1d1b0004; | |
| 967 | + tcfg.fe = dcfg.fe; | |
| 968 | + cl = dvb_module_probe("qm1d1b0004", | |
| 969 | + info->type, dcfg.tuner_i2c, | |
| 970 | + info->addr, &tcfg); | |
| 971 | + } else { | |
| 972 | + struct dvb_pll_config tcfg; | |
| 973 | + | |
| 974 | + info = &pt1_configs[i].tuner_info; | |
| 975 | + tcfg = pt1_configs[i].tuner_cfg.tda6651; | |
| 976 | + tcfg.fe = dcfg.fe; | |
| 977 | + cl = dvb_module_probe("dvb_pll", | |
| 978 | + info->type, dcfg.tuner_i2c, | |
| 979 | + info->addr, &tcfg); | |
| 844 | 980 | } |
| 845 | − i++; | |
| 846 | − | |
| 847 | − ret = va1j5jf8007s_prepare(fe[i - 2]); | |
| 848 | − if (ret < 0) | |
| 849 | − goto err; | |
| 981 | + if (!cl) | |
| 982 | + goto demod_release; | |
| 983 | + pt1->adaps[i]->tuner_i2c_client = cl; | |
| 850 | 984 | |
| 851 | − ret = va1j5jf8007t_prepare(fe[i - 1]); | |
| 852 | − if (ret < 0) | |
| 853 | − goto err; | |
| 854 | − | |
| 855 | − } while (i < 4); | |
| 856 | − | |
| 857 | − do { | |
| 858 | − ret = pt1_init_frontend(pt1->adaps[j], fe[j]); | |
| 985 | + ret = pt1_init_frontend(pt1->adaps[i], dcfg.fe); | |
| 859 | 986 | if (ret < 0) |
| 860 | − goto err; | |
| 861 | − } while (++j < 4); | |
| 987 | + goto tuner_release; | |
| 988 | + } | |
| 862 | 989 | |
| 863 | 990 | return 0; |
| 864 | 991 | |
| 865 | −err: | |
| 866 | − while (i-- > j) | |
| 867 | − fe[i]->ops.release(fe[i]); | |
| 868 | − | |
| 869 | − while (j--) | |
| 870 | − dvb_unregister_frontend(fe[j]); | |
| 871 | − | |
| 992 | +tuner_release: | |
| 993 | + dvb_module_release(pt1->adaps[i]->tuner_i2c_client); | |
| 994 | +demod_release: | |
| 995 | + dvb_module_release(pt1->adaps[i]->demod_i2c_client); | |
| 996 | +fe_unregister: | |
| 997 | + dev_warn(&pt1->pdev->dev, "failed to init FE(%d).\n", i); | |
| 998 | + i--; | |
| 999 | + for (; i >= 0; i--) { | |
| 1000 | + dvb_unregister_frontend(pt1->adaps[i]->fe); | |
| 1001 | + dvb_module_release(pt1->adaps[i]->tuner_i2c_client); | |
| 1002 | + dvb_module_release(pt1->adaps[i]->demod_i2c_client); | |
| 1003 | + } | |
| 872 | 1004 | return ret; |
| 873 | 1005 | } |
| 874 | 1006 | |
| @@ -954,7 +1086,7 @@ static int pt1_i2c_end(struct pt1 *pt1, int addr) · 79 unmodified lines | ||
| 954 | 1086 | do { |
| 955 | 1087 | if (signal_pending(current)) |
| 956 | 1088 | return -EINTR; |
| 957 | − schedule_timeout_interruptible((HZ + 999) / 1000); | |
| 1089 | + usleep_range(1000, 2000); | |
| 958 | 1090 | } while (pt1_read_reg(pt1, 0) & 0x00000080); |
| 959 | 1091 | return 0; |
| 960 | 1092 | } |
| @@ -1052,6 +1184,98 @@ static void pt1_i2c_init(struct pt1 *pt1) · 91 unmodified lines | ||
| 1052 | 1184 | pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); |
| 1053 | 1185 | } |
| 1054 | 1186 | |
| 1187 | +#ifdef CONFIG_PM_SLEEP | |
| 1188 | + | |
| 1189 | +static int pt1_suspend(struct device *dev) | |
| 1190 | +{ | |
| 1191 | + struct pci_dev *pdev = to_pci_dev(dev); | |
| 1192 | + struct pt1 *pt1 = pci_get_drvdata(pdev); | |
| 1193 | + | |
| 1194 | + pt1_init_streams(pt1); | |
| 1195 | + pt1_disable_ram(pt1); | |
| 1196 | + pt1->power = 0; | |
| 1197 | + pt1->reset = 1; | |
| 1198 | + pt1_update_power(pt1); | |
| 1199 | + return 0; | |
| 1200 | +} | |
| 1201 | + | |
| 1202 | +static int pt1_resume(struct device *dev) | |
| 1203 | +{ | |
| 1204 | + struct pci_dev *pdev = to_pci_dev(dev); | |
| 1205 | + struct pt1 *pt1 = pci_get_drvdata(pdev); | |
| 1206 | + int ret; | |
| 1207 | + int i; | |
| 1208 | + | |
| 1209 | + pt1->power = 0; | |
| 1210 | + pt1->reset = 1; | |
| 1211 | + pt1_update_power(pt1); | |
| 1212 | + | |
| 1213 | + pt1_i2c_init(pt1); | |
| 1214 | + pt1_i2c_wait(pt1); | |
| 1215 | + | |
| 1216 | + ret = pt1_sync(pt1); | |
| 1217 | + if (ret < 0) | |
| 1218 | + goto resume_err; | |
| 1219 | + | |
| 1220 | + pt1_identify(pt1); | |
| 1221 | + | |
| 1222 | + ret = pt1_unlock(pt1); | |
| 1223 | + if (ret < 0) | |
| 1224 | + goto resume_err; | |
| 1225 | + | |
| 1226 | + ret = pt1_reset_pci(pt1); | |
| 1227 | + if (ret < 0) | |
| 1228 | + goto resume_err; | |
| 1229 | + | |
| 1230 | + ret = pt1_reset_ram(pt1); | |
| 1231 | + if (ret < 0) | |
| 1232 | + goto resume_err; | |
| 1233 | + | |
| 1234 | + ret = pt1_enable_ram(pt1); | |
| 1235 | + if (ret < 0) | |
| 1236 | + goto resume_err; | |
| 1237 | + | |
| 1238 | + pt1_init_streams(pt1); | |
| 1239 | + | |
| 1240 | + pt1->power = 1; | |
| 1241 | + pt1_update_power(pt1); | |
| 1242 | + msleep(20); | |
| 1243 | + | |
| 1244 | + pt1->reset = 0; | |
| 1245 | + pt1_update_power(pt1); | |
| 1246 | + usleep_range(1000, 2000); | |
| 1247 | + | |
| 1248 | + for (i = 0; i < PT1_NR_ADAPS; i++) | |
| 1249 | + dvb_frontend_reinitialise(pt1->adaps[i]->fe); | |
| 1250 | + | |
| 1251 | + pt1_init_table_count(pt1); | |
| 1252 | + for (i = 0; i < pt1_nr_tables; i++) { | |
| 1253 | + int j; | |
| 1254 | + | |
| 1255 | + for (j = 0; j < PT1_NR_BUFS; j++) | |
| 1256 | + pt1->tables[i].bufs[j].page->upackets[PT1_NR_UPACKETS-1] | |
| 1257 | + = 0; | |
| 1258 | + pt1_increment_table_count(pt1); | |
| 1259 | + } | |
| 1260 | + pt1_register_tables(pt1, pt1->tables[0].addr >> PT1_PAGE_SHIFT); | |
| 1261 | + | |
| 1262 | + pt1->table_index = 0; | |
| 1263 | + pt1->buf_index = 0; | |
| 1264 | + for (i = 0; i < PT1_NR_ADAPS; i++) { | |
| 1265 | + pt1->adaps[i]->upacket_count = 0; | |
| 1266 | + pt1->adaps[i]->packet_count = 0; | |
| 1267 | + pt1->adaps[i]->st_count = -1; | |
| 1268 | + } | |
| 1269 | + | |
| 1270 | + return 0; | |
| 1271 | + | |
| 1272 | +resume_err: | |
| 1273 | + dev_info(&pt1->pdev->dev, "failed to resume PT1/PT2."); | |
| 1274 | + return 0; /* resume anyway */ | |
| 1275 | +} | |
| 1276 | + | |
| 1277 | +#endif /* CONFIG_PM_SLEEP */ | |
| 1278 | + | |
| 1055 | 1279 | static void pt1_remove(struct pci_dev *pdev) |
| 1056 | 1280 | { |
| 1057 | 1281 | struct pt1 *pt1; |
| @@ -1112,6 +1336,8 @@ static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 54 unmodified lines | ||
| 1112 | 1336 | mutex_init(&pt1->lock); |
| 1113 | 1337 | pt1->pdev = pdev; |
| 1114 | 1338 | pt1->regs = regs; |
| 1339 | + pt1->fe_clk = (pdev->device == 0x211a) ? | |
| 1340 | + PT1_FE_CLK_20MHZ : PT1_FE_CLK_25MHZ; | |
| 1115 | 1341 | pci_set_drvdata(pdev, pt1); |
| 1116 | 1342 | |
| 1117 | 1343 | ret = pt1_init_adapters(pt1); |
| @@ -1163,11 +1389,11 @@ static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 45 unmodified lines | ||
| 1163 | 1389 | |
| 1164 | 1390 | pt1->power = 1; |
| 1165 | 1391 | pt1_update_power(pt1); |
| 1166 | − schedule_timeout_uninterruptible((HZ + 49) / 50); | |
| 1392 | + msleep(20); | |
| 1167 | 1393 | |
| 1168 | 1394 | pt1->reset = 0; |
| 1169 | 1395 | pt1_update_power(pt1); |
| 1170 | − schedule_timeout_uninterruptible((HZ + 999) / 1000); | |
| 1396 | + usleep_range(1000, 2000); | |
| 1171 | 1397 | |
| 1172 | 1398 | ret = pt1_init_frontends(pt1); |
| 1173 | 1399 | if (ret < 0) |
| @@ -1210,11 +1436,16 @@ static const struct pci_device_id pt1_id_table[] = { · 36 unmodified lines | ||
| 1210 | 1436 | }; |
| 1211 | 1437 | MODULE_DEVICE_TABLE(pci, pt1_id_table); |
| 1212 | 1438 | |
| 1439 | +static SIMPLE_DEV_PM_OPS(pt1_pm_ops, pt1_suspend, pt1_resume); | |
| 1440 | + | |
| 1213 | 1441 | static struct pci_driver pt1_driver = { |
| 1214 | 1442 | .name = DRIVER_NAME, |
| 1215 | 1443 | .probe = pt1_probe, |
| 1216 | 1444 | .remove = pt1_remove, |
| 1217 | 1445 | .id_table = pt1_id_table, |
| 1446 | +#ifdef CONFIG_PM_SLEEP | |
| 1447 | + .driver.pm = &pt1_pm_ops, | |
| 1448 | +#endif | |
| 1218 | 1449 | }; |
| 1219 | 1450 | |
| 1220 | 1451 | module_pci_driver(pt1_driver); |
| @@ -1,732 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 | |
| 3 | − * | |
| 4 | − * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | |
| 5 | − * | |
| 6 | − * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | |
| 7 | − * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | |
| 8 | − * | |
| 9 | − * This program is free software; you can redistribute it and/or modify | |
| 10 | − * it under the terms of the GNU General Public License as published by | |
| 11 | − * the Free Software Foundation; either version 2 of the License, or | |
| 12 | − * (at your option) any later version. | |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, | |
| 15 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − * GNU General Public License for more details. | |
| 18 | − */ | |
| 19 | − | |
| 20 | −#include <linux/kernel.h> | |
| 21 | −#include <linux/module.h> | |
| 22 | −#include <linux/slab.h> | |
| 23 | −#include <linux/i2c.h> | |
| 24 | −#include <media/dvb_frontend.h> | |
| 25 | −#include "va1j5jf8007s.h" | |
| 26 | − | |
| 27 | −enum va1j5jf8007s_tune_state { | |
| 28 | − VA1J5JF8007S_IDLE, | |
| 29 | − VA1J5JF8007S_SET_FREQUENCY_1, | |
| 30 | − VA1J5JF8007S_SET_FREQUENCY_2, | |
| 31 | − VA1J5JF8007S_SET_FREQUENCY_3, | |
| 32 | − VA1J5JF8007S_CHECK_FREQUENCY, | |
| 33 | − VA1J5JF8007S_SET_MODULATION, | |
| 34 | − VA1J5JF8007S_CHECK_MODULATION, | |
| 35 | − VA1J5JF8007S_SET_TS_ID, | |
| 36 | − VA1J5JF8007S_CHECK_TS_ID, | |
| 37 | − VA1J5JF8007S_TRACK, | |
| 38 | −}; | |
| 39 | − | |
| 40 | −struct va1j5jf8007s_state { | |
| 41 | − const struct va1j5jf8007s_config *config; | |
| 42 | − struct i2c_adapter *adap; | |
| 43 | − struct dvb_frontend fe; | |
| 44 | − enum va1j5jf8007s_tune_state tune_state; | |
| 45 | −}; | |
| 46 | − | |
| 47 | −static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr) | |
| 48 | −{ | |
| 49 | − struct va1j5jf8007s_state *state; | |
| 50 | − u8 addr; | |
| 51 | − int i; | |
| 52 | − u8 write_buf[1], read_buf[1]; | |
| 53 | − struct i2c_msg msgs[2]; | |
| 54 | − s32 word, x1, x2, x3, x4, x5, y; | |
| 55 | − | |
| 56 | − state = fe->demodulator_priv; | |
| 57 | − addr = state->config->demod_address; | |
| 58 | − | |
| 59 | − word = 0; | |
| 60 | − for (i = 0; i < 2; i++) { | |
| 61 | − write_buf[0] = 0xbc + i; | |
| 62 | − | |
| 63 | − msgs[0].addr = addr; | |
| 64 | − msgs[0].flags = 0; | |
| 65 | − msgs[0].len = sizeof(write_buf); | |
| 66 | − msgs[0].buf = write_buf; | |
| 67 | − | |
| 68 | − msgs[1].addr = addr; | |
| 69 | − msgs[1].flags = I2C_M_RD; | |
| 70 | − msgs[1].len = sizeof(read_buf); | |
| 71 | − msgs[1].buf = read_buf; | |
| 72 | − | |
| 73 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 74 | − return -EREMOTEIO; | |
| 75 | − | |
| 76 | − word <<= 8; | |
| 77 | − word |= read_buf[0]; | |
| 78 | − } | |
| 79 | − | |
| 80 | − word -= 3000; | |
| 81 | − if (word < 0) | |
| 82 | − word = 0; | |
| 83 | − | |
| 84 | − x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000); | |
| 85 | − x2 = (s64)x1 * x1 >> 31; | |
| 86 | − x3 = (s64)x2 * x1 >> 31; | |
| 87 | − x4 = (s64)x2 * x2 >> 31; | |
| 88 | − x5 = (s64)x4 * x1 >> 31; | |
| 89 | − | |
| 90 | − y = (58857ll << 23) / 1000; | |
| 91 | − y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30; | |
| 92 | − y += (s64)x2 * ((88977ll << 24) / 1000) >> 28; | |
| 93 | − y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27; | |
| 94 | − y += (s64)x4 * ((14341ll << 27) / 1000) >> 27; | |
| 95 | − y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28; | |
| 96 | − | |
| 97 | − *snr = y < 0 ? 0 : y >> 15; | |
| 98 | − return 0; | |
| 99 | −} | |
| 100 | − | |
| 101 | −static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) | |
| 102 | −{ | |
| 103 | − return DVBFE_ALGO_HW; | |
| 104 | −} | |
| 105 | − | |
| 106 | −static int | |
| 107 | −va1j5jf8007s_read_status(struct dvb_frontend *fe, enum fe_status *status) | |
| 108 | −{ | |
| 109 | − struct va1j5jf8007s_state *state; | |
| 110 | − | |
| 111 | − state = fe->demodulator_priv; | |
| 112 | − | |
| 113 | − switch (state->tune_state) { | |
| 114 | − case VA1J5JF8007S_IDLE: | |
| 115 | − case VA1J5JF8007S_SET_FREQUENCY_1: | |
| 116 | − case VA1J5JF8007S_SET_FREQUENCY_2: | |
| 117 | − case VA1J5JF8007S_SET_FREQUENCY_3: | |
| 118 | − case VA1J5JF8007S_CHECK_FREQUENCY: | |
| 119 | − *status = 0; | |
| 120 | − return 0; | |
| 121 | − | |
| 122 | − | |
| 123 | − case VA1J5JF8007S_SET_MODULATION: | |
| 124 | − case VA1J5JF8007S_CHECK_MODULATION: | |
| 125 | − *status |= FE_HAS_SIGNAL; | |
| 126 | − return 0; | |
| 127 | − | |
| 128 | − case VA1J5JF8007S_SET_TS_ID: | |
| 129 | − case VA1J5JF8007S_CHECK_TS_ID: | |
| 130 | − *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
| 131 | − return 0; | |
| 132 | − | |
| 133 | − case VA1J5JF8007S_TRACK: | |
| 134 | − *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | |
| 135 | − return 0; | |
| 136 | − } | |
| 137 | − | |
| 138 | − BUG(); | |
| 139 | −} | |
| 140 | − | |
| 141 | −struct va1j5jf8007s_cb_map { | |
| 142 | − u32 frequency; | |
| 143 | − u8 cb; | |
| 144 | −}; | |
| 145 | − | |
| 146 | −static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = { | |
| 147 | − { 986000, 0xb2 }, | |
| 148 | − { 1072000, 0xd2 }, | |
| 149 | − { 1154000, 0xe2 }, | |
| 150 | − { 1291000, 0x20 }, | |
| 151 | − { 1447000, 0x40 }, | |
| 152 | − { 1615000, 0x60 }, | |
| 153 | − { 1791000, 0x80 }, | |
| 154 | − { 1972000, 0xa0 }, | |
| 155 | −}; | |
| 156 | − | |
| 157 | −static u8 va1j5jf8007s_lookup_cb(u32 frequency) | |
| 158 | −{ | |
| 159 | − int i; | |
| 160 | − const struct va1j5jf8007s_cb_map *map; | |
| 161 | − | |
| 162 | − for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) { | |
| 163 | − map = &va1j5jf8007s_cb_maps[i]; | |
| 164 | − if (frequency < map->frequency) | |
| 165 | − return map->cb; | |
| 166 | − } | |
| 167 | − return 0xc0; | |
| 168 | −} | |
| 169 | − | |
| 170 | −static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state) | |
| 171 | −{ | |
| 172 | − u32 frequency; | |
| 173 | − u16 word; | |
| 174 | − u8 buf[6]; | |
| 175 | − struct i2c_msg msg; | |
| 176 | − | |
| 177 | − frequency = state->fe.dtv_property_cache.frequency; | |
| 178 | − | |
| 179 | − word = (frequency + 500) / 1000; | |
| 180 | − if (frequency < 1072000) | |
| 181 | − word = (word << 1 & ~0x1f) | (word & 0x0f); | |
| 182 | − | |
| 183 | − buf[0] = 0xfe; | |
| 184 | − buf[1] = 0xc0; | |
| 185 | − buf[2] = 0x40 | word >> 8; | |
| 186 | − buf[3] = word; | |
| 187 | − buf[4] = 0xe0; | |
| 188 | − buf[5] = va1j5jf8007s_lookup_cb(frequency); | |
| 189 | − | |
| 190 | − msg.addr = state->config->demod_address; | |
| 191 | − msg.flags = 0; | |
| 192 | − msg.len = sizeof(buf); | |
| 193 | − msg.buf = buf; | |
| 194 | − | |
| 195 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 196 | − return -EREMOTEIO; | |
| 197 | − | |
| 198 | − return 0; | |
| 199 | −} | |
| 200 | − | |
| 201 | −static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state) | |
| 202 | −{ | |
| 203 | − u8 buf[3]; | |
| 204 | − struct i2c_msg msg; | |
| 205 | − | |
| 206 | − buf[0] = 0xfe; | |
| 207 | − buf[1] = 0xc0; | |
| 208 | − buf[2] = 0xe4; | |
| 209 | − | |
| 210 | − msg.addr = state->config->demod_address; | |
| 211 | − msg.flags = 0; | |
| 212 | − msg.len = sizeof(buf); | |
| 213 | − msg.buf = buf; | |
| 214 | − | |
| 215 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 216 | − return -EREMOTEIO; | |
| 217 | − | |
| 218 | − return 0; | |
| 219 | −} | |
| 220 | − | |
| 221 | −static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state) | |
| 222 | −{ | |
| 223 | − u32 frequency; | |
| 224 | − u8 buf[4]; | |
| 225 | − struct i2c_msg msg; | |
| 226 | − | |
| 227 | − frequency = state->fe.dtv_property_cache.frequency; | |
| 228 | − | |
| 229 | − buf[0] = 0xfe; | |
| 230 | − buf[1] = 0xc0; | |
| 231 | − buf[2] = 0xf4; | |
| 232 | − buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4; | |
| 233 | − | |
| 234 | − msg.addr = state->config->demod_address; | |
| 235 | − msg.flags = 0; | |
| 236 | − msg.len = sizeof(buf); | |
| 237 | − msg.buf = buf; | |
| 238 | − | |
| 239 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 240 | − return -EREMOTEIO; | |
| 241 | − | |
| 242 | − return 0; | |
| 243 | −} | |
| 244 | − | |
| 245 | −static int | |
| 246 | −va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock) | |
| 247 | −{ | |
| 248 | − u8 addr; | |
| 249 | − u8 write_buf[2], read_buf[1]; | |
| 250 | − struct i2c_msg msgs[2]; | |
| 251 | − | |
| 252 | − addr = state->config->demod_address; | |
| 253 | − | |
| 254 | − write_buf[0] = 0xfe; | |
| 255 | − write_buf[1] = 0xc1; | |
| 256 | − | |
| 257 | − msgs[0].addr = addr; | |
| 258 | − msgs[0].flags = 0; | |
| 259 | − msgs[0].len = sizeof(write_buf); | |
| 260 | − msgs[0].buf = write_buf; | |
| 261 | − | |
| 262 | − msgs[1].addr = addr; | |
| 263 | − msgs[1].flags = I2C_M_RD; | |
| 264 | − msgs[1].len = sizeof(read_buf); | |
| 265 | − msgs[1].buf = read_buf; | |
| 266 | − | |
| 267 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 268 | − return -EREMOTEIO; | |
| 269 | − | |
| 270 | − *lock = read_buf[0] & 0x40; | |
| 271 | − return 0; | |
| 272 | −} | |
| 273 | − | |
| 274 | −static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state) | |
| 275 | −{ | |
| 276 | − u8 buf[2]; | |
| 277 | − struct i2c_msg msg; | |
| 278 | − | |
| 279 | − buf[0] = 0x03; | |
| 280 | − buf[1] = 0x01; | |
| 281 | − | |
| 282 | − msg.addr = state->config->demod_address; | |
| 283 | − msg.flags = 0; | |
| 284 | − msg.len = sizeof(buf); | |
| 285 | − msg.buf = buf; | |
| 286 | − | |
| 287 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 288 | − return -EREMOTEIO; | |
| 289 | − | |
| 290 | − return 0; | |
| 291 | −} | |
| 292 | − | |
| 293 | −static int | |
| 294 | −va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock) | |
| 295 | −{ | |
| 296 | − u8 addr; | |
| 297 | − u8 write_buf[1], read_buf[1]; | |
| 298 | − struct i2c_msg msgs[2]; | |
| 299 | − | |
| 300 | − addr = state->config->demod_address; | |
| 301 | − | |
| 302 | − write_buf[0] = 0xc3; | |
| 303 | − | |
| 304 | − msgs[0].addr = addr; | |
| 305 | − msgs[0].flags = 0; | |
| 306 | − msgs[0].len = sizeof(write_buf); | |
| 307 | − msgs[0].buf = write_buf; | |
| 308 | − | |
| 309 | − msgs[1].addr = addr; | |
| 310 | − msgs[1].flags = I2C_M_RD; | |
| 311 | − msgs[1].len = sizeof(read_buf); | |
| 312 | − msgs[1].buf = read_buf; | |
| 313 | − | |
| 314 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 315 | − return -EREMOTEIO; | |
| 316 | − | |
| 317 | − *lock = !(read_buf[0] & 0x10); | |
| 318 | − return 0; | |
| 319 | −} | |
| 320 | − | |
| 321 | −static int | |
| 322 | −va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state) | |
| 323 | −{ | |
| 324 | − u32 ts_id; | |
| 325 | − u8 buf[3]; | |
| 326 | − struct i2c_msg msg; | |
| 327 | − | |
| 328 | − ts_id = state->fe.dtv_property_cache.stream_id; | |
| 329 | − if (!ts_id || ts_id == NO_STREAM_ID_FILTER) | |
| 330 | − return 0; | |
| 331 | − | |
| 332 | − buf[0] = 0x8f; | |
| 333 | − buf[1] = ts_id >> 8; | |
| 334 | − buf[2] = ts_id; | |
| 335 | − | |
| 336 | − msg.addr = state->config->demod_address; | |
| 337 | − msg.flags = 0; | |
| 338 | − msg.len = sizeof(buf); | |
| 339 | − msg.buf = buf; | |
| 340 | − | |
| 341 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 342 | − return -EREMOTEIO; | |
| 343 | − | |
| 344 | − return 0; | |
| 345 | −} | |
| 346 | − | |
| 347 | −static int | |
| 348 | −va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) | |
| 349 | −{ | |
| 350 | − u8 addr; | |
| 351 | − u8 write_buf[1], read_buf[2]; | |
| 352 | − struct i2c_msg msgs[2]; | |
| 353 | − u32 ts_id; | |
| 354 | − | |
| 355 | − ts_id = state->fe.dtv_property_cache.stream_id; | |
| 356 | − if (!ts_id || ts_id == NO_STREAM_ID_FILTER) { | |
| 357 | − *lock = 1; | |
| 358 | − return 0; | |
| 359 | − } | |
| 360 | − | |
| 361 | − addr = state->config->demod_address; | |
| 362 | − | |
| 363 | − write_buf[0] = 0xe6; | |
| 364 | − | |
| 365 | − msgs[0].addr = addr; | |
| 366 | − msgs[0].flags = 0; | |
| 367 | − msgs[0].len = sizeof(write_buf); | |
| 368 | − msgs[0].buf = write_buf; | |
| 369 | − | |
| 370 | − msgs[1].addr = addr; | |
| 371 | − msgs[1].flags = I2C_M_RD; | |
| 372 | − msgs[1].len = sizeof(read_buf); | |
| 373 | − msgs[1].buf = read_buf; | |
| 374 | − | |
| 375 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 376 | − return -EREMOTEIO; | |
| 377 | − | |
| 378 | − *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id; | |
| 379 | − return 0; | |
| 380 | −} | |
| 381 | − | |
| 382 | −static int | |
| 383 | −va1j5jf8007s_tune(struct dvb_frontend *fe, | |
| 384 | − bool re_tune, | |
| 385 | − unsigned int mode_flags, unsigned int *delay, | |
| 386 | − enum fe_status *status) | |
| 387 | −{ | |
| 388 | − struct va1j5jf8007s_state *state; | |
| 389 | − int ret; | |
| 390 | − int lock = 0; | |
| 391 | − | |
| 392 | − state = fe->demodulator_priv; | |
| 393 | − | |
| 394 | − if (re_tune) | |
| 395 | − state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; | |
| 396 | − | |
| 397 | − switch (state->tune_state) { | |
| 398 | − case VA1J5JF8007S_IDLE: | |
| 399 | − *delay = 3 * HZ; | |
| 400 | − *status = 0; | |
| 401 | − return 0; | |
| 402 | − | |
| 403 | − case VA1J5JF8007S_SET_FREQUENCY_1: | |
| 404 | − ret = va1j5jf8007s_set_frequency_1(state); | |
| 405 | − if (ret < 0) | |
| 406 | − return ret; | |
| 407 | − | |
| 408 | − state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2; | |
| 409 | − *delay = 0; | |
| 410 | − *status = 0; | |
| 411 | − return 0; | |
| 412 | − | |
| 413 | − case VA1J5JF8007S_SET_FREQUENCY_2: | |
| 414 | − ret = va1j5jf8007s_set_frequency_2(state); | |
| 415 | − if (ret < 0) | |
| 416 | − return ret; | |
| 417 | − | |
| 418 | − state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3; | |
| 419 | − *delay = (HZ + 99) / 100; | |
| 420 | − *status = 0; | |
| 421 | − return 0; | |
| 422 | − | |
| 423 | − case VA1J5JF8007S_SET_FREQUENCY_3: | |
| 424 | − ret = va1j5jf8007s_set_frequency_3(state); | |
| 425 | − if (ret < 0) | |
| 426 | − return ret; | |
| 427 | − | |
| 428 | − state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY; | |
| 429 | − *delay = 0; | |
| 430 | − *status = 0; | |
| 431 | − return 0; | |
| 432 | − | |
| 433 | − case VA1J5JF8007S_CHECK_FREQUENCY: | |
| 434 | − ret = va1j5jf8007s_check_frequency(state, &lock); | |
| 435 | − if (ret < 0) | |
| 436 | − return ret; | |
| 437 | − | |
| 438 | − if (!lock) { | |
| 439 | − *delay = (HZ + 999) / 1000; | |
| 440 | − *status = 0; | |
| 441 | − return 0; | |
| 442 | − } | |
| 443 | − | |
| 444 | − state->tune_state = VA1J5JF8007S_SET_MODULATION; | |
| 445 | − *delay = 0; | |
| 446 | − *status = FE_HAS_SIGNAL; | |
| 447 | − return 0; | |
| 448 | − | |
| 449 | − case VA1J5JF8007S_SET_MODULATION: | |
| 450 | − ret = va1j5jf8007s_set_modulation(state); | |
| 451 | − if (ret < 0) | |
| 452 | − return ret; | |
| 453 | − | |
| 454 | − state->tune_state = VA1J5JF8007S_CHECK_MODULATION; | |
| 455 | − *delay = 0; | |
| 456 | − *status = FE_HAS_SIGNAL; | |
| 457 | − return 0; | |
| 458 | − | |
| 459 | − case VA1J5JF8007S_CHECK_MODULATION: | |
| 460 | − ret = va1j5jf8007s_check_modulation(state, &lock); | |
| 461 | − if (ret < 0) | |
| 462 | − return ret; | |
| 463 | − | |
| 464 | − if (!lock) { | |
| 465 | − *delay = (HZ + 49) / 50; | |
| 466 | − *status = FE_HAS_SIGNAL; | |
| 467 | − return 0; | |
| 468 | − } | |
| 469 | − | |
| 470 | − state->tune_state = VA1J5JF8007S_SET_TS_ID; | |
| 471 | − *delay = 0; | |
| 472 | − *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
| 473 | − return 0; | |
| 474 | − | |
| 475 | − case VA1J5JF8007S_SET_TS_ID: | |
| 476 | − ret = va1j5jf8007s_set_ts_id(state); | |
| 477 | − if (ret < 0) | |
| 478 | − return ret; | |
| 479 | − | |
| 480 | − state->tune_state = VA1J5JF8007S_CHECK_TS_ID; | |
| 481 | − return 0; | |
| 482 | − | |
| 483 | − case VA1J5JF8007S_CHECK_TS_ID: | |
| 484 | − ret = va1j5jf8007s_check_ts_id(state, &lock); | |
| 485 | − if (ret < 0) | |
| 486 | − return ret; | |
| 487 | − | |
| 488 | − if (!lock) { | |
| 489 | − *delay = (HZ + 99) / 100; | |
| 490 | − *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
| 491 | − return 0; | |
| 492 | − } | |
| 493 | − | |
| 494 | − state->tune_state = VA1J5JF8007S_TRACK; | |
| 495 | − /* fall through */ | |
| 496 | − | |
| 497 | − case VA1J5JF8007S_TRACK: | |
| 498 | − *delay = 3 * HZ; | |
| 499 | − *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | |
| 500 | − return 0; | |
| 501 | − } | |
| 502 | − | |
| 503 | − BUG(); | |
| 504 | −} | |
| 505 | − | |
| 506 | −static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state) | |
| 507 | −{ | |
| 508 | − u8 buf[4]; | |
| 509 | − struct i2c_msg msg; | |
| 510 | − | |
| 511 | − buf[0] = 0xfe; | |
| 512 | − buf[1] = 0xc0; | |
| 513 | − buf[2] = 0xf0; | |
| 514 | − buf[3] = 0x04; | |
| 515 | − | |
| 516 | − msg.addr = state->config->demod_address; | |
| 517 | − msg.flags = 0; | |
| 518 | − msg.len = sizeof(buf); | |
| 519 | − msg.buf = buf; | |
| 520 | − | |
| 521 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 522 | − return -EREMOTEIO; | |
| 523 | − | |
| 524 | − return 0; | |
| 525 | −} | |
| 526 | − | |
| 527 | −static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep) | |
| 528 | −{ | |
| 529 | − u8 buf[2]; | |
| 530 | − struct i2c_msg msg; | |
| 531 | − | |
| 532 | − buf[0] = 0x17; | |
| 533 | − buf[1] = sleep ? 0x01 : 0x00; | |
| 534 | − | |
| 535 | − msg.addr = state->config->demod_address; | |
| 536 | − msg.flags = 0; | |
| 537 | − msg.len = sizeof(buf); | |
| 538 | − msg.buf = buf; | |
| 539 | − | |
| 540 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 541 | − return -EREMOTEIO; | |
| 542 | − | |
| 543 | − return 0; | |
| 544 | −} | |
| 545 | − | |
| 546 | −static int va1j5jf8007s_sleep(struct dvb_frontend *fe) | |
| 547 | −{ | |
| 548 | − struct va1j5jf8007s_state *state; | |
| 549 | − int ret; | |
| 550 | − | |
| 551 | − state = fe->demodulator_priv; | |
| 552 | − | |
| 553 | − ret = va1j5jf8007s_init_frequency(state); | |
| 554 | − if (ret < 0) | |
| 555 | − return ret; | |
| 556 | − | |
| 557 | − return va1j5jf8007s_set_sleep(state, 1); | |
| 558 | −} | |
| 559 | − | |
| 560 | −static int va1j5jf8007s_init(struct dvb_frontend *fe) | |
| 561 | −{ | |
| 562 | − struct va1j5jf8007s_state *state; | |
| 563 | − | |
| 564 | − state = fe->demodulator_priv; | |
| 565 | − state->tune_state = VA1J5JF8007S_IDLE; | |
| 566 | − | |
| 567 | − return va1j5jf8007s_set_sleep(state, 0); | |
| 568 | −} | |
| 569 | − | |
| 570 | −static void va1j5jf8007s_release(struct dvb_frontend *fe) | |
| 571 | −{ | |
| 572 | − struct va1j5jf8007s_state *state; | |
| 573 | − state = fe->demodulator_priv; | |
| 574 | − kfree(state); | |
| 575 | −} | |
| 576 | − | |
| 577 | −static const struct dvb_frontend_ops va1j5jf8007s_ops = { | |
| 578 | − .delsys = { SYS_ISDBS }, | |
| 579 | − .info = { | |
| 580 | − .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", | |
| 581 | − .frequency_min = 950000, | |
| 582 | − .frequency_max = 2150000, | |
| 583 | − .frequency_stepsize = 1000, | |
| 584 | − .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | |
| 585 | − FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | |
| 586 | − FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | | |
| 587 | − FE_CAN_MULTISTREAM, | |
| 588 | − }, | |
| 589 | − | |
| 590 | − .read_snr = va1j5jf8007s_read_snr, | |
| 591 | − .get_frontend_algo = va1j5jf8007s_get_frontend_algo, | |
| 592 | − .read_status = va1j5jf8007s_read_status, | |
| 593 | − .tune = va1j5jf8007s_tune, | |
| 594 | − .sleep = va1j5jf8007s_sleep, | |
| 595 | − .init = va1j5jf8007s_init, | |
| 596 | − .release = va1j5jf8007s_release, | |
| 597 | −}; | |
| 598 | − | |
| 599 | −static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) | |
| 600 | −{ | |
| 601 | − u8 addr; | |
| 602 | − u8 write_buf[1], read_buf[1]; | |
| 603 | − struct i2c_msg msgs[2]; | |
| 604 | − | |
| 605 | − addr = state->config->demod_address; | |
| 606 | − | |
| 607 | − write_buf[0] = 0x07; | |
| 608 | − | |
| 609 | − msgs[0].addr = addr; | |
| 610 | − msgs[0].flags = 0; | |
| 611 | − msgs[0].len = sizeof(write_buf); | |
| 612 | − msgs[0].buf = write_buf; | |
| 613 | − | |
| 614 | − msgs[1].addr = addr; | |
| 615 | − msgs[1].flags = I2C_M_RD; | |
| 616 | − msgs[1].len = sizeof(read_buf); | |
| 617 | − msgs[1].buf = read_buf; | |
| 618 | − | |
| 619 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 620 | − return -EREMOTEIO; | |
| 621 | − | |
| 622 | − if (read_buf[0] != 0x41) | |
| 623 | − return -EIO; | |
| 624 | − | |
| 625 | − return 0; | |
| 626 | −} | |
| 627 | − | |
| 628 | −static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = { | |
| 629 | − {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, | |
| 630 | − {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, | |
| 631 | − {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, | |
| 632 | − {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
| 633 | −}; | |
| 634 | − | |
| 635 | −static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = { | |
| 636 | − {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, | |
| 637 | − {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, | |
| 638 | − {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, | |
| 639 | − {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
| 640 | −}; | |
| 641 | − | |
| 642 | −static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) | |
| 643 | −{ | |
| 644 | − const u8 (*bufs)[2]; | |
| 645 | − int size; | |
| 646 | − u8 addr; | |
| 647 | − u8 buf[2]; | |
| 648 | − struct i2c_msg msg; | |
| 649 | − int i; | |
| 650 | − | |
| 651 | − switch (state->config->frequency) { | |
| 652 | − case VA1J5JF8007S_20MHZ: | |
| 653 | − bufs = va1j5jf8007s_20mhz_prepare_bufs; | |
| 654 | − size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs); | |
| 655 | − break; | |
| 656 | − case VA1J5JF8007S_25MHZ: | |
| 657 | − bufs = va1j5jf8007s_25mhz_prepare_bufs; | |
| 658 | − size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs); | |
| 659 | − break; | |
| 660 | − default: | |
| 661 | − return -EINVAL; | |
| 662 | − } | |
| 663 | − | |
| 664 | − addr = state->config->demod_address; | |
| 665 | − | |
| 666 | − msg.addr = addr; | |
| 667 | − msg.flags = 0; | |
| 668 | − msg.len = 2; | |
| 669 | − msg.buf = buf; | |
| 670 | − for (i = 0; i < size; i++) { | |
| 671 | − memcpy(buf, bufs[i], sizeof(buf)); | |
| 672 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 673 | − return -EREMOTEIO; | |
| 674 | − } | |
| 675 | − | |
| 676 | − return 0; | |
| 677 | −} | |
| 678 | − | |
| 679 | −/* must be called after va1j5jf8007t_attach */ | |
| 680 | −int va1j5jf8007s_prepare(struct dvb_frontend *fe) | |
| 681 | −{ | |
| 682 | − struct va1j5jf8007s_state *state; | |
| 683 | − int ret; | |
| 684 | − | |
| 685 | − state = fe->demodulator_priv; | |
| 686 | − | |
| 687 | − ret = va1j5jf8007s_prepare_1(state); | |
| 688 | − if (ret < 0) | |
| 689 | − return ret; | |
| 690 | − | |
| 691 | − ret = va1j5jf8007s_prepare_2(state); | |
| 692 | − if (ret < 0) | |
| 693 | − return ret; | |
| 694 | − | |
| 695 | − return va1j5jf8007s_init_frequency(state); | |
| 696 | −} | |
| 697 | − | |
| 698 | −struct dvb_frontend * | |
| 699 | −va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, | |
| 700 | − struct i2c_adapter *adap) | |
| 701 | −{ | |
| 702 | − struct va1j5jf8007s_state *state; | |
| 703 | − struct dvb_frontend *fe; | |
| 704 | − u8 buf[2]; | |
| 705 | − struct i2c_msg msg; | |
| 706 | − | |
| 707 | − state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL); | |
| 708 | − if (!state) | |
| 709 | − return NULL; | |
| 710 | − | |
| 711 | − state->config = config; | |
| 712 | − state->adap = adap; | |
| 713 | − | |
| 714 | − fe = &state->fe; | |
| 715 | − memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops)); | |
| 716 | − fe->demodulator_priv = state; | |
| 717 | − | |
| 718 | − buf[0] = 0x01; | |
| 719 | − buf[1] = 0x80; | |
| 720 | − | |
| 721 | − msg.addr = state->config->demod_address; | |
| 722 | − msg.flags = 0; | |
| 723 | − msg.len = sizeof(buf); | |
| 724 | − msg.buf = buf; | |
| 725 | − | |
| 726 | − if (i2c_transfer(state->adap, &msg, 1) != 1) { | |
| 727 | − kfree(state); | |
| 728 | − return NULL; | |
| 729 | − } | |
| 730 | − | |
| 731 | − return fe; | |
| 732 | −} | |
| @@ -1,42 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 | |
| 3 | − * | |
| 4 | − * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | |
| 5 | − * | |
| 6 | − * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | |
| 7 | − * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | |
| 8 | − * | |
| 9 | − * This program is free software; you can redistribute it and/or modify | |
| 10 | − * it under the terms of the GNU General Public License as published by | |
| 11 | − * the Free Software Foundation; either version 2 of the License, or | |
| 12 | − * (at your option) any later version. | |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, | |
| 15 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − * GNU General Public License for more details. | |
| 18 | − */ | |
| 19 | − | |
| 20 | −#ifndef VA1J5JF8007S_H | |
| 21 | −#define VA1J5JF8007S_H | |
| 22 | − | |
| 23 | −enum va1j5jf8007s_frequency { | |
| 24 | − VA1J5JF8007S_20MHZ, | |
| 25 | − VA1J5JF8007S_25MHZ, | |
| 26 | −}; | |
| 27 | − | |
| 28 | −struct va1j5jf8007s_config { | |
| 29 | − u8 demod_address; | |
| 30 | − enum va1j5jf8007s_frequency frequency; | |
| 31 | −}; | |
| 32 | − | |
| 33 | −struct i2c_adapter; | |
| 34 | − | |
| 35 | −struct dvb_frontend * | |
| 36 | −va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, | |
| 37 | − struct i2c_adapter *adap); | |
| 38 | − | |
| 39 | −/* must be called after va1j5jf8007t_attach */ | |
| 40 | −int va1j5jf8007s_prepare(struct dvb_frontend *fe); | |
| 41 | − | |
| 42 | −#endif | |
| @@ -1,532 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 | |
| 3 | − * | |
| 4 | − * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | |
| 5 | − * | |
| 6 | − * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | |
| 7 | − * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | |
| 8 | − * | |
| 9 | − * This program is free software; you can redistribute it and/or modify | |
| 10 | − * it under the terms of the GNU General Public License as published by | |
| 11 | − * the Free Software Foundation; either version 2 of the License, or | |
| 12 | − * (at your option) any later version. | |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, | |
| 15 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − * GNU General Public License for more details. | |
| 18 | − */ | |
| 19 | − | |
| 20 | −#include <linux/kernel.h> | |
| 21 | −#include <linux/module.h> | |
| 22 | −#include <linux/slab.h> | |
| 23 | −#include <linux/i2c.h> | |
| 24 | −#include <media/dvb_frontend.h> | |
| 25 | −#include <media/dvb_math.h> | |
| 26 | −#include "va1j5jf8007t.h" | |
| 27 | − | |
| 28 | −enum va1j5jf8007t_tune_state { | |
| 29 | − VA1J5JF8007T_IDLE, | |
| 30 | − VA1J5JF8007T_SET_FREQUENCY, | |
| 31 | − VA1J5JF8007T_CHECK_FREQUENCY, | |
| 32 | − VA1J5JF8007T_SET_MODULATION, | |
| 33 | − VA1J5JF8007T_CHECK_MODULATION, | |
| 34 | − VA1J5JF8007T_TRACK, | |
| 35 | − VA1J5JF8007T_ABORT, | |
| 36 | −}; | |
| 37 | − | |
| 38 | −struct va1j5jf8007t_state { | |
| 39 | − const struct va1j5jf8007t_config *config; | |
| 40 | − struct i2c_adapter *adap; | |
| 41 | − struct dvb_frontend fe; | |
| 42 | − enum va1j5jf8007t_tune_state tune_state; | |
| 43 | −}; | |
| 44 | − | |
| 45 | −static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr) | |
| 46 | −{ | |
| 47 | − struct va1j5jf8007t_state *state; | |
| 48 | − u8 addr; | |
| 49 | − int i; | |
| 50 | − u8 write_buf[1], read_buf[1]; | |
| 51 | − struct i2c_msg msgs[2]; | |
| 52 | − s32 word, x, y; | |
| 53 | − | |
| 54 | − state = fe->demodulator_priv; | |
| 55 | − addr = state->config->demod_address; | |
| 56 | − | |
| 57 | − word = 0; | |
| 58 | − for (i = 0; i < 3; i++) { | |
| 59 | − write_buf[0] = 0x8b + i; | |
| 60 | − | |
| 61 | − msgs[0].addr = addr; | |
| 62 | − msgs[0].flags = 0; | |
| 63 | − msgs[0].len = sizeof(write_buf); | |
| 64 | − msgs[0].buf = write_buf; | |
| 65 | − | |
| 66 | − msgs[1].addr = addr; | |
| 67 | − msgs[1].flags = I2C_M_RD; | |
| 68 | − msgs[1].len = sizeof(read_buf); | |
| 69 | − msgs[1].buf = read_buf; | |
| 70 | − | |
| 71 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 72 | − return -EREMOTEIO; | |
| 73 | − | |
| 74 | − word <<= 8; | |
| 75 | − word |= read_buf[0]; | |
| 76 | − } | |
| 77 | − | |
| 78 | − if (!word) | |
| 79 | − return -EIO; | |
| 80 | − | |
| 81 | − x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24)); | |
| 82 | − y = (24ll << 46) / 1000000; | |
| 83 | − y = ((s64)y * x >> 30) - (16ll << 40) / 10000; | |
| 84 | − y = ((s64)y * x >> 29) + (398ll << 35) / 10000; | |
| 85 | − y = ((s64)y * x >> 30) + (5491ll << 29) / 10000; | |
| 86 | − y = ((s64)y * x >> 30) + (30965ll << 23) / 10000; | |
| 87 | − *snr = y >> 15; | |
| 88 | − return 0; | |
| 89 | −} | |
| 90 | − | |
| 91 | −static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) | |
| 92 | −{ | |
| 93 | − return DVBFE_ALGO_HW; | |
| 94 | −} | |
| 95 | − | |
| 96 | −static int | |
| 97 | −va1j5jf8007t_read_status(struct dvb_frontend *fe, enum fe_status *status) | |
| 98 | −{ | |
| 99 | − struct va1j5jf8007t_state *state; | |
| 100 | − | |
| 101 | − state = fe->demodulator_priv; | |
| 102 | − | |
| 103 | − switch (state->tune_state) { | |
| 104 | − case VA1J5JF8007T_IDLE: | |
| 105 | − case VA1J5JF8007T_SET_FREQUENCY: | |
| 106 | − case VA1J5JF8007T_CHECK_FREQUENCY: | |
| 107 | − *status = 0; | |
| 108 | − return 0; | |
| 109 | − | |
| 110 | − | |
| 111 | − case VA1J5JF8007T_SET_MODULATION: | |
| 112 | − case VA1J5JF8007T_CHECK_MODULATION: | |
| 113 | − case VA1J5JF8007T_ABORT: | |
| 114 | − *status |= FE_HAS_SIGNAL; | |
| 115 | − return 0; | |
| 116 | − | |
| 117 | − case VA1J5JF8007T_TRACK: | |
| 118 | − *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | |
| 119 | − return 0; | |
| 120 | − } | |
| 121 | − | |
| 122 | − BUG(); | |
| 123 | −} | |
| 124 | − | |
| 125 | −struct va1j5jf8007t_cb_map { | |
| 126 | − u32 frequency; | |
| 127 | − u8 cb; | |
| 128 | −}; | |
| 129 | − | |
| 130 | −static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = { | |
| 131 | − { 90000000, 0x80 }, | |
| 132 | − { 140000000, 0x81 }, | |
| 133 | − { 170000000, 0xa1 }, | |
| 134 | − { 220000000, 0x62 }, | |
| 135 | − { 330000000, 0xa2 }, | |
| 136 | − { 402000000, 0xe2 }, | |
| 137 | − { 450000000, 0x64 }, | |
| 138 | − { 550000000, 0x84 }, | |
| 139 | − { 600000000, 0xa4 }, | |
| 140 | − { 700000000, 0xc4 }, | |
| 141 | −}; | |
| 142 | − | |
| 143 | −static u8 va1j5jf8007t_lookup_cb(u32 frequency) | |
| 144 | −{ | |
| 145 | − int i; | |
| 146 | − const struct va1j5jf8007t_cb_map *map; | |
| 147 | − | |
| 148 | − for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) { | |
| 149 | − map = &va1j5jf8007t_cb_maps[i]; | |
| 150 | − if (frequency < map->frequency) | |
| 151 | − return map->cb; | |
| 152 | − } | |
| 153 | − return 0xe4; | |
| 154 | −} | |
| 155 | − | |
| 156 | −static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state) | |
| 157 | −{ | |
| 158 | − u32 frequency; | |
| 159 | − u16 word; | |
| 160 | − u8 buf[6]; | |
| 161 | − struct i2c_msg msg; | |
| 162 | − | |
| 163 | − frequency = state->fe.dtv_property_cache.frequency; | |
| 164 | − | |
| 165 | − word = (frequency + 71428) / 142857 + 399; | |
| 166 | − buf[0] = 0xfe; | |
| 167 | − buf[1] = 0xc2; | |
| 168 | − buf[2] = word >> 8; | |
| 169 | − buf[3] = word; | |
| 170 | − buf[4] = 0x80; | |
| 171 | − buf[5] = va1j5jf8007t_lookup_cb(frequency); | |
| 172 | − | |
| 173 | − msg.addr = state->config->demod_address; | |
| 174 | − msg.flags = 0; | |
| 175 | − msg.len = sizeof(buf); | |
| 176 | − msg.buf = buf; | |
| 177 | − | |
| 178 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 179 | − return -EREMOTEIO; | |
| 180 | − | |
| 181 | − return 0; | |
| 182 | −} | |
| 183 | − | |
| 184 | −static int | |
| 185 | −va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock) | |
| 186 | −{ | |
| 187 | − u8 addr; | |
| 188 | − u8 write_buf[2], read_buf[1]; | |
| 189 | − struct i2c_msg msgs[2]; | |
| 190 | − | |
| 191 | − addr = state->config->demod_address; | |
| 192 | − | |
| 193 | − write_buf[0] = 0xfe; | |
| 194 | − write_buf[1] = 0xc3; | |
| 195 | − | |
| 196 | − msgs[0].addr = addr; | |
| 197 | − msgs[0].flags = 0; | |
| 198 | − msgs[0].len = sizeof(write_buf); | |
| 199 | − msgs[0].buf = write_buf; | |
| 200 | − | |
| 201 | − msgs[1].addr = addr; | |
| 202 | − msgs[1].flags = I2C_M_RD; | |
| 203 | − msgs[1].len = sizeof(read_buf); | |
| 204 | − msgs[1].buf = read_buf; | |
| 205 | − | |
| 206 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 207 | − return -EREMOTEIO; | |
| 208 | − | |
| 209 | − *lock = read_buf[0] & 0x40; | |
| 210 | − return 0; | |
| 211 | −} | |
| 212 | − | |
| 213 | −static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state) | |
| 214 | −{ | |
| 215 | − u8 buf[2]; | |
| 216 | − struct i2c_msg msg; | |
| 217 | − | |
| 218 | − buf[0] = 0x01; | |
| 219 | − buf[1] = 0x40; | |
| 220 | − | |
| 221 | − msg.addr = state->config->demod_address; | |
| 222 | − msg.flags = 0; | |
| 223 | − msg.len = sizeof(buf); | |
| 224 | − msg.buf = buf; | |
| 225 | − | |
| 226 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 227 | − return -EREMOTEIO; | |
| 228 | − | |
| 229 | − return 0; | |
| 230 | −} | |
| 231 | − | |
| 232 | −static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, | |
| 233 | − int *lock, int *retry) | |
| 234 | −{ | |
| 235 | − u8 addr; | |
| 236 | − u8 write_buf[1], read_buf[1]; | |
| 237 | − struct i2c_msg msgs[2]; | |
| 238 | − | |
| 239 | − addr = state->config->demod_address; | |
| 240 | − | |
| 241 | − write_buf[0] = 0x80; | |
| 242 | − | |
| 243 | − msgs[0].addr = addr; | |
| 244 | − msgs[0].flags = 0; | |
| 245 | − msgs[0].len = sizeof(write_buf); | |
| 246 | − msgs[0].buf = write_buf; | |
| 247 | − | |
| 248 | − msgs[1].addr = addr; | |
| 249 | − msgs[1].flags = I2C_M_RD; | |
| 250 | − msgs[1].len = sizeof(read_buf); | |
| 251 | − msgs[1].buf = read_buf; | |
| 252 | − | |
| 253 | − if (i2c_transfer(state->adap, msgs, 2) != 2) | |
| 254 | − return -EREMOTEIO; | |
| 255 | − | |
| 256 | − *lock = !(read_buf[0] & 0x10); | |
| 257 | − *retry = read_buf[0] & 0x80; | |
| 258 | − return 0; | |
| 259 | −} | |
| 260 | − | |
| 261 | −static int | |
| 262 | −va1j5jf8007t_tune(struct dvb_frontend *fe, | |
| 263 | − bool re_tune, | |
| 264 | − unsigned int mode_flags, unsigned int *delay, | |
| 265 | − enum fe_status *status) | |
| 266 | −{ | |
| 267 | − struct va1j5jf8007t_state *state; | |
| 268 | − int ret; | |
| 269 | − int lock = 0, retry = 0; | |
| 270 | − | |
| 271 | − state = fe->demodulator_priv; | |
| 272 | − | |
| 273 | − if (re_tune) | |
| 274 | − state->tune_state = VA1J5JF8007T_SET_FREQUENCY; | |
| 275 | − | |
| 276 | − switch (state->tune_state) { | |
| 277 | − case VA1J5JF8007T_IDLE: | |
| 278 | − *delay = 3 * HZ; | |
| 279 | − *status = 0; | |
| 280 | − return 0; | |
| 281 | − | |
| 282 | − case VA1J5JF8007T_SET_FREQUENCY: | |
| 283 | − ret = va1j5jf8007t_set_frequency(state); | |
| 284 | − if (ret < 0) | |
| 285 | − return ret; | |
| 286 | − | |
| 287 | − state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY; | |
| 288 | − *delay = 0; | |
| 289 | − *status = 0; | |
| 290 | − return 0; | |
| 291 | − | |
| 292 | − case VA1J5JF8007T_CHECK_FREQUENCY: | |
| 293 | − ret = va1j5jf8007t_check_frequency(state, &lock); | |
| 294 | − if (ret < 0) | |
| 295 | − return ret; | |
| 296 | − | |
| 297 | − if (!lock) { | |
| 298 | − *delay = (HZ + 999) / 1000; | |
| 299 | − *status = 0; | |
| 300 | − return 0; | |
| 301 | − } | |
| 302 | − | |
| 303 | − state->tune_state = VA1J5JF8007T_SET_MODULATION; | |
| 304 | − *delay = 0; | |
| 305 | − *status = FE_HAS_SIGNAL; | |
| 306 | − return 0; | |
| 307 | − | |
| 308 | − case VA1J5JF8007T_SET_MODULATION: | |
| 309 | − ret = va1j5jf8007t_set_modulation(state); | |
| 310 | − if (ret < 0) | |
| 311 | − return ret; | |
| 312 | − | |
| 313 | − state->tune_state = VA1J5JF8007T_CHECK_MODULATION; | |
| 314 | − *delay = 0; | |
| 315 | − *status = FE_HAS_SIGNAL; | |
| 316 | − return 0; | |
| 317 | − | |
| 318 | − case VA1J5JF8007T_CHECK_MODULATION: | |
| 319 | − ret = va1j5jf8007t_check_modulation(state, &lock, &retry); | |
| 320 | − if (ret < 0) | |
| 321 | − return ret; | |
| 322 | − | |
| 323 | − if (!lock) { | |
| 324 | − if (!retry) { | |
| 325 | − state->tune_state = VA1J5JF8007T_ABORT; | |
| 326 | − *delay = 3 * HZ; | |
| 327 | − *status = FE_HAS_SIGNAL; | |
| 328 | − return 0; | |
| 329 | − } | |
| 330 | − *delay = (HZ + 999) / 1000; | |
| 331 | − *status = FE_HAS_SIGNAL; | |
| 332 | − return 0; | |
| 333 | − } | |
| 334 | − | |
| 335 | − state->tune_state = VA1J5JF8007T_TRACK; | |
| 336 | − /* fall through */ | |
| 337 | − | |
| 338 | − case VA1J5JF8007T_TRACK: | |
| 339 | − *delay = 3 * HZ; | |
| 340 | − *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | |
| 341 | − return 0; | |
| 342 | − | |
| 343 | − case VA1J5JF8007T_ABORT: | |
| 344 | − *delay = 3 * HZ; | |
| 345 | − *status = FE_HAS_SIGNAL; | |
| 346 | − return 0; | |
| 347 | − } | |
| 348 | − | |
| 349 | − BUG(); | |
| 350 | −} | |
| 351 | − | |
| 352 | −static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state) | |
| 353 | −{ | |
| 354 | − u8 buf[7]; | |
| 355 | − struct i2c_msg msg; | |
| 356 | − | |
| 357 | − buf[0] = 0xfe; | |
| 358 | − buf[1] = 0xc2; | |
| 359 | − buf[2] = 0x01; | |
| 360 | − buf[3] = 0x8f; | |
| 361 | − buf[4] = 0xc1; | |
| 362 | − buf[5] = 0x80; | |
| 363 | − buf[6] = 0x80; | |
| 364 | − | |
| 365 | − msg.addr = state->config->demod_address; | |
| 366 | − msg.flags = 0; | |
| 367 | − msg.len = sizeof(buf); | |
| 368 | − msg.buf = buf; | |
| 369 | − | |
| 370 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 371 | − return -EREMOTEIO; | |
| 372 | − | |
| 373 | − return 0; | |
| 374 | −} | |
| 375 | − | |
| 376 | −static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep) | |
| 377 | −{ | |
| 378 | − u8 buf[2]; | |
| 379 | − struct i2c_msg msg; | |
| 380 | − | |
| 381 | − buf[0] = 0x03; | |
| 382 | − buf[1] = sleep ? 0x90 : 0x80; | |
| 383 | − | |
| 384 | − msg.addr = state->config->demod_address; | |
| 385 | − msg.flags = 0; | |
| 386 | − msg.len = sizeof(buf); | |
| 387 | − msg.buf = buf; | |
| 388 | − | |
| 389 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 390 | − return -EREMOTEIO; | |
| 391 | − | |
| 392 | − return 0; | |
| 393 | −} | |
| 394 | − | |
| 395 | −static int va1j5jf8007t_sleep(struct dvb_frontend *fe) | |
| 396 | −{ | |
| 397 | − struct va1j5jf8007t_state *state; | |
| 398 | − int ret; | |
| 399 | − | |
| 400 | − state = fe->demodulator_priv; | |
| 401 | − | |
| 402 | − ret = va1j5jf8007t_init_frequency(state); | |
| 403 | − if (ret < 0) | |
| 404 | − return ret; | |
| 405 | − | |
| 406 | − return va1j5jf8007t_set_sleep(state, 1); | |
| 407 | −} | |
| 408 | − | |
| 409 | −static int va1j5jf8007t_init(struct dvb_frontend *fe) | |
| 410 | −{ | |
| 411 | − struct va1j5jf8007t_state *state; | |
| 412 | − | |
| 413 | − state = fe->demodulator_priv; | |
| 414 | − state->tune_state = VA1J5JF8007T_IDLE; | |
| 415 | − | |
| 416 | − return va1j5jf8007t_set_sleep(state, 0); | |
| 417 | −} | |
| 418 | − | |
| 419 | −static void va1j5jf8007t_release(struct dvb_frontend *fe) | |
| 420 | −{ | |
| 421 | − struct va1j5jf8007t_state *state; | |
| 422 | − state = fe->demodulator_priv; | |
| 423 | − kfree(state); | |
| 424 | −} | |
| 425 | − | |
| 426 | −static const struct dvb_frontend_ops va1j5jf8007t_ops = { | |
| 427 | − .delsys = { SYS_ISDBT }, | |
| 428 | − .info = { | |
| 429 | − .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", | |
| 430 | − .frequency_min = 90000000, | |
| 431 | − .frequency_max = 770000000, | |
| 432 | − .frequency_stepsize = 142857, | |
| 433 | − .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | |
| 434 | − FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | |
| 435 | − FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, | |
| 436 | − }, | |
| 437 | − | |
| 438 | − .read_snr = va1j5jf8007t_read_snr, | |
| 439 | − .get_frontend_algo = va1j5jf8007t_get_frontend_algo, | |
| 440 | − .read_status = va1j5jf8007t_read_status, | |
| 441 | − .tune = va1j5jf8007t_tune, | |
| 442 | − .sleep = va1j5jf8007t_sleep, | |
| 443 | − .init = va1j5jf8007t_init, | |
| 444 | − .release = va1j5jf8007t_release, | |
| 445 | −}; | |
| 446 | − | |
| 447 | −static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = { | |
| 448 | − {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, | |
| 449 | − {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, | |
| 450 | − {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, | |
| 451 | − {0xef, 0x01} | |
| 452 | −}; | |
| 453 | − | |
| 454 | −static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = { | |
| 455 | − {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, | |
| 456 | − {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c}, | |
| 457 | − {0x77, 0x03}, {0xef, 0x01} | |
| 458 | −}; | |
| 459 | − | |
| 460 | −int va1j5jf8007t_prepare(struct dvb_frontend *fe) | |
| 461 | −{ | |
| 462 | − struct va1j5jf8007t_state *state; | |
| 463 | − const u8 (*bufs)[2]; | |
| 464 | − int size; | |
| 465 | − u8 buf[2]; | |
| 466 | − struct i2c_msg msg; | |
| 467 | − int i; | |
| 468 | − | |
| 469 | − state = fe->demodulator_priv; | |
| 470 | − | |
| 471 | − switch (state->config->frequency) { | |
| 472 | − case VA1J5JF8007T_20MHZ: | |
| 473 | − bufs = va1j5jf8007t_20mhz_prepare_bufs; | |
| 474 | − size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs); | |
| 475 | − break; | |
| 476 | − case VA1J5JF8007T_25MHZ: | |
| 477 | − bufs = va1j5jf8007t_25mhz_prepare_bufs; | |
| 478 | − size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs); | |
| 479 | − break; | |
| 480 | − default: | |
| 481 | − return -EINVAL; | |
| 482 | − } | |
| 483 | − | |
| 484 | − msg.addr = state->config->demod_address; | |
| 485 | − msg.flags = 0; | |
| 486 | − msg.len = sizeof(buf); | |
| 487 | − msg.buf = buf; | |
| 488 | − | |
| 489 | − for (i = 0; i < size; i++) { | |
| 490 | − memcpy(buf, bufs[i], sizeof(buf)); | |
| 491 | − if (i2c_transfer(state->adap, &msg, 1) != 1) | |
| 492 | − return -EREMOTEIO; | |
| 493 | − } | |
| 494 | − | |
| 495 | − return va1j5jf8007t_init_frequency(state); | |
| 496 | −} | |
| 497 | − | |
| 498 | −struct dvb_frontend * | |
| 499 | −va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, | |
| 500 | − struct i2c_adapter *adap) | |
| 501 | −{ | |
| 502 | − struct va1j5jf8007t_state *state; | |
| 503 | − struct dvb_frontend *fe; | |
| 504 | − u8 buf[2]; | |
| 505 | − struct i2c_msg msg; | |
| 506 | − | |
| 507 | − state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL); | |
| 508 | − if (!state) | |
| 509 | − return NULL; | |
| 510 | − | |
| 511 | − state->config = config; | |
| 512 | − state->adap = adap; | |
| 513 | − | |
| 514 | − fe = &state->fe; | |
| 515 | − memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops)); | |
| 516 | − fe->demodulator_priv = state; | |
| 517 | − | |
| 518 | − buf[0] = 0x01; | |
| 519 | − buf[1] = 0x80; | |
| 520 | − | |
| 521 | − msg.addr = state->config->demod_address; | |
| 522 | − msg.flags = 0; | |
| 523 | − msg.len = sizeof(buf); | |
| 524 | − msg.buf = buf; | |
| 525 | − | |
| 526 | − if (i2c_transfer(state->adap, &msg, 1) != 1) { | |
| 527 | − kfree(state); | |
| 528 | − return NULL; | |
| 529 | − } | |
| 530 | − | |
| 531 | − return fe; | |
| 532 | −} | |
| @@ -1,42 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 | |
| 3 | − * | |
| 4 | − * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | |
| 5 | − * | |
| 6 | − * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | |
| 7 | − * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | |
| 8 | − * | |
| 9 | − * This program is free software; you can redistribute it and/or modify | |
| 10 | − * it under the terms of the GNU General Public License as published by | |
| 11 | − * the Free Software Foundation; either version 2 of the License, or | |
| 12 | − * (at your option) any later version. | |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, | |
| 15 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − * GNU General Public License for more details. | |
| 18 | − */ | |
| 19 | − | |
| 20 | −#ifndef VA1J5JF8007T_H | |
| 21 | −#define VA1J5JF8007T_H | |
| 22 | − | |
| 23 | −enum va1j5jf8007t_frequency { | |
| 24 | − VA1J5JF8007T_20MHZ, | |
| 25 | − VA1J5JF8007T_25MHZ, | |
| 26 | −}; | |
| 27 | − | |
| 28 | −struct va1j5jf8007t_config { | |
| 29 | − u8 demod_address; | |
| 30 | − enum va1j5jf8007t_frequency frequency; | |
| 31 | −}; | |
| 32 | − | |
| 33 | −struct i2c_adapter; | |
| 34 | − | |
| 35 | −struct dvb_frontend * | |
| 36 | −va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, | |
| 37 | − struct i2c_adapter *adap); | |
| 38 | − | |
| 39 | −/* must be called after va1j5jf8007s_attach */ | |
| 40 | −int va1j5jf8007t_prepare(struct dvb_frontend *fe); | |
| 41 | − | |
| 42 | −#endif | |
| @@ -1,17 +1,8 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * Earthsoft PT3 driver |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | |
| 17 | 8 | #include <linux/freezer.h> |
| @@ -376,25 +367,22 @@ static int pt3_fe_init(struct pt3_board *pt3) · 358 unmodified lines | ||
| 376 | 367 | |
| 377 | 368 | static int pt3_attach_fe(struct pt3_board *pt3, int i) |
| 378 | 369 | { |
| 379 | − struct i2c_board_info info; | |
| 370 | + const struct i2c_board_info *info; | |
| 380 | 371 | struct tc90522_config cfg; |
| 381 | 372 | struct i2c_client *cl; |
| 382 | 373 | struct dvb_adapter *dvb_adap; |
| 383 | 374 | int ret; |
| 384 | 375 | |
| 385 | − info = adap_conf[i].demod_info; | |
| 376 | + info = &adap_conf[i].demod_info; | |
| 386 | 377 | cfg = adap_conf[i].demod_cfg; |
| 387 | 378 | cfg.tuner_i2c = NULL; |
| 388 | − info.platform_data = &cfg; | |
| 389 | 379 | |
| 390 | 380 | ret = -ENODEV; |
| 391 | − request_module("tc90522"); | |
| 392 | − cl = i2c_new_device(&pt3->i2c_adap, &info); | |
| 393 | − if (!cl || !cl->dev.driver) | |
| 381 | + cl = dvb_module_probe("tc90522", info->type, &pt3->i2c_adap, | |
| 382 | + info->addr, &cfg); | |
| 383 | + if (!cl) | |
| 394 | 384 | return -ENODEV; |
| 395 | 385 | pt3->adaps[i]->i2c_demod = cl; |
| 396 | − if (!try_module_get(cl->dev.driver->owner)) | |
| 397 | − goto err_demod_i2c_unregister_device; | |
| 398 | 386 | |
| 399 | 387 | if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, |
| 400 | 388 | strlen(TC90522_I2C_DEV_SAT))) { |
| @@ -402,41 +390,33 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i) · 1 unmodified line | ||
| 402 | 390 | |
| 403 | 391 | tcfg = adap_conf[i].tuner_cfg.qm1d1c0042; |
| 404 | 392 | tcfg.fe = cfg.fe; |
| 405 | − info = adap_conf[i].tuner_info; | |
| 406 | − info.platform_data = &tcfg; | |
| 407 | − request_module("qm1d1c0042"); | |
| 408 | − cl = i2c_new_device(cfg.tuner_i2c, &info); | |
| 393 | + info = &adap_conf[i].tuner_info; | |
| 394 | + cl = dvb_module_probe("qm1d1c0042", info->type, cfg.tuner_i2c, | |
| 395 | + info->addr, &tcfg); | |
| 409 | 396 | } else { |
| 410 | 397 | struct mxl301rf_config tcfg; |
| 411 | 398 | |
| 412 | 399 | tcfg = adap_conf[i].tuner_cfg.mxl301rf; |
| 413 | 400 | tcfg.fe = cfg.fe; |
| 414 | − info = adap_conf[i].tuner_info; | |
| 415 | − info.platform_data = &tcfg; | |
| 416 | − request_module("mxl301rf"); | |
| 417 | − cl = i2c_new_device(cfg.tuner_i2c, &info); | |
| 401 | + info = &adap_conf[i].tuner_info; | |
| 402 | + cl = dvb_module_probe("mxl301rf", info->type, cfg.tuner_i2c, | |
| 403 | + info->addr, &tcfg); | |
| 418 | 404 | } |
| 419 | − if (!cl || !cl->dev.driver) | |
| 420 | − goto err_demod_module_put; | |
| 405 | + if (!cl) | |
| 406 | + goto err_demod_module_release; | |
| 421 | 407 | pt3->adaps[i]->i2c_tuner = cl; |
| 422 | − if (!try_module_get(cl->dev.driver->owner)) | |
| 423 | − goto err_tuner_i2c_unregister_device; | |
| 424 | 408 | |
| 425 | 409 | dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; |
| 426 | 410 | ret = dvb_register_frontend(dvb_adap, cfg.fe); |
| 427 | 411 | if (ret < 0) |
| 428 | − goto err_tuner_module_put; | |
| 412 | + goto err_tuner_module_release; | |
| 429 | 413 | pt3->adaps[i]->fe = cfg.fe; |
| 430 | 414 | return 0; |
| 431 | 415 | |
| 432 | −err_tuner_module_put: | |
| 433 | − module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); | |
| 434 | −err_tuner_i2c_unregister_device: | |
| 435 | − i2c_unregister_device(pt3->adaps[i]->i2c_tuner); | |
| 436 | −err_demod_module_put: | |
| 437 | − module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); | |
| 438 | −err_demod_i2c_unregister_device: | |
| 439 | − i2c_unregister_device(pt3->adaps[i]->i2c_demod); | |
| 416 | +err_tuner_module_release: | |
| 417 | + dvb_module_release(pt3->adaps[i]->i2c_tuner); | |
| 418 | +err_demod_module_release: | |
| 419 | + dvb_module_release(pt3->adaps[i]->i2c_demod); | |
| 440 | 420 | |
| 441 | 421 | return ret; |
| 442 | 422 | } |
| @@ -464,7 +444,7 @@ static int pt3_fetch_thread(void *data) · 21 unmodified lines | ||
| 464 | 444 | |
| 465 | 445 | pt3_proc_dma(adap); |
| 466 | 446 | |
| 467 | − delay = PT3_FETCH_DELAY * NSEC_PER_MSEC; | |
| 447 | + delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC); | |
| 468 | 448 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 469 | 449 | freezable_schedule_hrtimeout_range(&delay, |
| 470 | 450 | PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC, |
| @@ -630,14 +610,8 @@ static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) · 159 unmodified lines | ||
| 630 | 610 | adap->fe->callback = NULL; |
| 631 | 611 | if (adap->fe->frontend_priv) |
| 632 | 612 | dvb_unregister_frontend(adap->fe); |
| 633 | − if (adap->i2c_tuner) { | |
| 634 | − module_put(adap->i2c_tuner->dev.driver->owner); | |
| 635 | − i2c_unregister_device(adap->i2c_tuner); | |
| 636 | − } | |
| 637 | − if (adap->i2c_demod) { | |
| 638 | − module_put(adap->i2c_demod->dev.driver->owner); | |
| 639 | − i2c_unregister_device(adap->i2c_demod); | |
| 640 | − } | |
| 613 | + dvb_module_release(adap->i2c_tuner); | |
| 614 | + dvb_module_release(adap->i2c_demod); | |
| 641 | 615 | } |
| 642 | 616 | pt3_free_dmabuf(adap); |
| 643 | 617 | dvb_dmxdev_release(&adap->dmxdev); |
| @@ -1,17 +1,8 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 1 | 2 | /* |
| 2 | 3 | * Earthsoft PT3 driver |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | |
| 17 | 8 | #ifndef PT3_H |
| @@ -1,17 +1,8 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * Earthsoft PT3 driver |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | #include <linux/dma-mapping.h> |
| 17 | 8 | #include <linux/kernel.h> |
| @@ -1,17 +1,8 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * Earthsoft PT3 driver |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public License as | |
| 8 | − * published by the Free Software Foundation version 2. | |
| 9 | − * | |
| 10 | − * | |
| 11 | − * This program is distributed in the hope that it will be useful, | |
| 12 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 6 | */ |
| 16 | 7 | #include <linux/delay.h> |
| 17 | 8 | #include <linux/device.h> |
| @@ -426,7 +426,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) · 425 unmodified lines | ||
| 426 | 426 | __func__, fw->size); |
| 427 | 427 | |
| 428 | 428 | if (fw->size != fwlength) { |
| 429 | − printk(KERN_ERR "xc5000: firmware incorrect size\n"); | |
| 429 | + printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n", | |
| 430 | + fw->size, fwlength); | |
| 430 | 431 | ret = -ENOMEM; |
| 431 | 432 | goto out; |
| 432 | 433 | } |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config VIDEO_SOLO6X10 |
| 2 | 2 | tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)" |
| 3 | 3 | depends on PCI && VIDEO_DEV && SND && I2C |
| 4 | − depends on HAS_DMA | |
| 5 | 4 | select BITREVERSE |
| 6 | 5 | select FONT_SUPPORT |
| 7 | 6 | select FONT_8x16 |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config STA2X11_VIP |
| 2 | 2 | tristate "STA2X11 VIP Video For Linux" |
| 3 | − depends on STA2X11 | |
| 4 | − depends on HAS_DMA | |
| 3 | + depends on STA2X11 || COMPILE_TEST | |
| 5 | 4 | select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT |
| 6 | 5 | select VIDEOBUF2_DMA_CONTIG |
| 7 | 6 | depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS |
| @@ -908,10 +908,10 @@ static int sta2x11_vip_init_controls(struct sta2x11_vip *vip) · 907 unmodified lines | ||
| 908 | 908 | static int vip_gpio_reserve(struct device *dev, int pin, int dir, |
| 909 | 909 | const char *name) |
| 910 | 910 | { |
| 911 | − int ret; | |
| 911 | + int ret = -ENODEV; | |
| 912 | 912 | |
| 913 | − if (pin == -1) | |
| 914 | − return 0; | |
| 913 | + if (!gpio_is_valid(pin)) | |
| 914 | + return ret; | |
| 915 | 915 | |
| 916 | 916 | ret = gpio_request(pin, name); |
| 917 | 917 | if (ret) { |
| @@ -946,7 +946,7 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir, · 28 unmodified lines | ||
| 946 | 946 | */ |
| 947 | 947 | static void vip_gpio_release(struct device *dev, int pin, const char *name) |
| 948 | 948 | { |
| 949 | − if (pin != -1) { | |
| 949 | + if (gpio_is_valid(pin)) { | |
| 950 | 950 | dev_dbg(dev, "releasing pin %d (%s)\n", pin, name); |
| 951 | 951 | gpio_unexport(pin); |
| 952 | 952 | gpio_free(pin); |
| @@ -1003,25 +1003,24 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev, · 50 unmodified lines | ||
| 1003 | 1003 | if (ret) |
| 1004 | 1004 | goto disable; |
| 1005 | 1005 | |
| 1006 | − if (config->reset_pin >= 0) { | |
| 1007 | − ret = vip_gpio_reserve(&pdev->dev, config->reset_pin, 0, | |
| 1008 | − config->reset_name); | |
| 1009 | − if (ret) { | |
| 1010 | − vip_gpio_release(&pdev->dev, config->pwr_pin, | |
| 1011 | − config->pwr_name); | |
| 1012 | − goto disable; | |
| 1013 | − } | |
| 1006 | + ret = vip_gpio_reserve(&pdev->dev, config->reset_pin, 0, | |
| 1007 | + config->reset_name); | |
| 1008 | + if (ret) { | |
| 1009 | + vip_gpio_release(&pdev->dev, config->pwr_pin, | |
| 1010 | + config->pwr_name); | |
| 1011 | + goto disable; | |
| 1014 | 1012 | } |
| 1015 | − if (config->pwr_pin != -1) { | |
| 1013 | + | |
| 1014 | + if (gpio_is_valid(config->pwr_pin)) { | |
| 1016 | 1015 | /* Datasheet says 5ms between PWR and RST */ |
| 1017 | 1016 | usleep_range(5000, 25000); |
| 1018 | − ret = gpio_direction_output(config->pwr_pin, 1); | |
| 1017 | + gpio_direction_output(config->pwr_pin, 1); | |
| 1019 | 1018 | } |
| 1020 | 1019 | |
| 1021 | − if (config->reset_pin != -1) { | |
| 1020 | + if (gpio_is_valid(config->reset_pin)) { | |
| 1022 | 1021 | /* Datasheet says 5ms between PWR and RST */ |
| 1023 | 1022 | usleep_range(5000, 25000); |
| 1024 | − ret = gpio_direction_output(config->reset_pin, 1); | |
| 1023 | + gpio_direction_output(config->reset_pin, 1); | |
| 1025 | 1024 | } |
| 1026 | 1025 | usleep_range(5000, 25000); |
| 1027 | 1026 | |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config VIDEO_TW5864 |
| 2 | 2 | tristate "Techwell TW5864 video/audio grabber and encoder" |
| 3 | 3 | depends on VIDEO_DEV && PCI && VIDEO_V4L2 |
| 4 | − depends on HAS_DMA | |
| 5 | 4 | select VIDEOBUF2_DMA_CONTIG |
| 6 | 5 | ---help--- |
| 7 | 6 | Support for boards based on Techwell TW5864 chip which provides |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config VIDEO_TW686X |
| 2 | 2 | tristate "Intersil/Techwell TW686x video capture cards" |
| 3 | 3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND |
| 4 | − depends on HAS_DMA | |
| 5 | 4 | select VIDEOBUF2_VMALLOC |
| 6 | 5 | select VIDEOBUF2_DMA_CONTIG |
| 7 | 6 | select VIDEOBUF2_DMA_SG |
| @@ -1228,7 +1228,8 @@ int tw686x_video_init(struct tw686x_dev *dev) · 1227 unmodified lines | ||
| 1228 | 1228 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1229 | 1229 | vc->vidq.min_buffers_needed = 2; |
| 1230 | 1230 | vc->vidq.lock = &vc->vb_mutex; |
| 1231 | − vc->vidq.gfp_flags = GFP_DMA32; | |
| 1231 | + vc->vidq.gfp_flags = dev->dma_mode != TW686X_DMA_MODE_MEMCPY ? | |
| 1232 | + GFP_DMA32 : 0; | |
| 1232 | 1233 | vc->vidq.dev = &dev->pci_dev->dev; |
| 1233 | 1234 | |
| 1234 | 1235 | err = vb2_queue_init(&vc->vidq); |
| @@ -26,6 +26,7 @@ config VIDEO_VIA_CAMERA · 25 unmodified lines | ||
| 26 | 26 | # |
| 27 | 27 | # Platform multimedia device configuration |
| 28 | 28 | # |
| 29 | +source "drivers/media/platform/cadence/Kconfig" | |
| 29 | 30 | |
| 30 | 31 | source "drivers/media/platform/davinci/Kconfig" |
| 31 | 32 | |
| @@ -34,7 +35,7 @@ source "drivers/media/platform/omap/Kconfig" · 2 unmodified lines | ||
| 34 | 35 | config VIDEO_SH_VOU |
| 35 | 36 | tristate "SuperH VOU video output driver" |
| 36 | 37 | depends on MEDIA_CAMERA_SUPPORT |
| 37 | − depends on VIDEO_DEV && I2C && HAS_DMA | |
| 38 | + depends on VIDEO_DEV && I2C | |
| 38 | 39 | depends on ARCH_SHMOBILE || COMPILE_TEST |
| 39 | 40 | select VIDEOBUF2_DMA_CONTIG |
| 40 | 41 | help |
| @@ -42,7 +43,7 @@ config VIDEO_SH_VOU · 1 unmodified line | ||
| 42 | 43 | |
| 43 | 44 | config VIDEO_VIU |
| 44 | 45 | tristate "Freescale VIU Video Driver" |
| 45 | − depends on VIDEO_V4L2 && PPC_MPC512x | |
| 46 | + depends on VIDEO_V4L2 && (PPC_MPC512x || COMPILE_TEST) && I2C | |
| 46 | 47 | select VIDEOBUF_DMA_CONTIG |
| 47 | 48 | default y |
| 48 | 49 | ---help--- |
| @@ -62,10 +63,10 @@ config VIDEO_MUX · 13 unmodified lines | ||
| 62 | 63 | |
| 63 | 64 | config VIDEO_OMAP3 |
| 64 | 65 | tristate "OMAP 3 Camera support" |
| 65 | − depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 | |
| 66 | − depends on HAS_DMA && OF | |
| 67 | − depends on OMAP_IOMMU | |
| 68 | − select ARM_DMA_USE_IOMMU | |
| 66 | + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | |
| 67 | + depends on (ARCH_OMAP3 && OMAP_IOMMU) || COMPILE_TEST | |
| 68 | + depends on COMMON_CLK && OF | |
| 69 | + select ARM_DMA_USE_IOMMU if OMAP_IOMMU | |
| 69 | 70 | select VIDEOBUF2_DMA_CONTIG |
| 70 | 71 | select MFD_SYSCON |
| 71 | 72 | select V4L2_FWNODE |
| @@ -80,7 +81,7 @@ config VIDEO_OMAP3_DEBUG · 8 unmodified lines | ||
| 80 | 81 | |
| 81 | 82 | config VIDEO_PXA27x |
| 82 | 83 | tristate "PXA27x Quick Capture Interface driver" |
| 83 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 84 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 84 | 85 | depends on PXA27x || COMPILE_TEST |
| 85 | 86 | select VIDEOBUF2_DMA_SG |
| 86 | 87 | select SG_SPLIT |
| @@ -90,7 +91,7 @@ config VIDEO_PXA27x · 3 unmodified lines | ||
| 90 | 91 | |
| 91 | 92 | config VIDEO_QCOM_CAMSS |
| 92 | 93 | tristate "Qualcomm 8x16 V4L2 Camera Subsystem driver" |
| 93 | − depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | |
| 94 | + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 94 | 95 | depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST |
| 95 | 96 | select VIDEOBUF2_DMA_SG |
| 96 | 97 | select V4L2_FWNODE |
| @@ -100,7 +101,6 @@ config VIDEO_S3C_CAMIF · 3 unmodified lines | ||
| 100 | 101 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 101 | 102 | depends on PM |
| 102 | 103 | depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST |
| 103 | − depends on HAS_DMA | |
| 104 | 104 | select VIDEOBUF2_DMA_CONTIG |
| 105 | 105 | ---help--- |
| 106 | 106 | This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera |
| @@ -111,7 +111,7 @@ config VIDEO_S3C_CAMIF · 4 unmodified lines | ||
| 111 | 111 | |
| 112 | 112 | config VIDEO_STM32_DCMI |
| 113 | 113 | tristate "STM32 Digital Camera Memory Interface (DCMI) support" |
| 114 | − depends on VIDEO_V4L2 && OF && HAS_DMA | |
| 114 | + depends on VIDEO_V4L2 && OF | |
| 115 | 115 | depends on ARCH_STM32 || COMPILE_TEST |
| 116 | 116 | select VIDEOBUF2_DMA_CONTIG |
| 117 | 117 | select V4L2_FWNODE |
| @@ -124,7 +124,7 @@ config VIDEO_STM32_DCMI · 6 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | config VIDEO_RENESAS_CEU |
| 126 | 126 | tristate "Renesas Capture Engine Unit (CEU) driver" |
| 127 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 127 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 128 | 128 | depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST |
| 129 | 129 | select VIDEOBUF2_DMA_CONTIG |
| 130 | 130 | select V4L2_FWNODE |
| @@ -142,7 +142,6 @@ config VIDEO_TI_CAL · 11 unmodified lines | ||
| 142 | 142 | tristate "TI CAL (Camera Adaptation Layer) driver" |
| 143 | 143 | depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
| 144 | 144 | depends on SOC_DRA7XX || COMPILE_TEST |
| 145 | − depends on HAS_DMA | |
| 146 | 145 | select VIDEOBUF2_DMA_CONTIG |
| 147 | 146 | select V4L2_FWNODE |
| 148 | 147 | default n |
| @@ -170,7 +169,6 @@ if V4L_MEM2MEM_DRIVERS · 21 unmodified lines | ||
| 170 | 169 | config VIDEO_CODA |
| 171 | 170 | tristate "Chips&Media Coda multi-standard codec IP" |
| 172 | 171 | depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MXC || COMPILE_TEST) |
| 173 | − depends on HAS_DMA | |
| 174 | 172 | select SRAM |
| 175 | 173 | select VIDEOBUF2_DMA_CONTIG |
| 176 | 174 | select VIDEOBUF2_VMALLOC |
| @@ -188,7 +186,6 @@ config VIDEO_MEDIATEK_JPEG · 11 unmodified lines | ||
| 188 | 186 | depends on MTK_IOMMU_V1 || COMPILE_TEST |
| 189 | 187 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 190 | 188 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 191 | − depends on HAS_DMA | |
| 192 | 189 | select VIDEOBUF2_DMA_CONTIG |
| 193 | 190 | select V4L2_MEM2MEM_DEV |
| 194 | 191 | ---help--- |
| @@ -200,7 +197,7 @@ config VIDEO_MEDIATEK_JPEG · 5 unmodified lines | ||
| 200 | 197 | |
| 201 | 198 | config VIDEO_MEDIATEK_VPU |
| 202 | 199 | tristate "Mediatek Video Processor Unit" |
| 203 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 200 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 204 | 201 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 205 | 202 | ---help--- |
| 206 | 203 | This driver provides downloading VPU firmware and |
| @@ -216,7 +213,6 @@ config VIDEO_MEDIATEK_MDP · 9 unmodified lines | ||
| 216 | 213 | depends on MTK_IOMMU || COMPILE_TEST |
| 217 | 214 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 218 | 215 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 219 | − depends on HAS_DMA | |
| 220 | 216 | select VIDEOBUF2_DMA_CONTIG |
| 221 | 217 | select V4L2_MEM2MEM_DEV |
| 222 | 218 | select VIDEO_MEDIATEK_VPU |
| @@ -231,7 +227,7 @@ config VIDEO_MEDIATEK_MDP · 8 unmodified lines | ||
| 231 | 227 | config VIDEO_MEDIATEK_VCODEC |
| 232 | 228 | tristate "Mediatek Video Codec driver" |
| 233 | 229 | depends on MTK_IOMMU || COMPILE_TEST |
| 234 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 230 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 235 | 231 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 236 | 232 | select VIDEOBUF2_DMA_CONTIG |
| 237 | 233 | select V4L2_MEM2MEM_DEV |
| @@ -247,7 +243,7 @@ config VIDEO_MEDIATEK_VCODEC · 9 unmodified lines | ||
| 247 | 243 | |
| 248 | 244 | config VIDEO_MEM2MEM_DEINTERLACE |
| 249 | 245 | tristate "Deinterlace support" |
| 250 | − depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE | |
| 246 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 251 | 247 | depends on HAS_DMA |
| 252 | 248 | select VIDEOBUF2_DMA_CONTIG |
| 253 | 249 | select V4L2_MEM2MEM_DEV |
| @@ -258,7 +254,6 @@ config VIDEO_SAMSUNG_S5P_G2D · 4 unmodified lines | ||
| 258 | 254 | tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" |
| 259 | 255 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 260 | 256 | depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST |
| 261 | − depends on HAS_DMA | |
| 262 | 257 | select VIDEOBUF2_DMA_CONTIG |
| 263 | 258 | select V4L2_MEM2MEM_DEV |
| 264 | 259 | default n |
| @@ -270,7 +265,6 @@ config VIDEO_SAMSUNG_S5P_JPEG · 5 unmodified lines | ||
| 270 | 265 | tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" |
| 271 | 266 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 272 | 267 | depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST |
| 273 | − depends on HAS_DMA | |
| 274 | 268 | select VIDEOBUF2_DMA_CONTIG |
| 275 | 269 | select V4L2_MEM2MEM_DEV |
| 276 | 270 | ---help--- |
| @@ -281,7 +275,6 @@ config VIDEO_SAMSUNG_S5P_MFC · 4 unmodified lines | ||
| 281 | 275 | tristate "Samsung S5P MFC Video Codec" |
| 282 | 276 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 283 | 277 | depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST |
| 284 | − depends on HAS_DMA | |
| 285 | 278 | select VIDEOBUF2_DMA_CONTIG |
| 286 | 279 | default n |
| 287 | 280 | help |
| @@ -291,7 +284,6 @@ config VIDEO_MX2_EMMAPRP · 3 unmodified lines | ||
| 291 | 284 | tristate "MX2 eMMa-PrP support" |
| 292 | 285 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 293 | 286 | depends on SOC_IMX27 || COMPILE_TEST |
| 294 | − depends on HAS_DMA | |
| 295 | 287 | select VIDEOBUF2_DMA_CONTIG |
| 296 | 288 | select V4L2_MEM2MEM_DEV |
| 297 | 289 | help |
| @@ -303,7 +295,6 @@ config VIDEO_SAMSUNG_EXYNOS_GSC · 5 unmodified lines | ||
| 303 | 295 | tristate "Samsung Exynos G-Scaler driver" |
| 304 | 296 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 305 | 297 | depends on ARCH_EXYNOS || COMPILE_TEST |
| 306 | − depends on HAS_DMA | |
| 307 | 298 | select VIDEOBUF2_DMA_CONTIG |
| 308 | 299 | select V4L2_MEM2MEM_DEV |
| 309 | 300 | help |
| @@ -312,7 +303,6 @@ config VIDEO_SAMSUNG_EXYNOS_GSC · 2 unmodified lines | ||
| 312 | 303 | config VIDEO_STI_BDISP |
| 313 | 304 | tristate "STMicroelectronics BDISP 2D blitter driver" |
| 314 | 305 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 315 | − depends on HAS_DMA | |
| 316 | 306 | depends on ARCH_STI || COMPILE_TEST |
| 317 | 307 | select VIDEOBUF2_DMA_CONTIG |
| 318 | 308 | select V4L2_MEM2MEM_DEV |
| @@ -322,7 +312,6 @@ config VIDEO_STI_BDISP · 3 unmodified lines | ||
| 322 | 312 | config VIDEO_STI_HVA |
| 323 | 313 | tristate "STMicroelectronics HVA multi-format video encoder V4L2 driver" |
| 324 | 314 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 325 | − depends on HAS_DMA | |
| 326 | 315 | depends on ARCH_STI || COMPILE_TEST |
| 327 | 316 | select VIDEOBUF2_DMA_CONTIG |
| 328 | 317 | select V4L2_MEM2MEM_DEV |
| @@ -349,7 +338,6 @@ config VIDEO_STI_DELTA · 20 unmodified lines | ||
| 349 | 338 | tristate "STMicroelectronics DELTA multi-format video decoder V4L2 driver" |
| 350 | 339 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 351 | 340 | depends on ARCH_STI || COMPILE_TEST |
| 352 | − depends on HAS_DMA | |
| 353 | 341 | help |
| 354 | 342 | This V4L2 driver enables DELTA multi-format video decoder |
| 355 | 343 | of STMicroelectronics STiH4xx SoC series allowing hardware |
| @@ -395,7 +383,7 @@ config VIDEO_SH_VEU · 39 unmodified lines | ||
| 395 | 383 | |
| 396 | 384 | config VIDEO_RENESAS_FDP1 |
| 397 | 385 | tristate "Renesas Fine Display Processor" |
| 398 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 386 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 399 | 387 | depends on ARCH_SHMOBILE || COMPILE_TEST |
| 400 | 388 | depends on (!ARCH_RENESAS && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP |
| 401 | 389 | select VIDEOBUF2_DMA_CONTIG |
| @@ -409,7 +397,7 @@ config VIDEO_RENESAS_FDP1 · 7 unmodified lines | ||
| 409 | 397 | |
| 410 | 398 | config VIDEO_RENESAS_JPU |
| 411 | 399 | tristate "Renesas JPEG Processing Unit" |
| 412 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 400 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 413 | 401 | depends on ARCH_RENESAS || COMPILE_TEST |
| 414 | 402 | select VIDEOBUF2_DMA_CONTIG |
| 415 | 403 | select V4L2_MEM2MEM_DEV |
| @@ -434,8 +422,8 @@ config VIDEO_RENESAS_FCP · 18 unmodified lines | ||
| 434 | 422 | |
| 435 | 423 | config VIDEO_RENESAS_VSP1 |
| 436 | 424 | tristate "Renesas VSP1 Video Processing Engine" |
| 437 | − depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | |
| 438 | − depends on (ARCH_RENESAS && OF) || COMPILE_TEST | |
| 425 | + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 426 | + depends on ARCH_RENESAS || COMPILE_TEST | |
| 439 | 427 | depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP |
| 440 | 428 | select VIDEOBUF2_DMA_CONTIG |
| 441 | 429 | select VIDEOBUF2_VMALLOC |
| @@ -447,7 +435,7 @@ config VIDEO_RENESAS_VSP1 · 5 unmodified lines | ||
| 447 | 435 | |
| 448 | 436 | config VIDEO_ROCKCHIP_RGA |
| 449 | 437 | tristate "Rockchip Raster 2d Graphic Acceleration Unit" |
| 450 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 438 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 451 | 439 | depends on ARCH_ROCKCHIP || COMPILE_TEST |
| 452 | 440 | select VIDEOBUF2_DMA_SG |
| 453 | 441 | select V4L2_MEM2MEM_DEV |
| @@ -464,7 +452,6 @@ config VIDEO_TI_VPE · 10 unmodified lines | ||
| 464 | 452 | tristate "TI VPE (Video Processing Engine) driver" |
| 465 | 453 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 466 | 454 | depends on SOC_DRA7XX || COMPILE_TEST |
| 467 | − depends on HAS_DMA | |
| 468 | 455 | select VIDEOBUF2_DMA_CONTIG |
| 469 | 456 | select V4L2_MEM2MEM_DEV |
| 470 | 457 | select VIDEO_TI_VPDMA |
| @@ -483,7 +470,7 @@ config VIDEO_TI_VPE_DEBUG · 12 unmodified lines | ||
| 483 | 470 | |
| 484 | 471 | config VIDEO_QCOM_VENUS |
| 485 | 472 | tristate "Qualcomm Venus V4L2 encoder/decoder driver" |
| 486 | − depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | |
| 473 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 487 | 474 | depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST |
| 488 | 475 | select QCOM_MDT_LOADER if ARCH_QCOM |
| 489 | 476 | select QCOM_SCM if ARCH_QCOM |
| @@ -558,7 +545,7 @@ config VIDEO_MESON_AO_CEC · 68 unmodified lines | ||
| 558 | 545 | |
| 559 | 546 | config CEC_GPIO |
| 560 | 547 | tristate "Generic GPIO-based CEC driver" |
| 561 | − depends on PREEMPT | |
| 548 | + depends on PREEMPT || COMPILE_TEST | |
| 562 | 549 | select CEC_CORE |
| 563 | 550 | select CEC_PIN |
| 564 | 551 | select GPIOLIB |
| @@ -625,7 +612,7 @@ if SDR_PLATFORM_DRIVERS · 60 unmodified lines | ||
| 625 | 612 | |
| 626 | 613 | config VIDEO_RCAR_DRIF |
| 627 | 614 | tristate "Renesas Digitial Radio Interface (DRIF)" |
| 628 | − depends on VIDEO_V4L2 && HAS_DMA | |
| 615 | + depends on VIDEO_V4L2 | |
| 629 | 616 | depends on ARCH_RENESAS || COMPILE_TEST |
| 630 | 617 | select VIDEOBUF2_VMALLOC |
| 631 | 618 | ---help--- |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | # Makefile for the video capture/playback device drivers. |
| 4 | 4 | # |
| 5 | 5 | |
| 6 | +obj-$(CONFIG_VIDEO_CADENCE) += cadence/ | |
| 6 | 7 | obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o |
| 7 | 8 | obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ |
| 8 | 9 | obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | config VIDEO_AM437X_VPFE |
| 2 | 2 | tristate "TI AM437x VPFE video capture driver" |
| 3 | − depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | |
| 3 | + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 4 | 4 | depends on SOC_AM43XX || COMPILE_TEST |
| 5 | 5 | select VIDEOBUF2_DMA_CONTIG |
| 6 | 6 | select V4L2_FWNODE |
| @@ -2662,8 +2662,7 @@ static void vpfe_save_context(struct vpfe_ccdc *ccdc) · 2661 unmodified lines | ||
| 2662 | 2662 | |
| 2663 | 2663 | static int vpfe_suspend(struct device *dev) |
| 2664 | 2664 | { |
| 2665 | − struct platform_device *pdev = to_platform_device(dev); | |
| 2666 | − struct vpfe_device *vpfe = platform_get_drvdata(pdev); | |
| 2665 | + struct vpfe_device *vpfe = dev_get_drvdata(dev); | |
| 2667 | 2666 | struct vpfe_ccdc *ccdc = &vpfe->ccdc; |
| 2668 | 2667 | |
| 2669 | 2668 | /* if streaming has not started we don't care */ |
| @@ -2720,8 +2719,7 @@ static void vpfe_restore_context(struct vpfe_ccdc *ccdc) · 50 unmodified lines | ||
| 2720 | 2719 | |
| 2721 | 2720 | static int vpfe_resume(struct device *dev) |
| 2722 | 2721 | { |
| 2723 | − struct platform_device *pdev = to_platform_device(dev); | |
| 2724 | − struct vpfe_device *vpfe = platform_get_drvdata(pdev); | |
| 2722 | + struct vpfe_device *vpfe = dev_get_drvdata(dev); | |
| 2725 | 2723 | struct vpfe_ccdc *ccdc = &vpfe->ccdc; |
| 2726 | 2724 | |
| 2727 | 2725 | /* if streaming has not started we don't care */ |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | config VIDEO_ATMEL_ISC |
| 2 | 2 | tristate "ATMEL Image Sensor Controller (ISC) support" |
| 3 | − depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA | |
| 3 | + depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API | |
| 4 | 4 | depends on ARCH_AT91 || COMPILE_TEST |
| 5 | 5 | select VIDEOBUF2_DMA_CONTIG |
| 6 | 6 | select REGMAP_MMIO |
| @@ -11,7 +11,7 @@ config VIDEO_ATMEL_ISC · 4 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | config VIDEO_ATMEL_ISI |
| 13 | 13 | tristate "ATMEL Image Sensor Interface (ISI) support" |
| 14 | − depends on VIDEO_V4L2 && OF && HAS_DMA | |
| 14 | + depends on VIDEO_V4L2 && OF | |
| 15 | 15 | depends on ARCH_AT91 || COMPILE_TEST |
| 16 | 16 | select VIDEOBUF2_DMA_CONTIG |
| 17 | 17 | select V4L2_FWNODE |
| @@ -0,0 +1,34 @@ | ||
| 1 | +config VIDEO_CADENCE | |
| 2 | + bool "Cadence Video Devices" | |
| 3 | + help | |
| 4 | + If you have a media device designed by Cadence, say Y. | |
| 5 | + | |
| 6 | + Note that this option doesn't include new drivers in the kernel: | |
| 7 | + saying N will just cause Kconfig to skip all the questions about | |
| 8 | + Cadence media devices. | |
| 9 | + | |
| 10 | +if VIDEO_CADENCE | |
| 11 | + | |
| 12 | +config VIDEO_CADENCE_CSI2RX | |
| 13 | + tristate "Cadence MIPI-CSI2 RX Controller" | |
| 14 | + depends on MEDIA_CONTROLLER | |
| 15 | + depends on VIDEO_V4L2_SUBDEV_API | |
| 16 | + select V4L2_FWNODE | |
| 17 | + help | |
| 18 | + Support for the Cadence MIPI CSI2 Receiver controller. | |
| 19 | + | |
| 20 | + To compile this driver as a module, choose M here: the module will be | |
| 21 | + called cdns-csi2rx. | |
| 22 | + | |
| 23 | +config VIDEO_CADENCE_CSI2TX | |
| 24 | + tristate "Cadence MIPI-CSI2 TX Controller" | |
| 25 | + depends on MEDIA_CONTROLLER | |
| 26 | + depends on VIDEO_V4L2_SUBDEV_API | |
| 27 | + select V4L2_FWNODE | |
| 28 | + help | |
| 29 | + Support for the Cadence MIPI CSI2 Transceiver controller. | |
| 30 | + | |
| 31 | + To compile this driver as a module, choose M here: the module will be | |
| 32 | + called cdns-csi2tx. | |
| 33 | + | |
| 34 | +endif | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +obj-$(CONFIG_VIDEO_CADENCE_CSI2RX) += cdns-csi2rx.o | |
| 4 | +obj-$(CONFIG_VIDEO_CADENCE_CSI2TX) += cdns-csi2tx.o | |
| @@ -0,0 +1,498 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +/* | |
| 3 | + * Driver for Cadence MIPI-CSI2 RX Controller v1.3 | |
| 4 | + * | |
| 5 | + * Copyright (C) 2017 Cadence Design Systems Inc. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/delay.h> | |
| 10 | +#include <linux/io.h> | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/of.h> | |
| 13 | +#include <linux/of_graph.h> | |
| 14 | +#include <linux/phy/phy.h> | |
| 15 | +#include <linux/platform_device.h> | |
| 16 | + | |
| 17 | +#include <media/v4l2-ctrls.h> | |
| 18 | +#include <media/v4l2-device.h> | |
| 19 | +#include <media/v4l2-fwnode.h> | |
| 20 | +#include <media/v4l2-subdev.h> | |
| 21 | + | |
| 22 | +#define CSI2RX_DEVICE_CFG_REG 0x000 | |
| 23 | + | |
| 24 | +#define CSI2RX_SOFT_RESET_REG 0x004 | |
| 25 | +#define CSI2RX_SOFT_RESET_PROTOCOL BIT(1) | |
| 26 | +#define CSI2RX_SOFT_RESET_FRONT BIT(0) | |
| 27 | + | |
| 28 | +#define CSI2RX_STATIC_CFG_REG 0x008 | |
| 29 | +#define CSI2RX_STATIC_CFG_DLANE_MAP(llane, plane) ((plane) << (16 + (llane) * 4)) | |
| 30 | +#define CSI2RX_STATIC_CFG_LANES_MASK GENMASK(11, 8) | |
| 31 | + | |
| 32 | +#define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100) | |
| 33 | + | |
| 34 | +#define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) | |
| 35 | +#define CSI2RX_STREAM_CTRL_START BIT(0) | |
| 36 | + | |
| 37 | +#define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) | |
| 38 | +#define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31) | |
| 39 | +#define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) | |
| 40 | + | |
| 41 | +#define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) | |
| 42 | +#define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF (1 << 8) | |
| 43 | + | |
| 44 | +#define CSI2RX_LANES_MAX 4 | |
| 45 | +#define CSI2RX_STREAMS_MAX 4 | |
| 46 | + | |
| 47 | +enum csi2rx_pads { | |
| 48 | + CSI2RX_PAD_SINK, | |
| 49 | + CSI2RX_PAD_SOURCE_STREAM0, | |
| 50 | + CSI2RX_PAD_SOURCE_STREAM1, | |
| 51 | + CSI2RX_PAD_SOURCE_STREAM2, | |
| 52 | + CSI2RX_PAD_SOURCE_STREAM3, | |
| 53 | + CSI2RX_PAD_MAX, | |
| 54 | +}; | |
| 55 | + | |
| 56 | +struct csi2rx_priv { | |
| 57 | + struct device *dev; | |
| 58 | + unsigned int count; | |
| 59 | + | |
| 60 | + /* | |
| 61 | + * Used to prevent race conditions between multiple, | |
| 62 | + * concurrent calls to start and stop. | |
| 63 | + */ | |
| 64 | + struct mutex lock; | |
| 65 | + | |
| 66 | + void __iomem *base; | |
| 67 | + struct clk *sys_clk; | |
| 68 | + struct clk *p_clk; | |
| 69 | + struct clk *pixel_clk[CSI2RX_STREAMS_MAX]; | |
| 70 | + struct phy *dphy; | |
| 71 | + | |
| 72 | + u8 lanes[CSI2RX_LANES_MAX]; | |
| 73 | + u8 num_lanes; | |
| 74 | + u8 max_lanes; | |
| 75 | + u8 max_streams; | |
| 76 | + bool has_internal_dphy; | |
| 77 | + | |
| 78 | + struct v4l2_subdev subdev; | |
| 79 | + struct v4l2_async_notifier notifier; | |
| 80 | + struct media_pad pads[CSI2RX_PAD_MAX]; | |
| 81 | + | |
| 82 | + /* Remote source */ | |
| 83 | + struct v4l2_async_subdev asd; | |
| 84 | + struct v4l2_subdev *source_subdev; | |
| 85 | + int source_pad; | |
| 86 | +}; | |
| 87 | + | |
| 88 | +static inline | |
| 89 | +struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) | |
| 90 | +{ | |
| 91 | + return container_of(subdev, struct csi2rx_priv, subdev); | |
| 92 | +} | |
| 93 | + | |
| 94 | +static void csi2rx_reset(struct csi2rx_priv *csi2rx) | |
| 95 | +{ | |
| 96 | + writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT, | |
| 97 | + csi2rx->base + CSI2RX_SOFT_RESET_REG); | |
| 98 | + | |
| 99 | + udelay(10); | |
| 100 | + | |
| 101 | + writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG); | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int csi2rx_start(struct csi2rx_priv *csi2rx) | |
| 105 | +{ | |
| 106 | + unsigned int i; | |
| 107 | + unsigned long lanes_used = 0; | |
| 108 | + u32 reg; | |
| 109 | + int ret; | |
| 110 | + | |
| 111 | + ret = clk_prepare_enable(csi2rx->p_clk); | |
| 112 | + if (ret) | |
| 113 | + return ret; | |
| 114 | + | |
| 115 | + csi2rx_reset(csi2rx); | |
| 116 | + | |
| 117 | + reg = csi2rx->num_lanes << 8; | |
| 118 | + for (i = 0; i < csi2rx->num_lanes; i++) { | |
| 119 | + reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csi2rx->lanes[i]); | |
| 120 | + set_bit(csi2rx->lanes[i], &lanes_used); | |
| 121 | + } | |
| 122 | + | |
| 123 | + /* | |
| 124 | + * Even the unused lanes need to be mapped. In order to avoid | |
| 125 | + * to map twice to the same physical lane, keep the lanes used | |
| 126 | + * in the previous loop, and only map unused physical lanes to | |
| 127 | + * the rest of our logical lanes. | |
| 128 | + */ | |
| 129 | + for (i = csi2rx->num_lanes; i < csi2rx->max_lanes; i++) { | |
| 130 | + unsigned int idx = find_first_zero_bit(&lanes_used, | |
| 131 | + sizeof(lanes_used)); | |
| 132 | + set_bit(idx, &lanes_used); | |
| 133 | + reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1); | |
| 134 | + } | |
| 135 | + | |
| 136 | + writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG); | |
| 137 | + | |
| 138 | + ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); | |
| 139 | + if (ret) | |
| 140 | + goto err_disable_pclk; | |
| 141 | + | |
| 142 | + /* | |
| 143 | + * Create a static mapping between the CSI virtual channels | |
| 144 | + * and the output stream. | |
| 145 | + * | |
| 146 | + * This should be enhanced, but v4l2 lacks the support for | |
| 147 | + * changing that mapping dynamically. | |
| 148 | + * | |
| 149 | + * We also cannot enable and disable independent streams here, | |
| 150 | + * hence the reference counting. | |
| 151 | + */ | |
| 152 | + for (i = 0; i < csi2rx->max_streams; i++) { | |
| 153 | + ret = clk_prepare_enable(csi2rx->pixel_clk[i]); | |
| 154 | + if (ret) | |
| 155 | + goto err_disable_pixclk; | |
| 156 | + | |
| 157 | + writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, | |
| 158 | + csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); | |
| 159 | + | |
| 160 | + writel(CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT | | |
| 161 | + CSI2RX_STREAM_DATA_CFG_VC_SELECT(i), | |
| 162 | + csi2rx->base + CSI2RX_STREAM_DATA_CFG_REG(i)); | |
| 163 | + | |
| 164 | + writel(CSI2RX_STREAM_CTRL_START, | |
| 165 | + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); | |
| 166 | + } | |
| 167 | + | |
| 168 | + ret = clk_prepare_enable(csi2rx->sys_clk); | |
| 169 | + if (ret) | |
| 170 | + goto err_disable_pixclk; | |
| 171 | + | |
| 172 | + clk_disable_unprepare(csi2rx->p_clk); | |
| 173 | + | |
| 174 | + return 0; | |
| 175 | + | |
| 176 | +err_disable_pixclk: | |
| 177 | + for (; i > 0; i--) | |
| 178 | + clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); | |
| 179 | + | |
| 180 | +err_disable_pclk: | |
| 181 | + clk_disable_unprepare(csi2rx->p_clk); | |
| 182 | + | |
| 183 | + return ret; | |
| 184 | +} | |
| 185 | + | |
| 186 | +static void csi2rx_stop(struct csi2rx_priv *csi2rx) | |
| 187 | +{ | |
| 188 | + unsigned int i; | |
| 189 | + | |
| 190 | + clk_prepare_enable(csi2rx->p_clk); | |
| 191 | + clk_disable_unprepare(csi2rx->sys_clk); | |
| 192 | + | |
| 193 | + for (i = 0; i < csi2rx->max_streams; i++) { | |
| 194 | + writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); | |
| 195 | + | |
| 196 | + clk_disable_unprepare(csi2rx->pixel_clk[i]); | |
| 197 | + } | |
| 198 | + | |
| 199 | + clk_disable_unprepare(csi2rx->p_clk); | |
| 200 | + | |
| 201 | + if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) | |
| 202 | + dev_warn(csi2rx->dev, "Couldn't disable our subdev\n"); | |
| 203 | +} | |
| 204 | + | |
| 205 | +static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 206 | +{ | |
| 207 | + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); | |
| 208 | + int ret = 0; | |
| 209 | + | |
| 210 | + mutex_lock(&csi2rx->lock); | |
| 211 | + | |
| 212 | + if (enable) { | |
| 213 | + /* | |
| 214 | + * If we're not the first users, there's no need to | |
| 215 | + * enable the whole controller. | |
| 216 | + */ | |
| 217 | + if (!csi2rx->count) { | |
| 218 | + ret = csi2rx_start(csi2rx); | |
| 219 | + if (ret) | |
| 220 | + goto out; | |
| 221 | + } | |
| 222 | + | |
| 223 | + csi2rx->count++; | |
| 224 | + } else { | |
| 225 | + csi2rx->count--; | |
| 226 | + | |
| 227 | + /* | |
| 228 | + * Let the last user turn off the lights. | |
| 229 | + */ | |
| 230 | + if (!csi2rx->count) | |
| 231 | + csi2rx_stop(csi2rx); | |
| 232 | + } | |
| 233 | + | |
| 234 | +out: | |
| 235 | + mutex_unlock(&csi2rx->lock); | |
| 236 | + return ret; | |
| 237 | +} | |
| 238 | + | |
| 239 | +static const struct v4l2_subdev_video_ops csi2rx_video_ops = { | |
| 240 | + .s_stream = csi2rx_s_stream, | |
| 241 | +}; | |
| 242 | + | |
| 243 | +static const struct v4l2_subdev_ops csi2rx_subdev_ops = { | |
| 244 | + .video = &csi2rx_video_ops, | |
| 245 | +}; | |
| 246 | + | |
| 247 | +static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, | |
| 248 | + struct v4l2_subdev *s_subdev, | |
| 249 | + struct v4l2_async_subdev *asd) | |
| 250 | +{ | |
| 251 | + struct v4l2_subdev *subdev = notifier->sd; | |
| 252 | + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); | |
| 253 | + | |
| 254 | + csi2rx->source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, | |
| 255 | + s_subdev->fwnode, | |
| 256 | + MEDIA_PAD_FL_SOURCE); | |
| 257 | + if (csi2rx->source_pad < 0) { | |
| 258 | + dev_err(csi2rx->dev, "Couldn't find output pad for subdev %s\n", | |
| 259 | + s_subdev->name); | |
| 260 | + return csi2rx->source_pad; | |
| 261 | + } | |
| 262 | + | |
| 263 | + csi2rx->source_subdev = s_subdev; | |
| 264 | + | |
| 265 | + dev_dbg(csi2rx->dev, "Bound %s pad: %d\n", s_subdev->name, | |
| 266 | + csi2rx->source_pad); | |
| 267 | + | |
| 268 | + return media_create_pad_link(&csi2rx->source_subdev->entity, | |
| 269 | + csi2rx->source_pad, | |
| 270 | + &csi2rx->subdev.entity, 0, | |
| 271 | + MEDIA_LNK_FL_ENABLED | | |
| 272 | + MEDIA_LNK_FL_IMMUTABLE); | |
| 273 | +} | |
| 274 | + | |
| 275 | +static const struct v4l2_async_notifier_operations csi2rx_notifier_ops = { | |
| 276 | + .bound = csi2rx_async_bound, | |
| 277 | +}; | |
| 278 | + | |
| 279 | +static int csi2rx_get_resources(struct csi2rx_priv *csi2rx, | |
| 280 | + struct platform_device *pdev) | |
| 281 | +{ | |
| 282 | + struct resource *res; | |
| 283 | + unsigned char i; | |
| 284 | + u32 dev_cfg; | |
| 285 | + | |
| 286 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 287 | + csi2rx->base = devm_ioremap_resource(&pdev->dev, res); | |
| 288 | + if (IS_ERR(csi2rx->base)) | |
| 289 | + return PTR_ERR(csi2rx->base); | |
| 290 | + | |
| 291 | + csi2rx->sys_clk = devm_clk_get(&pdev->dev, "sys_clk"); | |
| 292 | + if (IS_ERR(csi2rx->sys_clk)) { | |
| 293 | + dev_err(&pdev->dev, "Couldn't get sys clock\n"); | |
| 294 | + return PTR_ERR(csi2rx->sys_clk); | |
| 295 | + } | |
| 296 | + | |
| 297 | + csi2rx->p_clk = devm_clk_get(&pdev->dev, "p_clk"); | |
| 298 | + if (IS_ERR(csi2rx->p_clk)) { | |
| 299 | + dev_err(&pdev->dev, "Couldn't get P clock\n"); | |
| 300 | + return PTR_ERR(csi2rx->p_clk); | |
| 301 | + } | |
| 302 | + | |
| 303 | + csi2rx->dphy = devm_phy_optional_get(&pdev->dev, "dphy"); | |
| 304 | + if (IS_ERR(csi2rx->dphy)) { | |
| 305 | + dev_err(&pdev->dev, "Couldn't get external D-PHY\n"); | |
| 306 | + return PTR_ERR(csi2rx->dphy); | |
| 307 | + } | |
| 308 | + | |
| 309 | + /* | |
| 310 | + * FIXME: Once we'll have external D-PHY support, the check | |
| 311 | + * will need to be removed. | |
| 312 | + */ | |
| 313 | + if (csi2rx->dphy) { | |
| 314 | + dev_err(&pdev->dev, "External D-PHY not supported yet\n"); | |
| 315 | + return -EINVAL; | |
| 316 | + } | |
| 317 | + | |
| 318 | + clk_prepare_enable(csi2rx->p_clk); | |
| 319 | + dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG); | |
| 320 | + clk_disable_unprepare(csi2rx->p_clk); | |
| 321 | + | |
| 322 | + csi2rx->max_lanes = dev_cfg & 7; | |
| 323 | + if (csi2rx->max_lanes > CSI2RX_LANES_MAX) { | |
| 324 | + dev_err(&pdev->dev, "Invalid number of lanes: %u\n", | |
| 325 | + csi2rx->max_lanes); | |
| 326 | + return -EINVAL; | |
| 327 | + } | |
| 328 | + | |
| 329 | + csi2rx->max_streams = (dev_cfg >> 4) & 7; | |
| 330 | + if (csi2rx->max_streams > CSI2RX_STREAMS_MAX) { | |
| 331 | + dev_err(&pdev->dev, "Invalid number of streams: %u\n", | |
| 332 | + csi2rx->max_streams); | |
| 333 | + return -EINVAL; | |
| 334 | + } | |
| 335 | + | |
| 336 | + csi2rx->has_internal_dphy = dev_cfg & BIT(3) ? true : false; | |
| 337 | + | |
| 338 | + /* | |
| 339 | + * FIXME: Once we'll have internal D-PHY support, the check | |
| 340 | + * will need to be removed. | |
| 341 | + */ | |
| 342 | + if (csi2rx->has_internal_dphy) { | |
| 343 | + dev_err(&pdev->dev, "Internal D-PHY not supported yet\n"); | |
| 344 | + return -EINVAL; | |
| 345 | + } | |
| 346 | + | |
| 347 | + for (i = 0; i < csi2rx->max_streams; i++) { | |
| 348 | + char clk_name[16]; | |
| 349 | + | |
| 350 | + snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); | |
| 351 | + csi2rx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); | |
| 352 | + if (IS_ERR(csi2rx->pixel_clk[i])) { | |
| 353 | + dev_err(&pdev->dev, "Couldn't get clock %s\n", clk_name); | |
| 354 | + return PTR_ERR(csi2rx->pixel_clk[i]); | |
| 355 | + } | |
| 356 | + } | |
| 357 | + | |
| 358 | + return 0; | |
| 359 | +} | |
| 360 | + | |
| 361 | +static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx) | |
| 362 | +{ | |
| 363 | + struct v4l2_fwnode_endpoint v4l2_ep; | |
| 364 | + struct fwnode_handle *fwh; | |
| 365 | + struct device_node *ep; | |
| 366 | + int ret; | |
| 367 | + | |
| 368 | + ep = of_graph_get_endpoint_by_regs(csi2rx->dev->of_node, 0, 0); | |
| 369 | + if (!ep) | |
| 370 | + return -EINVAL; | |
| 371 | + | |
| 372 | + fwh = of_fwnode_handle(ep); | |
| 373 | + ret = v4l2_fwnode_endpoint_parse(fwh, &v4l2_ep); | |
| 374 | + if (ret) { | |
| 375 | + dev_err(csi2rx->dev, "Could not parse v4l2 endpoint\n"); | |
| 376 | + of_node_put(ep); | |
| 377 | + return ret; | |
| 378 | + } | |
| 379 | + | |
| 380 | + if (v4l2_ep.bus_type != V4L2_MBUS_CSI2) { | |
| 381 | + dev_err(csi2rx->dev, "Unsupported media bus type: 0x%x\n", | |
| 382 | + v4l2_ep.bus_type); | |
| 383 | + of_node_put(ep); | |
| 384 | + return -EINVAL; | |
| 385 | + } | |
| 386 | + | |
| 387 | + memcpy(csi2rx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, | |
| 388 | + sizeof(csi2rx->lanes)); | |
| 389 | + csi2rx->num_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; | |
| 390 | + if (csi2rx->num_lanes > csi2rx->max_lanes) { | |
| 391 | + dev_err(csi2rx->dev, "Unsupported number of data-lanes: %d\n", | |
| 392 | + csi2rx->num_lanes); | |
| 393 | + of_node_put(ep); | |
| 394 | + return -EINVAL; | |
| 395 | + } | |
| 396 | + | |
| 397 | + csi2rx->asd.match.fwnode = fwnode_graph_get_remote_port_parent(fwh); | |
| 398 | + csi2rx->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; | |
| 399 | + of_node_put(ep); | |
| 400 | + | |
| 401 | + csi2rx->notifier.subdevs = devm_kzalloc(csi2rx->dev, | |
| 402 | + sizeof(*csi2rx->notifier.subdevs), | |
| 403 | + GFP_KERNEL); | |
| 404 | + if (!csi2rx->notifier.subdevs) | |
| 405 | + return -ENOMEM; | |
| 406 | + | |
| 407 | + csi2rx->notifier.subdevs[0] = &csi2rx->asd; | |
| 408 | + csi2rx->notifier.num_subdevs = 1; | |
| 409 | + csi2rx->notifier.ops = &csi2rx_notifier_ops; | |
| 410 | + | |
| 411 | + return v4l2_async_subdev_notifier_register(&csi2rx->subdev, | |
| 412 | + &csi2rx->notifier); | |
| 413 | +} | |
| 414 | + | |
| 415 | +static int csi2rx_probe(struct platform_device *pdev) | |
| 416 | +{ | |
| 417 | + struct csi2rx_priv *csi2rx; | |
| 418 | + unsigned int i; | |
| 419 | + int ret; | |
| 420 | + | |
| 421 | + csi2rx = kzalloc(sizeof(*csi2rx), GFP_KERNEL); | |
| 422 | + if (!csi2rx) | |
| 423 | + return -ENOMEM; | |
| 424 | + platform_set_drvdata(pdev, csi2rx); | |
| 425 | + csi2rx->dev = &pdev->dev; | |
| 426 | + mutex_init(&csi2rx->lock); | |
| 427 | + | |
| 428 | + ret = csi2rx_get_resources(csi2rx, pdev); | |
| 429 | + if (ret) | |
| 430 | + goto err_free_priv; | |
| 431 | + | |
| 432 | + ret = csi2rx_parse_dt(csi2rx); | |
| 433 | + if (ret) | |
| 434 | + goto err_free_priv; | |
| 435 | + | |
| 436 | + csi2rx->subdev.owner = THIS_MODULE; | |
| 437 | + csi2rx->subdev.dev = &pdev->dev; | |
| 438 | + v4l2_subdev_init(&csi2rx->subdev, &csi2rx_subdev_ops); | |
| 439 | + v4l2_set_subdevdata(&csi2rx->subdev, &pdev->dev); | |
| 440 | + snprintf(csi2rx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", | |
| 441 | + KBUILD_MODNAME, dev_name(&pdev->dev)); | |
| 442 | + | |
| 443 | + /* Create our media pads */ | |
| 444 | + csi2rx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | |
| 445 | + csi2rx->pads[CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | |
| 446 | + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) | |
| 447 | + csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; | |
| 448 | + | |
| 449 | + ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, | |
| 450 | + csi2rx->pads); | |
| 451 | + if (ret) | |
| 452 | + goto err_free_priv; | |
| 453 | + | |
| 454 | + ret = v4l2_async_register_subdev(&csi2rx->subdev); | |
| 455 | + if (ret < 0) | |
| 456 | + goto err_free_priv; | |
| 457 | + | |
| 458 | + dev_info(&pdev->dev, | |
| 459 | + "Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n", | |
| 460 | + csi2rx->num_lanes, csi2rx->max_lanes, csi2rx->max_streams, | |
| 461 | + csi2rx->has_internal_dphy ? "internal" : "no"); | |
| 462 | + | |
| 463 | + return 0; | |
| 464 | + | |
| 465 | +err_free_priv: | |
| 466 | + kfree(csi2rx); | |
| 467 | + return ret; | |
| 468 | +} | |
| 469 | + | |
| 470 | +static int csi2rx_remove(struct platform_device *pdev) | |
| 471 | +{ | |
| 472 | + struct csi2rx_priv *csi2rx = platform_get_drvdata(pdev); | |
| 473 | + | |
| 474 | + v4l2_async_unregister_subdev(&csi2rx->subdev); | |
| 475 | + kfree(csi2rx); | |
| 476 | + | |
| 477 | + return 0; | |
| 478 | +} | |
| 479 | + | |
| 480 | +static const struct of_device_id csi2rx_of_table[] = { | |
| 481 | + { .compatible = "cdns,csi2rx" }, | |
| 482 | + { }, | |
| 483 | +}; | |
| 484 | +MODULE_DEVICE_TABLE(of, csi2rx_of_table); | |
| 485 | + | |
| 486 | +static struct platform_driver csi2rx_driver = { | |
| 487 | + .probe = csi2rx_probe, | |
| 488 | + .remove = csi2rx_remove, | |
| 489 | + | |
| 490 | + .driver = { | |
| 491 | + .name = "cdns-csi2rx", | |
| 492 | + .of_match_table = csi2rx_of_table, | |
| 493 | + }, | |
| 494 | +}; | |
| 495 | +module_platform_driver(csi2rx_driver); | |
| 496 | +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); | |
| 497 | +MODULE_DESCRIPTION("Cadence CSI2-RX controller"); | |
| 498 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,563 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +/* | |
| 3 | + * Driver for Cadence MIPI-CSI2 TX Controller | |
| 4 | + * | |
| 5 | + * Copyright (C) 2017-2018 Cadence Design Systems Inc. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/delay.h> | |
| 10 | +#include <linux/io.h> | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/mutex.h> | |
| 13 | +#include <linux/of.h> | |
| 14 | +#include <linux/of_graph.h> | |
| 15 | +#include <linux/platform_device.h> | |
| 16 | + | |
| 17 | +#include <media/v4l2-ctrls.h> | |
| 18 | +#include <media/v4l2-device.h> | |
| 19 | +#include <media/v4l2-fwnode.h> | |
| 20 | +#include <media/v4l2-subdev.h> | |
| 21 | + | |
| 22 | +#define CSI2TX_DEVICE_CONFIG_REG 0x00 | |
| 23 | +#define CSI2TX_DEVICE_CONFIG_STREAMS_MASK GENMASK(6, 4) | |
| 24 | +#define CSI2TX_DEVICE_CONFIG_HAS_DPHY BIT(3) | |
| 25 | +#define CSI2TX_DEVICE_CONFIG_LANES_MASK GENMASK(2, 0) | |
| 26 | + | |
| 27 | +#define CSI2TX_CONFIG_REG 0x20 | |
| 28 | +#define CSI2TX_CONFIG_CFG_REQ BIT(2) | |
| 29 | +#define CSI2TX_CONFIG_SRST_REQ BIT(1) | |
| 30 | + | |
| 31 | +#define CSI2TX_DPHY_CFG_REG 0x28 | |
| 32 | +#define CSI2TX_DPHY_CFG_CLK_RESET BIT(16) | |
| 33 | +#define CSI2TX_DPHY_CFG_LANE_RESET(n) BIT((n) + 12) | |
| 34 | +#define CSI2TX_DPHY_CFG_MODE_MASK GENMASK(9, 8) | |
| 35 | +#define CSI2TX_DPHY_CFG_MODE_LPDT (2 << 8) | |
| 36 | +#define CSI2TX_DPHY_CFG_MODE_HS (1 << 8) | |
| 37 | +#define CSI2TX_DPHY_CFG_MODE_ULPS (0 << 8) | |
| 38 | +#define CSI2TX_DPHY_CFG_CLK_ENABLE BIT(4) | |
| 39 | +#define CSI2TX_DPHY_CFG_LANE_ENABLE(n) BIT(n) | |
| 40 | + | |
| 41 | +#define CSI2TX_DPHY_CLK_WAKEUP_REG 0x2c | |
| 42 | +#define CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(n) ((n) & 0xffff) | |
| 43 | + | |
| 44 | +#define CSI2TX_DT_CFG_REG(n) (0x80 + (n) * 8) | |
| 45 | +#define CSI2TX_DT_CFG_DT(n) (((n) & 0x3f) << 2) | |
| 46 | + | |
| 47 | +#define CSI2TX_DT_FORMAT_REG(n) (0x84 + (n) * 8) | |
| 48 | +#define CSI2TX_DT_FORMAT_BYTES_PER_LINE(n) (((n) & 0xffff) << 16) | |
| 49 | +#define CSI2TX_DT_FORMAT_MAX_LINE_NUM(n) ((n) & 0xffff) | |
| 50 | + | |
| 51 | +#define CSI2TX_STREAM_IF_CFG_REG(n) (0x100 + (n) * 4) | |
| 52 | +#define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n) ((n) & 0x1f) | |
| 53 | + | |
| 54 | +#define CSI2TX_LANES_MAX 4 | |
| 55 | +#define CSI2TX_STREAMS_MAX 4 | |
| 56 | + | |
| 57 | +enum csi2tx_pads { | |
| 58 | + CSI2TX_PAD_SOURCE, | |
| 59 | + CSI2TX_PAD_SINK_STREAM0, | |
| 60 | + CSI2TX_PAD_SINK_STREAM1, | |
| 61 | + CSI2TX_PAD_SINK_STREAM2, | |
| 62 | + CSI2TX_PAD_SINK_STREAM3, | |
| 63 | + CSI2TX_PAD_MAX, | |
| 64 | +}; | |
| 65 | + | |
| 66 | +struct csi2tx_fmt { | |
| 67 | + u32 mbus; | |
| 68 | + u32 dt; | |
| 69 | + u32 bpp; | |
| 70 | +}; | |
| 71 | + | |
| 72 | +struct csi2tx_priv { | |
| 73 | + struct device *dev; | |
| 74 | + unsigned int count; | |
| 75 | + | |
| 76 | + /* | |
| 77 | + * Used to prevent race conditions between multiple, | |
| 78 | + * concurrent calls to start and stop. | |
| 79 | + */ | |
| 80 | + struct mutex lock; | |
| 81 | + | |
| 82 | + void __iomem *base; | |
| 83 | + | |
| 84 | + struct clk *esc_clk; | |
| 85 | + struct clk *p_clk; | |
| 86 | + struct clk *pixel_clk[CSI2TX_STREAMS_MAX]; | |
| 87 | + | |
| 88 | + struct v4l2_subdev subdev; | |
| 89 | + struct media_pad pads[CSI2TX_PAD_MAX]; | |
| 90 | + struct v4l2_mbus_framefmt pad_fmts[CSI2TX_PAD_MAX]; | |
| 91 | + | |
| 92 | + bool has_internal_dphy; | |
| 93 | + u8 lanes[CSI2TX_LANES_MAX]; | |
| 94 | + unsigned int num_lanes; | |
| 95 | + unsigned int max_lanes; | |
| 96 | + unsigned int max_streams; | |
| 97 | +}; | |
| 98 | + | |
| 99 | +static const struct csi2tx_fmt csi2tx_formats[] = { | |
| 100 | + { | |
| 101 | + .mbus = MEDIA_BUS_FMT_UYVY8_1X16, | |
| 102 | + .bpp = 2, | |
| 103 | + .dt = 0x1e, | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + .mbus = MEDIA_BUS_FMT_RGB888_1X24, | |
| 107 | + .bpp = 3, | |
| 108 | + .dt = 0x24, | |
| 109 | + }, | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static const struct v4l2_mbus_framefmt fmt_default = { | |
| 113 | + .width = 1280, | |
| 114 | + .height = 720, | |
| 115 | + .code = MEDIA_BUS_FMT_RGB888_1X24, | |
| 116 | + .field = V4L2_FIELD_NONE, | |
| 117 | + .colorspace = V4L2_COLORSPACE_DEFAULT, | |
| 118 | +}; | |
| 119 | + | |
| 120 | +static inline | |
| 121 | +struct csi2tx_priv *v4l2_subdev_to_csi2tx(struct v4l2_subdev *subdev) | |
| 122 | +{ | |
| 123 | + return container_of(subdev, struct csi2tx_priv, subdev); | |
| 124 | +} | |
| 125 | + | |
| 126 | +static const struct csi2tx_fmt *csi2tx_get_fmt_from_mbus(u32 mbus) | |
| 127 | +{ | |
| 128 | + unsigned int i; | |
| 129 | + | |
| 130 | + for (i = 0; i < ARRAY_SIZE(csi2tx_formats); i++) | |
| 131 | + if (csi2tx_formats[i].mbus == mbus) | |
| 132 | + return &csi2tx_formats[i]; | |
| 133 | + | |
| 134 | + return NULL; | |
| 135 | +} | |
| 136 | + | |
| 137 | +static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev, | |
| 138 | + struct v4l2_subdev_pad_config *cfg, | |
| 139 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 140 | +{ | |
| 141 | + if (code->pad || code->index >= ARRAY_SIZE(csi2tx_formats)) | |
| 142 | + return -EINVAL; | |
| 143 | + | |
| 144 | + code->code = csi2tx_formats[code->index].mbus; | |
| 145 | + | |
| 146 | + return 0; | |
| 147 | +} | |
| 148 | + | |
| 149 | +static struct v4l2_mbus_framefmt * | |
| 150 | +__csi2tx_get_pad_format(struct v4l2_subdev *subdev, | |
| 151 | + struct v4l2_subdev_pad_config *cfg, | |
| 152 | + struct v4l2_subdev_format *fmt) | |
| 153 | +{ | |
| 154 | + struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev); | |
| 155 | + | |
| 156 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 157 | + return v4l2_subdev_get_try_format(subdev, cfg, | |
| 158 | + fmt->pad); | |
| 159 | + | |
| 160 | + return &csi2tx->pad_fmts[fmt->pad]; | |
| 161 | +} | |
| 162 | + | |
| 163 | +static int csi2tx_get_pad_format(struct v4l2_subdev *subdev, | |
| 164 | + struct v4l2_subdev_pad_config *cfg, | |
| 165 | + struct v4l2_subdev_format *fmt) | |
| 166 | +{ | |
| 167 | + const struct v4l2_mbus_framefmt *format; | |
| 168 | + | |
| 169 | + /* Multiplexed pad? */ | |
| 170 | + if (fmt->pad == CSI2TX_PAD_SOURCE) | |
| 171 | + return -EINVAL; | |
| 172 | + | |
| 173 | + format = __csi2tx_get_pad_format(subdev, cfg, fmt); | |
| 174 | + if (!format) | |
| 175 | + return -EINVAL; | |
| 176 | + | |
| 177 | + fmt->format = *format; | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int csi2tx_set_pad_format(struct v4l2_subdev *subdev, | |
| 183 | + struct v4l2_subdev_pad_config *cfg, | |
| 184 | + struct v4l2_subdev_format *fmt) | |
| 185 | +{ | |
| 186 | + const struct v4l2_mbus_framefmt *src_format = &fmt->format; | |
| 187 | + struct v4l2_mbus_framefmt *dst_format; | |
| 188 | + | |
| 189 | + /* Multiplexed pad? */ | |
| 190 | + if (fmt->pad == CSI2TX_PAD_SOURCE) | |
| 191 | + return -EINVAL; | |
| 192 | + | |
| 193 | + if (!csi2tx_get_fmt_from_mbus(fmt->format.code)) | |
| 194 | + src_format = &fmt_default; | |
| 195 | + | |
| 196 | + dst_format = __csi2tx_get_pad_format(subdev, cfg, fmt); | |
| 197 | + if (!dst_format) | |
| 198 | + return -EINVAL; | |
| 199 | + | |
| 200 | + *dst_format = *src_format; | |
| 201 | + | |
| 202 | + return 0; | |
| 203 | +} | |
| 204 | + | |
| 205 | +static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = { | |
| 206 | + .enum_mbus_code = csi2tx_enum_mbus_code, | |
| 207 | + .get_fmt = csi2tx_get_pad_format, | |
| 208 | + .set_fmt = csi2tx_set_pad_format, | |
| 209 | +}; | |
| 210 | + | |
| 211 | +static void csi2tx_reset(struct csi2tx_priv *csi2tx) | |
| 212 | +{ | |
| 213 | + writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); | |
| 214 | + | |
| 215 | + udelay(10); | |
| 216 | +} | |
| 217 | + | |
| 218 | +static int csi2tx_start(struct csi2tx_priv *csi2tx) | |
| 219 | +{ | |
| 220 | + struct media_entity *entity = &csi2tx->subdev.entity; | |
| 221 | + struct media_link *link; | |
| 222 | + unsigned int i; | |
| 223 | + u32 reg; | |
| 224 | + | |
| 225 | + csi2tx_reset(csi2tx); | |
| 226 | + | |
| 227 | + writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); | |
| 228 | + | |
| 229 | + udelay(10); | |
| 230 | + | |
| 231 | + /* Configure our PPI interface with the D-PHY */ | |
| 232 | + writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32), | |
| 233 | + csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); | |
| 234 | + | |
| 235 | + /* Put our lanes (clock and data) out of reset */ | |
| 236 | + reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT; | |
| 237 | + for (i = 0; i < csi2tx->num_lanes; i++) | |
| 238 | + reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i]); | |
| 239 | + writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); | |
| 240 | + | |
| 241 | + udelay(10); | |
| 242 | + | |
| 243 | + /* Enable our (clock and data) lanes */ | |
| 244 | + reg |= CSI2TX_DPHY_CFG_CLK_ENABLE; | |
| 245 | + for (i = 0; i < csi2tx->num_lanes; i++) | |
| 246 | + reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i]); | |
| 247 | + writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); | |
| 248 | + | |
| 249 | + udelay(10); | |
| 250 | + | |
| 251 | + /* Switch to HS mode */ | |
| 252 | + reg &= ~CSI2TX_DPHY_CFG_MODE_MASK; | |
| 253 | + writel(reg | CSI2TX_DPHY_CFG_MODE_HS, | |
| 254 | + csi2tx->base + CSI2TX_DPHY_CFG_REG); | |
| 255 | + | |
| 256 | + udelay(10); | |
| 257 | + | |
| 258 | + /* | |
| 259 | + * Create a static mapping between the CSI virtual channels | |
| 260 | + * and the input streams. | |
| 261 | + * | |
| 262 | + * This should be enhanced, but v4l2 lacks the support for | |
| 263 | + * changing that mapping dynamically at the moment. | |
| 264 | + * | |
| 265 | + * We're protected from the userspace setting up links at the | |
| 266 | + * same time by the upper layer having called | |
| 267 | + * media_pipeline_start(). | |
| 268 | + */ | |
| 269 | + list_for_each_entry(link, &entity->links, list) { | |
| 270 | + struct v4l2_mbus_framefmt *mfmt; | |
| 271 | + const struct csi2tx_fmt *fmt; | |
| 272 | + unsigned int stream; | |
| 273 | + int pad_idx = -1; | |
| 274 | + | |
| 275 | + /* Only consider our enabled input pads */ | |
| 276 | + for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++) { | |
| 277 | + struct media_pad *pad = &csi2tx->pads[i]; | |
| 278 | + | |
| 279 | + if ((pad == link->sink) && | |
| 280 | + (link->flags & MEDIA_LNK_FL_ENABLED)) { | |
| 281 | + pad_idx = i; | |
| 282 | + break; | |
| 283 | + } | |
| 284 | + } | |
| 285 | + | |
| 286 | + if (pad_idx < 0) | |
| 287 | + continue; | |
| 288 | + | |
| 289 | + mfmt = &csi2tx->pad_fmts[pad_idx]; | |
| 290 | + fmt = csi2tx_get_fmt_from_mbus(mfmt->code); | |
| 291 | + if (!fmt) | |
| 292 | + continue; | |
| 293 | + | |
| 294 | + stream = pad_idx - CSI2TX_PAD_SINK_STREAM0; | |
| 295 | + | |
| 296 | + /* | |
| 297 | + * We use the stream ID there, but it's wrong. | |
| 298 | + * | |
| 299 | + * A stream could very well send a data type that is | |
| 300 | + * not equal to its stream ID. We need to find a | |
| 301 | + * proper way to address it. | |
| 302 | + */ | |
| 303 | + writel(CSI2TX_DT_CFG_DT(fmt->dt), | |
| 304 | + csi2tx->base + CSI2TX_DT_CFG_REG(stream)); | |
| 305 | + | |
| 306 | + writel(CSI2TX_DT_FORMAT_BYTES_PER_LINE(mfmt->width * fmt->bpp) | | |
| 307 | + CSI2TX_DT_FORMAT_MAX_LINE_NUM(mfmt->height + 1), | |
| 308 | + csi2tx->base + CSI2TX_DT_FORMAT_REG(stream)); | |
| 309 | + | |
| 310 | + /* | |
| 311 | + * TODO: This needs to be calculated based on the | |
| 312 | + * output CSI2 clock rate. | |
| 313 | + */ | |
| 314 | + writel(CSI2TX_STREAM_IF_CFG_FILL_LEVEL(4), | |
| 315 | + csi2tx->base + CSI2TX_STREAM_IF_CFG_REG(stream)); | |
| 316 | + } | |
| 317 | + | |
| 318 | + /* Disable the configuration mode */ | |
| 319 | + writel(0, csi2tx->base + CSI2TX_CONFIG_REG); | |
| 320 | + | |
| 321 | + return 0; | |
| 322 | +} | |
| 323 | + | |
| 324 | +static void csi2tx_stop(struct csi2tx_priv *csi2tx) | |
| 325 | +{ | |
| 326 | + writel(CSI2TX_CONFIG_CFG_REQ | CSI2TX_CONFIG_SRST_REQ, | |
| 327 | + csi2tx->base + CSI2TX_CONFIG_REG); | |
| 328 | +} | |
| 329 | + | |
| 330 | +static int csi2tx_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 331 | +{ | |
| 332 | + struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev); | |
| 333 | + int ret = 0; | |
| 334 | + | |
| 335 | + mutex_lock(&csi2tx->lock); | |
| 336 | + | |
| 337 | + if (enable) { | |
| 338 | + /* | |
| 339 | + * If we're not the first users, there's no need to | |
| 340 | + * enable the whole controller. | |
| 341 | + */ | |
| 342 | + if (!csi2tx->count) { | |
| 343 | + ret = csi2tx_start(csi2tx); | |
| 344 | + if (ret) | |
| 345 | + goto out; | |
| 346 | + } | |
| 347 | + | |
| 348 | + csi2tx->count++; | |
| 349 | + } else { | |
| 350 | + csi2tx->count--; | |
| 351 | + | |
| 352 | + /* | |
| 353 | + * Let the last user turn off the lights. | |
| 354 | + */ | |
| 355 | + if (!csi2tx->count) | |
| 356 | + csi2tx_stop(csi2tx); | |
| 357 | + } | |
| 358 | + | |
| 359 | +out: | |
| 360 | + mutex_unlock(&csi2tx->lock); | |
| 361 | + return ret; | |
| 362 | +} | |
| 363 | + | |
| 364 | +static const struct v4l2_subdev_video_ops csi2tx_video_ops = { | |
| 365 | + .s_stream = csi2tx_s_stream, | |
| 366 | +}; | |
| 367 | + | |
| 368 | +static const struct v4l2_subdev_ops csi2tx_subdev_ops = { | |
| 369 | + .pad = &csi2tx_pad_ops, | |
| 370 | + .video = &csi2tx_video_ops, | |
| 371 | +}; | |
| 372 | + | |
| 373 | +static int csi2tx_get_resources(struct csi2tx_priv *csi2tx, | |
| 374 | + struct platform_device *pdev) | |
| 375 | +{ | |
| 376 | + struct resource *res; | |
| 377 | + unsigned int i; | |
| 378 | + u32 dev_cfg; | |
| 379 | + | |
| 380 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 381 | + csi2tx->base = devm_ioremap_resource(&pdev->dev, res); | |
| 382 | + if (IS_ERR(csi2tx->base)) | |
| 383 | + return PTR_ERR(csi2tx->base); | |
| 384 | + | |
| 385 | + csi2tx->p_clk = devm_clk_get(&pdev->dev, "p_clk"); | |
| 386 | + if (IS_ERR(csi2tx->p_clk)) { | |
| 387 | + dev_err(&pdev->dev, "Couldn't get p_clk\n"); | |
| 388 | + return PTR_ERR(csi2tx->p_clk); | |
| 389 | + } | |
| 390 | + | |
| 391 | + csi2tx->esc_clk = devm_clk_get(&pdev->dev, "esc_clk"); | |
| 392 | + if (IS_ERR(csi2tx->esc_clk)) { | |
| 393 | + dev_err(&pdev->dev, "Couldn't get the esc_clk\n"); | |
| 394 | + return PTR_ERR(csi2tx->esc_clk); | |
| 395 | + } | |
| 396 | + | |
| 397 | + clk_prepare_enable(csi2tx->p_clk); | |
| 398 | + dev_cfg = readl(csi2tx->base + CSI2TX_DEVICE_CONFIG_REG); | |
| 399 | + clk_disable_unprepare(csi2tx->p_clk); | |
| 400 | + | |
| 401 | + csi2tx->max_lanes = dev_cfg & CSI2TX_DEVICE_CONFIG_LANES_MASK; | |
| 402 | + if (csi2tx->max_lanes > CSI2TX_LANES_MAX) { | |
| 403 | + dev_err(&pdev->dev, "Invalid number of lanes: %u\n", | |
| 404 | + csi2tx->max_lanes); | |
| 405 | + return -EINVAL; | |
| 406 | + } | |
| 407 | + | |
| 408 | + csi2tx->max_streams = (dev_cfg & CSI2TX_DEVICE_CONFIG_STREAMS_MASK) >> 4; | |
| 409 | + if (csi2tx->max_streams > CSI2TX_STREAMS_MAX) { | |
| 410 | + dev_err(&pdev->dev, "Invalid number of streams: %u\n", | |
| 411 | + csi2tx->max_streams); | |
| 412 | + return -EINVAL; | |
| 413 | + } | |
| 414 | + | |
| 415 | + csi2tx->has_internal_dphy = !!(dev_cfg & CSI2TX_DEVICE_CONFIG_HAS_DPHY); | |
| 416 | + | |
| 417 | + for (i = 0; i < csi2tx->max_streams; i++) { | |
| 418 | + char clk_name[16]; | |
| 419 | + | |
| 420 | + snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); | |
| 421 | + csi2tx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); | |
| 422 | + if (IS_ERR(csi2tx->pixel_clk[i])) { | |
| 423 | + dev_err(&pdev->dev, "Couldn't get clock %s\n", | |
| 424 | + clk_name); | |
| 425 | + return PTR_ERR(csi2tx->pixel_clk[i]); | |
| 426 | + } | |
| 427 | + } | |
| 428 | + | |
| 429 | + return 0; | |
| 430 | +} | |
| 431 | + | |
| 432 | +static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) | |
| 433 | +{ | |
| 434 | + struct v4l2_fwnode_endpoint v4l2_ep; | |
| 435 | + struct device_node *ep; | |
| 436 | + int ret; | |
| 437 | + | |
| 438 | + ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0); | |
| 439 | + if (!ep) | |
| 440 | + return -EINVAL; | |
| 441 | + | |
| 442 | + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); | |
| 443 | + if (ret) { | |
| 444 | + dev_err(csi2tx->dev, "Could not parse v4l2 endpoint\n"); | |
| 445 | + goto out; | |
| 446 | + } | |
| 447 | + | |
| 448 | + if (v4l2_ep.bus_type != V4L2_MBUS_CSI2) { | |
| 449 | + dev_err(csi2tx->dev, "Unsupported media bus type: 0x%x\n", | |
| 450 | + v4l2_ep.bus_type); | |
| 451 | + ret = -EINVAL; | |
| 452 | + goto out; | |
| 453 | + } | |
| 454 | + | |
| 455 | + csi2tx->num_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; | |
| 456 | + if (csi2tx->num_lanes > csi2tx->max_lanes) { | |
| 457 | + dev_err(csi2tx->dev, | |
| 458 | + "Current configuration uses more lanes than supported\n"); | |
| 459 | + ret = -EINVAL; | |
| 460 | + goto out; | |
| 461 | + } | |
| 462 | + | |
| 463 | + memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, | |
| 464 | + sizeof(csi2tx->lanes)); | |
| 465 | + | |
| 466 | +out: | |
| 467 | + of_node_put(ep); | |
| 468 | + return ret; | |
| 469 | +} | |
| 470 | + | |
| 471 | +static int csi2tx_probe(struct platform_device *pdev) | |
| 472 | +{ | |
| 473 | + struct csi2tx_priv *csi2tx; | |
| 474 | + unsigned int i; | |
| 475 | + int ret; | |
| 476 | + | |
| 477 | + csi2tx = kzalloc(sizeof(*csi2tx), GFP_KERNEL); | |
| 478 | + if (!csi2tx) | |
| 479 | + return -ENOMEM; | |
| 480 | + platform_set_drvdata(pdev, csi2tx); | |
| 481 | + mutex_init(&csi2tx->lock); | |
| 482 | + csi2tx->dev = &pdev->dev; | |
| 483 | + | |
| 484 | + ret = csi2tx_get_resources(csi2tx, pdev); | |
| 485 | + if (ret) | |
| 486 | + goto err_free_priv; | |
| 487 | + | |
| 488 | + v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops); | |
| 489 | + csi2tx->subdev.owner = THIS_MODULE; | |
| 490 | + csi2tx->subdev.dev = &pdev->dev; | |
| 491 | + csi2tx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 492 | + snprintf(csi2tx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", | |
| 493 | + KBUILD_MODNAME, dev_name(&pdev->dev)); | |
| 494 | + | |
| 495 | + ret = csi2tx_check_lanes(csi2tx); | |
| 496 | + if (ret) | |
| 497 | + goto err_free_priv; | |
| 498 | + | |
| 499 | + /* Create our media pads */ | |
| 500 | + csi2tx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | |
| 501 | + csi2tx->pads[CSI2TX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | |
| 502 | + for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++) | |
| 503 | + csi2tx->pads[i].flags = MEDIA_PAD_FL_SINK; | |
| 504 | + | |
| 505 | + /* | |
| 506 | + * Only the input pads are considered to have a format at the | |
| 507 | + * moment. The CSI link can multiplex various streams with | |
| 508 | + * different formats, and we can't expose this in v4l2 right | |
| 509 | + * now. | |
| 510 | + */ | |
| 511 | + for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++) | |
| 512 | + csi2tx->pad_fmts[i] = fmt_default; | |
| 513 | + | |
| 514 | + ret = media_entity_pads_init(&csi2tx->subdev.entity, CSI2TX_PAD_MAX, | |
| 515 | + csi2tx->pads); | |
| 516 | + if (ret) | |
| 517 | + goto err_free_priv; | |
| 518 | + | |
| 519 | + ret = v4l2_async_register_subdev(&csi2tx->subdev); | |
| 520 | + if (ret < 0) | |
| 521 | + goto err_free_priv; | |
| 522 | + | |
| 523 | + dev_info(&pdev->dev, | |
| 524 | + "Probed CSI2TX with %u/%u lanes, %u streams, %s D-PHY\n", | |
| 525 | + csi2tx->num_lanes, csi2tx->max_lanes, csi2tx->max_streams, | |
| 526 | + csi2tx->has_internal_dphy ? "internal" : "no"); | |
| 527 | + | |
| 528 | + return 0; | |
| 529 | + | |
| 530 | +err_free_priv: | |
| 531 | + kfree(csi2tx); | |
| 532 | + return ret; | |
| 533 | +} | |
| 534 | + | |
| 535 | +static int csi2tx_remove(struct platform_device *pdev) | |
| 536 | +{ | |
| 537 | + struct csi2tx_priv *csi2tx = platform_get_drvdata(pdev); | |
| 538 | + | |
| 539 | + v4l2_async_unregister_subdev(&csi2tx->subdev); | |
| 540 | + kfree(csi2tx); | |
| 541 | + | |
| 542 | + return 0; | |
| 543 | +} | |
| 544 | + | |
| 545 | +static const struct of_device_id csi2tx_of_table[] = { | |
| 546 | + { .compatible = "cdns,csi2tx" }, | |
| 547 | + { }, | |
| 548 | +}; | |
| 549 | +MODULE_DEVICE_TABLE(of, csi2tx_of_table); | |
| 550 | + | |
| 551 | +static struct platform_driver csi2tx_driver = { | |
| 552 | + .probe = csi2tx_probe, | |
| 553 | + .remove = csi2tx_remove, | |
| 554 | + | |
| 555 | + .driver = { | |
| 556 | + .name = "cdns-csi2tx", | |
| 557 | + .of_match_table = csi2tx_of_table, | |
| 558 | + }, | |
| 559 | +}; | |
| 560 | +module_platform_driver(csi2tx_driver); | |
| 561 | +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); | |
| 562 | +MODULE_DESCRIPTION("Cadence CSI2-TX controller"); | |
| 563 | +MODULE_LICENSE("GPL"); | |
| @@ -158,7 +158,7 @@ static int cec_gpio_probe(struct platform_device *pdev) · 157 unmodified lines | ||
| 158 | 158 | |
| 159 | 159 | cec->dev = dev; |
| 160 | 160 | |
| 161 | − cec->cec_gpio = devm_gpiod_get(dev, "cec", GPIOD_IN); | |
| 161 | + cec->cec_gpio = devm_gpiod_get(dev, "cec", GPIOD_OUT_HIGH_OPEN_DRAIN); | |
| 162 | 162 | if (IS_ERR(cec->cec_gpio)) |
| 163 | 163 | return PTR_ERR(cec->cec_gpio); |
| 164 | 164 | cec->cec_irq = gpiod_to_irq(cec->cec_gpio); |
| @@ -779,16 +779,27 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, · 778 unmodified lines | ||
| 779 | 779 | r.width = q_data_src->width; |
| 780 | 780 | r.height = q_data_src->height; |
| 781 | 781 | |
| 782 | − return coda_s_fmt(ctx, f, &r); | |
| 782 | + ret = coda_s_fmt(ctx, f, &r); | |
| 783 | + if (ret) | |
| 784 | + return ret; | |
| 785 | + | |
| 786 | + if (ctx->inst_type != CODA_INST_ENCODER) | |
| 787 | + return 0; | |
| 788 | + | |
| 789 | + ctx->colorspace = f->fmt.pix.colorspace; | |
| 790 | + ctx->xfer_func = f->fmt.pix.xfer_func; | |
| 791 | + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; | |
| 792 | + ctx->quantization = f->fmt.pix.quantization; | |
| 793 | + | |
| 794 | + return 0; | |
| 783 | 795 | } |
| 784 | 796 | |
| 785 | 797 | static int coda_s_fmt_vid_out(struct file *file, void *priv, |
| 786 | 798 | struct v4l2_format *f) |
| 787 | 799 | { |
| 788 | 800 | struct coda_ctx *ctx = fh_to_ctx(priv); |
| 789 | − struct coda_q_data *q_data_src; | |
| 790 | 801 | struct v4l2_format f_cap; |
| 791 | − struct v4l2_rect r; | |
| 802 | + struct vb2_queue *dst_vq; | |
| 792 | 803 | int ret; |
| 793 | 804 | |
| 794 | 805 | ret = coda_try_fmt_vid_out(file, priv, f); |
| @@ -799,28 +810,34 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, · 4 unmodified lines | ||
| 799 | 810 | if (ret) |
| 800 | 811 | return ret; |
| 801 | 812 | |
| 813 | + if (ctx->inst_type != CODA_INST_DECODER) | |
| 814 | + return 0; | |
| 815 | + | |
| 802 | 816 | ctx->colorspace = f->fmt.pix.colorspace; |
| 803 | 817 | ctx->xfer_func = f->fmt.pix.xfer_func; |
| 804 | 818 | ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; |
| 805 | 819 | ctx->quantization = f->fmt.pix.quantization; |
| 806 | 820 | |
| 821 | + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | |
| 822 | + if (!dst_vq) | |
| 823 | + return -EINVAL; | |
| 824 | + | |
| 825 | + /* | |
| 826 | + * Setting the capture queue format is not possible while the capture | |
| 827 | + * queue is still busy. This is not an error, but the user will have to | |
| 828 | + * make sure themselves that the capture format is set correctly before | |
| 829 | + * starting the output queue again. | |
| 830 | + */ | |
| 831 | + if (vb2_is_busy(dst_vq)) | |
| 832 | + return 0; | |
| 833 | + | |
| 807 | 834 | memset(&f_cap, 0, sizeof(f_cap)); |
| 808 | 835 | f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 809 | 836 | coda_g_fmt(file, priv, &f_cap); |
| 810 | 837 | f_cap.fmt.pix.width = f->fmt.pix.width; |
| 811 | 838 | f_cap.fmt.pix.height = f->fmt.pix.height; |
| 812 | 839 | |
| 813 | − ret = coda_try_fmt_vid_cap(file, priv, &f_cap); | |
| 814 | − if (ret) | |
| 815 | − return ret; | |
| 816 | − | |
| 817 | − q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | |
| 818 | − r.left = 0; | |
| 819 | − r.top = 0; | |
| 820 | − r.width = q_data_src->width; | |
| 821 | − r.height = q_data_src->height; | |
| 822 | − | |
| 823 | − return coda_s_fmt(ctx, &f_cap, &r); | |
| 840 | + return coda_s_fmt_vid_cap(file, priv, &f_cap); | |
| 824 | 841 | } |
| 825 | 842 | |
| 826 | 843 | static int coda_reqbufs(struct file *file, void *priv, |
| @@ -2,7 +2,6 @@ config VIDEO_DAVINCI_VPIF_DISPLAY · 1 unmodified line | ||
| 2 | 2 | tristate "TI DaVinci VPIF V4L2-Display driver" |
| 3 | 3 | depends on VIDEO_V4L2 |
| 4 | 4 | depends on ARCH_DAVINCI || COMPILE_TEST |
| 5 | − depends on HAS_DMA | |
| 6 | 5 | depends on I2C |
| 7 | 6 | select VIDEOBUF2_DMA_CONTIG |
| 8 | 7 | select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT |
| @@ -19,7 +18,6 @@ config VIDEO_DAVINCI_VPIF_CAPTURE · 10 unmodified lines | ||
| 19 | 18 | tristate "TI DaVinci VPIF video capture driver" |
| 20 | 19 | depends on VIDEO_V4L2 |
| 21 | 20 | depends on ARCH_DAVINCI || COMPILE_TEST |
| 22 | − depends on HAS_DMA | |
| 23 | 21 | depends on I2C |
| 24 | 22 | select VIDEOBUF2_DMA_CONTIG |
| 25 | 23 | select V4L2_FWNODE |
| @@ -35,7 +33,6 @@ config VIDEO_DM6446_CCDC · 9 unmodified lines | ||
| 35 | 33 | tristate "TI DM6446 CCDC video capture driver" |
| 36 | 34 | depends on VIDEO_V4L2 |
| 37 | 35 | depends on ARCH_DAVINCI || COMPILE_TEST |
| 38 | − depends on HAS_DMA | |
| 39 | 36 | depends on I2C |
| 40 | 37 | select VIDEOBUF_DMA_CONTIG |
| 41 | 38 | help |
| @@ -52,7 +49,6 @@ config VIDEO_DM355_CCDC · 10 unmodified lines | ||
| 52 | 49 | tristate "TI DM355 CCDC video capture driver" |
| 53 | 50 | depends on VIDEO_V4L2 |
| 54 | 51 | depends on ARCH_DAVINCI || COMPILE_TEST |
| 55 | − depends on HAS_DMA | |
| 56 | 52 | depends on I2C |
| 57 | 53 | select VIDEOBUF_DMA_CONTIG |
| 58 | 54 | help |
| @@ -67,8 +63,8 @@ config VIDEO_DM355_CCDC · 8 unmodified lines | ||
| 67 | 63 | |
| 68 | 64 | config VIDEO_DM365_ISIF |
| 69 | 65 | tristate "TI DM365 ISIF video capture driver" |
| 70 | − depends on VIDEO_V4L2 && ARCH_DAVINCI | |
| 71 | − depends on HAS_DMA | |
| 66 | + depends on VIDEO_V4L2 | |
| 67 | + depends on ARCH_DAVINCI || COMPILE_TEST | |
| 72 | 68 | depends on I2C |
| 73 | 69 | select VIDEOBUF_DMA_CONTIG |
| 74 | 70 | help |
| @@ -81,8 +77,8 @@ config VIDEO_DM365_ISIF · 6 unmodified lines | ||
| 81 | 77 | |
| 82 | 78 | config VIDEO_DAVINCI_VPBE_DISPLAY |
| 83 | 79 | tristate "TI DaVinci VPBE V4L2-Display driver" |
| 84 | − depends on VIDEO_V4L2 && ARCH_DAVINCI | |
| 85 | − depends on HAS_DMA | |
| 80 | + depends on VIDEO_V4L2 | |
| 81 | + depends on ARCH_DAVINCI || COMPILE_TEST | |
| 86 | 82 | depends on I2C |
| 87 | 83 | select VIDEOBUF2_DMA_CONTIG |
| 88 | 84 | help |
| @@ -31,8 +31,6 @@ · 30 unmodified lines | ||
| 31 | 31 | #include <linux/err.h> |
| 32 | 32 | #include <linux/module.h> |
| 33 | 33 | |
| 34 | −#include <mach/mux.h> | |
| 35 | − | |
| 36 | 34 | #include <media/davinci/isif.h> |
| 37 | 35 | #include <media/davinci/vpss.h> |
| 38 | 36 | |
| @@ -1029,7 +1027,7 @@ static int isif_probe(struct platform_device *pdev) · 990 unmodified lines | ||
| 1029 | 1027 | { |
| 1030 | 1028 | void (*setup_pinmux)(void); |
| 1031 | 1029 | struct resource *res; |
| 1032 | − void *__iomem addr; | |
| 1030 | + void __iomem *addr; | |
| 1033 | 1031 | int status = 0, i; |
| 1034 | 1032 | |
| 1035 | 1033 | /* Platform data holds setup_pinmux function ptr */ |
| @@ -51,7 +51,7 @@ MODULE_AUTHOR("Texas Instruments"); · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | 53 | * vpbe_current_encoder_info - Get config info for current encoder |
| 54 | − * @vpbe_dev - vpbe device ptr | |
| 54 | + * @vpbe_dev: vpbe device ptr | |
| 55 | 55 | * |
| 56 | 56 | * Return ptr to current encoder config info |
| 57 | 57 | */ |
| @@ -68,8 +68,8 @@ vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) · 10 unmodified lines | ||
| 68 | 68 | /** |
| 69 | 69 | * vpbe_find_encoder_sd_index - Given a name find encoder sd index |
| 70 | 70 | * |
| 71 | − * @vpbe_config - ptr to vpbe cfg | |
| 72 | − * @output_index - index used by application | |
| 71 | + * @cfg: ptr to vpbe cfg | |
| 72 | + * @index: index used by application | |
| 73 | 73 | * |
| 74 | 74 | * Return sd index of the encoder |
| 75 | 75 | */ |
| @@ -94,8 +94,8 @@ static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, · 18 unmodified lines | ||
| 94 | 94 | |
| 95 | 95 | /** |
| 96 | 96 | * vpbe_g_cropcap - Get crop capabilities of the display |
| 97 | − * @vpbe_dev - vpbe device ptr | |
| 98 | − * @cropcap - cropcap is a ptr to struct v4l2_cropcap | |
| 97 | + * @vpbe_dev: vpbe device ptr | |
| 98 | + * @cropcap: cropcap is a ptr to struct v4l2_cropcap | |
| 99 | 99 | * |
| 100 | 100 | * Update the crop capabilities in crop cap for current |
| 101 | 101 | * mode |
| @@ -116,8 +116,8 @@ static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, · 14 unmodified lines | ||
| 116 | 116 | |
| 117 | 117 | /** |
| 118 | 118 | * vpbe_enum_outputs - enumerate outputs |
| 119 | − * @vpbe_dev - vpbe device ptr | |
| 120 | − * @output - ptr to v4l2_output structure | |
| 119 | + * @vpbe_dev: vpbe device ptr | |
| 120 | + * @output: ptr to v4l2_output structure | |
| 121 | 121 | * |
| 122 | 122 | * Enumerates the outputs available at the vpbe display |
| 123 | 123 | * returns the status, -EINVAL if end of output list |
| @@ -212,8 +212,8 @@ static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, · 88 unmodified lines | ||
| 212 | 212 | |
| 213 | 213 | /** |
| 214 | 214 | * vpbe_set_output - Set output |
| 215 | − * @vpbe_dev - vpbe device ptr | |
| 216 | − * @index - index of output | |
| 215 | + * @vpbe_dev: vpbe device ptr | |
| 216 | + * @index: index of output | |
| 217 | 217 | * |
| 218 | 218 | * Set vpbe output to the output specified by the index |
| 219 | 219 | */ |
| @@ -308,7 +308,7 @@ static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) · 88 unmodified lines | ||
| 308 | 308 | |
| 309 | 309 | /** |
| 310 | 310 | * vpbe_get_output - Get output |
| 311 | − * @vpbe_dev - vpbe device ptr | |
| 311 | + * @vpbe_dev: vpbe device ptr | |
| 312 | 312 | * |
| 313 | 313 | * return current vpbe output to the the index |
| 314 | 314 | */ |
| @@ -317,7 +317,7 @@ static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) · 2 unmodified lines | ||
| 317 | 317 | return vpbe_dev->current_out_index; |
| 318 | 318 | } |
| 319 | 319 | |
| 320 | −/** | |
| 320 | +/* | |
| 321 | 321 | * vpbe_s_dv_timings - Set the given preset timings in the encoder |
| 322 | 322 | * |
| 323 | 323 | * Sets the timings if supported by the current encoder. Return the status. |
| @@ -369,7 +369,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, · 45 unmodified lines | ||
| 369 | 369 | return ret; |
| 370 | 370 | } |
| 371 | 371 | |
| 372 | −/** | |
| 372 | +/* | |
| 373 | 373 | * vpbe_g_dv_timings - Get the timings in the current encoder |
| 374 | 374 | * |
| 375 | 375 | * Get the timings in the current encoder. Return the status. 0 - success |
| @@ -394,7 +394,7 @@ static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, · 18 unmodified lines | ||
| 394 | 394 | return -EINVAL; |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | −/** | |
| 397 | +/* | |
| 398 | 398 | * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder |
| 399 | 399 | * |
| 400 | 400 | * Get the timings in the current encoder. Return the status. 0 - success |
| @@ -426,7 +426,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, · 25 unmodified lines | ||
| 426 | 426 | return 0; |
| 427 | 427 | } |
| 428 | 428 | |
| 429 | −/** | |
| 429 | +/* | |
| 430 | 430 | * vpbe_s_std - Set the given standard in the encoder |
| 431 | 431 | * |
| 432 | 432 | * Sets the standard if supported by the current encoder. Return the status. |
| @@ -465,7 +465,7 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) · 32 unmodified lines | ||
| 465 | 465 | return ret; |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | −/** | |
| 468 | +/* | |
| 469 | 469 | * vpbe_g_std - Get the standard in the current encoder |
| 470 | 470 | * |
| 471 | 471 | * Get the standard in the current encoder. Return the status. 0 - success |
| @@ -488,7 +488,7 @@ static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) · 16 unmodified lines | ||
| 488 | 488 | return -EINVAL; |
| 489 | 489 | } |
| 490 | 490 | |
| 491 | −/** | |
| 491 | +/* | |
| 492 | 492 | * vpbe_set_mode - Set mode in the current encoder using mode info |
| 493 | 493 | * |
| 494 | 494 | * Use the mode string to decide what timings to set in the encoder |
| @@ -572,7 +572,8 @@ static int platform_device_get(struct device *dev, void *data) · 77 unmodified lines | ||
| 572 | 572 | |
| 573 | 573 | /** |
| 574 | 574 | * vpbe_initialize() - Initialize the vpbe display controller |
| 575 | − * @vpbe_dev - vpbe device ptr | |
| 575 | + * @dev: Master and slave device ptr | |
| 576 | + * @vpbe_dev: vpbe device ptr | |
| 576 | 577 | * |
| 577 | 578 | * Master frame buffer device drivers calls this to initialize vpbe |
| 578 | 579 | * display controller. This will then registers v4l2 device and the sub |
| @@ -769,7 +770,8 @@ fail_mutex_unlock: · 190 unmodified lines | ||
| 769 | 770 | |
| 770 | 771 | /** |
| 771 | 772 | * vpbe_deinitialize() - de-initialize the vpbe display controller |
| 772 | − * @dev - Master and slave device ptr | |
| 773 | + * @dev: Master and slave device ptr | |
| 774 | + * @vpbe_dev: vpbe device ptr | |
| 773 | 775 | * |
| 774 | 776 | * vpbe_master and slave frame buffer devices calls this to de-initialize |
| 775 | 777 | * the display controller. It is called when master and slave device |
| @@ -26,7 +26,10 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/slab.h> |
| 27 | 27 | |
| 28 | 28 | #include <asm/pgtable.h> |
| 29 | + | |
| 30 | +#ifdef CONFIG_ARCH_DAVINCI | |
| 29 | 31 | #include <mach/cputype.h> |
| 32 | +#endif | |
| 30 | 33 | |
| 31 | 34 | #include <media/v4l2-dev.h> |
| 32 | 35 | #include <media/v4l2-common.h> |
| @@ -53,8 +56,7 @@ static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, · 20 unmodified lines | ||
| 53 | 56 | static int venc_is_second_field(struct vpbe_display *disp_dev) |
| 54 | 57 | { |
| 55 | 58 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; |
| 56 | − int ret; | |
| 57 | − int val; | |
| 59 | + int ret, val; | |
| 58 | 60 | |
| 59 | 61 | ret = v4l2_subdev_call(vpbe_dev->venc, |
| 60 | 62 | core, |
| @@ -64,6 +66,7 @@ static int venc_is_second_field(struct vpbe_display *disp_dev) · 3 unmodified lines | ||
| 64 | 66 | if (ret < 0) { |
| 65 | 67 | v4l2_err(&vpbe_dev->v4l2_dev, |
| 66 | 68 | "Error in getting Field ID 0\n"); |
| 69 | + return 1; | |
| 67 | 70 | } |
| 68 | 71 | return val; |
| 69 | 72 | } |
| @@ -282,7 +285,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) · 212 unmodified lines | ||
| 282 | 285 | struct osd_state *osd_device = layer->disp_dev->osd_device; |
| 283 | 286 | int ret; |
| 284 | 287 | |
| 285 | − osd_device->ops.disable_layer(osd_device, layer->layer_info.id); | |
| 288 | + osd_device->ops.disable_layer(osd_device, layer->layer_info.id); | |
| 286 | 289 | |
| 287 | 290 | /* Get the next frame from the buffer queue */ |
| 288 | 291 | layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, |
| @@ -564,7 +567,7 @@ static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, · 275 unmodified lines | ||
| 564 | 567 | |
| 565 | 568 | } |
| 566 | 569 | |
| 567 | −/** | |
| 570 | +/* | |
| 568 | 571 | * vpbe_try_format() |
| 569 | 572 | * If user application provides width and height, and have bytesperline set |
| 570 | 573 | * to zero, driver calculates bytesperline and sizeimage based on hardware |
| @@ -929,7 +932,7 @@ static int vpbe_display_try_fmt(struct file *file, void *priv, · 358 unmodified lines | ||
| 929 | 932 | |
| 930 | 933 | } |
| 931 | 934 | |
| 932 | −/** | |
| 935 | +/* | |
| 933 | 936 | * vpbe_display_s_std - Set the given standard in the encoder |
| 934 | 937 | * |
| 935 | 938 | * Sets the standard if supported by the current encoder. Return the status. |
| @@ -961,7 +964,7 @@ static int vpbe_display_s_std(struct file *file, void *priv, · 25 unmodified lines | ||
| 961 | 964 | return 0; |
| 962 | 965 | } |
| 963 | 966 | |
| 964 | −/** | |
| 967 | +/* | |
| 965 | 968 | * vpbe_display_g_std - Get the standard in the current encoder |
| 966 | 969 | * |
| 967 | 970 | * Get the standard in the current encoder. Return the status. 0 - success |
| @@ -984,7 +987,7 @@ static int vpbe_display_g_std(struct file *file, void *priv, · 16 unmodified lines | ||
| 984 | 987 | return -EINVAL; |
| 985 | 988 | } |
| 986 | 989 | |
| 987 | −/** | |
| 990 | +/* | |
| 988 | 991 | * vpbe_display_enum_output - enumerate outputs |
| 989 | 992 | * |
| 990 | 993 | * Enumerates the outputs available at the vpbe display |
| @@ -1013,7 +1016,7 @@ static int vpbe_display_enum_output(struct file *file, void *priv, · 22 unmodified lines | ||
| 1013 | 1016 | return 0; |
| 1014 | 1017 | } |
| 1015 | 1018 | |
| 1016 | −/** | |
| 1019 | +/* | |
| 1017 | 1020 | * vpbe_display_s_output - Set output to |
| 1018 | 1021 | * the output specified by the index |
| 1019 | 1022 | */ |
| @@ -1042,7 +1045,7 @@ static int vpbe_display_s_output(struct file *file, void *priv, · 22 unmodified lines | ||
| 1042 | 1045 | return 0; |
| 1043 | 1046 | } |
| 1044 | 1047 | |
| 1045 | −/** | |
| 1048 | +/* | |
| 1046 | 1049 | * vpbe_display_g_output - Get output from subdevice |
| 1047 | 1050 | * for a given by the index |
| 1048 | 1051 | */ |
| @@ -1059,7 +1062,7 @@ static int vpbe_display_g_output(struct file *file, void *priv, · 10 unmodified lines | ||
| 1059 | 1062 | return 0; |
| 1060 | 1063 | } |
| 1061 | 1064 | |
| 1062 | −/** | |
| 1065 | +/* | |
| 1063 | 1066 | * vpbe_display_enum_dv_timings - Enumerate the dv timings |
| 1064 | 1067 | * |
| 1065 | 1068 | * enum the timings in the current encoder. Return the status. 0 - success |
| @@ -1089,7 +1092,7 @@ vpbe_display_enum_dv_timings(struct file *file, void *priv, · 23 unmodified lines | ||
| 1089 | 1092 | return 0; |
| 1090 | 1093 | } |
| 1091 | 1094 | |
| 1092 | −/** | |
| 1095 | +/* | |
| 1093 | 1096 | * vpbe_display_s_dv_timings - Set the dv timings |
| 1094 | 1097 | * |
| 1095 | 1098 | * Set the timings in the current encoder. Return the status. 0 - success |
| @@ -1122,7 +1125,7 @@ vpbe_display_s_dv_timings(struct file *file, void *priv, · 26 unmodified lines | ||
| 1122 | 1125 | return 0; |
| 1123 | 1126 | } |
| 1124 | 1127 | |
| 1125 | −/** | |
| 1128 | +/* | |
| 1126 | 1129 | * vpbe_display_g_dv_timings - Set the dv timings |
| 1127 | 1130 | * |
| 1128 | 1131 | * Get the timings in the current encoder. Return the status. 0 - success |
| @@ -1351,9 +1354,9 @@ static int register_device(struct vpbe_layer *vpbe_display_layer, · 222 unmodified lines | ||
| 1351 | 1354 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, |
| 1352 | 1355 | "Trying to register VPBE display device.\n"); |
| 1353 | 1356 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, |
| 1354 | − "layer=%x,layer->video_dev=%x\n", | |
| 1355 | − (int)vpbe_display_layer, | |
| 1356 | − (int)&vpbe_display_layer->video_dev); | |
| 1357 | + "layer=%p,layer->video_dev=%p\n", | |
| 1358 | + vpbe_display_layer, | |
| 1359 | + &vpbe_display_layer->video_dev); | |
| 1357 | 1360 | |
| 1358 | 1361 | vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue; |
| 1359 | 1362 | err = video_register_device(&vpbe_display_layer->video_dev, |
| @@ -24,8 +24,10 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/clk.h> |
| 25 | 25 | #include <linux/slab.h> |
| 26 | 26 | |
| 27 | +#ifdef CONFIG_ARCH_DAVINCI | |
| 27 | 28 | #include <mach/cputype.h> |
| 28 | 29 | #include <mach/hardware.h> |
| 30 | +#endif | |
| 29 | 31 | |
| 30 | 32 | #include <media/davinci/vpss.h> |
| 31 | 33 | #include <media/v4l2-device.h> |
| @@ -122,10 +124,10 @@ static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, · 90 unmodified lines | ||
| 122 | 124 | |
| 123 | 125 | /** |
| 124 | 126 | * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 |
| 125 | − * @sd - ptr to struct osd_state | |
| 126 | − * @field_inversion - inversion flag | |
| 127 | − * @fb_base_phys - frame buffer address | |
| 128 | − * @lconfig - ptr to layer config | |
| 127 | + * @sd: ptr to struct osd_state | |
| 128 | + * @field_inversion: inversion flag | |
| 129 | + * @fb_base_phys: frame buffer address | |
| 130 | + * @lconfig: ptr to layer config | |
| 129 | 131 | * |
| 130 | 132 | * This routine implements a workaround for the field signal inversion silicon |
| 131 | 133 | * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and |
| @@ -782,9 +784,9 @@ static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, · 650 unmodified lines | ||
| 782 | 784 | |
| 783 | 785 | /** |
| 784 | 786 | * try_layer_config() - Try a specific configuration for the layer |
| 785 | − * @sd - ptr to struct osd_state | |
| 786 | − * @layer - layer to configure | |
| 787 | − * @lconfig - layer configuration to try | |
| 787 | + * @sd: ptr to struct osd_state | |
| 788 | + * @layer: layer to configure | |
| 789 | + * @lconfig: layer configuration to try | |
| 788 | 790 | * |
| 789 | 791 | * If the requested lconfig is completely rejected and the value of lconfig on |
| 790 | 792 | * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, |
| @@ -844,9 +846,10 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, · 53 unmodified lines | ||
| 844 | 846 | |
| 845 | 847 | /* DM6446: */ |
| 846 | 848 | /* only one OSD window at a time can use RGB pixel formats */ |
| 847 | − if ((osd->vpbe_type == VPBE_VERSION_1) && | |
| 848 | − is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { | |
| 849 | + if ((osd->vpbe_type == VPBE_VERSION_1) && | |
| 850 | + is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { | |
| 849 | 851 | enum osd_pix_format pixfmt; |
| 852 | + | |
| 850 | 853 | if (layer == WIN_OSD0) |
| 851 | 854 | pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; |
| 852 | 855 | else |
| @@ -21,8 +21,11 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/videodev2.h> |
| 22 | 22 | #include <linux/slab.h> |
| 23 | 23 | |
| 24 | +#ifdef CONFIG_ARCH_DAVINCI | |
| 24 | 25 | #include <mach/hardware.h> |
| 25 | 26 | #include <mach/mux.h> |
| 27 | +#endif | |
| 28 | + | |
| 26 | 29 | #include <linux/platform_data/i2c-davinci.h> |
| 27 | 30 | |
| 28 | 31 | #include <linux/io.h> |
| @@ -224,7 +227,6 @@ venc_enable_vpss_clock(int venc_type, · 195 unmodified lines | ||
| 224 | 227 | */ |
| 225 | 228 | static int venc_set_ntsc(struct v4l2_subdev *sd) |
| 226 | 229 | { |
| 227 | − u32 val; | |
| 228 | 230 | struct venc_state *venc = to_state(sd); |
| 229 | 231 | struct venc_platform_data *pdata = venc->pdata; |
| 230 | 232 | |
| @@ -241,7 +243,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) · 10 unmodified lines | ||
| 241 | 243 | if (venc->venc_type == VPBE_VERSION_3) { |
| 242 | 244 | venc_write(sd, VENC_CLKCTL, 0x01); |
| 243 | 245 | venc_write(sd, VENC_VIDCTL, 0); |
| 244 | − val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3); | |
| 246 | + vdaccfg_write(sd, VDAC_CONFIG_SD_V3); | |
| 245 | 247 | } else if (venc->venc_type == VPBE_VERSION_2) { |
| 246 | 248 | venc_write(sd, VENC_CLKCTL, 0x01); |
| 247 | 249 | venc_write(sd, VENC_VIDCTL, 0); |
| @@ -604,10 +606,9 @@ static int venc_device_get(struct device *dev, void *data) · 356 unmodified lines | ||
| 604 | 606 | struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, |
| 605 | 607 | const char *venc_name) |
| 606 | 608 | { |
| 607 | − struct venc_state *venc; | |
| 608 | − int err; | |
| 609 | + struct venc_state *venc = NULL; | |
| 609 | 610 | |
| 610 | − err = bus_for_each_dev(&platform_bus_type, NULL, &venc, | |
| 611 | + bus_for_each_dev(&platform_bus_type, NULL, &venc, | |
| 611 | 612 | venc_device_get); |
| 612 | 613 | if (venc == NULL) |
| 613 | 614 | return NULL; |
| @@ -1509,7 +1509,7 @@ static int vpfe_streamon(struct file *file, void *priv, · 1508 unmodified lines | ||
| 1509 | 1509 | unlock_out: |
| 1510 | 1510 | mutex_unlock(&vpfe_dev->lock); |
| 1511 | 1511 | streamoff: |
| 1512 | − ret = videobuf_streamoff(&vpfe_dev->buffer_queue); | |
| 1512 | + videobuf_streamoff(&vpfe_dev->buffer_queue); | |
| 1513 | 1513 | return ret; |
| 1514 | 1514 | } |
| 1515 | 1515 | |
| @@ -41,11 +41,10 @@ config VIDEO_S5P_MIPI_CSIS · 40 unmodified lines | ||
| 41 | 41 | To compile this driver as a module, choose M here: the |
| 42 | 42 | module will be called s5p-csis. |
| 43 | 43 | |
| 44 | −if SOC_EXYNOS4412 || SOC_EXYNOS5250 | |
| 45 | − | |
| 46 | 44 | config VIDEO_EXYNOS_FIMC_LITE |
| 47 | 45 | tristate "EXYNOS FIMC-LITE camera interface driver" |
| 48 | 46 | depends on I2C |
| 47 | + depends on SOC_EXYNOS4412 || SOC_EXYNOS5250 || COMPILE_TEST | |
| 49 | 48 | depends on HAS_DMA |
| 50 | 49 | select VIDEOBUF2_DMA_CONTIG |
| 51 | 50 | select VIDEO_EXYNOS4_IS_COMMON |
| @@ -55,7 +54,6 @@ config VIDEO_EXYNOS_FIMC_LITE · 3 unmodified lines | ||
| 55 | 54 | |
| 56 | 55 | To compile this driver as a module, choose M here: the |
| 57 | 56 | module will be called exynos-fimc-lite. |
| 58 | −endif | |
| 59 | 57 | |
| 60 | 58 | config VIDEO_EXYNOS4_FIMC_IS |
| 61 | 59 | tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" |
| @@ -254,7 +254,7 @@ void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f) · 253 unmodified lines | ||
| 254 | 254 | /* Maximum output pixel size */ |
| 255 | 255 | cfg = readl(dev->regs + FLITE_REG_CIOCAN); |
| 256 | 256 | cfg &= ~FLITE_REG_CIOCAN_MASK; |
| 257 | − cfg = (f->f_height << 16) | f->f_width; | |
| 257 | + cfg |= (f->f_height << 16) | f->f_width; | |
| 258 | 258 | writel(cfg, dev->regs + FLITE_REG_CIOCAN); |
| 259 | 259 | |
| 260 | 260 | /* DMA offsets */ |
| @@ -36,6 +36,12 @@ · 35 unmodified lines | ||
| 36 | 36 | #define DRV_NAME "fsl_viu" |
| 37 | 37 | #define VIU_VERSION "0.5.1" |
| 38 | 38 | |
| 39 | +/* Allow building this driver with COMPILE_TEST */ | |
| 40 | +#ifndef CONFIG_PPC | |
| 41 | +#define out_be32(v, a) iowrite32be(a, (void __iomem *)v) | |
| 42 | +#define in_be32(a) ioread32be((void __iomem *)a) | |
| 43 | +#endif | |
| 44 | + | |
| 39 | 45 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ |
| 40 | 46 | |
| 41 | 47 | #define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ |
| @@ -128,7 +134,7 @@ struct viu_dev { · 86 unmodified lines | ||
| 128 | 134 | int dma_done; |
| 129 | 135 | |
| 130 | 136 | /* Hardware register area */ |
| 131 | − struct viu_reg *vr; | |
| 137 | + struct viu_reg __iomem *vr; | |
| 132 | 138 | |
| 133 | 139 | /* Interrupt vector */ |
| 134 | 140 | int irq; |
| @@ -229,7 +235,7 @@ enum status_config { · 94 unmodified lines | ||
| 229 | 235 | |
| 230 | 236 | static irqreturn_t viu_intr(int irq, void *dev_id); |
| 231 | 237 | |
| 232 | −struct viu_fmt *format_by_fourcc(int fourcc) | |
| 238 | +static struct viu_fmt *format_by_fourcc(int fourcc) | |
| 233 | 239 | { |
| 234 | 240 | int i; |
| 235 | 241 | |
| @@ -242,9 +248,9 @@ struct viu_fmt *format_by_fourcc(int fourcc) · 6 unmodified lines | ||
| 242 | 248 | return NULL; |
| 243 | 249 | } |
| 244 | 250 | |
| 245 | −void viu_start_dma(struct viu_dev *dev) | |
| 251 | +static void viu_start_dma(struct viu_dev *dev) | |
| 246 | 252 | { |
| 247 | − struct viu_reg *vr = dev->vr; | |
| 253 | + struct viu_reg __iomem *vr = dev->vr; | |
| 248 | 254 | |
| 249 | 255 | dev->field = 0; |
| 250 | 256 | |
| @@ -253,9 +259,9 @@ void viu_start_dma(struct viu_dev *dev) · 2 unmodified lines | ||
| 253 | 259 | out_be32(&vr->status_cfg, INT_FIELD_EN); |
| 254 | 260 | } |
| 255 | 261 | |
| 256 | −void viu_stop_dma(struct viu_dev *dev) | |
| 262 | +static void viu_stop_dma(struct viu_dev *dev) | |
| 257 | 263 | { |
| 258 | − struct viu_reg *vr = dev->vr; | |
| 264 | + struct viu_reg __iomem *vr = dev->vr; | |
| 259 | 265 | int cnt = 100; |
| 260 | 266 | u32 status_cfg; |
| 261 | 267 | |
| @@ -290,7 +296,7 @@ static int restart_video_queue(struct viu_dmaqueue *vidq) · 28 unmodified lines | ||
| 290 | 296 | { |
| 291 | 297 | struct viu_buf *buf, *prev; |
| 292 | 298 | |
| 293 | − dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq); | |
| 299 | + dprintk(1, "%s vidq=%p\n", __func__, vidq); | |
| 294 | 300 | if (!list_empty(&vidq->active)) { |
| 295 | 301 | buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); |
| 296 | 302 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", |
| @@ -395,7 +401,7 @@ static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) · 98 unmodified lines | ||
| 395 | 401 | |
| 396 | 402 | inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) |
| 397 | 403 | { |
| 398 | − struct viu_reg *vr = dev->vr; | |
| 404 | + struct viu_reg __iomem *vr = dev->vr; | |
| 399 | 405 | int bpp; |
| 400 | 406 | |
| 401 | 407 | /* setup the DMA base address */ |
| @@ -497,8 +503,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) · 95 unmodified lines | ||
| 497 | 503 | struct viu_buf *prev; |
| 498 | 504 | |
| 499 | 505 | if (!list_empty(&vidq->queued)) { |
| 500 | − dprintk(1, "adding vb queue=0x%08lx\n", | |
| 501 | − (unsigned long)&buf->vb.queue); | |
| 506 | + dprintk(1, "adding vb queue=%p\n", &buf->vb.queue); | |
| 502 | 507 | dprintk(1, "vidq pointer 0x%p, queued 0x%p\n", |
| 503 | 508 | vidq, &vidq->queued); |
| 504 | 509 | dprintk(1, "dev %p, queued: self %p, next %p, head %p\n", |
| @@ -509,8 +514,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) · 4 unmodified lines | ||
| 509 | 514 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", |
| 510 | 515 | buf, buf->vb.i); |
| 511 | 516 | } else if (list_empty(&vidq->active)) { |
| 512 | − dprintk(1, "adding vb active=0x%08lx\n", | |
| 513 | − (unsigned long)&buf->vb.queue); | |
| 517 | + dprintk(1, "adding vb active=%p\n", &buf->vb.queue); | |
| 514 | 518 | list_add_tail(&buf->vb.queue, &vidq->active); |
| 515 | 519 | buf->vb.state = VIDEOBUF_ACTIVE; |
| 516 | 520 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); |
| @@ -519,8 +523,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) · 2 unmodified lines | ||
| 519 | 523 | |
| 520 | 524 | buffer_activate(dev, buf); |
| 521 | 525 | } else { |
| 522 | − dprintk(1, "adding vb queue2=0x%08lx\n", | |
| 523 | − (unsigned long)&buf->vb.queue); | |
| 526 | + dprintk(1, "adding vb queue2=%p\n", &buf->vb.queue); | |
| 524 | 527 | prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue); |
| 525 | 528 | if (prev->vb.width == buf->vb.width && |
| 526 | 529 | prev->vb.height == buf->vb.height && |
| @@ -703,10 +706,8 @@ static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) · 176 unmodified lines | ||
| 703 | 706 | return 0; |
| 704 | 707 | } |
| 705 | 708 | |
| 706 | −inline void viu_activate_overlay(struct viu_reg *viu_reg) | |
| 709 | +inline void viu_activate_overlay(struct viu_reg __iomem *vr) | |
| 707 | 710 | { |
| 708 | − struct viu_reg *vr = viu_reg; | |
| 709 | − | |
| 710 | 711 | out_be32(&vr->field_base_addr, reg_val.field_base_addr); |
| 711 | 712 | out_be32(&vr->dma_inc, reg_val.dma_inc); |
| 712 | 713 | out_be32(&vr->picture_count, reg_val.picture_count); |
| @@ -749,7 +750,7 @@ static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh) · 36 unmodified lines | ||
| 749 | 750 | reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; |
| 750 | 751 | |
| 751 | 752 | /* setup the base address of the overlay buffer */ |
| 752 | − reg_val.field_base_addr = (u32)dev->ovbuf.base; | |
| 753 | + reg_val.field_base_addr = (u32)(long)dev->ovbuf.base; | |
| 753 | 754 | |
| 754 | 755 | return 0; |
| 755 | 756 | } |
| @@ -802,7 +803,7 @@ static int vidioc_overlay(struct file *file, void *priv, unsigned int on) · 46 unmodified lines | ||
| 802 | 803 | return 0; |
| 803 | 804 | } |
| 804 | 805 | |
| 805 | −int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) | |
| 806 | +static int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) | |
| 806 | 807 | { |
| 807 | 808 | struct viu_fh *fh = priv; |
| 808 | 809 | struct viu_dev *dev = fh->dev; |
| @@ -813,7 +814,7 @@ int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) · 4 unmodified lines | ||
| 813 | 814 | return 0; |
| 814 | 815 | } |
| 815 | 816 | |
| 816 | −int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *arg) | |
| 817 | +static int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *arg) | |
| 817 | 818 | { |
| 818 | 819 | struct viu_fh *fh = priv; |
| 819 | 820 | struct viu_dev *dev = fh->dev; |
| @@ -985,10 +986,8 @@ inline void viu_activate_next_buf(struct viu_dev *dev, · 165 unmodified lines | ||
| 985 | 986 | } |
| 986 | 987 | } |
| 987 | 988 | |
| 988 | −inline void viu_default_settings(struct viu_reg *viu_reg) | |
| 989 | +inline void viu_default_settings(struct viu_reg __iomem *vr) | |
| 989 | 990 | { |
| 990 | − struct viu_reg *vr = viu_reg; | |
| 991 | − | |
| 992 | 991 | out_be32(&vr->luminance, 0x9512A254); |
| 993 | 992 | out_be32(&vr->chroma_r, 0x03310000); |
| 994 | 993 | out_be32(&vr->chroma_g, 0x06600F38); |
| @@ -1001,7 +1000,7 @@ inline void viu_default_settings(struct viu_reg *viu_reg) · 6 unmodified lines | ||
| 1001 | 1000 | |
| 1002 | 1001 | static void viu_overlay_intr(struct viu_dev *dev, u32 status) |
| 1003 | 1002 | { |
| 1004 | − struct viu_reg *vr = dev->vr; | |
| 1003 | + struct viu_reg __iomem *vr = dev->vr; | |
| 1005 | 1004 | |
| 1006 | 1005 | if (status & INT_DMA_END_STATUS) |
| 1007 | 1006 | dev->dma_done = 1; |
| @@ -1032,7 +1031,7 @@ static void viu_overlay_intr(struct viu_dev *dev, u32 status) · 24 unmodified lines | ||
| 1032 | 1031 | static void viu_capture_intr(struct viu_dev *dev, u32 status) |
| 1033 | 1032 | { |
| 1034 | 1033 | struct viu_dmaqueue *vidq = &dev->vidq; |
| 1035 | − struct viu_reg *vr = dev->vr; | |
| 1034 | + struct viu_reg __iomem *vr = dev->vr; | |
| 1036 | 1035 | struct viu_buf *buf; |
| 1037 | 1036 | int field_num; |
| 1038 | 1037 | int need_two; |
| @@ -1104,7 +1103,7 @@ static void viu_capture_intr(struct viu_dev *dev, u32 status) · 65 unmodified lines | ||
| 1104 | 1103 | static irqreturn_t viu_intr(int irq, void *dev_id) |
| 1105 | 1104 | { |
| 1106 | 1105 | struct viu_dev *dev = (struct viu_dev *)dev_id; |
| 1107 | − struct viu_reg *vr = dev->vr; | |
| 1106 | + struct viu_reg __iomem *vr = dev->vr; | |
| 1108 | 1107 | u32 status; |
| 1109 | 1108 | u32 error; |
| 1110 | 1109 | |
| @@ -1169,7 +1168,7 @@ static int viu_open(struct file *file) · 58 unmodified lines | ||
| 1169 | 1168 | struct video_device *vdev = video_devdata(file); |
| 1170 | 1169 | struct viu_dev *dev = video_get_drvdata(vdev); |
| 1171 | 1170 | struct viu_fh *fh; |
| 1172 | − struct viu_reg *vr; | |
| 1171 | + struct viu_reg __iomem *vr; | |
| 1173 | 1172 | int minor = vdev->minor; |
| 1174 | 1173 | u32 status_cfg; |
| 1175 | 1174 | |
| @@ -1210,9 +1209,7 @@ static int viu_open(struct file *file) · 34 unmodified lines | ||
| 1210 | 1209 | dev->crop_current.width = fh->width; |
| 1211 | 1210 | dev->crop_current.height = fh->height; |
| 1212 | 1211 | |
| 1213 | − dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", | |
| 1214 | − (unsigned long)fh, (unsigned long)dev, | |
| 1215 | − (unsigned long)&dev->vidq); | |
| 1212 | + dprintk(1, "Open: fh=%p, dev=%p, dev->vidq=%p\n", fh, dev, &dev->vidq); | |
| 1216 | 1213 | dprintk(1, "Open: list_empty queued=%d\n", |
| 1217 | 1214 | list_empty(&dev->vidq.queued)); |
| 1218 | 1215 | dprintk(1, "Open: list_empty active=%d\n", |
| @@ -1305,7 +1302,7 @@ static int viu_release(struct file *file) · 86 unmodified lines | ||
| 1305 | 1302 | return 0; |
| 1306 | 1303 | } |
| 1307 | 1304 | |
| 1308 | −void viu_reset(struct viu_reg *reg) | |
| 1305 | +static void viu_reset(struct viu_reg __iomem *reg) | |
| 1309 | 1306 | { |
| 1310 | 1307 | out_be32(®->status_cfg, 0); |
| 1311 | 1308 | out_be32(®->luminance, 0x9512a254); |
| @@ -1325,7 +1322,7 @@ static int viu_mmap(struct file *file, struct vm_area_struct *vma) · 13 unmodified lines | ||
| 1325 | 1322 | struct viu_dev *dev = fh->dev; |
| 1326 | 1323 | int ret; |
| 1327 | 1324 | |
| 1328 | − dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | |
| 1325 | + dprintk(1, "mmap called, vma=%p\n", vma); | |
| 1329 | 1326 | |
| 1330 | 1327 | if (mutex_lock_interruptible(&dev->lock)) |
| 1331 | 1328 | return -ERESTARTSYS; |
| @@ -1407,7 +1404,7 @@ static int viu_of_probe(struct platform_device *op) · 75 unmodified lines | ||
| 1407 | 1404 | } |
| 1408 | 1405 | |
| 1409 | 1406 | viu_irq = irq_of_parse_and_map(op->dev.of_node, 0); |
| 1410 | − if (viu_irq == NO_IRQ) { | |
| 1407 | + if (!viu_irq) { | |
| 1411 | 1408 | dev_err(&op->dev, "Error while mapping the irq\n"); |
| 1412 | 1409 | return -EINVAL; |
| 1413 | 1410 | } |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | config VIDEO_CAFE_CCIC |
| 2 | 2 | tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" |
| 3 | 3 | depends on PCI && I2C && VIDEO_V4L2 |
| 4 | − depends on HAS_DMA | |
| 5 | 4 | select VIDEO_OV7670 |
| 6 | 5 | select VIDEOBUF2_VMALLOC |
| 7 | 6 | select VIDEOBUF2_DMA_CONTIG |
| @@ -13,10 +12,12 @@ config VIDEO_CAFE_CCIC · 5 unmodified lines | ||
| 13 | 12 | |
| 14 | 13 | config VIDEO_MMP_CAMERA |
| 15 | 14 | tristate "Marvell Armada 610 integrated camera controller support" |
| 16 | − depends on ARCH_MMP && I2C && VIDEO_V4L2 | |
| 17 | − depends on HAS_DMA && BROKEN | |
| 15 | + depends on I2C && VIDEO_V4L2 | |
| 16 | + depends on ARCH_MMP || COMPILE_TEST | |
| 18 | 17 | select VIDEO_OV7670 |
| 19 | 18 | select I2C_GPIO |
| 19 | + select VIDEOBUF2_VMALLOC | |
| 20 | + select VIDEOBUF2_DMA_CONTIG | |
| 20 | 21 | select VIDEOBUF2_DMA_SG |
| 21 | 22 | ---help--- |
| 22 | 23 | This is a Video4Linux2 driver for the integrated camera |
| @@ -1,6 +1,5 @@ | ||
| 1 | −obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o | |
| 2 | −cafe_ccic-y := cafe-driver.o mcam-core.o | |
| 3 | − | |
| 4 | −obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o | |
| 5 | −mmp_camera-y := mmp-driver.o mcam-core.o | |
| 1 | +obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o mcam-core.o | |
| 2 | +cafe_ccic-y := cafe-driver.o | |
| 6 | 3 | |
| 4 | +obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o mcam-core.o | |
| 5 | +mmp_camera-y := mmp-driver.o | |
| @@ -1720,6 +1720,7 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs) · 1719 unmodified lines | ||
| 1720 | 1720 | } |
| 1721 | 1721 | return handled; |
| 1722 | 1722 | } |
| 1723 | +EXPORT_SYMBOL_GPL(mccic_irq); | |
| 1723 | 1724 | |
| 1724 | 1725 | /* ---------------------------------------------------------------------- */ |
| 1725 | 1726 | /* |
| @@ -1830,7 +1831,7 @@ out_unregister: · 104 unmodified lines | ||
| 1830 | 1831 | v4l2_device_unregister(&cam->v4l2_dev); |
| 1831 | 1832 | return ret; |
| 1832 | 1833 | } |
| 1833 | − | |
| 1834 | +EXPORT_SYMBOL_GPL(mccic_register); | |
| 1834 | 1835 | |
| 1835 | 1836 | void mccic_shutdown(struct mcam_camera *cam) |
| 1836 | 1837 | { |
| @@ -1850,6 +1851,7 @@ void mccic_shutdown(struct mcam_camera *cam) · 13 unmodified lines | ||
| 1850 | 1851 | v4l2_ctrl_handler_free(&cam->ctrl_handler); |
| 1851 | 1852 | v4l2_device_unregister(&cam->v4l2_dev); |
| 1852 | 1853 | } |
| 1854 | +EXPORT_SYMBOL_GPL(mccic_shutdown); | |
| 1853 | 1855 | |
| 1854 | 1856 | /* |
| 1855 | 1857 | * Power management |
| @@ -1868,6 +1870,7 @@ void mccic_suspend(struct mcam_camera *cam) · 12 unmodified lines | ||
| 1868 | 1870 | } |
| 1869 | 1871 | mutex_unlock(&cam->s_mutex); |
| 1870 | 1872 | } |
| 1873 | +EXPORT_SYMBOL_GPL(mccic_suspend); | |
| 1871 | 1874 | |
| 1872 | 1875 | int mccic_resume(struct mcam_camera *cam) |
| 1873 | 1876 | { |
| @@ -1898,4 +1901,8 @@ int mccic_resume(struct mcam_camera *cam) · 24 unmodified lines | ||
| 1898 | 1901 | } |
| 1899 | 1902 | return ret; |
| 1900 | 1903 | } |
| 1904 | +EXPORT_SYMBOL_GPL(mccic_resume); | |
| 1901 | 1905 | #endif /* CONFIG_PM */ |
| 1906 | + | |
| 1907 | +MODULE_LICENSE("GPL v2"); | |
| 1908 | +MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | |
| @@ -37,7 +37,7 @@ MODULE_LICENSE("GPL"); · 36 unmodified lines | ||
| 37 | 37 | static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"}; |
| 38 | 38 | |
| 39 | 39 | struct mmp_camera { |
| 40 | − void *power_regs; | |
| 40 | + void __iomem *power_regs; | |
| 41 | 41 | struct platform_device *pdev; |
| 42 | 42 | struct mcam_camera mcam; |
| 43 | 43 | struct list_head devlist; |
| @@ -183,7 +183,7 @@ static void mmpcam_power_down(struct mcam_camera *mcam) · 139 unmodified lines | ||
| 183 | 183 | mcam_clk_disable(mcam); |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | −void mcam_ctlr_reset(struct mcam_camera *mcam) | |
| 186 | +static void mcam_ctlr_reset(struct mcam_camera *mcam) | |
| 187 | 187 | { |
| 188 | 188 | unsigned long val; |
| 189 | 189 | struct mmp_camera *cam = mcam_to_cam(mcam); |
| @@ -214,7 +214,7 @@ void mcam_ctlr_reset(struct mcam_camera *mcam) · 24 unmodified lines | ||
| 214 | 214 | * CSI2_DPHY3 and CSI2_DPHY6 can be set with a default value |
| 215 | 215 | * or be calculated dynamically |
| 216 | 216 | */ |
| 217 | −void mmpcam_calc_dphy(struct mcam_camera *mcam) | |
| 217 | +static void mmpcam_calc_dphy(struct mcam_camera *mcam) | |
| 218 | 218 | { |
| 219 | 219 | struct mmp_camera *cam = mcam_to_cam(mcam); |
| 220 | 220 | struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data; |
| @@ -1084,10 +1084,7 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) · 1083 unmodified lines | ||
| 1084 | 1084 | return PTR_ERR(jpeg->clk_jdec); |
| 1085 | 1085 | |
| 1086 | 1086 | jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi"); |
| 1087 | − if (IS_ERR(jpeg->clk_jdec_smi)) | |
| 1088 | − return PTR_ERR(jpeg->clk_jdec_smi); | |
| 1089 | − | |
| 1090 | − return 0; | |
| 1087 | + return PTR_ERR_OR_ZERO(jpeg->clk_jdec_smi); | |
| 1091 | 1088 | } |
| 1092 | 1089 | |
| 1093 | 1090 | static int mtk_jpeg_probe(struct platform_device *pdev) |
| @@ -1,15 +1,16 @@ | ||
| 1 | 1 | config VIDEO_OMAP2_VOUT_VRFB |
| 2 | 2 | bool |
| 3 | + default y | |
| 4 | + depends on VIDEO_OMAP2_VOUT && (OMAP2_VRFB || COMPILE_TEST) | |
| 3 | 5 | |
| 4 | 6 | config VIDEO_OMAP2_VOUT |
| 5 | 7 | tristate "OMAP2/OMAP3 V4L2-Display driver" |
| 6 | 8 | depends on MMU |
| 7 | − depends on ARCH_OMAP2 || ARCH_OMAP3 | |
| 8 | − depends on FB_OMAP2 | |
| 9 | + depends on FB_OMAP2 || (COMPILE_TEST && FB_OMAP2=n) | |
| 10 | + depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST | |
| 9 | 11 | select VIDEOBUF_GEN |
| 10 | 12 | select VIDEOBUF_DMA_CONTIG |
| 11 | 13 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 |
| 12 | − select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB | |
| 13 | 14 | select FRAME_VECTOR |
| 14 | 15 | default n |
| 15 | 16 | ---help--- |
| @@ -198,7 +198,7 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) · 197 unmodified lines | ||
| 198 | 198 | * omap_vout_get_userptr: Convert user space virtual address to physical |
| 199 | 199 | * address. |
| 200 | 200 | */ |
| 201 | −static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp, | |
| 201 | +static int omap_vout_get_userptr(struct videobuf_buffer *vb, long virtp, | |
| 202 | 202 | u32 *physp) |
| 203 | 203 | { |
| 204 | 204 | struct frame_vector *vec; |
| @@ -702,19 +702,18 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, · 497 unmodified lines | ||
| 702 | 702 | virt_addr = omap_vout_alloc_buffer(vout->buffer_size, |
| 703 | 703 | &phy_addr); |
| 704 | 704 | if (!virt_addr) { |
| 705 | − if (ovid->rotation_type == VOUT_ROT_NONE) { | |
| 705 | + if (ovid->rotation_type == VOUT_ROT_NONE) | |
| 706 | 706 | break; |
| 707 | − } else { | |
| 708 | − if (!is_rotation_enabled(vout)) | |
| 709 | − break; | |
| 707 | + | |
| 708 | + if (!is_rotation_enabled(vout)) | |
| 709 | + break; | |
| 710 | + | |
| 710 | 711 | /* Free the VRFB buffers if no space for V4L2 buffers */ |
| 711 | 712 | for (j = i; j < *count; j++) { |
| 712 | − omap_vout_free_buffer( | |
| 713 | − vout->smsshado_virt_addr[j], | |
| 714 | − vout->smsshado_size); | |
| 713 | + omap_vout_free_buffer(vout->smsshado_virt_addr[j], | |
| 714 | + vout->smsshado_size); | |
| 715 | 715 | vout->smsshado_virt_addr[j] = 0; |
| 716 | 716 | vout->smsshado_phy_addr[j] = 0; |
| 717 | − } | |
| 718 | 717 | } |
| 719 | 718 | } |
| 720 | 719 | vout->buf_virt_addr[i] = virt_addr; |
| @@ -54,8 +54,8 @@ static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, · 53 unmodified lines | ||
| 54 | 54 | *count = 0; |
| 55 | 55 | return -ENOMEM; |
| 56 | 56 | } |
| 57 | − memset((void *) vout->smsshado_virt_addr[i], 0, | |
| 58 | − vout->smsshado_size); | |
| 57 | + memset((void *)(long)vout->smsshado_virt_addr[i], 0, | |
| 58 | + vout->smsshado_size); | |
| 59 | 59 | } |
| 60 | 60 | return 0; |
| 61 | 61 | } |
| @@ -61,7 +61,9 @@ · 60 unmodified lines | ||
| 61 | 61 | #include <linux/sched.h> |
| 62 | 62 | #include <linux/vmalloc.h> |
| 63 | 63 | |
| 64 | +#ifdef CONFIG_ARM_DMA_USE_IOMMU | |
| 64 | 65 | #include <asm/dma-iommu.h> |
| 66 | +#endif | |
| 65 | 67 | |
| 66 | 68 | #include <media/v4l2-common.h> |
| 67 | 69 | #include <media/v4l2-fwnode.h> |
| @@ -284,13 +286,6 @@ static const struct clk_ops isp_xclk_ops = { · 216 unmodified lines | ||
| 284 | 286 | |
| 285 | 287 | static const char *isp_xclk_parent_name = "cam_mclk"; |
| 286 | 288 | |
| 287 | −static const struct clk_init_data isp_xclk_init_data = { | |
| 288 | − .name = "cam_xclk", | |
| 289 | − .ops = &isp_xclk_ops, | |
| 290 | − .parent_names = &isp_xclk_parent_name, | |
| 291 | − .num_parents = 1, | |
| 292 | −}; | |
| 293 | − | |
| 294 | 289 | static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data) |
| 295 | 290 | { |
| 296 | 291 | unsigned int idx = clkspec->args[0]; |
| @@ -1945,12 +1940,16 @@ error_csi2: · 1648 unmodified lines | ||
| 1945 | 1940 | |
| 1946 | 1941 | static void isp_detach_iommu(struct isp_device *isp) |
| 1947 | 1942 | { |
| 1943 | +#ifdef CONFIG_ARM_DMA_USE_IOMMU | |
| 1944 | + arm_iommu_detach_device(isp->dev); | |
| 1948 | 1945 | arm_iommu_release_mapping(isp->mapping); |
| 1949 | 1946 | isp->mapping = NULL; |
| 1947 | +#endif | |
| 1950 | 1948 | } |
| 1951 | 1949 | |
| 1952 | 1950 | static int isp_attach_iommu(struct isp_device *isp) |
| 1953 | 1951 | { |
| 1952 | +#ifdef CONFIG_ARM_DMA_USE_IOMMU | |
| 1954 | 1953 | struct dma_iommu_mapping *mapping; |
| 1955 | 1954 | int ret; |
| 1956 | 1955 | |
| @@ -1961,8 +1960,7 @@ static int isp_attach_iommu(struct isp_device *isp) · 4 unmodified lines | ||
| 1961 | 1960 | mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); |
| 1962 | 1961 | if (IS_ERR(mapping)) { |
| 1963 | 1962 | dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); |
| 1964 | − ret = PTR_ERR(mapping); | |
| 1965 | − goto error; | |
| 1963 | + return PTR_ERR(mapping); | |
| 1966 | 1964 | } |
| 1967 | 1965 | |
| 1968 | 1966 | isp->mapping = mapping; |
| @@ -1977,8 +1975,12 @@ static int isp_attach_iommu(struct isp_device *isp) · 8 unmodified lines | ||
| 1977 | 1975 | return 0; |
| 1978 | 1976 | |
| 1979 | 1977 | error: |
| 1980 | − isp_detach_iommu(isp); | |
| 1978 | + arm_iommu_release_mapping(isp->mapping); | |
| 1979 | + isp->mapping = NULL; | |
| 1981 | 1980 | return ret; |
| 1981 | +#else | |
| 1982 | + return -ENODEV; | |
| 1983 | +#endif | |
| 1982 | 1984 | } |
| 1983 | 1985 | |
| 1984 | 1986 | /* |
| @@ -735,7 +735,7 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, · 734 unmodified lines | ||
| 735 | 735 | return -ENOMEM; |
| 736 | 736 | |
| 737 | 737 | if (copy_from_user(fpc_new.addr, |
| 738 | − (__force void __user *)fpc.fpcaddr, | |
| 738 | + (__force void __user *)(long)fpc.fpcaddr, | |
| 739 | 739 | size)) { |
| 740 | 740 | dma_free_coherent(isp->dev, size, fpc_new.addr, |
| 741 | 741 | fpc_new.dma); |
| @@ -250,6 +250,8 @@ static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) · 249 unmodified lines | ||
| 250 | 250 | return omap3isp_stat_config(stat, arg); |
| 251 | 251 | case VIDIOC_OMAP3ISP_STAT_REQ: |
| 252 | 252 | return omap3isp_stat_request_statistics(stat, arg); |
| 253 | + case VIDIOC_OMAP3ISP_STAT_REQ_TIME32: | |
| 254 | + return omap3isp_stat_request_statistics_time32(stat, arg); | |
| 253 | 255 | case VIDIOC_OMAP3ISP_STAT_EN: { |
| 254 | 256 | unsigned long *en = arg; |
| 255 | 257 | return omap3isp_stat_enable(stat, !!*en); |
| @@ -314,6 +314,8 @@ static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) · 313 unmodified lines | ||
| 314 | 314 | return omap3isp_stat_config(stat, arg); |
| 315 | 315 | case VIDIOC_OMAP3ISP_STAT_REQ: |
| 316 | 316 | return omap3isp_stat_request_statistics(stat, arg); |
| 317 | + case VIDIOC_OMAP3ISP_STAT_REQ_TIME32: | |
| 318 | + return omap3isp_stat_request_statistics_time32(stat, arg); | |
| 317 | 319 | case VIDIOC_OMAP3ISP_STAT_EN: { |
| 318 | 320 | int *en = arg; |
| 319 | 321 | return omap3isp_stat_enable(stat, !!*en); |
| @@ -435,6 +435,8 @@ static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) · 434 unmodified lines | ||
| 435 | 435 | return omap3isp_stat_config(stat, arg); |
| 436 | 436 | case VIDIOC_OMAP3ISP_STAT_REQ: |
| 437 | 437 | return omap3isp_stat_request_statistics(stat, arg); |
| 438 | + case VIDIOC_OMAP3ISP_STAT_REQ_TIME32: | |
| 439 | + return omap3isp_stat_request_statistics_time32(stat, arg); | |
| 438 | 440 | case VIDIOC_OMAP3ISP_STAT_EN: { |
| 439 | 441 | int *en = arg; |
| 440 | 442 | return omap3isp_stat_enable(stat, !!*en); |
| @@ -25,7 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include "isppreview.h" |
| 26 | 26 | |
| 27 | 27 | /* Default values in Office Fluorescent Light for RGBtoRGB Blending */ |
| 28 | −static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { | |
| 28 | +static const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { | |
| 29 | 29 | { /* RGB-RGB Matrix */ |
| 30 | 30 | {0x01E2, 0x0F30, 0x0FEE}, |
| 31 | 31 | {0x0F9B, 0x01AC, 0x0FB9}, |
| @@ -35,7 +35,7 @@ static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { · 3 unmodified lines | ||
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | 37 | /* Default values in Office Fluorescent Light for RGB to YUV Conversion*/ |
| 38 | −static struct omap3isp_prev_csc flr_prev_csc = { | |
| 38 | +static const struct omap3isp_prev_csc flr_prev_csc = { | |
| 39 | 39 | { /* CSC Coef Matrix */ |
| 40 | 40 | {66, 129, 25}, |
| 41 | 41 | {-38, -75, 112}, |
| @@ -890,7 +890,7 @@ static int preview_config(struct isp_prev_device *prev, · 848 unmodified lines | ||
| 890 | 890 | params = &prev->params.params[!!(active & bit)]; |
| 891 | 891 | |
| 892 | 892 | if (cfg->flag & bit) { |
| 893 | − void __user *from = *(void * __user *) | |
| 893 | + void __user *from = *(void __user **) | |
| 894 | 894 | ((void *)cfg + attr->config_offset); |
| 895 | 895 | void *to = (void *)params + attr->param_offset; |
| 896 | 896 | size_t size = attr->param_size; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include <linux/dma-mapping.h> |
| 19 | 19 | #include <linux/slab.h> |
| 20 | +#include <linux/timekeeping.h> | |
| 20 | 21 | #include <linux/uaccess.h> |
| 21 | 22 | |
| 22 | 23 | #include "isp.h" |
| @@ -237,7 +238,7 @@ static int isp_stat_buf_queue(struct ispstat *stat) · 214 unmodified lines | ||
| 237 | 238 | if (!stat->active_buf) |
| 238 | 239 | return STAT_NO_BUF; |
| 239 | 240 | |
| 240 | − v4l2_get_timestamp(&stat->active_buf->ts); | |
| 241 | + ktime_get_ts64(&stat->active_buf->ts); | |
| 241 | 242 | |
| 242 | 243 | stat->active_buf->buf_size = stat->buf_size; |
| 243 | 244 | if (isp_stat_buf_check_magic(stat, stat->active_buf)) { |
| @@ -370,7 +371,7 @@ static int isp_stat_bufs_alloc_one(struct device *dev, · 126 unmodified lines | ||
| 370 | 371 | int ret; |
| 371 | 372 | |
| 372 | 373 | buf->virt_addr = dma_alloc_coherent(dev, size, &buf->dma_addr, |
| 373 | − GFP_KERNEL | GFP_DMA); | |
| 374 | + GFP_KERNEL); | |
| 374 | 375 | if (!buf->virt_addr) |
| 375 | 376 | return -ENOMEM; |
| 376 | 377 | |
| @@ -449,10 +450,8 @@ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) · 72 unmodified lines | ||
| 449 | 450 | buf->empty = 1; |
| 450 | 451 | |
| 451 | 452 | dev_dbg(stat->isp->dev, |
| 452 | − "%s: buffer[%u] allocated. dma=0x%08lx virt=0x%08lx", | |
| 453 | − stat->subdev.name, i, | |
| 454 | − (unsigned long)buf->dma_addr, | |
| 455 | − (unsigned long)buf->virt_addr); | |
| 453 | + "%s: buffer[%u] allocated. dma=%pad virt=%p", | |
| 454 | + stat->subdev.name, i, &buf->dma_addr, buf->virt_addr); | |
| 456 | 455 | } |
| 457 | 456 | |
| 458 | 457 | return 0; |
| @@ -500,7 +499,8 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, · 41 unmodified lines | ||
| 500 | 499 | return PTR_ERR(buf); |
| 501 | 500 | } |
| 502 | 501 | |
| 503 | − data->ts = buf->ts; | |
| 502 | + data->ts.tv_sec = buf->ts.tv_sec; | |
| 503 | + data->ts.tv_usec = buf->ts.tv_nsec / NSEC_PER_USEC; | |
| 504 | 504 | data->config_counter = buf->config_counter; |
| 505 | 505 | data->frame_number = buf->frame_number; |
| 506 | 506 | data->buf_size = buf->buf_size; |
| @@ -512,6 +512,23 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, · 5 unmodified lines | ||
| 512 | 512 | return 0; |
| 513 | 513 | } |
| 514 | 514 | |
| 515 | +int omap3isp_stat_request_statistics_time32(struct ispstat *stat, | |
| 516 | + struct omap3isp_stat_data_time32 *data) | |
| 517 | +{ | |
| 518 | + struct omap3isp_stat_data data64; | |
| 519 | + int ret; | |
| 520 | + | |
| 521 | + ret = omap3isp_stat_request_statistics(stat, &data64); | |
| 522 | + if (ret) | |
| 523 | + return ret; | |
| 524 | + | |
| 525 | + data->ts.tv_sec = data64.ts.tv_sec; | |
| 526 | + data->ts.tv_usec = data64.ts.tv_usec; | |
| 527 | + memcpy(&data->buf, &data64.buf, sizeof(*data) - sizeof(data->ts)); | |
| 528 | + | |
| 529 | + return 0; | |
| 530 | +} | |
| 531 | + | |
| 515 | 532 | /* |
| 516 | 533 | * omap3isp_stat_config - Receives new statistic engine configuration. |
| 517 | 534 | * @new_conf: Pointer to config structure. |
| @@ -527,12 +544,6 @@ int omap3isp_stat_config(struct ispstat *stat, void *new_conf) · 9 unmodified lines | ||
| 527 | 544 | struct ispstat_generic_config *user_cfg = new_conf; |
| 528 | 545 | u32 buf_size = user_cfg->buf_size; |
| 529 | 546 | |
| 530 | − if (!new_conf) { | |
| 531 | − dev_dbg(stat->isp->dev, "%s: configuration is NULL\n", | |
| 532 | − stat->subdev.name); | |
| 533 | − return -EINVAL; | |
| 534 | − } | |
| 535 | − | |
| 536 | 547 | mutex_lock(&stat->ioctl_lock); |
| 537 | 548 | |
| 538 | 549 | dev_dbg(stat->isp->dev, |
| @@ -39,7 +39,7 @@ struct ispstat_buffer { · 38 unmodified lines | ||
| 39 | 39 | struct sg_table sgt; |
| 40 | 40 | void *virt_addr; |
| 41 | 41 | dma_addr_t dma_addr; |
| 42 | − struct timeval ts; | |
| 42 | + struct timespec64 ts; | |
| 43 | 43 | u32 buf_size; |
| 44 | 44 | u32 frame_number; |
| 45 | 45 | u16 config_counter; |
| @@ -130,6 +130,8 @@ struct ispstat_generic_config { · 84 unmodified lines | ||
| 130 | 130 | int omap3isp_stat_config(struct ispstat *stat, void *new_conf); |
| 131 | 131 | int omap3isp_stat_request_statistics(struct ispstat *stat, |
| 132 | 132 | struct omap3isp_stat_data *data); |
| 133 | +int omap3isp_stat_request_statistics_time32(struct ispstat *stat, | |
| 134 | + struct omap3isp_stat_data_time32 *data); | |
| 133 | 135 | int omap3isp_stat_init(struct ispstat *stat, const char *name, |
| 134 | 136 | const struct v4l2_subdev_ops *sd_ops); |
| 135 | 137 | void omap3isp_stat_cleanup(struct ispstat *stat); |
| @@ -1403,7 +1403,7 @@ static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) · 1402 unmodified lines | ||
| 1403 | 1403 | return vb2_mmap(&vfh->queue, vma); |
| 1404 | 1404 | } |
| 1405 | 1405 | |
| 1406 | −static struct v4l2_file_operations isp_video_fops = { | |
| 1406 | +static const struct v4l2_file_operations isp_video_fops = { | |
| 1407 | 1407 | .owner = THIS_MODULE, |
| 1408 | 1408 | .unlocked_ioctl = video_ioctl2, |
| 1409 | 1409 | .open = isp_video_open, |
| @@ -2030,6 +2030,22 @@ static int pxac_vidioc_s_input(struct file *file, void *priv, unsigned int i) · 2029 unmodified lines | ||
| 2030 | 2030 | return 0; |
| 2031 | 2031 | } |
| 2032 | 2032 | |
| 2033 | +static int pxac_sensor_set_power(struct pxa_camera_dev *pcdev, int on) | |
| 2034 | +{ | |
| 2035 | + int ret; | |
| 2036 | + | |
| 2037 | + ret = sensor_call(pcdev, core, s_power, on); | |
| 2038 | + if (ret == -ENOIOCTLCMD) | |
| 2039 | + ret = 0; | |
| 2040 | + if (ret) { | |
| 2041 | + dev_warn(pcdev_to_dev(pcdev), | |
| 2042 | + "Failed to put subdevice in %s mode: %d\n", | |
| 2043 | + on ? "normal operation" : "power saving", ret); | |
| 2044 | + } | |
| 2045 | + | |
| 2046 | + return ret; | |
| 2047 | +} | |
| 2048 | + | |
| 2033 | 2049 | static int pxac_fops_camera_open(struct file *filp) |
| 2034 | 2050 | { |
| 2035 | 2051 | struct pxa_camera_dev *pcdev = video_drvdata(filp); |
| @@ -2040,7 +2056,10 @@ static int pxac_fops_camera_open(struct file *filp) · 4 unmodified lines | ||
| 2040 | 2056 | if (ret < 0) |
| 2041 | 2057 | goto out; |
| 2042 | 2058 | |
| 2043 | − ret = sensor_call(pcdev, core, s_power, 1); | |
| 2059 | + if (!v4l2_fh_is_singular_file(filp)) | |
| 2060 | + goto out; | |
| 2061 | + | |
| 2062 | + ret = pxac_sensor_set_power(pcdev, 1); | |
| 2044 | 2063 | if (ret) |
| 2045 | 2064 | v4l2_fh_release(filp); |
| 2046 | 2065 | out: |
| @@ -2052,13 +2071,17 @@ static int pxac_fops_camera_release(struct file *filp) · 5 unmodified lines | ||
| 2052 | 2071 | { |
| 2053 | 2072 | struct pxa_camera_dev *pcdev = video_drvdata(filp); |
| 2054 | 2073 | int ret; |
| 2055 | − | |
| 2056 | − ret = vb2_fop_release(filp); | |
| 2057 | − if (ret < 0) | |
| 2058 | − return ret; | |
| 2074 | + bool fh_singular; | |
| 2059 | 2075 | |
| 2060 | 2076 | mutex_lock(&pcdev->mlock); |
| 2061 | − ret = sensor_call(pcdev, core, s_power, 0); | |
| 2077 | + | |
| 2078 | + fh_singular = v4l2_fh_is_singular_file(filp); | |
| 2079 | + | |
| 2080 | + ret = _vb2_fop_release(filp, NULL); | |
| 2081 | + | |
| 2082 | + if (fh_singular) | |
| 2083 | + ret = pxac_sensor_set_power(pcdev, 0); | |
| 2084 | + | |
| 2062 | 2085 | mutex_unlock(&pcdev->mlock); |
| 2063 | 2086 | |
| 2064 | 2087 | return ret; |
| @@ -2160,7 +2183,7 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, · 95 unmodified lines | ||
| 2160 | 2183 | pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; |
| 2161 | 2184 | v4l2_fill_mbus_format(mf, pix, pcdev->current_fmt->code); |
| 2162 | 2185 | |
| 2163 | − err = sensor_call(pcdev, core, s_power, 1); | |
| 2186 | + err = pxac_sensor_set_power(pcdev, 1); | |
| 2164 | 2187 | if (err) |
| 2165 | 2188 | goto out; |
| 2166 | 2189 | |
| @@ -2187,7 +2210,7 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, · 20 unmodified lines | ||
| 2187 | 2210 | } |
| 2188 | 2211 | |
| 2189 | 2212 | out_sensor_poweroff: |
| 2190 | − err = sensor_call(pcdev, core, s_power, 0); | |
| 2213 | + err = pxac_sensor_set_power(pcdev, 0); | |
| 2191 | 2214 | out: |
| 2192 | 2215 | mutex_unlock(&pcdev->mlock); |
| 2193 | 2216 | return err; |
| @@ -2242,11 +2265,8 @@ static int pxa_camera_suspend(struct device *dev) · 48 unmodified lines | ||
| 2242 | 2265 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); |
| 2243 | 2266 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); |
| 2244 | 2267 | |
| 2245 | − if (pcdev->sensor) { | |
| 2246 | − ret = sensor_call(pcdev, core, s_power, 0); | |
| 2247 | − if (ret == -ENOIOCTLCMD) | |
| 2248 | − ret = 0; | |
| 2249 | − } | |
| 2268 | + if (pcdev->sensor) | |
| 2269 | + ret = pxac_sensor_set_power(pcdev, 0); | |
| 2250 | 2270 | |
| 2251 | 2271 | return ret; |
| 2252 | 2272 | } |
| @@ -2263,9 +2283,7 @@ static int pxa_camera_resume(struct device *dev) · 10 unmodified lines | ||
| 2263 | 2283 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); |
| 2264 | 2284 | |
| 2265 | 2285 | if (pcdev->sensor) { |
| 2266 | − ret = sensor_call(pcdev, core, s_power, 1); | |
| 2267 | − if (ret == -ENOIOCTLCMD) | |
| 2268 | − ret = 0; | |
| 2286 | + ret = pxac_sensor_set_power(pcdev, 1); | |
| 2269 | 2287 | } |
| 2270 | 2288 | |
| 2271 | 2289 | /* Restart frame capture if active buffer exists */ |
| @@ -1,12 +1,24 @@ | ||
| 1 | +config VIDEO_RCAR_CSI2 | |
| 2 | + tristate "R-Car MIPI CSI-2 Receiver" | |
| 3 | + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF | |
| 4 | + depends on ARCH_RENESAS || COMPILE_TEST | |
| 5 | + select V4L2_FWNODE | |
| 6 | + help | |
| 7 | + Support for Renesas R-Car MIPI CSI-2 receiver. | |
| 8 | + Supports R-Car Gen3 SoCs. | |
| 9 | + | |
| 10 | + To compile this driver as a module, choose M here: the | |
| 11 | + module will be called rcar-csi2. | |
| 12 | + | |
| 1 | 13 | config VIDEO_RCAR_VIN |
| 2 | 14 | tristate "R-Car Video Input (VIN) Driver" |
| 3 | − depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA && MEDIA_CONTROLLER | |
| 15 | + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && MEDIA_CONTROLLER | |
| 4 | 16 | depends on ARCH_RENESAS || COMPILE_TEST |
| 5 | 17 | select VIDEOBUF2_DMA_CONTIG |
| 6 | 18 | select V4L2_FWNODE |
| 7 | 19 | ---help--- |
| 8 | 20 | Support for Renesas R-Car Video Input (VIN) driver. |
| 9 | − Supports R-Car Gen2 SoCs. | |
| 21 | + Supports R-Car Gen2 and Gen3 SoCs. | |
| 10 | 22 | |
| 11 | 23 | To compile this driver as a module, choose M here: the |
| 12 | 24 | module will be called rcar-vin. |
| @@ -1,3 +1,4 @@ | ||
| 1 | 1 | rcar-vin-objs = rcar-core.o rcar-dma.o rcar-v4l2.o |
| 2 | 2 | |
| 3 | +obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o | |
| 3 | 4 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin.o |
| @@ -20,12 +20,341 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/of_graph.h> |
| 21 | 21 | #include <linux/platform_device.h> |
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | +#include <linux/slab.h> | |
| 24 | +#include <linux/sys_soc.h> | |
| 23 | 25 | |
| 24 | 26 | #include <media/v4l2-async.h> |
| 25 | 27 | #include <media/v4l2-fwnode.h> |
| 28 | +#include <media/v4l2-mc.h> | |
| 26 | 29 | |
| 27 | 30 | #include "rcar-vin.h" |
| 28 | 31 | |
| 32 | +/* | |
| 33 | + * The companion CSI-2 receiver driver (rcar-csi2) is known | |
| 34 | + * and we know it has one source pad (pad 0) and four sink | |
| 35 | + * pads (pad 1-4). So to translate a pad on the remote | |
| 36 | + * CSI-2 receiver to/from the VIN internal channel number simply | |
| 37 | + * subtract/add one from the pad/channel number. | |
| 38 | + */ | |
| 39 | +#define rvin_group_csi_pad_to_channel(pad) ((pad) - 1) | |
| 40 | +#define rvin_group_csi_channel_to_pad(channel) ((channel) + 1) | |
| 41 | + | |
| 42 | +/* | |
| 43 | + * Not all VINs are created equal, master VINs control the | |
| 44 | + * routing for other VIN's. We can figure out which VIN is | |
| 45 | + * master by looking at a VINs id. | |
| 46 | + */ | |
| 47 | +#define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4) | |
| 48 | + | |
| 49 | +/* ----------------------------------------------------------------------------- | |
| 50 | + * Media Controller link notification | |
| 51 | + */ | |
| 52 | + | |
| 53 | +/* group lock should be held when calling this function. */ | |
| 54 | +static int rvin_group_entity_to_csi_id(struct rvin_group *group, | |
| 55 | + struct media_entity *entity) | |
| 56 | +{ | |
| 57 | + struct v4l2_subdev *sd; | |
| 58 | + unsigned int i; | |
| 59 | + | |
| 60 | + sd = media_entity_to_v4l2_subdev(entity); | |
| 61 | + | |
| 62 | + for (i = 0; i < RVIN_CSI_MAX; i++) | |
| 63 | + if (group->csi[i].subdev == sd) | |
| 64 | + return i; | |
| 65 | + | |
| 66 | + return -ENODEV; | |
| 67 | +} | |
| 68 | + | |
| 69 | +static unsigned int rvin_group_get_mask(struct rvin_dev *vin, | |
| 70 | + enum rvin_csi_id csi_id, | |
| 71 | + unsigned char channel) | |
| 72 | +{ | |
| 73 | + const struct rvin_group_route *route; | |
| 74 | + unsigned int mask = 0; | |
| 75 | + | |
| 76 | + for (route = vin->info->routes; route->mask; route++) { | |
| 77 | + if (route->vin == vin->id && | |
| 78 | + route->csi == csi_id && | |
| 79 | + route->channel == channel) { | |
| 80 | + vin_dbg(vin, | |
| 81 | + "Adding route: vin: %d csi: %d channel: %d\n", | |
| 82 | + route->vin, route->csi, route->channel); | |
| 83 | + mask |= route->mask; | |
| 84 | + } | |
| 85 | + } | |
| 86 | + | |
| 87 | + return mask; | |
| 88 | +} | |
| 89 | + | |
| 90 | +/* | |
| 91 | + * Link setup for the links between a VIN and a CSI-2 receiver is a bit | |
| 92 | + * complex. The reason for this is that the register controlling routing | |
| 93 | + * is not present in each VIN instance. There are special VINs which | |
| 94 | + * control routing for themselves and other VINs. There are not many | |
| 95 | + * different possible links combinations that can be enabled at the same | |
| 96 | + * time, therefor all already enabled links which are controlled by a | |
| 97 | + * master VIN need to be taken into account when making the decision | |
| 98 | + * if a new link can be enabled or not. | |
| 99 | + * | |
| 100 | + * 1. Find out which VIN the link the user tries to enable is connected to. | |
| 101 | + * 2. Lookup which master VIN controls the links for this VIN. | |
| 102 | + * 3. Start with a bitmask with all bits set. | |
| 103 | + * 4. For each previously enabled link from the master VIN bitwise AND its | |
| 104 | + * route mask (see documentation for mask in struct rvin_group_route) | |
| 105 | + * with the bitmask. | |
| 106 | + * 5. Bitwise AND the mask for the link the user tries to enable to the bitmask. | |
| 107 | + * 6. If the bitmask is not empty at this point the new link can be enabled | |
| 108 | + * while keeping all previous links enabled. Update the CHSEL value of the | |
| 109 | + * master VIN and inform the user that the link could be enabled. | |
| 110 | + * | |
| 111 | + * Please note that no link can be enabled if any VIN in the group is | |
| 112 | + * currently open. | |
| 113 | + */ | |
| 114 | +static int rvin_group_link_notify(struct media_link *link, u32 flags, | |
| 115 | + unsigned int notification) | |
| 116 | +{ | |
| 117 | + struct rvin_group *group = container_of(link->graph_obj.mdev, | |
| 118 | + struct rvin_group, mdev); | |
| 119 | + unsigned int master_id, channel, mask_new, i; | |
| 120 | + unsigned int mask = ~0; | |
| 121 | + struct media_entity *entity; | |
| 122 | + struct video_device *vdev; | |
| 123 | + struct media_pad *csi_pad; | |
| 124 | + struct rvin_dev *vin = NULL; | |
| 125 | + int csi_id, ret; | |
| 126 | + | |
| 127 | + ret = v4l2_pipeline_link_notify(link, flags, notification); | |
| 128 | + if (ret) | |
| 129 | + return ret; | |
| 130 | + | |
| 131 | + /* Only care about link enablement for VIN nodes. */ | |
| 132 | + if (!(flags & MEDIA_LNK_FL_ENABLED) || | |
| 133 | + !is_media_entity_v4l2_video_device(link->sink->entity)) | |
| 134 | + return 0; | |
| 135 | + | |
| 136 | + /* If any entity is in use don't allow link changes. */ | |
| 137 | + media_device_for_each_entity(entity, &group->mdev) | |
| 138 | + if (entity->use_count) | |
| 139 | + return -EBUSY; | |
| 140 | + | |
| 141 | + mutex_lock(&group->lock); | |
| 142 | + | |
| 143 | + /* Find the master VIN that controls the routes. */ | |
| 144 | + vdev = media_entity_to_video_device(link->sink->entity); | |
| 145 | + vin = container_of(vdev, struct rvin_dev, vdev); | |
| 146 | + master_id = rvin_group_id_to_master(vin->id); | |
| 147 | + | |
| 148 | + if (WARN_ON(!group->vin[master_id])) { | |
| 149 | + ret = -ENODEV; | |
| 150 | + goto out; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /* Build a mask for already enabled links. */ | |
| 154 | + for (i = master_id; i < master_id + 4; i++) { | |
| 155 | + if (!group->vin[i]) | |
| 156 | + continue; | |
| 157 | + | |
| 158 | + /* Get remote CSI-2, if any. */ | |
| 159 | + csi_pad = media_entity_remote_pad( | |
| 160 | + &group->vin[i]->vdev.entity.pads[0]); | |
| 161 | + if (!csi_pad) | |
| 162 | + continue; | |
| 163 | + | |
| 164 | + csi_id = rvin_group_entity_to_csi_id(group, csi_pad->entity); | |
| 165 | + channel = rvin_group_csi_pad_to_channel(csi_pad->index); | |
| 166 | + | |
| 167 | + mask &= rvin_group_get_mask(group->vin[i], csi_id, channel); | |
| 168 | + } | |
| 169 | + | |
| 170 | + /* Add the new link to the existing mask and check if it works. */ | |
| 171 | + csi_id = rvin_group_entity_to_csi_id(group, link->source->entity); | |
| 172 | + channel = rvin_group_csi_pad_to_channel(link->source->index); | |
| 173 | + mask_new = mask & rvin_group_get_mask(vin, csi_id, channel); | |
| 174 | + | |
| 175 | + vin_dbg(vin, "Try link change mask: 0x%x new: 0x%x\n", mask, mask_new); | |
| 176 | + | |
| 177 | + if (!mask_new) { | |
| 178 | + ret = -EMLINK; | |
| 179 | + goto out; | |
| 180 | + } | |
| 181 | + | |
| 182 | + /* New valid CHSEL found, set the new value. */ | |
| 183 | + ret = rvin_set_channel_routing(group->vin[master_id], __ffs(mask_new)); | |
| 184 | +out: | |
| 185 | + mutex_unlock(&group->lock); | |
| 186 | + | |
| 187 | + return ret; | |
| 188 | +} | |
| 189 | + | |
| 190 | +static const struct media_device_ops rvin_media_ops = { | |
| 191 | + .link_notify = rvin_group_link_notify, | |
| 192 | +}; | |
| 193 | + | |
| 194 | +/* ----------------------------------------------------------------------------- | |
| 195 | + * Gen3 CSI2 Group Allocator | |
| 196 | + */ | |
| 197 | + | |
| 198 | +/* FIXME: This should if we find a system that supports more | |
| 199 | + * than one group for the whole system be replaced with a linked | |
| 200 | + * list of groups. And eventually all of this should be replaced | |
| 201 | + * with a global device allocator API. | |
| 202 | + * | |
| 203 | + * But for now this works as on all supported systems there will | |
| 204 | + * be only one group for all instances. | |
| 205 | + */ | |
| 206 | + | |
| 207 | +static DEFINE_MUTEX(rvin_group_lock); | |
| 208 | +static struct rvin_group *rvin_group_data; | |
| 209 | + | |
| 210 | +static void rvin_group_cleanup(struct rvin_group *group) | |
| 211 | +{ | |
| 212 | + media_device_unregister(&group->mdev); | |
| 213 | + media_device_cleanup(&group->mdev); | |
| 214 | + mutex_destroy(&group->lock); | |
| 215 | +} | |
| 216 | + | |
| 217 | +static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin) | |
| 218 | +{ | |
| 219 | + struct media_device *mdev = &group->mdev; | |
| 220 | + const struct of_device_id *match; | |
| 221 | + struct device_node *np; | |
| 222 | + int ret; | |
| 223 | + | |
| 224 | + mutex_init(&group->lock); | |
| 225 | + | |
| 226 | + /* Count number of VINs in the system */ | |
| 227 | + group->count = 0; | |
| 228 | + for_each_matching_node(np, vin->dev->driver->of_match_table) | |
| 229 | + if (of_device_is_available(np)) | |
| 230 | + group->count++; | |
| 231 | + | |
| 232 | + vin_dbg(vin, "found %u enabled VIN's in DT", group->count); | |
| 233 | + | |
| 234 | + mdev->dev = vin->dev; | |
| 235 | + mdev->ops = &rvin_media_ops; | |
| 236 | + | |
| 237 | + match = of_match_node(vin->dev->driver->of_match_table, | |
| 238 | + vin->dev->of_node); | |
| 239 | + | |
| 240 | + strlcpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name)); | |
| 241 | + strlcpy(mdev->model, match->compatible, sizeof(mdev->model)); | |
| 242 | + snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", | |
| 243 | + dev_name(mdev->dev)); | |
| 244 | + | |
| 245 | + media_device_init(mdev); | |
| 246 | + | |
| 247 | + ret = media_device_register(&group->mdev); | |
| 248 | + if (ret) | |
| 249 | + rvin_group_cleanup(group); | |
| 250 | + | |
| 251 | + return ret; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static void rvin_group_release(struct kref *kref) | |
| 255 | +{ | |
| 256 | + struct rvin_group *group = | |
| 257 | + container_of(kref, struct rvin_group, refcount); | |
| 258 | + | |
| 259 | + mutex_lock(&rvin_group_lock); | |
| 260 | + | |
| 261 | + rvin_group_data = NULL; | |
| 262 | + | |
| 263 | + rvin_group_cleanup(group); | |
| 264 | + | |
| 265 | + kfree(group); | |
| 266 | + | |
| 267 | + mutex_unlock(&rvin_group_lock); | |
| 268 | +} | |
| 269 | + | |
| 270 | +static int rvin_group_get(struct rvin_dev *vin) | |
| 271 | +{ | |
| 272 | + struct rvin_group *group; | |
| 273 | + u32 id; | |
| 274 | + int ret; | |
| 275 | + | |
| 276 | + /* Make sure VIN id is present and sane */ | |
| 277 | + ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id); | |
| 278 | + if (ret) { | |
| 279 | + vin_err(vin, "%pOF: No renesas,id property found\n", | |
| 280 | + vin->dev->of_node); | |
| 281 | + return -EINVAL; | |
| 282 | + } | |
| 283 | + | |
| 284 | + if (id >= RCAR_VIN_NUM) { | |
| 285 | + vin_err(vin, "%pOF: Invalid renesas,id '%u'\n", | |
| 286 | + vin->dev->of_node, id); | |
| 287 | + return -EINVAL; | |
| 288 | + } | |
| 289 | + | |
| 290 | + /* Join or create a VIN group */ | |
| 291 | + mutex_lock(&rvin_group_lock); | |
| 292 | + if (rvin_group_data) { | |
| 293 | + group = rvin_group_data; | |
| 294 | + kref_get(&group->refcount); | |
| 295 | + } else { | |
| 296 | + group = kzalloc(sizeof(*group), GFP_KERNEL); | |
| 297 | + if (!group) { | |
| 298 | + ret = -ENOMEM; | |
| 299 | + goto err_group; | |
| 300 | + } | |
| 301 | + | |
| 302 | + ret = rvin_group_init(group, vin); | |
| 303 | + if (ret) { | |
| 304 | + kfree(group); | |
| 305 | + vin_err(vin, "Failed to initialize group\n"); | |
| 306 | + goto err_group; | |
| 307 | + } | |
| 308 | + | |
| 309 | + kref_init(&group->refcount); | |
| 310 | + | |
| 311 | + rvin_group_data = group; | |
| 312 | + } | |
| 313 | + mutex_unlock(&rvin_group_lock); | |
| 314 | + | |
| 315 | + /* Add VIN to group */ | |
| 316 | + mutex_lock(&group->lock); | |
| 317 | + | |
| 318 | + if (group->vin[id]) { | |
| 319 | + vin_err(vin, "Duplicate renesas,id property value %u\n", id); | |
| 320 | + mutex_unlock(&group->lock); | |
| 321 | + kref_put(&group->refcount, rvin_group_release); | |
| 322 | + return -EINVAL; | |
| 323 | + } | |
| 324 | + | |
| 325 | + group->vin[id] = vin; | |
| 326 | + | |
| 327 | + vin->id = id; | |
| 328 | + vin->group = group; | |
| 329 | + vin->v4l2_dev.mdev = &group->mdev; | |
| 330 | + | |
| 331 | + mutex_unlock(&group->lock); | |
| 332 | + | |
| 333 | + return 0; | |
| 334 | +err_group: | |
| 335 | + mutex_unlock(&rvin_group_lock); | |
| 336 | + return ret; | |
| 337 | +} | |
| 338 | + | |
| 339 | +static void rvin_group_put(struct rvin_dev *vin) | |
| 340 | +{ | |
| 341 | + struct rvin_group *group = vin->group; | |
| 342 | + | |
| 343 | + mutex_lock(&group->lock); | |
| 344 | + | |
| 345 | + vin->group = NULL; | |
| 346 | + vin->v4l2_dev.mdev = NULL; | |
| 347 | + | |
| 348 | + if (WARN_ON(group->vin[vin->id] != vin)) | |
| 349 | + goto out; | |
| 350 | + | |
| 351 | + group->vin[vin->id] = NULL; | |
| 352 | +out: | |
| 353 | + mutex_unlock(&group->lock); | |
| 354 | + | |
| 355 | + kref_put(&group->refcount, rvin_group_release); | |
| 356 | +} | |
| 357 | + | |
| 29 | 358 | /* ----------------------------------------------------------------------------- |
| 30 | 359 | * Async notifier |
| 31 | 360 | */ |
| @@ -46,30 +375,93 @@ static int rvin_find_pad(struct v4l2_subdev *sd, int direction) · 14 unmodified lines | ||
| 46 | 375 | return -EINVAL; |
| 47 | 376 | } |
| 48 | 377 | |
| 49 | −static bool rvin_mbus_supported(struct rvin_graph_entity *entity) | |
| 378 | +/* ----------------------------------------------------------------------------- | |
| 379 | + * Digital async notifier | |
| 380 | + */ | |
| 381 | + | |
| 382 | +/* The vin lock should be held when calling the subdevice attach and detach */ | |
| 383 | +static int rvin_digital_subdevice_attach(struct rvin_dev *vin, | |
| 384 | + struct v4l2_subdev *subdev) | |
| 50 | 385 | { |
| 51 | − struct v4l2_subdev *sd = entity->subdev; | |
| 52 | 386 | struct v4l2_subdev_mbus_code_enum code = { |
| 53 | 387 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
| 54 | 388 | }; |
| 389 | + int ret; | |
| 55 | 390 | |
| 391 | + /* Find source and sink pad of remote subdevice */ | |
| 392 | + ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); | |
| 393 | + if (ret < 0) | |
| 394 | + return ret; | |
| 395 | + vin->digital->source_pad = ret; | |
| 396 | + | |
| 397 | + ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); | |
| 398 | + vin->digital->sink_pad = ret < 0 ? 0 : ret; | |
| 399 | + | |
| 400 | + /* Find compatible subdevices mbus format */ | |
| 401 | + vin->mbus_code = 0; | |
| 56 | 402 | code.index = 0; |
| 57 | − code.pad = entity->source_pad; | |
| 58 | − while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { | |
| 403 | + code.pad = vin->digital->source_pad; | |
| 404 | + while (!vin->mbus_code && | |
| 405 | + !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) { | |
| 59 | 406 | code.index++; |
| 60 | 407 | switch (code.code) { |
| 61 | 408 | case MEDIA_BUS_FMT_YUYV8_1X16: |
| 409 | + case MEDIA_BUS_FMT_UYVY8_1X16: | |
| 62 | 410 | case MEDIA_BUS_FMT_UYVY8_2X8: |
| 63 | 411 | case MEDIA_BUS_FMT_UYVY10_2X10: |
| 64 | 412 | case MEDIA_BUS_FMT_RGB888_1X24: |
| 65 | − entity->code = code.code; | |
| 66 | − return true; | |
| 413 | + vin->mbus_code = code.code; | |
| 414 | + vin_dbg(vin, "Found media bus format for %s: %d\n", | |
| 415 | + subdev->name, vin->mbus_code); | |
| 416 | + break; | |
| 67 | 417 | default: |
| 68 | 418 | break; |
| 69 | 419 | } |
| 70 | 420 | } |
| 71 | 421 | |
| 72 | − return false; | |
| 422 | + if (!vin->mbus_code) { | |
| 423 | + vin_err(vin, "Unsupported media bus format for %s\n", | |
| 424 | + subdev->name); | |
| 425 | + return -EINVAL; | |
| 426 | + } | |
| 427 | + | |
| 428 | + /* Read tvnorms */ | |
| 429 | + ret = v4l2_subdev_call(subdev, video, g_tvnorms, &vin->vdev.tvnorms); | |
| 430 | + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | |
| 431 | + return ret; | |
| 432 | + | |
| 433 | + /* Read standard */ | |
| 434 | + vin->std = V4L2_STD_UNKNOWN; | |
| 435 | + ret = v4l2_subdev_call(subdev, video, g_std, &vin->std); | |
| 436 | + if (ret < 0 && ret != -ENOIOCTLCMD) | |
| 437 | + return ret; | |
| 438 | + | |
| 439 | + /* Add the controls */ | |
| 440 | + ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16); | |
| 441 | + if (ret < 0) | |
| 442 | + return ret; | |
| 443 | + | |
| 444 | + ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler, | |
| 445 | + NULL); | |
| 446 | + if (ret < 0) { | |
| 447 | + v4l2_ctrl_handler_free(&vin->ctrl_handler); | |
| 448 | + return ret; | |
| 449 | + } | |
| 450 | + | |
| 451 | + vin->vdev.ctrl_handler = &vin->ctrl_handler; | |
| 452 | + | |
| 453 | + vin->digital->subdev = subdev; | |
| 454 | + | |
| 455 | + return 0; | |
| 456 | +} | |
| 457 | + | |
| 458 | +static void rvin_digital_subdevice_detach(struct rvin_dev *vin) | |
| 459 | +{ | |
| 460 | + rvin_v4l2_unregister(vin); | |
| 461 | + v4l2_ctrl_handler_free(&vin->ctrl_handler); | |
| 462 | + | |
| 463 | + vin->vdev.ctrl_handler = NULL; | |
| 464 | + vin->digital->subdev = NULL; | |
| 73 | 465 | } |
| 74 | 466 | |
| 75 | 467 | static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier) |
| @@ -77,23 +469,13 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier) · 1 unmodified line | ||
| 77 | 469 | struct rvin_dev *vin = notifier_to_vin(notifier); |
| 78 | 470 | int ret; |
| 79 | 471 | |
| 80 | − /* Verify subdevices mbus format */ | |
| 81 | − if (!rvin_mbus_supported(vin->digital)) { | |
| 82 | − vin_err(vin, "Unsupported media bus format for %s\n", | |
| 83 | − vin->digital->subdev->name); | |
| 84 | − return -EINVAL; | |
| 85 | − } | |
| 86 | − | |
| 87 | − vin_dbg(vin, "Found media bus format for %s: %d\n", | |
| 88 | − vin->digital->subdev->name, vin->digital->code); | |
| 89 | − | |
| 90 | 472 | ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); |
| 91 | 473 | if (ret < 0) { |
| 92 | 474 | vin_err(vin, "Failed to register subdev nodes\n"); |
| 93 | 475 | return ret; |
| 94 | 476 | } |
| 95 | 477 | |
| 96 | − return rvin_v4l2_probe(vin); | |
| 478 | + return rvin_v4l2_register(vin); | |
| 97 | 479 | } |
| 98 | 480 | |
| 99 | 481 | static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier, |
| @@ -103,8 +485,10 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier, · 3 unmodified lines | ||
| 103 | 485 | struct rvin_dev *vin = notifier_to_vin(notifier); |
| 104 | 486 | |
| 105 | 487 | vin_dbg(vin, "unbind digital subdev %s\n", subdev->name); |
| 106 | − rvin_v4l2_remove(vin); | |
| 107 | − vin->digital->subdev = NULL; | |
| 488 | + | |
| 489 | + mutex_lock(&vin->lock); | |
| 490 | + rvin_digital_subdevice_detach(vin); | |
| 491 | + mutex_unlock(&vin->lock); | |
| 108 | 492 | } |
| 109 | 493 | |
| 110 | 494 | static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, |
| @@ -114,19 +498,13 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, · 3 unmodified lines | ||
| 114 | 498 | struct rvin_dev *vin = notifier_to_vin(notifier); |
| 115 | 499 | int ret; |
| 116 | 500 | |
| 117 | − v4l2_set_subdev_hostdata(subdev, vin); | |
| 118 | − | |
| 119 | − /* Find source and sink pad of remote subdevice */ | |
| 120 | − | |
| 121 | − ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); | |
| 122 | − if (ret < 0) | |
| 501 | + mutex_lock(&vin->lock); | |
| 502 | + ret = rvin_digital_subdevice_attach(vin, subdev); | |
| 503 | + mutex_unlock(&vin->lock); | |
| 504 | + if (ret) | |
| 123 | 505 | return ret; |
| 124 | − vin->digital->source_pad = ret; | |
| 125 | 506 | |
| 126 | − ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); | |
| 127 | − vin->digital->sink_pad = ret < 0 ? 0 : ret; | |
| 128 | − | |
| 129 | − vin->digital->subdev = subdev; | |
| 507 | + v4l2_set_subdev_hostdata(subdev, vin); | |
| 130 | 508 | |
| 131 | 509 | vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n", |
| 132 | 510 | subdev->name, vin->digital->source_pad, |
| @@ -134,13 +512,13 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, · 1 unmodified line | ||
| 134 | 512 | |
| 135 | 513 | return 0; |
| 136 | 514 | } |
| 515 | + | |
| 137 | 516 | static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = { |
| 138 | 517 | .bound = rvin_digital_notify_bound, |
| 139 | 518 | .unbind = rvin_digital_notify_unbind, |
| 140 | 519 | .complete = rvin_digital_notify_complete, |
| 141 | 520 | }; |
| 142 | 521 | |
| 143 | − | |
| 144 | 522 | static int rvin_digital_parse_v4l2(struct device *dev, |
| 145 | 523 | struct v4l2_fwnode_endpoint *vep, |
| 146 | 524 | struct v4l2_async_subdev *asd) |
| @@ -152,16 +530,16 @@ static int rvin_digital_parse_v4l2(struct device *dev, · 5 unmodified lines | ||
| 152 | 530 | if (vep->base.port || vep->base.id) |
| 153 | 531 | return -ENOTCONN; |
| 154 | 532 | |
| 155 | − rvge->mbus_cfg.type = vep->bus_type; | |
| 533 | + vin->mbus_cfg.type = vep->bus_type; | |
| 156 | 534 | |
| 157 | − switch (rvge->mbus_cfg.type) { | |
| 535 | + switch (vin->mbus_cfg.type) { | |
| 158 | 536 | case V4L2_MBUS_PARALLEL: |
| 159 | 537 | vin_dbg(vin, "Found PARALLEL media bus\n"); |
| 160 | − rvge->mbus_cfg.flags = vep->bus.parallel.flags; | |
| 538 | + vin->mbus_cfg.flags = vep->bus.parallel.flags; | |
| 161 | 539 | break; |
| 162 | 540 | case V4L2_MBUS_BT656: |
| 163 | 541 | vin_dbg(vin, "Found BT656 media bus\n"); |
| 164 | − rvge->mbus_cfg.flags = 0; | |
| 542 | + vin->mbus_cfg.flags = 0; | |
| 165 | 543 | break; |
| 166 | 544 | default: |
| 167 | 545 | vin_err(vin, "Unknown media bus type\n"); |
| @@ -199,25 +577,478 @@ static int rvin_digital_graph_init(struct rvin_dev *vin) · 31 unmodified lines | ||
| 199 | 577 | return 0; |
| 200 | 578 | } |
| 201 | 579 | |
| 580 | +/* ----------------------------------------------------------------------------- | |
| 581 | + * Group async notifier | |
| 582 | + */ | |
| 583 | + | |
| 584 | +static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) | |
| 585 | +{ | |
| 586 | + struct rvin_dev *vin = notifier_to_vin(notifier); | |
| 587 | + const struct rvin_group_route *route; | |
| 588 | + unsigned int i; | |
| 589 | + int ret; | |
| 590 | + | |
| 591 | + ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); | |
| 592 | + if (ret) { | |
| 593 | + vin_err(vin, "Failed to register subdev nodes\n"); | |
| 594 | + return ret; | |
| 595 | + } | |
| 596 | + | |
| 597 | + /* Register all video nodes for the group. */ | |
| 598 | + for (i = 0; i < RCAR_VIN_NUM; i++) { | |
| 599 | + if (vin->group->vin[i]) { | |
| 600 | + ret = rvin_v4l2_register(vin->group->vin[i]); | |
| 601 | + if (ret) | |
| 602 | + return ret; | |
| 603 | + } | |
| 604 | + } | |
| 605 | + | |
| 606 | + /* Create all media device links between VINs and CSI-2's. */ | |
| 607 | + mutex_lock(&vin->group->lock); | |
| 608 | + for (route = vin->info->routes; route->mask; route++) { | |
| 609 | + struct media_pad *source_pad, *sink_pad; | |
| 610 | + struct media_entity *source, *sink; | |
| 611 | + unsigned int source_idx; | |
| 612 | + | |
| 613 | + /* Check that VIN is part of the group. */ | |
| 614 | + if (!vin->group->vin[route->vin]) | |
| 615 | + continue; | |
| 616 | + | |
| 617 | + /* Check that VIN' master is part of the group. */ | |
| 618 | + if (!vin->group->vin[rvin_group_id_to_master(route->vin)]) | |
| 619 | + continue; | |
| 620 | + | |
| 621 | + /* Check that CSI-2 is part of the group. */ | |
| 622 | + if (!vin->group->csi[route->csi].subdev) | |
| 623 | + continue; | |
| 624 | + | |
| 625 | + source = &vin->group->csi[route->csi].subdev->entity; | |
| 626 | + source_idx = rvin_group_csi_channel_to_pad(route->channel); | |
| 627 | + source_pad = &source->pads[source_idx]; | |
| 628 | + | |
| 629 | + sink = &vin->group->vin[route->vin]->vdev.entity; | |
| 630 | + sink_pad = &sink->pads[0]; | |
| 631 | + | |
| 632 | + /* Skip if link already exists. */ | |
| 633 | + if (media_entity_find_link(source_pad, sink_pad)) | |
| 634 | + continue; | |
| 635 | + | |
| 636 | + ret = media_create_pad_link(source, source_idx, sink, 0, 0); | |
| 637 | + if (ret) { | |
| 638 | + vin_err(vin, "Error adding link from %s to %s\n", | |
| 639 | + source->name, sink->name); | |
| 640 | + break; | |
| 641 | + } | |
| 642 | + } | |
| 643 | + mutex_unlock(&vin->group->lock); | |
| 644 | + | |
| 645 | + return ret; | |
| 646 | +} | |
| 647 | + | |
| 648 | +static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, | |
| 649 | + struct v4l2_subdev *subdev, | |
| 650 | + struct v4l2_async_subdev *asd) | |
| 651 | +{ | |
| 652 | + struct rvin_dev *vin = notifier_to_vin(notifier); | |
| 653 | + unsigned int i; | |
| 654 | + | |
| 655 | + for (i = 0; i < RCAR_VIN_NUM; i++) | |
| 656 | + if (vin->group->vin[i]) | |
| 657 | + rvin_v4l2_unregister(vin->group->vin[i]); | |
| 658 | + | |
| 659 | + mutex_lock(&vin->group->lock); | |
| 660 | + | |
| 661 | + for (i = 0; i < RVIN_CSI_MAX; i++) { | |
| 662 | + if (vin->group->csi[i].fwnode != asd->match.fwnode) | |
| 663 | + continue; | |
| 664 | + vin->group->csi[i].subdev = NULL; | |
| 665 | + vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); | |
| 666 | + break; | |
| 667 | + } | |
| 668 | + | |
| 669 | + mutex_unlock(&vin->group->lock); | |
| 670 | +} | |
| 671 | + | |
| 672 | +static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, | |
| 673 | + struct v4l2_subdev *subdev, | |
| 674 | + struct v4l2_async_subdev *asd) | |
| 675 | +{ | |
| 676 | + struct rvin_dev *vin = notifier_to_vin(notifier); | |
| 677 | + unsigned int i; | |
| 678 | + | |
| 679 | + mutex_lock(&vin->group->lock); | |
| 680 | + | |
| 681 | + for (i = 0; i < RVIN_CSI_MAX; i++) { | |
| 682 | + if (vin->group->csi[i].fwnode != asd->match.fwnode) | |
| 683 | + continue; | |
| 684 | + vin->group->csi[i].subdev = subdev; | |
| 685 | + vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i); | |
| 686 | + break; | |
| 687 | + } | |
| 688 | + | |
| 689 | + mutex_unlock(&vin->group->lock); | |
| 690 | + | |
| 691 | + return 0; | |
| 692 | +} | |
| 693 | + | |
| 694 | +static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { | |
| 695 | + .bound = rvin_group_notify_bound, | |
| 696 | + .unbind = rvin_group_notify_unbind, | |
| 697 | + .complete = rvin_group_notify_complete, | |
| 698 | +}; | |
| 699 | + | |
| 700 | +static int rvin_mc_parse_of_endpoint(struct device *dev, | |
| 701 | + struct v4l2_fwnode_endpoint *vep, | |
| 702 | + struct v4l2_async_subdev *asd) | |
| 703 | +{ | |
| 704 | + struct rvin_dev *vin = dev_get_drvdata(dev); | |
| 705 | + | |
| 706 | + if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX) | |
| 707 | + return -EINVAL; | |
| 708 | + | |
| 709 | + if (!of_device_is_available(to_of_node(asd->match.fwnode))) { | |
| 710 | + | |
| 711 | + vin_dbg(vin, "OF device %pOF disabled, ignoring\n", | |
| 712 | + to_of_node(asd->match.fwnode)); | |
| 713 | + return -ENOTCONN; | |
| 714 | + | |
| 715 | + } | |
| 716 | + | |
| 717 | + if (vin->group->csi[vep->base.id].fwnode) { | |
| 718 | + vin_dbg(vin, "OF device %pOF already handled\n", | |
| 719 | + to_of_node(asd->match.fwnode)); | |
| 720 | + return -ENOTCONN; | |
| 721 | + } | |
| 722 | + | |
| 723 | + vin->group->csi[vep->base.id].fwnode = asd->match.fwnode; | |
| 724 | + | |
| 725 | + vin_dbg(vin, "Add group OF device %pOF to slot %u\n", | |
| 726 | + to_of_node(asd->match.fwnode), vep->base.id); | |
| 727 | + | |
| 728 | + return 0; | |
| 729 | +} | |
| 730 | + | |
| 731 | +static int rvin_mc_parse_of_graph(struct rvin_dev *vin) | |
| 732 | +{ | |
| 733 | + unsigned int count = 0; | |
| 734 | + unsigned int i; | |
| 735 | + int ret; | |
| 736 | + | |
| 737 | + mutex_lock(&vin->group->lock); | |
| 738 | + | |
| 739 | + /* If there already is a notifier something has gone wrong, bail out. */ | |
| 740 | + if (WARN_ON(vin->group->notifier)) { | |
| 741 | + mutex_unlock(&vin->group->lock); | |
| 742 | + return -EINVAL; | |
| 743 | + } | |
| 744 | + | |
| 745 | + /* If not all VIN's are registered don't register the notifier. */ | |
| 746 | + for (i = 0; i < RCAR_VIN_NUM; i++) | |
| 747 | + if (vin->group->vin[i]) | |
| 748 | + count++; | |
| 749 | + | |
| 750 | + if (vin->group->count != count) { | |
| 751 | + mutex_unlock(&vin->group->lock); | |
| 752 | + return 0; | |
| 753 | + } | |
| 754 | + | |
| 755 | + /* | |
| 756 | + * Have all VIN's look for subdevices. Some subdevices will overlap | |
| 757 | + * but the parser function can handle it, so each subdevice will | |
| 758 | + * only be registered once with the notifier. | |
| 759 | + */ | |
| 760 | + | |
| 761 | + vin->group->notifier = &vin->notifier; | |
| 762 | + | |
| 763 | + for (i = 0; i < RCAR_VIN_NUM; i++) { | |
| 764 | + if (!vin->group->vin[i]) | |
| 765 | + continue; | |
| 766 | + | |
| 767 | + ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( | |
| 768 | + vin->group->vin[i]->dev, vin->group->notifier, | |
| 769 | + sizeof(struct v4l2_async_subdev), 1, | |
| 770 | + rvin_mc_parse_of_endpoint); | |
| 771 | + if (ret) { | |
| 772 | + mutex_unlock(&vin->group->lock); | |
| 773 | + return ret; | |
| 774 | + } | |
| 775 | + } | |
| 776 | + | |
| 777 | + mutex_unlock(&vin->group->lock); | |
| 778 | + | |
| 779 | + vin->group->notifier->ops = &rvin_group_notify_ops; | |
| 780 | + | |
| 781 | + ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); | |
| 782 | + if (ret < 0) { | |
| 783 | + vin_err(vin, "Notifier registration failed\n"); | |
| 784 | + return ret; | |
| 785 | + } | |
| 786 | + | |
| 787 | + return 0; | |
| 788 | +} | |
| 789 | + | |
| 790 | +static int rvin_mc_init(struct rvin_dev *vin) | |
| 791 | +{ | |
| 792 | + int ret; | |
| 793 | + | |
| 794 | + /* All our sources are CSI-2 */ | |
| 795 | + vin->mbus_cfg.type = V4L2_MBUS_CSI2; | |
| 796 | + vin->mbus_cfg.flags = 0; | |
| 797 | + | |
| 798 | + vin->pad.flags = MEDIA_PAD_FL_SINK; | |
| 799 | + ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); | |
| 800 | + if (ret) | |
| 801 | + return ret; | |
| 802 | + | |
| 803 | + ret = rvin_group_get(vin); | |
| 804 | + if (ret) | |
| 805 | + return ret; | |
| 806 | + | |
| 807 | + ret = rvin_mc_parse_of_graph(vin); | |
| 808 | + if (ret) | |
| 809 | + rvin_group_put(vin); | |
| 810 | + | |
| 811 | + return ret; | |
| 812 | +} | |
| 813 | + | |
| 202 | 814 | /* ----------------------------------------------------------------------------- |
| 203 | 815 | * Platform Device Driver |
| 204 | 816 | */ |
| 205 | 817 | |
| 818 | +static const struct rvin_info rcar_info_h1 = { | |
| 819 | + .model = RCAR_H1, | |
| 820 | + .use_mc = false, | |
| 821 | + .max_width = 2048, | |
| 822 | + .max_height = 2048, | |
| 823 | +}; | |
| 824 | + | |
| 825 | +static const struct rvin_info rcar_info_m1 = { | |
| 826 | + .model = RCAR_M1, | |
| 827 | + .use_mc = false, | |
| 828 | + .max_width = 2048, | |
| 829 | + .max_height = 2048, | |
| 830 | +}; | |
| 831 | + | |
| 832 | +static const struct rvin_info rcar_info_gen2 = { | |
| 833 | + .model = RCAR_GEN2, | |
| 834 | + .use_mc = false, | |
| 835 | + .max_width = 2048, | |
| 836 | + .max_height = 2048, | |
| 837 | +}; | |
| 838 | + | |
| 839 | +static const struct rvin_group_route rcar_info_r8a7795_routes[] = { | |
| 840 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, | |
| 841 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) }, | |
| 842 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) }, | |
| 843 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) }, | |
| 844 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) }, | |
| 845 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) }, | |
| 846 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) }, | |
| 847 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) }, | |
| 848 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) }, | |
| 849 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) }, | |
| 850 | + { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) }, | |
| 851 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) }, | |
| 852 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) }, | |
| 853 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) }, | |
| 854 | + { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) }, | |
| 855 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) }, | |
| 856 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) }, | |
| 857 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) }, | |
| 858 | + { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) }, | |
| 859 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) }, | |
| 860 | + { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) }, | |
| 861 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) }, | |
| 862 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) }, | |
| 863 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) }, | |
| 864 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) }, | |
| 865 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) }, | |
| 866 | + { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) }, | |
| 867 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) }, | |
| 868 | + { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) }, | |
| 869 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) }, | |
| 870 | + { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) }, | |
| 871 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) }, | |
| 872 | + { /* Sentinel */ } | |
| 873 | +}; | |
| 874 | + | |
| 875 | +static const struct rvin_info rcar_info_r8a7795 = { | |
| 876 | + .model = RCAR_GEN3, | |
| 877 | + .use_mc = true, | |
| 878 | + .max_width = 4096, | |
| 879 | + .max_height = 4096, | |
| 880 | + .routes = rcar_info_r8a7795_routes, | |
| 881 | +}; | |
| 882 | + | |
| 883 | +static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = { | |
| 884 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, | |
| 885 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) }, | |
| 886 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 0, .mask = BIT(2) | BIT(5) }, | |
| 887 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) }, | |
| 888 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 1, .mask = BIT(1) }, | |
| 889 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) }, | |
| 890 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) }, | |
| 891 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) }, | |
| 892 | + { .csi = RVIN_CSI21, .channel = 1, .vin = 1, .mask = BIT(5) }, | |
| 893 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 2, .mask = BIT(0) }, | |
| 894 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) }, | |
| 895 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) }, | |
| 896 | + { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) }, | |
| 897 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) }, | |
| 898 | + { .csi = RVIN_CSI21, .channel = 2, .vin = 2, .mask = BIT(5) }, | |
| 899 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) }, | |
| 900 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) }, | |
| 901 | + { .csi = RVIN_CSI21, .channel = 1, .vin = 3, .mask = BIT(2) }, | |
| 902 | + { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) }, | |
| 903 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) }, | |
| 904 | + { .csi = RVIN_CSI21, .channel = 3, .vin = 3, .mask = BIT(5) }, | |
| 905 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) }, | |
| 906 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) }, | |
| 907 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 4, .mask = BIT(2) | BIT(5) }, | |
| 908 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) }, | |
| 909 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 5, .mask = BIT(1) }, | |
| 910 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) }, | |
| 911 | + { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(3) }, | |
| 912 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) }, | |
| 913 | + { .csi = RVIN_CSI21, .channel = 1, .vin = 5, .mask = BIT(5) }, | |
| 914 | + { .csi = RVIN_CSI21, .channel = 0, .vin = 6, .mask = BIT(0) }, | |
| 915 | + { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) }, | |
| 916 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) }, | |
| 917 | + { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) }, | |
| 918 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) }, | |
| 919 | + { .csi = RVIN_CSI21, .channel = 2, .vin = 6, .mask = BIT(5) }, | |
| 920 | + { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) }, | |
| 921 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) }, | |
| 922 | + { .csi = RVIN_CSI21, .channel = 1, .vin = 7, .mask = BIT(2) }, | |
| 923 | + { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) }, | |
| 924 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) }, | |
| 925 | + { .csi = RVIN_CSI21, .channel = 3, .vin = 7, .mask = BIT(5) }, | |
| 926 | + { /* Sentinel */ } | |
| 927 | +}; | |
| 928 | + | |
| 929 | +static const struct rvin_info rcar_info_r8a7795es1 = { | |
| 930 | + .model = RCAR_GEN3, | |
| 931 | + .use_mc = true, | |
| 932 | + .max_width = 4096, | |
| 933 | + .max_height = 4096, | |
| 934 | + .routes = rcar_info_r8a7795es1_routes, | |
| 935 | +}; | |
| 936 | + | |
| 937 | +static const struct rvin_group_route rcar_info_r8a7796_routes[] = { | |
| 938 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, | |
| 939 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) }, | |
| 940 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) }, | |
| 941 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) }, | |
| 942 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) }, | |
| 943 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) }, | |
| 944 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) }, | |
| 945 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) }, | |
| 946 | + { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) }, | |
| 947 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) }, | |
| 948 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) }, | |
| 949 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) }, | |
| 950 | + { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) }, | |
| 951 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) }, | |
| 952 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) }, | |
| 953 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) }, | |
| 954 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) }, | |
| 955 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) }, | |
| 956 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(3) }, | |
| 957 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) }, | |
| 958 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) }, | |
| 959 | + { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) }, | |
| 960 | + { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) }, | |
| 961 | + { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) }, | |
| 962 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) }, | |
| 963 | + { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) }, | |
| 964 | + { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) }, | |
| 965 | + { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) }, | |
| 966 | + { /* Sentinel */ } | |
| 967 | +}; | |
| 968 | + | |
| 969 | +static const struct rvin_info rcar_info_r8a7796 = { | |
| 970 | + .model = RCAR_GEN3, | |
| 971 | + .use_mc = true, | |
| 972 | + .max_width = 4096, | |
| 973 | + .max_height = 4096, | |
| 974 | + .routes = rcar_info_r8a7796_routes, | |
| 975 | +}; | |
| 976 | + | |
| 977 | +static const struct rvin_group_route _rcar_info_r8a77970_routes[] = { | |
| 978 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, | |
| 979 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) }, | |
| 980 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) }, | |
| 981 | + { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) }, | |
| 982 | + { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) }, | |
| 983 | + { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) }, | |
| 984 | + { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) }, | |
| 985 | + { /* Sentinel */ } | |
| 986 | +}; | |
| 987 | + | |
| 988 | +static const struct rvin_info rcar_info_r8a77970 = { | |
| 989 | + .model = RCAR_GEN3, | |
| 990 | + .use_mc = true, | |
| 991 | + .max_width = 4096, | |
| 992 | + .max_height = 4096, | |
| 993 | + .routes = _rcar_info_r8a77970_routes, | |
| 994 | +}; | |
| 995 | + | |
| 206 | 996 | static const struct of_device_id rvin_of_id_table[] = { |
| 207 | − { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 }, | |
| 208 | − { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 }, | |
| 209 | − { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 }, | |
| 210 | − { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, | |
| 211 | − { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, | |
| 212 | − { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, | |
| 213 | − { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 }, | |
| 214 | − { }, | |
| 997 | + { | |
| 998 | + .compatible = "renesas,vin-r8a7778", | |
| 999 | + .data = &rcar_info_m1, | |
| 1000 | + }, | |
| 1001 | + { | |
| 1002 | + .compatible = "renesas,vin-r8a7779", | |
| 1003 | + .data = &rcar_info_h1, | |
| 1004 | + }, | |
| 1005 | + { | |
| 1006 | + .compatible = "renesas,vin-r8a7790", | |
| 1007 | + .data = &rcar_info_gen2, | |
| 1008 | + }, | |
| 1009 | + { | |
| 1010 | + .compatible = "renesas,vin-r8a7791", | |
| 1011 | + .data = &rcar_info_gen2, | |
| 1012 | + }, | |
| 1013 | + { | |
| 1014 | + .compatible = "renesas,vin-r8a7793", | |
| 1015 | + .data = &rcar_info_gen2, | |
| 1016 | + }, | |
| 1017 | + { | |
| 1018 | + .compatible = "renesas,vin-r8a7794", | |
| 1019 | + .data = &rcar_info_gen2, | |
| 1020 | + }, | |
| 1021 | + { | |
| 1022 | + .compatible = "renesas,rcar-gen2-vin", | |
| 1023 | + .data = &rcar_info_gen2, | |
| 1024 | + }, | |
| 1025 | + { | |
| 1026 | + .compatible = "renesas,vin-r8a7795", | |
| 1027 | + .data = &rcar_info_r8a7795, | |
| 1028 | + }, | |
| 1029 | + { | |
| 1030 | + .compatible = "renesas,vin-r8a7796", | |
| 1031 | + .data = &rcar_info_r8a7796, | |
| 1032 | + }, | |
| 1033 | + { | |
| 1034 | + .compatible = "renesas,vin-r8a77970", | |
| 1035 | + .data = &rcar_info_r8a77970, | |
| 1036 | + }, | |
| 1037 | + { /* Sentinel */ }, | |
| 215 | 1038 | }; |
| 216 | 1039 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); |
| 217 | 1040 | |
| 1041 | +static const struct soc_device_attribute r8a7795es1[] = { | |
| 1042 | + { | |
| 1043 | + .soc_id = "r8a7795", .revision = "ES1.*", | |
| 1044 | + .data = &rcar_info_r8a7795es1, | |
| 1045 | + }, | |
| 1046 | + { /* Sentinel */ } | |
| 1047 | +}; | |
| 1048 | + | |
| 218 | 1049 | static int rcar_vin_probe(struct platform_device *pdev) |
| 219 | 1050 | { |
| 220 | − const struct of_device_id *match; | |
| 1051 | + const struct soc_device_attribute *attr; | |
| 221 | 1052 | struct rvin_dev *vin; |
| 222 | 1053 | struct resource *mem; |
| 223 | 1054 | int irq, ret; |
| @@ -226,12 +1057,16 @@ static int rcar_vin_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 226 | 1057 | if (!vin) |
| 227 | 1058 | return -ENOMEM; |
| 228 | 1059 | |
| 229 | − match = of_match_device(of_match_ptr(rvin_of_id_table), &pdev->dev); | |
| 230 | − if (!match) | |
| 231 | − return -ENODEV; | |
| 232 | − | |
| 233 | 1060 | vin->dev = &pdev->dev; |
| 234 | − vin->chip = (enum chip_id)match->data; | |
| 1061 | + vin->info = of_device_get_match_data(&pdev->dev); | |
| 1062 | + | |
| 1063 | + /* | |
| 1064 | + * Special care is needed on r8a7795 ES1.x since it | |
| 1065 | + * uses different routing than r8a7795 ES2.0. | |
| 1066 | + */ | |
| 1067 | + attr = soc_device_match(r8a7795es1); | |
| 1068 | + if (attr) | |
| 1069 | + vin->info = attr->data; | |
| 235 | 1070 | |
| 236 | 1071 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 237 | 1072 | if (mem == NULL) |
| @@ -245,13 +1080,15 @@ static int rcar_vin_probe(struct platform_device *pdev) · 7 unmodified lines | ||
| 245 | 1080 | if (irq < 0) |
| 246 | 1081 | return irq; |
| 247 | 1082 | |
| 248 | − ret = rvin_dma_probe(vin, irq); | |
| 1083 | + ret = rvin_dma_register(vin, irq); | |
| 249 | 1084 | if (ret) |
| 250 | 1085 | return ret; |
| 251 | 1086 | |
| 252 | 1087 | platform_set_drvdata(pdev, vin); |
| 253 | − | |
| 254 | − ret = rvin_digital_graph_init(vin); | |
| 1088 | + if (vin->info->use_mc) | |
| 1089 | + ret = rvin_mc_init(vin); | |
| 1090 | + else | |
| 1091 | + ret = rvin_digital_graph_init(vin); | |
| 255 | 1092 | if (ret < 0) |
| 256 | 1093 | goto error; |
| 257 | 1094 | |
| @@ -260,7 +1097,7 @@ static int rcar_vin_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 260 | 1097 | |
| 261 | 1098 | return 0; |
| 262 | 1099 | error: |
| 263 | − rvin_dma_remove(vin); | |
| 1100 | + rvin_dma_unregister(vin); | |
| 264 | 1101 | v4l2_async_notifier_cleanup(&vin->notifier); |
| 265 | 1102 | |
| 266 | 1103 | return ret; |
| @@ -272,10 +1109,22 @@ static int rcar_vin_remove(struct platform_device *pdev) · 5 unmodified lines | ||
| 272 | 1109 | |
| 273 | 1110 | pm_runtime_disable(&pdev->dev); |
| 274 | 1111 | |
| 1112 | + rvin_v4l2_unregister(vin); | |
| 1113 | + | |
| 275 | 1114 | v4l2_async_notifier_unregister(&vin->notifier); |
| 276 | 1115 | v4l2_async_notifier_cleanup(&vin->notifier); |
| 277 | 1116 | |
| 278 | − rvin_dma_remove(vin); | |
| 1117 | + if (vin->info->use_mc) { | |
| 1118 | + mutex_lock(&vin->group->lock); | |
| 1119 | + if (vin->group->notifier == &vin->notifier) | |
| 1120 | + vin->group->notifier = NULL; | |
| 1121 | + mutex_unlock(&vin->group->lock); | |
| 1122 | + rvin_group_put(vin); | |
| 1123 | + } else { | |
| 1124 | + v4l2_ctrl_handler_free(&vin->ctrl_handler); | |
| 1125 | + } | |
| 1126 | + | |
| 1127 | + rvin_dma_unregister(vin); | |
| 279 | 1128 | |
| 280 | 1129 | return 0; |
| 281 | 1130 | } |
| @@ -0,0 +1,1084 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Driver for Renesas R-Car MIPI CSI-2 Receiver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2018 Renesas Electronics Corp. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/delay.h> | |
| 9 | +#include <linux/interrupt.h> | |
| 10 | +#include <linux/io.h> | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/of.h> | |
| 13 | +#include <linux/of_device.h> | |
| 14 | +#include <linux/of_graph.h> | |
| 15 | +#include <linux/platform_device.h> | |
| 16 | +#include <linux/pm_runtime.h> | |
| 17 | +#include <linux/sys_soc.h> | |
| 18 | + | |
| 19 | +#include <media/v4l2-ctrls.h> | |
| 20 | +#include <media/v4l2-device.h> | |
| 21 | +#include <media/v4l2-fwnode.h> | |
| 22 | +#include <media/v4l2-mc.h> | |
| 23 | +#include <media/v4l2-subdev.h> | |
| 24 | + | |
| 25 | +struct rcar_csi2; | |
| 26 | + | |
| 27 | +/* Register offsets and bits */ | |
| 28 | + | |
| 29 | +/* Control Timing Select */ | |
| 30 | +#define TREF_REG 0x00 | |
| 31 | +#define TREF_TREF BIT(0) | |
| 32 | + | |
| 33 | +/* Software Reset */ | |
| 34 | +#define SRST_REG 0x04 | |
| 35 | +#define SRST_SRST BIT(0) | |
| 36 | + | |
| 37 | +/* PHY Operation Control */ | |
| 38 | +#define PHYCNT_REG 0x08 | |
| 39 | +#define PHYCNT_SHUTDOWNZ BIT(17) | |
| 40 | +#define PHYCNT_RSTZ BIT(16) | |
| 41 | +#define PHYCNT_ENABLECLK BIT(4) | |
| 42 | +#define PHYCNT_ENABLE_3 BIT(3) | |
| 43 | +#define PHYCNT_ENABLE_2 BIT(2) | |
| 44 | +#define PHYCNT_ENABLE_1 BIT(1) | |
| 45 | +#define PHYCNT_ENABLE_0 BIT(0) | |
| 46 | + | |
| 47 | +/* Checksum Control */ | |
| 48 | +#define CHKSUM_REG 0x0c | |
| 49 | +#define CHKSUM_ECC_EN BIT(1) | |
| 50 | +#define CHKSUM_CRC_EN BIT(0) | |
| 51 | + | |
| 52 | +/* | |
| 53 | + * Channel Data Type Select | |
| 54 | + * VCDT[0-15]: Channel 1 VCDT[16-31]: Channel 2 | |
| 55 | + * VCDT2[0-15]: Channel 3 VCDT2[16-31]: Channel 4 | |
| 56 | + */ | |
| 57 | +#define VCDT_REG 0x10 | |
| 58 | +#define VCDT2_REG 0x14 | |
| 59 | +#define VCDT_VCDTN_EN BIT(15) | |
| 60 | +#define VCDT_SEL_VC(n) (((n) & 0x3) << 8) | |
| 61 | +#define VCDT_SEL_DTN_ON BIT(6) | |
| 62 | +#define VCDT_SEL_DT(n) (((n) & 0x3f) << 0) | |
| 63 | + | |
| 64 | +/* Frame Data Type Select */ | |
| 65 | +#define FRDT_REG 0x18 | |
| 66 | + | |
| 67 | +/* Field Detection Control */ | |
| 68 | +#define FLD_REG 0x1c | |
| 69 | +#define FLD_FLD_NUM(n) (((n) & 0xff) << 16) | |
| 70 | +#define FLD_FLD_EN4 BIT(3) | |
| 71 | +#define FLD_FLD_EN3 BIT(2) | |
| 72 | +#define FLD_FLD_EN2 BIT(1) | |
| 73 | +#define FLD_FLD_EN BIT(0) | |
| 74 | + | |
| 75 | +/* Automatic Standby Control */ | |
| 76 | +#define ASTBY_REG 0x20 | |
| 77 | + | |
| 78 | +/* Long Data Type Setting 0 */ | |
| 79 | +#define LNGDT0_REG 0x28 | |
| 80 | + | |
| 81 | +/* Long Data Type Setting 1 */ | |
| 82 | +#define LNGDT1_REG 0x2c | |
| 83 | + | |
| 84 | +/* Interrupt Enable */ | |
| 85 | +#define INTEN_REG 0x30 | |
| 86 | + | |
| 87 | +/* Interrupt Source Mask */ | |
| 88 | +#define INTCLOSE_REG 0x34 | |
| 89 | + | |
| 90 | +/* Interrupt Status Monitor */ | |
| 91 | +#define INTSTATE_REG 0x38 | |
| 92 | +#define INTSTATE_INT_ULPS_START BIT(7) | |
| 93 | +#define INTSTATE_INT_ULPS_END BIT(6) | |
| 94 | + | |
| 95 | +/* Interrupt Error Status Monitor */ | |
| 96 | +#define INTERRSTATE_REG 0x3c | |
| 97 | + | |
| 98 | +/* Short Packet Data */ | |
| 99 | +#define SHPDAT_REG 0x40 | |
| 100 | + | |
| 101 | +/* Short Packet Count */ | |
| 102 | +#define SHPCNT_REG 0x44 | |
| 103 | + | |
| 104 | +/* LINK Operation Control */ | |
| 105 | +#define LINKCNT_REG 0x48 | |
| 106 | +#define LINKCNT_MONITOR_EN BIT(31) | |
| 107 | +#define LINKCNT_REG_MONI_PACT_EN BIT(25) | |
| 108 | +#define LINKCNT_ICLK_NONSTOP BIT(24) | |
| 109 | + | |
| 110 | +/* Lane Swap */ | |
| 111 | +#define LSWAP_REG 0x4c | |
| 112 | +#define LSWAP_L3SEL(n) (((n) & 0x3) << 6) | |
| 113 | +#define LSWAP_L2SEL(n) (((n) & 0x3) << 4) | |
| 114 | +#define LSWAP_L1SEL(n) (((n) & 0x3) << 2) | |
| 115 | +#define LSWAP_L0SEL(n) (((n) & 0x3) << 0) | |
| 116 | + | |
| 117 | +/* PHY Test Interface Write Register */ | |
| 118 | +#define PHTW_REG 0x50 | |
| 119 | +#define PHTW_DWEN BIT(24) | |
| 120 | +#define PHTW_TESTDIN_DATA(n) (((n & 0xff)) << 16) | |
| 121 | +#define PHTW_CWEN BIT(8) | |
| 122 | +#define PHTW_TESTDIN_CODE(n) ((n & 0xff)) | |
| 123 | + | |
| 124 | +struct phtw_value { | |
| 125 | + u16 data; | |
| 126 | + u16 code; | |
| 127 | +}; | |
| 128 | + | |
| 129 | +struct rcsi2_mbps_reg { | |
| 130 | + u16 mbps; | |
| 131 | + u16 reg; | |
| 132 | +}; | |
| 133 | + | |
| 134 | +static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { | |
| 135 | + { .mbps = 80, .reg = 0x86 }, | |
| 136 | + { .mbps = 90, .reg = 0x86 }, | |
| 137 | + { .mbps = 100, .reg = 0x87 }, | |
| 138 | + { .mbps = 110, .reg = 0x87 }, | |
| 139 | + { .mbps = 120, .reg = 0x88 }, | |
| 140 | + { .mbps = 130, .reg = 0x88 }, | |
| 141 | + { .mbps = 140, .reg = 0x89 }, | |
| 142 | + { .mbps = 150, .reg = 0x89 }, | |
| 143 | + { .mbps = 160, .reg = 0x8a }, | |
| 144 | + { .mbps = 170, .reg = 0x8a }, | |
| 145 | + { .mbps = 180, .reg = 0x8b }, | |
| 146 | + { .mbps = 190, .reg = 0x8b }, | |
| 147 | + { .mbps = 205, .reg = 0x8c }, | |
| 148 | + { .mbps = 220, .reg = 0x8d }, | |
| 149 | + { .mbps = 235, .reg = 0x8e }, | |
| 150 | + { .mbps = 250, .reg = 0x8e }, | |
| 151 | + { /* sentinel */ }, | |
| 152 | +}; | |
| 153 | + | |
| 154 | +static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { | |
| 155 | + { .mbps = 80, .reg = 0x00 }, | |
| 156 | + { .mbps = 90, .reg = 0x20 }, | |
| 157 | + { .mbps = 100, .reg = 0x40 }, | |
| 158 | + { .mbps = 110, .reg = 0x02 }, | |
| 159 | + { .mbps = 130, .reg = 0x22 }, | |
| 160 | + { .mbps = 140, .reg = 0x42 }, | |
| 161 | + { .mbps = 150, .reg = 0x04 }, | |
| 162 | + { .mbps = 170, .reg = 0x24 }, | |
| 163 | + { .mbps = 180, .reg = 0x44 }, | |
| 164 | + { .mbps = 200, .reg = 0x06 }, | |
| 165 | + { .mbps = 220, .reg = 0x26 }, | |
| 166 | + { .mbps = 240, .reg = 0x46 }, | |
| 167 | + { .mbps = 250, .reg = 0x08 }, | |
| 168 | + { .mbps = 270, .reg = 0x28 }, | |
| 169 | + { .mbps = 300, .reg = 0x0a }, | |
| 170 | + { .mbps = 330, .reg = 0x2a }, | |
| 171 | + { .mbps = 360, .reg = 0x4a }, | |
| 172 | + { .mbps = 400, .reg = 0x0c }, | |
| 173 | + { .mbps = 450, .reg = 0x2c }, | |
| 174 | + { .mbps = 500, .reg = 0x0e }, | |
| 175 | + { .mbps = 550, .reg = 0x2e }, | |
| 176 | + { .mbps = 600, .reg = 0x10 }, | |
| 177 | + { .mbps = 650, .reg = 0x30 }, | |
| 178 | + { .mbps = 700, .reg = 0x12 }, | |
| 179 | + { .mbps = 750, .reg = 0x32 }, | |
| 180 | + { .mbps = 800, .reg = 0x52 }, | |
| 181 | + { .mbps = 850, .reg = 0x72 }, | |
| 182 | + { .mbps = 900, .reg = 0x14 }, | |
| 183 | + { .mbps = 950, .reg = 0x34 }, | |
| 184 | + { .mbps = 1000, .reg = 0x54 }, | |
| 185 | + { .mbps = 1050, .reg = 0x74 }, | |
| 186 | + { .mbps = 1125, .reg = 0x16 }, | |
| 187 | + { /* sentinel */ }, | |
| 188 | +}; | |
| 189 | + | |
| 190 | +/* PHY Test Interface Clear */ | |
| 191 | +#define PHTC_REG 0x58 | |
| 192 | +#define PHTC_TESTCLR BIT(0) | |
| 193 | + | |
| 194 | +/* PHY Frequency Control */ | |
| 195 | +#define PHYPLL_REG 0x68 | |
| 196 | +#define PHYPLL_HSFREQRANGE(n) ((n) << 16) | |
| 197 | + | |
| 198 | +static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { | |
| 199 | + { .mbps = 80, .reg = 0x00 }, | |
| 200 | + { .mbps = 90, .reg = 0x10 }, | |
| 201 | + { .mbps = 100, .reg = 0x20 }, | |
| 202 | + { .mbps = 110, .reg = 0x30 }, | |
| 203 | + { .mbps = 120, .reg = 0x01 }, | |
| 204 | + { .mbps = 130, .reg = 0x11 }, | |
| 205 | + { .mbps = 140, .reg = 0x21 }, | |
| 206 | + { .mbps = 150, .reg = 0x31 }, | |
| 207 | + { .mbps = 160, .reg = 0x02 }, | |
| 208 | + { .mbps = 170, .reg = 0x12 }, | |
| 209 | + { .mbps = 180, .reg = 0x22 }, | |
| 210 | + { .mbps = 190, .reg = 0x32 }, | |
| 211 | + { .mbps = 205, .reg = 0x03 }, | |
| 212 | + { .mbps = 220, .reg = 0x13 }, | |
| 213 | + { .mbps = 235, .reg = 0x23 }, | |
| 214 | + { .mbps = 250, .reg = 0x33 }, | |
| 215 | + { .mbps = 275, .reg = 0x04 }, | |
| 216 | + { .mbps = 300, .reg = 0x14 }, | |
| 217 | + { .mbps = 325, .reg = 0x25 }, | |
| 218 | + { .mbps = 350, .reg = 0x35 }, | |
| 219 | + { .mbps = 400, .reg = 0x05 }, | |
| 220 | + { .mbps = 450, .reg = 0x16 }, | |
| 221 | + { .mbps = 500, .reg = 0x26 }, | |
| 222 | + { .mbps = 550, .reg = 0x37 }, | |
| 223 | + { .mbps = 600, .reg = 0x07 }, | |
| 224 | + { .mbps = 650, .reg = 0x18 }, | |
| 225 | + { .mbps = 700, .reg = 0x28 }, | |
| 226 | + { .mbps = 750, .reg = 0x39 }, | |
| 227 | + { .mbps = 800, .reg = 0x09 }, | |
| 228 | + { .mbps = 850, .reg = 0x19 }, | |
| 229 | + { .mbps = 900, .reg = 0x29 }, | |
| 230 | + { .mbps = 950, .reg = 0x3a }, | |
| 231 | + { .mbps = 1000, .reg = 0x0a }, | |
| 232 | + { .mbps = 1050, .reg = 0x1a }, | |
| 233 | + { .mbps = 1100, .reg = 0x2a }, | |
| 234 | + { .mbps = 1150, .reg = 0x3b }, | |
| 235 | + { .mbps = 1200, .reg = 0x0b }, | |
| 236 | + { .mbps = 1250, .reg = 0x1b }, | |
| 237 | + { .mbps = 1300, .reg = 0x2b }, | |
| 238 | + { .mbps = 1350, .reg = 0x3c }, | |
| 239 | + { .mbps = 1400, .reg = 0x0c }, | |
| 240 | + { .mbps = 1450, .reg = 0x1c }, | |
| 241 | + { .mbps = 1500, .reg = 0x2c }, | |
| 242 | + { /* sentinel */ }, | |
| 243 | +}; | |
| 244 | + | |
| 245 | +static const struct rcsi2_mbps_reg hsfreqrange_m3w_h3es1[] = { | |
| 246 | + { .mbps = 80, .reg = 0x00 }, | |
| 247 | + { .mbps = 90, .reg = 0x10 }, | |
| 248 | + { .mbps = 100, .reg = 0x20 }, | |
| 249 | + { .mbps = 110, .reg = 0x30 }, | |
| 250 | + { .mbps = 120, .reg = 0x01 }, | |
| 251 | + { .mbps = 130, .reg = 0x11 }, | |
| 252 | + { .mbps = 140, .reg = 0x21 }, | |
| 253 | + { .mbps = 150, .reg = 0x31 }, | |
| 254 | + { .mbps = 160, .reg = 0x02 }, | |
| 255 | + { .mbps = 170, .reg = 0x12 }, | |
| 256 | + { .mbps = 180, .reg = 0x22 }, | |
| 257 | + { .mbps = 190, .reg = 0x32 }, | |
| 258 | + { .mbps = 205, .reg = 0x03 }, | |
| 259 | + { .mbps = 220, .reg = 0x13 }, | |
| 260 | + { .mbps = 235, .reg = 0x23 }, | |
| 261 | + { .mbps = 250, .reg = 0x33 }, | |
| 262 | + { .mbps = 275, .reg = 0x04 }, | |
| 263 | + { .mbps = 300, .reg = 0x14 }, | |
| 264 | + { .mbps = 325, .reg = 0x05 }, | |
| 265 | + { .mbps = 350, .reg = 0x15 }, | |
| 266 | + { .mbps = 400, .reg = 0x25 }, | |
| 267 | + { .mbps = 450, .reg = 0x06 }, | |
| 268 | + { .mbps = 500, .reg = 0x16 }, | |
| 269 | + { .mbps = 550, .reg = 0x07 }, | |
| 270 | + { .mbps = 600, .reg = 0x17 }, | |
| 271 | + { .mbps = 650, .reg = 0x08 }, | |
| 272 | + { .mbps = 700, .reg = 0x18 }, | |
| 273 | + { .mbps = 750, .reg = 0x09 }, | |
| 274 | + { .mbps = 800, .reg = 0x19 }, | |
| 275 | + { .mbps = 850, .reg = 0x29 }, | |
| 276 | + { .mbps = 900, .reg = 0x39 }, | |
| 277 | + { .mbps = 950, .reg = 0x0a }, | |
| 278 | + { .mbps = 1000, .reg = 0x1a }, | |
| 279 | + { .mbps = 1050, .reg = 0x2a }, | |
| 280 | + { .mbps = 1100, .reg = 0x3a }, | |
| 281 | + { .mbps = 1150, .reg = 0x0b }, | |
| 282 | + { .mbps = 1200, .reg = 0x1b }, | |
| 283 | + { .mbps = 1250, .reg = 0x2b }, | |
| 284 | + { .mbps = 1300, .reg = 0x3b }, | |
| 285 | + { .mbps = 1350, .reg = 0x0c }, | |
| 286 | + { .mbps = 1400, .reg = 0x1c }, | |
| 287 | + { .mbps = 1450, .reg = 0x2c }, | |
| 288 | + { .mbps = 1500, .reg = 0x3c }, | |
| 289 | + { /* sentinel */ }, | |
| 290 | +}; | |
| 291 | + | |
| 292 | +/* PHY ESC Error Monitor */ | |
| 293 | +#define PHEERM_REG 0x74 | |
| 294 | + | |
| 295 | +/* PHY Clock Lane Monitor */ | |
| 296 | +#define PHCLM_REG 0x78 | |
| 297 | +#define PHCLM_STOPSTATECKL BIT(0) | |
| 298 | + | |
| 299 | +/* PHY Data Lane Monitor */ | |
| 300 | +#define PHDLM_REG 0x7c | |
| 301 | + | |
| 302 | +/* CSI0CLK Frequency Configuration Preset Register */ | |
| 303 | +#define CSI0CLKFCPR_REG 0x260 | |
| 304 | +#define CSI0CLKFREQRANGE(n) ((n & 0x3f) << 16) | |
| 305 | + | |
| 306 | +struct rcar_csi2_format { | |
| 307 | + u32 code; | |
| 308 | + unsigned int datatype; | |
| 309 | + unsigned int bpp; | |
| 310 | +}; | |
| 311 | + | |
| 312 | +static const struct rcar_csi2_format rcar_csi2_formats[] = { | |
| 313 | + { .code = MEDIA_BUS_FMT_RGB888_1X24, .datatype = 0x24, .bpp = 24 }, | |
| 314 | + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, | |
| 315 | + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, | |
| 316 | + { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, | |
| 317 | + { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, | |
| 318 | +}; | |
| 319 | + | |
| 320 | +static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) | |
| 321 | +{ | |
| 322 | + unsigned int i; | |
| 323 | + | |
| 324 | + for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++) | |
| 325 | + if (rcar_csi2_formats[i].code == code) | |
| 326 | + return &rcar_csi2_formats[i]; | |
| 327 | + | |
| 328 | + return NULL; | |
| 329 | +} | |
| 330 | + | |
| 331 | +enum rcar_csi2_pads { | |
| 332 | + RCAR_CSI2_SINK, | |
| 333 | + RCAR_CSI2_SOURCE_VC0, | |
| 334 | + RCAR_CSI2_SOURCE_VC1, | |
| 335 | + RCAR_CSI2_SOURCE_VC2, | |
| 336 | + RCAR_CSI2_SOURCE_VC3, | |
| 337 | + NR_OF_RCAR_CSI2_PAD, | |
| 338 | +}; | |
| 339 | + | |
| 340 | +struct rcar_csi2_info { | |
| 341 | + int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); | |
| 342 | + const struct rcsi2_mbps_reg *hsfreqrange; | |
| 343 | + unsigned int csi0clkfreqrange; | |
| 344 | + bool clear_ulps; | |
| 345 | +}; | |
| 346 | + | |
| 347 | +struct rcar_csi2 { | |
| 348 | + struct device *dev; | |
| 349 | + void __iomem *base; | |
| 350 | + const struct rcar_csi2_info *info; | |
| 351 | + | |
| 352 | + struct v4l2_subdev subdev; | |
| 353 | + struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; | |
| 354 | + | |
| 355 | + struct v4l2_async_notifier notifier; | |
| 356 | + struct v4l2_async_subdev asd; | |
| 357 | + struct v4l2_subdev *remote; | |
| 358 | + | |
| 359 | + struct v4l2_mbus_framefmt mf; | |
| 360 | + | |
| 361 | + struct mutex lock; | |
| 362 | + int stream_count; | |
| 363 | + | |
| 364 | + unsigned short lanes; | |
| 365 | + unsigned char lane_swap[4]; | |
| 366 | +}; | |
| 367 | + | |
| 368 | +static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd) | |
| 369 | +{ | |
| 370 | + return container_of(sd, struct rcar_csi2, subdev); | |
| 371 | +} | |
| 372 | + | |
| 373 | +static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) | |
| 374 | +{ | |
| 375 | + return container_of(n, struct rcar_csi2, notifier); | |
| 376 | +} | |
| 377 | + | |
| 378 | +static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) | |
| 379 | +{ | |
| 380 | + return ioread32(priv->base + reg); | |
| 381 | +} | |
| 382 | + | |
| 383 | +static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) | |
| 384 | +{ | |
| 385 | + iowrite32(data, priv->base + reg); | |
| 386 | +} | |
| 387 | + | |
| 388 | +static void rcsi2_reset(struct rcar_csi2 *priv) | |
| 389 | +{ | |
| 390 | + rcsi2_write(priv, SRST_REG, SRST_SRST); | |
| 391 | + usleep_range(100, 150); | |
| 392 | + rcsi2_write(priv, SRST_REG, 0); | |
| 393 | +} | |
| 394 | + | |
| 395 | +static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) | |
| 396 | +{ | |
| 397 | + unsigned int timeout; | |
| 398 | + | |
| 399 | + /* Wait for the clock and data lanes to enter LP-11 state. */ | |
| 400 | + for (timeout = 0; timeout <= 20; timeout++) { | |
| 401 | + const u32 lane_mask = (1 << priv->lanes) - 1; | |
| 402 | + | |
| 403 | + if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && | |
| 404 | + (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) | |
| 405 | + return 0; | |
| 406 | + | |
| 407 | + usleep_range(1000, 2000); | |
| 408 | + } | |
| 409 | + | |
| 410 | + dev_err(priv->dev, "Timeout waiting for LP-11 state\n"); | |
| 411 | + | |
| 412 | + return -ETIMEDOUT; | |
| 413 | +} | |
| 414 | + | |
| 415 | +static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) | |
| 416 | +{ | |
| 417 | + const struct rcsi2_mbps_reg *hsfreq; | |
| 418 | + | |
| 419 | + for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) | |
| 420 | + if (hsfreq->mbps >= mbps) | |
| 421 | + break; | |
| 422 | + | |
| 423 | + if (!hsfreq->mbps) { | |
| 424 | + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); | |
| 425 | + return -ERANGE; | |
| 426 | + } | |
| 427 | + | |
| 428 | + rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); | |
| 429 | + | |
| 430 | + return 0; | |
| 431 | +} | |
| 432 | + | |
| 433 | +static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) | |
| 434 | +{ | |
| 435 | + struct v4l2_subdev *source; | |
| 436 | + struct v4l2_ctrl *ctrl; | |
| 437 | + u64 mbps; | |
| 438 | + | |
| 439 | + if (!priv->remote) | |
| 440 | + return -ENODEV; | |
| 441 | + | |
| 442 | + source = priv->remote; | |
| 443 | + | |
| 444 | + /* Read the pixel rate control from remote. */ | |
| 445 | + ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); | |
| 446 | + if (!ctrl) { | |
| 447 | + dev_err(priv->dev, "no pixel rate control in subdev %s\n", | |
| 448 | + source->name); | |
| 449 | + return -EINVAL; | |
| 450 | + } | |
| 451 | + | |
| 452 | + /* | |
| 453 | + * Calculate the phypll in mbps. | |
| 454 | + * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes) | |
| 455 | + * bps = link_freq * 2 | |
| 456 | + */ | |
| 457 | + mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; | |
| 458 | + do_div(mbps, priv->lanes * 1000000); | |
| 459 | + | |
| 460 | + return mbps; | |
| 461 | +} | |
| 462 | + | |
| 463 | +static int rcsi2_start(struct rcar_csi2 *priv) | |
| 464 | +{ | |
| 465 | + const struct rcar_csi2_format *format; | |
| 466 | + u32 phycnt, vcdt = 0, vcdt2 = 0; | |
| 467 | + unsigned int i; | |
| 468 | + int mbps, ret; | |
| 469 | + | |
| 470 | + dev_dbg(priv->dev, "Input size (%ux%u%c)\n", | |
| 471 | + priv->mf.width, priv->mf.height, | |
| 472 | + priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); | |
| 473 | + | |
| 474 | + /* Code is validated in set_fmt. */ | |
| 475 | + format = rcsi2_code_to_fmt(priv->mf.code); | |
| 476 | + | |
| 477 | + /* | |
| 478 | + * Enable all Virtual Channels. | |
| 479 | + * | |
| 480 | + * NOTE: It's not possible to get individual datatype for each | |
| 481 | + * source virtual channel. Once this is possible in V4L2 | |
| 482 | + * it should be used here. | |
| 483 | + */ | |
| 484 | + for (i = 0; i < 4; i++) { | |
| 485 | + u32 vcdt_part; | |
| 486 | + | |
| 487 | + vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON | | |
| 488 | + VCDT_SEL_DT(format->datatype); | |
| 489 | + | |
| 490 | + /* Store in correct reg and offset. */ | |
| 491 | + if (i < 2) | |
| 492 | + vcdt |= vcdt_part << ((i % 2) * 16); | |
| 493 | + else | |
| 494 | + vcdt2 |= vcdt_part << ((i % 2) * 16); | |
| 495 | + } | |
| 496 | + | |
| 497 | + phycnt = PHYCNT_ENABLECLK; | |
| 498 | + phycnt |= (1 << priv->lanes) - 1; | |
| 499 | + | |
| 500 | + mbps = rcsi2_calc_mbps(priv, format->bpp); | |
| 501 | + if (mbps < 0) | |
| 502 | + return mbps; | |
| 503 | + | |
| 504 | + /* Init */ | |
| 505 | + rcsi2_write(priv, TREF_REG, TREF_TREF); | |
| 506 | + rcsi2_reset(priv); | |
| 507 | + rcsi2_write(priv, PHTC_REG, 0); | |
| 508 | + | |
| 509 | + /* Configure */ | |
| 510 | + rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | | |
| 511 | + FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); | |
| 512 | + rcsi2_write(priv, VCDT_REG, vcdt); | |
| 513 | + rcsi2_write(priv, VCDT2_REG, vcdt2); | |
| 514 | + /* Lanes are zero indexed. */ | |
| 515 | + rcsi2_write(priv, LSWAP_REG, | |
| 516 | + LSWAP_L0SEL(priv->lane_swap[0] - 1) | | |
| 517 | + LSWAP_L1SEL(priv->lane_swap[1] - 1) | | |
| 518 | + LSWAP_L2SEL(priv->lane_swap[2] - 1) | | |
| 519 | + LSWAP_L3SEL(priv->lane_swap[3] - 1)); | |
| 520 | + | |
| 521 | + /* Start */ | |
| 522 | + if (priv->info->init_phtw) { | |
| 523 | + ret = priv->info->init_phtw(priv, mbps); | |
| 524 | + if (ret) | |
| 525 | + return ret; | |
| 526 | + } | |
| 527 | + | |
| 528 | + if (priv->info->hsfreqrange) { | |
| 529 | + ret = rcsi2_set_phypll(priv, mbps); | |
| 530 | + if (ret) | |
| 531 | + return ret; | |
| 532 | + } | |
| 533 | + | |
| 534 | + if (priv->info->csi0clkfreqrange) | |
| 535 | + rcsi2_write(priv, CSI0CLKFCPR_REG, | |
| 536 | + CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); | |
| 537 | + | |
| 538 | + rcsi2_write(priv, PHYCNT_REG, phycnt); | |
| 539 | + rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | | |
| 540 | + LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); | |
| 541 | + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); | |
| 542 | + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); | |
| 543 | + | |
| 544 | + ret = rcsi2_wait_phy_start(priv); | |
| 545 | + if (ret) | |
| 546 | + return ret; | |
| 547 | + | |
| 548 | + /* Clear Ultra Low Power interrupt. */ | |
| 549 | + if (priv->info->clear_ulps) | |
| 550 | + rcsi2_write(priv, INTSTATE_REG, | |
| 551 | + INTSTATE_INT_ULPS_START | | |
| 552 | + INTSTATE_INT_ULPS_END); | |
| 553 | + return 0; | |
| 554 | +} | |
| 555 | + | |
| 556 | +static void rcsi2_stop(struct rcar_csi2 *priv) | |
| 557 | +{ | |
| 558 | + rcsi2_write(priv, PHYCNT_REG, 0); | |
| 559 | + | |
| 560 | + rcsi2_reset(priv); | |
| 561 | + | |
| 562 | + rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); | |
| 563 | +} | |
| 564 | + | |
| 565 | +static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) | |
| 566 | +{ | |
| 567 | + struct rcar_csi2 *priv = sd_to_csi2(sd); | |
| 568 | + struct v4l2_subdev *nextsd; | |
| 569 | + int ret = 0; | |
| 570 | + | |
| 571 | + mutex_lock(&priv->lock); | |
| 572 | + | |
| 573 | + if (!priv->remote) { | |
| 574 | + ret = -ENODEV; | |
| 575 | + goto out; | |
| 576 | + } | |
| 577 | + | |
| 578 | + nextsd = priv->remote; | |
| 579 | + | |
| 580 | + if (enable && priv->stream_count == 0) { | |
| 581 | + pm_runtime_get_sync(priv->dev); | |
| 582 | + | |
| 583 | + ret = rcsi2_start(priv); | |
| 584 | + if (ret) { | |
| 585 | + pm_runtime_put(priv->dev); | |
| 586 | + goto out; | |
| 587 | + } | |
| 588 | + | |
| 589 | + ret = v4l2_subdev_call(nextsd, video, s_stream, 1); | |
| 590 | + if (ret) { | |
| 591 | + rcsi2_stop(priv); | |
| 592 | + pm_runtime_put(priv->dev); | |
| 593 | + goto out; | |
| 594 | + } | |
| 595 | + } else if (!enable && priv->stream_count == 1) { | |
| 596 | + rcsi2_stop(priv); | |
| 597 | + v4l2_subdev_call(nextsd, video, s_stream, 0); | |
| 598 | + pm_runtime_put(priv->dev); | |
| 599 | + } | |
| 600 | + | |
| 601 | + priv->stream_count += enable ? 1 : -1; | |
| 602 | +out: | |
| 603 | + mutex_unlock(&priv->lock); | |
| 604 | + | |
| 605 | + return ret; | |
| 606 | +} | |
| 607 | + | |
| 608 | +static int rcsi2_set_pad_format(struct v4l2_subdev *sd, | |
| 609 | + struct v4l2_subdev_pad_config *cfg, | |
| 610 | + struct v4l2_subdev_format *format) | |
| 611 | +{ | |
| 612 | + struct rcar_csi2 *priv = sd_to_csi2(sd); | |
| 613 | + struct v4l2_mbus_framefmt *framefmt; | |
| 614 | + | |
| 615 | + if (!rcsi2_code_to_fmt(format->format.code)) | |
| 616 | + format->format.code = rcar_csi2_formats[0].code; | |
| 617 | + | |
| 618 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 619 | + priv->mf = format->format; | |
| 620 | + } else { | |
| 621 | + framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); | |
| 622 | + *framefmt = format->format; | |
| 623 | + } | |
| 624 | + | |
| 625 | + return 0; | |
| 626 | +} | |
| 627 | + | |
| 628 | +static int rcsi2_get_pad_format(struct v4l2_subdev *sd, | |
| 629 | + struct v4l2_subdev_pad_config *cfg, | |
| 630 | + struct v4l2_subdev_format *format) | |
| 631 | +{ | |
| 632 | + struct rcar_csi2 *priv = sd_to_csi2(sd); | |
| 633 | + | |
| 634 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 635 | + format->format = priv->mf; | |
| 636 | + else | |
| 637 | + format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); | |
| 638 | + | |
| 639 | + return 0; | |
| 640 | +} | |
| 641 | + | |
| 642 | +static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { | |
| 643 | + .s_stream = rcsi2_s_stream, | |
| 644 | +}; | |
| 645 | + | |
| 646 | +static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { | |
| 647 | + .set_fmt = rcsi2_set_pad_format, | |
| 648 | + .get_fmt = rcsi2_get_pad_format, | |
| 649 | +}; | |
| 650 | + | |
| 651 | +static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { | |
| 652 | + .video = &rcar_csi2_video_ops, | |
| 653 | + .pad = &rcar_csi2_pad_ops, | |
| 654 | +}; | |
| 655 | + | |
| 656 | +/* ----------------------------------------------------------------------------- | |
| 657 | + * Async handling and registration of subdevices and links. | |
| 658 | + */ | |
| 659 | + | |
| 660 | +static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, | |
| 661 | + struct v4l2_subdev *subdev, | |
| 662 | + struct v4l2_async_subdev *asd) | |
| 663 | +{ | |
| 664 | + struct rcar_csi2 *priv = notifier_to_csi2(notifier); | |
| 665 | + int pad; | |
| 666 | + | |
| 667 | + pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, | |
| 668 | + MEDIA_PAD_FL_SOURCE); | |
| 669 | + if (pad < 0) { | |
| 670 | + dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name); | |
| 671 | + return pad; | |
| 672 | + } | |
| 673 | + | |
| 674 | + priv->remote = subdev; | |
| 675 | + | |
| 676 | + dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); | |
| 677 | + | |
| 678 | + return media_create_pad_link(&subdev->entity, pad, | |
| 679 | + &priv->subdev.entity, 0, | |
| 680 | + MEDIA_LNK_FL_ENABLED | | |
| 681 | + MEDIA_LNK_FL_IMMUTABLE); | |
| 682 | +} | |
| 683 | + | |
| 684 | +static void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier, | |
| 685 | + struct v4l2_subdev *subdev, | |
| 686 | + struct v4l2_async_subdev *asd) | |
| 687 | +{ | |
| 688 | + struct rcar_csi2 *priv = notifier_to_csi2(notifier); | |
| 689 | + | |
| 690 | + priv->remote = NULL; | |
| 691 | + | |
| 692 | + dev_dbg(priv->dev, "Unbind %s\n", subdev->name); | |
| 693 | +} | |
| 694 | + | |
| 695 | +static const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = { | |
| 696 | + .bound = rcsi2_notify_bound, | |
| 697 | + .unbind = rcsi2_notify_unbind, | |
| 698 | +}; | |
| 699 | + | |
| 700 | +static int rcsi2_parse_v4l2(struct rcar_csi2 *priv, | |
| 701 | + struct v4l2_fwnode_endpoint *vep) | |
| 702 | +{ | |
| 703 | + unsigned int i; | |
| 704 | + | |
| 705 | + /* Only port 0 endpoint 0 is valid. */ | |
| 706 | + if (vep->base.port || vep->base.id) | |
| 707 | + return -ENOTCONN; | |
| 708 | + | |
| 709 | + if (vep->bus_type != V4L2_MBUS_CSI2) { | |
| 710 | + dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type); | |
| 711 | + return -EINVAL; | |
| 712 | + } | |
| 713 | + | |
| 714 | + priv->lanes = vep->bus.mipi_csi2.num_data_lanes; | |
| 715 | + if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) { | |
| 716 | + dev_err(priv->dev, "Unsupported number of data-lanes: %u\n", | |
| 717 | + priv->lanes); | |
| 718 | + return -EINVAL; | |
| 719 | + } | |
| 720 | + | |
| 721 | + for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) { | |
| 722 | + priv->lane_swap[i] = i < priv->lanes ? | |
| 723 | + vep->bus.mipi_csi2.data_lanes[i] : i; | |
| 724 | + | |
| 725 | + /* Check for valid lane number. */ | |
| 726 | + if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) { | |
| 727 | + dev_err(priv->dev, "data-lanes must be in 1-4 range\n"); | |
| 728 | + return -EINVAL; | |
| 729 | + } | |
| 730 | + } | |
| 731 | + | |
| 732 | + return 0; | |
| 733 | +} | |
| 734 | + | |
| 735 | +static int rcsi2_parse_dt(struct rcar_csi2 *priv) | |
| 736 | +{ | |
| 737 | + struct device_node *ep; | |
| 738 | + struct v4l2_fwnode_endpoint v4l2_ep; | |
| 739 | + int ret; | |
| 740 | + | |
| 741 | + ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0); | |
| 742 | + if (!ep) { | |
| 743 | + dev_err(priv->dev, "Not connected to subdevice\n"); | |
| 744 | + return -EINVAL; | |
| 745 | + } | |
| 746 | + | |
| 747 | + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); | |
| 748 | + if (ret) { | |
| 749 | + dev_err(priv->dev, "Could not parse v4l2 endpoint\n"); | |
| 750 | + of_node_put(ep); | |
| 751 | + return -EINVAL; | |
| 752 | + } | |
| 753 | + | |
| 754 | + ret = rcsi2_parse_v4l2(priv, &v4l2_ep); | |
| 755 | + if (ret) { | |
| 756 | + of_node_put(ep); | |
| 757 | + return ret; | |
| 758 | + } | |
| 759 | + | |
| 760 | + priv->asd.match.fwnode = | |
| 761 | + fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); | |
| 762 | + priv->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; | |
| 763 | + | |
| 764 | + of_node_put(ep); | |
| 765 | + | |
| 766 | + priv->notifier.subdevs = devm_kzalloc(priv->dev, | |
| 767 | + sizeof(*priv->notifier.subdevs), | |
| 768 | + GFP_KERNEL); | |
| 769 | + if (!priv->notifier.subdevs) | |
| 770 | + return -ENOMEM; | |
| 771 | + | |
| 772 | + priv->notifier.num_subdevs = 1; | |
| 773 | + priv->notifier.subdevs[0] = &priv->asd; | |
| 774 | + priv->notifier.ops = &rcar_csi2_notify_ops; | |
| 775 | + | |
| 776 | + dev_dbg(priv->dev, "Found '%pOF'\n", | |
| 777 | + to_of_node(priv->asd.match.fwnode)); | |
| 778 | + | |
| 779 | + return v4l2_async_subdev_notifier_register(&priv->subdev, | |
| 780 | + &priv->notifier); | |
| 781 | +} | |
| 782 | + | |
| 783 | +/* ----------------------------------------------------------------------------- | |
| 784 | + * PHTW initialization sequences. | |
| 785 | + * | |
| 786 | + * NOTE: Magic values are from the datasheet and lack documentation. | |
| 787 | + */ | |
| 788 | + | |
| 789 | +static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) | |
| 790 | +{ | |
| 791 | + unsigned int timeout; | |
| 792 | + | |
| 793 | + rcsi2_write(priv, PHTW_REG, | |
| 794 | + PHTW_DWEN | PHTW_TESTDIN_DATA(data) | | |
| 795 | + PHTW_CWEN | PHTW_TESTDIN_CODE(code)); | |
| 796 | + | |
| 797 | + /* Wait for DWEN and CWEN to be cleared by hardware. */ | |
| 798 | + for (timeout = 0; timeout <= 20; timeout++) { | |
| 799 | + if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) | |
| 800 | + return 0; | |
| 801 | + | |
| 802 | + usleep_range(1000, 2000); | |
| 803 | + } | |
| 804 | + | |
| 805 | + dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); | |
| 806 | + | |
| 807 | + return -ETIMEDOUT; | |
| 808 | +} | |
| 809 | + | |
| 810 | +static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, | |
| 811 | + const struct phtw_value *values) | |
| 812 | +{ | |
| 813 | + const struct phtw_value *value; | |
| 814 | + int ret; | |
| 815 | + | |
| 816 | + for (value = values; value->data || value->code; value++) { | |
| 817 | + ret = rcsi2_phtw_write(priv, value->data, value->code); | |
| 818 | + if (ret) | |
| 819 | + return ret; | |
| 820 | + } | |
| 821 | + | |
| 822 | + return 0; | |
| 823 | +} | |
| 824 | + | |
| 825 | +static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, | |
| 826 | + const struct rcsi2_mbps_reg *values, u16 code) | |
| 827 | +{ | |
| 828 | + const struct rcsi2_mbps_reg *value; | |
| 829 | + | |
| 830 | + for (value = values; value->mbps; value++) | |
| 831 | + if (value->mbps >= mbps) | |
| 832 | + break; | |
| 833 | + | |
| 834 | + if (!value->mbps) { | |
| 835 | + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); | |
| 836 | + return -ERANGE; | |
| 837 | + } | |
| 838 | + | |
| 839 | + return rcsi2_phtw_write(priv, value->reg, code); | |
| 840 | +} | |
| 841 | + | |
| 842 | +static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) | |
| 843 | +{ | |
| 844 | + static const struct phtw_value step1[] = { | |
| 845 | + { .data = 0xcc, .code = 0xe2 }, | |
| 846 | + { .data = 0x01, .code = 0xe3 }, | |
| 847 | + { .data = 0x11, .code = 0xe4 }, | |
| 848 | + { .data = 0x01, .code = 0xe5 }, | |
| 849 | + { .data = 0x10, .code = 0x04 }, | |
| 850 | + { /* sentinel */ }, | |
| 851 | + }; | |
| 852 | + | |
| 853 | + static const struct phtw_value step2[] = { | |
| 854 | + { .data = 0x38, .code = 0x08 }, | |
| 855 | + { .data = 0x01, .code = 0x00 }, | |
| 856 | + { .data = 0x4b, .code = 0xac }, | |
| 857 | + { .data = 0x03, .code = 0x00 }, | |
| 858 | + { .data = 0x80, .code = 0x07 }, | |
| 859 | + { /* sentinel */ }, | |
| 860 | + }; | |
| 861 | + | |
| 862 | + int ret; | |
| 863 | + | |
| 864 | + ret = rcsi2_phtw_write_array(priv, step1); | |
| 865 | + if (ret) | |
| 866 | + return ret; | |
| 867 | + | |
| 868 | + if (mbps <= 250) { | |
| 869 | + ret = rcsi2_phtw_write(priv, 0x39, 0x05); | |
| 870 | + if (ret) | |
| 871 | + return ret; | |
| 872 | + | |
| 873 | + ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_h3_v3h_m3n, | |
| 874 | + 0xf1); | |
| 875 | + if (ret) | |
| 876 | + return ret; | |
| 877 | + } | |
| 878 | + | |
| 879 | + return rcsi2_phtw_write_array(priv, step2); | |
| 880 | +} | |
| 881 | + | |
| 882 | +static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) | |
| 883 | +{ | |
| 884 | + static const struct phtw_value step1[] = { | |
| 885 | + { .data = 0xed, .code = 0x34 }, | |
| 886 | + { .data = 0xed, .code = 0x44 }, | |
| 887 | + { .data = 0xed, .code = 0x54 }, | |
| 888 | + { .data = 0xed, .code = 0x84 }, | |
| 889 | + { .data = 0xed, .code = 0x94 }, | |
| 890 | + { /* sentinel */ }, | |
| 891 | + }; | |
| 892 | + | |
| 893 | + int ret; | |
| 894 | + | |
| 895 | + ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); | |
| 896 | + if (ret) | |
| 897 | + return ret; | |
| 898 | + | |
| 899 | + return rcsi2_phtw_write_array(priv, step1); | |
| 900 | +} | |
| 901 | + | |
| 902 | +/* ----------------------------------------------------------------------------- | |
| 903 | + * Platform Device Driver. | |
| 904 | + */ | |
| 905 | + | |
| 906 | +static const struct media_entity_operations rcar_csi2_entity_ops = { | |
| 907 | + .link_validate = v4l2_subdev_link_validate, | |
| 908 | +}; | |
| 909 | + | |
| 910 | +static int rcsi2_probe_resources(struct rcar_csi2 *priv, | |
| 911 | + struct platform_device *pdev) | |
| 912 | +{ | |
| 913 | + struct resource *res; | |
| 914 | + int irq; | |
| 915 | + | |
| 916 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 917 | + priv->base = devm_ioremap_resource(&pdev->dev, res); | |
| 918 | + if (IS_ERR(priv->base)) | |
| 919 | + return PTR_ERR(priv->base); | |
| 920 | + | |
| 921 | + irq = platform_get_irq(pdev, 0); | |
| 922 | + if (irq < 0) | |
| 923 | + return irq; | |
| 924 | + | |
| 925 | + return 0; | |
| 926 | +} | |
| 927 | + | |
| 928 | +static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { | |
| 929 | + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, | |
| 930 | + .hsfreqrange = hsfreqrange_h3_v3h_m3n, | |
| 931 | + .csi0clkfreqrange = 0x20, | |
| 932 | + .clear_ulps = true, | |
| 933 | +}; | |
| 934 | + | |
| 935 | +static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = { | |
| 936 | + .hsfreqrange = hsfreqrange_m3w_h3es1, | |
| 937 | +}; | |
| 938 | + | |
| 939 | +static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { | |
| 940 | + .hsfreqrange = hsfreqrange_m3w_h3es1, | |
| 941 | +}; | |
| 942 | + | |
| 943 | +static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { | |
| 944 | + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, | |
| 945 | + .hsfreqrange = hsfreqrange_h3_v3h_m3n, | |
| 946 | + .csi0clkfreqrange = 0x20, | |
| 947 | + .clear_ulps = true, | |
| 948 | +}; | |
| 949 | + | |
| 950 | +static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { | |
| 951 | + .init_phtw = rcsi2_init_phtw_v3m_e3, | |
| 952 | +}; | |
| 953 | + | |
| 954 | +static const struct of_device_id rcar_csi2_of_table[] = { | |
| 955 | + { | |
| 956 | + .compatible = "renesas,r8a7795-csi2", | |
| 957 | + .data = &rcar_csi2_info_r8a7795, | |
| 958 | + }, | |
| 959 | + { | |
| 960 | + .compatible = "renesas,r8a7796-csi2", | |
| 961 | + .data = &rcar_csi2_info_r8a7796, | |
| 962 | + }, | |
| 963 | + { | |
| 964 | + .compatible = "renesas,r8a77965-csi2", | |
| 965 | + .data = &rcar_csi2_info_r8a77965, | |
| 966 | + }, | |
| 967 | + { | |
| 968 | + .compatible = "renesas,r8a77970-csi2", | |
| 969 | + .data = &rcar_csi2_info_r8a77970, | |
| 970 | + }, | |
| 971 | + { /* sentinel */ }, | |
| 972 | +}; | |
| 973 | +MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); | |
| 974 | + | |
| 975 | +static const struct soc_device_attribute r8a7795es1[] = { | |
| 976 | + { | |
| 977 | + .soc_id = "r8a7795", .revision = "ES1.*", | |
| 978 | + .data = &rcar_csi2_info_r8a7795es1, | |
| 979 | + }, | |
| 980 | + { /* sentinel */ }, | |
| 981 | +}; | |
| 982 | + | |
| 983 | +static int rcsi2_probe(struct platform_device *pdev) | |
| 984 | +{ | |
| 985 | + const struct soc_device_attribute *attr; | |
| 986 | + struct rcar_csi2 *priv; | |
| 987 | + unsigned int i; | |
| 988 | + int ret; | |
| 989 | + | |
| 990 | + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | |
| 991 | + if (!priv) | |
| 992 | + return -ENOMEM; | |
| 993 | + | |
| 994 | + priv->info = of_device_get_match_data(&pdev->dev); | |
| 995 | + | |
| 996 | + /* | |
| 997 | + * r8a7795 ES1.x behaves differently than the ES2.0+ but doesn't | |
| 998 | + * have it's own compatible string. | |
| 999 | + */ | |
| 1000 | + attr = soc_device_match(r8a7795es1); | |
| 1001 | + if (attr) | |
| 1002 | + priv->info = attr->data; | |
| 1003 | + | |
| 1004 | + priv->dev = &pdev->dev; | |
| 1005 | + | |
| 1006 | + mutex_init(&priv->lock); | |
| 1007 | + priv->stream_count = 0; | |
| 1008 | + | |
| 1009 | + ret = rcsi2_probe_resources(priv, pdev); | |
| 1010 | + if (ret) { | |
| 1011 | + dev_err(priv->dev, "Failed to get resources\n"); | |
| 1012 | + return ret; | |
| 1013 | + } | |
| 1014 | + | |
| 1015 | + platform_set_drvdata(pdev, priv); | |
| 1016 | + | |
| 1017 | + ret = rcsi2_parse_dt(priv); | |
| 1018 | + if (ret) | |
| 1019 | + return ret; | |
| 1020 | + | |
| 1021 | + priv->subdev.owner = THIS_MODULE; | |
| 1022 | + priv->subdev.dev = &pdev->dev; | |
| 1023 | + v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); | |
| 1024 | + v4l2_set_subdevdata(&priv->subdev, &pdev->dev); | |
| 1025 | + snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", | |
| 1026 | + KBUILD_MODNAME, dev_name(&pdev->dev)); | |
| 1027 | + priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1028 | + | |
| 1029 | + priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; | |
| 1030 | + priv->subdev.entity.ops = &rcar_csi2_entity_ops; | |
| 1031 | + | |
| 1032 | + priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; | |
| 1033 | + for (i = RCAR_CSI2_SOURCE_VC0; i < NR_OF_RCAR_CSI2_PAD; i++) | |
| 1034 | + priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; | |
| 1035 | + | |
| 1036 | + ret = media_entity_pads_init(&priv->subdev.entity, NR_OF_RCAR_CSI2_PAD, | |
| 1037 | + priv->pads); | |
| 1038 | + if (ret) | |
| 1039 | + goto error; | |
| 1040 | + | |
| 1041 | + pm_runtime_enable(&pdev->dev); | |
| 1042 | + | |
| 1043 | + ret = v4l2_async_register_subdev(&priv->subdev); | |
| 1044 | + if (ret < 0) | |
| 1045 | + goto error; | |
| 1046 | + | |
| 1047 | + dev_info(priv->dev, "%d lanes found\n", priv->lanes); | |
| 1048 | + | |
| 1049 | + return 0; | |
| 1050 | + | |
| 1051 | +error: | |
| 1052 | + v4l2_async_notifier_unregister(&priv->notifier); | |
| 1053 | + v4l2_async_notifier_cleanup(&priv->notifier); | |
| 1054 | + | |
| 1055 | + return ret; | |
| 1056 | +} | |
| 1057 | + | |
| 1058 | +static int rcsi2_remove(struct platform_device *pdev) | |
| 1059 | +{ | |
| 1060 | + struct rcar_csi2 *priv = platform_get_drvdata(pdev); | |
| 1061 | + | |
| 1062 | + v4l2_async_notifier_unregister(&priv->notifier); | |
| 1063 | + v4l2_async_notifier_cleanup(&priv->notifier); | |
| 1064 | + v4l2_async_unregister_subdev(&priv->subdev); | |
| 1065 | + | |
| 1066 | + pm_runtime_disable(&pdev->dev); | |
| 1067 | + | |
| 1068 | + return 0; | |
| 1069 | +} | |
| 1070 | + | |
| 1071 | +static struct platform_driver rcar_csi2_pdrv = { | |
| 1072 | + .remove = rcsi2_remove, | |
| 1073 | + .probe = rcsi2_probe, | |
| 1074 | + .driver = { | |
| 1075 | + .name = "rcar-csi2", | |
| 1076 | + .of_match_table = rcar_csi2_of_table, | |
| 1077 | + }, | |
| 1078 | +}; | |
| 1079 | + | |
| 1080 | +module_platform_driver(rcar_csi2_pdrv); | |
| 1081 | + | |
| 1082 | +MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); | |
| 1083 | +MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver"); | |
| 1084 | +MODULE_LICENSE("GPL"); | |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #include <linux/delay.h> |
| 18 | 18 | #include <linux/interrupt.h> |
| 19 | +#include <linux/pm_runtime.h> | |
| 19 | 20 | |
| 20 | 21 | #include <media/videobuf2-dma-contig.h> |
| 21 | 22 | |
| @@ -33,21 +34,23 @@ · 11 unmodified lines | ||
| 33 | 34 | #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ |
| 34 | 35 | #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ |
| 35 | 36 | #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ |
| 36 | −#define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ | |
| 37 | −#define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ | |
| 38 | −#define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ | |
| 39 | −#define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ | |
| 40 | 37 | #define VNIS_REG 0x2C /* Video n Image Stride Register */ |
| 41 | 38 | #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ |
| 42 | 39 | #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ |
| 43 | 40 | #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ |
| 44 | 41 | #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ |
| 45 | 42 | #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ |
| 46 | −#define VNYS_REG 0x50 /* Video n Y Scale Register */ | |
| 47 | −#define VNXS_REG 0x54 /* Video n X Scale Register */ | |
| 48 | 43 | #define VNDMR_REG 0x58 /* Video n Data Mode Register */ |
| 49 | 44 | #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ |
| 50 | 45 | #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */ |
| 46 | + | |
| 47 | +/* Register offsets specific for Gen2 */ | |
| 48 | +#define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ | |
| 49 | +#define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ | |
| 50 | +#define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ | |
| 51 | +#define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ | |
| 52 | +#define VNYS_REG 0x50 /* Video n Y Scale Register */ | |
| 53 | +#define VNXS_REG 0x54 /* Video n X Scale Register */ | |
| 51 | 54 | #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ |
| 52 | 55 | #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ |
| 53 | 56 | #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ |
| @@ -73,9 +76,13 @@ · 19 unmodified lines | ||
| 73 | 76 | #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ |
| 74 | 77 | #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */ |
| 75 | 78 | |
| 79 | +/* Register offsets specific for Gen3 */ | |
| 80 | +#define VNCSI_IFMD_REG 0x20 /* Video n CSI2 Interface Mode Register */ | |
| 76 | 81 | |
| 77 | 82 | /* Register bit fields for R-Car VIN */ |
| 78 | 83 | /* Video n Main Control Register bits */ |
| 84 | +#define VNMC_DPINE (1 << 27) /* Gen3 specific */ | |
| 85 | +#define VNMC_SCLE (1 << 26) /* Gen3 specific */ | |
| 79 | 86 | #define VNMC_FOC (1 << 21) |
| 80 | 87 | #define VNMC_YCAL (1 << 19) |
| 81 | 88 | #define VNMC_INF_YUV8_BT656 (0 << 16) |
| @@ -119,6 +126,12 @@ · 37 unmodified lines | ||
| 119 | 126 | #define VNDMR2_FTEV (1 << 17) |
| 120 | 127 | #define VNDMR2_VLV(n) ((n & 0xf) << 12) |
| 121 | 128 | |
| 129 | +/* Video n CSI2 Interface Mode Register (Gen3) */ | |
| 130 | +#define VNCSI_IFMD_DES1 (1 << 26) | |
| 131 | +#define VNCSI_IFMD_DES0 (1 << 25) | |
| 132 | +#define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0) | |
| 133 | +#define VNCSI_IFMD_CSI_CHSEL_MASK 0xf | |
| 134 | + | |
| 122 | 135 | struct rvin_buffer { |
| 123 | 136 | struct vb2_v4l2_buffer vb; |
| 124 | 137 | struct list_head list; |
| @@ -138,267 +151,6 @@ static u32 rvin_read(struct rvin_dev *vin, u32 offset) · 13 unmodified lines | ||
| 138 | 151 | return ioread32(vin->base + offset); |
| 139 | 152 | } |
| 140 | 153 | |
| 141 | −static int rvin_setup(struct rvin_dev *vin) | |
| 142 | −{ | |
| 143 | − u32 vnmc, dmr, dmr2, interrupts; | |
| 144 | − v4l2_std_id std; | |
| 145 | − bool progressive = false, output_is_yuv = false, input_is_yuv = false; | |
| 146 | − | |
| 147 | − switch (vin->format.field) { | |
| 148 | − case V4L2_FIELD_TOP: | |
| 149 | − vnmc = VNMC_IM_ODD; | |
| 150 | − break; | |
| 151 | − case V4L2_FIELD_BOTTOM: | |
| 152 | − vnmc = VNMC_IM_EVEN; | |
| 153 | − break; | |
| 154 | − case V4L2_FIELD_INTERLACED: | |
| 155 | − /* Default to TB */ | |
| 156 | − vnmc = VNMC_IM_FULL; | |
| 157 | − /* Use BT if video standard can be read and is 60 Hz format */ | |
| 158 | − if (!v4l2_subdev_call(vin_to_source(vin), video, g_std, &std)) { | |
| 159 | − if (std & V4L2_STD_525_60) | |
| 160 | − vnmc = VNMC_IM_FULL | VNMC_FOC; | |
| 161 | − } | |
| 162 | − break; | |
| 163 | − case V4L2_FIELD_INTERLACED_TB: | |
| 164 | − vnmc = VNMC_IM_FULL; | |
| 165 | − break; | |
| 166 | − case V4L2_FIELD_INTERLACED_BT: | |
| 167 | − vnmc = VNMC_IM_FULL | VNMC_FOC; | |
| 168 | − break; | |
| 169 | − case V4L2_FIELD_ALTERNATE: | |
| 170 | − case V4L2_FIELD_NONE: | |
| 171 | − vnmc = VNMC_IM_ODD_EVEN; | |
| 172 | − progressive = true; | |
| 173 | − break; | |
| 174 | − default: | |
| 175 | − vnmc = VNMC_IM_ODD; | |
| 176 | − break; | |
| 177 | − } | |
| 178 | − | |
| 179 | − /* | |
| 180 | − * Input interface | |
| 181 | − */ | |
| 182 | − switch (vin->digital->code) { | |
| 183 | − case MEDIA_BUS_FMT_YUYV8_1X16: | |
| 184 | − /* BT.601/BT.1358 16bit YCbCr422 */ | |
| 185 | − vnmc |= VNMC_INF_YUV16; | |
| 186 | − input_is_yuv = true; | |
| 187 | − break; | |
| 188 | − case MEDIA_BUS_FMT_UYVY8_2X8: | |
| 189 | − /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ | |
| 190 | − vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? | |
| 191 | − VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; | |
| 192 | − input_is_yuv = true; | |
| 193 | − break; | |
| 194 | − case MEDIA_BUS_FMT_RGB888_1X24: | |
| 195 | − vnmc |= VNMC_INF_RGB888; | |
| 196 | − break; | |
| 197 | − case MEDIA_BUS_FMT_UYVY10_2X10: | |
| 198 | − /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ | |
| 199 | − vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? | |
| 200 | − VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; | |
| 201 | − input_is_yuv = true; | |
| 202 | − break; | |
| 203 | − default: | |
| 204 | − break; | |
| 205 | − } | |
| 206 | − | |
| 207 | − /* Enable VSYNC Field Toogle mode after one VSYNC input */ | |
| 208 | − dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); | |
| 209 | − | |
| 210 | − /* Hsync Signal Polarity Select */ | |
| 211 | − if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) | |
| 212 | − dmr2 |= VNDMR2_HPS; | |
| 213 | − | |
| 214 | − /* Vsync Signal Polarity Select */ | |
| 215 | − if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) | |
| 216 | − dmr2 |= VNDMR2_VPS; | |
| 217 | − | |
| 218 | − /* | |
| 219 | − * Output format | |
| 220 | − */ | |
| 221 | − switch (vin->format.pixelformat) { | |
| 222 | − case V4L2_PIX_FMT_NV16: | |
| 223 | − rvin_write(vin, | |
| 224 | − ALIGN(vin->format.width * vin->format.height, 0x80), | |
| 225 | − VNUVAOF_REG); | |
| 226 | − dmr = VNDMR_DTMD_YCSEP; | |
| 227 | − output_is_yuv = true; | |
| 228 | − break; | |
| 229 | − case V4L2_PIX_FMT_YUYV: | |
| 230 | − dmr = VNDMR_BPSM; | |
| 231 | − output_is_yuv = true; | |
| 232 | − break; | |
| 233 | − case V4L2_PIX_FMT_UYVY: | |
| 234 | − dmr = 0; | |
| 235 | − output_is_yuv = true; | |
| 236 | − break; | |
| 237 | − case V4L2_PIX_FMT_XRGB555: | |
| 238 | − dmr = VNDMR_DTMD_ARGB1555; | |
| 239 | − break; | |
| 240 | − case V4L2_PIX_FMT_RGB565: | |
| 241 | − dmr = 0; | |
| 242 | − break; | |
| 243 | − case V4L2_PIX_FMT_XBGR32: | |
| 244 | − /* Note: not supported on M1 */ | |
| 245 | − dmr = VNDMR_EXRGB; | |
| 246 | − break; | |
| 247 | − default: | |
| 248 | − vin_err(vin, "Invalid pixelformat (0x%x)\n", | |
| 249 | − vin->format.pixelformat); | |
| 250 | − return -EINVAL; | |
| 251 | − } | |
| 252 | − | |
| 253 | − /* Always update on field change */ | |
| 254 | − vnmc |= VNMC_VUP; | |
| 255 | − | |
| 256 | − /* If input and output use the same colorspace, use bypass mode */ | |
| 257 | − if (input_is_yuv == output_is_yuv) | |
| 258 | − vnmc |= VNMC_BPS; | |
| 259 | − | |
| 260 | − /* Progressive or interlaced mode */ | |
| 261 | − interrupts = progressive ? VNIE_FIE : VNIE_EFE; | |
| 262 | − | |
| 263 | − /* Ack interrupts */ | |
| 264 | − rvin_write(vin, interrupts, VNINTS_REG); | |
| 265 | − /* Enable interrupts */ | |
| 266 | − rvin_write(vin, interrupts, VNIE_REG); | |
| 267 | − /* Start capturing */ | |
| 268 | − rvin_write(vin, dmr, VNDMR_REG); | |
| 269 | − rvin_write(vin, dmr2, VNDMR2_REG); | |
| 270 | − | |
| 271 | − /* Enable module */ | |
| 272 | − rvin_write(vin, vnmc | VNMC_ME, VNMC_REG); | |
| 273 | − | |
| 274 | − return 0; | |
| 275 | −} | |
| 276 | − | |
| 277 | −static void rvin_disable_interrupts(struct rvin_dev *vin) | |
| 278 | −{ | |
| 279 | − rvin_write(vin, 0, VNIE_REG); | |
| 280 | −} | |
| 281 | − | |
| 282 | −static u32 rvin_get_interrupt_status(struct rvin_dev *vin) | |
| 283 | −{ | |
| 284 | − return rvin_read(vin, VNINTS_REG); | |
| 285 | −} | |
| 286 | − | |
| 287 | −static void rvin_ack_interrupt(struct rvin_dev *vin) | |
| 288 | −{ | |
| 289 | − rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG); | |
| 290 | −} | |
| 291 | − | |
| 292 | −static bool rvin_capture_active(struct rvin_dev *vin) | |
| 293 | −{ | |
| 294 | − return rvin_read(vin, VNMS_REG) & VNMS_CA; | |
| 295 | −} | |
| 296 | − | |
| 297 | −static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) | |
| 298 | −{ | |
| 299 | − if (vin->format.field == V4L2_FIELD_ALTERNATE) { | |
| 300 | − /* If FS is set it's a Even field */ | |
| 301 | − if (vnms & VNMS_FS) | |
| 302 | − return V4L2_FIELD_BOTTOM; | |
| 303 | − return V4L2_FIELD_TOP; | |
| 304 | − } | |
| 305 | − | |
| 306 | − return vin->format.field; | |
| 307 | −} | |
| 308 | − | |
| 309 | −static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) | |
| 310 | −{ | |
| 311 | − const struct rvin_video_format *fmt; | |
| 312 | − int offsetx, offsety; | |
| 313 | − dma_addr_t offset; | |
| 314 | − | |
| 315 | − fmt = rvin_format_from_pixel(vin->format.pixelformat); | |
| 316 | − | |
| 317 | − /* | |
| 318 | − * There is no HW support for composition do the beast we can | |
| 319 | − * by modifying the buffer offset | |
| 320 | − */ | |
| 321 | − offsetx = vin->compose.left * fmt->bpp; | |
| 322 | − offsety = vin->compose.top * vin->format.bytesperline; | |
| 323 | − offset = addr + offsetx + offsety; | |
| 324 | − | |
| 325 | − /* | |
| 326 | − * The address needs to be 128 bytes aligned. Driver should never accept | |
| 327 | − * settings that do not satisfy this in the first place... | |
| 328 | − */ | |
| 329 | − if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK)) | |
| 330 | − return; | |
| 331 | − | |
| 332 | − rvin_write(vin, offset, VNMB_REG(slot)); | |
| 333 | −} | |
| 334 | − | |
| 335 | −/* | |
| 336 | − * Moves a buffer from the queue to the HW slot. If no buffer is | |
| 337 | − * available use the scratch buffer. The scratch buffer is never | |
| 338 | − * returned to userspace, its only function is to enable the capture | |
| 339 | − * loop to keep running. | |
| 340 | − */ | |
| 341 | −static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) | |
| 342 | −{ | |
| 343 | − struct rvin_buffer *buf; | |
| 344 | − struct vb2_v4l2_buffer *vbuf; | |
| 345 | − dma_addr_t phys_addr; | |
| 346 | − | |
| 347 | − /* A already populated slot shall never be overwritten. */ | |
| 348 | − if (WARN_ON(vin->queue_buf[slot] != NULL)) | |
| 349 | − return; | |
| 350 | − | |
| 351 | − vin_dbg(vin, "Filling HW slot: %d\n", slot); | |
| 352 | − | |
| 353 | − if (list_empty(&vin->buf_list)) { | |
| 354 | − vin->queue_buf[slot] = NULL; | |
| 355 | − phys_addr = vin->scratch_phys; | |
| 356 | − } else { | |
| 357 | − /* Keep track of buffer we give to HW */ | |
| 358 | − buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); | |
| 359 | − vbuf = &buf->vb; | |
| 360 | − list_del_init(to_buf_list(vbuf)); | |
| 361 | − vin->queue_buf[slot] = vbuf; | |
| 362 | − | |
| 363 | − /* Setup DMA */ | |
| 364 | − phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); | |
| 365 | − } | |
| 366 | − | |
| 367 | − rvin_set_slot_addr(vin, slot, phys_addr); | |
| 368 | −} | |
| 369 | − | |
| 370 | −static int rvin_capture_start(struct rvin_dev *vin) | |
| 371 | −{ | |
| 372 | − int slot, ret; | |
| 373 | − | |
| 374 | − for (slot = 0; slot < HW_BUFFER_NUM; slot++) | |
| 375 | − rvin_fill_hw_slot(vin, slot); | |
| 376 | − | |
| 377 | − rvin_crop_scale_comp(vin); | |
| 378 | − | |
| 379 | − ret = rvin_setup(vin); | |
| 380 | − if (ret) | |
| 381 | − return ret; | |
| 382 | − | |
| 383 | − vin_dbg(vin, "Starting to capture\n"); | |
| 384 | − | |
| 385 | − /* Continuous Frame Capture Mode */ | |
| 386 | − rvin_write(vin, VNFC_C_FRAME, VNFC_REG); | |
| 387 | − | |
| 388 | − vin->state = RUNNING; | |
| 389 | − | |
| 390 | − return 0; | |
| 391 | −} | |
| 392 | − | |
| 393 | −static void rvin_capture_stop(struct rvin_dev *vin) | |
| 394 | −{ | |
| 395 | − /* Set continuous & single transfer off */ | |
| 396 | − rvin_write(vin, 0, VNFC_REG); | |
| 397 | − | |
| 398 | − /* Disable module */ | |
| 399 | − rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG); | |
| 400 | −} | |
| 401 | − | |
| 402 | 154 | /* ----------------------------------------------------------------------------- |
| 403 | 155 | * Crop and Scaling Gen2 |
| 404 | 156 | */ |
| @@ -736,122 +488,386 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) · 331 unmodified lines | ||
| 736 | 488 | break; |
| 737 | 489 | } |
| 738 | 490 | |
| 739 | − /* Use previous value if its XS value is closer */ | |
| 740 | − if (p_prev_set && p_set && | |
| 741 | − xs - p_prev_set->xs_value < p_set->xs_value - xs) | |
| 742 | − p_set = p_prev_set; | |
| 491 | + /* Use previous value if its XS value is closer */ | |
| 492 | + if (p_prev_set && p_set && | |
| 493 | + xs - p_prev_set->xs_value < p_set->xs_value - xs) | |
| 494 | + p_set = p_prev_set; | |
| 495 | + | |
| 496 | + /* Set coefficient registers */ | |
| 497 | + rvin_write(vin, p_set->coeff_set[0], VNC1A_REG); | |
| 498 | + rvin_write(vin, p_set->coeff_set[1], VNC1B_REG); | |
| 499 | + rvin_write(vin, p_set->coeff_set[2], VNC1C_REG); | |
| 500 | + | |
| 501 | + rvin_write(vin, p_set->coeff_set[3], VNC2A_REG); | |
| 502 | + rvin_write(vin, p_set->coeff_set[4], VNC2B_REG); | |
| 503 | + rvin_write(vin, p_set->coeff_set[5], VNC2C_REG); | |
| 504 | + | |
| 505 | + rvin_write(vin, p_set->coeff_set[6], VNC3A_REG); | |
| 506 | + rvin_write(vin, p_set->coeff_set[7], VNC3B_REG); | |
| 507 | + rvin_write(vin, p_set->coeff_set[8], VNC3C_REG); | |
| 508 | + | |
| 509 | + rvin_write(vin, p_set->coeff_set[9], VNC4A_REG); | |
| 510 | + rvin_write(vin, p_set->coeff_set[10], VNC4B_REG); | |
| 511 | + rvin_write(vin, p_set->coeff_set[11], VNC4C_REG); | |
| 512 | + | |
| 513 | + rvin_write(vin, p_set->coeff_set[12], VNC5A_REG); | |
| 514 | + rvin_write(vin, p_set->coeff_set[13], VNC5B_REG); | |
| 515 | + rvin_write(vin, p_set->coeff_set[14], VNC5C_REG); | |
| 516 | + | |
| 517 | + rvin_write(vin, p_set->coeff_set[15], VNC6A_REG); | |
| 518 | + rvin_write(vin, p_set->coeff_set[16], VNC6B_REG); | |
| 519 | + rvin_write(vin, p_set->coeff_set[17], VNC6C_REG); | |
| 520 | + | |
| 521 | + rvin_write(vin, p_set->coeff_set[18], VNC7A_REG); | |
| 522 | + rvin_write(vin, p_set->coeff_set[19], VNC7B_REG); | |
| 523 | + rvin_write(vin, p_set->coeff_set[20], VNC7C_REG); | |
| 524 | + | |
| 525 | + rvin_write(vin, p_set->coeff_set[21], VNC8A_REG); | |
| 526 | + rvin_write(vin, p_set->coeff_set[22], VNC8B_REG); | |
| 527 | + rvin_write(vin, p_set->coeff_set[23], VNC8C_REG); | |
| 528 | +} | |
| 529 | + | |
| 530 | +static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) | |
| 531 | +{ | |
| 532 | + u32 xs, ys; | |
| 533 | + | |
| 534 | + /* Set scaling coefficient */ | |
| 535 | + ys = 0; | |
| 536 | + if (vin->crop.height != vin->compose.height) | |
| 537 | + ys = (4096 * vin->crop.height) / vin->compose.height; | |
| 538 | + rvin_write(vin, ys, VNYS_REG); | |
| 539 | + | |
| 540 | + xs = 0; | |
| 541 | + if (vin->crop.width != vin->compose.width) | |
| 542 | + xs = (4096 * vin->crop.width) / vin->compose.width; | |
| 543 | + | |
| 544 | + /* Horizontal upscaling is up to double size */ | |
| 545 | + if (xs > 0 && xs < 2048) | |
| 546 | + xs = 2048; | |
| 547 | + | |
| 548 | + rvin_write(vin, xs, VNXS_REG); | |
| 549 | + | |
| 550 | + /* Horizontal upscaling is done out by scaling down from double size */ | |
| 551 | + if (xs < 4096) | |
| 552 | + xs *= 2; | |
| 553 | + | |
| 554 | + rvin_set_coeff(vin, xs); | |
| 555 | + | |
| 556 | + /* Set Start/End Pixel/Line Post-Clip */ | |
| 557 | + rvin_write(vin, 0, VNSPPOC_REG); | |
| 558 | + rvin_write(vin, 0, VNSLPOC_REG); | |
| 559 | + rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); | |
| 560 | + switch (vin->format.field) { | |
| 561 | + case V4L2_FIELD_INTERLACED: | |
| 562 | + case V4L2_FIELD_INTERLACED_TB: | |
| 563 | + case V4L2_FIELD_INTERLACED_BT: | |
| 564 | + rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); | |
| 565 | + break; | |
| 566 | + default: | |
| 567 | + rvin_write(vin, vin->format.height - 1, VNELPOC_REG); | |
| 568 | + break; | |
| 569 | + } | |
| 570 | + | |
| 571 | + vin_dbg(vin, | |
| 572 | + "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", | |
| 573 | + vin->crop.width, vin->crop.height, vin->crop.left, | |
| 574 | + vin->crop.top, ys, xs, vin->format.width, vin->format.height, | |
| 575 | + 0, 0); | |
| 576 | +} | |
632 more lines aren’t shown here.
This diff is large: its 644 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 520 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 722 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 1117 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 293 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 429 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 178 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 267 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 647 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 577 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 1217 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 1441 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 374 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 1393 lines aren’t shown here.
This diff is large: its 1123 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 969 lines aren’t shown here.
This diff is large: its 1918 lines aren’t shown here.
This diff is large: its 1471 lines aren’t shown here.
This diff is large: its 1272 lines aren’t shown here.
This diff is large: its 405 lines aren’t shown here.
This diff is large: its 671 lines aren’t shown here.
This diff is large: its 1778 lines aren’t shown here.
This diff is large: its 857 lines aren’t shown here.
This diff is large: its 1263 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 1994 lines aren’t shown here.
This diff is large: its 1377 lines aren’t shown here.
This diff is large: its 1360 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 350 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 605 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 6697 lines aren’t shown here.
This diff is large: its 447 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 663 lines aren’t shown here.
This diff is large: its 4705 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 1260 lines aren’t shown here.
This diff is large: its 366 lines aren’t shown here.
This diff is large: its 443 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 409 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 1305 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 3125 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 1423 lines aren’t shown here.
This diff is large: its 468 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 1574 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 322 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 282 lines aren’t shown here.
This diff is large: its 298 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 881 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 3222 lines aren’t shown here.
This diff is large: its 400 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 417 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 3635 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 3221 lines aren’t shown here.
This diff is large: its 400 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 382 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 216 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 3687 lines aren’t shown here.
This diff is large: its 459 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 3221 lines aren’t shown here.
This diff is large: its 400 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 3635 lines aren’t shown here.
This diff is large: its 389 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 256 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 300 lines aren’t shown here.
This diff is large: its 208 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 568 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 1824 lines aren’t shown here.
This diff is large: its 534 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 449 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 307 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 349 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 195 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 185 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 469 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 300 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 353 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 236 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 580 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 583 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 617 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 216 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 307 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 322 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 387 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 220 lines aren’t shown here.
This diff is large: its 424 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 220 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 483 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 258 lines aren’t shown here.
This diff is large: its 1839 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 590 lines aren’t shown here.
This diff is large: its 510 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 3597 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 181 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 1027 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 570 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 614 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 608 lines aren’t shown here.
This diff is large: its 899 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 303 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 806 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 413 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 331 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 11095 lines aren’t shown here.
This diff is large: its 411 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 316 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 1090 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 750 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 268 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 418 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 5254 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 1804 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 728 lines aren’t shown here.
This diff is large: its 1529 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 585 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 786 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
File renamed without changes.
This diff is large: its 5 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This diff is large: its 11 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.