Merge 827060261c ("Merge tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media") into android-mainline

Steps on the way to 5.19-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Iaa8f0f3fc1f0374d0e098f2ac690af1acbbcfede
This commit is contained in:
Greg Kroah-Hartman 2022-06-07 18:20:54 +02:00
commit b7ffc57a95
332 changed files with 14153 additions and 3834 deletions

View file

@ -9,14 +9,14 @@ digraph board {
n00000003:port0 -> n00000008:port0 [style=bold]
n00000003:port0 -> n0000000f [style=bold]
n00000005 [label="{{<port0> 0} | Debayer A\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000005:port1 -> n00000017:port0
n00000005:port1 -> n00000015:port0
n00000008 [label="{{<port0> 0} | Debayer B\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000008:port1 -> n00000017:port0 [style=dashed]
n00000008:port1 -> n00000015:port0 [style=dashed]
n0000000b [label="Raw Capture 0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
n0000000f [label="Raw Capture 1\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
n00000013 [label="RGB/YUV Input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
n00000013 -> n00000017:port0 [style=dashed]
n00000017 [label="{{<port0> 0} | Scaler\n/dev/v4l-subdev4 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000017:port1 -> n0000001a [style=bold]
n0000001a [label="RGB/YUV Capture\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
n00000013 [label="{{} | RGB/YUV Input\n/dev/v4l-subdev4 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
n00000013:port0 -> n00000015:port0 [style=dashed]
n00000015 [label="{{<port0> 0} | Scaler\n/dev/v4l-subdev5 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000015:port1 -> n00000018 [style=bold]
n00000018 [label="RGB/YUV Capture\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
}

View file

@ -1,9 +0,0 @@
Dongwoon Anatech DW9807 voice coil lens driver
DW9807 is a 10-bit DAC with current sink capability. It is intended for
controlling voice coil lenses.
Mandatory properties:
- compatible: "dongwoon,dw9807-vcm"
- reg: I2C slave address

View file

@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2018, 2021 Intel Corporation
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9807-vcm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dongwoon Anatech DW9807 voice coil lens driver
maintainers:
- Sakari Ailus <sakari.ailus@linux.intel.com>
description: |
DW9807 is a 10-bit DAC with current sink capability. It is intended for
controlling voice coil lenses.
properties:
compatible:
const: dongwoon,dw9807-vcm
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
lens@e {
compatible = "dongwoon,dw9807-vcm";
reg = <0x0e>;
};
};
...

View file

@ -32,6 +32,15 @@ properties:
description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz
maxItems: 1
dovdd-supply:
description: Interface power supply.
avdd-supply:
description: Analog power supply.
dvdd-supply:
description: Digital power supply.
reset-gpios:
description: Reference to the GPIO connected to the XCLR pin, if any.
maxItems: 1

View file

@ -63,6 +63,9 @@ properties:
description:
Describes point to scp.
power-domains:
maxItems: 1
required:
- compatible
- reg

View file

@ -47,7 +47,9 @@ description: |
properties:
compatible:
const: mediatek,mt8192-vcodec-dec
enum:
- mediatek,mt8192-vcodec-dec
- mediatek,mt8186-vcodec-dec
reg:
maxItems: 1

View file

@ -67,7 +67,7 @@ properties:
remote-endpoint: true
bus-width:
enum: [8, 9, 10, 11, 12]
enum: [8, 9, 10, 11, 12, 14]
default: 12
hsync-active:

View file

@ -18,7 +18,9 @@ properties:
oneOf:
- const: rockchip,rk3399-vdec
- items:
- const: rockchip,rk3228-vdec
- enum:
- rockchip,rk3228-vdec
- rockchip,rk3328-vdec
- const: rockchip,rk3399-vdec
reg:

View file

@ -23,6 +23,7 @@ properties:
- rockchip,rk3328-vpu
- rockchip,rk3399-vpu
- rockchip,px30-vpu
- rockchip,rk3568-vpu
- items:
- const: rockchip,rk3188-vpu
- const: rockchip,rk3066-vpu

View file

@ -93,6 +93,7 @@ properties:
- 4 # MIPI CSI-2 D-PHY
- 5 # Parallel
- 6 # BT.656
- 7 # DPI
description:
Data bus type.

View file

@ -18,6 +18,7 @@ description:
properties:
compatible:
enum:
- qcom,sc8180x-lmh
- qcom,sdm845-lmh
- qcom,sm8150-lmh

View file

@ -10,7 +10,9 @@ maintainers:
properties:
compatible:
const: qcom,spmi-adc-tm5
enum:
- qcom,spmi-adc-tm5
- qcom,spmi-adc-tm5-gen2
reg:
maxItems: 1
@ -33,6 +35,7 @@ properties:
qcom,avg-samples:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of samples to be used for measurement.
Not applicable for Gen2 ADC_TM peripheral.
enum:
- 1
- 2
@ -45,6 +48,7 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: This parameter is used to decrease ADC sampling rate.
Quicker measurements can be made by reducing decimation ratio.
Not applicable for Gen2 ADC_TM peripheral.
enum:
- 250
- 420
@ -93,6 +97,29 @@ patternProperties:
- const: 1
- enum: [ 1, 3, 4, 6, 20, 8, 10 ]
qcom,avg-samples:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of samples to be used for measurement.
This property in child node is applicable only for Gen2 ADC_TM peripheral.
enum:
- 1
- 2
- 4
- 8
- 16
default: 1
qcom,decimation:
$ref: /schemas/types.yaml#/definitions/uint32
description: This parameter is used to decrease ADC sampling rate.
Quicker measurements can be made by reducing decimation ratio.
This property in child node is applicable only for Gen2 ADC_TM peripheral.
enum:
- 85
- 340
- 1360
default: 1360
required:
- reg
- io-channels
@ -100,6 +127,31 @@ patternProperties:
additionalProperties:
false
allOf:
- if:
properties:
compatible:
contains:
const: qcom,spmi-adc-tm5
then:
patternProperties:
"^([-a-z0-9]*)@[0-7]$":
properties:
qcom,decimation: false
qcom,avg-samples: false
- if:
properties:
compatible:
contains:
const: qcom,spmi-adc-tm5-gen2
then:
properties:
qcom,avg-samples: false
qcom,decimation: false
required:
- compatible
- reg
@ -124,7 +176,7 @@ examples:
#size-cells = <0>;
#io-channel-cells = <1>;
/* Other propreties are omitted */
/* Other properties are omitted */
conn-therm@4f {
reg = <ADC5_AMUX_THM3_100K_PU>;
qcom,ratiometric;
@ -148,4 +200,58 @@ examples:
};
};
};
- |
#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
#address-cells = <1>;
#size-cells = <0>;
pmk8350_vadc: adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc7";
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
/* Other properties are omitted */
xo-therm@44 {
reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
};
conn-therm@47 {
reg = <PM8350_ADC7_AMUX_THM4_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
};
};
pmk8350_adc_tm: adc-tm@3400 {
compatible = "qcom,spmi-adc-tm5-gen2";
reg = <0x3400>;
interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
#thermal-sensor-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
pmk8350-xo-therm@0 {
reg = <0>;
io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>;
qcom,decimation = <340>;
qcom,ratiometric;
qcom,hw-settle-time-us = <200>;
};
conn-therm@1 {
reg = <1>;
io-channels = <&pmk8350_vadc PM8350_ADC7_AMUX_THM4_100K_PU>;
qcom,avg-samples = <2>;
qcom,ratiometric;
qcom,hw-settle-time-us = <200>;
};
};
};
...

View file

@ -19,10 +19,11 @@ description: |
properties:
compatible:
oneOf:
- description: msm9860 TSENS based
- description: msm8960 TSENS based
items:
- enum:
- qcom,ipq8064-tsens
- qcom,msm8960-tsens
- description: v0.1 of TSENS
items:
@ -49,6 +50,7 @@ properties:
- qcom,sc7180-tsens
- qcom,sc7280-tsens
- qcom,sc8180x-tsens
- qcom,sc8280xp-tsens
- qcom,sdm630-tsens
- qcom,sdm845-tsens
- qcom,sm8150-tsens
@ -116,6 +118,7 @@ allOf:
- qcom,ipq8064-tsens
- qcom,mdm9607-tsens
- qcom,msm8916-tsens
- qcom,msm8960-tsens
- qcom,msm8974-tsens
- qcom,msm8976-tsens
- qcom,qcs404-tsens

View file

@ -17,7 +17,9 @@ properties:
compatible:
items:
- enum:
- renesas,r9a07g043-tsu # RZ/G2UL
- renesas,r9a07g044-tsu # RZ/G2{L,LC}
- renesas,r9a07g054-tsu # RZ/V2L
- const: renesas,rzg2l-tsu
reg:

View file

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/ti,j72xx-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments J72XX VTM (DTS) binding
maintainers:
- Keerthy <j-keerthy@ti.com>
properties:
compatible:
enum:
- ti,j721e-vtm
- ti,j7200-vtm
reg:
items:
- description: VTM cfg1 register space
- description: VTM cfg2 register space
- description: VTM efuse register space
power-domains:
maxItems: 1
"#thermal-sensor-cells":
const: 1
required:
- compatible
- reg
- power-domains
- "#thermal-sensor-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/ti,sci_pm_domain.h>
wkup_vtm0: thermal-sensor@42040000 {
compatible = "ti,j721e-vtm";
reg = <0x42040000 0x350>,
<0x42050000 0x350>,
<0x43000300 0x10>;
power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>;
#thermal-sensor-cells = <1>;
};
mpu_thermal: mpu-thermal {
polling-delay-passive = <250>; /* milliseconds */
polling-delay = <500>; /* milliseconds */
thermal-sensors = <&wkup_vtm0 0>;
trips {
mpu_crit: mpu-crit {
temperature = <125000>; /* milliCelsius */
hysteresis = <2000>; /* milliCelsius */
type = "critical";
};
};
};
...

View file

@ -109,6 +109,7 @@ your driver:
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable);
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
void (*adap_configured)(struct cec_adapter *adap, bool configured);
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg);
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
@ -117,7 +118,7 @@ your driver:
/* Error injection callbacks */
...
/* High-level callbacks */
/* High-level callback */
...
};
@ -178,6 +179,16 @@ can receive directed messages to that address.
Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID.
Called when the adapter is fully configured or unconfigured::
void (*adap_configured)(struct cec_adapter *adap, bool configured);
If configured == true, then the adapter is fully configured, i.e. all logical
addresses have been successfully claimed. If configured == false, then the
adapter is unconfigured. If the driver has to take specific actions after
(un)configuration, then that can be done through this optional callback.
To transmit a new message::
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,

View file

@ -42,9 +42,16 @@ Allocation of the structure is handled by the media device driver, usually by
embedding the :c:type:`media_device` instance in a larger driver-specific
structure.
Drivers register media device instances by calling
:c:func:`__media_device_register()` via the macro ``media_device_register()``
and unregistered by calling :c:func:`media_device_unregister()`.
Drivers initialise media device instances by calling
:c:func:`media_device_init()`. After initialising a media device instance, it is
registered by calling :c:func:`__media_device_register()` via the macro
``media_device_register()`` and unregistered by calling
:c:func:`media_device_unregister()`. An initialised media device must be
eventually cleaned up by calling :c:func:`media_device_cleanup()`.
Note that it is not allowed to unregister a media device instance that was not
previously registered, or clean up a media device instance that was not
previously initialised.
Entities
^^^^^^^^

View file

@ -518,6 +518,75 @@ The :c:func:`v4l2_i2c_new_subdev` function will call
:c:type:`i2c_board_info` structure using the ``client_type`` and the
``addr`` to fill it.
Centrally managed subdev active state
-------------------------------------
Traditionally V4L2 subdev drivers maintained internal state for the active
device configuration. This is often implemented as e.g. an array of struct
v4l2_mbus_framefmt, one entry for each pad, and similarly for crop and compose
rectangles.
In addition to the active configuration, each subdev file handle has an array of
struct v4l2_subdev_pad_config, managed by the V4L2 core, which contains the try
configuration.
To simplify the subdev drivers the V4L2 subdev API now optionally supports a
centrally managed active configuration represented by
:c:type:`v4l2_subdev_state`. One instance of state, which contains the active
device configuration, is stored in the sub-device itself as part of
the :c:type:`v4l2_subdev` structure, while the core associates a try state to
each open file handle, to store the try configuration related to that file
handle.
Sub-device drivers can opt-in and use state to manage their active configuration
by initializing the subdevice state with a call to v4l2_subdev_init_finalize()
before registering the sub-device. They must also call v4l2_subdev_cleanup()
to release all the allocated resources before unregistering the sub-device.
The core automatically allocates and initializes a state for each open file
handle to store the try configurations and frees it when closing the file
handle.
V4L2 sub-device operations that use both the :ref:`ACTIVE and TRY formats
<v4l2-subdev-format-whence>` receive the correct state to operate on through
the 'state' parameter. The state must be locked and unlocked by the
caller by calling :c:func:`v4l2_subdev_lock_state()` and
:c:func:`v4l2_subdev_unlock_state()`. The caller can do so by calling the subdev
operation through the :c:func:`v4l2_subdev_call_state_active()` macro.
Operations that do not receive a state parameter implicitly operate on the
subdevice active state, which drivers can exclusively access by
calling :c:func:`v4l2_subdev_lock_and_get_active_state()`. The sub-device active
state must equally be released by calling :c:func:`v4l2_subdev_unlock_state()`.
Drivers must never manually access the state stored in the :c:type:`v4l2_subdev`
or in the file handle without going through the designated helpers.
While the V4L2 core passes the correct try or active state to the subdevice
operations, many existing device drivers pass a NULL state when calling
operations with :c:func:`v4l2_subdev_call()`. This legacy construct causes
issues with subdevice drivers that let the V4L2 core manage the active state,
as they expect to receive the appropriate state as a parameter. To help the
conversion of subdevice drivers to a managed active state without having to
convert all callers at the same time, an additional wrapper layer has been
added to v4l2_subdev_call(), which handles the NULL case by geting and locking
the callee's active state with :c:func:`v4l2_subdev_lock_and_get_active_state()`,
and unlocking the state after the call.
The whole subdev state is in reality split into three parts: the
v4l2_subdev_state, subdev controls and subdev driver's internal state. In the
future these parts should be combined into a single state. For the time being
we need a way to handle the locking for these parts. This can be accomplished
by sharing a lock. The v4l2_ctrl_handler already supports this via its 'lock'
pointer and the same model is used with states. The driver can do the following
before calling v4l2_subdev_init_finalize():
.. code-block:: c
sd->ctrl_handler->lock = &priv->mutex;
sd->state_lock = &priv->mutex;
This shares the driver's private mutex between the controls and the states.
V4L2 sub-device functions and data structures
---------------------------------------------

View file

@ -7,7 +7,7 @@ This file documents some driver-specific aspects of the UVC driver, such as
driver-specific ioctls and implementation notes.
Questions and remarks can be sent to the Linux UVC development mailing list at
linux-uvc-devel@lists.berlios.de.
linux-media@vger.kernel.org.
Extension Unit (XU) support

View file

@ -33,3 +33,9 @@ are:
- An **interface link** is a point-to-point bidirectional control
connection between a Linux Kernel interface and an entity.
- An **ancillary link** is a point-to-point connection denoting that two
entities form a single logical unit. For example this could represent the
fact that a particular camera sensor and lens controller form a single
physical module, meaning this lens controller drives the lens for this
camera sensor.

View file

@ -412,14 +412,21 @@ must be set for every pad.
is set by drivers and is read-only for applications.
* - ``MEDIA_LNK_FL_LINK_TYPE``
- This is a bitmask that defines the type of the link. Currently,
two types of links are supported:
- This is a bitmask that defines the type of the link. The following
link types are currently supported:
.. _MEDIA-LNK-FL-DATA-LINK:
``MEDIA_LNK_FL_DATA_LINK`` if the link is between two pads
``MEDIA_LNK_FL_DATA_LINK`` for links that represent a data connection
between two pads.
.. _MEDIA-LNK-FL-INTERFACE-LINK:
``MEDIA_LNK_FL_INTERFACE_LINK`` if the link is between an
interface and an entity
``MEDIA_LNK_FL_INTERFACE_LINK`` for links that associate an entity to its
interface.
.. _MEDIA-LNK-FL-ANCILLARY-LINK:
``MEDIA_LNK_FL_ANCILLARY_LINK`` for links that represent a physical
relationship between two entities. The link may or may not be
immutable, so applications must not assume either case.

View file

@ -72,6 +72,12 @@ coded resolution
coded width
width for given coded resolution.
coding tree unit
processing unit of the HEVC codec (corresponds to macroblock units in
H.264, VP8, VP9),
can use block structures of up to 64×64 pixels.
Good at sub-partitioning the picture into variable sized structures.
decode order
the order in which frames are decoded; may differ from display order if the
coded format includes a feature of frame reordering; for decoders,
@ -104,7 +110,8 @@ keyframe
macroblock
a processing unit in image and video compression formats based on linear
block transforms (e.g. H.264, VP8, VP9); codec-specific, but for most of
popular codecs the size is 16x16 samples (pixels).
popular codecs the size is 16x16 samples (pixels). The HEVC codec uses a
slightly more flexible processing unit called coding tree unit (CTU).
OUTPUT
the source buffer queue; for decoders, the queue of buffers containing

View file

@ -649,10 +649,16 @@ Stateless Codec Control ID
:c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
* - __u32
- ``pic_num``
-
- For short term references, this must match the derived value PicNum
(8-28) and for long term references it must match the derived value
LongTermPicNum (8-29). When decoding frames (as opposed to fields)
pic_num is the same as FrameNumWrap.
* - __u16
- ``frame_num``
-
- For short term references, this must match the frame_num value from
the slice header syntax (the driver will wrap the value if needed). For
long term references, this must be set to the value of
long_term_frame_idx described in the dec_ref_pic_marking() syntax.
* - __u8
- ``fields``
- Specifies how the DPB entry is referenced. See :ref:`Reference Fields <h264_ref_fields>`

View file

@ -1180,6 +1180,28 @@ enum v4l2_mpeg_video_h264_entropy_mode -
is set to non zero value.
Applicable to H264, H263 and MPEG4 encoder.
``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE (enum)``
enum v4l2_mpeg_video_intra_refresh_period_type -
Sets the type of intra refresh. The period to refresh
the whole frame is specified by V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD.
Note that if this control is not present, then it is undefined what
refresh type is used and it is up to the driver to decide.
Applicable to H264 and HEVC encoders. Possible values are:
.. tabularcolumns:: |p{9.6cm}|p{7.9cm}|
.. flat-table::
:header-rows: 0
:stub-columns: 0
* - ``V4L2_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM``
- The whole frame is completely refreshed randomly
after the specified period.
* - ``V4L2_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC``
- The whole frame MBs are completely refreshed in cyclic order
after the specified period.
``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (integer)``
Intra macroblock refresh period. This sets the period to refresh
the whole frame. In other words, this defines the number of frames

View file

@ -239,6 +239,25 @@ please make a proposal on the linux-media mailing list.
It remains an opaque intermediate format and the MDP hardware must be
used to convert ``V4L2_PIX_FMT_MT21C`` to ``V4L2_PIX_FMT_NV12M``,
``V4L2_PIX_FMT_YUV420M`` or ``V4L2_PIX_FMT_YVU420``.
* .. _V4L2-PIX-FMT-QC08C:
- ``V4L2_PIX_FMT_QC08C``
- 'QC08C'
- Compressed Macro-tile 8-Bit YUV420 format used by Qualcomm platforms.
It is an opaque intermediate format. The used compression is lossless
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video and eight planes for
interlaced video.
* .. _V4L2-PIX-FMT-QC10C:
- ``V4L2_PIX_FMT_QC10C``
- 'QC10C'
- Compressed Macro-tile 10-Bit YUV420 format used by Qualcomm platforms.
It is an opaque intermediate format. The used compression is lossless
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video.
.. raw:: latex
\normalsize

View file

@ -48,6 +48,17 @@ are often referred to as greyscale formats.
- ...
- ...
* .. _V4L2-PIX-FMT-IPU3-Y10:
- ``V4L2_PIX_FMT_IPU3_Y10``
- 'ip3y'
- Y'\ :sub:`0`\ [7:0]
- Y'\ :sub:`1`\ [5:0] Y'\ :sub:`0`\ [9:8]
- Y'\ :sub:`2`\ [3:0] Y'\ :sub:`1`\ [9:6]
- Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [9:4]
- Y'\ :sub:`3`\ [9:2]
* .. _V4L2-PIX-FMT-Y10:
- ``V4L2_PIX_FMT_Y10``
@ -133,4 +144,5 @@ are often referred to as greyscale formats.
For the Y16 and Y16_BE formats, the actual sampling precision may be lower
than 16 bits. For example, 10 bits per pixel uses values in the range 0 to
1023.
1023. For the IPU3_Y10 format 25 pixels are packed into 32 bytes, which
leaves the 6 most significant bits of the last byte padded with 0.

View file

@ -43,8 +43,7 @@ the capture or output process during streaming
Capture hardware is disabled and no input buffers are filled (if there
are any empty buffers in the incoming queue) until ``VIDIOC_STREAMON``
has been called. Output hardware is disabled and no video signal is
produced until ``VIDIOC_STREAMON`` has been called. The ioctl will
succeed when at least one output buffer is in the incoming queue.
produced until ``VIDIOC_STREAMON`` has been called.
Memory-to-memory devices will not start until ``VIDIOC_STREAMON`` has
been called for both the capture and output stream types.

View file

@ -12201,7 +12201,7 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/admin-guide/media/imx7.rst
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
F: drivers/media/platform/imx/imx-mipi-csis.c
F: drivers/media/platform/nxp/imx-mipi-csis.c
F: drivers/staging/media/imx/imx7-media-csi.c
MEDIA DRIVERS FOR HELENE
@ -12256,7 +12256,7 @@ L: linux-media@vger.kernel.org
L: linux-tegra@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
F: drivers/media/platform/nvidia/tegra-vde/
MEDIA DRIVERS FOR RENESAS - CEU
@ -12419,10 +12419,9 @@ F: drivers/iommu/mtk_iommu*
F: include/dt-bindings/memory/mt*-port.h
MEDIATEK JPEG DRIVER
M: Rick Chang <rick.chang@mediatek.com>
M: Bin Liu <bin.liu@mediatek.com>
S: Supported
F: Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
F: Documentation/devicetree/bindings/media/mediatek-jpeg-*.yaml
F: drivers/media/platform/mediatek/jpeg/
MEDIATEK MDP DRIVER
@ -12438,7 +12437,7 @@ MEDIATEK MEDIA DRIVER
M: Tiffany Lin <tiffany.lin@mediatek.com>
M: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
S: Supported
F: Documentation/devicetree/bindings/media/mediatek-vcodec.txt
F: Documentation/devicetree/bindings/media/mediatek,vcodec*.yaml
F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
F: drivers/media/platform/mediatek/vcodec/
F: drivers/media/platform/mediatek/vpu/
@ -14253,7 +14252,7 @@ R: NXP Linux Team <linux-imx@nxp.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
F: drivers/media/platform/imx-jpeg
F: drivers/media/platform/nxp/imx-jpeg
NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
M: Jonas Malaco <jonas@protocubo.io>
@ -19596,6 +19595,7 @@ F: drivers/thermal/
F: include/linux/cpu_cooling.h
F: include/linux/thermal.h
F: include/uapi/linux/thermal.h
F: tools/lib/thermal/
F: tools/thermal/
THERMAL DRIVER FOR AMLOGIC SOCS
@ -20589,7 +20589,6 @@ F: drivers/usb/host/uhci*
USB VIDEO CLASS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-uvc-devel@lists.sourceforge.net (subscribers-only)
L: linux-media@vger.kernel.org
S: Maintained
W: http://www.ideasonboard.org/uvc/

View file

@ -433,6 +433,16 @@ void acpi_init_properties(struct acpi_device *adev)
acpi_extract_apple_properties(adev);
}
static void acpi_free_device_properties(struct list_head *list)
{
struct acpi_device_properties *props, *tmp;
list_for_each_entry_safe(props, tmp, list, list) {
list_del(&props->list);
kfree(props);
}
}
static void acpi_destroy_nondev_subnodes(struct list_head *list)
{
struct acpi_data_node *dn, *next;
@ -445,22 +455,18 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list)
wait_for_completion(&dn->kobj_done);
list_del(&dn->sibling);
ACPI_FREE((void *)dn->data.pointer);
acpi_free_device_properties(&dn->data.properties);
kfree(dn);
}
}
void acpi_free_properties(struct acpi_device *adev)
{
struct acpi_device_properties *props, *tmp;
acpi_destroy_nondev_subnodes(&adev->data.subnodes);
ACPI_FREE((void *)adev->data.pointer);
adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
list_del(&props->list);
kfree(props);
}
acpi_free_device_properties(&adev->data.properties);
}
/**
@ -1256,6 +1262,24 @@ static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
return acpi_device_is_present(to_acpi_device_node(fwnode));
}
static const void *
acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
const struct device *dev)
{
return acpi_device_get_match_data(dev);
}
static bool acpi_fwnode_device_dma_supported(const struct fwnode_handle *fwnode)
{
return acpi_dma_supported(to_acpi_device_node(fwnode));
}
static enum dev_dma_attr
acpi_fwnode_device_get_dma_attr(const struct fwnode_handle *fwnode)
{
return acpi_get_dma_attr(to_acpi_device_node(fwnode));
}
static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
const char *propname)
{
@ -1376,17 +1400,26 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
return 0;
}
static const void *
acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
const struct device *dev)
static int acpi_fwnode_irq_get(const struct fwnode_handle *fwnode,
unsigned int index)
{
return acpi_device_get_match_data(dev);
struct resource res;
int ret;
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
if (ret)
return ret;
return res.start;
}
#define DECLARE_ACPI_FWNODE_OPS(ops) \
const struct fwnode_operations ops = { \
.device_is_available = acpi_fwnode_device_is_available, \
.device_get_match_data = acpi_fwnode_device_get_match_data, \
.device_dma_supported = \
acpi_fwnode_device_dma_supported, \
.device_get_dma_attr = acpi_fwnode_device_get_dma_attr, \
.property_present = acpi_fwnode_property_present, \
.property_read_int_array = \
acpi_fwnode_property_read_int_array, \
@ -1404,6 +1437,7 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
acpi_graph_get_remote_endpoint, \
.graph_get_port_parent = acpi_fwnode_get_parent, \
.graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
.irq_get = acpi_fwnode_irq_get, \
}; \
EXPORT_SYMBOL_GPL(ops)

View file

@ -969,6 +969,7 @@ bool pm_wakeup_pending(void)
return ret || atomic_read(&pm_abort_suspend) > 0;
}
EXPORT_SYMBOL_GPL(pm_wakeup_pending);
void pm_system_wakeup(void)
{

View file

@ -47,12 +47,14 @@ bool fwnode_property_present(const struct fwnode_handle *fwnode,
{
bool ret;
if (IS_ERR_OR_NULL(fwnode))
return false;
ret = fwnode_call_bool_op(fwnode, property_present, propname);
if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_bool_op(fwnode->secondary, property_present,
propname);
return ret;
if (ret)
return ret;
return fwnode_call_bool_op(fwnode->secondary, property_present, propname);
}
EXPORT_SYMBOL_GPL(fwnode_property_present);
@ -66,6 +68,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_present);
* Function reads an array of u8 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* It's recommended to call device_property_count_u8() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -91,6 +96,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
* Function reads an array of u16 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* It's recommended to call device_property_count_u16() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -116,6 +124,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
* Function reads an array of u32 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* It's recommended to call device_property_count_u32() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -141,6 +152,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
* Function reads an array of u64 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* It's recommended to call device_property_count_u64() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -166,6 +180,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
* Function reads an array of string properties with @propname from the device
* firmware description and stores them to @val if found.
*
* It's recommended to call device_property_string_array_count() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values read on success if @val is non-NULL,
* number of values available on success if @val is NULL,
* %-EINVAL if given arguments are not valid,
@ -232,15 +249,16 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
{
int ret;
if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
elem_size, val, nval);
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_int_op(
fwnode->secondary, property_read_int_array, propname,
elem_size, val, nval);
if (ret != -EINVAL)
return ret;
return ret;
return fwnode_call_int_op(fwnode->secondary, property_read_int_array, propname,
elem_size, val, nval);
}
/**
@ -253,6 +271,9 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
* Read an array of u8 properties with @propname from @fwnode and stores them to
* @val if found.
*
* It's recommended to call fwnode_property_count_u8() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -279,6 +300,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
* Read an array of u16 properties with @propname from @fwnode and store them to
* @val if found.
*
* It's recommended to call fwnode_property_count_u16() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -305,6 +329,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
* Read an array of u32 properties with @propname from @fwnode store them to
* @val if found.
*
* It's recommended to call fwnode_property_count_u32() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -331,6 +358,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
* Read an array of u64 properties with @propname from @fwnode and store them to
* @val if found.
*
* It's recommended to call fwnode_property_count_u64() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
@ -357,6 +387,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
* Read an string list property @propname from the given firmware node and store
* them to @val if found.
*
* It's recommended to call fwnode_property_string_array_count() instead of calling
* this function with @val equals %NULL and @nval equals 0.
*
* Return: number of values read on success if @val is non-NULL,
* number of values available on success if @val is NULL,
* %-EINVAL if given arguments are not valid,
@ -371,14 +404,16 @@ int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
{
int ret;
if (IS_ERR_OR_NULL(fwnode))
return -EINVAL;
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
val, nval);
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_int_op(fwnode->secondary,
property_read_string_array, propname,
val, nval);
return ret;
if (ret != -EINVAL)
return ret;
return fwnode_call_int_op(fwnode->secondary, property_read_string_array, propname,
val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
@ -480,15 +515,19 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
{
int ret;
if (IS_ERR_OR_NULL(fwnode))
return -ENOENT;
ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
nargs, index, args);
if (ret == 0)
return ret;
if (ret < 0 && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_int_op(fwnode->secondary, get_reference_args,
prop, nargs_prop, nargs, index, args);
if (IS_ERR_OR_NULL(fwnode->secondary))
return ret;
return ret;
return fwnode_call_int_op(fwnode->secondary, get_reference_args, prop, nargs_prop,
nargs, index, args);
}
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
@ -587,17 +626,17 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
*/
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
{
struct fwnode_handle *parent;
struct device *dev;
fwnode_handle_get(fwnode);
do {
fwnode = fwnode_get_next_parent(fwnode);
if (!fwnode)
return NULL;
dev = get_dev_from_fwnode(fwnode);
} while (!dev);
fwnode_handle_put(fwnode);
return dev;
fwnode_for_each_parent_node(fwnode, parent) {
dev = get_dev_from_fwnode(parent);
if (dev) {
fwnode_handle_put(parent);
return dev;
}
}
return NULL;
}
/**
@ -608,13 +647,11 @@ struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
*/
unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
{
struct fwnode_handle *__fwnode;
unsigned int count;
struct fwnode_handle *parent;
unsigned int count = 0;
__fwnode = fwnode_get_parent(fwnode);
for (count = 0; __fwnode; count++)
__fwnode = fwnode_get_next_parent(__fwnode);
fwnode_for_each_parent_node(fwnode, parent)
count++;
return count;
}
@ -635,40 +672,43 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents);
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
unsigned int depth)
{
unsigned int i;
struct fwnode_handle *parent;
fwnode_handle_get(fwnode);
if (depth == 0)
return fwnode_handle_get(fwnode);
for (i = 0; i < depth && fwnode; i++)
fwnode = fwnode_get_next_parent(fwnode);
return fwnode;
fwnode_for_each_parent_node(fwnode, parent) {
if (--depth == 0)
return parent;
}
return NULL;
}
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
/**
* fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child
* @test_ancestor: Firmware which is tested for being an ancestor
* @test_child: Firmware which is tested for being the child
* fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
* @ancestor: Firmware which is tested for being an ancestor
* @child: Firmware which is tested for being the child
*
* A node is considered an ancestor of itself too.
*
* Returns true if @test_ancestor is an ancestor of @test_child.
* Otherwise, returns false.
* Returns true if @ancestor is an ancestor of @child. Otherwise, returns false.
*/
bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
struct fwnode_handle *test_child)
bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle *child)
{
if (!test_ancestor)
struct fwnode_handle *parent;
if (IS_ERR_OR_NULL(ancestor))
return false;
fwnode_handle_get(test_child);
while (test_child) {
if (test_child == test_ancestor) {
fwnode_handle_put(test_child);
if (child == ancestor)
return true;
fwnode_for_each_parent_node(child, parent) {
if (parent == ancestor) {
fwnode_handle_put(parent);
return true;
}
test_child = fwnode_get_next_parent(test_child);
}
return false;
}
@ -698,7 +738,7 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
{
struct fwnode_handle *next_child = child;
if (!fwnode)
if (IS_ERR_OR_NULL(fwnode))
return NULL;
do {
@ -722,16 +762,16 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
const struct fwnode_handle *fwnode = dev_fwnode(dev);
struct fwnode_handle *next;
if (IS_ERR_OR_NULL(fwnode))
return NULL;
/* Try to find a child in primary fwnode */
next = fwnode_get_next_child_node(fwnode, child);
if (next)
return next;
/* When no more children in primary, continue with secondary */
if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
next = fwnode_get_next_child_node(fwnode->secondary, child);
return next;
return fwnode_get_next_child_node(fwnode->secondary, child);
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
@ -798,6 +838,9 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
*/
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
{
if (IS_ERR_OR_NULL(fwnode))
return false;
if (!fwnode_has_op(fwnode, device_is_available))
return true;
@ -823,33 +866,16 @@ EXPORT_SYMBOL_GPL(device_get_child_node_count);
bool device_dma_supported(struct device *dev)
{
const struct fwnode_handle *fwnode = dev_fwnode(dev);
/* For DT, this is always supported.
* For ACPI, this depends on CCA, which
* is determined by the acpi_dma_supported().
*/
if (is_of_node(fwnode))
return true;
return acpi_dma_supported(to_acpi_device_node(fwnode));
return fwnode_call_bool_op(dev_fwnode(dev), device_dma_supported);
}
EXPORT_SYMBOL_GPL(device_dma_supported);
enum dev_dma_attr device_get_dma_attr(struct device *dev)
{
const struct fwnode_handle *fwnode = dev_fwnode(dev);
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
if (!fwnode_has_op(dev_fwnode(dev), device_get_dma_attr))
return DEV_DMA_NOT_SUPPORTED;
if (is_of_node(fwnode)) {
if (of_dma_is_coherent(to_of_node(fwnode)))
attr = DEV_DMA_COHERENT;
else
attr = DEV_DMA_NON_COHERENT;
} else
attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
return attr;
return fwnode_call_int_op(dev_fwnode(dev), device_get_dma_attr);
}
EXPORT_SYMBOL_GPL(device_get_dma_attr);
@ -904,10 +930,7 @@ EXPORT_SYMBOL_GPL(device_get_phy_mode);
*/
void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index)
{
if (IS_ENABLED(CONFIG_OF_ADDRESS) && is_of_node(fwnode))
return of_iomap(to_of_node(fwnode), index);
return NULL;
return fwnode_call_ptr_op(fwnode, iomap, index);
}
EXPORT_SYMBOL(fwnode_iomap);
@ -921,17 +944,7 @@ EXPORT_SYMBOL(fwnode_iomap);
*/
int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index)
{
struct resource res;
int ret;
if (is_of_node(fwnode))
return of_irq_get(to_of_node(fwnode), index);
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
if (ret)
return ret;
return res.start;
return fwnode_call_int_op(fwnode, irq_get, index);
}
EXPORT_SYMBOL(fwnode_irq_get);
@ -988,14 +1001,14 @@ fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
parent = fwnode_graph_get_port_parent(prev);
else
parent = fwnode;
if (IS_ERR_OR_NULL(parent))
return NULL;
ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
if (ep)
return ep;
if (IS_ERR_OR_NULL(ep) &&
!IS_ERR_OR_NULL(parent) && !IS_ERR_OR_NULL(parent->secondary))
ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
return ep;
return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);

View file

@ -677,6 +677,17 @@ u16 qcom_adc_tm5_temp_volt_scale(unsigned int prescale_ratio,
}
EXPORT_SYMBOL(qcom_adc_tm5_temp_volt_scale);
u16 qcom_adc_tm5_gen2_temp_res_scale(int temp)
{
int64_t resistance;
resistance = qcom_vadc_map_temp_voltage(adcmap7_100k,
ARRAY_SIZE(adcmap7_100k), temp);
return div64_s64(resistance * RATIO_MAX_ADC7, resistance + R_PU_100K);
}
EXPORT_SYMBOL(qcom_adc_tm5_gen2_temp_res_scale);
int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
unsigned int prescale_ratio,
const struct adc5_data *data,

View file

@ -27,27 +27,6 @@ static void cec_fill_msg_report_features(struct cec_adapter *adap,
struct cec_msg *msg,
unsigned int la_idx);
/*
* 400 ms is the time it takes for one 16 byte message to be
* transferred and 5 is the maximum number of retries. Add
* another 100 ms as a margin. So if the transmit doesn't
* finish before that time something is really wrong and we
* have to time out.
*
* This is a sign that something it really wrong and a warning
* will be issued.
*/
#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
#define call_op(adap, op, arg...) \
(adap->ops->op ? adap->ops->op(adap, ## arg) : 0)
#define call_void_op(adap, op, arg...) \
do { \
if (adap->ops->op) \
adap->ops->op(adap, ## arg); \
} while (0)
static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr)
{
int i;
@ -366,38 +345,48 @@ static void cec_data_completed(struct cec_data *data)
/*
* A pending CEC transmit needs to be cancelled, either because the CEC
* adapter is disabled or the transmit takes an impossibly long time to
* finish.
* finish, or the reply timed out.
*
* This function is called with adap->lock held.
*/
static void cec_data_cancel(struct cec_data *data, u8 tx_status)
static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status)
{
struct cec_adapter *adap = data->adap;
/*
* It's either the current transmit, or it is a pending
* transmit. Take the appropriate action to clear it.
*/
if (data->adap->transmitting == data) {
data->adap->transmitting = NULL;
if (adap->transmitting == data) {
adap->transmitting = NULL;
} else {
list_del_init(&data->list);
if (!(data->msg.tx_status & CEC_TX_STATUS_OK))
if (!WARN_ON(!data->adap->transmit_queue_sz))
data->adap->transmit_queue_sz--;
if (!WARN_ON(!adap->transmit_queue_sz))
adap->transmit_queue_sz--;
}
if (data->msg.tx_status & CEC_TX_STATUS_OK) {
data->msg.rx_ts = ktime_get_ns();
data->msg.rx_status = CEC_RX_STATUS_ABORTED;
data->msg.rx_status = rx_status;
if (!data->blocking)
data->msg.tx_status = 0;
} else {
data->msg.tx_ts = ktime_get_ns();
data->msg.tx_status |= tx_status |
CEC_TX_STATUS_MAX_RETRIES;
data->msg.tx_error_cnt++;
data->attempts = 0;
if (!data->blocking)
data->msg.rx_status = 0;
}
/* Queue transmitted message for monitoring purposes */
cec_queue_msg_monitor(data->adap, &data->msg, 1);
cec_queue_msg_monitor(adap, &data->msg, 1);
if (!data->blocking && data->msg.sequence)
/* Allow drivers to process the message first */
call_op(adap, received, &data->msg);
cec_data_completed(data);
}
@ -418,15 +407,15 @@ static void cec_flush(struct cec_adapter *adap)
while (!list_empty(&adap->transmit_queue)) {
data = list_first_entry(&adap->transmit_queue,
struct cec_data, list);
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
}
if (adap->transmitting)
cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED);
adap->transmit_in_progress_aborted = true;
/* Cancel the pending timeout work. */
list_for_each_entry_safe(data, n, &adap->wait_queue, list) {
if (cancel_delayed_work(&data->work))
cec_data_cancel(data, CEC_TX_STATUS_OK);
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED);
/*
* If cancel_delayed_work returned false, then
* the cec_wait_timeout function is running,
@ -482,7 +471,7 @@ int cec_thread_func(void *_adap)
kthread_should_stop() ||
(!adap->transmit_in_progress &&
!list_empty(&adap->transmit_queue)),
msecs_to_jiffies(CEC_XFER_TIMEOUT_MS));
msecs_to_jiffies(adap->xfer_timeout_ms));
timeout = err == 0;
} else {
/* Otherwise we just wait for something to happen. */
@ -508,7 +497,8 @@ int cec_thread_func(void *_adap)
* adapter driver, or the CEC bus is in some weird
* state. On rare occasions it can happen if there is
* so much traffic on the bus that the adapter was
* unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s).
* unable to transmit for xfer_timeout_ms (2.1s by
* default).
*/
if (adap->transmitting) {
pr_warn("cec-%s: message %*ph timed out\n", adap->name,
@ -516,7 +506,7 @@ int cec_thread_func(void *_adap)
adap->transmitting->msg.msg);
/* Just give up on this. */
cec_data_cancel(adap->transmitting,
CEC_TX_STATUS_TIMEOUT);
CEC_TX_STATUS_TIMEOUT, 0);
} else {
pr_warn("cec-%s: transmit timed out\n", adap->name);
}
@ -572,10 +562,11 @@ int cec_thread_func(void *_adap)
if (data->attempts == 0)
data->attempts = attempts;
adap->transmit_in_progress_aborted = false;
/* Tell the adapter to transmit, cancel on error */
if (adap->ops->adap_transmit(adap, data->attempts,
signal_free_time, &data->msg))
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
if (call_op(adap, adap_transmit, data->attempts,
signal_free_time, &data->msg))
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
else
adap->transmit_in_progress = true;
@ -599,6 +590,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
struct cec_msg *msg;
unsigned int attempts_made = arb_lost_cnt + nack_cnt +
low_drive_cnt + error_cnt;
bool done = status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK);
bool aborted = adap->transmit_in_progress_aborted;
dprintk(2, "%s: status 0x%02x\n", __func__, status);
if (attempts_made < 1)
@ -619,6 +612,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
goto wake_thread;
}
adap->transmit_in_progress = false;
adap->transmit_in_progress_aborted = false;
msg = &data->msg;
@ -639,8 +633,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
* the hardware didn't signal that it retried itself (by setting
* CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves.
*/
if (data->attempts > attempts_made &&
!(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) {
if (!aborted && data->attempts > attempts_made && !done) {
/* Retry this message */
data->attempts -= attempts_made;
if (msg->timeout)
@ -655,6 +648,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
goto wake_thread;
}
if (aborted && !done)
status |= CEC_TX_STATUS_ABORTED;
data->attempts = 0;
/* Always set CEC_TX_STATUS_MAX_RETRIES on error */
@ -733,9 +728,7 @@ static void cec_wait_timeout(struct work_struct *work)
/* Mark the message as timed out */
list_del_init(&data->list);
data->msg.rx_ts = ktime_get_ns();
data->msg.rx_status = CEC_RX_STATUS_TIMEOUT;
cec_data_completed(data);
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_TIMEOUT);
unlock:
mutex_unlock(&adap->lock);
}
@ -921,8 +914,12 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
mutex_lock(&adap->lock);
/* Cancel the transmit if it was interrupted */
if (!data->completed)
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
if (!data->completed) {
if (data->msg.tx_status & CEC_TX_STATUS_OK)
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED);
else
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
}
/* The transmit completed (possibly with an error) */
*msg = data->msg;
@ -1278,17 +1275,22 @@ static int cec_config_log_addr(struct cec_adapter *adap,
* While trying to poll the physical address was reset
* and the adapter was unconfigured, so bail out.
*/
if (!adap->is_configuring)
if (adap->phys_addr == CEC_PHYS_ADDR_INVALID)
return -EINTR;
/* Also bail out if the PA changed while configuring. */
if (adap->must_reconfigure)
return -EINTR;
if (err)
return err;
/*
* The message was aborted due to a disconnect or
* The message was aborted or timed out due to a disconnect or
* unconfigure, just bail out.
*/
if (msg.tx_status & CEC_TX_STATUS_ABORTED)
if (msg.tx_status &
(CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT))
return -EINTR;
if (msg.tx_status & CEC_TX_STATUS_OK)
return 0;
@ -1314,7 +1316,7 @@ static int cec_config_log_addr(struct cec_adapter *adap,
* Message not acknowledged, so this logical
* address is free to use.
*/
err = adap->ops->adap_log_addr(adap, log_addr);
err = call_op(adap, adap_log_addr, log_addr);
if (err)
return err;
@ -1331,15 +1333,14 @@ static int cec_config_log_addr(struct cec_adapter *adap,
*/
static void cec_adap_unconfigure(struct cec_adapter *adap)
{
if (!adap->needs_hpd ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID)
WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
if (!adap->needs_hpd || adap->phys_addr != CEC_PHYS_ADDR_INVALID)
WARN_ON(call_op(adap, adap_log_addr, CEC_LOG_ADDR_INVALID));
adap->log_addrs.log_addr_mask = 0;
adap->is_configuring = false;
adap->is_configured = false;
cec_flush(adap);
wake_up_interruptible(&adap->kthread_waitq);
cec_post_state_event(adap);
call_void_op(adap, adap_configured, false);
}
/*
@ -1408,6 +1409,7 @@ static int cec_config_thread_func(void *arg)
if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED)
goto configured;
reconfigure:
for (i = 0; i < las->num_log_addrs; i++) {
unsigned int type = las->log_addr_type[i];
const u8 *la_list;
@ -1430,6 +1432,13 @@ static int cec_config_thread_func(void *arg)
last_la = la_list[0];
err = cec_config_log_addr(adap, i, last_la);
if (adap->must_reconfigure) {
adap->must_reconfigure = false;
las->log_addr_mask = 0;
goto reconfigure;
}
if (err > 0) /* Reused last LA */
continue;
@ -1475,6 +1484,7 @@ configured:
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
adap->is_configured = true;
adap->is_configuring = false;
adap->must_reconfigure = false;
cec_post_state_event(adap);
/*
@ -1521,15 +1531,18 @@ configured:
adap->kthread_config = NULL;
complete(&adap->config_completion);
mutex_unlock(&adap->lock);
call_void_op(adap, adap_configured, true);
return 0;
unconfigure:
for (i = 0; i < las->num_log_addrs; i++)
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
cec_adap_unconfigure(adap);
adap->is_configuring = false;
adap->must_reconfigure = false;
adap->kthread_config = NULL;
mutex_unlock(&adap->lock);
complete(&adap->config_completion);
mutex_unlock(&adap->lock);
return 0;
}
@ -1552,6 +1565,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
"ceccfg-%s", adap->name);
if (IS_ERR(adap->kthread_config)) {
adap->kthread_config = NULL;
adap->is_configuring = false;
} else if (block) {
mutex_unlock(&adap->lock);
wait_for_completion(&adap->config_completion);
@ -1559,63 +1573,96 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
}
}
/*
* Helper function to enable/disable the CEC adapter.
*
* This function is called with adap->lock held.
*/
static int cec_adap_enable(struct cec_adapter *adap)
{
bool enable;
int ret = 0;
enable = adap->monitor_all_cnt || adap->monitor_pin_cnt ||
adap->log_addrs.num_log_addrs;
if (adap->needs_hpd)
enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID;
if (enable == adap->is_enabled)
return 0;
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
if (enable) {
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
ret = adap->ops->adap_enable(adap, true);
if (!ret) {
/*
* Enable monitor-all/pin modes if needed. We warn, but
* continue if this fails as this is not a critical error.
*/
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, true));
if (adap->monitor_pin_cnt)
WARN_ON(call_op(adap, adap_monitor_pin_enable, true));
}
} else {
/* Disable monitor-all/pin modes if needed (needs_hpd == 1) */
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
if (adap->monitor_pin_cnt)
WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
WARN_ON(adap->ops->adap_enable(adap, false));
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
adap->transmit_in_progress_aborted = false;
if (adap->transmitting)
cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED, 0);
}
if (!ret)
adap->is_enabled = enable;
wake_up_interruptible(&adap->kthread_waitq);
mutex_unlock(&adap->devnode.lock);
return ret;
}
/* Set a new physical address and send an event notifying userspace of this.
*
* This function is called with adap->lock held.
*/
void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
{
bool becomes_invalid = phys_addr == CEC_PHYS_ADDR_INVALID;
bool is_invalid = adap->phys_addr == CEC_PHYS_ADDR_INVALID;
if (phys_addr == adap->phys_addr)
return;
if (phys_addr != CEC_PHYS_ADDR_INVALID && adap->devnode.unregistered)
if (!becomes_invalid && adap->devnode.unregistered)
return;
dprintk(1, "new physical address %x.%x.%x.%x\n",
cec_phys_addr_exp(phys_addr));
if (phys_addr == CEC_PHYS_ADDR_INVALID ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID) {
if (becomes_invalid || !is_invalid) {
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
cec_post_state_event(adap);
cec_adap_unconfigure(adap);
/* Disabling monitor all mode should always succeed */
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) {
WARN_ON(adap->ops->adap_enable(adap, false));
adap->transmit_in_progress = false;
wake_up_interruptible(&adap->kthread_waitq);
}
mutex_unlock(&adap->devnode.lock);
if (phys_addr == CEC_PHYS_ADDR_INVALID)
return;
}
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) {
if (adap->ops->adap_enable(adap, true)) {
mutex_unlock(&adap->devnode.lock);
if (becomes_invalid) {
cec_adap_enable(adap);
return;
}
}
if (adap->monitor_all_cnt &&
call_op(adap, adap_monitor_all_enable, true)) {
if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock);
return;
}
mutex_unlock(&adap->devnode.lock);
adap->phys_addr = phys_addr;
if (is_invalid)
cec_adap_enable(adap);
cec_post_state_event(adap);
if (adap->log_addrs.num_log_addrs)
if (!adap->log_addrs.num_log_addrs)
return;
if (adap->is_configuring)
adap->must_reconfigure = true;
else
cec_claim_log_addrs(adap, block);
}
@ -1670,19 +1717,24 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs *log_addrs, bool block)
{
u16 type_mask = 0;
int err;
int i;
if (adap->devnode.unregistered)
return -ENODEV;
if (!log_addrs || log_addrs->num_log_addrs == 0) {
cec_adap_unconfigure(adap);
if (!adap->log_addrs.num_log_addrs)
return 0;
if (adap->is_configuring || adap->is_configured)
cec_adap_unconfigure(adap);
adap->log_addrs.num_log_addrs = 0;
for (i = 0; i < CEC_MAX_LOG_ADDRS; i++)
adap->log_addrs.log_addr[i] = CEC_LOG_ADDR_INVALID;
adap->log_addrs.osd_name[0] = '\0';
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
cec_adap_enable(adap);
return 0;
}
@ -1818,9 +1870,10 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask;
adap->log_addrs = *log_addrs;
if (adap->phys_addr != CEC_PHYS_ADDR_INVALID)
err = cec_adap_enable(adap);
if (!err && adap->phys_addr != CEC_PHYS_ADDR_INVALID)
cec_claim_log_addrs(adap, block);
return 0;
return err;
}
int cec_s_log_addrs(struct cec_adapter *adap,
@ -1922,11 +1975,10 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
msg->msg[1] != CEC_MSG_CDC_MESSAGE)
return 0;
if (adap->ops->received) {
/* Allow drivers to process the message first */
if (adap->ops->received(adap, msg) != -ENOMSG)
return 0;
}
/* Allow drivers to process the message first */
if (adap->ops->received && !adap->devnode.unregistered &&
adap->ops->received(adap, msg) != -ENOMSG)
return 0;
/*
* REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and
@ -2119,20 +2171,25 @@ skip_processing:
*/
int cec_monitor_all_cnt_inc(struct cec_adapter *adap)
{
int ret = 0;
int ret;
if (adap->monitor_all_cnt == 0)
ret = call_op(adap, adap_monitor_all_enable, 1);
if (ret == 0)
adap->monitor_all_cnt++;
if (adap->monitor_all_cnt++)
return 0;
ret = cec_adap_enable(adap);
if (ret)
adap->monitor_all_cnt--;
return ret;
}
void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
{
adap->monitor_all_cnt--;
if (adap->monitor_all_cnt == 0)
WARN_ON(call_op(adap, adap_monitor_all_enable, 0));
if (WARN_ON(!adap->monitor_all_cnt))
return;
if (--adap->monitor_all_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
cec_adap_enable(adap);
}
/*
@ -2142,20 +2199,25 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
*/
int cec_monitor_pin_cnt_inc(struct cec_adapter *adap)
{
int ret = 0;
int ret;
if (adap->monitor_pin_cnt == 0)
ret = call_op(adap, adap_monitor_pin_enable, 1);
if (ret == 0)
adap->monitor_pin_cnt++;
if (adap->monitor_pin_cnt++)
return 0;
ret = cec_adap_enable(adap);
if (ret)
adap->monitor_pin_cnt--;
return ret;
}
void cec_monitor_pin_cnt_dec(struct cec_adapter *adap)
{
adap->monitor_pin_cnt--;
if (adap->monitor_pin_cnt == 0)
WARN_ON(call_op(adap, adap_monitor_pin_enable, 0));
if (WARN_ON(!adap->monitor_pin_cnt))
return;
if (--adap->monitor_pin_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
cec_adap_enable(adap);
}
#ifdef CONFIG_DEBUG_FS
@ -2169,6 +2231,7 @@ int cec_adap_status(struct seq_file *file, void *priv)
struct cec_data *data;
mutex_lock(&adap->lock);
seq_printf(file, "enabled: %d\n", adap->is_enabled);
seq_printf(file, "configured: %d\n", adap->is_configured);
seq_printf(file, "configuring: %d\n", adap->is_configuring);
seq_printf(file, "phys_addr: %x.%x.%x.%x\n",
@ -2183,6 +2246,9 @@ int cec_adap_status(struct seq_file *file, void *priv)
if (adap->monitor_all_cnt)
seq_printf(file, "file handles in Monitor All mode: %u\n",
adap->monitor_all_cnt);
if (adap->monitor_pin_cnt)
seq_printf(file, "file handles in Monitor Pin mode: %u\n",
adap->monitor_pin_cnt);
if (adap->tx_timeouts) {
seq_printf(file, "transmit timeouts: %u\n",
adap->tx_timeouts);

View file

@ -586,18 +586,6 @@ static int cec_open(struct inode *inode, struct file *filp)
return err;
}
/* serialize adap_enable */
mutex_lock(&devnode->lock);
if (list_empty(&devnode->fhs) &&
!adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
err = adap->ops->adap_enable(adap, true);
if (err) {
mutex_unlock(&devnode->lock);
kfree(fh);
return err;
}
}
filp->private_data = fh;
/* Queue up initial state events */
@ -607,7 +595,8 @@ static int cec_open(struct inode *inode, struct file *filp)
adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR;
cec_queue_event_fh(fh, &ev, 0);
#ifdef CONFIG_CEC_PIN
if (adap->pin && adap->pin->ops->read_hpd) {
if (adap->pin && adap->pin->ops->read_hpd &&
!adap->devnode.unregistered) {
err = adap->pin->ops->read_hpd(adap);
if (err >= 0) {
ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
@ -615,7 +604,8 @@ static int cec_open(struct inode *inode, struct file *filp)
cec_queue_event_fh(fh, &ev, 0);
}
}
if (adap->pin && adap->pin->ops->read_5v) {
if (adap->pin && adap->pin->ops->read_5v &&
!adap->devnode.unregistered) {
err = adap->pin->ops->read_5v(adap);
if (err >= 0) {
ev.event = err ? CEC_EVENT_PIN_5V_HIGH :
@ -625,6 +615,7 @@ static int cec_open(struct inode *inode, struct file *filp)
}
#endif
mutex_lock(&devnode->lock);
mutex_lock(&devnode->lock_fhs);
list_add(&fh->list, &devnode->fhs);
mutex_unlock(&devnode->lock_fhs);
@ -656,15 +647,10 @@ static int cec_release(struct inode *inode, struct file *filp)
cec_monitor_all_cnt_dec(adap);
mutex_unlock(&adap->lock);
/* serialize adap_enable */
mutex_lock(&devnode->lock);
mutex_lock(&devnode->lock_fhs);
list_del(&fh->list);
mutex_unlock(&devnode->lock_fhs);
if (cec_is_registered(adap) && list_empty(&devnode->fhs) &&
!adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
WARN_ON(adap->ops->adap_enable(adap, false));
}
mutex_unlock(&devnode->lock);
/* Unhook pending transmits from this filehandle. */

View file

@ -20,6 +20,18 @@
#define CEC_NUM_DEVICES 256
#define CEC_NAME "cec"
/*
* 400 ms is the time it takes for one 16 byte message to be
* transferred and 5 is the maximum number of retries. Add
* another 100 ms as a margin. So if the transmit doesn't
* finish before that time something is really wrong and we
* have to time out.
*
* This is a sign that something it really wrong and a warning
* will be issued.
*/
#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
int cec_debug;
module_param_named(debug, cec_debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
@ -204,7 +216,7 @@ static ssize_t cec_error_inj_write(struct file *file,
line = strsep(&p, "\n");
if (!*line || *line == '#')
continue;
if (!adap->ops->error_inj_parse_line(adap, line)) {
if (!call_op(adap, error_inj_parse_line, line)) {
kfree(buf);
return -EINVAL;
}
@ -217,7 +229,7 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused)
{
struct cec_adapter *adap = sf->private;
return adap->ops->error_inj_show(adap, sf);
return call_op(adap, error_inj_show, sf);
}
static int cec_error_inj_open(struct inode *inode, struct file *file)
@ -331,6 +343,8 @@ int cec_register_adapter(struct cec_adapter *adap,
adap->owner = parent->driver->owner;
adap->devnode.dev.parent = parent;
if (!adap->xfer_timeout_ms)
adap->xfer_timeout_ms = CEC_XFER_TIMEOUT_MS;
#ifdef CONFIG_MEDIA_CEC_RC
if (adap->capabilities & CEC_CAP_RC) {

View file

@ -12,6 +12,17 @@
#include <linux/atomic.h>
#include <media/cec-pin.h>
#define call_pin_op(pin, op, arg...) \
((pin && pin->ops->op && !pin->adap->devnode.unregistered) ? \
pin->ops->op(pin->adap, ## arg) : 0)
#define call_void_pin_op(pin, op, arg...) \
do { \
if (pin && pin->ops->op && \
!pin->adap->devnode.unregistered) \
pin->ops->op(pin->adap, ## arg); \
} while (0)
enum cec_pin_state {
/* CEC is off */
CEC_ST_OFF,

View file

@ -135,7 +135,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)
static bool cec_pin_read(struct cec_pin *pin)
{
bool v = pin->ops->read(pin->adap);
bool v = call_pin_op(pin, read);
cec_pin_update(pin, v, false);
return v;
@ -143,13 +143,13 @@ static bool cec_pin_read(struct cec_pin *pin)
static void cec_pin_low(struct cec_pin *pin)
{
pin->ops->low(pin->adap);
call_void_pin_op(pin, low);
cec_pin_update(pin, false, false);
}
static bool cec_pin_high(struct cec_pin *pin)
{
pin->ops->high(pin->adap);
call_void_pin_op(pin, high);
return cec_pin_read(pin);
}
@ -1037,11 +1037,14 @@ static int cec_pin_thread_func(void *_adap)
for (;;) {
wait_event_interruptible(pin->kthread_waitq,
kthread_should_stop() ||
pin->work_rx_msg.len ||
pin->work_tx_status ||
atomic_read(&pin->work_irq_change) ||
atomic_read(&pin->work_pin_num_events));
kthread_should_stop() ||
pin->work_rx_msg.len ||
pin->work_tx_status ||
atomic_read(&pin->work_irq_change) ||
atomic_read(&pin->work_pin_num_events));
if (kthread_should_stop())
break;
if (pin->work_rx_msg.len) {
struct cec_msg *msg = &pin->work_rx_msg;
@ -1086,10 +1089,12 @@ static int cec_pin_thread_func(void *_adap)
CEC_PIN_IRQ_UNCHANGED)) {
case CEC_PIN_IRQ_DISABLE:
if (irq_enabled) {
pin->ops->disable_irq(adap);
call_void_pin_op(pin, disable_irq);
irq_enabled = false;
}
cec_pin_high(pin);
if (pin->state == CEC_ST_OFF)
break;
cec_pin_to_idle(pin);
hrtimer_start(&pin->timer, ns_to_ktime(0),
HRTIMER_MODE_REL);
@ -1097,7 +1102,7 @@ static int cec_pin_thread_func(void *_adap)
case CEC_PIN_IRQ_ENABLE:
if (irq_enabled)
break;
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
pin->enable_irq_failed = !call_pin_op(pin, enable_irq);
if (pin->enable_irq_failed) {
cec_pin_to_idle(pin);
hrtimer_start(&pin->timer, ns_to_ktime(0),
@ -1109,15 +1114,7 @@ static int cec_pin_thread_func(void *_adap)
default:
break;
}
if (kthread_should_stop())
break;
}
if (pin->ops->disable_irq && irq_enabled)
pin->ops->disable_irq(adap);
hrtimer_cancel(&pin->timer);
cec_pin_read(pin);
cec_pin_to_idle(pin);
pin->state = CEC_ST_OFF;
return 0;
}
@ -1126,24 +1123,32 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
struct cec_pin *pin = adap->pin;
if (enable) {
atomic_set(&pin->work_pin_num_events, 0);
pin->work_pin_events_rd = pin->work_pin_events_wr = 0;
pin->work_pin_events_dropped = false;
cec_pin_read(pin);
cec_pin_to_idle(pin);
pin->tx_msg.len = 0;
pin->timer_ts = ns_to_ktime(0);
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
pin->kthread = kthread_run(cec_pin_thread_func, adap,
"cec-pin");
if (IS_ERR(pin->kthread)) {
pr_err("cec-pin: kernel_thread() failed\n");
return PTR_ERR(pin->kthread);
if (!pin->kthread) {
pin->kthread = kthread_run(cec_pin_thread_func, adap,
"cec-pin");
if (IS_ERR(pin->kthread)) {
int err = PTR_ERR(pin->kthread);
pr_err("cec-pin: kernel_thread() failed\n");
pin->kthread = NULL;
return err;
}
}
hrtimer_start(&pin->timer, ns_to_ktime(0),
HRTIMER_MODE_REL);
} else {
kthread_stop(pin->kthread);
} else if (pin->kthread) {
hrtimer_cancel(&pin->timer);
cec_pin_high(pin);
cec_pin_to_idle(pin);
pin->state = CEC_ST_OFF;
pin->work_tx_status = 0;
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE);
wake_up_interruptible(&pin->kthread_waitq);
}
return 0;
}
@ -1207,7 +1212,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
seq_printf(file, "state: %s\n", states[pin->state].name);
seq_printf(file, "tx_bit: %d\n", pin->tx_bit);
seq_printf(file, "rx_bit: %d\n", pin->rx_bit);
seq_printf(file, "cec pin: %d\n", pin->ops->read(adap));
seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read));
seq_printf(file, "cec pin events dropped: %u\n",
pin->work_pin_events_dropped_cnt);
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
@ -1260,8 +1265,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
pin->rx_data_bit_too_long_cnt = 0;
pin->rx_low_drive_cnt = 0;
pin->tx_low_drive_cnt = 0;
if (pin->ops->status)
pin->ops->status(adap, file);
call_void_pin_op(pin, status, file);
}
static int cec_pin_adap_monitor_all_enable(struct cec_adapter *adap,
@ -1277,6 +1281,9 @@ static void cec_pin_adap_free(struct cec_adapter *adap)
{
struct cec_pin *pin = adap->pin;
if (pin->kthread)
kthread_stop(pin->kthread);
pin->kthread = NULL;
if (pin->ops->free)
pin->ops->free(adap);
adap->pin = NULL;
@ -1287,7 +1294,7 @@ static int cec_pin_received(struct cec_adapter *adap, struct cec_msg *msg)
{
struct cec_pin *pin = adap->pin;
if (pin->ops->received)
if (pin->ops->received && !adap->devnode.unregistered)
return pin->ops->received(adap, msg);
return -ENOMSG;
}
@ -1327,6 +1334,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
return ERR_PTR(-ENOMEM);
pin->ops = pin_ops;
hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
atomic_set(&pin->work_pin_num_events, 0);
pin->timer.function = cec_pin_timer;
init_waitqueue_head(&pin->kthread_waitq);
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;

View file

@ -17,6 +17,16 @@
pr_info("cec-%s: " fmt, adap->name, ## arg); \
} while (0)
#define call_op(adap, op, arg...) \
((adap->ops->op && !adap->devnode.unregistered) ? \
adap->ops->op(adap, ## arg) : 0)
#define call_void_op(adap, op, arg...) \
do { \
if (adap->ops->op && !adap->devnode.unregistered) \
adap->ops->op(adap, ## arg); \
} while (0)
/* devnode to cec_adapter */
#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode)

View file

@ -31,29 +31,17 @@ struct secocec_data {
int irq;
};
#define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
cmd, data, SMBUS_WRITE, NULL)
#define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
#define smb_wr16(cmd, data) smb_word_op(SECOCEC_MICRO_ADDRESS, \
cmd, data, SMBUS_WRITE, NULL)
#define smb_rd16(cmd, res) smb_word_op(SECOCEC_MICRO_ADDRESS, \
cmd, 0, SMBUS_READ, res)
static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
static int smb_word_op(u16 slave_addr, u8 cmd, u16 data,
u8 operation, u16 *result)
{
unsigned int count;
short _data_format;
int status = 0;
switch (data_format) {
case CMD_BYTE_DATA:
_data_format = BRA_SMB_CMD_BYTE_DATA;
break;
case CMD_WORD_DATA:
_data_format = BRA_SMB_CMD_WORD_DATA;
break;
default:
return -EINVAL;
}
/* Active wait until ready */
for (count = 0; count <= SMBTIMEOUT; ++count) {
if (!(inb(HSTS) & BRA_INUSE_STS))
@ -75,7 +63,7 @@ static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
outb((u8)(data >> 8), HDAT1);
}
outb(BRA_START + _data_format, HCNT);
outb(BRA_START + BRA_SMB_CMD_WORD_DATA, HCNT);
for (count = 0; count <= SMBTIMEOUT; count++) {
if (!(inb(HSTS) & BRA_HOST_BUSY))

View file

@ -443,7 +443,6 @@ static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *
strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_DEVICE_CAPS;

View file

@ -126,8 +126,7 @@ static void *vb2_dma_sg_alloc(struct vb2_buffer *vb, struct device *dev,
* there is no memory consistency guarantee, hence dma-sg ignores DMA
* attributes passed from the upper layer.
*/
buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *),
GFP_KERNEL | __GFP_ZERO);
buf->pages = kvcalloc(buf->num_pages, sizeof(struct page *), GFP_KERNEL);
if (!buf->pages)
goto fail_pages_array_alloc;

View file

@ -977,12 +977,6 @@ EXPORT_SYMBOL_GPL(vb2_poll);
* and so they simplify the driver code.
*/
/* The queue is busy if there is a owner and you are not that owner. */
static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
{
return vdev->queue->owner && vdev->queue->owner != file->private_data;
}
/* vb2 ioctl helpers */
int vb2_ioctl_reqbufs(struct file *file, void *priv,
@ -997,7 +991,7 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
p->flags = flags;
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count);
/* If count == 0, then the owner has released all buffers and he
@ -1026,7 +1020,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
return res != -EBUSY ? res : 0;
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
res = vb2_create_bufs(vdev->queue, p);
@ -1041,7 +1035,7 @@ int vb2_ioctl_prepare_buf(struct file *file, void *priv,
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_prepare_buf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
@ -1060,7 +1054,7 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_qbuf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
@ -1070,7 +1064,7 @@ int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
}
@ -1080,7 +1074,7 @@ int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_streamon(vdev->queue, i);
}
@ -1090,7 +1084,7 @@ int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_streamoff(vdev->queue, i);
}
@ -1100,7 +1094,7 @@ int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_expbuf(vdev->queue, p);
}
@ -1152,7 +1146,7 @@ ssize_t vb2_fop_write(struct file *file, const char __user *buf,
return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
goto exit;
err = vb2_write(vdev->queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);
@ -1176,7 +1170,7 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
goto exit;
err = vb2_read(vdev->queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);

View file

@ -372,6 +372,7 @@ config VIDEO_OV13B10
config VIDEO_OV2640
tristate "OmniVision OV2640 sensor support"
depends on VIDEO_DEV && I2C
select V4L2_ASYNC
help
This is a Video4Linux2 sensor driver for the OmniVision
OV2640 camera.

View file

@ -66,6 +66,9 @@
#define ADV7180_HUE_DEF 0
#define ADV7180_HUE_MAX 128
#define ADV7180_REG_DEF_VALUE_Y 0x000c
#define ADV7180_DEF_VAL_EN 0x1
#define ADV7180_DEF_VAL_AUTO_EN 0x2
#define ADV7180_REG_CTRL 0x000e
#define ADV7180_CTRL_IRQ_SPACE 0x20
@ -549,6 +552,40 @@ static int adv7180_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
static const char * const test_pattern_menu[] = {
"Single color",
"Color bars",
"Luma ramp",
"Boundary box",
"Disable",
};
static int adv7180_test_pattern(struct adv7180_state *state, int value)
{
unsigned int reg = 0;
/* Map menu value into register value */
if (value < 3)
reg = value;
if (value == 3)
reg = 5;
adv7180_write(state, ADV7180_REG_ANALOG_CLAMP_CTL, reg);
if (value == ARRAY_SIZE(test_pattern_menu) - 1) {
reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
reg &= ~ADV7180_DEF_VAL_EN;
adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
return 0;
}
reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
reg |= ADV7180_DEF_VAL_EN | ADV7180_DEF_VAL_AUTO_EN;
adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
return 0;
}
static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
@ -592,6 +629,9 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
}
break;
case V4L2_CID_TEST_PATTERN:
ret = adv7180_test_pattern(state, val);
break;
default:
ret = -EINVAL;
}
@ -632,6 +672,12 @@ static int adv7180_init_controls(struct adv7180_state *state)
ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(test_pattern_menu) - 1,
0, ARRAY_SIZE(test_pattern_menu) - 1,
test_pattern_menu);
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
int err = state->ctrl_hdl.error;

View file

@ -121,7 +121,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor,
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n",
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n",
linfo->reg, linfo->name, offset, val, val);
ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val);
@ -288,7 +288,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK;
} else {
dev_dbg(&client->dev,
"invalid frame format model type %d\n",
"invalid frame format model type %u\n",
fmt_model_type);
return -EINVAL;
}
@ -320,7 +320,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
}
dev_dbg(&client->dev,
"%s pixels: %d %s (pixelcode %u)\n",
"%s pixels: %u %s (pixelcode %u)\n",
what, pixels, which, pixelcode);
if (i < ncol_desc) {
@ -353,9 +353,9 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
sensor->image_start = sensor->embedded_end;
}
dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
dev_dbg(&client->dev, "embedded data from lines %u to %u\n",
sensor->embedded_start, sensor->embedded_end);
dev_dbg(&client->dev, "image data starts at line %d\n",
dev_dbg(&client->dev, "image data starts at line %u\n",
sensor->image_start);
return 0;
@ -571,7 +571,7 @@ static u32 ccs_pixel_order(struct ccs_sensor *sensor)
flip ^= sensor->hvflip_inv_mask;
dev_dbg(&client->dev, "flip %d\n", flip);
dev_dbg(&client->dev, "flip %u\n", flip);
return sensor->default_pixel_order ^ flip;
}
@ -1056,18 +1056,18 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor)
type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE);
dev_dbg(&client->dev, "data_format_model_type %d\n", type);
dev_dbg(&client->dev, "data_format_model_type %u\n", type);
rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order);
if (rval)
return rval;
if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
dev_dbg(&client->dev, "bad pixel order %u\n", pixel_order);
return -EINVAL;
}
dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
dev_dbg(&client->dev, "pixel order %u (%s)\n", pixel_order,
pixel_order_str[pixel_order]);
switch (type) {
@ -1105,7 +1105,7 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor)
(fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK))
continue;
dev_dbg(&client->dev, "jolly good! %d\n", j);
dev_dbg(&client->dev, "jolly good! %u\n", j);
sensor->default_mbus_frame_fmts |= 1 << j;
}
@ -1602,8 +1602,11 @@ static int ccs_power_on(struct device *dev)
usleep_range(1000, 2000);
} while (--retry);
if (!reset)
return -EIO;
if (!reset) {
dev_err(dev, "software reset failed\n");
rval = -EIO;
goto out_cci_addr_fail;
}
}
if (sensor->hwcfg.i2c_addr_alt) {
@ -1999,7 +2002,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
dev_err(&client->dev, "subdev %s, pad %u, index %u\n",
subdev->name, code->pad, code->index);
if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) {
@ -2017,7 +2020,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
if (idx == code->index) {
code->code = ccs_csi_data_formats[i].code;
dev_err(&client->dev, "found index %d, i %d, code %x\n",
dev_err(&client->dev, "found index %u, i %u, code %x\n",
code->index, i, code->code);
rval = 0;
break;
@ -2386,7 +2389,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN),
CCS_LIM(sensor, SCALER_M_MAX));
dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
dev_dbg(&client->dev, "scaling: a %u b %u max_m %u\n", a, b, max_m);
min = min(max_m, min(a, b));
max = min(max_m, max(a, b));
@ -2416,7 +2419,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
sel->r.height,
sel->flags);
dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
dev_dbg(&client->dev, "trying factor %u (%u)\n", try[i], i);
if (this > best) {
scale_m = try[i];
@ -3183,7 +3186,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
u32 rotation;
int i;
unsigned int i;
int rval;
ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0,
@ -3221,8 +3224,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
goto out_err;
}
dev_dbg(dev, "lanes %u\n", hwcfg->lanes);
rval = fwnode_property_read_u32(fwnode, "rotation", &rotation);
if (!rval) {
switch (rotation) {
@ -3244,7 +3245,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
if (rval)
dev_info(dev, "can't get clock-frequency\n");
dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk,
dev_dbg(dev, "clk %u, mode %u\n", hwcfg->ext_clk,
hwcfg->csi_signalling_mode);
if (!bus_cfg.nr_of_link_frequencies) {
@ -3263,7 +3264,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i];
dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]);
dev_dbg(dev, "freq %u: %lld\n", i, hwcfg->op_sys_clock[i]);
}
v4l2_fwnode_endpoint_free(&bus_cfg);

