mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
media updates for v6.11-rc1
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmaXfCQACgkQCF8+vY7k 4RWuBg/+NRAVuzYW3AQPIaggajTGHfkk6WCTCVgQQZFCDqphS6YtgfXUJ8qO5YXk ZieGu+g2081BFehzcZxcaSo9pFWyqX1fjUU2sjFwRDSl9NRctsjvKE9J1DVKCsMW QU5yOYyBJmoVugj4YCH7Yga8OElZAWperxJidV4AmFkX93OwZDZl+wNKuSTmG/lX ju+Z6yzv0DN0WvgL8+LlZ2k5tpx+kAld07FFwQM54MPI9CBWyQjogGyro/1S6ymh WAbwbEMCvGSvGhi4issMMOK2mpmh2EAKCXBMWF5bXNOLuFWrU9TtCBr6AITKDvn7 btQNpa8GApO+GehEQtWOX5WgZp2ypwCrMUtiwftPOtF4Z8Tl7MJfn4u6wWCxj4cy 67HbOgWRZQRIzyUSF8vay6PeMrh8jYi+unWuOxGpnzilno1nV2hTzh4n1we15qIn 8pnNSbtgrJCvrIgtATYjP1FWgjBxwuNIpFGxo2ly+hgbu6COLZFfg0Oju3FBdOF1 ZxGkp1SaxcKeuFa6kbATj7y2dAjtre8drB9RfJY1C97Ta+C9ws4jBytVHbceA7u+ GJfAis2CEStLPpe3ND9n0ekeB/qSPcgGC2HLQR7L1u30Kx75T4I49HF0lcKev9gK oTRUPvZu/bI6NmSRwYYY7jo1rox5ffftJ2ZICeQaluV2dbOMUc8= =7nBb -----END PGP SIGNATURE----- Merge tag 'media/v6.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media updates from Mauro Carvalho Chehab: - New sensor drivers: gc05a2, gc08a3 and imx283 - New serializer/deserializer drivers: max96714 and max96717 - New JPEG encoder driver: e5010 - Support for Raspberry Pi PiSP Backend (BE) ISP driver - Old documentation for av7110 driver removed, as a new version was added as Documentation/userspace-api/media/dvb/legacy*.rst - atompisp: Linux firmwares are now available, so drop firmware-related task from TODO and update firmware logic - The imx258 driver has gained several improvements - wave5 driver has gained support for HEVC decoding - em28xx gained support for MyGica UTV3 - av7110 budget-patch driver removed - Lots of other cleanups, improvements and fixes * tag 'media/v6.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (301 commits) media: raspberrypi: Switch to remove_new media: uapi: pisp_be_config: Add extra config fields media: uapi: pisp_be_config: Re-sort pisp_be_tiles_config media: uapi: pisp_common: Capitalize all macros media: uapi: pisp_common: Add 32 bpp format test media: uapi: pisp_be_config: Drop BIT() from uAPI media: stm32: dcmipp: correct error handling in dcmipp_create_subdevs media: atomisp: Fix spelling mistakes in sh_css_sp.c media: atomisp: Fix spelling mistake in ia_css_debug.c media: atomisp: Fix spelling mistake in hmm_bo.c media: atomisp: Fix spelling mistake in ia_css_eed1_8.host.c media: atomisp: Fix spelling mistake in sh_css_internal.h media: atomisp: Fix spelling mistake "pipline" -> "pipeline" media: atomisp: Remove unused GPIO related defines and APIs media: atomisp: Replace COMPILATION_ERROR_IF() by static_assert() media: atomisp: Clean up unused macros from math_support.h media: atomisp: csi2-bridge: Add DMI quirk for OV5693 on Xiaomi Mipad2 media: atomisp: Update TODO media: atomisp: Prefix firmware paths with "intel/ipu/" media: atomisp: Remove firmware_name module parameter ...
This commit is contained in:
commit
b1bc554e00
@ -438,3 +438,11 @@ EM28xx cards list
|
||||
- MyGica iGrabber
|
||||
- em2860
|
||||
- 1f4d:1abe
|
||||
* - 106
|
||||
- Hauppauge USB QuadHD ATSC
|
||||
- em28274
|
||||
- 2040:846d
|
||||
* - 107
|
||||
- MyGica UTV3 Analog USB2.0 TV Box
|
||||
- em2860
|
||||
- eb1a:2860
|
||||
|
@ -135,16 +135,16 @@ sensor ov2740 on Lenovo X1 Yoga laptop.
|
||||
.. code-block:: none
|
||||
|
||||
media-ctl -l "\"ov2740 14-0036\":0 -> \"Intel IPU6 CSI2 1\":0[1]"
|
||||
media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[5]"
|
||||
media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[5]"
|
||||
media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[1]"
|
||||
media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[1]"
|
||||
|
||||
# set routing
|
||||
media-ctl -v -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]"
|
||||
media-ctl -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]"
|
||||
|
||||
media-ctl -v "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]"
|
||||
media-ctl -v "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]"
|
||||
media-ctl -v "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]"
|
||||
media-ctl -v "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]"
|
||||
media-ctl -V "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]"
|
||||
media-ctl -V "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]"
|
||||
media-ctl -V "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]"
|
||||
media-ctl -V "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]"
|
||||
|
||||
CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0")
|
||||
./yavta --data-prefix -c100 -n5 -I -s1932x1092 --file=/tmp/frame-#.bin \
|
||||
|
20
Documentation/admin-guide/media/raspberrypi-pisp-be.dot
Normal file
20
Documentation/admin-guide/media/raspberrypi-pisp-be.dot
Normal file
@ -0,0 +1,20 @@
|
||||
digraph board {
|
||||
rankdir=TB
|
||||
n00000001 [label="{{<port0> 0 | <port1> 1 | <port2> 2 | <port7> 7} | pispbe\n | {<port3> 3 | <port4> 4 | <port5> 5 | <port6> 6}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000001:port3 -> n0000001c [style=bold]
|
||||
n00000001:port4 -> n00000022 [style=bold]
|
||||
n00000001:port5 -> n00000028 [style=bold]
|
||||
n00000001:port6 -> n0000002e [style=bold]
|
||||
n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
|
||||
n0000000a -> n00000001:port0 [style=bold]
|
||||
n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000010 -> n00000001:port1 [style=bold]
|
||||
n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000016 -> n00000001:port2 [style=bold]
|
||||
n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow]
|
||||
n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000034 -> n00000001:port7 [style=bold]
|
||||
}
|
109
Documentation/admin-guide/media/raspberrypi-pisp-be.rst
Normal file
109
Documentation/admin-guide/media/raspberrypi-pisp-be.rst
Normal file
@ -0,0 +1,109 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================================================
|
||||
Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be)
|
||||
=========================================================
|
||||
|
||||
The PiSP Back End
|
||||
=================
|
||||
|
||||
The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads
|
||||
image data from DRAM memory and performs image processing as specified by the
|
||||
application through the parameters in a configuration buffer, before writing
|
||||
pixel data back to memory through two distinct output channels.
|
||||
|
||||
The ISP registers and programming model are documented in the `Raspberry Pi
|
||||
Image Signal Processor (PiSP) Specification document`_
|
||||
|
||||
The PiSP Back End ISP processes images in tiles. The handling of image
|
||||
tessellation and the computation of low-level configuration parameters is
|
||||
realized by a free software library called `libpisp
|
||||
<https://github.com/raspberrypi/libpisp>`_.
|
||||
|
||||
The full image processing pipeline, which involves capturing RAW Bayer data from
|
||||
an image sensor through a MIPI CSI-2 compatible capture interface, storing them
|
||||
in DRAM memory and processing them in the PiSP Back End to obtain images usable
|
||||
by an application is implemented in `libcamera <https://libcamera.org>`_ as
|
||||
part of the Raspberry Pi platform support.
|
||||
|
||||
The pisp-be driver
|
||||
==================
|
||||
|
||||
The Raspberry Pi PiSP Back End (pisp-be) driver is located under
|
||||
drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register
|
||||
a number of video capture and output devices, the `V4L2 subdev API` to register
|
||||
a subdevice for the ISP that connects the video devices in a single media graph
|
||||
realized using the `Media Controller (MC) API`.
|
||||
|
||||
The media topology registered by the `pisp-be` driver is represented below:
|
||||
|
||||
.. _pips-be-topology:
|
||||
|
||||
.. kernel-figure:: raspberrypi-pisp-be.dot
|
||||
:alt: Diagram of the default media pipeline topology
|
||||
:align: center
|
||||
|
||||
|
||||
The media graph registers the following video device nodes:
|
||||
|
||||
- pispbe-input: output device for images to be submitted to the ISP for
|
||||
processing.
|
||||
- pispbe-tdn_input: output device for temporal denoise.
|
||||
- pispbe-stitch_input: output device for image stitching (HDR).
|
||||
- pispbe-output0: first capture device for processed images.
|
||||
- pispbe-output1: second capture device for processed images.
|
||||
- pispbe-tdn_output: capture device for temporal denoise.
|
||||
- pispbe-stitch_output: capture device for image stitching (HDR).
|
||||
- pispbe-config: output device for ISP configuration parameters.
|
||||
|
||||
pispbe-input
|
||||
------------
|
||||
|
||||
Images to be processed by the ISP are queued to the `pispbe-input` output device
|
||||
node. For a list of image formats supported as input to the ISP refer to the
|
||||
`Raspberry Pi Image Signal Processor (PiSP) Specification document`_.
|
||||
|
||||
pispbe-tdn_input, pispbe-tdn_output
|
||||
-----------------------------------
|
||||
|
||||
The `pispbe-tdn_input` output video device receives images to be processed by
|
||||
the temporal denoise block which are captured from the `pispbe-tdn_output`
|
||||
capture video device. Userspace is responsible for maintaining queues on both
|
||||
devices, and ensuring that buffers completed on the output are queued to the
|
||||
input.
|
||||
|
||||
pispbe-stitch_input, pispbe-stitch_output
|
||||
-----------------------------------------
|
||||
|
||||
To realize HDR (high dynamic range) image processing the image stitching and
|
||||
tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory
|
||||
and the `pispbe-stitch_input` receives the previously written frame to process
|
||||
it along with the current input image. Userspace is responsible for maintaining
|
||||
queues on both devices, and ensuring that buffers completed on the output are
|
||||
queued to the input.
|
||||
|
||||
pispbe-output0, pispbe-output1
|
||||
------------------------------
|
||||
|
||||
The two capture devices write to memory the pixel data as processed by the ISP.
|
||||
|
||||
pispbe-config
|
||||
-------------
|
||||
|
||||
The `pispbe-config` output video devices receives a buffer of configuration
|
||||
parameters that define the desired image processing to be performed by the ISP.
|
||||
|
||||
The format of the ISP configuration parameter is defined by
|
||||
:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is
|
||||
described in the `Raspberry Pi Image Signal Processor (PiSP) Specification
|
||||
document`_.
|
||||
|
||||
ISP configuration
|
||||
=================
|
||||
|
||||
The ISP configuration is described solely by the content of the parameters
|
||||
buffer. The only parameter that userspace needs to configure using the V4L2 API
|
||||
is the image format on the output and capture video devices for validation of
|
||||
the content of the parameters buffer.
|
||||
|
||||
.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
|
@ -97,4 +97,6 @@ Tuner number Card name
|
||||
89 Sony BTF-PG472Z PAL/SECAM
|
||||
90 Sony BTF-PK467Z NTSC-M-JP
|
||||
91 Sony BTF-PB463Z NTSC-M
|
||||
92 Silicon Labs Si2157 tuner
|
||||
93 Tena TNF931D-DFDR1
|
||||
============ =====================================================
|
||||
|
@ -23,6 +23,7 @@ Video4Linux (V4L) driver-specific documentation
|
||||
omap4_camera
|
||||
philips
|
||||
qcom_camss
|
||||
raspberrypi-pisp-be
|
||||
rcar-fdp1
|
||||
rkisp1
|
||||
saa7134
|
||||
|
@ -302,6 +302,15 @@ all configurable using the following module options:
|
||||
- 0: forbid hints
|
||||
- 1: allow hints
|
||||
|
||||
- supports_requests:
|
||||
|
||||
specifies if the device should support the Request API. There are
|
||||
three possible values, default is 1:
|
||||
|
||||
- 0: no request
|
||||
- 1: supports requests
|
||||
- 2: requires requests
|
||||
|
||||
Taken together, all these module options allow you to precisely customize
|
||||
the driver behavior and test your application with all sorts of permutations.
|
||||
It is also very suitable to emulate hardware that is not yet available, e.g.
|
||||
@ -313,10 +322,10 @@ Video Capture
|
||||
|
||||
This is probably the most frequently used feature. The video capture device
|
||||
can be configured by using the module options num_inputs, input_types and
|
||||
ccs_cap_mode (see section 1 for more detailed information), but by default
|
||||
four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI
|
||||
input, one input for each input type. Those are described in more detail
|
||||
below.
|
||||
ccs_cap_mode (see "Configuring the driver" for more detailed information),
|
||||
but by default four inputs are configured: a webcam, a TV tuner, an S-Video
|
||||
and an HDMI input, one input for each input type. Those are described in more
|
||||
detail below.
|
||||
|
||||
Special attention has been given to the rate at which new frames become
|
||||
available. The jitter will be around 1 jiffie (that depends on the HZ
|
||||
@ -434,10 +443,10 @@ Video Output
|
||||
------------
|
||||
|
||||
The video output device can be configured by using the module options
|
||||
num_outputs, output_types and ccs_out_mode (see section 1 for more detailed
|
||||
information), but by default two outputs are configured: an S-Video and an
|
||||
HDMI input, one output for each output type. Those are described in more detail
|
||||
below.
|
||||
num_outputs, output_types and ccs_out_mode (see "Configuring the driver"
|
||||
for more detailed information), but by default two outputs are configured:
|
||||
an S-Video and an HDMI input, one output for each output type. Those are
|
||||
described in more detail below.
|
||||
|
||||
Like with video capture the framerate is also exact in the long term.
|
||||
|
||||
@ -1011,11 +1020,6 @@ Digital Video Controls
|
||||
affects the reported colorspace since DVI_D outputs will always use
|
||||
sRGB.
|
||||
|
||||
- Display Present:
|
||||
|
||||
sets the presence of a "display" on the HDMI output. This affects
|
||||
the tx_edid_present, tx_hotplug and tx_rxsense controls.
|
||||
|
||||
|
||||
FM Radio Receiver Controls
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -1130,35 +1134,34 @@ Metadata Capture Controls
|
||||
|
||||
if set, then the generated metadata stream contains Source Clock information.
|
||||
|
||||
Video, VBI and RDS Looping
|
||||
--------------------------
|
||||
|
||||
The vivid driver supports looping of video output to video input, VBI output
|
||||
to VBI input and RDS output to RDS input. For video/VBI looping this emulates
|
||||
as if a cable was hooked up between the output and input connector. So video
|
||||
and VBI looping is only supported between S-Video and HDMI inputs and outputs.
|
||||
VBI is only valid for S-Video as it makes no sense for HDMI.
|
||||
Video, Sliced VBI and HDMI CEC Looping
|
||||
--------------------------------------
|
||||
|
||||
Since radio is wireless this looping always happens if the radio receiver
|
||||
frequency is close to the radio transmitter frequency. In that case the radio
|
||||
transmitter will 'override' the emulated radio stations.
|
||||
Video Looping functionality is supported for devices created by the same
|
||||
vivid driver instance, as well as across multiple instances of the vivid driver.
|
||||
The vivid driver supports looping of video and Sliced VBI data between an S-Video output
|
||||
and an S-Video input. It also supports looping of video and HDMI CEC data between an
|
||||
HDMI output and an HDMI input.
|
||||
|
||||
Looping is currently supported only between devices created by the same
|
||||
vivid driver instance.
|
||||
To enable looping, set the 'HDMI/S-Video XXX-N Is Connected To' control(s) to select
|
||||
whether an input uses the Test Pattern Generator, or is disconnected, or is connected
|
||||
to an output. An input can be connected to an output from any vivid instance.
|
||||
The inputs and outputs are numbered XXX-N where XXX is the vivid instance number
|
||||
(see module option n_devs). If there is only one vivid instance (the default), then
|
||||
XXX will be 000. And N is the Nth S-Video/HDMI input or output of that instance.
|
||||
If vivid is loaded without module options, then you can connect the S-Video 000-0 input
|
||||
to the S-Video 000-0 output, or the HDMI 000-0 input to the HDMI 000-0 output.
|
||||
This is the equivalent of connecting or disconnecting a cable between an input and an
|
||||
output in a physical device.
|
||||
|
||||
If an 'HDMI/S-Video XXX-N Is Connected To' control selected an output, then the video
|
||||
output will be looped to the video input provided that:
|
||||
|
||||
Video and Sliced VBI looping
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- the currently selected input matches the input indicated by the control name.
|
||||
|
||||
The way to enable video/VBI looping is currently fairly crude. A 'Loop Video'
|
||||
control is available in the "Vivid" control class of the video
|
||||
capture and VBI capture devices. When checked the video looping will be enabled.
|
||||
Once enabled any video S-Video or HDMI input will show a static test pattern
|
||||
until the video output has started. At that time the video output will be
|
||||
looped to the video input provided that:
|
||||
|
||||
- the input type matches the output type. So the HDMI input cannot receive
|
||||
video from the S-Video output.
|
||||
- in the vivid instance of the output connector, the currently selected output matches
|
||||
the output indicated by the control's value.
|
||||
|
||||
- the video resolution of the video input must match that of the video output.
|
||||
So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz
|
||||
@ -1185,6 +1188,8 @@ looped to the video input provided that:
|
||||
"DV Timings Signal Mode" for the HDMI input should be configured so that a
|
||||
valid signal is passed to the video input.
|
||||
|
||||
If any condition is not valid, then the 'Noise' test pattern is shown.
|
||||
|
||||
The framerates do not have to match, although this might change in the future.
|
||||
|
||||
By default you will see the OSD text superimposed on top of the looped video.
|
||||
@ -1198,17 +1203,26 @@ and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped.
|
||||
|
||||
|
||||
Radio & RDS Looping
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
-------------------
|
||||
|
||||
As mentioned in section 6 the radio receiver emulates stations are regular
|
||||
frequency intervals. Depending on the frequency of the radio receiver a
|
||||
signal strength value is calculated (this is returned by VIDIOC_G_TUNER).
|
||||
However, it will also look at the frequency set by the radio transmitter and
|
||||
if that results in a higher signal strength than the settings of the radio
|
||||
transmitter will be used as if it was a valid station. This also includes
|
||||
the RDS data (if any) that the transmitter 'transmits'. This is received
|
||||
faithfully on the receiver side. Note that when the driver is loaded the
|
||||
frequencies of the radio receiver and transmitter are not identical, so
|
||||
The vivid driver supports looping of RDS output to RDS input.
|
||||
|
||||
Since radio is wireless this looping always happens if the radio receiver
|
||||
frequency is close to the radio transmitter frequency. In that case the radio
|
||||
transmitter will 'override' the emulated radio stations.
|
||||
|
||||
RDS looping is currently supported only between devices created by the same
|
||||
vivid driver instance.
|
||||
|
||||
As mentioned in the "Radio Receiver" section, the radio receiver emulates
|
||||
stations at regular frequency intervals. Depending on the frequency of the
|
||||
radio receiver a signal strength value is calculated (this is returned by
|
||||
VIDIOC_G_TUNER). However, it will also look at the frequency set by the radio
|
||||
transmitter and if that results in a higher signal strength than the settings
|
||||
of the radio transmitter will be used as if it was a valid station. This also
|
||||
includes the RDS data (if any) that the transmitter 'transmits'. This is
|
||||
received faithfully on the receiver side. Note that when the driver is loaded
|
||||
the frequencies of the radio receiver and transmitter are not identical, so
|
||||
initially no looping takes place.
|
||||
|
||||
|
||||
@ -1218,8 +1232,8 @@ Cropping, Composing, Scaling
|
||||
This driver supports cropping, composing and scaling in any combination. Normally
|
||||
which features are supported can be selected through the Vivid controls,
|
||||
but it is also possible to hardcode it when the module is loaded through the
|
||||
ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of
|
||||
these module options.
|
||||
ccs_cap_mode and ccs_out_mode module options. See "Configuring the driver" on
|
||||
the details of these module options.
|
||||
|
||||
This allows you to test your application for all these variations.
|
||||
|
||||
@ -1260,7 +1274,8 @@ is set, then the alpha component is only used for the color red and set to
|
||||
|
||||
The driver has to be configured to support the multiplanar formats. By default
|
||||
the driver instances are single-planar. This can be changed by setting the
|
||||
multiplanar module option, see section 1 for more details on that option.
|
||||
multiplanar module option, see "Configuring the driver" for more details on that
|
||||
option.
|
||||
|
||||
If the driver instance is using the multiplanar formats/API, then the first
|
||||
single planar format (YUYV) and the multiplanar NV16M and NV61M formats the
|
||||
@ -1270,74 +1285,6 @@ data_offset to be non-zero, so this is a useful feature for testing applications
|
||||
Video output will also honor any data_offset that the application set.
|
||||
|
||||
|
||||
Capture Overlay
|
||||
---------------
|
||||
|
||||
Note: capture overlay support is implemented primarily to test the existing
|
||||
V4L2 capture overlay API. In practice few if any GPUs support such overlays
|
||||
anymore, and neither are they generally needed anymore since modern hardware
|
||||
is so much more capable. By setting flag 0x10000 in the node_types module
|
||||
option the vivid driver will create a simple framebuffer device that can be
|
||||
used for testing this API. Whether this API should be used for new drivers is
|
||||
questionable.
|
||||
|
||||
This driver has support for a destructive capture overlay with bitmap clipping
|
||||
and list clipping (up to 16 rectangles) capabilities. Overlays are not
|
||||
supported for multiplanar formats. It also honors the struct v4l2_window field
|
||||
setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is
|
||||
FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay.
|
||||
|
||||
The overlay only works if you are also capturing at that same time. This is a
|
||||
vivid limitation since it copies from a buffer to the overlay instead of
|
||||
filling the overlay directly. And if you are not capturing, then no buffers
|
||||
are available to fill.
|
||||
|
||||
In addition, the pixelformat of the capture format and that of the framebuffer
|
||||
must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return
|
||||
an error.
|
||||
|
||||
In order to really see what it going on you will need to create two vivid
|
||||
instances: the first with a framebuffer enabled. You configure the capture
|
||||
overlay of the second instance to use the framebuffer of the first, then
|
||||
you start capturing in the second instance. For the first instance you setup
|
||||
the output overlay for the video output, turn on video looping and capture
|
||||
to see the blended framebuffer overlay that's being written to by the second
|
||||
instance. This setup would require the following commands:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1
|
||||
$ v4l2-ctl -d1 --find-fb
|
||||
/dev/fb1 is the framebuffer associated with base address 0x12800000
|
||||
$ sudo v4l2-ctl -d2 --set-fbuf fb=1
|
||||
$ v4l2-ctl -d1 --set-fbuf fb=1
|
||||
$ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15'
|
||||
$ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15'
|
||||
$ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15'
|
||||
$ v4l2-ctl -d0 -i2
|
||||
$ v4l2-ctl -d2 -i2
|
||||
$ v4l2-ctl -d2 -c horizontal_movement=4
|
||||
$ v4l2-ctl -d1 --overlay=1
|
||||
$ v4l2-ctl -d0 -c loop_video=1
|
||||
$ v4l2-ctl -d2 --stream-mmap --overlay=1
|
||||
|
||||
And from another console:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ v4l2-ctl -d1 --stream-out-mmap
|
||||
|
||||
And yet another console:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ qv4l2
|
||||
|
||||
and start streaming.
|
||||
|
||||
As you can see, this is not for the faint of heart...
|
||||
|
||||
|
||||
Output Overlay
|
||||
--------------
|
||||
|
||||
@ -1405,8 +1352,6 @@ Just as a reminder and in no particular order:
|
||||
- Add ARGB888 overlay support: better testing of the alpha channel
|
||||
- Improve pixel aspect support in the tpg code by passing a real v4l2_fract
|
||||
- Use per-queue locks and/or per-device locks to improve throughput
|
||||
- Add support to loop from a specific output to a specific input across
|
||||
vivid instances
|
||||
- The SDR radio should use the same 'frequencies' for stations as the normal
|
||||
radio receiver, and give back noise if the frequency doesn't match up with
|
||||
a station frequency
|
||||
|
@ -0,0 +1,112 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright (c) 2023 MediaTek Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc05a2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GalaxyCore gc05a2 1/5" 5M Pixel MIPI CSI-2 sensor
|
||||
|
||||
maintainers:
|
||||
- Zhi Mao <zhi.mao@mediatek.com>
|
||||
|
||||
description:
|
||||
The gc05a2 is a raw image sensor with an MIPI CSI-2 image data
|
||||
interface and CCI (I2C compatible) control bus. The output format
|
||||
is raw Bayer.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: galaxycore,gc05a2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
dovdd-supply: true
|
||||
|
||||
avdd-supply: true
|
||||
|
||||
dvdd-supply: true
|
||||
|
||||
reset-gpios:
|
||||
description: Reference to the GPIO connected to the RESETB pin.
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
additionalProperties: false
|
||||
description:
|
||||
Output port node, single endpoint describing the CSI-2 transmitter.
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- dovdd-supply
|
||||
- avdd-supply
|
||||
- dvdd-supply
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@37 {
|
||||
compatible = "galaxycore,gc05a2";
|
||||
reg = <0x37>;
|
||||
|
||||
clocks = <&gc05a2_clk>;
|
||||
|
||||
reset-gpios = <&pio 21 GPIO_ACTIVE_LOW>;
|
||||
|
||||
avdd-supply = <&gc05a2_avdd>;
|
||||
dovdd-supply = <&gc05a2_dovdd>;
|
||||
dvdd-supply = <&gc05a2_dvdd>;
|
||||
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
data-lanes = <1 2>;
|
||||
link-frequencies = /bits/ 64 <448000000 224000000>;
|
||||
remote-endpoint = <&seninf_csi_port_1_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,112 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright (c) 2023 MediaTek Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc08a3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GalaxyCore gc08a3 1/4" 8M Pixel MIPI CSI-2 sensor
|
||||
|
||||
maintainers:
|
||||
- Zhi Mao <zhi.mao@mediatek.com>
|
||||
|
||||
description:
|
||||
The gc08a3 is a raw image sensor with an MIPI CSI-2 image data
|
||||
interface and CCI (I2C compatible) control bus. The output format
|
||||
is raw Bayer.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: galaxycore,gc08a3
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
dovdd-supply: true
|
||||
|
||||
avdd-supply: true
|
||||
|
||||
dvdd-supply: true
|
||||
|
||||
reset-gpios:
|
||||
description: Reference to the GPIO connected to the RESETB pin.
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
additionalProperties: false
|
||||
description:
|
||||
Output port node, single endpoint describing the CSI-2 transmitter.
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- dovdd-supply
|
||||
- avdd-supply
|
||||
- dvdd-supply
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@31 {
|
||||
compatible = "galaxycore,gc08a3";
|
||||
reg = <0x31>;
|
||||
|
||||
clocks = <&gc08a3_clk>;
|
||||
|
||||
reset-gpios = <&pio 19 GPIO_ACTIVE_LOW>;
|
||||
|
||||
avdd-supply = <&gc08a3_avdd>;
|
||||
dovdd-supply = <&gc08a3_dovdd>;
|
||||
dvdd-supply = <&gc08a3_dvdd>;
|
||||
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <336000000 207000000>;
|
||||
remote-endpoint = <&seninf_csi_port_0_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
174
Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
Normal file
174
Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
Normal file
@ -0,0 +1,174 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2024 Collabora Ltd.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/maxim,max96714.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX96714 GMSL2 to CSI-2 Deserializer
|
||||
|
||||
maintainers:
|
||||
- Julien Massot <julien.massot@collabora.com>
|
||||
|
||||
description:
|
||||
The MAX96714 deserializer converts GMSL2 serial inputs into MIPI
|
||||
CSI-2 D-PHY formatted output. The device allows the GMSL2 link to
|
||||
simultaneously transmit bidirectional control-channel data while forward
|
||||
video transmissions are in progress. The MAX96714 can connect to one
|
||||
remotely located serializer using industry-standard coax or STP
|
||||
interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
|
||||
the MAX96714 can select individual video stream, while the tunnel mode forward all
|
||||
the MIPI data received by the serializer.
|
||||
|
||||
The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the
|
||||
forward direction and 187.5Mbps in the reverse direction.
|
||||
MAX96714F only supports a fixed rate of 3Gbps in the forward direction.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: maxim,max96714f
|
||||
- items:
|
||||
- enum:
|
||||
- maxim,max96714
|
||||
- const: maxim,max96714f
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
powerdown-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
Specifier for the GPIO connected to the PWDNB pin.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
description: GMSL Input
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Endpoint for GMSL2-Link port.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: CSI-2 Output port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
lane-polarities:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
link-frequencies:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
required:
|
||||
- port@1
|
||||
|
||||
i2c-gate:
|
||||
$ref: /schemas/i2c/i2c-gate.yaml
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
The MAX96714 will pass through and forward the I2C requests from the
|
||||
incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate
|
||||
subnode to configure a serializer.
|
||||
|
||||
port0-poc-supply:
|
||||
description: Regulator providing Power over Coax for the GMSL port
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/media/video-interfaces.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
deserializer@28 {
|
||||
compatible = "maxim,max96714f";
|
||||
reg = <0x28>;
|
||||
powerdown-gpios = <&main_gpio0 37 GPIO_ACTIVE_LOW>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
max96714_gmsl_in: endpoint {
|
||||
remote-endpoint = <&max96917f_gmsl_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
max96714_csi_out: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <400000000>;
|
||||
remote-endpoint = <&csi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c-gate {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
serializer@40 {
|
||||
compatible = "maxim,max96717f";
|
||||
reg = <0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
max96717f_csi_in: endpoint {
|
||||
data-lanes = <1 2>;
|
||||
lane-polarities = <1 0 1>;
|
||||
remote-endpoint = <&sensor_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
max96917f_gmsl_out: endpoint {
|
||||
remote-endpoint = <&max96714_gmsl_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
157
Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
Normal file
157
Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
Normal file
@ -0,0 +1,157 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2024 Collabora Ltd.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/maxim,max96717.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MAX96717 CSI-2 to GMSL2 Serializer
|
||||
|
||||
maintainers:
|
||||
- Julien Massot <julien.massot@collabora.com>
|
||||
|
||||
description:
|
||||
The MAX96717 serializer converts MIPI CSI-2 D-PHY formatted input
|
||||
into GMSL2 serial outputs. The device allows the GMSL2 link to
|
||||
simultaneously transmit bidirectional control-channel data while forward
|
||||
video transmissions are in progress. The MAX96717 can connect to one
|
||||
remotely located deserializer using industry-standard coax or STP
|
||||
interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
|
||||
the MAX96717 can select the MIPI datatype, while the tunnel mode forward all the MIPI
|
||||
data received by the serializer.
|
||||
The MAX96717 supports Reference Over Reverse (channel),
|
||||
to generate a clock output for the sensor from the GMSL reverse channel.
|
||||
|
||||
The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the
|
||||
forward direction and 187.5Mbps in the reverse direction.
|
||||
MAX96717F only supports a fixed rate of 3Gbps in the forward direction.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: maxim,max96717f
|
||||
- items:
|
||||
- enum:
|
||||
- maxim,max96717
|
||||
- const: maxim,max96717f
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
description:
|
||||
First cell is the GPIO pin number, second cell is the flags. The GPIO pin
|
||||
number must be in range of [0, 10].
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: CSI-2 Input port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
lane-polarities:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
description: GMSL Output port
|
||||
|
||||
required:
|
||||
- port@1
|
||||
|
||||
i2c-gate:
|
||||
$ref: /schemas/i2c/i2c-gate.yaml
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
The MAX96717 will forward the I2C requests from the
|
||||
incoming GMSL2 link. Therefore, it supports an i2c-gate
|
||||
subnode to configure a sensor.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/media/video-interfaces.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
serializer: serializer@40 {
|
||||
compatible = "maxim,max96717f";
|
||||
reg = <0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
max96717f_csi_in: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
remote-endpoint = <&sensor_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
max96917f_gmsl_out: endpoint {
|
||||
remote-endpoint = <&deser_gmsl_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c-gate {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
sensor@10 {
|
||||
compatible = "st,st-vgxy61";
|
||||
reg = <0x10>;
|
||||
reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&serializer>;
|
||||
VCORE-supply = <&v1v2>;
|
||||
VDDIO-supply = <&v1v8>;
|
||||
VANA-supply = <&v2v8>;
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
remote-endpoint = <&max96717f_csi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/imx258.yaml#
|
||||
$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor
|
||||
@ -13,11 +13,16 @@ description: |-
|
||||
IMX258 is a diagonal 5.867mm (Type 1/3.06) 13 Mega-pixel CMOS active pixel
|
||||
type stacked image sensor with a square pixel array of size 4208 x 3120. It
|
||||
is programmable through I2C interface. Image data is sent through MIPI
|
||||
CSI-2.
|
||||
CSI-2. The sensor exists in two different models, a standard variant
|
||||
(IMX258) and a variant with phase detection autofocus (IMX258-PDAF).
|
||||
The camera module does not expose the model through registers, so the
|
||||
exact model needs to be specified.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sony,imx258
|
||||
enum:
|
||||
- sony,imx258
|
||||
- sony,imx258-pdaf
|
||||
|
||||
assigned-clocks: true
|
||||
assigned-clock-parents: true
|
107
Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
Normal file
107
Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
Normal file
@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2024 Ideas on Board Oy
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/sony,imx283.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony IMX283 Sensor
|
||||
|
||||
maintainers:
|
||||
- Kieran Bingham <kieran.bingham@ideasonboard.com>
|
||||
- Umang Jain <umang.jain@ideasonboard.com>
|
||||
|
||||
description:
|
||||
IMX283 sensor is a Sony CMOS active pixel digital image sensor with an active
|
||||
array size of 5472H x 3648V. It is programmable through I2C interface. The
|
||||
I2C client address is fixed to 0x1a as per sensor data sheet. Image data is
|
||||
sent through MIPI CSI-2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sony,imx283
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: Clock frequency from 6 to 24 MHz.
|
||||
maxItems: 1
|
||||
|
||||
vadd-supply:
|
||||
description: Analog power supply (2.9V)
|
||||
|
||||
vdd1-supply:
|
||||
description: Interface power supply (1.8V)
|
||||
|
||||
vdd2-supply:
|
||||
description: Digital power supply (1.2V)
|
||||
|
||||
reset-gpios:
|
||||
description: Sensor reset (XCLR) GPIO
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
anyOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
camera@1a {
|
||||
compatible = "sony,imx283";
|
||||
reg = <0x1a>;
|
||||
clocks = <&imx283_clk>;
|
||||
|
||||
assigned-clocks = <&imx283_clk>;
|
||||
assigned-clock-parents = <&imx283_clk_parent>;
|
||||
assigned-clock-rates = <12000000>;
|
||||
|
||||
vadd-supply = <&camera_vadd_2v9>;
|
||||
vdd1-supply = <&camera_vdd1_1v8>;
|
||||
vdd2-supply = <&camera_vdd2_1v2>;
|
||||
|
||||
port {
|
||||
imx283: endpoint {
|
||||
remote-endpoint = <&cam>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <360000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/img,e5010-jpeg-enc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Imagination E5010 JPEG Encoder
|
||||
|
||||
maintainers:
|
||||
- Devarsh Thakkar <devarsht@ti.com>
|
||||
|
||||
description: |
|
||||
The E5010 is a JPEG encoder from Imagination Technologies implemented on
|
||||
TI's AM62A SoC. It is capable of real time encoding of YUV420 and YUV422
|
||||
inputs to JPEG and M-JPEG. It supports baseline JPEG Encoding up to
|
||||
8Kx8K resolution.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: ti,am62a-jpeg-enc
|
||||
- const: img,e5010-jpeg-enc
|
||||
- const: img,e5010-jpeg-enc
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: The E5010 core register region
|
||||
- description: The E5010 mmu register region
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: mmu
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
jpeg-encoder@fd20000 {
|
||||
compatible = "img,e5010-jpeg-enc";
|
||||
reg = <0x00 0xfd20000 0x00 0x100>,
|
||||
<0x00 0xfd20200 0x00 0x200>;
|
||||
reg-names = "core", "mmu";
|
||||
clocks = <&k3_clks 201 0>;
|
||||
power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>;
|
||||
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
@ -23,6 +23,7 @@ properties:
|
||||
oneOf:
|
||||
- enum:
|
||||
- mediatek,mt8183-mdp3-rdma
|
||||
- mediatek,mt8188-mdp3-rdma
|
||||
- mediatek,mt8195-mdp3-rdma
|
||||
- mediatek,mt8195-vdo1-rdma
|
||||
- items:
|
||||
|
@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/mediatek,mt7622-cir.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Consumer Infrared Receiver on-SoC Controller
|
||||
|
||||
maintainers:
|
||||
- Sean Wang <sean.wang@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: rc.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7622-cir
|
||||
- mediatek,mt7623-cir
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: clk
|
||||
- const: bus
|
||||
|
||||
required:
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt2701-clk.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
ir@10013000 {
|
||||
compatible = "mediatek,mt7623-cir";
|
||||
reg = <0x10013000 0x1000>;
|
||||
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_IRRX>, <&topckgen CLK_TOP_AXI_SEL>;
|
||||
clock-names = "clk", "bus";
|
||||
linux,rc-map-name = "rc-rc6-mce";
|
||||
};
|
@ -1,28 +0,0 @@
|
||||
Device-Tree bindings for Mediatek consumer IR controller
|
||||
found in Mediatek SoC family
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be
|
||||
"mediatek,mt7623-cir": for MT7623 SoC
|
||||
"mediatek,mt7622-cir": for MT7622 SoC
|
||||
- clocks : list of clock specifiers, corresponding to
|
||||
entries in clock-names property;
|
||||
- clock-names : should contain
|
||||
- "clk" entries: for MT7623 SoC
|
||||
- "clk", "bus" entries: for MT7622 SoC
|
||||
- interrupts : should contain IR IRQ number;
|
||||
- reg : should contain IO map address for IR.
|
||||
|
||||
Optional properties:
|
||||
- linux,rc-map-name : see rc.txt file in the same directory.
|
||||
|
||||
Example:
|
||||
|
||||
cir: cir@10013000 {
|
||||
compatible = "mediatek,mt7623-cir";
|
||||
reg = <0 0x10013000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_IRRX>;
|
||||
clock-names = "clk";
|
||||
linux,rc-map-name = "rc-rc6-mce";
|
||||
};
|
@ -18,7 +18,9 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,msm8996-venus
|
||||
enum:
|
||||
- qcom,msm8996-venus
|
||||
- qcom,msm8998-venus
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End
|
||||
|
||||
maintainers:
|
||||
- Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
|
||||
- Jacopo Mondi <jacopo.mondi@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image
|
||||
processor that fetches images in Bayer or Grayscale format from DRAM memory
|
||||
in tiles and produces images consumable by applications.
|
||||
|
||||
The full ISP documentation is available at
|
||||
https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- brcm,bcm2712-pispbe
|
||||
- const: raspberrypi,pispbe
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
isp@880000 {
|
||||
compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe";
|
||||
reg = <0x10 0x00880000 0x0 0x4000>;
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&firmware_clocks 7>;
|
||||
iommus = <&iommu2>;
|
||||
};
|
||||
};
|
@ -103,6 +103,7 @@ properties:
|
||||
- rc-msi-digivox-iii
|
||||
- rc-msi-tvanywhere
|
||||
- rc-msi-tvanywhere-plus
|
||||
- rc-mygica-utv3
|
||||
- rc-nebula
|
||||
- rc-nec-terratec-cinergy-xs
|
||||
- rc-norwood
|
||||
|
@ -24,6 +24,7 @@ properties:
|
||||
- enum:
|
||||
- rockchip,rk3228-rga
|
||||
- rockchip,rk3568-rga
|
||||
- rockchip,rk3588-rga
|
||||
- const: rockchip,rk3288-rga
|
||||
|
||||
reg:
|
||||
|
@ -26,3 +26,4 @@ Video4Linux devices
|
||||
v4l2-tuner
|
||||
v4l2-common
|
||||
v4l2-tveeprom
|
||||
v4l2-jpeg
|
||||
|
10
Documentation/driver-api/media/v4l2-jpeg.rst
Normal file
10
Documentation/driver-api/media/v4l2-jpeg.rst
Normal file
@ -0,0 +1,10 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
V4L2 JPEG header related functions and data structures
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. kernel-doc:: include/media/v4l2-jpeg.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/media/v4l2-core/v4l2-jpeg.c
|
||||
:export:
|
@ -35,6 +35,6 @@ For more details see the file COPYING in the source distribution of Linux.
|
||||
max2175
|
||||
npcm-video
|
||||
omap3isp-uapi
|
||||
st-vgxy61
|
||||
thp7312
|
||||
uvcvideo
|
||||
vgxy61
|
||||
|
@ -971,8 +971,8 @@ FWHT Flags
|
||||
- ``horizontal_scale``
|
||||
- Horizontal scaling factor.
|
||||
* - __u8
|
||||
- ``vertical_scaling factor``
|
||||
- Vertical scale.
|
||||
- ``vertical_scale``
|
||||
- Vertical scaling factor.
|
||||
* - __u8
|
||||
- ``version``
|
||||
- Bitstream version.
|
||||
|
@ -1653,6 +1653,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
|
||||
Quantization parameter for a P frame for FWHT. Valid range: from 1
|
||||
to 31.
|
||||
|
||||
``V4L2_CID_MPEG_VIDEO_AVERAGE_QP (integer)``
|
||||
This read-only control returns the average QP value of the currently
|
||||
encoded frame. The value applies to the last dequeued capture buffer
|
||||
(VIDIOC_DQBUF). Its valid range depends on the encoding format and parameters.
|
||||
For H264, its valid range is from 0 to 51.
|
||||
For HEVC, its valid range is from 0 to 51 for 8 bit and
|
||||
from 0 to 63 for 10 bit.
|
||||
For H263 and MPEG4, its valid range is from 1 to 31.
|
||||
For VP8, its valid range is from 0 to 127.
|
||||
For VP9, its valid range is from 0 to 255.
|
||||
If the codec's MIN_QP and MAX_QP are set, then the QP will meet both requirements.
|
||||
Codecs need to always use the specified range, rather then a HW custom range.
|
||||
Applicable to encoders
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\normalsize
|
||||
|
@ -15,6 +15,7 @@ These formats are used for the :ref:`metadata` interface only.
|
||||
metafmt-d4xx
|
||||
metafmt-generic
|
||||
metafmt-intel-ipu3
|
||||
metafmt-pisp-be
|
||||
metafmt-rkisp1
|
||||
metafmt-uvc
|
||||
metafmt-vivid
|
||||
|
56
Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
Normal file
56
Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
Normal file
@ -0,0 +1,56 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _v4l2-meta-fmt-rpi-be-cfg:
|
||||
|
||||
************************
|
||||
V4L2_META_FMT_RPI_BE_CFG
|
||||
************************
|
||||
|
||||
Raspberry Pi PiSP Back End configuration format
|
||||
===============================================
|
||||
|
||||
The Raspberry Pi PiSP Back End memory-to-memory image signal processor is
|
||||
configured by userspace by providing a buffer of configuration parameters
|
||||
to the `pispbe-config` output video device node using the
|
||||
:c:type:`v4l2_meta_format` interface.
|
||||
|
||||
The PiSP Back End processes images in tiles, and its configuration requires
|
||||
specifying two different sets of parameters by populating the members of
|
||||
:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file.
|
||||
|
||||
The `Raspberry Pi PiSP technical specification
|
||||
<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_
|
||||
provide detailed description of the ISP back end configuration and programming
|
||||
model.
|
||||
|
||||
Global configuration data
|
||||
-------------------------
|
||||
|
||||
The global configuration data describe how the pixels in a particular image are
|
||||
to be processed and is therefore shared across all the tiles of the image. So
|
||||
for example, LSC (Lens Shading Correction) or Denoise parameters would be common
|
||||
across all tiles from the same frame.
|
||||
|
||||
Global configuration data are passed to the ISP by populating the member of
|
||||
:c:type:`pisp_be_config`.
|
||||
|
||||
Tile parameters
|
||||
---------------
|
||||
|
||||
As the ISP processes images in tiles, each set of tiles parameters describe how
|
||||
a single tile in an image is going to be processed. A single set of tile
|
||||
parameters consist of 160 bytes of data and to process a batch of tiles several
|
||||
sets of tiles parameters are required.
|
||||
|
||||
Tiles parameters are passed to the ISP by populating the member of
|
||||
``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`.
|
||||
|
||||
Raspberry Pi PiSP Back End uAPI data types
|
||||
==========================================
|
||||
|
||||
This section describes the data types exposed to userspace by the Raspberry Pi
|
||||
PiSP Back End. The section is informative only, for a detailed description of
|
||||
each field refer to the `Raspberry Pi PiSP technical specification
|
||||
<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_.
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h
|
@ -20,6 +20,7 @@ orders. See also `the Wikipedia article on Bayer filter
|
||||
:maxdepth: 1
|
||||
|
||||
pixfmt-srggb8
|
||||
pixfmt-srggb8-pisp-comp
|
||||
pixfmt-srggb10
|
||||
pixfmt-srggb10p
|
||||
pixfmt-srggb10alaw8
|
||||
|
@ -996,6 +996,60 @@ arranged in little endian order.
|
||||
|
||||
\normalsize
|
||||
|
||||
16 Bits Per Component
|
||||
=====================
|
||||
|
||||
These formats store an RGB triplet in six bytes, with 16 bits per component
|
||||
stored in memory in little endian byte order. They are named based on the order
|
||||
of the RGB components as stored in memory. For instance, RGB48 stores R\
|
||||
:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from
|
||||
the DRM format nomenclature that instead uses the order of components as seen in
|
||||
the 48-bits little endian word.
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\small
|
||||
|
||||
.. flat-table:: RGB Formats With 16 Bits Per Component
|
||||
:header-rows: 1
|
||||
|
||||
* - Identifier
|
||||
- Code
|
||||
- Byte 0
|
||||
- Byte 1
|
||||
- Byte 2
|
||||
- Byte 3
|
||||
- Byte 4
|
||||
- Byte 5
|
||||
|
||||
* .. _V4L2-PIX-FMT-BGR48:
|
||||
|
||||
- ``V4L2_PIX_FMT_BGR48``
|
||||
- 'BGR6'
|
||||
|
||||
- B\ :sub:`7-0`
|
||||
- B\ :sub:`15-8`
|
||||
- G\ :sub:`7-0`
|
||||
- G\ :sub:`15-8`
|
||||
- R\ :sub:`7-0`
|
||||
- R\ :sub:`15-8`
|
||||
|
||||
* .. _V4L2-PIX-FMT-RGB48:
|
||||
|
||||
- ``V4L2_PIX_FMT_RGB48``
|
||||
- 'RGB6'
|
||||
|
||||
- R\ :sub:`7-0`
|
||||
- R\ :sub:`15-8`
|
||||
- G\ :sub:`7-0`
|
||||
- G\ :sub:`15-8`
|
||||
- B\ :sub:`7-0`
|
||||
- B\ :sub:`15-8`
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\normalsize
|
||||
|
||||
Deprecated RGB Formats
|
||||
======================
|
||||
|
||||
|
@ -0,0 +1,74 @@
|
||||
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
|
||||
|
||||
.. _v4l2-pix-fmt-pisp-comp1-rggb:
|
||||
.. _v4l2-pix-fmt-pisp-comp1-grbg:
|
||||
.. _v4l2-pix-fmt-pisp-comp1-gbrg:
|
||||
.. _v4l2-pix-fmt-pisp-comp1-bggr:
|
||||
.. _v4l2-pix-fmt-pisp-comp1-mono:
|
||||
.. _v4l2-pix-fmt-pisp-comp2-rggb:
|
||||
.. _v4l2-pix-fmt-pisp-comp2-grbg:
|
||||
.. _v4l2-pix-fmt-pisp-comp2-gbrg:
|
||||
.. _v4l2-pix-fmt-pisp-comp2-bggr:
|
||||
.. _v4l2-pix-fmt-pisp-comp2-mono:
|
||||
|
||||
**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||
V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M')
|
||||
**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||
|
||||
================================================
|
||||
Raspberry Pi PiSP compressed 8-bit Bayer formats
|
||||
================================================
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer
|
||||
formats. A black-level offset may be subtracted to improve compression
|
||||
efficiency; the nominal black level and amount of offset must be signalled out
|
||||
of band. Each scanline is padded to a multiple of 8 pixels wide, and each block
|
||||
of 8 horizontally-contiguous pixels is coded using 8 bytes.
|
||||
|
||||
Mode 1 uses a quantization and delta-based coding scheme which preserves up to
|
||||
12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL
|
||||
chords, preserving up to 12 significant bits. Mode 3 combines both companding
|
||||
(with 4 chords) and the delta scheme, preserving up to 14 significant bits.
|
||||
|
||||
The remainder of this description applies to Modes 1 and 3.
|
||||
|
||||
Each block of 8 pixels is separated into even and odd phases of 4 pixels,
|
||||
coded independently by 32-bit words at successive locations in memory.
|
||||
The two LS bits of each 32-bit word give its "quantization mode".
|
||||
|
||||
In quantization mode 0, the lowest 321 quantization levels are multiples of
|
||||
FSD/4096 and the remaining levels are successive multiples of FSD/2048.
|
||||
Quantization modes 1 and 2 use linear quantization with step sizes of
|
||||
FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized
|
||||
independently, with rounding to the nearest level.
|
||||
In quantization mode 2 where the middle two samples have quantized values
|
||||
(q1,q2) both in the range [384..511], they are coded using 9 bits for q1
|
||||
followed by 7 bits for (q2 & 127). Otherwise, for quantization modes
|
||||
0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range
|
||||
[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127].
|
||||
|
||||
Each of the outer samples (q0,q3) is encoded using a 7-bit field based
|
||||
on its inner neighbour q1 or q2. In quantization mode 2 where the inner
|
||||
sample has a quantized value in the range [448..511], the field value is
|
||||
(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample
|
||||
is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2.
|
||||
Each of these values must be in the range [0..127]. All these fields
|
||||
of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order
|
||||
to give a 32-bit word with LE byte order.
|
||||
|
||||
Quantization mode 3 has a "7.5-bit" escape, used when none of the above
|
||||
encodings will fit. Each pixel value is quantized to the nearest of 176
|
||||
levels, where the lowest 95 levels are multiples of FSD/256 and the
|
||||
remaining levels are multiples of FSD/128 (level 175 represents values
|
||||
very close to FSD and may require saturating arithmetic to decode).
|
||||
|
||||
Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded
|
||||
by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15).
|
||||
Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}.
|
||||
|
||||
An implementation of a software decoder of compressed formats is available
|
||||
in `Raspberry Pi camera applications code base
|
||||
<https://github.com/raspberrypi/rpicam-apps/blob/main/image/dng.cpp>`_.
|
@ -209,3 +209,7 @@ are often referred to as greyscale formats.
|
||||
For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with
|
||||
padding zeros in the 4 low bits, in contrast to the Y12 format, which has
|
||||
its padding located in the most significant bits of the 16 bit word.
|
||||
|
||||
The 'P' variations of the Y10, Y12 and Y14 formats are packed according to
|
||||
the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2
|
||||
specification.
|
||||
|
63
MAINTAINERS
63
MAINTAINERS
@ -9190,6 +9190,20 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml
|
||||
F: drivers/media/i2c/gc0308.c
|
||||
|
||||
GALAXYCORE GC05a2 CAMERA SENSOR DRIVER
|
||||
M: Zhi Mao <zhi.mao@mediatek.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml
|
||||
F: drivers/media/i2c/gc05a2.c
|
||||
|
||||
GALAXYCORE GC08A3 CAMERA SENSOR DRIVER
|
||||
M: Zhi Mao <zhi.mao@mediatek.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml
|
||||
F: drivers/media/i2c/gc08a3.c
|
||||
|
||||
GALAXYCORE GC2145 SENSOR DRIVER
|
||||
M: Alain Volmat <alain.volmat@foss.st.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -10872,6 +10886,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml
|
||||
F: drivers/auxdisplay/img-ascii-lcd.c
|
||||
|
||||
IMGTEC JPEG ENCODER DRIVER
|
||||
M: Devarsh Thakkar <devarsht@ti.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml
|
||||
F: drivers/media/platform/imagination/e5010*
|
||||
|
||||
IMGTEC IR DECODER DRIVER
|
||||
S: Orphan
|
||||
F: drivers/media/rc/img-ir/
|
||||
@ -13632,6 +13653,20 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml
|
||||
F: drivers/staging/media/max96712/max96712.c
|
||||
|
||||
MAX96714 GMSL2 DESERIALIZER DRIVER
|
||||
M: Julien Massot <julien.massot@collabora.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
|
||||
F: drivers/media/i2c/max96714.c
|
||||
|
||||
MAX96717 GMSL2 SERIALIZER DRIVER
|
||||
M: Julien Massot <julien.massot@collabora.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
|
||||
F: drivers/media/i2c/max96717.c
|
||||
|
||||
MAX9860 MONO AUDIO VOICE CODEC DRIVER
|
||||
M: Peter Rosin <peda@axentia.se>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
@ -18948,6 +18983,15 @@ L: linux-edac@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/ras/amd/fmpm.c
|
||||
|
||||
RASPBERRY PI PISP BACK END
|
||||
M: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
|
||||
L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
|
||||
F: drivers/media/platform/raspberrypi/pisp_be/
|
||||
F: include/uapi/linux/media/raspberrypi/
|
||||
|
||||
RC-CORE / LIRC FRAMEWORK
|
||||
M: Sean Young <sean@mess.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -20898,7 +20942,6 @@ F: include/uapi/rdma/rdma_user_rxe.h
|
||||
|
||||
SOFTLOGIC 6x10 MPEG CODEC
|
||||
M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
|
||||
M: Anton Sviridenko <anton@corp.bluecherry.net>
|
||||
M: Andrey Utkin <andrey_utkin@fastmail.com>
|
||||
M: Ismael Luceno <ismael@iodev.co.uk>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -20994,7 +21037,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/imx258.yaml
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
|
||||
F: drivers/media/i2c/imx258.c
|
||||
|
||||
SONY IMX274 SENSOR DRIVER
|
||||
@ -21005,6 +21048,15 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml
|
||||
F: drivers/media/i2c/imx274.c
|
||||
|
||||
SONY IMX283 SENSOR DRIVER
|
||||
M: Kieran Bingham <kieran.bingham@ideasonboard.com>
|
||||
M: Umang Jain <umang.jain@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
|
||||
F: drivers/media/i2c/imx283.c
|
||||
|
||||
SONY IMX290 SENSOR DRIVER
|
||||
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -21381,8 +21433,8 @@ L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml
|
||||
F: Documentation/userspace-api/media/drivers/st-vgxy61.rst
|
||||
F: drivers/media/i2c/st-vgxy61.c
|
||||
F: Documentation/userspace-api/media/drivers/vgxy61.rst
|
||||
F: drivers/media/i2c/vgxy61.c
|
||||
|
||||
ST VL53L0X ToF RANGER(I2C) IIO DRIVER
|
||||
M: Song Qiang <songqiang1304521@gmail.com>
|
||||
@ -23108,7 +23160,6 @@ F: tools/testing/selftests/turbostat/
|
||||
|
||||
TW5864 VIDEO4LINUX DRIVER
|
||||
M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
|
||||
M: Anton Sviridenko <anton@corp.bluecherry.net>
|
||||
M: Andrey Utkin <andrey.utkin@corp.bluecherry.net>
|
||||
M: Andrey Utkin <andrey_utkin@fastmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -23725,7 +23776,7 @@ F: drivers/media/i2c/mt*
|
||||
F: drivers/media/i2c/og*
|
||||
F: drivers/media/i2c/ov*
|
||||
F: drivers/media/i2c/s5*
|
||||
F: drivers/media/i2c/st-vgxy61.c
|
||||
F: drivers/media/i2c/vgxy61.c
|
||||
|
||||
VF610 NAND DRIVER
|
||||
M: Stefan Agner <stefan@agner.ch>
|
||||
|
@ -839,7 +839,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
|
||||
mtu_msg.x_msg_header.msg_flags = 0;
|
||||
mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
|
||||
mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg);
|
||||
mtu_msg.msg_data[0] = board->mtu;
|
||||
mtu_msg.msg_data = board->mtu;
|
||||
|
||||
coredev->sendrequest_handler(coredev->context, &mtu_msg,
|
||||
sizeof(mtu_msg));
|
||||
@ -852,7 +852,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
|
||||
SMS_INIT_MSG(&crys_msg.x_msg_header,
|
||||
MSG_SMS_NEW_CRYSTAL_REQ,
|
||||
sizeof(crys_msg));
|
||||
crys_msg.msg_data[0] = board->crystal;
|
||||
crys_msg.msg_data = board->crystal;
|
||||
|
||||
coredev->sendrequest_handler(coredev->context, &crys_msg,
|
||||
sizeof(crys_msg));
|
||||
@ -1306,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode)
|
||||
msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer);
|
||||
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
|
||||
sizeof(struct sms_msg_data));
|
||||
msg->msg_data[0] = mode;
|
||||
msg->msg_data = mode;
|
||||
|
||||
rc = smscore_sendrequest_and_wait(coredev, msg,
|
||||
msg->x_msg_header. msg_length,
|
||||
@ -1394,7 +1394,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
|
||||
|
||||
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
|
||||
sizeof(struct sms_msg_data));
|
||||
msg->msg_data[0] = mode;
|
||||
msg->msg_data = mode;
|
||||
|
||||
rc = smscore_sendrequest_and_wait(
|
||||
coredev, msg, msg->x_msg_header.msg_length,
|
||||
@ -1554,7 +1554,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
|
||||
struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
|
||||
|
||||
pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n",
|
||||
validity->msg_data[0]);
|
||||
validity->msg_data);
|
||||
complete(&coredev->data_validity_done);
|
||||
break;
|
||||
}
|
||||
|
@ -616,7 +616,7 @@ struct sms_msg_hdr {
|
||||
|
||||
struct sms_msg_data {
|
||||
struct sms_msg_hdr x_msg_header;
|
||||
u32 msg_data[1];
|
||||
u32 msg_data;
|
||||
};
|
||||
|
||||
struct sms_msg_data2 {
|
||||
@ -666,7 +666,7 @@ struct sms_firmware {
|
||||
u32 check_sum;
|
||||
u32 length;
|
||||
u32 start_address;
|
||||
u8 payload[1];
|
||||
u8 payload[];
|
||||
};
|
||||
|
||||
/* statistics information returned as response for
|
||||
@ -1042,20 +1042,6 @@ struct sms_srvm_signal_status {
|
||||
u32 request_id;
|
||||
};
|
||||
|
||||
struct sms_i2c_req {
|
||||
u32 device_address; /* I2c device address */
|
||||
u32 write_count; /* number of bytes to write */
|
||||
u32 read_count; /* number of bytes to read */
|
||||
u8 Data[1];
|
||||
};
|
||||
|
||||
struct sms_i2c_res {
|
||||
u32 status; /* non-zero value in case of failure */
|
||||
u32 read_count; /* number of bytes read */
|
||||
u8 Data[1];
|
||||
};
|
||||
|
||||
|
||||
struct smscore_config_gpio {
|
||||
#define SMS_GPIO_DIRECTION_INPUT 0
|
||||
#define SMS_GPIO_DIRECTION_OUTPUT 1
|
||||
|
@ -689,7 +689,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
|
||||
pid_msg.x_msg_header.msg_flags = 0;
|
||||
pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;
|
||||
pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
|
||||
pid_msg.msg_data[0] = feed->pid;
|
||||
pid_msg.msg_data = feed->pid;
|
||||
|
||||
return smsclient_sendrequest(client->smsclient,
|
||||
&pid_msg, sizeof(pid_msg));
|
||||
@ -711,7 +711,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
|
||||
pid_msg.x_msg_header.msg_flags = 0;
|
||||
pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;
|
||||
pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
|
||||
pid_msg.msg_data[0] = feed->pid;
|
||||
pid_msg.msg_data = feed->pid;
|
||||
|
||||
return smsclient_sendrequest(client->smsclient,
|
||||
&pid_msg, sizeof(pid_msg));
|
||||
|
@ -20,11 +20,12 @@ void smsendian_handle_tx_message(void *buffer)
|
||||
struct sms_msg_data *msg = buffer;
|
||||
int i;
|
||||
int msg_words;
|
||||
u32 *msg_data = &msg->msg_data;
|
||||
|
||||
switch (msg->x_msg_header.msg_type) {
|
||||
case MSG_SMS_DATA_DOWNLOAD_REQ:
|
||||
{
|
||||
msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0]));
|
||||
msg->msg_data = le32_to_cpu((__force __le32)(msg->msg_data));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -33,7 +34,7 @@ void smsendian_handle_tx_message(void *buffer)
|
||||
sizeof(struct sms_msg_hdr))/4;
|
||||
|
||||
for (i = 0; i < msg_words; i++)
|
||||
msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
|
||||
msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -66,11 +67,12 @@ void smsendian_handle_rx_message(void *buffer)
|
||||
|
||||
default:
|
||||
{
|
||||
u32 *msg_data = &msg->msg_data;
|
||||
msg_words = (msg->x_msg_header.msg_length -
|
||||
sizeof(struct sms_msg_hdr))/4;
|
||||
|
||||
for (i = 0; i < msg_words; i++)
|
||||
msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
|
||||
msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -180,4 +180,5 @@ const struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uvc_format_by_guid);
|
||||
|
||||
MODULE_DESCRIPTION("USB Video Class common code");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -199,7 +199,6 @@ module_param(debug, int, 0644);
|
||||
})
|
||||
|
||||
static void __vb2_queue_cancel(struct vb2_queue *q);
|
||||
static void __enqueue_in_driver(struct vb2_buffer *vb);
|
||||
|
||||
static const char *vb2_state_name(enum vb2_buffer_state s)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
|
||||
MODULE_DESCRIPTION("Videobuf2 helper library for simple DVB cards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "au8522_priv.h"
|
||||
|
||||
MODULE_AUTHOR("Devin Heitmueller");
|
||||
MODULE_DESCRIPTION("Auvitek AU8522 QAM/8VSB demodulator driver and video decoder");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int au8522_analog_debug;
|
||||
|
@ -32,11 +32,6 @@ MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (defau
|
||||
__func__, ##arg); \
|
||||
} while (0)
|
||||
|
||||
struct i2c_device {
|
||||
struct i2c_adapter *i2c_adap;
|
||||
u8 i2c_addr;
|
||||
};
|
||||
|
||||
struct dib7000p_state {
|
||||
struct dvb_frontend demod;
|
||||
struct dib7000p_config cfg;
|
||||
|
@ -976,13 +976,6 @@ static struct drx_aud_data drxj_default_aud_data_g = {
|
||||
/*-----------------------------------------------------------------------------
|
||||
STRUCTURES
|
||||
----------------------------------------------------------------------------*/
|
||||
struct drxjeq_stat {
|
||||
u16 eq_mse;
|
||||
u8 eq_mode;
|
||||
u8 eq_ctrl;
|
||||
u8 eq_stat;
|
||||
};
|
||||
|
||||
/* HI command */
|
||||
struct drxj_hi_cmd {
|
||||
u16 cmd;
|
||||
|
@ -1854,5 +1854,6 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mb86a16_attach);
|
||||
MODULE_DESCRIPTION("Fujitsu MB86A16 DVB-S/DSS DC Receiver driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Manu Abraham");
|
||||
|
@ -168,7 +168,7 @@ struct MBIN_FILE_HEADER_T {
|
||||
|
||||
struct MBIN_FILE_T {
|
||||
struct MBIN_FILE_HEADER_T header;
|
||||
u8 data[1];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
struct MBIN_SEGMENT_HEADER_T {
|
||||
@ -179,7 +179,7 @@ struct MBIN_SEGMENT_HEADER_T {
|
||||
|
||||
struct MBIN_SEGMENT_T {
|
||||
struct MBIN_SEGMENT_HEADER_T header;
|
||||
u8 data[1];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ };
|
||||
|
@ -748,6 +748,22 @@ static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 d
|
||||
return stv090x_write_regs(state, reg, &tmp, 1);
|
||||
}
|
||||
|
||||
static inline void stv090x_tuner_i2c_lock(struct stv090x_state *state)
|
||||
{
|
||||
if (state->config->tuner_i2c_lock)
|
||||
state->config->tuner_i2c_lock(&state->frontend, 1);
|
||||
else
|
||||
mutex_lock(&state->internal->tuner_lock);
|
||||
}
|
||||
|
||||
static inline void stv090x_tuner_i2c_unlock(struct stv090x_state *state)
|
||||
{
|
||||
if (state->config->tuner_i2c_lock)
|
||||
state->config->tuner_i2c_lock(&state->frontend, 0);
|
||||
else
|
||||
mutex_unlock(&state->internal->tuner_lock);
|
||||
}
|
||||
|
||||
static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
|
||||
{
|
||||
u32 reg;
|
||||
@ -761,12 +777,8 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
|
||||
* In case of any error, the lock is unlocked and exit within the
|
||||
* relevant operations themselves.
|
||||
*/
|
||||
if (enable) {
|
||||
if (state->config->tuner_i2c_lock)
|
||||
state->config->tuner_i2c_lock(&state->frontend, 1);
|
||||
else
|
||||
mutex_lock(&state->internal->tuner_lock);
|
||||
}
|
||||
if (enable)
|
||||
stv090x_tuner_i2c_lock(state);
|
||||
|
||||
reg = STV090x_READ_DEMOD(state, I2CRPT);
|
||||
if (enable) {
|
||||
@ -782,20 +794,13 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!enable) {
|
||||
if (state->config->tuner_i2c_lock)
|
||||
state->config->tuner_i2c_lock(&state->frontend, 0);
|
||||
else
|
||||
mutex_unlock(&state->internal->tuner_lock);
|
||||
}
|
||||
if (!enable)
|
||||
stv090x_tuner_i2c_unlock(state);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dprintk(FE_ERROR, 1, "I/O error");
|
||||
if (state->config->tuner_i2c_lock)
|
||||
state->config->tuner_i2c_lock(&state->frontend, 0);
|
||||
else
|
||||
mutex_unlock(&state->internal->tuner_lock);
|
||||
stv090x_tuner_i2c_unlock(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -119,11 +119,6 @@ struct stv {
|
||||
u8 vth[6];
|
||||
};
|
||||
|
||||
struct sinit_table {
|
||||
u16 address;
|
||||
u8 data;
|
||||
};
|
||||
|
||||
struct slookup {
|
||||
s16 value;
|
||||
u32 reg_value;
|
||||
|
@ -70,6 +70,26 @@ config VIDEO_GC0308
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gc0308.
|
||||
|
||||
config VIDEO_GC05A2
|
||||
tristate "GalaxyCore gc05a2 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the GalaxyCore gc05a2
|
||||
camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gc05a2.
|
||||
|
||||
config VIDEO_GC08A3
|
||||
tristate "GalaxyCore gc08a3 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the GalaxyCore gc08a3
|
||||
camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gc08a3.
|
||||
|
||||
config VIDEO_GC2145
|
||||
select V4L2_CCI_I2C
|
||||
tristate "GalaxyCore GC2145 sensor support"
|
||||
@ -139,6 +159,7 @@ config VIDEO_IMX219
|
||||
|
||||
config VIDEO_IMX258
|
||||
tristate "Sony IMX258 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX258 camera.
|
||||
@ -153,6 +174,16 @@ config VIDEO_IMX274
|
||||
This is a V4L2 sensor driver for the Sony IMX274
|
||||
CMOS image sensor.
|
||||
|
||||
config VIDEO_IMX283
|
||||
tristate "Sony IMX283 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a V4L2 sensor driver for the Sony IMX283
|
||||
CMOS image sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx283.
|
||||
|
||||
config VIDEO_IMX290
|
||||
tristate "Sony IMX290 sensor support"
|
||||
select REGMAP_I2C
|
||||
@ -659,7 +690,7 @@ config VIDEO_S5K6A3
|
||||
This is a V4L2 sensor driver for Samsung S5K6A3 raw
|
||||
camera sensor.
|
||||
|
||||
config VIDEO_ST_VGXY61
|
||||
config VIDEO_VGXY61
|
||||
tristate "ST VGXY61 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
depends on OF && GPIOLIB
|
||||
@ -679,6 +710,7 @@ config VIDEO_THP7312
|
||||
tristate "THine THP7312 support"
|
||||
depends on I2C
|
||||
select FW_LOADER
|
||||
select FW_UPLOAD
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_CCI_I2C
|
||||
select V4L2_FWNODE
|
||||
@ -1575,6 +1607,40 @@ config VIDEO_DS90UB960
|
||||
Device driver for the Texas Instruments DS90UB960
|
||||
FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer.
|
||||
|
||||
config VIDEO_MAX96714
|
||||
tristate "Maxim MAX96714 GMSL2 deserializer"
|
||||
depends on OF && I2C && VIDEO_DEV
|
||||
select I2C_MUX
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
select V4L2_CCI_I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
Device driver for the Maxim MAX96714 GMSL2 Deserializer.
|
||||
MAX96714 deserializers convert a GMSL2 input to MIPI CSI-2
|
||||
output.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max96714.
|
||||
|
||||
config VIDEO_MAX96717
|
||||
tristate "Maxim MAX96717 GMSL2 Serializer support"
|
||||
depends on OF && I2C && VIDEO_DEV && COMMON_CLK
|
||||
select I2C_MUX
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
select V4L2_CCI_I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
Device driver for the Maxim MAX96717 GMSL2 Serializer.
|
||||
MAX96717 serializers convert video on a MIPI CSI-2
|
||||
input to a GMSL2 output.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max96717.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # VIDEO_DEV
|
||||
|
@ -38,6 +38,8 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
|
||||
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
|
||||
obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
|
||||
obj-$(CONFIG_VIDEO_GC0308) += gc0308.o
|
||||
obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o
|
||||
obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o
|
||||
obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
|
||||
obj-$(CONFIG_VIDEO_HI556) += hi556.o
|
||||
obj-$(CONFIG_VIDEO_HI846) += hi846.o
|
||||
@ -48,6 +50,7 @@ obj-$(CONFIG_VIDEO_IMX214) += imx214.o
|
||||
obj-$(CONFIG_VIDEO_IMX219) += imx219.o
|
||||
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
|
||||
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
|
||||
obj-$(CONFIG_VIDEO_IMX283) += imx283.o
|
||||
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
|
||||
obj-$(CONFIG_VIDEO_IMX296) += imx296.o
|
||||
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
|
||||
@ -64,6 +67,8 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
|
||||
obj-$(CONFIG_VIDEO_M52790) += m52790.o
|
||||
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
|
||||
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
|
||||
obj-$(CONFIG_VIDEO_MAX96714) += max96714.o
|
||||
obj-$(CONFIG_VIDEO_MAX96717) += max96717.o
|
||||
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
|
||||
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
|
||||
obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
|
||||
@ -124,7 +129,6 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
|
||||
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
|
||||
obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
|
||||
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
|
||||
obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o
|
||||
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
|
||||
obj-$(CONFIG_VIDEO_TC358746) += tc358746.o
|
||||
obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o
|
||||
@ -148,6 +152,7 @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o
|
||||
obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o
|
||||
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
|
||||
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
|
||||
obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o
|
||||
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
|
||||
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
|
||||
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
|
||||
|
@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe,
|
||||
{
|
||||
memset(fmt, 0, sizeof(*fmt));
|
||||
|
||||
fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
|
||||
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
fmt->field = V4L2_FIELD_ALTERNATE;
|
||||
|
||||
@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
if (code->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
code->code = MEDIA_BUS_FMT_UYVY8_2X8;
|
||||
code->code = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
@ -14,6 +13,15 @@
|
||||
|
||||
#include "adv748x.h"
|
||||
|
||||
static const unsigned int adv748x_csi2_txa_fmts[] = {
|
||||
MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
MEDIA_BUS_FMT_RGB888_1X24,
|
||||
};
|
||||
|
||||
static const unsigned int adv748x_csi2_txb_fmts[] = {
|
||||
MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
};
|
||||
|
||||
int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
|
||||
{
|
||||
return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
|
||||
@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* v4l2_subdev_internal_ops
|
||||
*
|
||||
*/
|
||||
|
||||
static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = {
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.code = MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
|
||||
.quantization = V4L2_QUANTIZATION_DEFAULT,
|
||||
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
|
||||
};
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK);
|
||||
*fmt = adv748x_csi2_default_fmt;
|
||||
|
||||
fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE);
|
||||
*fmt = adv748x_csi2_default_fmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the internal registered operation to be able to ensure that our
|
||||
* incremental subdevices (not connected in the forward path) can be registered
|
||||
* against the resulting video path and media device.
|
||||
@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
|
||||
.init_state = adv748x_csi2_init_state,
|
||||
.registered = adv748x_csi2_registered,
|
||||
};
|
||||
|
||||
@ -139,78 +174,82 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
|
||||
* But we must support setting the pad formats for format propagation.
|
||||
*/
|
||||
|
||||
static struct v4l2_mbus_framefmt *
|
||||
adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
unsigned int pad, u32 which)
|
||||
static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
|
||||
const unsigned int *codes = is_txa(tx) ?
|
||||
adv748x_csi2_txa_fmts :
|
||||
adv748x_csi2_txb_fmts;
|
||||
size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
|
||||
: ARRAY_SIZE(adv748x_csi2_txb_fmts);
|
||||
|
||||
if (which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
return v4l2_subdev_state_get_format(sd_state, pad);
|
||||
/*
|
||||
* The format available on the source pad is the one applied on the sink
|
||||
* pad.
|
||||
*/
|
||||
if (code->pad == ADV748X_CSI2_SOURCE) {
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
return &tx->format;
|
||||
}
|
||||
if (code->index)
|
||||
return -EINVAL;
|
||||
|
||||
static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *sdformat)
|
||||
{
|
||||
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
|
||||
struct adv748x_state *state = tx->state;
|
||||
struct v4l2_mbus_framefmt *mbusformat;
|
||||
fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK);
|
||||
code->code = fmt->code;
|
||||
|
||||
mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
|
||||
sdformat->which);
|
||||
if (!mbusformat)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (code->index >= num_fmts)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
sdformat->format = *mbusformat;
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
code->code = codes[code->index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code)
|
||||
{
|
||||
const unsigned int *codes = is_txa(tx) ?
|
||||
adv748x_csi2_txa_fmts :
|
||||
adv748x_csi2_txb_fmts;
|
||||
size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
|
||||
: ARRAY_SIZE(adv748x_csi2_txb_fmts);
|
||||
|
||||
for (unsigned int i = 0; i < num_fmts; i++) {
|
||||
if (codes[i] == code)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *sdformat)
|
||||
{
|
||||
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
|
||||
struct adv748x_state *state = tx->state;
|
||||
struct v4l2_mbus_framefmt *mbusformat;
|
||||
int ret = 0;
|
||||
|
||||
mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
|
||||
sdformat->which);
|
||||
if (!mbusformat)
|
||||
return -EINVAL;
|
||||
if (sdformat->pad == ADV748X_CSI2_SOURCE)
|
||||
return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
if (sdformat->pad == ADV748X_CSI2_SOURCE) {
|
||||
const struct v4l2_mbus_framefmt *sink_fmt;
|
||||
|
||||
sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
|
||||
ADV748X_CSI2_SINK,
|
||||
sdformat->which);
|
||||
|
||||
if (!sink_fmt) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
sdformat->format = *sink_fmt;
|
||||
}
|
||||
/*
|
||||
* Make sure the format is supported, if not default it to
|
||||
* UYVY8 as it's supported by both TXes.
|
||||
*/
|
||||
if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code))
|
||||
sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
|
||||
mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
|
||||
*mbusformat = sdformat->format;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&state->mutex);
|
||||
/* Propagate format to the source pad. */
|
||||
mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE);
|
||||
*mbusformat = sdformat->format;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
|
||||
@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
|
||||
.get_fmt = adv748x_csi2_get_format,
|
||||
.enum_mbus_code = adv748x_csi2_enum_mbus_code,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = adv748x_csi2_set_format,
|
||||
.get_mbus_config = adv748x_csi2_get_mbus_config,
|
||||
};
|
||||
@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
|
||||
if (ret)
|
||||
goto err_cleanup_subdev;
|
||||
|
||||
tx->sd.state_lock = &state->mutex;
|
||||
ret = v4l2_subdev_init_finalize(&tx->sd);
|
||||
if (ret)
|
||||
goto err_free_ctrl;
|
||||
|
||||
ret = v4l2_async_register_subdev(&tx->sd);
|
||||
if (ret)
|
||||
goto err_free_ctrl;
|
||||
|
@ -75,7 +75,6 @@ enum adv748x_csi2_pads {
|
||||
|
||||
struct adv748x_csi2 {
|
||||
struct adv748x_state *state;
|
||||
struct v4l2_mbus_framefmt format;
|
||||
unsigned int page;
|
||||
unsigned int port;
|
||||
unsigned int num_lanes;
|
||||
|
@ -62,11 +62,6 @@ MODULE_LICENSE("GPL v2");
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
struct i2c_reg_value {
|
||||
unsigned char reg;
|
||||
unsigned char value;
|
||||
};
|
||||
|
||||
struct adv7511_state_edid {
|
||||
/* total number of blocks */
|
||||
u32 blocks;
|
||||
|
@ -403,21 +403,22 @@ static int alvium_get_bcrm_vers(struct alvium_dev *alvium)
|
||||
static int alvium_get_fw_version(struct alvium_dev *alvium)
|
||||
{
|
||||
struct device *dev = &alvium->i2c_client->dev;
|
||||
u64 spec, maj, min, pat;
|
||||
int ret = 0;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_SPEC_VERSION_R,
|
||||
&spec, &ret);
|
||||
ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MAJOR_VERSION_R,
|
||||
&maj, &ret);
|
||||
ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MINOR_VERSION_R,
|
||||
&min, &ret);
|
||||
ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_PATCH_VERSION_R,
|
||||
&pat, &ret);
|
||||
ret = alvium_read(alvium, REG_BCRM_DEVICE_FW, &val, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(dev, "fw version: %llu.%llu.%llu.%llu\n", spec, maj, min, pat);
|
||||
dev_info(dev, "fw version: %02u.%02u.%04u.%08x\n",
|
||||
(u8)((val & BCRM_DEVICE_FW_SPEC_MASK) >>
|
||||
BCRM_DEVICE_FW_SPEC_SHIFT),
|
||||
(u8)((val & BCRM_DEVICE_FW_MAJOR_MASK) >>
|
||||
BCRM_DEVICE_FW_MAJOR_SHIFT),
|
||||
(u16)((val & BCRM_DEVICE_FW_MINOR_MASK) >>
|
||||
BCRM_DEVICE_FW_MINOR_SHIFT),
|
||||
(u32)((val & BCRM_DEVICE_FW_PATCH_MASK) >>
|
||||
BCRM_DEVICE_FW_PATCH_SHIFT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1188,6 +1189,20 @@ static int alvium_set_frame_rate(struct alvium_dev *alvium, u64 fr)
|
||||
struct device *dev = &alvium->i2c_client->dev;
|
||||
int ret;
|
||||
|
||||
ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW,
|
||||
1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Fail to set acquisition frame rate enable reg\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = alvium_write_hshake(alvium, REG_BCRM_FRAME_START_TRIGGER_MODE_RW,
|
||||
0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Fail to set frame start trigger mode reg\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW,
|
||||
fr);
|
||||
if (ret) {
|
||||
@ -1707,6 +1722,27 @@ alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code)
|
||||
return &alvium->alvium_csi2_fmt[0];
|
||||
}
|
||||
|
||||
static int alvium_enum_frame_size(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct alvium_dev *alvium = sd_to_alvium(sd);
|
||||
const struct alvium_pixfmt *alvium_csi2_fmt;
|
||||
|
||||
if (fse->index)
|
||||
return -EINVAL;
|
||||
|
||||
alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, fse->code);
|
||||
if (fse->code != alvium_csi2_fmt->code)
|
||||
return -EINVAL;
|
||||
|
||||
fse->min_width = alvium->img_min_width;
|
||||
fse->max_width = alvium->img_max_width;
|
||||
fse->min_height = alvium->img_min_height;
|
||||
fse->max_height = alvium->img_max_height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alvium_set_mode(struct alvium_dev *alvium,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
@ -1962,7 +1998,7 @@ static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
||||
int val;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_GAIN:
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
val = alvium_get_gain(alvium);
|
||||
if (val < 0)
|
||||
return val;
|
||||
@ -1994,7 +2030,7 @@ static int alvium_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
return 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_GAIN:
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
ret = alvium_set_ctrl_gain(alvium, ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
@ -2123,7 +2159,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium)
|
||||
|
||||
if (alvium->avail_ft.gain) {
|
||||
ctrls->gain = v4l2_ctrl_new_std(hdl, ops,
|
||||
V4L2_CID_GAIN,
|
||||
V4L2_CID_ANALOGUE_GAIN,
|
||||
alvium->min_gain,
|
||||
alvium->max_gain,
|
||||
alvium->inc_gain,
|
||||
@ -2214,6 +2250,7 @@ static const struct v4l2_subdev_video_ops alvium_video_ops = {
|
||||
|
||||
static const struct v4l2_subdev_pad_ops alvium_pad_ops = {
|
||||
.enum_mbus_code = alvium_enum_mbus_code,
|
||||
.enum_frame_size = alvium_enum_frame_size,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = alvium_set_fmt,
|
||||
.get_selection = alvium_get_selection,
|
||||
|
@ -31,10 +31,7 @@
|
||||
#define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014)
|
||||
|
||||
#define REG_BCRM_FEATURE_INQUIRY_R REG_BCRM_V4L2_64BIT(0x0008)
|
||||
#define REG_BCRM_DEVICE_FW_SPEC_VERSION_R REG_BCRM_V4L2_8BIT(0x0010)
|
||||
#define REG_BCRM_DEVICE_FW_MAJOR_VERSION_R REG_BCRM_V4L2_8BIT(0x0011)
|
||||
#define REG_BCRM_DEVICE_FW_MINOR_VERSION_R REG_BCRM_V4L2_16BIT(0x0012)
|
||||
#define REG_BCRM_DEVICE_FW_PATCH_VERSION_R REG_BCRM_V4L2_32BIT(0x0014)
|
||||
#define REG_BCRM_DEVICE_FW REG_BCRM_V4L2_64BIT(0x0010)
|
||||
#define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018)
|
||||
|
||||
/* Streaming Control Registers */
|
||||
@ -66,7 +63,7 @@
|
||||
#define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098)
|
||||
#define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0)
|
||||
#define REG_BCRM_ACQUISITION_FRAME_RATE_INC_R REG_BCRM_V4L2_64BIT(0x00a8)
|
||||
#define REG_BCRM_ACQUISITION_FRAME_RATE_ENABLE_RW REG_BCRM_V4L2_8BIT(0x00b0)
|
||||
#define REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW REG_BCRM_V4L2_8BIT(0x00b0)
|
||||
|
||||
#define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4)
|
||||
#define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8)
|
||||
@ -205,6 +202,15 @@
|
||||
|
||||
#define ALVIUM_LP2HS_DELAY_MS 100
|
||||
|
||||
#define BCRM_DEVICE_FW_MAJOR_MASK GENMASK_ULL(15, 8)
|
||||
#define BCRM_DEVICE_FW_MAJOR_SHIFT 8
|
||||
#define BCRM_DEVICE_FW_MINOR_MASK GENMASK_ULL(31, 16)
|
||||
#define BCRM_DEVICE_FW_MINOR_SHIFT 16
|
||||
#define BCRM_DEVICE_FW_PATCH_MASK GENMASK_ULL(63, 32)
|
||||
#define BCRM_DEVICE_FW_PATCH_SHIFT 32
|
||||
#define BCRM_DEVICE_FW_SPEC_MASK GENMASK_ULL(7, 0)
|
||||
#define BCRM_DEVICE_FW_SPEC_SHIFT 0
|
||||
|
||||
enum alvium_bcrm_mode {
|
||||
ALVIUM_BCM_MODE,
|
||||
ALVIUM_GENCP_MODE,
|
||||
|
@ -115,11 +115,6 @@ static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
|
||||
return container_of(subdev, struct dw9768, sd);
|
||||
}
|
||||
|
||||
struct regval_list {
|
||||
u8 reg_num;
|
||||
u8 value;
|
||||
};
|
||||
|
||||
struct dw9768_aac_mode_ot_multi {
|
||||
u32 aac_mode_enum;
|
||||
u32 ot_multi_base100;
|
||||
|
1359
drivers/media/i2c/gc05a2.c
Normal file
1359
drivers/media/i2c/gc05a2.c
Normal file
File diff suppressed because it is too large
Load Diff
1339
drivers/media/i2c/gc08a3.c
Normal file
1339
drivers/media/i2c/gc08a3.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -68,8 +68,7 @@
|
||||
#define GC2145_DPHY_CLK_DELAY BIT(4)
|
||||
#define GC2145_DPHY_LANE0_DELAY BIT(5)
|
||||
#define GC2145_DPHY_LANE1_DELAY BIT(6)
|
||||
#define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04)
|
||||
#define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05)
|
||||
#define GC2145_REG_FIFO_FULL_LVL CCI_REG16_LE(0x04)
|
||||
#define GC2145_REG_FIFO_MODE CCI_REG8(0x06)
|
||||
#define GC2145_FIFO_MODE_READ_GATE BIT(3)
|
||||
#define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7)
|
||||
@ -79,8 +78,7 @@
|
||||
#define GC2145_CSI2_MODE_MIPI_EN BIT(4)
|
||||
#define GC2145_CSI2_MODE_EN BIT(7)
|
||||
#define GC2145_REG_MIPI_DT CCI_REG8(0x11)
|
||||
#define GC2145_REG_LWC_LOW CCI_REG8(0x12)
|
||||
#define GC2145_REG_LWC_HIGH CCI_REG8(0x13)
|
||||
#define GC2145_REG_LWC CCI_REG16_LE(0x12)
|
||||
#define GC2145_REG_DPHY_MODE CCI_REG8(0x15)
|
||||
#define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4)
|
||||
#define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17)
|
||||
@ -542,45 +540,82 @@ static const struct gc2145_mode supported_modes[] = {
|
||||
/**
|
||||
* struct gc2145_format - GC2145 pixel format description
|
||||
* @code: media bus (MBUS) associated code
|
||||
* @colorspace: V4L2 colorspace
|
||||
* @datatype: MIPI CSI2 data type
|
||||
* @output_fmt: GC2145 output format
|
||||
* @switch_bit: GC2145 first/second switch
|
||||
* @row_col_switch: GC2145 switch row and/or column
|
||||
*/
|
||||
struct gc2145_format {
|
||||
unsigned int code;
|
||||
unsigned int colorspace;
|
||||
unsigned char datatype;
|
||||
unsigned char output_fmt;
|
||||
bool switch_bit;
|
||||
unsigned char row_col_switch;
|
||||
};
|
||||
|
||||
/* All supported formats */
|
||||
static const struct gc2145_format supported_formats[] = {
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.datatype = MIPI_CSI2_DT_YUV422_8B,
|
||||
.output_fmt = 0x00,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_VYUY8_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.datatype = MIPI_CSI2_DT_YUV422_8B,
|
||||
.output_fmt = 0x01,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_YUYV8_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.datatype = MIPI_CSI2_DT_YUV422_8B,
|
||||
.output_fmt = 0x02,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_YVYU8_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.datatype = MIPI_CSI2_DT_YUV422_8B,
|
||||
.output_fmt = 0x03,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_RGB565_1X16,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.datatype = MIPI_CSI2_DT_RGB565,
|
||||
.output_fmt = 0x06,
|
||||
.switch_bit = true,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
|
||||
.colorspace = V4L2_COLORSPACE_RAW,
|
||||
.datatype = MIPI_CSI2_DT_RAW8,
|
||||
.output_fmt = 0x17,
|
||||
.row_col_switch = GC2145_SYNC_MODE_COL_SWITCH,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
|
||||
.colorspace = V4L2_COLORSPACE_RAW,
|
||||
.datatype = MIPI_CSI2_DT_RAW8,
|
||||
.output_fmt = 0x17,
|
||||
.row_col_switch = GC2145_SYNC_MODE_COL_SWITCH | GC2145_SYNC_MODE_ROW_SWITCH,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
|
||||
.colorspace = V4L2_COLORSPACE_RAW,
|
||||
.datatype = MIPI_CSI2_DT_RAW8,
|
||||
.output_fmt = 0x17,
|
||||
.row_col_switch = 0,
|
||||
},
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
|
||||
.colorspace = V4L2_COLORSPACE_RAW,
|
||||
.datatype = MIPI_CSI2_DT_RAW8,
|
||||
.output_fmt = 0x17,
|
||||
.row_col_switch = GC2145_SYNC_MODE_ROW_SWITCH,
|
||||
},
|
||||
};
|
||||
|
||||
struct gc2145_ctrls {
|
||||
@ -641,7 +676,8 @@ gc2145_get_format_code(struct gc2145 *gc2145, u32 code)
|
||||
|
||||
static void gc2145_update_pad_format(struct gc2145 *gc2145,
|
||||
const struct gc2145_mode *mode,
|
||||
struct v4l2_mbus_framefmt *fmt, u32 code)
|
||||
struct v4l2_mbus_framefmt *fmt, u32 code,
|
||||
u32 colorspace)
|
||||
{
|
||||
fmt->code = code;
|
||||
fmt->width = mode->width;
|
||||
@ -663,7 +699,8 @@ static int gc2145_init_state(struct v4l2_subdev *sd,
|
||||
/* Initialize pad format */
|
||||
format = v4l2_subdev_state_get_format(state, 0);
|
||||
gc2145_update_pad_format(gc2145, &supported_modes[0], format,
|
||||
MEDIA_BUS_FMT_RGB565_1X16);
|
||||
MEDIA_BUS_FMT_RGB565_1X16,
|
||||
V4L2_COLORSPACE_SRGB);
|
||||
|
||||
/* Initialize crop rectangle. */
|
||||
crop = v4l2_subdev_state_get_crop(state, 0);
|
||||
@ -754,7 +791,13 @@ static int gc2145_set_pad_format(struct v4l2_subdev *sd,
|
||||
width, height,
|
||||
fmt->format.width, fmt->format.height);
|
||||
|
||||
gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code);
|
||||
/* In RAW mode, VGA is not possible so use 720p instead */
|
||||
if (gc2145_fmt->colorspace == V4L2_COLORSPACE_RAW &&
|
||||
mode == &supported_modes[GC2145_MODE_640X480])
|
||||
mode = &supported_modes[GC2145_MODE_1280X720];
|
||||
|
||||
gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code,
|
||||
gc2145_fmt->colorspace);
|
||||
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||
gc2145->mode = mode;
|
||||
@ -811,9 +854,12 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
|
||||
* For RAW8, LWC = image width
|
||||
* For RAW10, LWC = image width * 1.25
|
||||
*/
|
||||
lwc = gc2145->mode->width * 2;
|
||||
cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret);
|
||||
cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret);
|
||||
if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW)
|
||||
lwc = gc2145->mode->width * 2;
|
||||
else
|
||||
lwc = gc2145->mode->width;
|
||||
|
||||
cci_write(gc2145->regmap, GC2145_REG_LWC, lwc, &ret);
|
||||
|
||||
/*
|
||||
* Adjust the MIPI FIFO Full Level
|
||||
@ -821,21 +867,25 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
|
||||
* 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001
|
||||
* 1600x1200 RAW: 0x0190
|
||||
*/
|
||||
if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
|
||||
fifo_full_lvl = 0x0001;
|
||||
else
|
||||
if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) {
|
||||
if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
|
||||
fifo_full_lvl = 0x0001;
|
||||
else
|
||||
fifo_full_lvl = 0x0190;
|
||||
} else {
|
||||
fifo_full_lvl = 0x0190;
|
||||
}
|
||||
|
||||
cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH,
|
||||
fifo_full_lvl >> 8, &ret);
|
||||
cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW,
|
||||
fifo_full_lvl & 0xff, &ret);
|
||||
cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL,
|
||||
fifo_full_lvl, &ret);
|
||||
|
||||
/*
|
||||
* Set the FIFO gate mode / MIPI wdiv set:
|
||||
* 0xf1 in case of RAW mode and 0xf0 otherwise
|
||||
*/
|
||||
cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret);
|
||||
cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE,
|
||||
gc2145_format->colorspace == V4L2_COLORSPACE_RAW ?
|
||||
0xf1 : 0xf0, &ret);
|
||||
|
||||
/* Set the MIPI data type */
|
||||
cci_write(gc2145->regmap, GC2145_REG_MIPI_DT,
|
||||
@ -883,6 +933,10 @@ static int gc2145_start_streaming(struct gc2145 *gc2145,
|
||||
GC2145_BYPASS_MODE_SWITCH,
|
||||
gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH
|
||||
: 0, &ret);
|
||||
cci_update_bits(gc2145->regmap, GC2145_REG_SYNC_MODE,
|
||||
GC2145_SYNC_MODE_COL_SWITCH |
|
||||
GC2145_SYNC_MODE_ROW_SWITCH,
|
||||
gc2145_format->row_col_switch, &ret);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed to write regs\n", __func__);
|
||||
goto err_rpm_put;
|
||||
|
@ -1851,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd,
|
||||
mutex_lock(&hi846->mutex);
|
||||
switch (sel->which) {
|
||||
case V4L2_SUBDEV_FORMAT_TRY:
|
||||
v4l2_subdev_state_get_crop(sd_state, sel->pad);
|
||||
sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
|
||||
break;
|
||||
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||
sel->r = hi846->cur_mode->crop;
|
||||
|
@ -162,8 +162,8 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
|
||||
{ IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */
|
||||
|
||||
/* To Access Addresses 3000-5fff, send the following commands */
|
||||
{ CCI_REG8(0x30eb), 0x0c },
|
||||
{ CCI_REG8(0x30eb), 0x05 },
|
||||
{ CCI_REG8(0x30eb), 0x0c },
|
||||
{ CCI_REG8(0x300a), 0xff },
|
||||
{ CCI_REG8(0x300b), 0xff },
|
||||
{ CCI_REG8(0x30eb), 0x05 },
|
||||
|
File diff suppressed because it is too large
Load Diff
1612
drivers/media/i2c/imx283.c
Normal file
1612
drivers/media/i2c/imx283.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -542,14 +542,13 @@ static int imx412_update_controls(struct imx412 *imx412,
|
||||
*/
|
||||
static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
|
||||
{
|
||||
u32 lpfr, shutter;
|
||||
u32 lpfr;
|
||||
int ret;
|
||||
|
||||
lpfr = imx412->vblank + imx412->cur_mode->height;
|
||||
shutter = lpfr - exposure;
|
||||
|
||||
dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u",
|
||||
exposure, gain, shutter, lpfr);
|
||||
dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u",
|
||||
exposure, gain, lpfr);
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1);
|
||||
if (ret)
|
||||
@ -559,7 +558,7 @@ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
|
||||
if (ret)
|
||||
goto error_release_group_hold;
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter);
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure);
|
||||
if (ret)
|
||||
goto error_release_group_hold;
|
||||
|
||||
|
@ -175,14 +175,6 @@ MODULE_LICENSE("GPL");
|
||||
* mga_dev : represents one ks0127 chip.
|
||||
****************************************************************************/
|
||||
|
||||
struct adjust {
|
||||
int contrast;
|
||||
int bright;
|
||||
int hue;
|
||||
int ugain;
|
||||
int vgain;
|
||||
};
|
||||
|
||||
struct ks0127 {
|
||||
struct v4l2_subdev sd;
|
||||
v4l2_std_id norm;
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
@ -198,12 +197,6 @@ struct max9286_priv {
|
||||
struct v4l2_ctrl *pixelrate_ctrl;
|
||||
unsigned int pixelrate;
|
||||
|
||||
struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
|
||||
struct v4l2_fract interval;
|
||||
|
||||
/* Protects controls and fmt structures */
|
||||
struct mutex mutex;
|
||||
|
||||
unsigned int nsources;
|
||||
unsigned int source_mask;
|
||||
unsigned int route_mask;
|
||||
@ -576,11 +569,14 @@ static void max9286_set_video_format(struct max9286_priv *priv,
|
||||
MAX9286_INVVS | MAX9286_HVSRC_D14);
|
||||
}
|
||||
|
||||
static void max9286_set_fsync_period(struct max9286_priv *priv)
|
||||
static void max9286_set_fsync_period(struct max9286_priv *priv,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
const struct v4l2_fract *interval;
|
||||
u32 fsync;
|
||||
|
||||
if (!priv->interval.numerator || !priv->interval.denominator) {
|
||||
interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
|
||||
if (!interval->numerator || !interval->denominator) {
|
||||
/*
|
||||
* Special case, a null interval enables automatic FRAMESYNC
|
||||
* mode. FRAMESYNC is taken from the slowest link.
|
||||
@ -596,8 +592,8 @@ static void max9286_set_fsync_period(struct max9286_priv *priv)
|
||||
* The FRAMESYNC generator is configured with a period expressed as a
|
||||
* number of PCLK periods.
|
||||
*/
|
||||
fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
|
||||
priv->interval.denominator);
|
||||
fsync = div_u64((u64)priv->pixelrate * interval->numerator,
|
||||
interval->denominator);
|
||||
|
||||
dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
|
||||
priv->pixelrate);
|
||||
@ -788,22 +784,25 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv)
|
||||
static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
struct v4l2_subdev_state *state;
|
||||
struct max9286_source *source;
|
||||
unsigned int i;
|
||||
bool sync = false;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
|
||||
if (enable) {
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/*
|
||||
* Get the format from the first used sink pad, as all sink
|
||||
* formats must be identical.
|
||||
* Get the format from the source pad, as all formats must be
|
||||
* identical.
|
||||
*/
|
||||
format = &priv->fmt[__ffs(priv->bound_sources)];
|
||||
format = v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD);
|
||||
|
||||
max9286_set_video_format(priv, format);
|
||||
max9286_set_fsync_period(priv);
|
||||
max9286_set_fsync_period(priv, state);
|
||||
|
||||
/*
|
||||
* The frame sync between cameras is transmitted across the
|
||||
@ -816,12 +815,12 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
for_each_source(priv, source) {
|
||||
ret = v4l2_subdev_call(source->sd, video, s_stream, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = max9286_check_video_links(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* Wait until frame synchronization is locked.
|
||||
@ -842,7 +841,8 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
if (!sync) {
|
||||
dev_err(&priv->client->dev,
|
||||
"Failed to get frame synchronization\n");
|
||||
return -EXDEV; /* Invalid cross-device link */
|
||||
ret = -EXDEV; /* Invalid cross-device link */
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -865,26 +865,21 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
max9286_i2c_mux_close(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
v4l2_subdev_unlock_state(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max9286_get_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_frame_interval *interval)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
|
||||
/*
|
||||
* FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
|
||||
* subdev active state API.
|
||||
*/
|
||||
if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (interval->pad != MAX9286_SRC_PAD)
|
||||
return -EINVAL;
|
||||
|
||||
interval->interval = priv->interval;
|
||||
interval->interval = *v4l2_subdev_state_get_interval(sd_state,
|
||||
interval->pad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -893,19 +888,11 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_frame_interval *interval)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
|
||||
/*
|
||||
* FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
|
||||
* subdev active state API.
|
||||
*/
|
||||
if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (interval->pad != MAX9286_SRC_PAD)
|
||||
return -EINVAL;
|
||||
|
||||
priv->interval = interval->interval;
|
||||
*v4l2_subdev_state_get_interval(sd_state,
|
||||
interval->pad) = interval->interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -914,39 +901,28 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
if (code->pad || code->index > 0)
|
||||
if (code->pad || code->index >= ARRAY_SIZE(max9286_formats))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
code->code = max9286_formats[code->index].code;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_mbus_framefmt *
|
||||
max9286_get_pad_format(struct max9286_priv *priv,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
unsigned int pad, u32 which)
|
||||
{
|
||||
switch (which) {
|
||||
case V4L2_SUBDEV_FORMAT_TRY:
|
||||
return v4l2_subdev_state_get_format(sd_state, pad);
|
||||
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||
return &priv->fmt[pad];
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int max9286_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
struct v4l2_mbus_framefmt *cfg_fmt;
|
||||
struct max9286_source *source;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Disable setting format on the source pad: format is propagated
|
||||
* from the sinks.
|
||||
*/
|
||||
if (format->pad == MAX9286_SRC_PAD)
|
||||
return -EINVAL;
|
||||
return v4l2_subdev_get_fmt(sd, state, format);
|
||||
|
||||
/* Validate the format. */
|
||||
for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
|
||||
@ -957,42 +933,17 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
|
||||
if (i == ARRAY_SIZE(max9286_formats))
|
||||
format->format.code = max9286_formats[0].code;
|
||||
|
||||
cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
|
||||
format->which);
|
||||
if (!cfg_fmt)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
*cfg_fmt = format->format;
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9286_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
struct v4l2_mbus_framefmt *cfg_fmt;
|
||||
unsigned int pad = format->pad;
|
||||
|
||||
/*
|
||||
* Multiplexed Stream Support: Support link validation by returning the
|
||||
* format of the first bound link. All links must have the same format,
|
||||
* as we do not support mixing and matching of cameras connected to the
|
||||
* max9286.
|
||||
* Apply the same format on all the other pad as all links must have the
|
||||
* same format.
|
||||
*/
|
||||
if (pad == MAX9286_SRC_PAD)
|
||||
pad = __ffs(priv->bound_sources);
|
||||
for_each_source(priv, source) {
|
||||
unsigned int index = to_index(priv, source);
|
||||
|
||||
cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
|
||||
if (!cfg_fmt)
|
||||
return -EINVAL;
|
||||
*v4l2_subdev_state_get_format(state, index) = format->format;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
format->format = *cfg_fmt;
|
||||
mutex_unlock(&priv->mutex);
|
||||
*v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD) = format->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1003,7 +954,7 @@ static const struct v4l2_subdev_video_ops max9286_video_ops = {
|
||||
|
||||
static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
|
||||
.enum_mbus_code = max9286_enum_mbus_code,
|
||||
.get_fmt = max9286_get_fmt,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = max9286_set_fmt,
|
||||
.get_frame_interval = max9286_get_frame_interval,
|
||||
.set_frame_interval = max9286_set_frame_interval,
|
||||
@ -1025,26 +976,29 @@ static const struct v4l2_mbus_framefmt max9286_default_format = {
|
||||
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
|
||||
};
|
||||
|
||||
static void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
|
||||
static int max9286_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
*fmt = max9286_default_format;
|
||||
}
|
||||
struct v4l2_fract *interval;
|
||||
|
||||
static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
unsigned int i;
|
||||
for (unsigned int i = 0; i < MAX9286_N_PADS; i++)
|
||||
*v4l2_subdev_state_get_format(state, i) = max9286_default_format;
|
||||
|
||||
for (i = 0; i < MAX9286_N_SINKS; i++) {
|
||||
format = v4l2_subdev_state_get_format(fh->state, i);
|
||||
max9286_init_format(format);
|
||||
}
|
||||
/*
|
||||
* Special case: a null interval enables automatic FRAMESYNC mode.
|
||||
*
|
||||
* FRAMESYNC is taken from the slowest link. See register 0x01
|
||||
* configuration.
|
||||
*/
|
||||
interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
|
||||
interval->numerator = 0;
|
||||
interval->denominator = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = {
|
||||
.open = max9286_open,
|
||||
.init_state = max9286_init_state,
|
||||
};
|
||||
|
||||
static const struct media_entity_operations max9286_media_ops = {
|
||||
@ -1079,10 +1033,6 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
||||
}
|
||||
|
||||
/* Configure V4L2 for the MAX9286 itself */
|
||||
|
||||
for (i = 0; i < MAX9286_N_SINKS; i++)
|
||||
max9286_init_format(&priv->fmt[i]);
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops);
|
||||
priv->sd.internal_ops = &max9286_subdev_internal_ops;
|
||||
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
@ -1109,14 +1059,21 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
||||
if (ret)
|
||||
goto err_async;
|
||||
|
||||
priv->sd.state_lock = priv->ctrls.lock;
|
||||
ret = v4l2_subdev_init_finalize(&priv->sd);
|
||||
if (ret)
|
||||
goto err_async;
|
||||
|
||||
ret = v4l2_async_register_subdev(&priv->sd);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to register subdevice\n");
|
||||
goto err_async;
|
||||
goto err_subdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_subdev:
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
err_async:
|
||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||
max9286_v4l2_notifier_unregister(priv);
|
||||
@ -1126,6 +1083,7 @@ err_async:
|
||||
|
||||
static void max9286_v4l2_unregister(struct max9286_priv *priv)
|
||||
{
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||
v4l2_async_unregister_subdev(&priv->sd);
|
||||
max9286_v4l2_notifier_unregister(priv);
|
||||
@ -1182,7 +1140,6 @@ static int max9286_setup(struct max9286_priv *priv)
|
||||
max9286_write(priv, 0x69, (0xf & ~priv->route_mask));
|
||||
|
||||
max9286_set_video_format(priv, &max9286_default_format);
|
||||
max9286_set_fsync_period(priv);
|
||||
|
||||
cfg = max9286_read(priv, 0x1c);
|
||||
if (cfg < 0)
|
||||
@ -1629,8 +1586,6 @@ static int max9286_probe(struct i2c_client *client)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
||||
priv->client = client;
|
||||
|
||||
/* GPIO values default to high */
|
||||
|
1024
drivers/media/i2c/max96714.c
Normal file
1024
drivers/media/i2c/max96714.c
Normal file
File diff suppressed because it is too large
Load Diff
927
drivers/media/i2c/max96717.c
Normal file
927
drivers/media/i2c/max96717.c
Normal file
@ -0,0 +1,927 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Maxim GMSL2 Serializer Driver
|
||||
*
|
||||
* Copyright (C) 2024 Collabora Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#define MAX96717_DEVICE_ID 0xbf
|
||||
#define MAX96717F_DEVICE_ID 0xc8
|
||||
#define MAX96717_PORTS 2
|
||||
#define MAX96717_PAD_SINK 0
|
||||
#define MAX96717_PAD_SOURCE 1
|
||||
|
||||
#define MAX96717_DEFAULT_CLKOUT_RATE 24000000UL
|
||||
|
||||
/* DEV */
|
||||
#define MAX96717_REG3 CCI_REG8(0x3)
|
||||
#define MAX96717_RCLKSEL GENMASK(1, 0)
|
||||
#define RCLKSEL_REF_PLL CCI_REG8(0x3)
|
||||
#define MAX96717_REG6 CCI_REG8(0x6)
|
||||
#define RCLKEN BIT(5)
|
||||
#define MAX96717_DEV_ID CCI_REG8(0xd)
|
||||
#define MAX96717_DEV_REV CCI_REG8(0xe)
|
||||
#define MAX96717_DEV_REV_MASK GENMASK(3, 0)
|
||||
|
||||
/* VID_TX Z */
|
||||
#define MAX96717_VIDEO_TX2 CCI_REG8(0x112)
|
||||
#define MAX96717_VIDEO_PCLKDET BIT(7)
|
||||
|
||||
/* GPIO */
|
||||
#define MAX96717_NUM_GPIO 11
|
||||
#define MAX96717_GPIO_REG_A(gpio) CCI_REG8(0x2be + (gpio) * 3)
|
||||
#define MAX96717_GPIO_OUT BIT(4)
|
||||
#define MAX96717_GPIO_IN BIT(3)
|
||||
#define MAX96717_GPIO_RX_EN BIT(2)
|
||||
#define MAX96717_GPIO_TX_EN BIT(1)
|
||||
#define MAX96717_GPIO_OUT_DIS BIT(0)
|
||||
|
||||
/* FRONTTOP */
|
||||
/* MAX96717 only have CSI port 'B' */
|
||||
#define MAX96717_FRONTOP0 CCI_REG8(0x308)
|
||||
#define MAX96717_START_PORT_B BIT(5)
|
||||
|
||||
/* MIPI_RX */
|
||||
#define MAX96717_MIPI_RX1 CCI_REG8(0x331)
|
||||
#define MAX96717_MIPI_LANES_CNT GENMASK(5, 4)
|
||||
#define MAX96717_MIPI_RX2 CCI_REG8(0x332) /* phy1 Lanes map */
|
||||
#define MAX96717_PHY2_LANES_MAP GENMASK(7, 4)
|
||||
#define MAX96717_MIPI_RX3 CCI_REG8(0x333) /* phy2 Lanes map */
|
||||
#define MAX96717_PHY1_LANES_MAP GENMASK(3, 0)
|
||||
#define MAX96717_MIPI_RX4 CCI_REG8(0x334) /* phy1 lane polarities */
|
||||
#define MAX96717_PHY1_LANES_POL GENMASK(6, 4)
|
||||
#define MAX96717_MIPI_RX5 CCI_REG8(0x335) /* phy2 lane polarities */
|
||||
#define MAX96717_PHY2_LANES_POL GENMASK(2, 0)
|
||||
|
||||
/* MIPI_RX_EXT */
|
||||
#define MAX96717_MIPI_RX_EXT11 CCI_REG8(0x383)
|
||||
#define MAX96717_TUN_MODE BIT(7)
|
||||
|
||||
/* REF_VTG */
|
||||
#define REF_VTG0 CCI_REG8(0x3f0)
|
||||
#define REFGEN_PREDEF_EN BIT(6)
|
||||
#define REFGEN_PREDEF_FREQ_MASK GENMASK(5, 4)
|
||||
#define REFGEN_PREDEF_FREQ_ALT BIT(3)
|
||||
#define REFGEN_RST BIT(1)
|
||||
#define REFGEN_EN BIT(0)
|
||||
|
||||
/* MISC */
|
||||
#define PIO_SLEW_1 CCI_REG8(0x570)
|
||||
|
||||
struct max96717_priv {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct i2c_mux_core *mux;
|
||||
struct v4l2_mbus_config_mipi_csi2 mipi_csi2;
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pads[MAX96717_PORTS];
|
||||
struct v4l2_async_notifier notifier;
|
||||
struct v4l2_subdev *source_sd;
|
||||
u16 source_sd_pad;
|
||||
u64 enabled_source_streams;
|
||||
u8 pll_predef_index;
|
||||
struct clk_hw clk_hw;
|
||||
struct gpio_chip gpio_chip;
|
||||
};
|
||||
|
||||
static inline struct max96717_priv *sd_to_max96717(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct max96717_priv, sd);
|
||||
}
|
||||
|
||||
static inline struct max96717_priv *clk_hw_to_max96717(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct max96717_priv, clk_hw);
|
||||
}
|
||||
|
||||
static int max96717_i2c_mux_select(struct i2c_mux_core *mux, u32 chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_i2c_mux_init(struct max96717_priv *priv)
|
||||
{
|
||||
priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
|
||||
1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
|
||||
max96717_i2c_mux_select, NULL);
|
||||
if (!priv->mux)
|
||||
return -ENOMEM;
|
||||
|
||||
return i2c_mux_add_adapter(priv->mux, 0, 0);
|
||||
}
|
||||
|
||||
static inline int max96717_start_csi(struct max96717_priv *priv, bool start)
|
||||
{
|
||||
return cci_update_bits(priv->regmap, MAX96717_FRONTOP0,
|
||||
MAX96717_START_PORT_B,
|
||||
start ? MAX96717_START_PORT_B : 0, NULL);
|
||||
}
|
||||
|
||||
static int max96717_gpiochip_get(struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
&val, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & MAX96717_GPIO_OUT_DIS)
|
||||
return !!(val & MAX96717_GPIO_IN);
|
||||
else
|
||||
return !!(val & MAX96717_GPIO_OUT);
|
||||
}
|
||||
|
||||
static void max96717_gpiochip_set(struct gpio_chip *gpiochip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL);
|
||||
}
|
||||
|
||||
static int max96717_gpio_get_direction(struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset), &val, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(val & MAX96717_GPIO_OUT_DIS);
|
||||
}
|
||||
|
||||
static int max96717_gpio_direction_out(struct gpio_chip *gpiochip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
|
||||
return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
MAX96717_GPIO_OUT_DIS | MAX96717_GPIO_OUT,
|
||||
value ? MAX96717_GPIO_OUT : 0, NULL);
|
||||
}
|
||||
|
||||
static int max96717_gpio_direction_in(struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
|
||||
return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
MAX96717_GPIO_OUT_DIS, MAX96717_GPIO_OUT_DIS,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int max96717_gpiochip_probe(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct gpio_chip *gc = &priv->gpio_chip;
|
||||
int i, ret = 0;
|
||||
|
||||
gc->label = dev_name(dev);
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->ngpio = MAX96717_NUM_GPIO;
|
||||
gc->base = -1;
|
||||
gc->can_sleep = true;
|
||||
gc->get_direction = max96717_gpio_get_direction;
|
||||
gc->direction_input = max96717_gpio_direction_in;
|
||||
gc->direction_output = max96717_gpio_direction_out;
|
||||
gc->set = max96717_gpiochip_set;
|
||||
gc->get = max96717_gpiochip_get;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
/* Disable GPIO forwarding */
|
||||
for (i = 0; i < gc->ngpio; i++)
|
||||
cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(i),
|
||||
MAX96717_GPIO_RX_EN | MAX96717_GPIO_TX_EN,
|
||||
0, &ret);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gc, priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to create gpio_chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _max96717_set_routing(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_krouting *routing)
|
||||
{
|
||||
static const struct v4l2_mbus_framefmt format = {
|
||||
.width = 1280,
|
||||
.height = 1080,
|
||||
.code = MEDIA_BUS_FMT_Y8_1X8,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_set_routing(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
enum v4l2_subdev_format_whence which,
|
||||
struct v4l2_subdev_krouting *routing)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
|
||||
if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
|
||||
return -EBUSY;
|
||||
|
||||
return _max96717_set_routing(sd, state, routing);
|
||||
}
|
||||
|
||||
static int max96717_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
u64 stream_source_mask;
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
|
||||
priv->enabled_source_streams)
|
||||
return -EBUSY;
|
||||
|
||||
/* No transcoding, source and sink formats must match. */
|
||||
if (format->pad == MAX96717_PAD_SOURCE)
|
||||
return v4l2_subdev_get_fmt(sd, state, format);
|
||||
|
||||
/* Set sink format */
|
||||
fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
*fmt = format->format;
|
||||
|
||||
/* Propagate to source format */
|
||||
fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
|
||||
format->stream);
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
*fmt = format->format;
|
||||
|
||||
stream_source_mask = BIT(format->stream);
|
||||
|
||||
return v4l2_subdev_state_xlate_streams(state, MAX96717_PAD_SOURCE,
|
||||
MAX96717_PAD_SINK,
|
||||
&stream_source_mask);
|
||||
}
|
||||
|
||||
static int max96717_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
struct v4l2_subdev_route routes[] = {
|
||||
{
|
||||
.sink_pad = MAX96717_PAD_SINK,
|
||||
.sink_stream = 0,
|
||||
.source_pad = MAX96717_PAD_SOURCE,
|
||||
.source_stream = 0,
|
||||
.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
|
||||
},
|
||||
};
|
||||
struct v4l2_subdev_krouting routing = {
|
||||
.num_routes = ARRAY_SIZE(routes),
|
||||
.routes = routes,
|
||||
};
|
||||
|
||||
return _max96717_set_routing(sd, state, &routing);
|
||||
}
|
||||
|
||||
static bool max96717_pipe_pclkdet(struct max96717_priv *priv)
|
||||
{
|
||||
u64 val = 0;
|
||||
|
||||
cci_read(priv->regmap, MAX96717_VIDEO_TX2, &val, NULL);
|
||||
|
||||
return val & MAX96717_VIDEO_PCLKDET;
|
||||
}
|
||||
|
||||
static int max96717_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
struct device *dev = &priv->client->dev;
|
||||
|
||||
dev_info(dev, "Serializer: max96717\n");
|
||||
dev_info(dev, "Pipe: pclkdet:%d\n", max96717_pipe_pclkdet(priv));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_enable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state, u32 pad,
|
||||
u64 streams_mask)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
struct device *dev = &priv->client->dev;
|
||||
u64 sink_streams;
|
||||
int ret;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state,
|
||||
MAX96717_PAD_SOURCE,
|
||||
MAX96717_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
if (!priv->enabled_source_streams)
|
||||
max96717_start_csi(priv, true);
|
||||
|
||||
ret = v4l2_subdev_enable_streams(priv->source_sd, priv->source_sd_pad,
|
||||
sink_streams);
|
||||
if (ret) {
|
||||
dev_err(dev, "Fail to start streams:%llu on remote subdev\n",
|
||||
sink_streams);
|
||||
goto stop_csi;
|
||||
}
|
||||
|
||||
priv->enabled_source_streams |= streams_mask;
|
||||
|
||||
return 0;
|
||||
|
||||
stop_csi:
|
||||
if (!priv->enabled_source_streams)
|
||||
max96717_start_csi(priv, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max96717_disable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state, u32 pad,
|
||||
u64 streams_mask)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
u64 sink_streams;
|
||||
|
||||
/*
|
||||
* Stop the CSI receiver first then the source,
|
||||
* otherwise the device may become unresponsive
|
||||
* while holding the I2C bus low.
|
||||
*/
|
||||
priv->enabled_source_streams &= ~streams_mask;
|
||||
if (!priv->enabled_source_streams)
|
||||
max96717_start_csi(priv, false);
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state,
|
||||
MAX96717_PAD_SOURCE,
|
||||
MAX96717_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
return v4l2_subdev_disable_streams(priv->source_sd, priv->source_sd_pad,
|
||||
sink_streams);
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_pad_ops max96717_pad_ops = {
|
||||
.enable_streams = max96717_enable_streams,
|
||||
.disable_streams = max96717_disable_streams,
|
||||
.set_routing = max96717_set_routing,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = max96717_set_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops max96717_subdev_core_ops = {
|
||||
.log_status = max96717_log_status,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops max96717_internal_ops = {
|
||||
.init_state = max96717_init_state,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops max96717_subdev_ops = {
|
||||
.core = &max96717_subdev_core_ops,
|
||||
.pad = &max96717_pad_ops,
|
||||
};
|
||||
|
||||
static const struct media_entity_operations max96717_entity_ops = {
|
||||
.link_validate = v4l2_subdev_link_validate,
|
||||
};
|
||||
|
||||
static int max96717_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *source_subdev,
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct max96717_priv *priv = sd_to_max96717(notifier->sd);
|
||||
struct device *dev = &priv->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = media_entity_get_fwnode_pad(&source_subdev->entity,
|
||||
source_subdev->fwnode,
|
||||
MEDIA_PAD_FL_SOURCE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to find pad for %s\n",
|
||||
source_subdev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->source_sd = source_subdev;
|
||||
priv->source_sd_pad = ret;
|
||||
|
||||
ret = media_create_pad_link(&source_subdev->entity, priv->source_sd_pad,
|
||||
&priv->sd.entity, 0,
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to link %s:%u -> %s:0\n",
|
||||
source_subdev->name, priv->source_sd_pad,
|
||||
priv->sd.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_async_notifier_operations max96717_notify_ops = {
|
||||
.bound = max96717_notify_bound,
|
||||
};
|
||||
|
||||
static int max96717_v4l2_notifier_register(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct v4l2_async_connection *asd;
|
||||
struct fwnode_handle *ep_fwnode;
|
||||
int ret;
|
||||
|
||||
ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
|
||||
MAX96717_PAD_SINK, 0, 0);
|
||||
if (!ep_fwnode) {
|
||||
dev_err(dev, "No graph endpoint\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
|
||||
|
||||
asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep_fwnode,
|
||||
struct v4l2_async_connection);
|
||||
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
|
||||
if (IS_ERR(asd)) {
|
||||
dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd));
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
return PTR_ERR(asd);
|
||||
}
|
||||
|
||||
priv->notifier.ops = &max96717_notify_ops;
|
||||
|
||||
ret = v4l2_async_nf_register(&priv->notifier);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register subdev_notifier");
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_subdev_init(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
int ret;
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96717_subdev_ops);
|
||||
priv->sd.internal_ops = &max96717_internal_ops;
|
||||
|
||||
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
|
||||
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
|
||||
priv->sd.entity.ops = &max96717_entity_ops;
|
||||
|
||||
priv->pads[MAX96717_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
priv->pads[MAX96717_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to init pads\n");
|
||||
|
||||
ret = v4l2_subdev_init_finalize(&priv->sd);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret,
|
||||
"v4l2 subdev init finalized failed\n");
|
||||
goto err_entity_cleanup;
|
||||
}
|
||||
ret = max96717_v4l2_notifier_register(priv);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret,
|
||||
"v4l2 subdev notifier register failed\n");
|
||||
goto err_free_state;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev(&priv->sd);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "v4l2_async_register_subdev error\n");
|
||||
goto err_unreg_notif;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unreg_notif:
|
||||
v4l2_async_nf_unregister(&priv->notifier);
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
err_free_state:
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
err_entity_cleanup:
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max96717_subdev_uninit(struct max96717_priv *priv)
|
||||
{
|
||||
v4l2_async_unregister_subdev(&priv->sd);
|
||||
v4l2_async_nf_unregister(&priv->notifier);
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
}
|
||||
|
||||
struct max96717_pll_predef_freq {
|
||||
unsigned long freq;
|
||||
bool is_alt;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
static const struct max96717_pll_predef_freq max96717_predef_freqs[] = {
|
||||
{ 13500000, true, 0 }, { 19200000, false, 0 },
|
||||
{ 24000000, true, 1 }, { 27000000, false, 1 },
|
||||
{ 37125000, false, 2 }, { 74250000, false, 3 },
|
||||
};
|
||||
|
||||
static unsigned long
|
||||
max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct max96717_priv *priv = clk_hw_to_max96717(hw);
|
||||
|
||||
return max96717_predef_freqs[priv->pll_predef_index].freq;
|
||||
}
|
||||
|
||||
static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv,
|
||||
unsigned long rate)
|
||||
{
|
||||
unsigned int i, idx;
|
||||
unsigned long diff_new, diff_old;
|
||||
|
||||
diff_old = U32_MAX;
|
||||
idx = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) {
|
||||
diff_new = abs(rate - max96717_predef_freqs[i].freq);
|
||||
if (diff_new < diff_old) {
|
||||
diff_old = diff_new;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct max96717_priv *priv = clk_hw_to_max96717(hw);
|
||||
struct device *dev = &priv->client->dev;
|
||||
unsigned int idx;
|
||||
|
||||
idx = max96717_clk_find_best_index(priv, rate);
|
||||
|
||||
if (rate != max96717_predef_freqs[idx].freq) {
|
||||
dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n",
|
||||
rate, max96717_predef_freqs[idx].freq);
|
||||
}
|
||||
|
||||
return max96717_predef_freqs[idx].freq;
|
||||
}
|
||||
|
||||
static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct max96717_priv *priv = clk_hw_to_max96717(hw);
|
||||
unsigned int val, idx;
|
||||
int ret = 0;
|
||||
|
||||
idx = max96717_clk_find_best_index(priv, rate);
|
||||
|
||||
val = FIELD_PREP(REFGEN_PREDEF_FREQ_MASK,
|
||||
max96717_predef_freqs[idx].val);
|
||||
|
||||
if (max96717_predef_freqs[idx].is_alt)
|
||||
val |= REFGEN_PREDEF_FREQ_ALT;
|
||||
|
||||
val |= REFGEN_RST | REFGEN_PREDEF_EN;
|
||||
|
||||
cci_write(priv->regmap, REF_VTG0, val, &ret);
|
||||
cci_update_bits(priv->regmap, REF_VTG0, REFGEN_RST | REFGEN_EN,
|
||||
REFGEN_EN, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->pll_predef_index = idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max96717_priv *priv = clk_hw_to_max96717(hw);
|
||||
|
||||
return cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN,
|
||||
RCLKEN, NULL);
|
||||
}
|
||||
|
||||
static void max96717_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max96717_priv *priv = clk_hw_to_max96717(hw);
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN, 0, NULL);
|
||||
}
|
||||
|
||||
static const struct clk_ops max96717_clk_ops = {
|
||||
.prepare = max96717_clk_prepare,
|
||||
.unprepare = max96717_clk_unprepare,
|
||||
.set_rate = max96717_clk_set_rate,
|
||||
.recalc_rate = max96717_clk_recalc_rate,
|
||||
.round_rate = max96717_clk_round_rate,
|
||||
};
|
||||
|
||||
static int max96717_register_clkout(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct clk_init_data init = { .ops = &max96717_clk_ops };
|
||||
int ret;
|
||||
|
||||
init.name = kasprintf(GFP_KERNEL, "max96717.%s.clk_out",
|
||||
dev_name(dev));
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
/* RCLKSEL Reference PLL output */
|
||||
ret = cci_update_bits(priv->regmap, MAX96717_REG3, MAX96717_RCLKSEL,
|
||||
MAX96717_RCLKSEL, NULL);
|
||||
/* MFP4 fastest slew rate */
|
||||
cci_update_bits(priv->regmap, PIO_SLEW_1, BIT(5) | BIT(4), 0, &ret);
|
||||
if (ret)
|
||||
goto free_init_name;
|
||||
|
||||
priv->clk_hw.init = &init;
|
||||
|
||||
/* Initialize to 24 MHz */
|
||||
ret = max96717_clk_set_rate(&priv->clk_hw,
|
||||
MAX96717_DEFAULT_CLKOUT_RATE, 0);
|
||||
if (ret < 0)
|
||||
goto free_init_name;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &priv->clk_hw);
|
||||
kfree(init.name);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot register clock HW\n");
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
&priv->clk_hw);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Cannot add OF clock provider\n");
|
||||
|
||||
return 0;
|
||||
|
||||
free_init_name:
|
||||
kfree(init.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max96717_init_csi_lanes(struct max96717_priv *priv)
|
||||
{
|
||||
struct v4l2_mbus_config_mipi_csi2 *mipi = &priv->mipi_csi2;
|
||||
unsigned long lanes_used = 0;
|
||||
unsigned int nlanes, lane, val = 0;
|
||||
int ret;
|
||||
|
||||
nlanes = mipi->num_data_lanes;
|
||||
|
||||
ret = cci_update_bits(priv->regmap, MAX96717_MIPI_RX1,
|
||||
MAX96717_MIPI_LANES_CNT,
|
||||
FIELD_PREP(MAX96717_MIPI_LANES_CNT,
|
||||
nlanes - 1), NULL);
|
||||
|
||||
/* lanes polarity */
|
||||
for (lane = 0; lane < nlanes + 1; lane++) {
|
||||
if (!mipi->lane_polarities[lane])
|
||||
continue;
|
||||
/* Clock lane */
|
||||
if (lane == 0)
|
||||
val |= BIT(2);
|
||||
else if (lane < 3)
|
||||
val |= BIT(lane - 1);
|
||||
else
|
||||
val |= BIT(lane);
|
||||
}
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_MIPI_RX5,
|
||||
MAX96717_PHY2_LANES_POL,
|
||||
FIELD_PREP(MAX96717_PHY2_LANES_POL, val), &ret);
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_MIPI_RX4,
|
||||
MAX96717_PHY1_LANES_POL,
|
||||
FIELD_PREP(MAX96717_PHY1_LANES_POL,
|
||||
val >> 3), &ret);
|
||||
/* lanes mapping */
|
||||
for (lane = 0, val = 0; lane < nlanes; lane++) {
|
||||
val |= (mipi->data_lanes[lane] - 1) << (lane * 2);
|
||||
lanes_used |= BIT(mipi->data_lanes[lane] - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused lanes need to be mapped as well to not have
|
||||
* the same lanes mapped twice.
|
||||
*/
|
||||
for (; lane < 4; lane++) {
|
||||
unsigned int idx = find_first_zero_bit(&lanes_used, 4);
|
||||
|
||||
val |= idx << (lane * 2);
|
||||
lanes_used |= BIT(idx);
|
||||
}
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_MIPI_RX3,
|
||||
MAX96717_PHY1_LANES_MAP,
|
||||
FIELD_PREP(MAX96717_PHY1_LANES_MAP, val), &ret);
|
||||
|
||||
return cci_update_bits(priv->regmap, MAX96717_MIPI_RX2,
|
||||
MAX96717_PHY2_LANES_MAP,
|
||||
FIELD_PREP(MAX96717_PHY2_LANES_MAP, val >> 4),
|
||||
&ret);
|
||||
}
|
||||
|
||||
static int max96717_hw_init(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
u64 dev_id, val;
|
||||
int ret;
|
||||
|
||||
ret = cci_read(priv->regmap, MAX96717_DEV_ID, &dev_id, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Fail to read the device id\n");
|
||||
|
||||
if (dev_id != MAX96717_DEVICE_ID && dev_id != MAX96717F_DEVICE_ID)
|
||||
return dev_err_probe(dev, -EOPNOTSUPP,
|
||||
"Unsupported device id got %x\n", (u8)dev_id);
|
||||
|
||||
ret = cci_read(priv->regmap, MAX96717_DEV_REV, &val, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Fail to read device revision");
|
||||
|
||||
dev_dbg(dev, "Found %x (rev %lx)\n", (u8)dev_id,
|
||||
(u8)val & MAX96717_DEV_REV_MASK);
|
||||
|
||||
ret = cci_read(priv->regmap, MAX96717_MIPI_RX_EXT11, &val, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Fail to read mipi rx extension");
|
||||
|
||||
if (!(val & MAX96717_TUN_MODE))
|
||||
return dev_err_probe(dev, -EOPNOTSUPP,
|
||||
"Only supporting tunnel mode");
|
||||
|
||||
return max96717_init_csi_lanes(priv);
|
||||
}
|
||||
|
||||
static int max96717_parse_dt(struct max96717_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct v4l2_fwnode_endpoint vep = {
|
||||
.bus_type = V4L2_MBUS_CSI2_DPHY
|
||||
};
|
||||
struct fwnode_handle *ep_fwnode;
|
||||
unsigned char num_data_lanes;
|
||||
int ret;
|
||||
|
||||
ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
|
||||
MAX96717_PAD_SINK, 0, 0);
|
||||
if (!ep_fwnode)
|
||||
return dev_err_probe(dev, -ENOENT, "no endpoint found\n");
|
||||
|
||||
ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep);
|
||||
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to parse sink endpoint");
|
||||
|
||||
num_data_lanes = vep.bus.mipi_csi2.num_data_lanes;
|
||||
if (num_data_lanes < 1 || num_data_lanes > 4)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Invalid data lanes must be 1 to 4\n");
|
||||
|
||||
memcpy(&priv->mipi_csi2, &vep.bus.mipi_csi2, sizeof(priv->mipi_csi2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96717_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct max96717_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->client = client;
|
||||
priv->regmap = devm_cci_regmap_init_i2c(client, 16);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
ret = PTR_ERR(priv->regmap);
|
||||
return dev_err_probe(dev, ret, "Failed to init regmap\n");
|
||||
}
|
||||
|
||||
ret = max96717_parse_dt(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to parse the dt\n");
|
||||
|
||||
ret = max96717_hw_init(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to initialize the hardware\n");
|
||||
|
||||
ret = max96717_gpiochip_probe(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"Failed to init gpiochip\n");
|
||||
|
||||
ret = max96717_register_clkout(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to register clkout\n");
|
||||
|
||||
ret = max96717_subdev_init(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to initialize v4l2 subdev\n");
|
||||
|
||||
ret = max96717_i2c_mux_init(priv);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to add remote i2c adapter\n");
|
||||
max96717_subdev_uninit(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max96717_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct max96717_priv *priv = sd_to_max96717(sd);
|
||||
|
||||
max96717_subdev_uninit(priv);
|
||||
i2c_mux_del_adapters(priv->mux);
|
||||
}
|
||||
|
||||
static const struct of_device_id max96717_of_ids[] = {
|
||||
{ .compatible = "maxim,max96717f" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max96717_of_ids);
|
||||
|
||||
static struct i2c_driver max96717_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max96717",
|
||||
.of_match_table = max96717_of_ids,
|
||||
},
|
||||
.probe = max96717_probe,
|
||||
.remove = max96717_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(max96717_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Maxim GMSL2 MAX96717 Serializer Driver");
|
||||
MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -971,7 +971,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 5);
|
||||
v4l2_ctrl_handler_init(hdl, 11);
|
||||
|
||||
hdl->lock = &sensor->lock;
|
||||
|
||||
|
@ -1360,24 +1360,21 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
|
||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||
.bus_type = V4L2_MBUS_CSI2_DPHY,
|
||||
};
|
||||
struct device_node *ep;
|
||||
struct device_node *ep __free(device_node) =
|
||||
of_graph_get_endpoint_by_regs(np, 0, -1);
|
||||
int ret;
|
||||
|
||||
ep = of_graph_get_endpoint_by_regs(np, 0, -1);
|
||||
if (!ep)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags &
|
||||
V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
|
||||
|
||||
out:
|
||||
of_node_put(ep);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5647_probe(struct i2c_client *client)
|
||||
|
@ -141,7 +141,6 @@ struct ov5693_device {
|
||||
|
||||
struct gpio_desc *reset;
|
||||
struct gpio_desc *powerdown;
|
||||
struct gpio_desc *privacy_led;
|
||||
struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
|
||||
struct clk *xvclk;
|
||||
|
||||
@ -657,7 +656,6 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
|
||||
|
||||
static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
|
||||
{
|
||||
gpiod_set_value_cansleep(ov5693->privacy_led, 0);
|
||||
gpiod_set_value_cansleep(ov5693->reset, 1);
|
||||
gpiod_set_value_cansleep(ov5693->powerdown, 1);
|
||||
|
||||
@ -687,7 +685,6 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
|
||||
|
||||
gpiod_set_value_cansleep(ov5693->powerdown, 0);
|
||||
gpiod_set_value_cansleep(ov5693->reset, 0);
|
||||
gpiod_set_value_cansleep(ov5693->privacy_led, 1);
|
||||
|
||||
usleep_range(5000, 7500);
|
||||
|
||||
@ -1201,13 +1198,6 @@ static int ov5693_configure_gpios(struct ov5693_device *ov5693)
|
||||
return PTR_ERR(ov5693->powerdown);
|
||||
}
|
||||
|
||||
ov5693->privacy_led = devm_gpiod_get_optional(ov5693->dev, "privacy-led",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ov5693->privacy_led)) {
|
||||
dev_err(ov5693->dev, "Error fetching privacy-led GPIO\n");
|
||||
return PTR_ERR(ov5693->privacy_led);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -212,11 +212,6 @@
|
||||
* structure
|
||||
*/
|
||||
|
||||
struct regval_list {
|
||||
unsigned char reg_num;
|
||||
unsigned char value;
|
||||
};
|
||||
|
||||
struct tw9910_scale_ctrl {
|
||||
char *name;
|
||||
unsigned short width;
|
||||
|
@ -95,4 +95,5 @@ static struct i2c_driver uda1342_driver = {
|
||||
|
||||
module_i2c_driver(uda1342_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Philips UDA1342 audio codec driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1878,7 +1878,7 @@ static const struct dev_pm_ops vgxy61_pm_ops = {
|
||||
|
||||
static struct i2c_driver vgxy61_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "st-vgxy61",
|
||||
.name = "vgxy61",
|
||||
.of_match_table = vgxy61_dt_ids,
|
||||
.pm = &vgxy61_pm_ops,
|
||||
},
|
@ -300,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
|
||||
}
|
||||
if (astat & BT878_ARISCI) {
|
||||
bt->finished_block = (stat & BT878_ARISCS) >> 28;
|
||||
if (bt->tasklet.callback)
|
||||
tasklet_schedule(&bt->tasklet);
|
||||
if (bt->bh_work.func)
|
||||
queue_work(system_bh_wq, &bt->bh_work);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
@ -478,8 +478,8 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
bt878_num++;
|
||||
|
||||
if (!bt->tasklet.func)
|
||||
tasklet_disable(&bt->tasklet);
|
||||
if (!bt->bh_work.func)
|
||||
disable_work_sync(&bt->bh_work);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -563,4 +563,5 @@ static void __exit bt878_cleanup_module(void)
|
||||
module_init(bt878_init_module);
|
||||
module_exit(bt878_cleanup_module);
|
||||
|
||||
MODULE_DESCRIPTION("DVB/ATSC Support for bt878 based TV cards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "bt848.h"
|
||||
#include "bttv.h"
|
||||
@ -120,7 +121,7 @@ struct bt878 {
|
||||
dma_addr_t risc_dma;
|
||||
u32 risc_pos;
|
||||
|
||||
struct tasklet_struct tasklet;
|
||||
struct work_struct bh_work;
|
||||
int shutdown;
|
||||
};
|
||||
|
||||
|
@ -39,9 +39,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
|
||||
static void dvb_bt8xx_task(struct tasklet_struct *t)
|
||||
static void dvb_bt8xx_work(struct work_struct *t)
|
||||
{
|
||||
struct bt878 *bt = from_tasklet(bt, t, tasklet);
|
||||
struct bt878 *bt = from_work(bt, t, bh_work);
|
||||
struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev);
|
||||
|
||||
dprintk("%d\n", card->bt->finished_block);
|
||||
@ -782,7 +782,7 @@ static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
|
||||
goto err_disconnect_frontend;
|
||||
}
|
||||
|
||||
tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task);
|
||||
INIT_WORK(&card->bt->bh_work, dvb_bt8xx_work);
|
||||
|
||||
frontend_init(card, type);
|
||||
|
||||
@ -922,7 +922,7 @@ static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
|
||||
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
|
||||
|
||||
bt878_stop(card->bt);
|
||||
tasklet_kill(&card->bt->tasklet);
|
||||
cancel_work_sync(&card->bt->bh_work);
|
||||
dvb_net_release(&card->dvbnet);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
|
@ -258,7 +258,7 @@ struct cx18_scb {
|
||||
struct cx18_mailbox ppu2epu_mb;
|
||||
|
||||
struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS];
|
||||
struct cx18_mdl_ent cpu_mdl[1];
|
||||
struct cx18_mdl_ent cpu_mdl[];
|
||||
};
|
||||
|
||||
void cx18_init_scb(struct cx18 *cx);
|
||||
|
@ -298,7 +298,7 @@ struct ddb_link {
|
||||
spinlock_t lock; /* lock link access */
|
||||
struct mutex flash_mutex; /* lock flash access */
|
||||
struct ddb_lnb lnb;
|
||||
struct tasklet_struct tasklet;
|
||||
struct work_struct bh_work;
|
||||
struct ddb_ids ids;
|
||||
|
||||
spinlock_t temp_lock; /* lock temp chip access */
|
||||
|
@ -43,28 +43,46 @@
|
||||
* becoming apparent in the future.
|
||||
*
|
||||
* Do not add an entry for a sensor that is not actually supported.
|
||||
*
|
||||
* Please keep the list sorted by ACPI HID.
|
||||
*/
|
||||
static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
||||
/* Himax HM11B1 */
|
||||
IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000),
|
||||
/* Himax HM2170 */
|
||||
IPU_SENSOR_CONFIG("HIMX2170", 1, 384000000),
|
||||
/* Himax HM2172 */
|
||||
IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000),
|
||||
/* GalaxyCore GC0310 */
|
||||
IPU_SENSOR_CONFIG("INT0310", 0),
|
||||
/* Omnivision OV5693 */
|
||||
IPU_SENSOR_CONFIG("INT33BE", 1, 419200000),
|
||||
/* Omnivision OV2740 */
|
||||
IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
|
||||
/* Omnivision OV8865 */
|
||||
IPU_SENSOR_CONFIG("INT347A", 1, 360000000),
|
||||
/* Omnivision OV7251 */
|
||||
IPU_SENSOR_CONFIG("INT347E", 1, 319200000),
|
||||
/* Hynix Hi-556 */
|
||||
IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
|
||||
/* Omnivision OV01A10 / OV01A1S */
|
||||
IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000),
|
||||
IPU_SENSOR_CONFIG("OVTI01AS", 1, 400000000),
|
||||
/* Omnivision OV02C10 */
|
||||
IPU_SENSOR_CONFIG("OVTI02C1", 1, 400000000),
|
||||
/* Omnivision OV02E10 */
|
||||
IPU_SENSOR_CONFIG("OVTI02E1", 1, 360000000),
|
||||
/* Omnivision OV08A10 */
|
||||
IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000),
|
||||
/* Omnivision OV08x40 */
|
||||
IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000),
|
||||
/* Omnivision OV13B10 */
|
||||
IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000),
|
||||
IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
|
||||
/* Omnivision OV2680 */
|
||||
IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000),
|
||||
/* Omnivision ov8856 */
|
||||
/* Omnivision OV8856 */
|
||||
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
|
||||
/* Omnivision ov2740 */
|
||||
IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
|
||||
/* Hynix hi556 */
|
||||
IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
|
||||
/* Omnivision ov13b10 */
|
||||
IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
|
||||
/* GalaxyCore GC0310 */
|
||||
IPU_SENSOR_CONFIG("INT0310", 0),
|
||||
/* Omnivision ov01a10 */
|
||||
IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000),
|
||||
};
|
||||
|
||||
static const struct ipu_property_names prop_names = {
|
||||
|
@ -163,8 +163,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
|
||||
writel(ENTRY, isp->base + ipc->csr_out);
|
||||
break;
|
||||
default:
|
||||
dev_warn_ratelimited(&isp->pdev->dev,
|
||||
"Unexpected CSR 0x%x\n", val);
|
||||
dev_dbg_ratelimited(&isp->pdev->dev,
|
||||
"Unexpected CSR 0x%x\n", val);
|
||||
break;
|
||||
}
|
||||
} while (retries--);
|
||||
|
@ -345,42 +345,61 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_stream(struct v4l2_subdev *sd, int enable)
|
||||
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
|
||||
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
|
||||
struct device *dev = &csi2->isys->adev->auxdev.dev;
|
||||
struct ipu6_isys_csi2_timing timing = { };
|
||||
unsigned int nlanes;
|
||||
struct v4l2_subdev *remote_sd;
|
||||
struct media_pad *remote_pad;
|
||||
u64 sink_streams;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off");
|
||||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
if (!enable) {
|
||||
csi2->stream_count--;
|
||||
if (csi2->stream_count)
|
||||
return 0;
|
||||
|
||||
ipu6_isys_csi2_set_stream(sd, &timing, 0, enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (csi2->stream_count) {
|
||||
csi2->stream_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlanes = csi2->nlanes;
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ipu6_isys_csi2_set_stream(sd, &timing, nlanes, enable);
|
||||
ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csi2->stream_count++;
|
||||
ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
|
||||
sink_streams);
|
||||
if (ret) {
|
||||
ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct v4l2_subdev *remote_sd;
|
||||
struct media_pad *remote_pad;
|
||||
u64 sink_streams;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
|
||||
|
||||
v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -475,10 +494,6 @@ static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
|
||||
.s_stream = set_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = ipu6_isys_subdev_set_fmt,
|
||||
@ -486,11 +501,12 @@ static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
|
||||
.set_selection = ipu6_isys_csi2_set_sel,
|
||||
.enum_mbus_code = ipu6_isys_subdev_enum_mbus_code,
|
||||
.set_routing = ipu6_isys_subdev_set_routing,
|
||||
.enable_streams = ipu6_isys_csi2_enable_streams,
|
||||
.disable_streams = ipu6_isys_csi2_disable_streams,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops csi2_sd_ops = {
|
||||
.core = &csi2_sd_core_ops,
|
||||
.video = &csi2_sd_video_ops,
|
||||
.pad = &csi2_sd_pad_ops,
|
||||
};
|
||||
|
||||
@ -631,33 +647,3 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status)
|
||||
{
|
||||
struct ipu6_isys_stream *stream = av->stream;
|
||||
struct v4l2_subdev *sd = &stream->asd->sd;
|
||||
struct v4l2_subdev_state *state;
|
||||
struct media_pad *r_pad;
|
||||
unsigned int i;
|
||||
u32 r_stream;
|
||||
|
||||
r_pad = media_pad_remote_pad_first(&av->pad);
|
||||
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
|
||||
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
|
||||
for (i = 0; i < state->stream_configs.num_configs; i++) {
|
||||
struct v4l2_subdev_stream_config *cfg =
|
||||
&state->stream_configs.configs[i];
|
||||
|
||||
if (cfg->pad == r_pad->index && r_stream == cfg->stream) {
|
||||
dev_dbg(&av->isys->adev->auxdev.dev,
|
||||
"%s: pad:%u, stream:%u, status:%u\n",
|
||||
sd->entity.name, r_pad->index, r_stream,
|
||||
status);
|
||||
cfg->enabled = status;
|
||||
}
|
||||
}
|
||||
|
||||
v4l2_subdev_unlock_state(state);
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ struct ipu6_isys_csi2 {
|
||||
u32 receiver_errors;
|
||||
unsigned int nlanes;
|
||||
unsigned int port;
|
||||
unsigned int stream_count;
|
||||
};
|
||||
|
||||
struct ipu6_isys_csi2_timing {
|
||||
@ -77,6 +76,5 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
|
||||
struct ipu6_isys_csi2 *csi2,
|
||||
struct media_entity *source_entity,
|
||||
struct v4l2_mbus_frame_desc_entry *entry);
|
||||
void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status);
|
||||
|
||||
#endif /* IPU6_ISYS_CSI2_H */
|
||||
|
@ -551,7 +551,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
stream->nr_queues);
|
||||
|
||||
list_add(&aq->node, &stream->queues);
|
||||
ipu6_isys_set_csi2_streams_status(av, true);
|
||||
ipu6_isys_configure_stream_watermark(av, true);
|
||||
ipu6_isys_update_stream_watermark(av, true);
|
||||
|
||||
@ -598,8 +597,6 @@ static void stop_streaming(struct vb2_queue *q)
|
||||
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
|
||||
struct ipu6_isys_stream *stream = av->stream;
|
||||
|
||||
ipu6_isys_set_csi2_streams_status(av, false);
|
||||
|
||||
mutex_lock(&stream->mutex);
|
||||
|
||||
ipu6_isys_update_stream_watermark(av, false);
|
||||
|
@ -990,9 +990,7 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
||||
struct v4l2_subdev_state *subdev_state;
|
||||
struct device *dev = &av->isys->adev->auxdev.dev;
|
||||
struct v4l2_subdev *sd;
|
||||
struct v4l2_subdev *ssd;
|
||||
struct media_pad *r_pad;
|
||||
struct media_pad *s_pad;
|
||||
u32 sink_pad, sink_stream;
|
||||
u64 r_stream;
|
||||
u64 stream_mask = 0;
|
||||
@ -1003,7 +1001,6 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
||||
if (WARN(!stream->source_entity, "No source entity for stream\n"))
|
||||
return -ENODEV;
|
||||
|
||||
ssd = media_entity_to_v4l2_subdev(stream->source_entity);
|
||||
sd = &stream->asd->sd;
|
||||
r_pad = media_pad_remote_pad_first(&av->pad);
|
||||
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
|
||||
@ -1017,27 +1014,15 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]);
|
||||
|
||||
stream_mask = get_stream_mask_by_pipeline(av);
|
||||
if (!state) {
|
||||
stop_streaming_firmware(av);
|
||||
|
||||
/* stop external sub-device now. */
|
||||
dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask,
|
||||
ssd->name);
|
||||
ret = v4l2_subdev_disable_streams(ssd, s_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "disable streams of %s failed with %d\n",
|
||||
ssd->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* stop sub-device which connects with video */
|
||||
dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name,
|
||||
r_pad->index);
|
||||
ret = v4l2_subdev_call(sd, video, s_stream, state);
|
||||
dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
|
||||
sd->name, r_pad->index, stream_mask);
|
||||
ret = v4l2_subdev_disable_streams(sd, r_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "stream off %s failed with %d\n", sd->name,
|
||||
ret);
|
||||
@ -1052,34 +1037,20 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
||||
}
|
||||
|
||||
/* start sub-device which connects with video */
|
||||
dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
|
||||
ret = v4l2_subdev_call(sd, video, s_stream, state);
|
||||
dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
|
||||
r_pad->index, stream_mask);
|
||||
ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "stream on %s failed with %d\n", sd->name,
|
||||
ret);
|
||||
goto out_media_entity_stop_streaming_firmware;
|
||||
}
|
||||
|
||||
/* start external sub-device now. */
|
||||
dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask,
|
||||
ssd->name);
|
||||
ret = v4l2_subdev_enable_streams(ssd, s_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"enable streams 0x%llx of %s failed with %d\n",
|
||||
stream_mask, stream->source_entity->name, ret);
|
||||
goto out_media_entity_stop_streaming;
|
||||
}
|
||||
}
|
||||
|
||||
av->streaming = state;
|
||||
|
||||
return 0;
|
||||
|
||||
out_media_entity_stop_streaming:
|
||||
v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream));
|
||||
|
||||
out_media_entity_stop_streaming_firmware:
|
||||
stop_streaming_firmware(av);
|
||||
|
||||
|
@ -126,6 +126,8 @@ struct mei_csi {
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct v4l2_ctrl *freq_ctrl;
|
||||
struct v4l2_ctrl *privacy_ctrl;
|
||||
/* lock for v4l2 controls */
|
||||
struct mutex ctrl_lock;
|
||||
unsigned int remote_pad;
|
||||
/* start streaming or not */
|
||||
int streaming;
|
||||
@ -136,9 +138,6 @@ struct mei_csi {
|
||||
u32 nr_of_lanes;
|
||||
/* frequency of the CSI-2 link */
|
||||
u64 link_freq;
|
||||
|
||||
/* privacy status */
|
||||
enum ivsc_privacy_status status;
|
||||
};
|
||||
|
||||
static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = {
|
||||
@ -190,7 +189,11 @@ static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len)
|
||||
|
||||
/* command response status */
|
||||
ret = csi->cmd_response.status;
|
||||
if (ret) {
|
||||
if (ret == -1) {
|
||||
/* notify privacy on instead of reporting error */
|
||||
ret = 0;
|
||||
v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
|
||||
} else if (ret) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -265,10 +268,9 @@ static void mei_csi_rx(struct mei_cl_device *cldev)
|
||||
|
||||
switch (notif.cmd_id) {
|
||||
case CSI_PRIVACY_NOTIF:
|
||||
if (notif.cont.cont < CSI_PRIVACY_MAX) {
|
||||
csi->status = notif.cont.cont;
|
||||
v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status);
|
||||
}
|
||||
if (notif.cont.cont < CSI_PRIVACY_MAX)
|
||||
v4l2_ctrl_s_ctrl(csi->privacy_ctrl,
|
||||
notif.cont.cont == CSI_PRIVACY_ON);
|
||||
break;
|
||||
case CSI_SET_OWNER:
|
||||
case CSI_SET_CONF:
|
||||
@ -559,11 +561,13 @@ static int mei_csi_init_controls(struct mei_csi *csi)
|
||||
u32 max;
|
||||
int ret;
|
||||
|
||||
mutex_init(&csi->ctrl_lock);
|
||||
|
||||
ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csi->ctrl_handler.lock = &csi->lock;
|
||||
csi->ctrl_handler.lock = &csi->ctrl_lock;
|
||||
|
||||
max = ARRAY_SIZE(link_freq_menu_items) - 1;
|
||||
csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler,
|
||||
@ -755,6 +759,7 @@ err_entity:
|
||||
|
||||
err_ctrl_handler:
|
||||
v4l2_ctrl_handler_free(&csi->ctrl_handler);
|
||||
mutex_destroy(&csi->ctrl_lock);
|
||||
v4l2_async_nf_unregister(&csi->notifier);
|
||||
v4l2_async_nf_cleanup(&csi->notifier);
|
||||
|
||||
@ -774,6 +779,7 @@ static void mei_csi_remove(struct mei_cl_device *cldev)
|
||||
v4l2_async_nf_unregister(&csi->notifier);
|
||||
v4l2_async_nf_cleanup(&csi->notifier);
|
||||
v4l2_ctrl_handler_free(&csi->ctrl_handler);
|
||||
mutex_destroy(&csi->ctrl_lock);
|
||||
v4l2_async_unregister_subdev(&csi->subdev);
|
||||
v4l2_subdev_cleanup(&csi->subdev);
|
||||
media_entity_cleanup(&csi->subdev.entity);
|
||||
|
@ -371,33 +371,6 @@ int ivtv_msleep_timeout(unsigned int msecs, int intr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Release ioremapped memory */
|
||||
static void ivtv_iounmap(struct ivtv *itv)
|
||||
{
|
||||
if (itv == NULL)
|
||||
return;
|
||||
|
||||
/* Release registers memory */
|
||||
if (itv->reg_mem != NULL) {
|
||||
IVTV_DEBUG_INFO("releasing reg_mem\n");
|
||||
iounmap(itv->reg_mem);
|
||||
itv->reg_mem = NULL;
|
||||
}
|
||||
/* Release io memory */
|
||||
if (itv->has_cx23415 && itv->dec_mem != NULL) {
|
||||
IVTV_DEBUG_INFO("releasing dec_mem\n");
|
||||
iounmap(itv->dec_mem);
|
||||
}
|
||||
itv->dec_mem = NULL;
|
||||
|
||||
/* Release io memory */
|
||||
if (itv->enc_mem != NULL) {
|
||||
IVTV_DEBUG_INFO("releasing enc_mem\n");
|
||||
iounmap(itv->enc_mem);
|
||||
itv->enc_mem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hauppauge card? get values from tveeprom */
|
||||
void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
|
||||
{
|
||||
@ -833,7 +806,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
|
||||
|
||||
IVTV_DEBUG_INFO("Enabling pci device\n");
|
||||
|
||||
if (pci_enable_device(pdev)) {
|
||||
if (pcim_enable_device(pdev)) {
|
||||
IVTV_ERR("Can't enable device!\n");
|
||||
return -EIO;
|
||||
}
|
||||
@ -841,24 +814,24 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
|
||||
IVTV_ERR("No suitable DMA available.\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
|
||||
if (!devm_request_mem_region(&pdev->dev, itv->base_addr,
|
||||
IVTV_ENCODER_SIZE, "ivtv encoder")) {
|
||||
IVTV_ERR("Cannot request encoder memory region.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
|
||||
IVTV_REG_SIZE, "ivtv registers")) {
|
||||
if (!devm_request_mem_region(&pdev->dev,
|
||||
itv->base_addr + IVTV_REG_OFFSET,
|
||||
IVTV_REG_SIZE, "ivtv registers")) {
|
||||
IVTV_ERR("Cannot request register memory region.\n");
|
||||
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (itv->has_cx23415 &&
|
||||
!request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
|
||||
IVTV_DECODER_SIZE, "ivtv decoder")) {
|
||||
!devm_request_mem_region(&pdev->dev,
|
||||
itv->base_addr + IVTV_DECODER_OFFSET,
|
||||
IVTV_DECODER_SIZE, "ivtv decoder")) {
|
||||
IVTV_ERR("Cannot request decoder memory region.\n");
|
||||
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
|
||||
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -870,11 +843,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
if (!(cmd & PCI_COMMAND_MASTER)) {
|
||||
IVTV_ERR("Bus Mastering is not enabled\n");
|
||||
if (itv->has_cx23415)
|
||||
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
|
||||
IVTV_DECODER_SIZE);
|
||||
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
|
||||
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
@ -1033,37 +1001,37 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
|
||||
|
||||
/* PCI Device Setup */
|
||||
retval = ivtv_setup_pci(itv, pdev, pci_id);
|
||||
if (retval == -EIO)
|
||||
if (retval == -EIO || retval == -ENXIO)
|
||||
goto free_worker;
|
||||
if (retval == -ENXIO)
|
||||
goto free_mem;
|
||||
|
||||
/* map io memory */
|
||||
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
|
||||
(u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
|
||||
itv->enc_mem = ioremap(itv->base_addr + IVTV_ENCODER_OFFSET,
|
||||
IVTV_ENCODER_SIZE);
|
||||
itv->enc_mem = devm_ioremap(&pdev->dev,
|
||||
itv->base_addr + IVTV_ENCODER_OFFSET,
|
||||
IVTV_ENCODER_SIZE);
|
||||
if (!itv->enc_mem) {
|
||||
IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n");
|
||||
IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n");
|
||||
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
|
||||
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
|
||||
retval = -ENOMEM;
|
||||
goto free_mem;
|
||||
goto free_worker;
|
||||
}
|
||||
|
||||
if (itv->has_cx23415) {
|
||||
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
|
||||
(u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
|
||||
itv->dec_mem = ioremap(itv->base_addr + IVTV_DECODER_OFFSET,
|
||||
IVTV_DECODER_SIZE);
|
||||
itv->dec_mem = devm_ioremap(&pdev->dev,
|
||||
itv->base_addr + IVTV_DECODER_OFFSET,
|
||||
IVTV_DECODER_SIZE);
|
||||
if (!itv->dec_mem) {
|
||||
IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n");
|
||||
IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n");
|
||||
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
|
||||
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
|
||||
retval = -ENOMEM;
|
||||
goto free_mem;
|
||||
goto free_worker;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1073,26 +1041,27 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
|
||||
/* map registers memory */
|
||||
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
|
||||
(u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
itv->reg_mem =
|
||||
ioremap(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
itv->reg_mem = devm_ioremap(&pdev->dev,
|
||||
itv->base_addr + IVTV_REG_OFFSET,
|
||||
IVTV_REG_SIZE);
|
||||
if (!itv->reg_mem) {
|
||||
IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n");
|
||||
IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n");
|
||||
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
|
||||
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
|
||||
retval = -ENOMEM;
|
||||
goto free_io;
|
||||
goto free_worker;
|
||||
}
|
||||
|
||||
retval = ivtv_gpio_init(itv);
|
||||
if (retval)
|
||||
goto free_io;
|
||||
goto free_worker;
|
||||
|
||||
/* active i2c */
|
||||
IVTV_DEBUG_INFO("activating i2c...\n");
|
||||
if (init_ivtv_i2c(itv)) {
|
||||
IVTV_ERR("Could not initialize i2c\n");
|
||||
goto free_io;
|
||||
goto free_worker;
|
||||
}
|
||||
|
||||
if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
|
||||
@ -1277,13 +1246,6 @@ free_irq:
|
||||
free_i2c:
|
||||
v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
|
||||
exit_ivtv_i2c(itv);
|
||||
free_io:
|
||||
ivtv_iounmap(itv);
|
||||
free_mem:
|
||||
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
|
||||
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
if (itv->has_cx23415)
|
||||
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
|
||||
free_worker:
|
||||
kthread_stop(itv->irq_worker_task);
|
||||
err:
|
||||
@ -1439,14 +1401,7 @@ static void ivtv_remove(struct pci_dev *pdev)
|
||||
exit_ivtv_i2c(itv);
|
||||
|
||||
free_irq(itv->pdev->irq, (void *)itv);
|
||||
ivtv_iounmap(itv);
|
||||
|
||||
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
|
||||
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
|
||||
if (itv->has_cx23415)
|
||||
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
|
||||
|
||||
pci_disable_device(itv->pdev);
|
||||
for (i = 0; i < IVTV_VBI_FRAMES; i++)
|
||||
kfree(itv->vbi.sliced_mpeg_data[i]);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ivtv-ioctl.h"
|
||||
#include "ivtv-cards.h"
|
||||
#include "ivtv-firmware.h"
|
||||
#include <linux/lockdep.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/i2c/saa7115.h>
|
||||
|
||||
@ -190,12 +191,27 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
|
||||
itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
|
||||
}
|
||||
|
||||
static void ivtv_schedule(struct ivtv_stream *s)
|
||||
{
|
||||
struct ivtv *itv = s->itv;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
lockdep_assert_held(&itv->serialize_lock);
|
||||
|
||||
mutex_unlock(&itv->serialize_lock);
|
||||
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
/* New buffers might have become free before we were added to the waitqueue */
|
||||
if (!s->q_free.buffers)
|
||||
schedule();
|
||||
finish_wait(&s->waitq, &wait);
|
||||
mutex_lock(&itv->serialize_lock);
|
||||
}
|
||||
|
||||
static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
|
||||
{
|
||||
struct ivtv *itv = s->itv;
|
||||
struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
|
||||
struct ivtv_buffer *buf;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
*err = 0;
|
||||
while (1) {
|
||||
@ -258,13 +274,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
|
||||
}
|
||||
|
||||
/* wait for more data to arrive */
|
||||
mutex_unlock(&itv->serialize_lock);
|
||||
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
/* New buffers might have become available before we were added to the waitqueue */
|
||||
if (!s->q_full.buffers)
|
||||
schedule();
|
||||
finish_wait(&s->waitq, &wait);
|
||||
mutex_lock(&itv->serialize_lock);
|
||||
ivtv_schedule(s);
|
||||
if (signal_pending(current)) {
|
||||
/* return if a signal was received */
|
||||
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
|
||||
@ -533,6 +543,25 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ivtv_schedule_dma(struct ivtv_stream *s)
|
||||
{
|
||||
struct ivtv *itv = s->itv;
|
||||
int got_sig;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
lockdep_assert_held(&itv->serialize_lock);
|
||||
|
||||
mutex_unlock(&itv->serialize_lock);
|
||||
prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
while (!(got_sig = signal_pending(current)) &&
|
||||
test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
|
||||
schedule();
|
||||
finish_wait(&itv->dma_waitq, &wait);
|
||||
mutex_lock(&itv->serialize_lock);
|
||||
|
||||
return got_sig;
|
||||
}
|
||||
|
||||
static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
|
||||
{
|
||||
struct ivtv_open_id *id = fh2id(filp->private_data);
|
||||
@ -544,7 +573,6 @@ static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t
|
||||
int bytes_written = 0;
|
||||
int mode;
|
||||
int rc;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
|
||||
|
||||
@ -618,13 +646,7 @@ retry:
|
||||
break;
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
mutex_unlock(&itv->serialize_lock);
|
||||
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
/* New buffers might have become free before we were added to the waitqueue */
|
||||
if (!s->q_free.buffers)
|
||||
schedule();
|
||||
finish_wait(&s->waitq, &wait);
|
||||
mutex_lock(&itv->serialize_lock);
|
||||
ivtv_schedule(s);
|
||||
if (signal_pending(current)) {
|
||||
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
|
||||
return -EINTR;
|
||||
@ -674,20 +696,10 @@ retry:
|
||||
|
||||
if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
|
||||
if (s->q_full.length >= itv->dma_data_req_size) {
|
||||
int got_sig;
|
||||
|
||||
if (mode == OUT_YUV)
|
||||
ivtv_yuv_setup_stream_frame(itv);
|
||||
|
||||
mutex_unlock(&itv->serialize_lock);
|
||||
prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
while (!(got_sig = signal_pending(current)) &&
|
||||
test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
|
||||
schedule();
|
||||
}
|
||||
finish_wait(&itv->dma_waitq, &wait);
|
||||
mutex_lock(&itv->serialize_lock);
|
||||
if (got_sig) {
|
||||
if (ivtv_schedule_dma(s)) {
|
||||
IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
|
||||
return -EINTR;
|
||||
}
|
||||
|
@ -131,6 +131,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
|
||||
|
||||
/* Fill SG List with new values */
|
||||
if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
|
||||
IVTV_DEBUG_WARN("%s: could not allocate bounce buffers for highmem userspace buffers\n",
|
||||
__func__);
|
||||
unpin_user_pages(dma->map, dma->page_count);
|
||||
dma->page_count = 0;
|
||||
return -ENOMEM;
|
||||
@ -139,6 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
|
||||
/* Map SG List */
|
||||
dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
|
||||
dma->page_count, DMA_TO_DEVICE);
|
||||
if (!dma->SG_length) {
|
||||
IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
|
||||
unpin_user_pages(dma->map, dma->page_count);
|
||||
dma->page_count = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Fill SG Array with new values */
|
||||
ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
|
||||
|
@ -114,6 +114,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
|
||||
}
|
||||
dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
|
||||
dma->page_count, DMA_TO_DEVICE);
|
||||
if (!dma->SG_length) {
|
||||
IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
|
||||
unpin_user_pages(dma->map, dma->page_count);
|
||||
dma->page_count = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Fill SG Array with new values */
|
||||
ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
|
||||
|
@ -104,6 +104,7 @@ MODULE_PARM_DESC(osd_xres,
|
||||
"\t\t\tdefault 640");
|
||||
|
||||
MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
|
||||
MODULE_DESCRIPTION("Conexant cx23415 framebuffer support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -281,10 +282,10 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
|
||||
/* Map User DMA */
|
||||
if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
|
||||
mutex_unlock(&itv->udma.lock);
|
||||
IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with pin_user_pages: %d bytes, %d pages returned\n",
|
||||
size_in_bytes, itv->udma.page_count);
|
||||
IVTVFB_WARN("%s, Error in ivtv_udma_setup: %d bytes, %d pages returned\n",
|
||||
__func__, size_in_bytes, itv->udma.page_count);
|
||||
|
||||
/* pin_user_pages must have failed completely */
|
||||
/* pin_user_pages or DMA must have failed completely */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
|
||||
if (stat & MANTIS_INT_RISCI) {
|
||||
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
|
||||
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
|
||||
tasklet_schedule(&mantis->tasklet);
|
||||
queue_work(system_bh_wq, &mantis->bh_work);
|
||||
}
|
||||
if (stat & MANTIS_INT_I2CDONE) {
|
||||
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
|
||||
|
@ -125,7 +125,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
|
||||
if (stat & MANTIS_INT_RISCI) {
|
||||
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
|
||||
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
|
||||
tasklet_schedule(&mantis->tasklet);
|
||||
queue_work(system_bh_wq, &mantis->bh_work);
|
||||
}
|
||||
if (stat & MANTIS_INT_I2CDONE) {
|
||||
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
|
||||
|
@ -125,7 +125,7 @@ struct mantis_pci {
|
||||
__le32 *risc_cpu;
|
||||
dma_addr_t risc_dma;
|
||||
|
||||
struct tasklet_struct tasklet;
|
||||
struct work_struct bh_work;
|
||||
spinlock_t intmask_lock;
|
||||
|
||||
struct i2c_adapter adapter;
|
||||
|
@ -200,9 +200,9 @@ void mantis_dma_stop(struct mantis_pci *mantis)
|
||||
}
|
||||
|
||||
|
||||
void mantis_dma_xfer(struct tasklet_struct *t)
|
||||
void mantis_dma_xfer(struct work_struct *t)
|
||||
{
|
||||
struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet);
|
||||
struct mantis_pci *mantis = from_work(mantis, t, bh_work);
|
||||
struct mantis_hwconfig *config = mantis->hwconfig;
|
||||
|
||||
while (mantis->last_block != mantis->busy_block) {
|
||||
|
@ -13,6 +13,6 @@ extern int mantis_dma_init(struct mantis_pci *mantis);
|
||||
extern int mantis_dma_exit(struct mantis_pci *mantis);
|
||||
extern void mantis_dma_start(struct mantis_pci *mantis);
|
||||
extern void mantis_dma_stop(struct mantis_pci *mantis);
|
||||
extern void mantis_dma_xfer(struct tasklet_struct *t);
|
||||
extern void mantis_dma_xfer(struct work_struct *t);
|
||||
|
||||
#endif /* __MANTIS_DMA_H */
|
||||
|
@ -105,7 +105,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
if (mantis->feeds == 1) {
|
||||
dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
|
||||
mantis_dma_start(mantis);
|
||||
tasklet_enable(&mantis->tasklet);
|
||||
enable_and_queue_work(system_bh_wq, &mantis->bh_work);
|
||||
}
|
||||
|
||||
return mantis->feeds;
|
||||
@ -125,7 +125,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
mantis->feeds--;
|
||||
if (mantis->feeds == 0) {
|
||||
dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
|
||||
tasklet_disable(&mantis->tasklet);
|
||||
disable_work_sync(&mantis->bh_work);
|
||||
mantis_dma_stop(mantis);
|
||||
}
|
||||
|
||||
@ -205,8 +205,8 @@ int mantis_dvb_init(struct mantis_pci *mantis)
|
||||
}
|
||||
|
||||
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
|
||||
tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
|
||||
tasklet_disable(&mantis->tasklet);
|
||||
INIT_WORK(&mantis->bh_work, mantis_dma_xfer);
|
||||
disable_work_sync(&mantis->bh_work);
|
||||
if (mantis->hwconfig) {
|
||||
result = config->frontend_init(mantis, mantis->fe);
|
||||
if (result < 0) {
|
||||
@ -235,7 +235,7 @@ int mantis_dvb_init(struct mantis_pci *mantis)
|
||||
|
||||
/* Error conditions .. */
|
||||
err5:
|
||||
tasklet_kill(&mantis->tasklet);
|
||||
cancel_work_sync(&mantis->bh_work);
|
||||
dvb_net_release(&mantis->dvbnet);
|
||||
if (mantis->fe) {
|
||||
dvb_unregister_frontend(mantis->fe);
|
||||
@ -273,7 +273,7 @@ int mantis_dvb_exit(struct mantis_pci *mantis)
|
||||
dvb_frontend_detach(mantis->fe);
|
||||
}
|
||||
|
||||
tasklet_kill(&mantis->tasklet);
|
||||
cancel_work_sync(&mantis->bh_work);
|
||||
dvb_net_release(&mantis->dvbnet);
|
||||
|
||||
mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
|
||||
|
@ -50,9 +50,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
/* nGene interrupt handler **************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static void event_tasklet(struct tasklet_struct *t)
|
||||
static void event_bh_work(struct work_struct *t)
|
||||
{
|
||||
struct ngene *dev = from_tasklet(dev, t, event_tasklet);
|
||||
struct ngene *dev = from_work(dev, t, event_bh_work);
|
||||
|
||||
while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
|
||||
struct EVENT_BUFFER Event =
|
||||
@ -68,9 +68,9 @@ static void event_tasklet(struct tasklet_struct *t)
|
||||
}
|
||||
}
|
||||
|
||||
static void demux_tasklet(struct tasklet_struct *t)
|
||||
static void demux_bh_work(struct work_struct *t)
|
||||
{
|
||||
struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet);
|
||||
struct ngene_channel *chan = from_work(chan, t, demux_bh_work);
|
||||
struct device *pdev = &chan->dev->pci_dev->dev;
|
||||
struct SBufferHeader *Cur = chan->nextBuffer;
|
||||
|
||||
@ -204,7 +204,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
|
||||
dev->EventQueueOverflowFlag = 1;
|
||||
}
|
||||
dev->EventBuffer->EventStatus &= ~0x80;
|
||||
tasklet_schedule(&dev->event_tasklet);
|
||||
queue_work(system_bh_wq, &dev->event_bh_work);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -217,8 +217,8 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
|
||||
ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
|
||||
dev->channel[i].nextBuffer->
|
||||
ngeneBuffer.SR.Flags |= 0x40;
|
||||
tasklet_schedule(
|
||||
&dev->channel[i].demux_tasklet);
|
||||
queue_work(system_bh_wq,
|
||||
&dev->channel[i].demux_bh_work);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev)
|
||||
struct device *pdev = &dev->pci_dev->dev;
|
||||
int i;
|
||||
|
||||
tasklet_setup(&dev->event_tasklet, event_tasklet);
|
||||
INIT_WORK(&dev->event_bh_work, event_bh_work);
|
||||
|
||||
memset_io(dev->iomem + 0xc000, 0x00, 0x220);
|
||||
memset_io(dev->iomem + 0xc400, 0x00, 0x100);
|
||||
@ -1395,7 +1395,7 @@ static void release_channel(struct ngene_channel *chan)
|
||||
if (chan->running)
|
||||
set_transfer(chan, 0);
|
||||
|
||||
tasklet_kill(&chan->demux_tasklet);
|
||||
cancel_work_sync(&chan->demux_bh_work);
|
||||
|
||||
if (chan->ci_dev) {
|
||||
dvb_unregister_device(chan->ci_dev);
|
||||
@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan)
|
||||
struct ngene_info *ni = dev->card_info;
|
||||
int io = ni->io_type[nr];
|
||||
|
||||
tasklet_setup(&chan->demux_tasklet, demux_tasklet);
|
||||
INIT_WORK(&chan->demux_bh_work, demux_bh_work);
|
||||
chan->users = 0;
|
||||
chan->type = io;
|
||||
chan->mode = chan->type; /* for now only one mode */
|
||||
@ -1649,7 +1649,7 @@ void ngene_remove(struct pci_dev *pdev)
|
||||
struct ngene *dev = pci_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
tasklet_kill(&dev->event_tasklet);
|
||||
cancel_work_sync(&dev->event_bh_work);
|
||||
for (i = MAX_STREAM - 1; i >= 0; i--)
|
||||
release_channel(&dev->channel[i]);
|
||||
if (dev->ci.en)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <media/dmxdev.h>
|
||||
#include <media/dvbdev.h>
|
||||
@ -621,7 +622,7 @@ struct ngene_channel {
|
||||
int users;
|
||||
struct video_device *v4l_dev;
|
||||
struct dvb_device *ci_dev;
|
||||
struct tasklet_struct demux_tasklet;
|
||||
struct work_struct demux_bh_work;
|
||||
|
||||
struct SBufferHeader *nextBuffer;
|
||||
enum KSSTATE State;
|
||||
@ -717,7 +718,7 @@ struct ngene {
|
||||
struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE];
|
||||
int EventQueueOverflowCount;
|
||||
int EventQueueOverflowFlag;
|
||||
struct tasklet_struct event_tasklet;
|
||||
struct work_struct event_bh_work;
|
||||
struct EVENT_BUFFER *EventBuffer;
|
||||
int EventQueueWriteIndex;
|
||||
int EventQueueReadIndex;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user