View file

@ -183,6 +183,7 @@ static int dw9714_probe(struct i2c_client *client)
return 0;
err_cleanup:
regulator_disable(dw9714_dev->vcc);
v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm);
media_entity_cleanup(&dw9714_dev->sd.entity);
@ -201,7 +202,6 @@ static int dw9714_remove(struct i2c_client *client)
if (ret) {
dev_err(&client->dev,
"Failed to disable vcc: %d\n", ret);
return ret;
}
}
pm_runtime_set_suspended(&client->dev);

View file

@ -469,11 +469,6 @@ static int dw9768_probe(struct i2c_client *client)
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Attempt to turn off the device to satisfy the privacy LED concerns.
*/
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = dw9768_runtime_resume(dev);
@ -488,7 +483,6 @@ static int dw9768_probe(struct i2c_client *client)
dev_err(dev, "failed to register V4L2 subdev: %d", ret);
goto err_power_off;
}
pm_runtime_idle(dev);
return 0;

View file

@ -295,6 +295,8 @@ static int __maybe_unused dw9807_vcm_resume(struct device *dev)
static const struct of_device_id dw9807_of_table[] = {
{ .compatible = "dongwoon,dw9807-vcm" },
/* Compatibility for older firmware, NEVER USE THIS IN FIRMWARE! */
{ .compatible = "dongwoon,dw9807" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw9807_of_table);

View file

@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
@ -101,6 +102,12 @@ struct imx412_mode {
struct imx412_reg_list reg_list;
};
static const char * const imx412_supply_names[] = {
"dovdd", /* Digital I/O power */
"avdd", /* Analog power */
"dvdd", /* Digital core power */
};
/**
* struct imx412 - imx412 sensor device structure
* @dev: Pointer to generic device
@ -109,6 +116,7 @@ struct imx412_mode {
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
* @inclk: Sensor input clock
* @supplies: Regulator supplies
* @ctrl_handler: V4L2 control handler
* @link_freq_ctrl: Pointer to link frequency control
* @pclk_ctrl: Pointer to pixel clock control
@ -128,6 +136,7 @@ struct imx412 {
struct media_pad pad;
struct gpio_desc *reset_gpio;
struct clk *inclk;
struct regulator_bulk_data supplies[ARRAY_SIZE(imx412_supply_names)];
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *link_freq_ctrl;
struct v4l2_ctrl *pclk_ctrl;
@ -946,6 +955,16 @@ static int imx412_parse_hw_config(struct imx412 *imx412)
return -EINVAL;
}
/* Get optional DT defined regulators */
for (i = 0; i < ARRAY_SIZE(imx412_supply_names); i++)
imx412->supplies[i].supply = imx412_supply_names[i];
ret = devm_regulator_bulk_get(imx412->dev,
ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
if (ret)
return ret;
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
return -ENXIO;
@ -1011,7 +1030,14 @@ static int imx412_power_on(struct device *dev)
struct imx412 *imx412 = to_imx412(sd);
int ret;
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
ret = regulator_bulk_enable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
if (ret < 0) {
dev_err(dev, "failed to enable regulators\n");
return ret;
}
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
ret = clk_prepare_enable(imx412->inclk);
if (ret) {
@ -1024,7 +1050,9 @@ static int imx412_power_on(struct device *dev)
return 0;
error_reset:
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
return ret;
}
@ -1040,10 +1068,13 @@ static int imx412_power_off(struct device *dev)
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx412 *imx412 = to_imx412(sd);
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
clk_disable_unprepare(imx412->inclk);
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
return 0;
}

View file

@ -1147,22 +1147,18 @@ static int max9286_poc_enable(struct max9286_priv *priv, bool enable)
return ret;
}
static int max9286_init(struct device *dev)
static int max9286_init(struct max9286_priv *priv)
{
struct max9286_priv *priv;
struct i2c_client *client;
struct i2c_client *client = priv->client;
int ret;
client = to_i2c_client(dev);
priv = i2c_get_clientdata(client);
ret = max9286_poc_enable(priv, true);
if (ret)
return ret;
ret = max9286_setup(priv);
if (ret) {
dev_err(dev, "Unable to setup max9286\n");
dev_err(&client->dev, "Unable to setup max9286\n");
goto err_poc_disable;
}
@ -1172,13 +1168,13 @@ static int max9286_init(struct device *dev)
*/
ret = max9286_v4l2_register(priv);
if (ret) {
dev_err(dev, "Failed to register with V4L2\n");
dev_err(&client->dev, "Failed to register with V4L2\n");
goto err_poc_disable;
}
ret = max9286_i2c_mux_init(priv);
if (ret) {
dev_err(dev, "Unable to initialize I2C multiplexer\n");
dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
goto err_v4l2_register;
}
@ -1333,7 +1329,6 @@ static int max9286_probe(struct i2c_client *client)
mutex_init(&priv->mutex);
priv->client = client;
i2c_set_clientdata(client, priv);
priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable",
GPIOD_OUT_HIGH);
@ -1369,7 +1364,7 @@ static int max9286_probe(struct i2c_client *client)
if (ret)
goto err_powerdown;
ret = max9286_init(&client->dev);
ret = max9286_init(priv);
if (ret < 0)
goto err_cleanup_dt;
@ -1385,7 +1380,7 @@ err_powerdown:
static int max9286_remove(struct i2c_client *client)
{
struct max9286_priv *priv = i2c_get_clientdata(client);
struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client));
i2c_mux_del_adapters(priv->mux);

View file

@ -843,7 +843,7 @@ static int ov5645_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;
}
@ -852,7 +852,7 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16)
return -EINVAL;
if (fse->index >= ARRAY_SIZE(ov5645_mode_info_data))
@ -948,7 +948,7 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
format->which);
__format->width = __crop->width;
__format->height = __crop->height;
__format->code = MEDIA_BUS_FMT_UYVY8_2X8;
__format->code = MEDIA_BUS_FMT_UYVY8_1X16;
__format->field = V4L2_FIELD_NONE;
__format->colorspace = V4L2_COLORSPACE_SRGB;
@ -1283,7 +1283,7 @@ MODULE_DEVICE_TABLE(of, ov5645_of_match);
static struct i2c_driver ov5645_i2c_driver = {
.driver = {
.of_match_table = of_match_ptr(ov5645_of_match),
.of_match_table = ov5645_of_match,
.name = "ov5645",
},
.probe_new = ov5645_probe,

View file

@ -2498,9 +2498,9 @@ static int ov5648_probe(struct i2c_client *client)
/* DOVDD: digital I/O */
sensor->dovdd = devm_regulator_get(dev, "dovdd");
if (IS_ERR(sensor->dvdd)) {
if (IS_ERR(sensor->dovdd)) {
dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n");
ret = PTR_ERR(sensor->dvdd);
ret = PTR_ERR(sensor->dovdd);
goto error_endpoint;
}

View file

@ -1122,7 +1122,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
/* 4 least significant bits of expsoure are fractional part */
/* 4 least significant bits of exposure are fractional part */
ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE,
OV5695_REG_VALUE_24BIT, ctrl->val << 4);
break;

File diff suppressed because it is too large Load diff

View file

@ -13,23 +13,28 @@
MODULE_DESCRIPTION("OmniVision ov7640 sensor driver");
MODULE_LICENSE("GPL v2");
static const u8 initial_registers[] = {
0x12, 0x80,
0x12, 0x54,
0x14, 0x24,
0x15, 0x01,
0x28, 0x20,
0x75, 0x82,
0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
struct reg_val {
u8 reg;
u8 val;
};
static int write_regs(struct i2c_client *client, const u8 *regs)
{
int i;
static const struct reg_val regval_init[] = {
{0x12, 0x80},
{0x12, 0x54},
{0x14, 0x24},
{0x15, 0x01},
{0x28, 0x20},
{0x75, 0x82},
};
for (i = 0; regs[i] != 0xFF; i += 2)
if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
static int write_regs(struct i2c_client *client,
const struct reg_val *rv, int len)
{
while (--len >= 0) {
if (i2c_smbus_write_byte_data(client, rv->reg, rv->val) < 0)
return -1;
rv++;
}
return 0;
}
@ -56,7 +61,7 @@ static int ov7640_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
if (write_regs(client, initial_registers) < 0) {
if (write_regs(client, regval_init, ARRAY_SIZE(regval_init)) < 0) {
v4l_err(client, "error initializing OV7640\n");
return -ENODEV;
}

View file

@ -2017,7 +2017,6 @@ static int ov7670_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&info->hdl);
media_entity_cleanup(&info->sd.entity);
ov7670_power_off(sd);
return 0;
}

View file

@ -63,6 +63,7 @@
#define OV8856_ANAL_GAIN_STEP 1
/* Digital gain controls from sensor */
#define OV8856_REG_DIGITAL_GAIN 0x350a
#define OV8856_REG_MWB_R_GAIN 0x5019
#define OV8856_REG_MWB_G_GAIN 0x501b
#define OV8856_REG_MWB_B_GAIN 0x501d
@ -351,7 +352,7 @@ static const struct ov8856_reg lane_2_mode_3280x2464[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5795, 0x02},
@ -543,7 +544,7 @@ static const struct ov8856_reg lane_2_mode_1640x1232[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5795, 0x00},
@ -734,7 +735,7 @@ static const struct ov8856_reg lane_4_mode_3280x2464[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5780, 0x14},
@ -925,7 +926,7 @@ static const struct ov8856_reg lane_4_mode_1640x1232[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5780, 0x14},
@ -1755,19 +1756,7 @@ static int ov8856_identify_module(struct ov8856 *ov8856)
static int ov8856_update_digital_gain(struct ov8856 *ov8856, u32 d_gain)
{
int ret;
ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_R_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_G_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
return ov8856_write_reg(ov8856, OV8856_REG_MWB_B_GAIN,
return ov8856_write_reg(ov8856, OV8856_REG_DIGITAL_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
}

View file

@ -47,11 +47,11 @@
#define OV10635_VTS 933
/*
* As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 format we
* As the drivers supports a single MEDIA_BUS_FMT_UYVY8_1X16 format we
* can harcode the pixel rate.
*
* PCLK is fed through the system clock, programmed @88MHz.
* MEDIA_BUS_FMT_UYVY8_2X8 format = 2 samples per pixel.
* MEDIA_BUS_FMT_UYVY8_1X16 format = 2 samples per pixel.
*
* Pixelrate = PCLK / 2
* FPS = (OV10635_VTS * OV10635_HTS) / PixelRate
@ -409,7 +409,7 @@ static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
if (code->pad || code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_UYVY8_2X8;
code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0;
}
@ -425,7 +425,7 @@ static int rdacm20_get_fmt(struct v4l2_subdev *sd,
mf->width = OV10635_WIDTH;
mf->height = OV10635_HEIGHT;
mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
mf->colorspace = V4L2_COLORSPACE_RAW;
mf->field = V4L2_FIELD_NONE;
mf->ycbcr_enc = V4L2_YCBCR_ENC_601;
@ -611,7 +611,7 @@ static int rdacm20_probe(struct i2c_client *client)
goto error_free_ctrls;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret < 0)
goto error_free_ctrls;

View file

@ -583,7 +583,7 @@ static int rdacm21_probe(struct i2c_client *client)
goto error_free_ctrls;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret < 0)
goto error_free_ctrls;

View file

@ -213,7 +213,7 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
for (i++; i < S5K6A3_NUM_SUPPLIES; i++) {
ret = regulator_enable(sensor->supplies[i].consumer);
if (ret < 0)
goto error_reg_dis;
goto error_clk;
}
gpio_set_value(sensor->gpio_reset, 1);
@ -226,6 +226,8 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
msleep(20);
return 0;
error_clk:
clk_disable_unprepare(sensor->clock);
error_reg_dis:
for (--i; i >= 0; --i)
regulator_disable(sensor->supplies[i].consumer);

View file

@ -9,6 +9,7 @@
* - Melexis MLX90640 Thermal Cameras
*/
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/hwmon.h>
@ -34,6 +35,37 @@
#define VIDEO_I2C_DRIVER "video-i2c"
/* Power control register */
#define AMG88XX_REG_PCTL 0x00
#define AMG88XX_PCTL_NORMAL 0x00
#define AMG88XX_PCTL_SLEEP 0x10
/* Reset register */
#define AMG88XX_REG_RST 0x01
#define AMG88XX_RST_FLAG 0x30
#define AMG88XX_RST_INIT 0x3f
/* Frame rate register */
#define AMG88XX_REG_FPSC 0x02
#define AMG88XX_FPSC_1FPS BIT(0)
/* Thermistor register */
#define AMG88XX_REG_TTHL 0x0e
/* Temperature register */
#define AMG88XX_REG_T01L 0x80
/* RAM */
#define MLX90640_RAM_START_ADDR 0x0400
/* EEPROM */
#define MLX90640_EEPROM_START_ADDR 0x2400
/* Control register */
#define MLX90640_REG_CTL1 0x800d
#define MLX90640_REG_CTL1_MASK GENMASK(9, 7)
#define MLX90640_REG_CTL1_MASK_SHIFT 7
struct video_i2c_chip;
struct video_i2c_buffer {
@ -124,7 +156,7 @@ static int mlx90640_nvram_read(void *priv, unsigned int offset, void *val,
{
struct video_i2c_data *data = priv;
return regmap_bulk_read(data->regmap, 0x2400 + offset, val, bytes);
return regmap_bulk_read(data->regmap, MLX90640_EEPROM_START_ADDR + offset, val, bytes);
}
static struct nvmem_config mlx90640_nvram_config = {
@ -135,31 +167,6 @@ static struct nvmem_config mlx90640_nvram_config = {
.reg_read = mlx90640_nvram_read,
};
/* Power control register */
#define AMG88XX_REG_PCTL 0x00
#define AMG88XX_PCTL_NORMAL 0x00
#define AMG88XX_PCTL_SLEEP 0x10
/* Reset register */
#define AMG88XX_REG_RST 0x01
#define AMG88XX_RST_FLAG 0x30
#define AMG88XX_RST_INIT 0x3f
/* Frame rate register */
#define AMG88XX_REG_FPSC 0x02
#define AMG88XX_FPSC_1FPS BIT(0)
/* Thermistor register */
#define AMG88XX_REG_TTHL 0x0e
/* Temperature register */
#define AMG88XX_REG_T01L 0x80
/* Control register */
#define MLX90640_REG_CTL1 0x800d
#define MLX90640_REG_CTL1_MASK 0x0380
#define MLX90640_REG_CTL1_MASK_SHIFT 7
static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
{
return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf,
@ -168,7 +175,7 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
static int mlx90640_xfer(struct video_i2c_data *data, char *buf)
{
return regmap_bulk_read(data->regmap, 0x400, buf,
return regmap_bulk_read(data->regmap, MLX90640_RAM_START_ADDR, buf,
data->chip->buffer_size);
}

View file

@ -604,15 +604,8 @@ static void __media_device_unregister_entity(struct media_entity *entity)
media_gobj_destroy(&entity->graph_obj);
/* invoke entity_notify callbacks to handle entity removal?? */
entity->graph_obj.mdev = NULL;
}
/**
* media_device_register_entity - Register an entity with a media device
* @mdev: The media device
* @entity: The entity
*/
int __must_check media_device_register_entity(struct media_device *mdev,
struct media_entity *entity)
{
@ -691,16 +684,6 @@ void media_device_unregister_entity(struct media_entity *entity)
}
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
/**
* media_device_init() - initialize a media device
* @mdev: The media device
*
* The caller is responsible for initializing the media device before
* registration. The following fields must be set:
*
* - dev must point to the parent device
* - model must be filled with the device model name
*/
void media_device_init(struct media_device *mdev)
{
INIT_LIST_HEAD(&mdev->entities);
@ -715,6 +698,10 @@ void media_device_init(struct media_device *mdev)
atomic_set(&mdev->request_id, 0);
if (!*mdev->bus_info)
media_set_bus_info(mdev->bus_info, sizeof(mdev->bus_info),
mdev->dev);
dev_dbg(mdev->dev, "Media device initialized\n");
}
EXPORT_SYMBOL_GPL(media_device_init);

View file

@ -44,6 +44,20 @@ static inline const char *intf_type(struct media_interface *intf)
}
};
static inline const char *link_type_name(struct media_link *link)
{
switch (link->flags & MEDIA_LNK_FL_LINK_TYPE) {
case MEDIA_LNK_FL_DATA_LINK:
return "data";
case MEDIA_LNK_FL_INTERFACE_LINK:
return "interface";
case MEDIA_LNK_FL_ANCILLARY_LINK:
return "ancillary";
default:
return "unknown";
}
}
__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
int idx_max)
{
@ -89,9 +103,7 @@ static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj)
dev_dbg(gobj->mdev->dev,
"%s id %u: %s link id %u ==> id %u\n",
event_name, media_id(gobj),
media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
"data" : "interface",
event_name, media_id(gobj), link_type_name(link),
media_id(link->gobj0),
media_id(link->gobj1));
break;
@ -295,6 +307,12 @@ static void media_graph_walk_iter(struct media_graph *graph)
link = list_entry(link_top(graph), typeof(*link), list);
/* If the link is not a data link, don't follow it */
if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
link_top(graph) = link_top(graph)->next;
return;
}
/* The link is not enabled so we do not follow. */
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
link_top(graph) = link_top(graph)->next;
@ -579,26 +597,30 @@ static void __media_entity_remove_link(struct media_entity *entity,
struct media_link *rlink, *tmp;
struct media_entity *remote;
if (link->source->entity == entity)
remote = link->sink->entity;
else
remote = link->source->entity;
list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
if (rlink != link->reverse)
continue;
/* Remove the reverse links for a data link. */
if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) {
if (link->source->entity == entity)
remote->num_backlinks--;
remote = link->sink->entity;
else
remote = link->source->entity;
/* Remove the remote link */
list_del(&rlink->list);
media_gobj_destroy(&rlink->graph_obj);
kfree(rlink);
list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
if (rlink != link->reverse)
continue;
if (--remote->num_links == 0)
break;
if (link->source->entity == entity)
remote->num_backlinks--;
/* Remove the remote link */
list_del(&rlink->list);
media_gobj_destroy(&rlink->graph_obj);
kfree(rlink);
if (--remote->num_links == 0)
break;
}
}
list_del(&link->list);
media_gobj_destroy(&link->graph_obj);
kfree(link);
@ -1007,3 +1029,25 @@ void media_remove_intf_links(struct media_interface *intf)
mutex_unlock(&mdev->graph_mutex);
}
EXPORT_SYMBOL_GPL(media_remove_intf_links);
struct media_link *media_create_ancillary_link(struct media_entity *primary,
struct media_entity *ancillary)
{
struct media_link *link;
link = media_add_link(&primary->links);
if (!link)
return ERR_PTR(-ENOMEM);
link->gobj0 = &primary->graph_obj;
link->gobj1 = &ancillary->graph_obj;
link->flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_ANCILLARY_LINK;
/* Initialize graph object embedded in the new link */
media_gobj_create(primary->graph_obj.mdev, MEDIA_GRAPH_LINK,
&link->graph_obj);
return link;
}
EXPORT_SYMBOL_GPL(media_create_ancillary_link);

View file

@ -2435,8 +2435,6 @@ static int bttv_querycap(struct file *file, void *priv,
strscpy(cap->driver, "bttv", sizeof(cap->driver));
strscpy(cap->card, btv->video_dev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(btv->c.pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
if (no_overlay <= 0)

View file

@ -389,8 +389,6 @@ static int cx18_querycap(struct file *file, void *fh,
strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCI:%s", pci_name(cx->pci_dev));
vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
return 0;
}

View file

@ -2165,7 +2165,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
err = dma_set_mask(&pci_dev->dev, 0xffffffff);
if (err) {
pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
goto fail_ctrl;
goto fail_dma_set_mask;
}
err = request_irq(pci_dev->irq, cx23885_irq,
@ -2173,7 +2173,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
goto fail_irq;
goto fail_dma_set_mask;
}
switch (dev->board) {
@ -2195,7 +2195,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
return 0;
fail_irq:
fail_dma_set_mask:
cx23885_dev_unregister(dev);
fail_ctrl:
v4l2_ctrl_handler_free(hdl);

View file

@ -728,8 +728,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
chip->irq = dev->pci->irq;
err = request_irq(dev->pci->irq, cx25821_irq,
IRQF_SHARED, chip->dev->name, chip);
err = devm_request_irq(&dev->pci->dev, dev->pci->irq, cx25821_irq,
IRQF_SHARED, chip->dev->name, chip);
if (err < 0) {
pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name,

View file

@ -1332,11 +1332,11 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
struct cx25821_dev *dev = get_cx25821(v4l2_dev);
cx25821_shutdown(dev);
pci_disable_device(pci_dev);
/* unregister stuff */
if (pci_dev->irq)
free_irq(pci_dev->irq, dev);
pci_disable_device(pci_dev);
cx25821_dev_unregister(dev);
v4l2_device_unregister(v4l2_dev);

View file

@ -796,7 +796,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx88_core *core = dev->core;
strscpy(cap->driver, "cx88_blackbird", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}

View file

@ -808,7 +808,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx88_core *core = dev->core;
strscpy(cap->driver, "cx8800", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}

View file

@ -292,11 +292,8 @@ static const struct v4l2_file_operations dt3155_fops = {
static int dt3155_querycap(struct file *filp, void *p,
struct v4l2_capability *cap)
{
struct dt3155_priv *pd = video_drvdata(filp);
strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
return 0;
}

View file

@ -25,6 +25,8 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = {
CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000),
/* Omnivision OV8865 */
CIO2_SENSOR_CONFIG("INT347A", 1, 360000000),
/* Omnivision OV7251 */
CIO2_SENSOR_CONFIG("INT347E", 1, 319200000),
/* Omnivision OV2680 */
CIO2_SENSOR_CONFIG("OVTI2680", 0),
};

View file

@ -65,6 +65,11 @@ static const struct ipu3_cio2_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_IPU3_SRGGB10,
.mipicode = 0x2b,
.bpp = 10,
}, {
.mbus_code = MEDIA_BUS_FMT_Y10_1X10,
.fourcc = V4L2_PIX_FMT_IPU3_Y10,
.mipicode = 0x2b,
.bpp = 10,
},
};
@ -1046,12 +1051,8 @@ static const struct vb2_ops cio2_vb2_ops = {
static int cio2_v4l2_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct cio2_device *cio2 = video_drvdata(file);
strscpy(cap->driver, CIO2_NAME, sizeof(cap->driver));
strscpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
return 0;
}
@ -1777,8 +1778,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
cio2->media_dev.dev = dev;
strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME,
sizeof(cio2->media_dev.model));
snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
cio2->media_dev.hw_revision = 0;
media_device_init(&cio2->media_dev);

View file

@ -732,7 +732,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, itv->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
return 0;
}

View file

@ -1012,7 +1012,6 @@ static int vidioc_querycap(struct file *file, void *fh,
{
strscpy(cap->driver, "meye", sizeof(cap->driver));
strscpy(cap->card, "meye", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
return 0;
}

View file

@ -1475,7 +1475,6 @@ int saa7134_querycap(struct file *file, void *priv,
strscpy(cap->driver, "saa7134", sizeof(cap->driver));
strscpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
@ -1833,8 +1832,7 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
spin_lock_irqsave(&dev->slock, flags);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
if (!on) {
} else {
if (priv != dev->overlay_owner)
return -EINVAL;
spin_lock_irqsave(&dev->slock, flags);

View file

@ -490,7 +490,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, dev->name, sizeof(cap->driver));
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_DEVICE_CAPS;

View file

@ -201,7 +201,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, dev->name, sizeof(cap->driver));
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_DEVICE_CAPS;

View file

@ -764,13 +764,10 @@ static int solo_enc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
solo_enc->ch);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
return 0;
}

View file

@ -372,12 +372,8 @@ static const struct vb2_ops solo_video_qops = {
static int solo_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct solo_dev *solo_dev = video_drvdata(file);
strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
return 0;
}

View file

@ -401,12 +401,8 @@ static const struct v4l2_file_operations vip_fops = {
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct sta2x11_vip *vip = video_drvdata(file);
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
return 0;
}

View file

@ -604,7 +604,6 @@ static int tw5864_querycap(struct file *file, void *priv,
strscpy(cap->driver, "tw5864", sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d",
input->nr);
sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci));
return 0;
}

View file

@ -712,12 +712,9 @@ static int tw68_s_input(struct file *file, void *priv, unsigned int i)
static int tw68_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct tw68_dev *dev = video_drvdata(file);
strscpy(cap->driver, "tw68", sizeof(cap->driver));
strscpy(cap->card, "Techwell Capture Card",
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return 0;
}

View file

@ -762,8 +762,6 @@ static int tw686x_querycap(struct file *file, void *priv,
strscpy(cap->driver, "tw686x", sizeof(cap->driver));
strscpy(cap->card, dev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(dev->pci_dev));
return 0;
}

View file

@ -3249,13 +3249,8 @@ static int allegro_release(struct file *file)
static int allegro_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct allegro_dev *dev = video_get_drvdata(vdev);
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
return 0;
}

View file

@ -26,8 +26,8 @@
#include "vpu_cmds.h"
#include "vpu_rpc.h"
#define VDEC_FRAME_DEPTH 256
#define VDEC_MIN_BUFFER_CAP 8
#define VDEC_MIN_BUFFER_OUT 8
struct vdec_fs_info {
char name[8];
@ -63,8 +63,6 @@ struct vdec_t {
bool is_source_changed;
u32 source_change;
u32 drain;
u32 ts_pre_count;
u32 frame_depth;
};
static const struct vpu_format vdec_formats[] = {
@ -164,6 +162,12 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
if (ret) {
dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret);
@ -470,7 +474,7 @@ static int vdec_drain(struct vpu_inst *inst)
if (!vdec->drain)
return 0;
if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx))
if (!vpu_is_source_empty(inst))
return 0;
if (!vdec->params.frame_count) {
@ -589,11 +593,8 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type)
{
struct vdec_t *vdec = inst->priv;
if (V4L2_TYPE_IS_OUTPUT(type)) {
if (vdec->ts_pre_count >= vdec->frame_depth)
return false;
if (V4L2_TYPE_IS_OUTPUT(type))
return true;
}
if (vdec->req_frame_count)
return true;
@ -601,12 +602,21 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type)
return false;
}
static struct vb2_v4l2_buffer *vdec_get_src_buffer(struct vpu_inst *inst, u32 count)
{
if (count > 1)
vpu_skip_frame(inst, count - 1);
return vpu_next_src_buf(inst);
}
static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
{
struct vdec_t *vdec = inst->priv;
struct vpu_dec_pic_info *info = arg;
struct vpu_vb2_buffer *vpu_buf;
struct vb2_v4l2_buffer *vbuf;
struct vb2_v4l2_buffer *src_buf;
int ret = 0;
if (!info || info->id >= ARRAY_SIZE(vdec->slots))
@ -620,14 +630,21 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
goto exit;
}
vbuf = &vpu_buf->m2m_buf.vb;
src_buf = vdec_get_src_buffer(inst, info->consumed_count);
if (src_buf) {
v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true);
if (info->consumed_count) {
v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
} else {
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_DECODED);
}
}
if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED)
dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED);
vdec->decoded_frame_count++;
if (vdec->ts_pre_count >= info->consumed_count)
vdec->ts_pre_count -= info->consumed_count;
else
vdec->ts_pre_count = 0;
exit:
vpu_inst_unlock(inst);
@ -683,10 +700,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY);
vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]);
vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]);
vbuf->vb2_buf.timestamp = frame->timestamp;
vbuf->field = inst->cap_format.field;
vbuf->sequence = sequence;
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->timestamp);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
vpu_inst_lock(inst);
@ -708,7 +724,6 @@ static void vdec_stop_done(struct vpu_inst *inst)
vdec->fixed_fmt = false;
vdec->params.end_flag = 0;
vdec->drain = 0;
vdec->ts_pre_count = 0;
vdec->params.frame_count = 0;
vdec->decoded_frame_count = 0;
vdec->display_frame_count = 0;
@ -782,7 +797,7 @@ static void vdec_init_fmt(struct vpu_inst *inst)
if (vdec->codec_info.progressive)
inst->cap_format.field = V4L2_FIELD_NONE;
else
inst->cap_format.field = V4L2_FIELD_SEQ_BT;
inst->cap_format.field = V4L2_FIELD_SEQ_TB;
if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT)
vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709;
if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT)
@ -1244,18 +1259,14 @@ static int vdec_process_output(struct vpu_inst *inst, struct vb2_buffer *vb)
if (free_space < vb2_get_plane_payload(vb, 0) + 0x40000)
return -ENOMEM;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
ret = vpu_iface_input_frame(inst, vb);
if (ret < 0)
return -ENOMEM;
dev_dbg(inst->dev, "[%d][INPUT TS]%32lld\n", inst->id, vb->timestamp);
vdec->ts_pre_count++;
vdec->params.frame_count++;
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
if (vdec->drain)
vdec_drain(inst);
@ -1318,7 +1329,6 @@ static void vdec_abort(struct vpu_inst *inst)
vdec->sequence);
vdec->params.end_flag = 0;
vdec->drain = 0;
vdec->ts_pre_count = 0;
vdec->params.frame_count = 0;
vdec->decoded_frame_count = 0;
vdec->display_frame_count = 0;
@ -1525,10 +1535,6 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i
vdec->drain, vdec->eos_received, vdec->source_change);
break;
case 8:
num = scnprintf(str, size, "ts_pre_count = %d, frame_depth = %d\n",
vdec->ts_pre_count, vdec->frame_depth);
break;
case 9:
num = scnprintf(str, size, "fps = %d/%d\n",
vdec->codec_info.frame_rate.numerator,
vdec->codec_info.frame_rate.denominator);
@ -1562,12 +1568,8 @@ static struct vpu_inst_ops vdec_inst_ops = {
static void vdec_init(struct file *file)
{
struct vpu_inst *inst = to_inst(file);
struct vdec_t *vdec;
struct v4l2_format f;
vdec = inst->priv;
vdec->frame_depth = VDEC_FRAME_DEPTH;
memset(&f, 0, sizeof(f));
f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
@ -1612,36 +1614,18 @@ static int vdec_open(struct file *file)
vdec->fixed_fmt = false;
inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP;
inst->min_buffer_out = VDEC_MIN_BUFFER_OUT;
vdec_init(file);
return 0;
}
static __poll_t vdec_poll(struct file *file, poll_table *wait)
{
struct vpu_inst *inst = to_inst(file);
struct vb2_queue *src_q, *dst_q;
__poll_t ret;
ret = v4l2_m2m_fop_poll(file, wait);
src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
if (vb2_is_streaming(src_q) && !vb2_is_streaming(dst_q))
ret &= (~EPOLLERR);
if (!src_q->error && !dst_q->error &&
(vb2_is_streaming(src_q) && list_empty(&src_q->queued_list)) &&
(vb2_is_streaming(dst_q) && list_empty(&dst_q->queued_list)))
ret &= (~EPOLLERR);
return ret;
}
static const struct v4l2_file_operations vdec_fops = {
.owner = THIS_MODULE,
.open = vdec_open,
.release = vpu_v4l2_close,
.unlocked_ioctl = video_ioctl2,
.poll = vdec_poll,
.poll = v4l2_m2m_fop_poll,
.mmap = v4l2_m2m_fop_mmap,
};

View file

@ -33,6 +33,8 @@
#define VENC_CAPTURE_ENABLE BIT(1)
#define VENC_ENABLE_MASK (VENC_OUTPUT_ENABLE | VENC_CAPTURE_ENABLE)
#define VENC_MAX_BUF_CNT 8
#define VENC_MIN_BUFFER_OUT 6
#define VENC_MIN_BUFFER_CAP 6
struct venc_t {
struct vpu_encode_params params;
@ -281,6 +283,9 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm
if (!parm)
return -EINVAL;
if (!V4L2_TYPE_IS_OUTPUT(parm->type))
return -EINVAL;
if (!vpu_helper_check_type(inst, parm->type))
return -EINVAL;
@ -302,6 +307,9 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm
if (!parm)
return -EINVAL;
if (!V4L2_TYPE_IS_OUTPUT(parm->type))
return -EINVAL;
if (!vpu_helper_check_type(inst, parm->type))
return -EINVAL;
@ -423,7 +431,7 @@ static int venc_drain(struct vpu_inst *inst)
if (inst->state != VPU_CODEC_STATE_DRAIN)
return 0;
if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx))
if (!vpu_is_source_empty(inst))
return 0;
if (!venc->input_ready)
@ -680,6 +688,12 @@ static int venc_ctrl_init(struct vpu_inst *inst)
~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
if (ret) {
dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret);
@ -775,10 +789,20 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst,
struct vb2_v4l2_buffer *vbuf)
{
struct venc_t *venc = inst->priv;
struct vb2_v4l2_buffer *src_buf;
if (!vbuf)
return -EAGAIN;
src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id);
if (src_buf) {
v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
} else {
vbuf->vb2_buf.timestamp = frame->info.timestamp;
}
if (!venc_get_enable(inst->priv, vbuf->vb2_buf.type)) {
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
return 0;
@ -800,11 +824,10 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst,
}
vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->bytesused);
vbuf->sequence = frame->info.frame_id;
vbuf->vb2_buf.timestamp = frame->info.timestamp;
vbuf->field = inst->cap_format.field;
vbuf->flags |= frame->info.pic_type;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->info.timestamp);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
venc->ready_count++;
@ -860,33 +883,6 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
return ret;
}
static void venc_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
{
struct vb2_v4l2_buffer *vbuf;
if (!inst->fh.m2m_ctx)
return;
vpu_inst_lock(inst);
if (!venc_get_enable(inst->priv, frame->type))
goto exit;
vbuf = vpu_find_buf_by_sequence(inst, frame->type, frame->sequence);
if (!vbuf) {
dev_err(inst->dev, "[%d] can't find buf: type %d, sequence %d\n",
inst->id, frame->type, frame->sequence);
goto exit;
}
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
if (V4L2_TYPE_IS_OUTPUT(frame->type))
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
else
v4l2_m2m_dst_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
exit:
vpu_inst_unlock(inst);
}
static void venc_set_last_buffer_dequeued(struct vpu_inst *inst)
{
struct venc_t *venc = inst->priv;
@ -1252,7 +1248,6 @@ static struct vpu_inst_ops venc_inst_ops = {
.check_ready = venc_check_ready,
.input_done = venc_input_done,
.get_one_frame = venc_frame_encoded,
.buf_done = venc_buf_done,
.stop_done = venc_stop_done,
.event_notify = venc_event_notify,
.release = venc_release,
@ -1333,6 +1328,8 @@ static int venc_open(struct file *file)
if (ret)
return ret;
inst->min_buffer_out = VENC_MIN_BUFFER_OUT;
inst->min_buffer_cap = VENC_MIN_BUFFER_CAP;
venc_init(file);
return 0;

View file

@ -413,10 +413,6 @@ int vpu_inst_create_dbgfs_file(struct vpu_inst *inst)
vpu->debugfs,
inst,
&vpu_dbg_inst_fops);
if (!inst->debugfs) {
dev_err(inst->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
return 0;
}
@ -451,10 +447,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core)
vpu->debugfs,
core,
&vpu_dbg_core_fops);
if (!core->debugfs) {
dev_err(core->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
}
if (!core->debugfs_fwlog) {
scnprintf(name, sizeof(name), "fwlog.%d", core->id);
@ -463,10 +455,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core)
vpu->debugfs,
core,
&vpu_dbg_fwlog_fops);
if (!core->debugfs_fwlog) {
dev_err(core->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
}
return 0;

View file

@ -69,8 +69,8 @@ enum {
VPU_MSG_ID_BS_ERROR,
VPU_MSG_ID_UNSUPPORTED,
VPU_MSG_ID_TIMESTAMP_INFO,
VPU_MSG_ID_FIRMWARE_XCPT,
VPU_MSG_ID_PIC_SKIPPED,
};
enum VPU_ENC_MEMORY_RESOURSE {

View file

@ -170,6 +170,7 @@ enum {
VID_API_EVENT_DEC_CHECK_RES = 0x24,
VID_API_EVENT_DEC_CFG_INFO = 0x25,
VID_API_EVENT_UNSUPPORTED_STREAM = 0x26,
VID_API_EVENT_PIC_SKIPPED = 0x27,
VID_API_EVENT_STR_SUSPENDED = 0x30,
VID_API_EVENT_SNAPSHOT_DONE = 0x40,
VID_API_EVENT_FW_STATUS = 0xF0,
@ -703,6 +704,7 @@ static struct vpu_pair malone_msgs[] = {
{VPU_MSG_ID_BS_ERROR, VID_API_EVENT_BS_ERROR},
{VPU_MSG_ID_UNSUPPORTED, VID_API_EVENT_UNSUPPORTED_STREAM},
{VPU_MSG_ID_FIRMWARE_XCPT, VID_API_EVENT_FIRMWARE_XCPT},
{VPU_MSG_ID_PIC_SKIPPED, VID_API_EVENT_PIC_SKIPPED},
};
static void vpu_malone_pack_fs_alloc(struct vpu_rpc_event *pkt,
@ -1556,7 +1558,7 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared,
* merge the data to next frame
*/
vbuf = to_vb2_v4l2_buffer(vb);
if (vpu_vb_is_codecconfig(vbuf) && (s64)vb->timestamp < 0) {
if (vpu_vb_is_codecconfig(vbuf)) {
inst->extra_size += size;
return 0;
}

View file

@ -166,6 +166,13 @@ static void vpu_session_handle_firmware_xcpt(struct vpu_inst *inst, struct vpu_r
vpu_v4l2_set_error(inst);
}
static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc_event *pkt)
{
vpu_inst_lock(inst);
vpu_skip_frame(inst, 1);
vpu_inst_unlock(inst);
}
static struct vpu_msg_handler handlers[] = {
{VPU_MSG_ID_START_DONE, vpu_session_handle_start_done},
{VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done},
@ -181,6 +188,7 @@ static struct vpu_msg_handler handlers[] = {
{VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos},
{VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error},
{VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt},
{VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped},
};
static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg)

View file

@ -73,10 +73,10 @@ void vpu_v4l2_set_error(struct vpu_inst *inst)
if (inst->fh.m2m_ctx) {
src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
if (src_q)
src_q->error = 1;
if (dst_q)
dst_q->error = 1;
src_q->error = 1;
dst_q->error = 1;
wake_up(&src_q->done_wq);
wake_up(&dst_q->done_wq);
}
vpu_inst_unlock(inst);
}
@ -127,6 +127,19 @@ int vpu_set_last_buffer_dequeued(struct vpu_inst *inst)
return 0;
}
bool vpu_is_source_empty(struct vpu_inst *inst)
{
struct v4l2_m2m_buffer *buf = NULL;
if (!inst->fh.m2m_ctx)
return true;
v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
if (vpu_get_buffer_state(&buf->vb) == VPU_BUF_STATE_IDLE)
return false;
}
return true;
}
const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
@ -234,6 +247,49 @@ int vpu_process_capture_buffer(struct vpu_inst *inst)
return call_vop(inst, process_capture, &vbuf->vb2_buf);
}
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst)
{
struct vb2_v4l2_buffer *src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return NULL;
while (vpu_vb_is_codecconfig(src_buf)) {
v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return NULL;
}
return src_buf;
}
void vpu_skip_frame(struct vpu_inst *inst, int count)
{
struct vb2_v4l2_buffer *src_buf;
enum vb2_buffer_state state;
int i = 0;
if (count <= 0)
return;
while (i < count) {
src_buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return;
if (vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_DECODED)
state = VB2_BUF_STATE_DONE;
else
state = VB2_BUF_STATE_ERROR;
i++;
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, state);
}
}
struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence)
{
struct v4l2_m2m_buffer *buf = NULL;
@ -342,6 +398,10 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq,
return 0;
}
if (V4L2_TYPE_IS_OUTPUT(vq->type))
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out);
else
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap);
*plane_count = cur_fmt->num_planes;
for (i = 0; i < cur_fmt->num_planes; i++)
psize[i] = cur_fmt->sizeimage[i];

View file

@ -19,6 +19,8 @@ int vpu_v4l2_close(struct file *file);
const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f);
int vpu_process_output_buffer(struct vpu_inst *inst);
int vpu_process_capture_buffer(struct vpu_inst *inst);
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst);
void vpu_skip_frame(struct vpu_inst *inst, int count);
struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence);
struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx);
void vpu_v4l2_set_error(struct vpu_inst *inst);
@ -27,6 +29,7 @@ int vpu_notify_source_change(struct vpu_inst *inst);
int vpu_set_last_buffer_dequeued(struct vpu_inst *inst);
void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state);
int vpu_get_num_buffers(struct vpu_inst *inst, u32 type);
bool vpu_is_source_empty(struct vpu_inst *inst);
dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no);
unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no);

View file

@ -1993,6 +1993,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
rc = aspeed_video_setup_video(video);
if (rc) {
aspeed_video_free_buf(video, &video->jpeg);
clk_unprepare(video->vclk);
clk_unprepare(video->eclk);
return rc;
@ -2024,8 +2025,7 @@ static int aspeed_video_remove(struct platform_device *pdev)
v4l2_device_unregister(v4l2_dev);
dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt,
video->jpeg.dma);
aspeed_video_free_buf(video, &video->jpeg);
of_reserved_mem_device_release(dev);

View file

@ -401,6 +401,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
struct isc_buffer *buf;
int ret;
mutex_lock(&isc->awb_mutex);
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
isc->stop = true;
@ -410,6 +411,8 @@ static void isc_stop_streaming(struct vb2_queue *vq)
v4l2_err(&isc->v4l2_dev,
"Timeout waiting for end of the capture\n");
mutex_unlock(&isc->awb_mutex);
/* Disable DMA interrupt */
regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
@ -442,7 +445,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&isc->dma_queue_lock, flags);
if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
vb2_is_streaming(vb->vb2_queue)) {
vb2_start_streaming_called(vb->vb2_queue)) {
isc->cur_frm = buf;
isc_start_dma(isc);
} else
@ -1029,7 +1032,7 @@ static int isc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct isc_device *isc = video_drvdata(file);
if (vb2_is_streaming(&isc->vb2_vidq))
if (vb2_is_busy(&isc->vb2_vidq))
return -EBUSY;
return isc_set_fmt(isc, f);
@ -1397,10 +1400,6 @@ static void isc_awb_work(struct work_struct *w)
u32 min, max;
int ret;
/* streaming is not active anymore */
if (isc->stop)
return;
if (ctrls->hist_stat != HIST_ENABLED)
return;
@ -1455,7 +1454,24 @@ static void isc_awb_work(struct work_struct *w)
}
regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
hist_id | baysel | ISC_HIS_CFG_RAR);
/*
* We have to make sure the streaming has not stopped meanwhile.
* ISC requires a frame to clock the internal profile update.
* To avoid issues, lock the sequence with a mutex
*/
mutex_lock(&isc->awb_mutex);
/* streaming is not active anymore */
if (isc->stop) {
mutex_unlock(&isc->awb_mutex);
return;
};
isc_update_profile(isc);
mutex_unlock(&isc->awb_mutex);
/* if awb has been disabled, we don't need to start another histogram */
if (ctrls->awb)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
@ -1534,6 +1550,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
isc_update_awb_ctrls(isc);
mutex_lock(&isc->awb_mutex);
if (vb2_is_streaming(&isc->vb2_vidq)) {
/*
* If we are streaming, we can update profile to
@ -1548,6 +1565,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
*/
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
}
mutex_unlock(&isc->awb_mutex);
/* if we have autowhitebalance on, start histogram procedure */
if (ctrls->awb == ISC_WB_AUTO &&
@ -1729,6 +1747,7 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier,
{
struct isc_device *isc = container_of(notifier->v4l2_dev,
struct isc_device, v4l2_dev);
mutex_destroy(&isc->awb_mutex);
cancel_work_sync(&isc->awb_work);
video_unregister_device(&isc->video_dev);
v4l2_ctrl_handler_free(&isc->ctrls.handler);
@ -1838,6 +1857,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
isc->current_subdev = container_of(notifier,
struct isc_subdev_entity, notifier);
mutex_init(&isc->lock);
mutex_init(&isc->awb_mutex);
init_completion(&isc->comp);
/* Initialize videobuf2 queue */
@ -1906,6 +1927,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
return 0;
isc_async_complete_err:
mutex_destroy(&isc->awb_mutex);
mutex_destroy(&isc->lock);
return ret;
}

View file

@ -218,6 +218,7 @@ struct isc_reg_offsets {
*
* @lock: lock for serializing userspace file operations
* with ISC operations
* @awb_mutex: serialize access to streaming status from awb work queue
* @awb_lock: lock for serializing awb work queue operations
* with DMA/buffer operations
*
@ -272,7 +273,7 @@ struct isc_device {
struct video_device video_dev;
struct vb2_queue vb2_vidq;
spinlock_t dma_queue_lock; /* serialize access to dma queue */
spinlock_t dma_queue_lock;
struct list_head dma_queue;
struct isc_buffer *cur_frm;
unsigned int sequence;
@ -289,8 +290,9 @@ struct isc_device {
struct isc_ctrls ctrls;
struct work_struct awb_work;
struct mutex lock; /* serialize access to file operations */
spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */
struct mutex lock;
struct mutex awb_mutex;
spinlock_t awb_lock;
struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];

View file

@ -60,56 +60,39 @@
static const struct isc_format sama5d2_controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB444,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ARGB555,
},
{
}, {
.fourcc = V4L2_PIX_FMT_RGB565,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ABGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_XBGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
},
{
}, {
.fourcc = V4L2_PIX_FMT_GREY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
},
};
@ -291,7 +274,7 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc)
* Thus, if the YCYC mode is selected, replace it with the
* sama5d2-compliant mode which is YYCC .
*/
if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) {
if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
}
@ -562,7 +545,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
ret = clk_prepare_enable(isc->ispck);
if (ret) {
dev_err(dev, "failed to enable ispck: %d\n", ret);
goto cleanup_subdev;
goto disable_pm;
}
/* ispck should be greater or equal to hclock */
@ -580,6 +563,9 @@ static int atmel_isc_probe(struct platform_device *pdev)
unprepare_clk:
clk_disable_unprepare(isc->ispck);
disable_pm:
pm_runtime_disable(dev);
cleanup_subdev:
isc_subdev_cleanup(isc);

View file

@ -63,65 +63,45 @@
static const struct isc_format sama7g5_controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB444,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ARGB555,
},
{
}, {
.fourcc = V4L2_PIX_FMT_RGB565,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ABGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_XBGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
},
{
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
},
{
}, {
.fourcc = V4L2_PIX_FMT_GREY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y16,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
},
};
@ -225,7 +205,6 @@ static struct isc_format sama7g5_formats_list[] = {
.mbus_code = MEDIA_BUS_FMT_Y10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
},
};
static void isc_sama7g5_config_csc(struct isc_device *isc)

View file

@ -454,6 +454,10 @@ static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd,
return 0;
}
static const struct media_entity_operations csi2dc_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = {
.enum_mbus_code = csi2dc_enum_mbus_code,
.set_fmt = csi2dc_set_fmt,
@ -683,6 +687,7 @@ static int csi2dc_probe(struct platform_device *pdev)
csi2dc->csi2dc_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
csi2dc->csi2dc_sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
csi2dc->csi2dc_sd.entity.ops = &csi2dc_entity_ops;
platform_set_drvdata(pdev, csi2dc);

View file

@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@ -121,12 +122,12 @@ static const struct csi2tx_fmt csi2tx_formats[] = {
{
.mbus = MEDIA_BUS_FMT_UYVY8_1X16,
.bpp = 2,
.dt = 0x1e,
.dt = MIPI_CSI2_DT_YUV422_8B,
},
{
.mbus = MEDIA_BUS_FMT_RGB888_1X24,
.bpp = 3,
.dt = 0x24,
.dt = MIPI_CSI2_DT_RGB888,
},
};

Some files were not shown because too many files have changed in this diff Show more