media updates for v5.9-rc1

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAl8tEbwACgkQCF8+vY7k
 4RUvgw//bIP9Jisg0wfUtjm34cRIKZ13PfMRYlaMKcz4Q2YVIcOCJN+xJ2kUo5M9
 D78q91g0u90OjsYIDJe/P8oKxluwr0RgXkHKsgywA+OiTIvJIEFxuvn7uiNMHFCJ
 BgU7inSZ39odgtrSbvqNAzOQgEqjx38I1NZathkRO1fr775Q5ZOhLn0fH1JroMsC
 mgfVB76p9R/UjYlYZLHumQPyxkAfN02xXmuXAqiIGBVLi/57eyuhT4qYC8FAbse6
 rYhiV3RHcZiiV0aec2HPP0BqRo5D3uIQW6Qv6FcSK8UDGpeBL8tX62Y47rqiPZED
 RExDlAHnTZgUSgquXzc+OtOolfWPctFAg6uLVHm7VVnzDOkJLQUrKWj18hEqLu87
 8H9BTo+DhDys1MUhJfzItTRsvcjke0SJUWsVhF8CWAI0PpnBH/inwLQhq2jcpsJb
 x2VxjnXJ1iyLw6zD4tJpMWhQwbpHSVjQ2cGK7w0ppMqytWxK9KJCROCrJup0T3EY
 lidp0gzymGZQxtpaUFksSAlsdjKUglrh3d1xCryZt5uepvMIFiPp+Vn6Ixmq+S8U
 UKBhW15EhVbAQdJLw5O0vsxQ/4AVSIbGXUpV6BA9mnMw9ZbDL62qB6iumCykByZC
 UyEvm/+MLLg1Y9JhyHmJzi6VI9gGZG9ayTpswhUlG4EGQDZ+U0w=
 =SYqr
 -----END PGP SIGNATURE-----

Merge tag 'media/v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - Legacy soc_camera driver was removed from staging

 - New I2C sensor related drivers: dw9768, ch7322, max9271, rdacm20

 - TI vpe driver code was re-organized and had new features added

 - Added Xilinx MIPI CSI-2 Rx Subsystem driver

 - Added support for Infrared Toy and IR Droid devices

 - Lots of random driver fixes, new features and cleanups

* tag 'media/v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (318 commits)
  media: camss: fix memory leaks on error handling paths in probe
  media: davinci: vpif_capture: fix potential double free
  media: radio: remove redundant assignment to variable retval
  media: allegro: fix potential null dereference on header
  media: mtk-mdp: Fix a refcounting bug on error in init
  media: allegro: fix an error pointer vs NULL check
  media: meye: fix missing pm_mchip_mode field
  media: cafe-driver: use generic power management
  media: saa7164: use generic power management
  media: v4l2-dev/ioctl: Fix document for VIDIOC_QUERYCAP
  media: v4l2: Correct kernel-doc inconsistency
  media: v4l2: Correct kernel-doc inconsistency
  media: dvbdev.h: keep * together with the type
  media: v4l2-subdev.h: keep * together with the type
  media: videobuf2: Print videobuf2 buffer state by name
  media: colorspaces-details.rst: fix V4L2_COLORSPACE_JPEG description
  media: tw68: use generic power management
  media: meye: use generic power management
  media: cx88: use generic power management
  media: cx25821: use generic power management
  ...
This commit is contained in:
Linus Torvalds 2020-08-07 13:00:53 -07:00
commit fa73e21231
268 changed files with 12841 additions and 12172 deletions

View File

@ -2,7 +2,7 @@
.. include:: <isonum.txt>
The Samsung S5P/EXYNOS4 FIMC driver
The Samsung S5P/Exynos4 FIMC driver
===================================
Copyright |copy| 2012 - 2013 Samsung Electronics Co., Ltd.
@ -19,7 +19,7 @@ drivers/media/platform/exynos4-is directory.
Supported SoCs
--------------
S5PC100 (mem-to-mem only), S5PV210, EXYNOS4210
S5PC100 (mem-to-mem only), S5PV210, Exynos4210
Supported features
------------------
@ -45,7 +45,7 @@ Media device interface
~~~~~~~~~~~~~~~~~~~~~~
The driver supports Media Controller API as defined at :ref:`media_controller`.
The media device driver name is "SAMSUNG S5P FIMC".
The media device driver name is "Samsung S5P FIMC".
The purpose of this interface is to allow changing assignment of FIMC instances
to the SoC peripheral camera input at runtime and optionally to control internal

View File

@ -293,6 +293,15 @@ all configurable using the following module options:
- 0: vmalloc
- 1: dma-contig
- cache_hints:
specifies if the device should set queues' user-space cache and memory
consistency hint capability (V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS).
The hints are valid only when using MMAP streaming I/O. Default is 0.
- 0: forbid hints
- 1: allow hints
Taken together, all these module options allow you to precisely customize
the driver behavior and test your application with all sorts of permutations.
It is also very suitable to emulate hardware that is not yet available, e.g.

View File

@ -0,0 +1,67 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/media/i2c/chrontel,ch7322.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Chrontel HDMI-CEC Controller
maintainers:
- Jeff Chase <jnchase@google.com>
description:
The Chrontel CH7322 is a discrete HDMI-CEC controller. It is
programmable through I2C and drives a single CEC line.
properties:
compatible:
const: chrontel,ch7322
reg:
description: I2C device address
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
reset-gpios:
description:
Reference to the GPIO connected to the RESET pin, if any. This
pin is active-low.
maxItems: 1
standby-gpios:
description:
Reference to the GPIO connected to the OE pin, if any. When low
the device will respond to power status requests with "standby"
if in auto mode.
maxItems: 1
# see ../cec.txt
hdmi-phandle:
description: phandle to the HDMI controller
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
ch7322@75 {
compatible = "chrontel,ch7322";
reg = <0x75>;
interrupts = <47 IRQ_TYPE_EDGE_RISING>;
standby-gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
hdmi-phandle = <&hdmi>;
};
};

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9768.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dongwoon Anatech DW9768 Voice Coil Motor (VCM) Lens Device Tree Bindings
maintainers:
- Dongchun Zhu <dongchun.zhu@mediatek.com>
description: |-
The Dongwoon DW9768 is a single 10-bit digital-to-analog (DAC) converter
with 100 mA output current sink capability. VCM current is controlled with
a linear mode driver. The DAC is controlled via a 2-wire (I2C-compatible)
serial interface that operates at clock rates up to 1MHz. This chip
integrates Advanced Actuator Control (AAC) technology and is intended for
driving voice coil lenses in camera modules.
properties:
compatible:
enum:
- dongwoon,dw9768 # for DW9768 VCM
- giantec,gt9769 # for GT9769 VCM
reg:
maxItems: 1
vin-supply:
description:
Definition of the regulator used as Digital I/O voltage supply.
vdd-supply:
description:
Definition of the regulator used as Digital core voltage supply.
dongwoon,aac-mode:
description:
Indication of AAC mode select.
allOf:
- $ref: "/schemas/types.yaml#/definitions/uint32"
- enum:
- 1 # AAC2 mode(operation time# 0.48 x Tvib)
- 2 # AAC3 mode(operation time# 0.70 x Tvib)
- 3 # AAC4 mode(operation time# 0.75 x Tvib)
- 5 # AAC8 mode(operation time# 1.13 x Tvib)
default: 2
dongwoon,aac-timing:
description:
Number of AAC Timing count that controlled by one 6-bit period of
vibration register AACT[5:0], the unit of which is 100 us.
allOf:
- $ref: "/schemas/types.yaml#/definitions/uint32"
- default: 0x20
minimum: 0x00
maximum: 0x3f
dongwoon,clock-presc:
description:
Indication of VCM internal clock dividing rate select, as one multiple
factor to calculate VCM ring periodic time Tvib.
allOf:
- $ref: "/schemas/types.yaml#/definitions/uint32"
- enum:
- 0 # Dividing Rate - 2
- 1 # Dividing Rate - 1
- 2 # Dividing Rate - 1/2
- 3 # Dividing Rate - 1/4
- 4 # Dividing Rate - 8
- 5 # Dividing Rate - 4
default: 1
required:
- compatible
- reg
- vin-supply
- vdd-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
dw9768: camera-lens@c {
compatible = "dongwoon,dw9768";
reg = <0x0c>;
vin-supply = <&mt6358_vcamio_reg>;
vdd-supply = <&mt6358_vcama2_reg>;
dongwoon,aac-timing = <0x39>;
};
};
...

View File

@ -0,0 +1,159 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
# Copyright (C) 2019 Renesas Electronics Corp.
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/imi,rdacm2x-gmsl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: IMI D&D RDACM20 and RDACM21 Automotive Camera Platforms
maintainers:
- Jacopo Mondi <jacopo+renesas@jmondi.org>
- Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
- Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
description: -|
The IMI D&D RDACM20 and RDACM21 are GMSL-compatible camera designed for
automotive applications.
The RDACM20 camera module encloses a Maxim Integrated MAX9271 GMSL serializer,
coupled with an OV10635 image sensor and an embedded MCU. Both the MCU and
the image sensor are connected to the serializer local I2C bus and are
accessible by the host SoC by direct addressing.
The RDACM21 camera module encloses the same serializer, coupled with an
OV10640 image sensor and an OV490 ISP. Only the OV490 ISP is interfaced to
the serializer local I2C bus while the image sensor is not accessible from
the host SoC.
They both connect to a remote GMSL endpoint through a coaxial cable.
IMI RDACM20
+---------------+ +--------------------------------+
| GMSL | <- Video Stream | <- Video--------\ |
| |< === GMSL Link ====== >|MAX9271<- I2C bus-> <-->OV10635 |
| de-serializer | <- I2C messages -> | \<-->MCU |
+---------------+ +--------------------------------+
IMI RDACM21
+---------------+ +--------------------------------+
| GMSL | <- Video Stream | <- Video--------\ |
| |< === GMSL Link ====== >|MAX9271<- I2C bus-> <-->OV490 |
| | <- I2C messages -> | | |
| de-serializer | | OV10640 <-------| |
+---------------+ +--------------------------------+
Both camera modules serialize video data generated by the embedded camera
sensor on the GMSL serial channel to a remote GMSL de-serializer. They also
receive and transmit I2C messages encapsulated and transmitted on the GMSL
bidirectional control channel.
All I2C traffic received on the GMSL link not directed to the serializer is
propagated on the local I2C bus to the remote device there connected. All the
I2C traffic generated on the local I2C bus not directed to the serializer is
propagated to the remote de-serializer encapsulated in the GMSL control
channel.
The RDACM20 and RDACM21 DT node should be a direct child of the GMSL
deserializer's I2C bus corresponding to the GMSL link that the camera is
attached to.
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
compatible:
enum:
- imi,rdacm20
- imi,rdacm21
reg:
description: -|
I2C device addresses, the first to be assigned to the serializer, the
following ones to be assigned to the remote devices.
For RDACM20 the second entry of the property is assigned to the
OV10635 image sensor and the optional third one to the embedded MCU.
For RDACM21 the second entry is assigned to the OV490 ISP and the optional
third one ignored.
minItems: 2
maxItems: 3
port:
type: object
additionalProperties: false
description: -|
Connection to the remote GMSL endpoint are modelled using the OF graph
bindings in accordance with the video interface bindings defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
The device node contains a single "port" child node with a single
"endpoint" sub-device.
properties:
endpoint:
type: object
additionalProperties: false
properties:
remote-endpoint:
description: -|
phandle to the remote GMSL endpoint sub-node in the remote node
port.
maxItems: 1
required:
- remote-endpoint
required:
- endpoint
required:
- compatible
- reg
- port
examples:
- |
i2c@e66d8000 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0xe66d8000>;
camera@31 {
compatible = "imi,rdacm20";
reg = <0x31>, <0x41>, <0x51>;
port {
rdacm20_out0: endpoint {
remote-endpoint = <&max9286_in0>;
};
};
};
};
- |
i2c@e66d8000 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0xe66d8000>;
camera@31 {
compatible = "imi,rdacm21";
reg = <0x31>, <0x41>;
port {
rdacm21_out0: endpoint {
remote-endpoint = <&max9286_in0>;
};
};
};
};

View File

@ -0,0 +1,366 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2019 Renesas Electronics Corp.
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/maxim,max9286.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim Integrated Quad GMSL Deserializer
maintainers:
- Jacopo Mondi <jacopo+renesas@jmondi.org>
- Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
- Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
description: |
The MAX9286 deserializer receives video data on up to 4 Gigabit Multimedia
Serial Links (GMSL) and outputs them on a CSI-2 D-PHY port using up to 4 data
lanes.
In addition to video data, the GMSL links carry a bidirectional control
channel that encapsulates I2C messages. The MAX9286 forwards all I2C traffic
not addressed to itself to the other side of the links, where a GMSL
serializer will output it on a local I2C bus. In the other direction all I2C
traffic received over GMSL by the MAX9286 is output on the local I2C bus.
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
compatible:
const: maxim,max9286
reg:
description: I2C device address
maxItems: 1
poc-supply:
description: Regulator providing Power over Coax to the cameras
maxItems: 1
enable-gpios:
description: GPIO connected to the \#PWDN pin with inverted polarity
maxItems: 1
gpio-controller: true
'#gpio-cells':
const: 2
ports:
type: object
description: |
The connections to the MAX9286 GMSL and its endpoint nodes are modelled
using the OF graph bindings in accordance with the video interface
bindings defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
The following table lists the port number corresponding to each device
port.
Port Description
----------------------------------------
Port 0 GMSL Input 0
Port 1 GMSL Input 1
Port 2 GMSL Input 2
Port 3 GMSL Input 3
Port 4 CSI-2 Output
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
port@[0-3]:
type: object
properties:
reg:
enum: [ 0, 1, 2, 3 ]
endpoint:
type: object
properties:
remote-endpoint:
description: |
phandle to the remote GMSL source endpoint subnode in the
remote node port.
required:
- remote-endpoint
required:
- reg
- endpoint
additionalProperties: false
port@4:
type: object
properties:
reg:
const: 4
endpoint:
type: object
properties:
remote-endpoint:
description: phandle to the remote CSI-2 sink endpoint.
data-lanes:
description: array of physical CSI-2 data lane indexes.
required:
- remote-endpoint
- data-lanes
required:
- reg
- endpoint
additionalProperties: false
required:
- port@4
i2c-mux:
type: object
description: |
Each GMSL link is modelled as a child bus of an i2c bus
multiplexer/switch, in accordance with bindings described in
Documentation/devicetree/bindings/i2c/i2c-mux.txt.
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
"^i2c@[0-3]$":
type: object
description: |
Child node of the i2c bus multiplexer which represents a GMSL link.
Each serializer device on the GMSL link remote end is represented with
an i2c-mux child node. The MAX9286 chip supports up to 4 GMSL
channels.
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
reg:
description: The index of the GMSL channel.
maxItems: 1
patternProperties:
"^camera@[a-f0-9]+$":
type: object
description: |
The remote camera device, composed by a GMSL serializer and a
connected video source.
properties:
compatible:
description: The remote device compatible string.
reg:
minItems: 2
maxItems: 3
description: |
The I2C addresses to be assigned to the remote devices through
address reprogramming. The number of entries depends on the
requirements of the currently connected remote device.
port:
type: object
properties:
endpoint:
type: object
properties:
remote-endpoint:
description: phandle to the MAX9286 sink endpoint.
required:
- remote-endpoint
additionalProperties: false
required:
- endpoint
additionalProperties: false
required:
- compatible
- reg
- port
additionalProperties: false
additionalProperties: false
additionalProperties: false
required:
- compatible
- reg
- ports
- i2c-mux
- gpio-controller
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c@e66d8000 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0xe66d8000>;
gmsl-deserializer@2c {
compatible = "maxim,max9286";
reg = <0x2c>;
poc-supply = <&camera_poc_12v>;
enable-gpios = <&gpio 13 GPIO_ACTIVE_HIGH>;
gpio-controller;
#gpio-cells = <2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
max9286_in0: endpoint {
remote-endpoint = <&rdacm20_out0>;
};
};
port@1 {
reg = <1>;
max9286_in1: endpoint {
remote-endpoint = <&rdacm20_out1>;
};
};
port@2 {
reg = <2>;
max9286_in2: endpoint {
remote-endpoint = <&rdacm20_out2>;
};
};
port@3 {
reg = <3>;
max9286_in3: endpoint {
remote-endpoint = <&rdacm20_out3>;
};
};
port@4 {
reg = <4>;
max9286_out: endpoint {
data-lanes = <1 2 3 4>;
remote-endpoint = <&csi40_in>;
};
};
};
i2c-mux {
#address-cells = <1>;
#size-cells = <0>;
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
camera@51 {
compatible = "imi,rdacm20";
reg = <0x51>, <0x61>;
port {
rdacm20_out0: endpoint {
remote-endpoint = <&max9286_in0>;
};
};
};
};
i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
camera@52 {
compatible = "imi,rdacm20";
reg = <0x52>, <0x62>;
port {
rdacm20_out1: endpoint {
remote-endpoint = <&max9286_in1>;
};
};
};
};
i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
camera@53 {
compatible = "imi,rdacm20";
reg = <0x53>, <0x63>;
port {
rdacm20_out2: endpoint {
remote-endpoint = <&max9286_in2>;
};
};
};
};
i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
camera@54 {
compatible = "imi,rdacm20";
reg = <0x54>, <0x64>;
port {
rdacm20_out3: endpoint {
remote-endpoint = <&max9286_in3>;
};
};
};
};
};
};
};

View File

@ -1,34 +0,0 @@
Renesas R-Car Frame Compression Processor (FCP)
-----------------------------------------------
The FCP is a companion module of video processing modules in the Renesas R-Car
Gen3 and RZ/G2 SoCs. It provides data compression and decompression, data
caching, and conversion of AXI transactions in order to reduce the memory
bandwidth.
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP
for FDP (FCPF). Their configuration and behaviour depend on the module they
are paired with. These DT bindings currently support the FCPV and FCPF.
- compatible: Must be one or more of the following
- "renesas,fcpv" for generic compatible 'FCP for VSP'
- "renesas,fcpf" for generic compatible 'FCP for FDP'
- reg: the register base and size for the device registers
- clocks: Reference to the functional clock
Optional properties:
- power-domains : power-domain property defined with a power domain specifier
to respective power domain.
Device node example
-------------------
fcpvd1: fcp@fea2f000 {
compatible = "renesas,fcpv";
reg = <0 0xfea2f000 0 0x200>;
clocks = <&cpg CPG_MOD 602>;
power-domains = <&sysc R8A7795_PD_A3VP>;
};

View File

@ -0,0 +1,66 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/renesas,fcp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car Frame Compression Processor (FCP)
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
description: |
The FCP is a companion module of video processing modules in the Renesas
R-Car Gen3 and RZ/G2 SoCs. It provides data compression and decompression,
data caching, and conversion of AXI transactions in order to reduce the
memory bandwidth.
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and
FCP for FDP (FCPF). Their configuration and behaviour depend on the module
they are paired with. These DT bindings currently support the FCPV and FCPF.
properties:
compatible:
enum:
- renesas,fcpv # FCP for VSP
- renesas,fcpf # FCP for FDP
reg:
maxItems: 1
clocks:
maxItems: 1
iommus:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- clocks
- power-domains
- resets
additionalProperties: false
examples:
# R8A7795 (R-Car H3) FCP for VSP-D1
- |
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include <dt-bindings/power/r8a7795-sysc.h>
fcp@fea2f000 {
compatible = "renesas,fcpv";
reg = <0xfea2f000 0x200>;
clocks = <&cpg CPG_MOD 602>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 602>;
iommus = <&ipmmu_vi0 9>;
};
...

View File

@ -1,37 +0,0 @@
Renesas R-Car Fine Display Processor (FDP1)
-------------------------------------------
The FDP1 is a de-interlacing module which converts interlaced video to
progressive video. It is capable of performing pixel format conversion between
YCbCr/YUV formats and RGB formats. Only YCbCr/YUV formats are supported as
an input to the module.
Required properties:
- compatible: must be "renesas,fdp1"
- reg: the register base and size for the device registers
- interrupts : interrupt specifier for the FDP1 instance
- clocks: reference to the functional clock
Optional properties:
- power-domains: reference to the power domain that the FDP1 belongs to, if
any.
- renesas,fcp: a phandle referencing the FCP that handles memory accesses
for the FDP1. Not needed on Gen2, mandatory on Gen3.
Please refer to the binding documentation for the clock and/or power domain
providers for more details.
Device node example
-------------------
fdp1@fe940000 {
compatible = "renesas,fdp1";
reg = <0 0xfe940000 0 0x2400>;
interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 119>;
power-domains = <&sysc R8A7795_PD_A3VP>;
renesas,fcp = <&fcpf0>;
};

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/renesas,fdp1.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car Fine Display Processor (FDP1)
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
description:
The FDP1 is a de-interlacing module which converts interlaced video to
progressive video. It is capable of performing pixel format conversion
between YCbCr/YUV formats and RGB formats. Only YCbCr/YUV formats are
supported as an input to the module.
properties:
compatible:
enum:
- renesas,fdp1
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
renesas,fcp:
$ref: /schemas/types.yaml#/definitions/phandle
description:
A phandle referencing the FCP that handles memory accesses for the FDP1.
Not allowed on R-Car Gen2, mandatory on R-Car Gen3.
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7795-sysc.h>
fdp1@fe940000 {
compatible = "renesas,fdp1";
reg = <0xfe940000 0x2400>;
interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 119>;
power-domains = <&sysc R8A7795_PD_A3VP>;
resets = <&cpg 119>;
renesas,fcp = <&fcpf0>;
};
...

View File

@ -1,30 +0,0 @@
* Renesas VSP Video Processing Engine
The VSP is a video processing engine that supports up-/down-scaling, alpha
blending, color space conversion and various other image processing features.
It can be found in the Renesas R-Car Gen2, R-Car Gen3, RZ/G1, and RZ/G2 SoCs.
Required properties:
- compatible: Must contain one of the following values
- "renesas,vsp1" for the R-Car Gen2 and RZ/G1 VSP1
- "renesas,vsp2" for the R-Car Gen3 and RZ/G2 VSP2
- reg: Base address and length of the registers block for the VSP.
- interrupts: VSP interrupt specifier.
- clocks: A phandle + clock-specifier pair for the VSP functional clock.
Optional properties:
- renesas,fcp: A phandle referencing the FCP that handles memory accesses
for the VSP. Not needed on Gen2, mandatory on Gen3.
Example: R8A7790 (R-Car H2) VSP1-S node
vsp@fe928000 {
compatible = "renesas,vsp1";
reg = <0 0xfe928000 0 0x8000>;
interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>;
};

View File

@ -0,0 +1,97 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/renesas,vsp1.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas VSP Video Processing Engine
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
description:
The VSP is a video processing engine that supports up-/down-scaling, alpha
blending, color space conversion and various other image processing features.
It can be found in the Renesas R-Car Gen2, R-Car Gen3, RZ/G1, and RZ/G2 SoCs.
properties:
compatible:
enum:
- renesas,vsp1 # R-Car Gen2 and RZ/G1
- renesas,vsp2 # R-Car Gen3 and RZ/G2
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
renesas,fcp:
$ref: /schemas/types.yaml#/definitions/phandle
description:
A phandle referencing the FCP that handles memory accesses for the VSP.
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
additionalProperties: false
if:
properties:
compatible:
items:
- const: renesas,vsp1
then:
properties:
renesas,fcp: false
else:
required:
- renesas,fcp
examples:
# R8A7790 (R-Car H2) VSP1-S
- |
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7790-sysc.h>
vsp@fe928000 {
compatible = "renesas,vsp1";
reg = <0xfe928000 0x8000>;
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 131>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 131>;
};
# R8A77951 (R-Car H3) VSP2-BC
- |
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7795-sysc.h>
vsp@fe920000 {
compatible = "renesas,vsp2";
reg = <0xfe920000 0x8000>;
interrupts = <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 624>;
power-domains = <&sysc R8A7795_PD_A3VP>;
resets = <&cpg 624>;
renesas,fcp = <&fcpvb1>;
};
...

View File

@ -0,0 +1,237 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/xilinx/xlnx,csi2rxss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx MIPI CSI-2 Receiver Subsystem
maintainers:
- Vishal Sagar <vishal.sagar@xilinx.com>
description: |
The Xilinx MIPI CSI-2 Receiver Subsystem is used to capture MIPI CSI-2
traffic from compliant camera sensors and send the output as AXI4 Stream
video data for image processing.
The subsystem consists of a MIPI D-PHY in slave mode which captures the
data packets. This is passed along the MIPI CSI-2 Rx IP which extracts the
packet data. The optional Video Format Bridge (VFB) converts this data to
AXI4 Stream video data.
For more details, please refer to PG232 Xilinx MIPI CSI-2 Receiver Subsystem.
Please note that this bindings includes only the MIPI CSI-2 Rx controller
and Video Format Bridge and not D-PHY.
properties:
compatible:
items:
- enum:
- xlnx,mipi-csi2-rx-subsystem-5.0
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
description: List of clock specifiers
items:
- description: AXI Lite clock
- description: Video clock
clock-names:
items:
- const: lite_aclk
- const: video_aclk
xlnx,csi-pxl-format:
description: |
This denotes the CSI Data type selected in hw design.
Packets other than this data type (except for RAW8 and
User defined data types) will be filtered out.
Possible values are as below -
0x1e - YUV4228B
0x1f - YUV42210B
0x20 - RGB444
0x21 - RGB555
0x22 - RGB565
0x23 - RGB666
0x24 - RGB888
0x28 - RAW6
0x29 - RAW7
0x2a - RAW8
0x2b - RAW10
0x2c - RAW12
0x2d - RAW14
0x2e - RAW16
0x2f - RAW20
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- anyOf:
- minimum: 0x1e
- maximum: 0x24
- minimum: 0x28
- maximum: 0x2f
xlnx,vfb:
type: boolean
description: Present when Video Format Bridge is enabled in IP configuration
xlnx,en-csi-v2-0:
type: boolean
description: Present if CSI v2 is enabled in IP configuration.
xlnx,en-vcx:
type: boolean
description: |
When present, there are maximum 16 virtual channels, else only 4.
xlnx,en-active-lanes:
type: boolean
description: |
Present if the number of active lanes can be re-configured at
runtime in the Protocol Configuration Register. Otherwise all lanes,
as set in IP configuration, are always active.
video-reset-gpios:
description: Optional specifier for a GPIO that asserts video_aresetn.
maxItems: 1
ports:
type: object
properties:
port@0:
type: object
description: |
Input / sink port node, single endpoint describing the
CSI-2 transmitter.
properties:
reg:
const: 0
endpoint:
type: object
properties:
data-lanes:
description: |
This is required only in the sink port 0 endpoint which
connects to MIPI CSI-2 source like sensor.
The possible values are -
1 - For 1 lane enabled in IP.
1 2 - For 2 lanes enabled in IP.
1 2 3 - For 3 lanes enabled in IP.
1 2 3 4 - For 4 lanes enabled in IP.
items:
- const: 1
- const: 2
- const: 3
- const: 4
remote-endpoint: true
required:
- data-lanes
- remote-endpoint
additionalProperties: false
additionalProperties: false
port@1:
type: object
description: |
Output / source port node, endpoint describing modules
connected the CSI-2 receiver.
properties:
reg:
const: 1
endpoint:
type: object
properties:
remote-endpoint: true
required:
- remote-endpoint
additionalProperties: false
additionalProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- ports
allOf:
- if:
required:
- xlnx,vfb
then:
required:
- xlnx,csi-pxl-format
else:
properties:
xlnx,csi-pxl-format: false
- if:
not:
required:
- xlnx,en-csi-v2-0
then:
properties:
xlnx,en-vcx: false
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
xcsi2rxss_1: csi2rx@a0020000 {
compatible = "xlnx,mipi-csi2-rx-subsystem-5.0";
reg = <0xa0020000 0x10000>;
interrupt-parent = <&gic>;
interrupts = <0 95 4>;
xlnx,csi-pxl-format = <0x2a>;
xlnx,vfb;
xlnx,en-active-lanes;
xlnx,en-csi-v2-0;
xlnx,en-vcx;
clock-names = "lite_aclk", "video_aclk";
clocks = <&misc_clk_0>, <&misc_clk_1>;
video-reset-gpios = <&gpio 86 GPIO_ACTIVE_LOW>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
/* Sink port */
reg = <0>;
csiss_in: endpoint {
data-lanes = <1 2 3 4>;
/* MIPI CSI-2 Camera handle */
remote-endpoint = <&camera_out>;
};
};
port@1 {
/* Source port */
reg = <1>;
csiss_out: endpoint {
remote-endpoint = <&vproc_in>;
};
};
};
};
...

View File

@ -473,6 +473,8 @@ patternProperties:
description: ILI Technology Corporation (ILITEK)
"^img,.*":
description: Imagination Technologies Ltd.
"^imi,.*":
description: Integrated Micro-Electronics Inc.
"^incircuit,.*":
description: In-Circuit GmbH
"^inet-tek,.*":

View File

@ -20,7 +20,7 @@ last known snapshot and evolved the driver to the state it is in
here.
More information on this driver can be found at:
http://www.isely.net/pvrusb2.html
https://www.isely.net/pvrusb2.html
This driver has a strong separation of layers. They are very

View File

@ -18,7 +18,7 @@ These differ mainly by the bandswitch byte.
Tuner Manufacturers
-------------------
- SAMSUNG Tuner identification: (e.g. TCPM9091PD27)
- Samsung Tuner identification: (e.g. TCPM9091PD27)
.. code-block:: none

View File

@ -57,6 +57,9 @@ returns the information to the application. The ioctl never fails.
- ``name[32]``
- The name of this CEC adapter. The combination ``driver`` and
``name`` must be unique.
* - __u32
- ``available_log_addrs``
- The maximum number of logical addresses that can be configured.
* - __u32
- ``capabilities``
- The capabilities of the CEC adapter, see

View File

@ -34,8 +34,7 @@ Arguments
File descriptor returned by :ref:`open() <frontend_f_open>`.
``argp``
pointer to struct struct
:c:type:`dvb_frontend_info`
pointer to struct :c:type:`dvb_frontend_info`
Description

View File

@ -23,8 +23,8 @@ argument to the :ref:`VIDIOC_QUERYBUF`,
:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. In the multi-planar API,
some plane-specific members of struct :c:type:`v4l2_buffer`,
such as pointers and sizes for each plane, are stored in struct
struct :c:type:`v4l2_plane` instead. In that case, struct
such as pointers and sizes for each plane, are stored in
struct :c:type:`v4l2_plane` instead. In that case,
struct :c:type:`v4l2_buffer` contains an array of plane structures.
Dequeued video buffers come with timestamps. The driver decides at which
@ -577,7 +577,10 @@ Buffer Flags
applications shall use this flag if the data captured in the
buffer is not going to be touched by the CPU, instead the buffer
will, probably, be passed on to a DMA-capable hardware unit for
further processing or output.
further processing or output. This flag is ignored unless the
queue is used for :ref:`memory mapping <mmap>` streaming I/O and
reports :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS
<V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability.
* .. _`V4L2-BUF-FLAG-NO-CACHE-CLEAN`:
- ``V4L2_BUF_FLAG_NO_CACHE_CLEAN``
@ -585,7 +588,10 @@ Buffer Flags
- Caches do not have to be cleaned for this buffer. Typically
applications shall use this flag for output buffers if the data in
this buffer has not been created by the CPU but by some
DMA-capable unit, in which case caches have not been used.
DMA-capable unit, in which case caches have not been used. This flag
is ignored unless the queue is used for :ref:`memory mapping <mmap>`
streaming I/O and reports :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS
<V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability.
* .. _`V4L2-BUF-FLAG-M2M-HOLD-CAPTURE-BUF`:
- ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF``
@ -681,6 +687,36 @@ Buffer Flags
\normalsize
.. _memory-flags:
Memory Consistency Flags
========================
.. tabularcolumns:: |p{7.0cm}|p{2.2cm}|p{8.3cm}|
.. cssclass:: longtable
.. flat-table::
:header-rows: 0
:stub-columns: 0
:widths: 3 1 4
* .. _`V4L2-FLAG-MEMORY-NON-CONSISTENT`:
- ``V4L2_FLAG_MEMORY_NON_CONSISTENT``
- 0x00000001
- A buffer is allocated either in consistent (it will be automatically
coherent between the CPU and the bus) or non-consistent memory. The
latter can provide performance gains, for instance the CPU cache
sync/flush operations can be avoided if the buffer is accessed by the
corresponding device only and the CPU does not read/write to/from that
buffer. However, this requires extra care from the driver -- it must
guarantee memory consistency by issuing a cache flush/sync when
consistency is needed. If this flag is set V4L2 will attempt to
allocate the buffer in non-consistent memory. The flag takes effect
only if the buffer is used for :ref:`memory mapping <mmap>` I/O and the
queue reports the :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS
<V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability.
.. c:type:: v4l2_memory

View File

@ -767,8 +767,8 @@ scaled to [-128…128] and then clipped to [-128…127].
information. So if something other than sRGB is used, then the driver
will have to set that information explicitly. Effectively
``V4L2_COLORSPACE_JPEG`` can be considered to be an abbreviation for
``V4L2_COLORSPACE_SRGB``, ``V4L2_YCBCR_ENC_601`` and
``V4L2_QUANTIZATION_FULL_RANGE``.
``V4L2_COLORSPACE_SRGB``, ``V4L2_XFER_FUNC_SRGB``, ``V4L2_YCBCR_ENC_601``
and ``V4L2_QUANTIZATION_FULL_RANGE``.
***************************************
Detailed Transfer Function Descriptions

View File

@ -247,7 +247,7 @@ Querying Capabilities
Initialization
==============
1. Set the coded format on ``OUTPUT`` via :c:func:`VIDIOC_S_FMT`
1. Set the coded format on ``OUTPUT`` via :c:func:`VIDIOC_S_FMT`.
* **Required fields:**
@ -803,7 +803,7 @@ it may be affected as per normal decoder operation.
* The decoder will drop all the pending ``OUTPUT`` buffers and they must be
treated as returned to the client (following standard semantics).
2. Restart the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON`
2. Restart the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON`.
* **Required fields:**
@ -906,7 +906,9 @@ reflected by corresponding queries):
* visible resolution (selection rectangles),
* the minimum number of buffers needed for decoding.
* the minimum number of buffers needed for decoding,
* bit-depth of the bitstream has been changed.
Whenever that happens, the decoder must proceed as follows:
@ -1059,7 +1061,7 @@ sequence was started.
``V4L2_DEC_CMD_STOP`` again while the drain sequence is in progress and they
will fail with -EBUSY error code if attempted.
Although mandatory, the availability of decoder commands may be queried
Although not mandatory, the availability of decoder commands may be queried
using :c:func:`VIDIOC_TRY_DECODER_CMD`.
End of Stream

View File

@ -0,0 +1,753 @@
.. This file is dual-licensed: you can use it either under the terms
.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
.. dual licensing only applies to this file, and not this project as a
.. whole.
..
.. a) This file is free software; you can redistribute it and/or
.. modify it under the terms of the GNU General Public License as
.. published by the Free Software Foundation version 2 of
.. the License.
..
.. This file is distributed in the hope that it will be useful,
.. but WITHOUT ANY WARRANTY; without even the implied warranty of
.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.. GNU General Public License for more details.
..
.. Or, alternatively,
..
.. b) Permission is granted to copy, distribute and/or modify this
.. document under the terms of the GNU Free Documentation License,
.. Version 1.1 or any later version published by the Free Software
.. Foundation, with no Invariant Sections, no Front-Cover Texts
.. and no Back-Cover Texts. A copy of the license is included at
.. Documentation/userspace-api/media/fdl-appendix.rst.
..
.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
.. _encoder:
*************************************************
Memory-to-Memory Stateful Video Encoder Interface
*************************************************
A stateful video encoder takes raw video frames in display order and encodes
them into a bytestream. It generates complete chunks of the bytestream, including
all metadata, headers, etc. The resulting bytestream does not require any
further post-processing by the client.
Performing software stream processing, header generation etc. in the driver
in order to support this interface is strongly discouraged. In case such
operations are needed, use of the Stateless Video Encoder Interface (in
development) is strongly advised.
Conventions and Notations Used in This Document
===============================================
1. The general V4L2 API rules apply if not specified in this document
otherwise.
2. The meaning of words "must", "may", "should", etc. is as per `RFC
2119 <https://tools.ietf.org/html/rfc2119>`_.
3. All steps not marked "optional" are required.
4. :c:func:`VIDIOC_G_EXT_CTRLS` and :c:func:`VIDIOC_S_EXT_CTRLS` may be used
interchangeably with :c:func:`VIDIOC_G_CTRL` and :c:func:`VIDIOC_S_CTRL`,
unless specified otherwise.
5. Single-planar API (see :ref:`planar-apis`) and applicable structures may be
used interchangeably with multi-planar API, unless specified otherwise,
depending on encoder capabilities and following the general V4L2 guidelines.
6. i = [a..b]: sequence of integers from a to b, inclusive, i.e. i =
[0..2]: i = 0, 1, 2.
7. Given an ``OUTPUT`` buffer A, then A' represents a buffer on the ``CAPTURE``
queue containing data that resulted from processing buffer A.
Glossary
========
Refer to :ref:`decoder-glossary`.
State Machine
=============
.. kernel-render:: DOT
:alt: DOT digraph of encoder state machine
:caption: Encoder State Machine
digraph encoder_state_machine {
node [shape = doublecircle, label="Encoding"] Encoding;
node [shape = circle, label="Initialization"] Initialization;
node [shape = circle, label="Stopped"] Stopped;
node [shape = circle, label="Drain"] Drain;
node [shape = circle, label="Reset"] Reset;
node [shape = point]; qi
qi -> Initialization [ label = "open()" ];
Initialization -> Encoding [ label = "Both queues streaming" ];
Encoding -> Drain [ label = "V4L2_ENC_CMD_STOP" ];
Encoding -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ];
Encoding -> Stopped [ label = "VIDIOC_STREAMOFF(OUTPUT)" ];
Encoding -> Encoding;
Drain -> Stopped [ label = "All CAPTURE\nbuffers dequeued\nor\nVIDIOC_STREAMOFF(OUTPUT)" ];
Drain -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ];
Reset -> Encoding [ label = "VIDIOC_STREAMON(CAPTURE)" ];
Reset -> Initialization [ label = "VIDIOC_REQBUFS(OUTPUT, 0)" ];
Stopped -> Encoding [ label = "V4L2_ENC_CMD_START\nor\nVIDIOC_STREAMON(OUTPUT)" ];
Stopped -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ];
}
Querying Capabilities
=====================
1. To enumerate the set of coded formats supported by the encoder, the
client may call :c:func:`VIDIOC_ENUM_FMT` on ``CAPTURE``.
* The full set of supported formats will be returned, regardless of the
format set on ``OUTPUT``.
2. To enumerate the set of supported raw formats, the client may call
:c:func:`VIDIOC_ENUM_FMT` on ``OUTPUT``.
* Only the formats supported for the format currently active on ``CAPTURE``
will be returned.
* In order to enumerate raw formats supported by a given coded format,
the client must first set that coded format on ``CAPTURE`` and then
enumerate the formats on ``OUTPUT``.
3. The client may use :c:func:`VIDIOC_ENUM_FRAMESIZES` to detect supported
resolutions for a given format, passing the desired pixel format in
:c:type:`v4l2_frmsizeenum` ``pixel_format``.
* Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a coded pixel
format will include all possible coded resolutions supported by the
encoder for the given coded pixel format.
* Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a raw pixel format
will include all possible frame buffer resolutions supported by the
encoder for the given raw pixel format and coded format currently set on
``CAPTURE``.
4. The client may use :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` to detect supported
frame intervals for a given format and resolution, passing the desired pixel
format in :c:type:`v4l2_frmsizeenum` ``pixel_format`` and the resolution
in :c:type:`v4l2_frmsizeenum` ``width`` and :c:type:`v4l2_frmsizeenum`
``height``.
* Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a coded pixel
format and coded resolution will include all possible frame intervals
supported by the encoder for the given coded pixel format and resolution.
* Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a raw pixel
format and resolution will include all possible frame intervals supported
by the encoder for the given raw pixel format and resolution and for the
coded format, coded resolution and coded frame interval currently set on
``CAPTURE``.
* Support for :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` is optional. If it is
not implemented, then there are no special restrictions other than the
limits of the codec itself.
5. Supported profiles and levels for the coded format currently set on
``CAPTURE``, if applicable, may be queried using their respective controls
via :c:func:`VIDIOC_QUERYCTRL`.
6. Any additional encoder capabilities may be discovered by querying
their respective controls.
Initialization
==============
1. Set the coded format on the ``CAPTURE`` queue via :c:func:`VIDIOC_S_FMT`.
* **Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
``pixelformat``
the coded format to be produced.
``sizeimage``
desired size of ``CAPTURE`` buffers; the encoder may adjust it to
match hardware requirements.
``width``, ``height``
ignored (read-only).
other fields
follow standard semantics.
* **Return fields:**
``sizeimage``
adjusted size of ``CAPTURE`` buffers.
``width``, ``height``
the coded size selected by the encoder based on current state, e.g.
``OUTPUT`` format, selection rectangles, etc. (read-only).
.. important::
Changing the ``CAPTURE`` format may change the currently set ``OUTPUT``
format. How the new ``OUTPUT`` format is determined is up to the encoder
and the client must ensure it matches its needs afterwards.
2. **Optional.** Enumerate supported ``OUTPUT`` formats (raw formats for
source) for the selected coded format via :c:func:`VIDIOC_ENUM_FMT`.
* **Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
other fields
follow standard semantics.
* **Return fields:**
``pixelformat``
raw format supported for the coded format currently selected on
the ``CAPTURE`` queue.
other fields
follow standard semantics.
3. Set the raw source format on the ``OUTPUT`` queue via
:c:func:`VIDIOC_S_FMT`.
* **Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
``pixelformat``
raw format of the source.
``width``, ``height``
source resolution.
other fields
follow standard semantics.
* **Return fields:**
``width``, ``height``
may be adjusted to match encoder minimums, maximums and alignment
requirements, as required by the currently selected formats, as
reported by :c:func:`VIDIOC_ENUM_FRAMESIZES`.
other fields
follow standard semantics.
* Setting the ``OUTPUT`` format will reset the selection rectangles to their
default values, based on the new resolution, as described in the next
step.
4. Set the raw frame interval on the ``OUTPUT`` queue via
:c:func:`VIDIOC_S_PARM`. This also sets the coded frame interval on the
``CAPTURE`` queue to the same value.
* ** Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
``parm.output``
set all fields except ``parm.output.timeperframe`` to 0.
``parm.output.timeperframe``
the desired frame interval; the encoder may adjust it to
match hardware requirements.
* **Return fields:**
``parm.output.timeperframe``
the adjusted frame interval.
.. important::
Changing the ``OUTPUT`` frame interval *also* sets the framerate that
the encoder uses to encode the video. So setting the frame interval
to 1/24 (or 24 frames per second) will produce a coded video stream
that can be played back at that speed. The frame interval for the
``OUTPUT`` queue is just a hint, the application may provide raw
frames at a different rate. It can be used by the driver to help
schedule multiple encoders running in parallel.
In the next step the ``CAPTURE`` frame interval can optionally be
changed to a different value. This is useful for off-line encoding
were the coded frame interval can be different from the rate at
which raw frames are supplied.
.. important::
``timeperframe`` deals with *frames*, not fields. So for interlaced
formats this is the time per two fields, since a frame consists of
a top and a bottom field.
.. note::
It is due to historical reasons that changing the ``OUTPUT`` frame
interval also changes the coded frame interval on the ``CAPTURE``
queue. Ideally these would be independent settings, but that would
break the existing API.
5. **Optional** Set the coded frame interval on the ``CAPTURE`` queue via
:c:func:`VIDIOC_S_PARM`. This is only necessary if the coded frame
interval is different from the raw frame interval, which is typically
the case for off-line encoding. Support for this feature is signalled
by the :ref:`V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL <fmtdesc-flags>` format flag.
* ** Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
``parm.capture``
set all fields except ``parm.capture.timeperframe`` to 0.
``parm.capture.timeperframe``
the desired coded frame interval; the encoder may adjust it to
match hardware requirements.
* **Return fields:**
``parm.capture.timeperframe``
the adjusted frame interval.
.. important::
Changing the ``CAPTURE`` frame interval sets the framerate for the
coded video. It does *not* set the rate at which buffers arrive on the
``CAPTURE`` queue, that depends on how fast the encoder is and how
fast raw frames are queued on the ``OUTPUT`` queue.
.. important::
``timeperframe`` deals with *frames*, not fields. So for interlaced
formats this is the time per two fields, since a frame consists of
a top and a bottom field.
.. note::
Not all drivers support this functionality, in that case just set
the desired coded frame interval for the ``OUTPUT`` queue.
However, drivers that can schedule multiple encoders based on the
``OUTPUT`` frame interval must support this optional feature.
6. **Optional.** Set the visible resolution for the stream metadata via
:c:func:`VIDIOC_S_SELECTION` on the ``OUTPUT`` queue if it is desired
to be different than the full OUTPUT resolution.
* **Required fields:**
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
``target``
set to ``V4L2_SEL_TGT_CROP``.
``r.left``, ``r.top``, ``r.width``, ``r.height``
visible rectangle; this must fit within the `V4L2_SEL_TGT_CROP_BOUNDS`
rectangle and may be subject to adjustment to match codec and
hardware constraints.
* **Return fields:**
``r.left``, ``r.top``, ``r.width``, ``r.height``
visible rectangle adjusted by the encoder.
* The following selection targets are supported on ``OUTPUT``:
``V4L2_SEL_TGT_CROP_BOUNDS``
equal to the full source frame, matching the active ``OUTPUT``
format.
``V4L2_SEL_TGT_CROP_DEFAULT``
equal to ``V4L2_SEL_TGT_CROP_BOUNDS``.
``V4L2_SEL_TGT_CROP``
rectangle within the source buffer to be encoded into the
``CAPTURE`` stream; defaults to ``V4L2_SEL_TGT_CROP_DEFAULT``.
.. note::
A common use case for this selection target is encoding a source
video with a resolution that is not a multiple of a macroblock,
e.g. the common 1920x1080 resolution may require the source
buffers to be aligned to 1920x1088 for codecs with 16x16 macroblock
size. To avoid encoding the padding, the client needs to explicitly
configure this selection target to 1920x1080.
.. warning::
The encoder may adjust the crop/compose rectangles to the nearest
supported ones to meet codec and hardware requirements. The client needs
to check the adjusted rectangle returned by :c:func:`VIDIOC_S_SELECTION`.
7. Allocate buffers for both ``OUTPUT`` and ``CAPTURE`` via
:c:func:`VIDIOC_REQBUFS`. This may be performed in any order.
* **Required fields:**
``count``
requested number of buffers to allocate; greater than zero.
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT`` or
``CAPTURE``.
other fields
follow standard semantics.
* **Return fields:**
``count``
actual number of buffers allocated.
.. warning::
The actual number of allocated buffers may differ from the ``count``
given. The client must check the updated value of ``count`` after the
call returns.
.. note::
To allocate more than the minimum number of OUTPUT buffers (for pipeline
depth), the client may query the ``V4L2_CID_MIN_BUFFERS_FOR_OUTPUT``
control to get the minimum number of buffers required, and pass the
obtained value plus the number of additional buffers needed in the
``count`` field to :c:func:`VIDIOC_REQBUFS`.
Alternatively, :c:func:`VIDIOC_CREATE_BUFS` can be used to have more
control over buffer allocation.
* **Required fields:**
``count``
requested number of buffers to allocate; greater than zero.
``type``
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
other fields
follow standard semantics.
* **Return fields:**
``count``
adjusted to the number of allocated buffers.
8. Begin streaming on both ``OUTPUT`` and ``CAPTURE`` queues via
:c:func:`VIDIOC_STREAMON`. This may be performed in any order. The actual
encoding process starts when both queues start streaming.
.. note::
If the client stops the ``CAPTURE`` queue during the encode process and then
restarts it again, the encoder will begin generating a stream independent
from the stream generated before the stop. The exact constraints depend
on the coded format, but may include the following implications:
* encoded frames produced after the restart must not reference any
frames produced before the stop, e.g. no long term references for
H.264/HEVC,
* any headers that must be included in a standalone stream must be
produced again, e.g. SPS and PPS for H.264/HEVC.
Encoding
========
This state is reached after the `Initialization` sequence finishes
successfully. In this state, the client queues and dequeues buffers to both
queues via :c:func:`VIDIOC_QBUF` and :c:func:`VIDIOC_DQBUF`, following the
standard semantics.
The content of encoded ``CAPTURE`` buffers depends on the active coded pixel
format and may be affected by codec-specific extended controls, as stated
in the documentation of each format.
Both queues operate independently, following standard behavior of V4L2 buffer
queues and memory-to-memory devices. In addition, the order of encoded frames
dequeued from the ``CAPTURE`` queue may differ from the order of queuing raw
frames to the ``OUTPUT`` queue, due to properties of the selected coded format,
e.g. frame reordering.
The client must not assume any direct relationship between ``CAPTURE`` and
``OUTPUT`` buffers and any specific timing of buffers becoming
available to dequeue. Specifically:
* a buffer queued to ``OUTPUT`` may result in more than one buffer produced on
``CAPTURE`` (for example, if returning an encoded frame allowed the encoder
to return a frame that preceded it in display, but succeeded it in the decode
order; however, there may be other reasons for this as well),
* a buffer queued to ``OUTPUT`` may result in a buffer being produced on
``CAPTURE`` later into encode process, and/or after processing further
``OUTPUT`` buffers, or be returned out of order, e.g. if display
reordering is used,
* buffers may become available on the ``CAPTURE`` queue without additional
buffers queued to ``OUTPUT`` (e.g. during drain or ``EOS``), because of the
``OUTPUT`` buffers queued in the past whose encoding results are only
available at later time, due to specifics of the encoding process,
* buffers queued to ``OUTPUT`` may not become available to dequeue instantly
after being encoded into a corresponding ``CAPTURE`` buffer, e.g. if the
encoder needs to use the frame as a reference for encoding further frames.
.. note::
To allow matching encoded ``CAPTURE`` buffers with ``OUTPUT`` buffers they
originated from, the client can set the ``timestamp`` field of the
:c:type:`v4l2_buffer` struct when queuing an ``OUTPUT`` buffer. The
``CAPTURE`` buffer(s), which resulted from encoding that ``OUTPUT`` buffer
will have their ``timestamp`` field set to the same value when dequeued.
In addition to the straightforward case of one ``OUTPUT`` buffer producing
one ``CAPTURE`` buffer, the following cases are defined:
* one ``OUTPUT`` buffer generates multiple ``CAPTURE`` buffers: the same
``OUTPUT`` timestamp will be copied to multiple ``CAPTURE`` buffers,
* the encoding order differs from the presentation order (i.e. the
``CAPTURE`` buffers are out-of-order compared to the ``OUTPUT`` buffers):
``CAPTURE`` timestamps will not retain the order of ``OUTPUT`` timestamps.
.. note::
To let the client distinguish between frame types (keyframes, intermediate
frames; the exact list of types depends on the coded format), the
``CAPTURE`` buffers will have corresponding flag bits set in their
:c:type:`v4l2_buffer` struct when dequeued. See the documentation of
:c:type:`v4l2_buffer` and each coded pixel format for exact list of flags
and their meanings.
Should an encoding error occur, it will be reported to the client with the level
of details depending on the encoder capabilities. Specifically:
* the ``CAPTURE`` buffer (if any) that contains the results of the failed encode
operation will be returned with the ``V4L2_BUF_FLAG_ERROR`` flag set,
* if the encoder is able to precisely report the ``OUTPUT`` buffer(s) that triggered
the error, such buffer(s) will be returned with the ``V4L2_BUF_FLAG_ERROR`` flag
set.
.. note::
If a ``CAPTURE`` buffer is too small then it is just returned with the
``V4L2_BUF_FLAG_ERROR`` flag set. More work is needed to detect that this
error occurred because the buffer was too small, and to provide support to
free existing buffers that were too small.
In case of a fatal failure that does not allow the encoding to continue, any
further operations on corresponding encoder file handle will return the -EIO
error code. The client may close the file handle and open a new one, or
alternatively reinitialize the instance by stopping streaming on both queues,
releasing all buffers and performing the Initialization sequence again.
Encoding Parameter Changes
==========================
The client is allowed to use :c:func:`VIDIOC_S_CTRL` to change encoder
parameters at any time. The availability of parameters is encoder-specific
and the client must query the encoder to find the set of available controls.
The ability to change each parameter during encoding is encoder-specific, as
per the standard semantics of the V4L2 control interface. The client may
attempt to set a control during encoding and if the operation fails with the
-EBUSY error code, the ``CAPTURE`` queue needs to be stopped for the
configuration change to be allowed. To do this, it may follow the `Drain`
sequence to avoid losing the already queued/encoded frames.
The timing of parameter updates is encoder-specific, as per the standard
semantics of the V4L2 control interface. If the client needs to apply the
parameters exactly at specific frame, using the Request API
(:ref:`media-request-api`) should be considered, if supported by the encoder.
Drain
=====
To ensure that all the queued ``OUTPUT`` buffers have been processed and the
related ``CAPTURE`` buffers are given to the client, the client must follow the
drain sequence described below. After the drain sequence ends, the client has
received all encoded frames for all ``OUTPUT`` buffers queued before the
sequence was started.
1. Begin the drain sequence by issuing :c:func:`VIDIOC_ENCODER_CMD`.
* **Required fields:**
``cmd``
set to ``V4L2_ENC_CMD_STOP``.
``flags``
set to 0.
``pts``
set to 0.
.. warning::
The sequence can be only initiated if both ``OUTPUT`` and ``CAPTURE``
queues are streaming. For compatibility reasons, the call to
:c:func:`VIDIOC_ENCODER_CMD` will not fail even if any of the queues is
not streaming, but at the same time it will not initiate the `Drain`
sequence and so the steps described below would not be applicable.
2. Any ``OUTPUT`` buffers queued by the client before the
:c:func:`VIDIOC_ENCODER_CMD` was issued will be processed and encoded as
normal. The client must continue to handle both queues independently,
similarly to normal encode operation. This includes:
* queuing and dequeuing ``CAPTURE`` buffers, until a buffer marked with the
``V4L2_BUF_FLAG_LAST`` flag is dequeued,
.. warning::
The last buffer may be empty (with :c:type:`v4l2_buffer`
``bytesused`` = 0) and in that case it must be ignored by the client,
as it does not contain an encoded frame.
.. note::
Any attempt to dequeue more ``CAPTURE`` buffers beyond the buffer
marked with ``V4L2_BUF_FLAG_LAST`` will result in a -EPIPE error from
:c:func:`VIDIOC_DQBUF`.
* dequeuing processed ``OUTPUT`` buffers, until all the buffers queued
before the ``V4L2_ENC_CMD_STOP`` command are dequeued,
* dequeuing the ``V4L2_EVENT_EOS`` event, if the client subscribes to it.
.. note::
For backwards compatibility, the encoder will signal a ``V4L2_EVENT_EOS``
event when the last frame has been encoded and all frames are ready to be
dequeued. It is deprecated behavior and the client must not rely on it.
The ``V4L2_BUF_FLAG_LAST`` buffer flag should be used instead.
3. Once all ``OUTPUT`` buffers queued before the ``V4L2_ENC_CMD_STOP`` call are
dequeued and the last ``CAPTURE`` buffer is dequeued, the encoder is stopped
and it will accept, but not process any newly queued ``OUTPUT`` buffers
until the client issues any of the following operations:
* ``V4L2_ENC_CMD_START`` - the encoder will not be reset and will resume
operation normally, with all the state from before the drain,
* a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the
``CAPTURE`` queue - the encoder will be reset (see the `Reset` sequence)
and then resume encoding,
* a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the
``OUTPUT`` queue - the encoder will resume operation normally, however any
source frames queued to the ``OUTPUT`` queue between ``V4L2_ENC_CMD_STOP``
and :c:func:`VIDIOC_STREAMOFF` will be discarded.
.. note::
Once the drain sequence is initiated, the client needs to drive it to
completion, as described by the steps above, unless it aborts the process by
issuing :c:func:`VIDIOC_STREAMOFF` on any of the ``OUTPUT`` or ``CAPTURE``
queues. The client is not allowed to issue ``V4L2_ENC_CMD_START`` or
``V4L2_ENC_CMD_STOP`` again while the drain sequence is in progress and they
will fail with -EBUSY error code if attempted.
For reference, handling of various corner cases is described below:
* In case of no buffer in the ``OUTPUT`` queue at the time the
``V4L2_ENC_CMD_STOP`` command was issued, the drain sequence completes
immediately and the encoder returns an empty ``CAPTURE`` buffer with the
``V4L2_BUF_FLAG_LAST`` flag set.
* In case of no buffer in the ``CAPTURE`` queue at the time the drain
sequence completes, the next time the client queues a ``CAPTURE`` buffer
it is returned at once as an empty buffer with the ``V4L2_BUF_FLAG_LAST``
flag set.
* If :c:func:`VIDIOC_STREAMOFF` is called on the ``CAPTURE`` queue in the
middle of the drain sequence, the drain sequence is canceled and all
``CAPTURE`` buffers are implicitly returned to the client.
* If :c:func:`VIDIOC_STREAMOFF` is called on the ``OUTPUT`` queue in the
middle of the drain sequence, the drain sequence completes immediately and
next ``CAPTURE`` buffer will be returned empty with the
``V4L2_BUF_FLAG_LAST`` flag set.
Although not mandatory, the availability of encoder commands may be queried
using :c:func:`VIDIOC_TRY_ENCODER_CMD`.
Reset
=====
The client may want to request the encoder to reinitialize the encoding, so
that the following stream data becomes independent from the stream data
generated before. Depending on the coded format, that may imply that:
* encoded frames produced after the restart must not reference any frames
produced before the stop, e.g. no long term references for H.264/HEVC,
* any headers that must be included in a standalone stream must be produced
again, e.g. SPS and PPS for H.264/HEVC.
This can be achieved by performing the reset sequence.
1. Perform the `Drain` sequence to ensure all the in-flight encoding finishes
and respective buffers are dequeued.
2. Stop streaming on the ``CAPTURE`` queue via :c:func:`VIDIOC_STREAMOFF`. This
will return all currently queued ``CAPTURE`` buffers to the client, without
valid frame data.
3. Start streaming on the ``CAPTURE`` queue via :c:func:`VIDIOC_STREAMON` and
continue with regular encoding sequence. The encoded frames produced into
``CAPTURE`` buffers from now on will contain a standalone stream that can be
decoded without the need for frames encoded before the reset sequence,
starting at the first ``OUTPUT`` buffer queued after issuing the
`V4L2_ENC_CMD_STOP` of the `Drain` sequence.
This sequence may be also used to change encoding parameters for encoders
without the ability to change the parameters on the fly.
Commit Points
=============
Setting formats and allocating buffers triggers changes in the behavior of the
encoder.
1. Setting the format on the ``CAPTURE`` queue may change the set of formats
supported/advertised on the ``OUTPUT`` queue. In particular, it also means
that the ``OUTPUT`` format may be reset and the client must not rely on the
previously set format being preserved.
2. Enumerating formats on the ``OUTPUT`` queue always returns only formats
supported for the current ``CAPTURE`` format.
3. Setting the format on the ``OUTPUT`` queue does not change the list of
formats available on the ``CAPTURE`` queue. An attempt to set the ``OUTPUT``
format that is not supported for the currently selected ``CAPTURE`` format
will result in the encoder adjusting the requested ``OUTPUT`` format to a
supported one.
4. Enumerating formats on the ``CAPTURE`` queue always returns the full set of
supported coded formats, irrespective of the current ``OUTPUT`` format.
5. While buffers are allocated on any of the ``OUTPUT`` or ``CAPTURE`` queues,
the client must not change the format on the ``CAPTURE`` queue. Drivers will
return the -EBUSY error code for any such format change attempt.
To summarize, setting formats and allocation must always start with the
``CAPTURE`` queue and the ``CAPTURE`` queue is the master that governs the
set of supported formats for the ``OUTPUT`` queue.

View File

@ -46,4 +46,5 @@ devices are given in the following sections.
:maxdepth: 1
dev-decoder
dev-encoder
dev-stateless-decoder

View File

@ -51,7 +51,7 @@ other information, the physical address of the framebuffer in the
``base`` field of struct :c:type:`v4l2_framebuffer`.
The framebuffer device ioctl ``FBIOGET_FSCREENINFO`` returns the same
address in the ``smem_start`` field of struct
struct :c:type:`fb_fix_screeninfo`. The ``FBIOGET_FSCREENINFO``
:c:type:`fb_fix_screeninfo`. The ``FBIOGET_FSCREENINFO``
ioctl and struct :c:type:`fb_fix_screeninfo` are defined in
the ``linux/fb.h`` header file.

View File

@ -78,7 +78,7 @@ field of a struct :c:type:`v4l2_format` to
``V4L2_BUF_TYPE_SDR_CAPTURE`` or ``V4L2_BUF_TYPE_SDR_OUTPUT`` and use
the struct :c:type:`v4l2_sdr_format` ``sdr`` member
of the ``fmt`` union as needed per the desired operation. Currently
there is two fields, ``pixelformat`` and ``buffersize``, of struct
there are two fields, ``pixelformat`` and ``buffersize``, of
struct :c:type:`v4l2_sdr_format` which are used.
Content of the ``pixelformat`` is V4L2 FourCC code of the data format.
The ``buffersize`` field is maximum buffer size in bytes required for

View File

@ -43,7 +43,7 @@ transmission arguments.
1998-09-28: Revamped video standard. Made video controls individually
enumerable.
1998-10-02: The ``id`` field was removed from struct
1998-10-02: The ``id`` field was removed from
struct ``video_standard`` and the color subcarrier fields were
renamed. The :ref:`VIDIOC_QUERYSTD` ioctl was
renamed to :ref:`VIDIOC_ENUMSTD`,
@ -260,7 +260,7 @@ multiple tuners into account.)
2000-09-18: ``V4L2_BUF_TYPE_VBI`` was added. This may *break
compatibility* as the :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` and
:ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctls may fail now if the struct
:ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctls may fail now if the
struct ``v4l2_fmt`` ``type`` field does not contain
``V4L2_BUF_TYPE_VBI``. In the documentation of the struct
:c:type:`v4l2_vbi_format` ``offset`` field the

View File

@ -69,37 +69,37 @@ Each cell is one byte.
B\ :sub:`00low bits 5--0`\ (bits 5--0)
- R\ :sub:`02low bits 3--0`\ (bits 7--4)
- B\ :sub:`02low bits 3--0`\ (bits 7--4)
G\ :sub:`01low bits 5--2`\ (bits 3--0)
- G\ :sub:`03low bits 5--0`\ (bits 7--2)
R\ :sub:`02low bits 5--4`\ (bits 1--0)
B\ :sub:`02low bits 5--4`\ (bits 1--0)
- .. row 2
- start + 7
- G\ :sub:`00high`
- G\ :sub:`10high`
- R\ :sub:`01high`
- R\ :sub:`11high`
- G\ :sub:`02high`
- G\ :sub:`12high`
- R\ :sub:`03high`
- R\ :sub:`13high`
- R\ :sub:`01low bits 1--0`\ (bits 7--6)
- R\ :sub:`11low bits 1--0`\ (bits 7--6)
G\ :sub:`00low bits 5--0`\ (bits 5--0)
G\ :sub:`10low bits 5--0`\ (bits 5--0)
- G\ :sub:`02low bits 3--0`\ (bits 7--4)
- G\ :sub:`12low bits 3--0`\ (bits 7--4)
R\ :sub:`01low bits 5--2`\ (bits 3--0)
R\ :sub:`11low bits 5--2`\ (bits 3--0)
- R\ :sub:`03low bits 5--0`\ (bits 7--2)
- R\ :sub:`13low bits 5--0`\ (bits 7--2)
G\ :sub:`02low bits 5--4`\ (bits 1--0)
G\ :sub:`12low bits 5--4`\ (bits 1--0)
- .. row 3
@ -117,13 +117,13 @@ Each cell is one byte.
B\ :sub:`20low bits 5--0`\ (bits 5--0)
- R\ :sub:`22low bits 3--0`\ (bits 7--4)
- B\ :sub:`22low bits 3--0`\ (bits 7--4)
G\ :sub:`21low bits 5--2`\ (bits 3--0)
- G\ :sub:`23low bits 5--0`\ (bits 7--2)
R\ :sub:`22low bits 5--4`\ (bits 1--0)
B\ :sub:`22low bits 5--4`\ (bits 1--0)
- .. row 4

View File

@ -44,6 +44,11 @@ Single-planar format structure
inside the stream, when fed to a stateful mem2mem decoder, the fields
may be zero to rely on the decoder to detect the right values. For more
details see :ref:`decoder` and format descriptions.
For compressed formats on the CAPTURE side of a stateful mem2mem
encoder, the fields must be zero, since the coded size is expected to
be calculated internally by the encoder itself, based on the OUTPUT
side. For more details see :ref:`encoder` and format descriptions.
* - __u32
- ``pixelformat``
- The pixel format or type of compression, set by the application.

View File

@ -63,6 +63,7 @@ Authors, in alphabetical order:
- Figa, Tomasz <tfiga@chromium.org>
- Documented the memory-to-memory decoder interface.
- Documented the memory-to-memory encoder interface.
- H Schimek, Michael <mschimek@gmx.at>
@ -75,6 +76,7 @@ Authors, in alphabetical order:
- Osciak, Pawel <posciak@chromium.org>
- Documented the memory-to-memory decoder interface.
- Documented the memory-to-memory encoder interface.
- Osciak, Pawel <pawel@osciak.com>

View File

@ -121,7 +121,12 @@ than the number requested.
other changes, then set ``count`` to 0, ``memory`` to
``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type.
* - __u32
- ``reserved``\ [7]
- ``flags``
- Specifies additional buffer management attributes.
See :ref:`memory-flags`.
* - __u32
- ``reserved``\ [6]
- A place holder for future extensions. Drivers and applications
must set the array to zero.

View File

@ -260,7 +260,7 @@ call.
:ref:`v4l2_queryctrl <v4l2-queryctrl>`.
* - __s32
- ``default_value``
- The default value value of the control. See struct
- The default value of the control. See struct
:ref:`v4l2_queryctrl <v4l2-queryctrl>`.

View File

@ -51,25 +51,26 @@ To send a command applications must initialize all fields of a struct
``VIDIOC_ENCODER_CMD`` or ``VIDIOC_TRY_ENCODER_CMD`` with a pointer to
this structure.
The ``cmd`` field must contain the command code. The ``flags`` field is
currently only used by the STOP command and contains one bit: If the
``V4L2_ENC_CMD_STOP_AT_GOP_END`` flag is set, encoding will continue
until the end of the current *Group Of Pictures*, otherwise it will stop
immediately.
The ``cmd`` field must contain the command code. Some commands use the
``flags`` field for additional information.
A :ref:`read() <func-read>` or :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
call sends an implicit START command to the encoder if it has not been
started yet. After a STOP command, :ref:`read() <func-read>` calls will read
After a STOP command, :ref:`read() <func-read>` calls will read
the remaining data buffered by the driver. When the buffer is empty,
:ref:`read() <func-read>` will return zero and the next :ref:`read() <func-read>`
call will restart the encoder.
A :ref:`read() <func-read>` or :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
call sends an implicit START command to the encoder if it has not been
started yet. Applies to both queues of mem2mem encoders.
A :ref:`close() <func-close>` or :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
call of a streaming file descriptor sends an implicit immediate STOP to
the encoder, and all buffered data is discarded.
the encoder, and all buffered data is discarded. Applies to both queues of
mem2mem encoders.
These ioctls are optional, not all drivers may support them. They were
introduced in Linux 2.6.21.
introduced in Linux 2.6.21. They are, however, mandatory for stateful mem2mem
encoders (as further documented in :ref:`encoder`).
.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
@ -109,21 +110,24 @@ introduced in Linux 2.6.21.
- 0
- Start the encoder. When the encoder is already running or paused,
this command does nothing. No flags are defined for this command.
For a device implementing the :ref:`encoder`, once the drain sequence
is initiated with the ``V4L2_ENC_CMD_STOP`` command, it must be driven
to completion before this command can be invoked. Any attempt to
invoke the command while the drain sequence is in progress will trigger
an ``EBUSY`` error code. See :ref:`encoder` for more details.
* - ``V4L2_ENC_CMD_STOP``
- 1
- Stop the encoder. When the ``V4L2_ENC_CMD_STOP_AT_GOP_END`` flag
is set, encoding will continue until the end of the current *Group
Of Pictures*, otherwise encoding will stop immediately. When the
encoder is already stopped, this command does nothing. mem2mem
encoders will send a ``V4L2_EVENT_EOS`` event when the last frame
has been encoded and all frames are ready to be dequeued and will
set the ``V4L2_BUF_FLAG_LAST`` buffer flag on the last buffer of
the capture queue to indicate there will be no new buffers
produced to dequeue. This buffer may be empty, indicated by the
driver setting the ``bytesused`` field to 0. Once the
``V4L2_BUF_FLAG_LAST`` flag was set, the
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl will not block anymore,
but return an ``EPIPE`` error code.
encoder is already stopped, this command does nothing.
For a device implementing the :ref:`encoder`, the command will initiate
the drain sequence as documented in :ref:`encoder`. No flags or other
arguments are accepted in this case. Any attempt to invoke the command
again before the sequence completes will trigger an ``EBUSY`` error
code.
* - ``V4L2_ENC_CMD_PAUSE``
- 2
- Pause the encoder. When the encoder has not been started yet, the
@ -152,6 +156,8 @@ introduced in Linux 2.6.21.
- Stop encoding at the end of the current *Group Of Pictures*,
rather than immediately.
Does not apply to :ref:`encoder`.
Return Value
============
@ -160,6 +166,11 @@ On success 0 is returned, on error -1 and the ``errno`` variable is set
appropriately. The generic error codes are described at the
:ref:`Generic Error Codes <gen-errors>` chapter.
EBUSY
A drain sequence of a device implementing the :ref:`encoder` is still in
progress. It is not allowed to issue another encoder command until it
completes.
EINVAL
The ``cmd`` field is invalid.

View File

@ -167,17 +167,37 @@ the ``mbus_code`` field is handled differently:
- The hardware decoder for this compressed bytestream format (aka coded
format) is capable of parsing a continuous bytestream. Applications do
not need to parse the bytestream themselves to find the boundaries
between frames/fields. This flag can only be used in combination with
the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to compressed
between frames/fields.
This flag can only be used in combination with the
``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to compressed
formats only. This flag is valid for stateful decoders only.
* - ``V4L2_FMT_FLAG_DYN_RESOLUTION``
- 0x0008
- Dynamic resolution switching is supported by the device for this
compressed bytestream format (aka coded format). It will notify the user
via the event ``V4L2_EVENT_SOURCE_CHANGE`` when changes in the video
parameters are detected. This flag can only be used in combination
with the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to
compressed formats only. It is also only applies to stateful codecs.
parameters are detected.
This flag can only be used in combination with the
``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to
compressed formats only. This flag is valid for stateful codecs only.
* - ``V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL``
- 0x0010
- The hardware encoder supports setting the ``CAPTURE`` coded frame
interval separately from the ``OUTPUT`` raw frame interval.
Setting the ``OUTPUT`` raw frame interval with :ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>`
also sets the ``CAPTURE`` coded frame interval to the same value.
If this flag is set, then the ``CAPTURE`` coded frame interval can be
set to a different value afterwards. This is typically used for
offline encoding where the ``OUTPUT`` raw frame interval is used as
a hint for reserving hardware encoder resources and the ``CAPTURE`` coded
frame interval is the actual frame rate embedded in the encoded video
stream.
This flag can only be used in combination with the
``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to
compressed formats only. This flag is valid for stateful encoders only.
Return Value

View File

@ -42,12 +42,13 @@ Arguments
Description
===========
The current video standard determines a nominal number of frames per
second. If less than this number of frames is to be captured or output,
applications can request frame skipping or duplicating on the driver
side. This is especially useful when using the :ref:`read() <func-read>` or
:ref:`write() <func-write>`, which are not augmented by timestamps or sequence
counters, and to avoid unnecessary data copying.
Applications can request a different frame interval. The capture or
output device will be reconfigured to support the requested frame
interval if possible. Optionally drivers may choose to skip or
repeat frames to achieve the requested frame interval.
For stateful encoders (see :ref:`encoder`) this represents the
frame interval that is typically embedded in the encoded video stream.
Changing the frame interval shall never change the format. Changing the
format, on the other hand, may change the frame interval.
@ -57,7 +58,8 @@ internally by a driver in read/write mode. For implications see the
section discussing the :ref:`read() <func-read>` function.
To get and set the streaming parameters applications call the
:ref:`VIDIOC_G_PARM <VIDIOC_G_PARM>` and :ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>` ioctl, respectively. They take a
:ref:`VIDIOC_G_PARM <VIDIOC_G_PARM>` and
:ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>` ioctl, respectively. They take a
pointer to a struct :c:type:`v4l2_streamparm` which contains a
union holding separate parameters for input and output devices.
@ -113,14 +115,21 @@ union holding separate parameters for input and output devices.
* - struct :c:type:`v4l2_fract`
- ``timeperframe``
- This is the desired period between successive frames captured by
the driver, in seconds. The field is intended to skip frames on
the driver side, saving I/O bandwidth.
the driver, in seconds.
* - :cspan:`2`
This will configure the speed at which the video source (e.g. a sensor)
generates video frames. If the speed is fixed, then the driver may
choose to skip or repeat frames in order to achieve the requested
frame rate.
For stateful encoders (see :ref:`encoder`) this represents the
frame interval that is typically embedded in the encoded video stream.
Applications store here the desired frame period, drivers return
the actual frame period, which must be greater or equal to the
nominal frame period determined by the current video standard
(struct :c:type:`v4l2_standard` ``frameperiod``
field). Changing the video standard (also implicitly by switching
the actual frame period.
Changing the video standard (also implicitly by switching
the video input) may reset this parameter to the nominal frame
period. To reset manually applications can just set this field to
zero.
@ -173,11 +182,15 @@ union holding separate parameters for input and output devices.
:ref:`write() <func-write>` mode (in streaming mode timestamps
can be used to throttle the output), saving I/O bandwidth.
For stateful encoders (see :ref:`encoder`) this represents the
frame interval that is typically embedded in the encoded video stream
and it provides a hint to the encoder of the speed at which raw
frames are queued up to the encoder.
Applications store here the desired frame period, drivers return
the actual frame period, which must be greater or equal to the
nominal frame period determined by the current video standard
(struct :c:type:`v4l2_standard` ``frameperiod``
field). Changing the video standard (also implicitly by switching
the actual frame period.
Changing the video standard (also implicitly by switching
the video output) may reset this parameter to the nominal frame
period. To reset manually applications can just set this field to
zero.
@ -216,8 +229,8 @@ union holding separate parameters for input and output devices.
* - ``V4L2_CAP_TIMEPERFRAME``
- 0x1000
- The frame skipping/repeating controlled by the ``timeperframe``
field is supported.
- The frame period can be modified by setting the ``timeperframe``
field.

View File

@ -168,11 +168,11 @@ specification the ioctl returns an ``EINVAL`` error code.
- The device supports the :ref:`multi-planar API <planar-apis>`
through the :ref:`Video Output <output>` interface.
* - ``V4L2_CAP_VIDEO_M2M``
- 0x00004000
- 0x00008000
- The device supports the single-planar API through the Video
Memory-To-Memory interface.
* - ``V4L2_CAP_VIDEO_M2M_MPLANE``
- 0x00008000
- 0x00004000
- The device supports the :ref:`multi-planar API <planar-apis>`
through the Video Memory-To-Memory interface.
* - ``V4L2_CAP_VIDEO_OVERLAY``

View File

@ -112,10 +112,17 @@ aborting or finishing any DMA in progress, an implicit
``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will
free any previously allocated buffers, so this is typically something
that will be done at the start of the application.
* - union {
- (anonymous)
* - __u32
- ``flags``
- Specifies additional buffer management attributes.
See :ref:`memory-flags`.
* - __u32
- ``reserved``\ [1]
- A place holder for future extensions. Drivers and applications
must set the array to zero.
- Kept for backwards compatibility. Use ``flags`` instead.
* - }
-
.. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}|
@ -126,6 +133,7 @@ aborting or finishing any DMA in progress, an implicit
.. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
.. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS:
.. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF:
.. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS:
.. cssclass:: longtable
@ -156,6 +164,15 @@ aborting or finishing any DMA in progress, an implicit
- Only valid for stateless decoders. If set, then userspace can set the
``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag to hold off on returning the
capture buffer until the OUTPUT timestamp changes.
* - ``V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS``
- 0x00000040
- This capability is set by the driver to indicate that the queue supports
cache and memory management hints. However, it's only valid when the
queue is used for :ref:`memory mapping <mmap>` streaming I/O. See
:ref:`V4L2_FLAG_MEMORY_NON_CONSISTENT <V4L2-FLAG-MEMORY-NON-CONSISTENT>`,
:ref:`V4L2_BUF_FLAG_NO_CACHE_INVALIDATE <V4L2-BUF-FLAG-NO-CACHE-INVALIDATE>` and
:ref:`V4L2_BUF_FLAG_NO_CACHE_CLEAN <V4L2-BUF-FLAG-NO-CACHE-CLEAN>`.
Return Value
============

View File

@ -187,6 +187,7 @@ replace define V4L2_FMT_FLAG_COMPRESSED fmtdesc-flags
replace define V4L2_FMT_FLAG_EMULATED fmtdesc-flags
replace define V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM fmtdesc-flags
replace define V4L2_FMT_FLAG_DYN_RESOLUTION fmtdesc-flags
replace define V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL fmtdesc-flags
# V4L2 timecode types
replace define V4L2_TC_TYPE_24FPS timecode-type

View File

@ -4141,6 +4141,14 @@ F: drivers/power/supply/cros_usbpd-charger.c
N: cros_ec
N: cros-ec
CHRONTEL CH7322 CEC DRIVER
M: Jeff Chase <jnchase@google.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml
F: drivers/media/cec/i2c/ch7322.c
CIRRUS LOGIC AUDIO CODEC DRIVERS
M: James Schulman <james.schulman@cirrus.com>
M: David Rhodes <david.rhodes@cirrus.com>
@ -5267,6 +5275,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt
F: drivers/media/i2c/dw9714.c
DONGWOON DW9768 LENS VOICE COIL DRIVER
M: Dongchun Zhu <dongchun.zhu@mediatek.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
F: drivers/media/i2c/dw9768.c
DONGWOON DW9807 LENS VOICE COIL DRIVER
M: Sakari Ailus <sakari.ailus@linux.intel.com>
L: linux-media@vger.kernel.org
@ -10507,6 +10523,16 @@ F: Documentation/hwmon/max6697.rst
F: drivers/hwmon/max6697.c
F: include/linux/platform_data/max6697.h
MAX9286 QUAD GMSL DESERIALIZER DRIVER
M: Jacopo Mondi <jacopo+renesas@jmondi.org>
M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
F: drivers/media/i2c/max9286.c
MAX9860 MONO AUDIO VOICE CODEC DRIVER
M: Peter Rosin <peda@axentia.se>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@ -10785,7 +10811,7 @@ L: linux-media@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/renesas,fcp.txt
F: Documentation/devicetree/bindings/media/renesas,fcp.yaml
F: drivers/media/platform/rcar-fcp.c
F: include/media/rcar-fcp.h
@ -10795,7 +10821,7 @@ L: linux-media@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/renesas,fdp1.txt
F: Documentation/devicetree/bindings/media/renesas,fdp1.yaml
F: drivers/media/platform/rcar_fdp1.c
MEDIA DRIVERS FOR RENESAS - VIN
@ -10815,7 +10841,7 @@ L: linux-media@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/renesas,vsp1.txt
F: Documentation/devicetree/bindings/media/renesas,vsp1.yaml
F: drivers/media/platform/vsp1/
MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs
@ -14483,6 +14509,19 @@ L: linux-wireless@vger.kernel.org
S: Orphan
F: drivers/net/wireless/ray*
RC-CORE / LIRC FRAMEWORK
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
S: Maintained
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: Documentation/driver-api/media/rc-core.rst
F: Documentation/userspace-api/media/rc/
F: drivers/media/rc/
F: include/media/rc-map.h
F: include/media/rc-core.h
F: include/uapi/linux/lirc.h
RCMM REMOTE CONTROLS DECODER
M: Patrick Lerda <patrick9876@free.fr>
S: Maintained
@ -14499,6 +14538,18 @@ S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
F: tools/testing/selftests/rcutorture
RDACM20 Camera Sensor
M: Jacopo Mondi <jacopo+renesas@jmondi.org>
M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml
F: drivers/media/i2c/rdacm20.c
F: drivers/media/i2c/max9271.c
F: drivers/media/i2c/max9271.h
RDC R-321X SoC
M: Florian Fainelli <florian@openwrt.org>
S: Maintained
@ -15887,13 +15938,6 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/smsc/smsc9420.*
SOC-CAMERA V4L2 SUBSYSTEM
L: linux-media@vger.kernel.org
S: Orphan
T: git git://linuxtv.org/media_tree.git
F: drivers/staging/media/soc_camera/
F: include/media/soc_camera.h
SOCIONEXT (SNI) AVE NETWORK DRIVER
M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
L: netdev@vger.kernel.org

View File

@ -236,8 +236,6 @@ CONFIG_MEDIA_TUNER_CUSTOMISE=y
# CONFIG_MEDIA_TUNER_MXL5007T is not set
# CONFIG_MEDIA_TUNER_MC44S803 is not set
# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_MT9M111=y
CONFIG_VIDEO_PXA27x=y
# CONFIG_V4L_USB_DRIVERS is not set
CONFIG_RADIO_TEA5764=y

View File

@ -217,8 +217,6 @@ CONFIG_MEDIA_TUNER_CUSTOMISE=y
# CONFIG_MEDIA_TUNER_MXL5007T is not set
# CONFIG_MEDIA_TUNER_MC44S803 is not set
# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_MT9M111=y
CONFIG_VIDEO_PXA27x=y
# CONFIG_V4L_USB_DRIVERS is not set
# CONFIG_RADIO_ADAPTERS is not set

View File

@ -110,7 +110,6 @@ CONFIG_REGULATOR_MC13892=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_CODA=y
CONFIG_FB=y

View File

@ -272,7 +272,6 @@ CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_MUX=y
CONFIG_SOC_CAMERA=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_CODA=m
CONFIG_VIDEO_IMX_PXP=y

View File

@ -447,11 +447,8 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=m
CONFIG_SOC_CAMERA_PLATFORM=m
CONFIG_VIDEO_PXA27x=m
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_SOC_CAMERA_MT9M111=m
CONFIG_DRM=m
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_TILEBLITTING=y

View File

@ -155,9 +155,7 @@ CONFIG_REGULATOR_PWM=m
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
CONFIG_VIDEO_ATMEL_ISI=y
CONFIG_SOC_CAMERA_OV2640=m
CONFIG_DRM=y
CONFIG_DRM_ATMEL_HLCDC=y
CONFIG_DRM_PANEL_SIMPLE=y

View File

@ -19,7 +19,6 @@
#include <linux/dma-mapping.h>
#include <linux/leds.h>
#include <linux/platform_data/asoc-mx27vis.h>
#include <media/soc_camera.h>
#include <sound/tlv320aic32x4.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -191,34 +190,6 @@ static const struct gpio visstrim_m10_gpios[] __initconst = {
};
/* Camera */
static int visstrim_camera_power(struct device *dev, int on)
{
gpio_set_value(TVP5150_PWDN, on);
return 0;
};
static int visstrim_camera_reset(struct device *dev)
{
gpio_set_value(TVP5150_RSTN, 0);
ndelay(500);
gpio_set_value(TVP5150_RSTN, 1);
return 0;
};
static struct i2c_board_info visstrim_i2c_camera = {
I2C_BOARD_INFO("tvp5150", 0x5d),
};
static struct soc_camera_link iclink_tvp5150 = {
.bus_id = 0,
.board_info = &visstrim_i2c_camera,
.i2c_adapter_id = 0,
.power = visstrim_camera_power,
.reset = visstrim_camera_reset,
};
static struct mx2_camera_platform_data visstrim_camera = {
.flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE |
MX2_CAMERA_PCLK_SAMPLE_RISING,
@ -549,8 +520,6 @@ static void __init visstrim_m10_late_init(void)
imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata,
sizeof(snd_mx27vis_pdata));
platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
&iclink_tvp5150, sizeof(iclink_tvp5150));
gpio_led_register_device(0, &visstrim_m10_led_data);

View File

@ -29,8 +29,6 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
#include <media/soc_camera.h>
#include <asm/serial.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -40,7 +38,6 @@
#include <mach/mux.h>
#include <mach/hardware.h>
#include "camera.h"
#include <mach/usb.h>
#include "ams-delta-fiq.h"
@ -459,12 +456,6 @@ static struct gpiod_lookup_table leds_gpio_table = {
},
};
static struct i2c_board_info ams_delta_camera_board_info[] = {
{
I2C_BOARD_INFO("ov6650", 0x60),
},
};
#ifdef CONFIG_LEDS_TRIGGERS
DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger);
@ -483,27 +474,6 @@ static int ams_delta_camera_power(struct device *dev, int power)
#define ams_delta_camera_power NULL
#endif
static struct soc_camera_link ams_delta_iclink = {
.bus_id = 0, /* OMAP1 SoC camera bus */
.i2c_adapter_id = 1,
.board_info = &ams_delta_camera_board_info[0],
.module_name = "ov6650",
.power = ams_delta_camera_power,
};
static struct platform_device ams_delta_camera_device = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = &ams_delta_iclink,
},
};
static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
.camexclk_khz = 12000, /* default 12MHz clock, no extra DPLL */
.lclk_khz_max = 1334, /* results in 5fps CIF, 10fps QCIF */
};
static struct platform_device ams_delta_audio_device = {
.name = "ams-delta-audio",
.id = -1,
@ -598,7 +568,6 @@ static struct platform_device *ams_delta_devices[] __initdata = {
&latch1_gpio_device,
&latch2_gpio_device,
&ams_delta_kp_device,
&ams_delta_camera_device,
&ams_delta_audio_device,
&ams_delta_serio_device,
&ams_delta_nand_device,
@ -750,7 +719,6 @@ static void __init ams_delta_init(void)
omap_register_i2c_bus(1, 100, NULL, 0);
omap1_usb_init(&ams_delta_usb_config);
omap1_set_camera_info(&ams_delta_camera_platform_data);
#ifdef CONFIG_LEDS_TRIGGERS
led_trigger_register_simple("ams_delta_camera",
&ams_delta_camera_led_trigger);

View File

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_ARCH_CAMERA_H_
#define __ASM_ARCH_CAMERA_H_
#include <linux/platform_data/media/omap1_camera.h>
void omap1_camera_init(void *);
static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info)
{
omap1_camera_init(info);
}
#endif /* __ASM_ARCH_CAMERA_H_ */

View File

@ -21,7 +21,6 @@
#include <mach/mux.h>
#include <mach/omap7xx.h>
#include "camera.h"
#include <mach/hardware.h>
#include "common.h"
@ -258,48 +257,6 @@ static inline void omap_init_spi100k(void)
}
#endif
#define OMAP1_CAMERA_BASE 0xfffb6800
#define OMAP1_CAMERA_IOSIZE 0x1c
static struct resource omap1_camera_resources[] = {
[0] = {
.start = OMAP1_CAMERA_BASE,
.end = OMAP1_CAMERA_BASE + OMAP1_CAMERA_IOSIZE - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = INT_CAMERA,
.flags = IORESOURCE_IRQ,
},
};
static u64 omap1_camera_dma_mask = DMA_BIT_MASK(32);
static struct platform_device omap1_camera_device = {
.name = "omap1-camera",
.id = 0, /* This is used to put cameras on this interface */
.dev = {
.dma_mask = &omap1_camera_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(omap1_camera_resources),
.resource = omap1_camera_resources,
};
void __init omap1_camera_init(void *info)
{
struct platform_device *dev = &omap1_camera_device;
int ret;
dev->dev.platform_data = info;
ret = platform_device_register(dev);
if (ret)
dev_err(&dev->dev, "unable to register device: %d\n", ret);
}
/*-------------------------------------------------------------------------*/
static inline void omap_init_sti(void) {}

View File

@ -47,8 +47,6 @@
#include "pm.h"
#include <linux/platform_data/media/camera-pxa.h>
#include <media/soc_camera.h>
#include "generic.h"
#include "devices.h"
@ -272,115 +270,6 @@ static int __init palmz72_pm_init(void)
device_initcall(palmz72_pm_init);
#endif
/******************************************************************************
* SoC Camera
******************************************************************************/
#if defined(CONFIG_SOC_CAMERA_OV9640) || \
defined(CONFIG_SOC_CAMERA_OV9640_MODULE)
static struct pxacamera_platform_data palmz72_pxacamera_platform_data = {
.flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
.mclk_10khz = 2600,
};
/* Board I2C devices. */
static struct i2c_board_info palmz72_i2c_device[] = {
{
I2C_BOARD_INFO("ov9640", 0x30),
}
};
static int palmz72_camera_power(struct device *dev, int power)
{
gpio_set_value(GPIO_NR_PALMZ72_CAM_PWDN, !power);
mdelay(50);
return 0;
}
static int palmz72_camera_reset(struct device *dev)
{
gpio_set_value(GPIO_NR_PALMZ72_CAM_RESET, 1);
mdelay(50);
gpio_set_value(GPIO_NR_PALMZ72_CAM_RESET, 0);
mdelay(50);
return 0;
}
static struct soc_camera_link palmz72_iclink = {
.bus_id = 0, /* Match id in pxa27x_device_camera in device.c */
.board_info = &palmz72_i2c_device[0],
.i2c_adapter_id = 0,
.module_name = "ov96xx",
.power = &palmz72_camera_power,
.reset = &palmz72_camera_reset,
.flags = SOCAM_DATAWIDTH_8,
};
static struct gpiod_lookup_table palmz72_i2c_gpiod_table = {
.dev_id = "i2c-gpio.0",
.table = {
GPIO_LOOKUP_IDX("gpio-pxa", 118, NULL, 0,
GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
GPIO_LOOKUP_IDX("gpio-pxa", 117, NULL, 1,
GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
},
};
static struct i2c_gpio_platform_data palmz72_i2c_bus_data = {
.udelay = 10,
.timeout = 100,
};
static struct platform_device palmz72_i2c_bus_device = {
.name = "i2c-gpio",
.id = 0, /* we use this as a replacement for i2c-pxa */
.dev = {
.platform_data = &palmz72_i2c_bus_data,
}
};
static struct platform_device palmz72_camera = {
.name = "soc-camera-pdrv",
.id = -1,
.dev = {
.platform_data = &palmz72_iclink,
},
};
/* Here we request the camera GPIOs and configure them. We power up the camera
* module, deassert the reset pin, but put it into powerdown (low to no power
* consumption) mode. This allows us to later bring the module up fast. */
static struct gpio palmz72_camera_gpios[] = {
{ GPIO_NR_PALMZ72_CAM_POWER, GPIOF_INIT_HIGH,"Camera DVDD" },
{ GPIO_NR_PALMZ72_CAM_RESET, GPIOF_INIT_LOW, "Camera RESET" },
{ GPIO_NR_PALMZ72_CAM_PWDN, GPIOF_INIT_LOW, "Camera PWDN" },
};
static inline void __init palmz72_cam_gpio_init(void)
{
int ret;
ret = gpio_request_array(ARRAY_AND_SIZE(palmz72_camera_gpios));
if (!ret)
gpio_free_array(ARRAY_AND_SIZE(palmz72_camera_gpios));
else
printk(KERN_ERR "Camera GPIO init failed!\n");
return;
}
static void __init palmz72_camera_init(void)
{
palmz72_cam_gpio_init();
pxa_set_camera_info(&palmz72_pxacamera_platform_data);
gpiod_add_lookup_table(&palmz72_i2c_gpiod_table);
platform_device_register(&palmz72_i2c_bus_device);
platform_device_register(&palmz72_camera);
}
#else
static inline void palmz72_camera_init(void) {}
#endif
static struct gpiod_lookup_table palmz72_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
@ -416,7 +305,6 @@ static void __init palmz72_init(void)
palm27x_pmic_init();
palmz72_kpc_init();
palmz72_leds_init();
palmz72_camera_init();
}
MACHINE_START(PALMZ72, "Palm Zire72")

View File

@ -24,10 +24,6 @@
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <media/i2c/mt9v022.h>
#include <media/soc_camera.h>
#include <linux/platform_data/media/camera-pxa.h>
#include <asm/mach/map.h>
#include "pxa27x.h"
#include <mach/audio.h>
@ -374,149 +370,6 @@ static struct pxaohci_platform_data pcm990_ohci_platform_data = {
.power_on_delay = 10,
};
/*
* PXA27x Camera specific stuff
*/
#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
static unsigned long pcm990_camera_pin_config[] = {
/* CIF */
GPIO98_CIF_DD_0,
GPIO105_CIF_DD_1,
GPIO104_CIF_DD_2,
GPIO103_CIF_DD_3,
GPIO95_CIF_DD_4,
GPIO94_CIF_DD_5,
GPIO93_CIF_DD_6,
GPIO108_CIF_DD_7,
GPIO107_CIF_DD_8,
GPIO106_CIF_DD_9,
GPIO42_CIF_MCLK,
GPIO45_CIF_PCLK,
GPIO43_CIF_FV,
GPIO44_CIF_LV,
};
/*
* CICR4: PCLK_EN: Pixel clock is supplied by the sensor
* MCLK_EN: Master clock is generated by PXA
* PCP: Data sampled on the falling edge of pixel clock
*/
struct pxacamera_platform_data pcm990_pxacamera_platform_data = {
.flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_10 |
PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN/* | PXA_CAMERA_PCP*/,
.mclk_10khz = 1000,
};
#include <linux/platform_data/pca953x.h>
static struct pca953x_platform_data pca9536_data = {
.gpio_base = PXA_NR_BUILTIN_GPIO,
};
static int gpio_bus_switch = -EINVAL;
static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
unsigned long flags)
{
if (gpio_bus_switch < 0) {
if (flags == SOCAM_DATAWIDTH_10)
return 0;
else
return -EINVAL;
}
if (flags & SOCAM_DATAWIDTH_8)
gpio_set_value_cansleep(gpio_bus_switch, 1);
else
gpio_set_value_cansleep(gpio_bus_switch, 0);
return 0;
}
static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
{
int ret;
if (gpio_bus_switch < 0) {
ret = gpio_request(PXA_NR_BUILTIN_GPIO, "camera");
if (!ret) {
gpio_bus_switch = PXA_NR_BUILTIN_GPIO;
gpio_direction_output(gpio_bus_switch, 0);
}
}
if (gpio_bus_switch >= 0)
return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
else
return SOCAM_DATAWIDTH_10;
}
static void pcm990_camera_free_bus(struct soc_camera_link *link)
{
if (gpio_bus_switch < 0)
return;
gpio_free(gpio_bus_switch);
gpio_bus_switch = -EINVAL;
}
/* Board I2C devices. */
static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
{
/* Must initialize before the camera(s) */
I2C_BOARD_INFO("pca9536", 0x41),
.platform_data = &pca9536_data,
},
};
static struct mt9v022_platform_data mt9v022_pdata = {
.y_skip_top = 1,
};
static struct i2c_board_info pcm990_camera_i2c[] = {
{
I2C_BOARD_INFO("mt9v022", 0x48),
}, {
I2C_BOARD_INFO("mt9m001", 0x5d),
},
};
static struct soc_camera_link iclink[] = {
{
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm990_camera_i2c[0],
.priv = &mt9v022_pdata,
.i2c_adapter_id = 0,
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
}, {
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm990_camera_i2c[1],
.i2c_adapter_id = 0,
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
},
};
static struct platform_device pcm990_camera[] = {
{
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = &iclink[0],
},
}, {
.name = "soc-camera-pdrv",
.id = 1,
.dev = {
.platform_data = &iclink[1],
},
},
};
#endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
/*
* system init for baseboard usage. Will be called by pcm027 init.
*
@ -551,15 +404,5 @@ void __init pcm990_baseboard_init(void)
pxa_set_i2c_info(NULL);
pxa_set_ac97_info(NULL);
#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_camera_pin_config));
pxa_set_camera_info(&pcm990_pxacamera_platform_data);
i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices));
platform_device_register(&pcm990_camera[0]);
platform_device_register(&pcm990_camera[1]);
#endif
printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n");
}

View File

@ -65,9 +65,6 @@ CONFIG_VIDEO_DEV=y
# CONFIG_VIDEO_ALLOW_V4L1 is not set
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_OV772X=y
CONFIG_VIDEO_SH_MOBILE_CEU=y
# CONFIG_RADIO_ADAPTERS is not set
CONFIG_FB=y

View File

@ -72,9 +72,6 @@ CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_MT9T112=y
CONFIG_SOC_CAMERA_TW9910=y
CONFIG_VIDEO_SH_MOBILE_CEU=y
# CONFIG_V4L_USB_DRIVERS is not set
CONFIG_FB=y

View File

@ -62,9 +62,6 @@ CONFIG_VIDEO_DEV=y
# CONFIG_VIDEO_ALLOW_V4L1 is not set
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_TW9910=y
CONFIG_SOC_CAMERA_OV772X=y
CONFIG_VIDEO_SH_MOBILE_CEU=y
# CONFIG_RADIO_ADAPTERS is not set
CONFIG_FB=y

View File

@ -70,8 +70,6 @@ CONFIG_VIDEO_DEV=y
CONFIG_DVB_CORE=m
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_OV772X=y
CONFIG_VIDEO_SH_MOBILE_CEU=y
# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DVB_FE_CUSTOMISE is not set

View File

@ -33,6 +33,7 @@ menuconfig MEDIA_CEC_SUPPORT
adapter that supports HDMI CEC.
if MEDIA_CEC_SUPPORT
source "drivers/media/cec/i2c/Kconfig"
source "drivers/media/cec/platform/Kconfig"
source "drivers/media/cec/usb/Kconfig"
endif

View File

@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += core/ platform/ usb/
obj-y += core/ i2c/ platform/ usb/

View File

@ -1306,7 +1306,6 @@ static int cec_config_log_addr(struct cec_adapter *adap,
las->log_addr[idx] = log_addr;
las->log_addr_mask |= 1 << log_addr;
adap->phys_addrs[log_addr] = adap->phys_addr;
return 1;
}
@ -1324,7 +1323,6 @@ static void cec_adap_unconfigure(struct cec_adapter *adap)
adap->log_addrs.log_addr_mask = 0;
adap->is_configuring = false;
adap->is_configured = false;
memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs));
cec_flush(adap);
wake_up_interruptible(&adap->kthread_waitq);
cec_post_state_event(adap);
@ -1974,8 +1972,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
case CEC_MSG_REPORT_PHYSICAL_ADDR: {
u16 pa = (msg->msg[2] << 8) | msg->msg[3];
if (!from_unregistered)
adap->phys_addrs[init_laddr] = pa;
dprintk(1, "reported physical address %x.%x.%x.%x for logical address %d\n",
cec_phys_addr_exp(pa), init_laddr);
break;

View File

@ -147,7 +147,13 @@ static long cec_adap_g_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs log_addrs;
mutex_lock(&adap->lock);
log_addrs = adap->log_addrs;
/*
* We use memcpy here instead of assignment since there is a
* hole at the end of struct cec_log_addrs that an assignment
* might ignore. So when we do copy_to_user() we could leak
* one byte of memory.
*/
memcpy(&log_addrs, &adap->log_addrs, sizeof(log_addrs));
if (!adap->is_configured)
memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID,
sizeof(log_addrs.log_addr));

View File

@ -265,7 +265,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
adap->sequence = 0;
adap->ops = ops;
adap->priv = priv;
memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs));
mutex_init(&adap->lock);
INIT_LIST_HEAD(&adap->transmit_queue);
INIT_LIST_HEAD(&adap->wait_queue);

View File

@ -116,7 +116,8 @@ cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name,
else
memset(&n->conn_info, 0, sizeof(n->conn_info));
if (n->cec_adap) {
cec_phys_addr_invalidate(n->cec_adap);
if (!n->cec_adap->adap_controls_phys_addr)
cec_phys_addr_invalidate(n->cec_adap);
cec_s_conn_info(n->cec_adap, conn_info);
}
mutex_unlock(&n->lock);
@ -133,7 +134,8 @@ void cec_notifier_conn_unregister(struct cec_notifier *n)
memset(&n->conn_info, 0, sizeof(n->conn_info));
n->phys_addr = CEC_PHYS_ADDR_INVALID;
if (n->cec_adap) {
cec_phys_addr_invalidate(n->cec_adap);
if (!n->cec_adap->adap_controls_phys_addr)
cec_phys_addr_invalidate(n->cec_adap);
cec_s_conn_info(n->cec_adap, NULL);
}
mutex_unlock(&n->lock);
@ -158,7 +160,8 @@ cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name,
n->cec_adap = adap;
adap->conn_info = n->conn_info;
adap->notifier = n;
cec_s_phys_addr(adap, n->phys_addr, false);
if (!adap->adap_controls_phys_addr)
cec_s_phys_addr(adap, n->phys_addr, false);
mutex_unlock(&n->lock);
return n;
}
@ -185,7 +188,7 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
mutex_lock(&n->lock);
n->phys_addr = pa;
if (n->cec_adap)
if (n->cec_adap && !n->cec_adap->adap_controls_phys_addr)
cec_s_phys_addr(n->cec_adap, n->phys_addr, false);
mutex_unlock(&n->lock);
}

View File

@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
#
# I2C drivers
config CEC_CH7322
tristate "Chrontel CH7322 CEC controller"
depends on I2C
select REGMAP_I2C
select CEC_CORE
help
This is a driver for the Chrontel CH7322 CEC controller. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
between compatible devices.

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the CEC I2C device drivers.
#
obj-$(CONFIG_CEC_CH7322) += ch7322.o

View File

@ -0,0 +1,604 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Chrontel CH7322 CEC Controller
*
* Copyright 2020 Google LLC.
*/
/*
* Notes
*
* - This device powers on in Auto Mode which has limited functionality. This
* driver disables Auto Mode when it attaches.
*
*/
#include <linux/cec.h>
#include <linux/dmi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/regmap.h>
#include <media/cec.h>
#include <media/cec-notifier.h>
#define CH7322_WRITE 0x00
#define CH7322_WRITE_MSENT 0x80
#define CH7322_WRITE_BOK 0x40
#define CH7322_WRITE_NMASK 0x0f
/* Write buffer is 0x01-0x10 */
#define CH7322_WRBUF 0x01
#define CH7322_WRBUF_LEN 0x10
#define CH7322_READ 0x40
#define CH7322_READ_NRDT 0x80
#define CH7322_READ_MSENT 0x20
#define CH7322_READ_NMASK 0x0f
/* Read buffer is 0x41-0x50 */
#define CH7322_RDBUF 0x41
#define CH7322_RDBUF_LEN 0x10
#define CH7322_MODE 0x11
#define CH7322_MODE_AUTO 0x78
#define CH7322_MODE_SW 0xb5
#define CH7322_RESET 0x12
#define CH7322_RESET_RST 0x00
#define CH7322_POWER 0x13
#define CH7322_POWER_FPD 0x04
#define CH7322_CFG0 0x17
#define CH7322_CFG0_EOBEN 0x40
#define CH7322_CFG0_PEOB 0x20
#define CH7322_CFG0_CLRSPP 0x10
#define CH7322_CFG0_FLOW 0x08
#define CH7322_CFG1 0x1a
#define CH7322_CFG1_STDBYO 0x04
#define CH7322_CFG1_HPBP 0x02
#define CH7322_CFG1_PIO 0x01
#define CH7322_INTCTL 0x1b
#define CH7322_INTCTL_INTPB 0x80
#define CH7322_INTCTL_STDBY 0x40
#define CH7322_INTCTL_HPDFALL 0x20
#define CH7322_INTCTL_HPDRISE 0x10
#define CH7322_INTCTL_RXMSG 0x08
#define CH7322_INTCTL_TXMSG 0x04
#define CH7322_INTCTL_NEWPHA 0x02
#define CH7322_INTCTL_ERROR 0x01
#define CH7322_DVCLKFNH 0x1d
#define CH7322_DVCLKFNL 0x1e
#define CH7322_CTL 0x31
#define CH7322_CTL_FSTDBY 0x80
#define CH7322_CTL_PLSEN 0x40
#define CH7322_CTL_PLSPB 0x20
#define CH7322_CTL_SPADL 0x10
#define CH7322_CTL_HINIT 0x08
#define CH7322_CTL_WPHYA 0x04
#define CH7322_CTL_H1T 0x02
#define CH7322_CTL_S1T 0x01
#define CH7322_PAWH 0x32
#define CH7322_PAWL 0x33
#define CH7322_ADDLW 0x34
#define CH7322_ADDLW_MASK 0xf0
#define CH7322_ADDLR 0x3d
#define CH7322_ADDLR_HPD 0x80
#define CH7322_ADDLR_MASK 0x0f
#define CH7322_INTDATA 0x3e
#define CH7322_INTDATA_MODE 0x80
#define CH7322_INTDATA_STDBY 0x40
#define CH7322_INTDATA_HPDFALL 0x20
#define CH7322_INTDATA_HPDRISE 0x10
#define CH7322_INTDATA_RXMSG 0x08
#define CH7322_INTDATA_TXMSG 0x04
#define CH7322_INTDATA_NEWPHA 0x02
#define CH7322_INTDATA_ERROR 0x01
#define CH7322_EVENT 0x3f
#define CH7322_EVENT_TXERR 0x80
#define CH7322_EVENT_HRST 0x40
#define CH7322_EVENT_HFST 0x20
#define CH7322_EVENT_PHACHG 0x10
#define CH7322_EVENT_ACTST 0x08
#define CH7322_EVENT_PHARDY 0x04
#define CH7322_EVENT_BSOK 0x02
#define CH7322_EVENT_ERRADCF 0x01
#define CH7322_DID 0x51
#define CH7322_DID_CH7322 0x5b
#define CH7322_DID_CH7323 0x5f
#define CH7322_REVISIONID 0x52
#define CH7322_PARH 0x53
#define CH7322_PARL 0x54
#define CH7322_IOCFG2 0x75
#define CH7322_IOCFG_CIO 0x80
#define CH7322_IOCFG_IOCFGMASK 0x78
#define CH7322_IOCFG_AUDIO 0x04
#define CH7322_IOCFG_SPAMST 0x02
#define CH7322_IOCFG_SPAMSP 0x01
#define CH7322_CTL3 0x7b
#define CH7322_CTL3_SWENA 0x80
#define CH7322_CTL3_FC_INIT 0x40
#define CH7322_CTL3_SML_FL 0x20
#define CH7322_CTL3_SM_RDST 0x10
#define CH7322_CTL3_SPP_CIAH 0x08
#define CH7322_CTL3_SPP_CIAL 0x04
#define CH7322_CTL3_SPP_ACTH 0x02
#define CH7322_CTL3_SPP_ACTL 0x01
/* BOK status means NACK */
#define CH7322_TX_FLAG_NACK BIT(0)
/* Device will retry automatically */
#define CH7322_TX_FLAG_RETRY BIT(1)
struct ch7322 {
struct i2c_client *i2c;
struct regmap *regmap;
struct cec_adapter *cec;
struct mutex mutex; /* device access mutex */
u8 tx_flags;
};
static const struct regmap_config ch7322_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x7f,
.disable_locking = true,
};
static int ch7322_send_message(struct ch7322 *ch7322, const struct cec_msg *msg)
{
unsigned int val;
unsigned int len = msg->len;
int ret;
int i;
WARN_ON(!mutex_is_locked(&ch7322->mutex));
if (len > CH7322_WRBUF_LEN || len < 1)
return -EINVAL;
ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
if (ret)
return ret;
/* Buffer not ready */
if (!(val & CH7322_WRITE_MSENT))
return -EBUSY;
if (cec_msg_opcode(msg) == -1 &&
cec_msg_initiator(msg) == cec_msg_destination(msg)) {
ch7322->tx_flags = CH7322_TX_FLAG_NACK | CH7322_TX_FLAG_RETRY;
} else if (cec_msg_is_broadcast(msg)) {
ch7322->tx_flags = CH7322_TX_FLAG_NACK;
} else {
ch7322->tx_flags = CH7322_TX_FLAG_RETRY;
}
ret = regmap_write(ch7322->regmap, CH7322_WRITE, len - 1);
if (ret)
return ret;
for (i = 0; i < len; i++) {
ret = regmap_write(ch7322->regmap,
CH7322_WRBUF + i, msg->msg[i]);
if (ret)
return ret;
}
return 0;
}
static int ch7322_receive_message(struct ch7322 *ch7322, struct cec_msg *msg)
{
unsigned int val;
int ret = 0;
int i;
WARN_ON(!mutex_is_locked(&ch7322->mutex));
ret = regmap_read(ch7322->regmap, CH7322_READ, &val);
if (ret)
return ret;
/* Message not ready */
if (!(val & CH7322_READ_NRDT))
return -EIO;
msg->len = (val & CH7322_READ_NMASK) + 1;
/* Read entire RDBUF to clear state */
for (i = 0; i < CH7322_RDBUF_LEN; i++) {
ret = regmap_read(ch7322->regmap, CH7322_RDBUF + i, &val);
if (ret)
return ret;
msg->msg[i] = (u8)val;
}
return 0;
}
static void ch7322_tx_done(struct ch7322 *ch7322)
{
int ret;
unsigned int val;
u8 status, flags;
mutex_lock(&ch7322->mutex);
ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
flags = ch7322->tx_flags;
mutex_unlock(&ch7322->mutex);
/*
* The device returns a one-bit OK status which usually means ACK but
* actually means NACK when sending a logical address query or a
* broadcast.
*/
if (ret)
status = CEC_TX_STATUS_ERROR;
else if ((val & CH7322_WRITE_BOK) && (flags & CH7322_TX_FLAG_NACK))
status = CEC_TX_STATUS_NACK;
else if (val & CH7322_WRITE_BOK)
status = CEC_TX_STATUS_OK;
else if (flags & CH7322_TX_FLAG_NACK)
status = CEC_TX_STATUS_OK;
else
status = CEC_TX_STATUS_NACK;
if (status == CEC_TX_STATUS_NACK && (flags & CH7322_TX_FLAG_RETRY))
status |= CEC_TX_STATUS_MAX_RETRIES;
cec_transmit_attempt_done(ch7322->cec, status);
}
static void ch7322_rx_done(struct ch7322 *ch7322)
{
struct cec_msg msg;
int ret;
mutex_lock(&ch7322->mutex);
ret = ch7322_receive_message(ch7322, &msg);
mutex_unlock(&ch7322->mutex);
if (ret)
dev_err(&ch7322->i2c->dev, "cec receive error: %d\n", ret);
else
cec_received_msg(ch7322->cec, &msg);
}
/*
* This device can either monitor the DDC lines to obtain the physical address
* or it can allow the host to program it. This driver lets the device obtain
* it.
*/
static void ch7322_phys_addr(struct ch7322 *ch7322)
{
unsigned int pah, pal;
int ret = 0;
mutex_lock(&ch7322->mutex);
ret |= regmap_read(ch7322->regmap, CH7322_PARH, &pah);
ret |= regmap_read(ch7322->regmap, CH7322_PARL, &pal);
mutex_unlock(&ch7322->mutex);
if (ret)
dev_err(&ch7322->i2c->dev, "phys addr error\n");
else
cec_s_phys_addr(ch7322->cec, pal | (pah << 8), false);
}
static irqreturn_t ch7322_irq(int irq, void *dev)
{
struct ch7322 *ch7322 = dev;
unsigned int data = 0;
mutex_lock(&ch7322->mutex);
regmap_read(ch7322->regmap, CH7322_INTDATA, &data);
regmap_write(ch7322->regmap, CH7322_INTDATA, data);
mutex_unlock(&ch7322->mutex);
if (data & CH7322_INTDATA_HPDFALL)
cec_phys_addr_invalidate(ch7322->cec);
if (data & CH7322_INTDATA_TXMSG)
ch7322_tx_done(ch7322);
if (data & CH7322_INTDATA_RXMSG)
ch7322_rx_done(ch7322);
if (data & CH7322_INTDATA_NEWPHA)
ch7322_phys_addr(ch7322);
if (data & CH7322_INTDATA_ERROR)
dev_dbg(&ch7322->i2c->dev, "unknown error\n");
return IRQ_HANDLED;
}
/* This device is always enabled */
static int ch7322_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
return 0;
}
static int ch7322_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
{
struct ch7322 *ch7322 = cec_get_drvdata(adap);
int ret;
mutex_lock(&ch7322->mutex);
ret = regmap_update_bits(ch7322->regmap, CH7322_ADDLW,
CH7322_ADDLW_MASK, log_addr << 4);
mutex_unlock(&ch7322->mutex);
return ret;
}
static int ch7322_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct ch7322 *ch7322 = cec_get_drvdata(adap);
int ret;
mutex_lock(&ch7322->mutex);
ret = ch7322_send_message(ch7322, msg);
mutex_unlock(&ch7322->mutex);
return ret;
}
static const struct cec_adap_ops ch7322_cec_adap_ops = {
.adap_enable = ch7322_cec_adap_enable,
.adap_log_addr = ch7322_cec_adap_log_addr,
.adap_transmit = ch7322_cec_adap_transmit,
};
#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
struct ch7322_conn_match {
const char *dev_name;
const char *pci_name;
const char *port_name;
};
static struct ch7322_conn_match google_endeavour[] = {
{ "i2c-PRP0001:00", "0000:00:02.0", "Port B" },
{ "i2c-PRP0001:01", "0000:00:02.0", "Port C" },
{ },
};
static const struct dmi_system_id ch7322_dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_NAME, "Endeavour"),
},
.driver_data = google_endeavour,
},
{ },
};
/* Make a best-effort attempt to locate a matching HDMI port */
static int ch7322_get_port(struct i2c_client *client,
struct device **dev,
const char **port)
{
const struct dmi_system_id *system;
const struct ch7322_conn_match *conn;
*dev = NULL;
*port = NULL;
system = dmi_first_match(ch7322_dmi_table);
if (!system)
return 0;
for (conn = system->driver_data; conn->dev_name; conn++) {
if (!strcmp(dev_name(&client->dev), conn->dev_name)) {
struct device *d;
d = bus_find_device_by_name(&pci_bus_type, NULL,
conn->pci_name);
if (!d)
return -EPROBE_DEFER;
put_device(d);
*dev = d;
*port = conn->port_name;
return 0;
}
}
return 0;
}
#else
static int ch7322_get_port(struct i2c_client *client,
struct device **dev,
const char **port)
{
*dev = NULL;
*port = NULL;
return 0;
}
#endif
static int ch7322_probe(struct i2c_client *client)
{
struct device *hdmi_dev;
const char *port_name;
struct ch7322 *ch7322;
struct cec_notifier *notifier = NULL;
u32 caps = CEC_CAP_DEFAULTS;
int ret;
unsigned int val;
ret = ch7322_get_port(client, &hdmi_dev, &port_name);
if (ret)
return ret;
if (hdmi_dev)
caps |= CEC_CAP_CONNECTOR_INFO;
ch7322 = devm_kzalloc(&client->dev, sizeof(*ch7322), GFP_KERNEL);
if (!ch7322)
return -ENOMEM;
ch7322->regmap = devm_regmap_init_i2c(client, &ch7322_regmap);
if (IS_ERR(ch7322->regmap))
return PTR_ERR(ch7322->regmap);
ret = regmap_read(ch7322->regmap, CH7322_DID, &val);
if (ret)
return ret;
if (val != CH7322_DID_CH7322)
return -EOPNOTSUPP;
mutex_init(&ch7322->mutex);
ch7322->i2c = client;
ch7322->tx_flags = 0;
i2c_set_clientdata(client, ch7322);
/* Disable auto mode */
ret = regmap_write(ch7322->regmap, CH7322_MODE, CH7322_MODE_SW);
if (ret)
goto err_mutex;
/* Enable logical address register */
ret = regmap_update_bits(ch7322->regmap, CH7322_CTL,
CH7322_CTL_SPADL, CH7322_CTL_SPADL);
if (ret)
goto err_mutex;
ch7322->cec = cec_allocate_adapter(&ch7322_cec_adap_ops, ch7322,
dev_name(&client->dev),
caps, 1);
if (IS_ERR(ch7322->cec)) {
ret = PTR_ERR(ch7322->cec);
goto err_mutex;
}
ch7322->cec->adap_controls_phys_addr = true;
if (hdmi_dev) {
notifier = cec_notifier_cec_adap_register(hdmi_dev,
port_name,
ch7322->cec);
if (!notifier) {
ret = -ENOMEM;
goto err_cec;
}
}
/* Configure, mask, and clear interrupt */
ret = regmap_write(ch7322->regmap, CH7322_CFG1, 0);
if (ret)
goto err_notifier;
ret = regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
if (ret)
goto err_notifier;
ret = regmap_write(ch7322->regmap, CH7322_INTDATA, 0xff);
if (ret)
goto err_notifier;
/* If HPD is up read physical address */
ret = regmap_read(ch7322->regmap, CH7322_ADDLR, &val);
if (ret)
goto err_notifier;
if (val & CH7322_ADDLR_HPD)
ch7322_phys_addr(ch7322);
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
ch7322_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
client->name, ch7322);
if (ret)
goto err_notifier;
/* Unmask interrupt */
mutex_lock(&ch7322->mutex);
ret = regmap_write(ch7322->regmap, CH7322_INTCTL, 0xff);
mutex_unlock(&ch7322->mutex);
if (ret)
goto err_notifier;
ret = cec_register_adapter(ch7322->cec, &client->dev);
if (ret)
goto err_notifier;
dev_info(&client->dev, "device registered\n");
return 0;
err_notifier:
if (notifier)
cec_notifier_cec_adap_unregister(notifier, ch7322->cec);
err_cec:
cec_delete_adapter(ch7322->cec);
err_mutex:
mutex_destroy(&ch7322->mutex);
return ret;
}
static int ch7322_remove(struct i2c_client *client)
{
struct ch7322 *ch7322 = i2c_get_clientdata(client);
/* Mask interrupt */
mutex_lock(&ch7322->mutex);
regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
mutex_unlock(&ch7322->mutex);
cec_unregister_adapter(ch7322->cec);
mutex_destroy(&ch7322->mutex);
dev_info(&client->dev, "device unregistered\n");
return 0;
}
static const struct of_device_id ch7322_of_match[] = {
{ .compatible = "chrontel,ch7322", },
{},
};
MODULE_DEVICE_TABLE(of, ch7322_of_match);
static struct i2c_driver ch7322_i2c_driver = {
.driver = {
.name = "ch7322",
.of_match_table = of_match_ptr(ch7322_of_match),
},
.probe_new = ch7322_probe,
.remove = ch7322_remove,
};
module_i2c_driver(ch7322_i2c_driver);
MODULE_DESCRIPTION("Chrontel CH7322 CEC Controller Driver");
MODULE_AUTHOR("Jeff Chase <jnchase@google.com>");
MODULE_LICENSE("GPL");

View File

@ -277,11 +277,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cros_ec_cec);
cros_ec_cec->cros_ec = cros_ec;
ret = device_init_wakeup(&pdev->dev, 1);
if (ret) {
dev_err(&pdev->dev, "failed to initialize wakeup\n");
return ret;
}
device_init_wakeup(&pdev->dev, 1);
cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec,
DRV_NAME,

View File

@ -1927,44 +1927,46 @@ typedef struct { u16 __; u8 _; } __packed x24;
static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, char *text, unsigned len)
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u8);
}
static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, char *text, unsigned len)
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u16);
}
static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, char *text, unsigned len)
int y, int x, const char *text, unsigned len)
{
PRINTSTR(x24);
}
static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
unsigned p, unsigned first, unsigned div, unsigned step,
int y, int x, char *text, unsigned len)
int y, int x, const char *text, unsigned len)
{
PRINTSTR(u32);
}
void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
int y, int x, char *text)
int y, int x, const char *text)
{
unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
unsigned div = step;
unsigned first = 0;
unsigned len = strlen(text);
unsigned len;
unsigned p;
if (font8x16 == NULL || basep == NULL)
if (font8x16 == NULL || basep == NULL || text == NULL)
return;
len = strlen(text);
/* Checks if it is possible to show string */
if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
return;
@ -2006,6 +2008,30 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
}
EXPORT_SYMBOL_GPL(tpg_gen_text);
const char *tpg_g_color_order(const struct tpg_data *tpg)
{
switch (tpg->pattern) {
case TPG_PAT_75_COLORBAR:
case TPG_PAT_100_COLORBAR:
case TPG_PAT_CSC_COLORBAR:
case TPG_PAT_100_HCOLORBAR:
return "White, yellow, cyan, green, magenta, red, blue, black";
case TPG_PAT_BLACK:
return "Black";
case TPG_PAT_WHITE:
return "White";
case TPG_PAT_RED:
return "Red";
case TPG_PAT_GREEN:
return "Green";
case TPG_PAT_BLUE:
return "Blue";
default:
return NULL;
}
}
EXPORT_SYMBOL_GPL(tpg_g_color_order);
void tpg_update_mv_step(struct tpg_data *tpg)
{
int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,11 @@ struct vb2_dc_buf {
struct dma_buf_attachment *db_attach;
};
static inline bool vb2_dc_buffer_consistent(unsigned long attr)
{
return !(attr & DMA_ATTR_NON_CONSISTENT);
}
/*********************************************/
/* scatterlist table functions */
/*********************************************/
@ -95,8 +100,7 @@ static void vb2_dc_prepare(void *buf_priv)
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
/* DMABUF exporter will flush the cache for us */
if (!sgt || buf->db_attach)
if (!sgt)
return;
dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
@ -108,8 +112,7 @@ static void vb2_dc_finish(void *buf_priv)
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
/* DMABUF exporter will flush the cache for us */
if (!sgt || buf->db_attach)
if (!sgt)
return;
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
@ -149,8 +152,7 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs,
if (!buf)
return ERR_PTR(-ENOMEM);
if (attrs)
buf->attrs = attrs;
buf->attrs = attrs;
buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,
GFP_KERNEL | gfp_flags, buf->attrs);
if (!buf->cookie) {
@ -335,6 +337,34 @@ static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf)
vb2_dc_put(dbuf->priv);
}
static int
vb2_dc_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
struct vb2_dc_buf *buf = dbuf->priv;
struct sg_table *sgt = buf->dma_sgt;
if (vb2_dc_buffer_consistent(buf->attrs))
return 0;
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
static int
vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
struct vb2_dc_buf *buf = dbuf->priv;
struct sg_table *sgt = buf->dma_sgt;
if (vb2_dc_buffer_consistent(buf->attrs))
return 0;
dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf)
{
struct vb2_dc_buf *buf = dbuf->priv;
@ -353,6 +383,8 @@ static const struct dma_buf_ops vb2_dc_dmabuf_ops = {
.detach = vb2_dc_dmabuf_ops_detach,
.map_dma_buf = vb2_dc_dmabuf_ops_map,
.unmap_dma_buf = vb2_dc_dmabuf_ops_unmap,
.begin_cpu_access = vb2_dc_dmabuf_ops_begin_cpu_access,
.end_cpu_access = vb2_dc_dmabuf_ops_end_cpu_access,
.vmap = vb2_dc_dmabuf_ops_vmap,
.mmap = vb2_dc_dmabuf_ops_mmap,
.release = vb2_dc_dmabuf_ops_release,

View File

@ -120,6 +120,12 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
buf->num_pages = size >> PAGE_SHIFT;
buf->dma_sgt = &buf->sg_table;
/*
* NOTE: dma-sg allocates memory using the page allocator directly, so
* there is no memory consistency guarantee, hence dma-sg ignores DMA
* attributes passed from the upper layer. That means that
* V4L2_FLAG_MEMORY_NON_CONSISTENT has no effect on dma-sg buffers.
*/
buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *),
GFP_KERNEL | __GFP_ZERO);
if (!buf->pages)
@ -198,10 +204,6 @@ static void vb2_dma_sg_prepare(void *buf_priv)
struct vb2_dma_sg_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
/* DMABUF exporter will flush the cache for us */
if (buf->db_attach)
return;
dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
buf->dma_dir);
}
@ -211,10 +213,6 @@ static void vb2_dma_sg_finish(void *buf_priv)
struct vb2_dma_sg_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
/* DMABUF exporter will flush the cache for us */
if (buf->db_attach)
return;
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
}
@ -469,6 +467,28 @@ static void vb2_dma_sg_dmabuf_ops_release(struct dma_buf *dbuf)
vb2_dma_sg_put(dbuf->priv);
}
static int
vb2_dma_sg_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
struct vb2_dma_sg_buf *buf = dbuf->priv;
struct sg_table *sgt = buf->dma_sgt;
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
static int
vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
struct vb2_dma_sg_buf *buf = dbuf->priv;
struct sg_table *sgt = buf->dma_sgt;
dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
static void *vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf)
{
struct vb2_dma_sg_buf *buf = dbuf->priv;
@ -487,6 +507,8 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
.detach = vb2_dma_sg_dmabuf_ops_detach,
.map_dma_buf = vb2_dma_sg_dmabuf_ops_map,
.unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap,
.begin_cpu_access = vb2_dma_sg_dmabuf_ops_begin_cpu_access,
.end_cpu_access = vb2_dma_sg_dmabuf_ops_end_cpu_access,
.vmap = vb2_dma_sg_dmabuf_ops_vmap,
.mmap = vb2_dma_sg_dmabuf_ops_mmap,
.release = vb2_dma_sg_dmabuf_ops_release,

View File

@ -35,10 +35,11 @@
static int debug;
module_param(debug, int, 0644);
#define dprintk(level, fmt, arg...) \
#define dprintk(q, level, fmt, arg...) \
do { \
if (debug >= level) \
pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \
pr_info("vb2-v4l2: [%p] %s: " fmt, \
(q)->name, __func__, ## arg); \
} while (0)
/* Flags that are set by us */
@ -66,12 +67,14 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
/* Is memory for copying plane information present? */
if (b->m.planes == NULL) {
dprintk(1, "multi-planar buffer passed but planes array not provided\n");
dprintk(vb->vb2_queue, 1,
"multi-planar buffer passed but planes array not provided\n");
return -EINVAL;
}
if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) {
dprintk(1, "incorrect planes array length, expected %d, got %d\n",
dprintk(vb->vb2_queue, 1,
"incorrect planes array length, expected %d, got %d\n",
vb->num_planes, b->length);
return -EINVAL;
}
@ -94,7 +97,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
unsigned int bytesused;
unsigned int plane;
if (!V4L2_TYPE_IS_OUTPUT(b->type))
if (V4L2_TYPE_IS_CAPTURE(b->type))
return 0;
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
@ -114,7 +117,8 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
return -EINVAL;
}
} else {
length = (b->memory == VB2_MEMORY_USERPTR)
length = (b->memory == VB2_MEMORY_USERPTR ||
b->memory == VB2_MEMORY_DMABUF)
? b->length : vb->planes[0].length;
if (b->bytesused > length)
@ -179,7 +183,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
ret = __verify_length(vb, b);
if (ret < 0) {
dprintk(1, "plane parameters verification failed: %d\n", ret);
dprintk(q, 1, "plane parameters verification failed: %d\n", ret);
return ret;
}
if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
@ -192,7 +196,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
* that just says that it is either a top or a bottom field,
* but not which of the two it is.
*/
dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
dprintk(q, 1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
return -EINVAL;
}
vbuf->sequence = 0;
@ -307,7 +311,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
/* Zero flags that we handle */
vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
if (!vb->vb2_queue->copy_timestamp || V4L2_TYPE_IS_CAPTURE(b->type)) {
/*
* Non-COPY timestamps and non-OUTPUT queues will get
* their timestamp and timestamp source flags from the
@ -337,6 +341,53 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
return 0;
}
static void set_buffer_cache_hints(struct vb2_queue *q,
struct vb2_buffer *vb,
struct v4l2_buffer *b)
{
/*
* DMA exporter should take care of cache syncs, so we can avoid
* explicit ->prepare()/->finish() syncs. For other ->memory types
* we always need ->prepare() or/and ->finish() cache sync.
*/
if (q->memory == VB2_MEMORY_DMABUF) {
vb->need_cache_sync_on_finish = 0;
vb->need_cache_sync_on_prepare = 0;
return;
}
/*
* Cache sync/invalidation flags are set by default in order to
* preserve existing behaviour for old apps/drivers.
*/
vb->need_cache_sync_on_prepare = 1;
vb->need_cache_sync_on_finish = 1;
if (!vb2_queue_allows_cache_hints(q)) {
/*
* Clear buffer cache flags if queue does not support user
* space hints. That's to indicate to userspace that these
* flags won't work.
*/
b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_INVALIDATE;
b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_CLEAN;
return;
}
/*
* ->finish() cache sync can be avoided when queue direction is
* TO_DEVICE.
*/
if (q->dma_dir == DMA_TO_DEVICE)
vb->need_cache_sync_on_finish = 0;
if (b->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE)
vb->need_cache_sync_on_finish = 0;
if (b->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN)
vb->need_cache_sync_on_prepare = 0;
}
static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
struct v4l2_buffer *b, bool is_prepare,
struct media_request **p_req)
@ -348,23 +399,23 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
int ret;
if (b->type != q->type) {
dprintk(1, "%s: invalid buffer type\n", opname);
dprintk(q, 1, "%s: invalid buffer type\n", opname);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
dprintk(1, "%s: buffer index out of range\n", opname);
dprintk(q, 1, "%s: buffer index out of range\n", opname);
return -EINVAL;
}
if (q->bufs[b->index] == NULL) {
/* Should never happen */
dprintk(1, "%s: buffer is NULL\n", opname);
dprintk(q, 1, "%s: buffer is NULL\n", opname);
return -EINVAL;
}
if (b->memory != q->memory) {
dprintk(1, "%s: invalid memory type\n", opname);
dprintk(q, 1, "%s: invalid memory type\n", opname);
return -EINVAL;
}
@ -376,11 +427,12 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) &&
vb->state != VB2_BUF_STATE_DEQUEUED) {
dprintk(1, "%s: buffer is not in dequeued state\n", opname);
dprintk(q, 1, "%s: buffer is not in dequeued state\n", opname);
return -EINVAL;
}
if (!vb->prepared) {
set_buffer_cache_hints(q, vb, b);
/* Copy relevant information provided by the userspace */
memset(vbuf->planes, 0,
sizeof(vbuf->planes[0]) * vb->num_planes);
@ -394,19 +446,19 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) {
if (q->requires_requests) {
dprintk(1, "%s: queue requires requests\n", opname);
dprintk(q, 1, "%s: queue requires requests\n", opname);
return -EBADR;
}
if (q->uses_requests) {
dprintk(1, "%s: queue uses requests\n", opname);
dprintk(q, 1, "%s: queue uses requests\n", opname);
return -EBUSY;
}
return 0;
} else if (!q->supports_requests) {
dprintk(1, "%s: queue does not support requests\n", opname);
dprintk(q, 1, "%s: queue does not support requests\n", opname);
return -EBADR;
} else if (q->uses_qbuf) {
dprintk(1, "%s: queue does not use requests\n", opname);
dprintk(q, 1, "%s: queue does not use requests\n", opname);
return -EBUSY;
}
@ -436,13 +488,13 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
return -EINVAL;
if (b->request_fd < 0) {
dprintk(1, "%s: request_fd < 0\n", opname);
dprintk(q, 1, "%s: request_fd < 0\n", opname);
return -EINVAL;
}
req = media_request_get_by_fd(mdev, b->request_fd);
if (IS_ERR(req)) {
dprintk(1, "%s: invalid request_fd\n", opname);
dprintk(q, 1, "%s: invalid request_fd\n", opname);
return PTR_ERR(req);
}
@ -452,7 +504,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
*/
if (req->state != MEDIA_REQUEST_STATE_IDLE &&
req->state != MEDIA_REQUEST_STATE_UPDATING) {
dprintk(1, "%s: request is not idle\n", opname);
dprintk(q, 1, "%s: request is not idle\n", opname);
media_request_put(req);
return -EBUSY;
}
@ -635,12 +687,12 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
int ret;
if (b->type != q->type) {
dprintk(1, "wrong buffer type\n");
dprintk(q, 1, "wrong buffer type\n");
return -EINVAL;
}
if (b->index >= q->num_buffers) {
dprintk(1, "buffer index out of range\n");
dprintk(q, 1, "buffer index out of range\n");
return -EINVAL;
}
vb = q->bufs[b->index];
@ -662,18 +714,30 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
*caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF;
if (q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF)
*caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
if (q->allow_cache_hints && q->io_modes & VB2_MMAP)
*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS;
#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
if (q->supports_requests)
*caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
#endif
}
static void clear_consistency_attr(struct vb2_queue *q,
int memory,
unsigned int *flags)
{
if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP)
*flags &= ~V4L2_FLAG_MEMORY_NON_CONSISTENT;
}
int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
{
int ret = vb2_verify_memory_type(q, req->memory, req->type);
fill_buf_caps(q, &req->capabilities);
return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
clear_consistency_attr(q, req->memory, &req->flags);
return ret ? ret : vb2_core_reqbufs(q, req->memory,
req->flags, &req->count);
}
EXPORT_SYMBOL_GPL(vb2_reqbufs);
@ -683,7 +747,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
int ret;
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
@ -705,6 +769,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
unsigned i;
fill_buf_caps(q, &create->capabilities);
clear_consistency_attr(q, create->memory, &create->flags);
create->index = q->num_buffers;
if (create->count == 0)
return ret != -EBUSY ? ret : 0;
@ -748,7 +813,10 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
if (requested_sizes[i] == 0)
return -EINVAL;
return ret ? ret : vb2_core_create_bufs(q, create->memory,
&create->count, requested_planes, requested_sizes);
create->flags,
&create->count,
requested_planes,
requested_sizes);
}
EXPORT_SYMBOL_GPL(vb2_create_bufs);
@ -759,7 +827,7 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev,
int ret;
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
@ -778,12 +846,12 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
int ret;
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
if (b->type != q->type) {
dprintk(1, "invalid buffer type\n");
dprintk(q, 1, "invalid buffer type\n");
return -EINVAL;
}
@ -807,7 +875,7 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf);
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
return vb2_core_streamon(q, type);
@ -817,7 +885,7 @@ EXPORT_SYMBOL_GPL(vb2_streamon);
int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
return vb2_core_streamoff(q, type);
@ -831,7 +899,7 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
}
EXPORT_SYMBOL_GPL(vb2_expbuf);
int vb2_queue_init(struct vb2_queue *q)
int vb2_queue_init_name(struct vb2_queue *q, const char *name)
{
/*
* Sanity check
@ -867,8 +935,19 @@ int vb2_queue_init(struct vb2_queue *q)
*/
q->quirk_poll_must_check_waiting_for_buffers = true;
if (name)
strscpy(q->name, name, sizeof(q->name));
else
q->name[0] = '\0';
return vb2_core_queue_init(q);
}
EXPORT_SYMBOL_GPL(vb2_queue_init_name);
int vb2_queue_init(struct vb2_queue *q)
{
return vb2_queue_init_name(q, NULL);
}
EXPORT_SYMBOL_GPL(vb2_queue_init);
void vb2_queue_release(struct vb2_queue *q)
@ -919,11 +998,12 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
fill_buf_caps(vdev->queue, &p->capabilities);
clear_consistency_attr(vdev->queue, p->memory, &p->flags);
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count);
/* If count == 0, then the owner has released all buffers and he
is no longer owner of the queue. Otherwise we have a new owner. */
if (res == 0)
@ -941,6 +1021,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
p->index = vdev->queue->num_buffers;
fill_buf_caps(vdev->queue, &p->capabilities);
clear_consistency_attr(vdev->queue, p->memory, &p->flags);
/*
* If count == 0, then just check if memory and type are valid.
* Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.

View File

@ -342,7 +342,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
ctx->buf_siz = req->size;
ctx->buf_cnt = req->count;
ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count);
ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name,

View File

@ -155,17 +155,6 @@ if (debug >= level) \
printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \
} while (0)
static inline u32 MulDiv32(u32 a, u32 b, u32 c)
{
u64 tmp64;
tmp64 = (u64) a * (u64) b;
do_div(tmp64, c);
return (u32) tmp64;
}
static inline u32 Frac28a(u32 a, u32 c)
{
int i = 0;

View File

@ -5,7 +5,7 @@
* Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
*
* GNU Radio plugin "gr-kernel" for device usage will be on:
* http://git.linuxtv.org/anttip/gr-kernel.git
* https://git.linuxtv.org/anttip/gr-kernel.git
*/
#include "rtl2832_sdr.h"

View File

@ -272,6 +272,8 @@ static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
name_len = fw_csr_string(unit->directory, CSR_MODEL,
name, sizeof(name));
if (name_len < 0)
return name_len;
for (i = ARRAY_SIZE(model_names); --i; )
if (strlen(model_names[i]) <= name_len &&
strncmp(name, model_names[i], name_len) == 0)

View File

@ -464,6 +464,19 @@ config VIDEO_VPX3220
To compile this driver as a module, choose M here: the
module will be called vpx3220.
config VIDEO_MAX9286
tristate "Maxim MAX9286 GMSL deserializer support"
depends on I2C && I2C_MUX
depends on OF
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
select MEDIA_CONTROLLER
help
This driver supports the Maxim MAX9286 GMSL deserializer.
To compile this driver as a module, choose M here: the
module will be called max9286.
comment "Video and audio decoders"
config VIDEO_SAA717X
@ -860,6 +873,7 @@ config VIDEO_OV2685
config VIDEO_OV2740
tristate "OmniVision OV2740 sensor support"
depends on VIDEO_V4L2 && I2C
depends on ACPI || COMPILE_TEST
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select V4L2_FWNODE
@ -1157,6 +1171,19 @@ config VIDEO_NOON010PC30
source "drivers/media/i2c/m5mols/Kconfig"
config VIDEO_RDACM20
tristate "IMI RDACM20 camera support"
depends on I2C
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
select MEDIA_CONTROLLER
help
This driver supports the IMI RDACM20 GMSL camera, used in
ADAS systems.
This camera should be used in conjunction with a GMSL
deserialiser such as the MAX9286.
config VIDEO_RJ54N1
tristate "Sharp RJ54N1CB0C sensor support"
depends on I2C && VIDEO_V4L2
@ -1253,6 +1280,18 @@ config VIDEO_DW9714
capability. This is designed for linear control of
voice coil motors, controlled via I2C serial interface.
config VIDEO_DW9768
tristate "DW9768 lens voice coil support"
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select V4L2_FWNODE
help
This is a driver for the DW9768 camera lens voice coil.
DW9768 is a 10 bit DAC with 100mA output current sink
capability. This is designed for linear control of
voice coil motors, controlled via I2C serial interface.
config VIDEO_DW9807_VCM
tristate "DW9807 lens voice coil support"
depends on I2C && VIDEO_V4L2

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o
obj-$(CONFIG_VIDEO_AD5820) += ad5820.o
obj-$(CONFIG_VIDEO_AK7375) += ak7375.o
obj-$(CONFIG_VIDEO_DW9714) += dw9714.o
obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
@ -118,6 +119,9 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
rdacm20-camera_module-objs := rdacm20.o max9271.o
obj-$(CONFIG_VIDEO_RDACM20) += rdacm20-camera_module.o
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o

554
drivers/media/i2c/dw9768.c Normal file
View File

@ -0,0 +1,554 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 MediaTek Inc.
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#define DW9768_NAME "dw9768"
#define DW9768_MAX_FOCUS_POS (1024 - 1)
/*
* This sets the minimum granularity for the focus positions.
* A value of 1 gives maximum accuracy for a desired focus position
*/
#define DW9768_FOCUS_STEPS 1
/*
* Ring control and Power control register
* Bit[1] RING_EN
* 0: Direct mode
* 1: AAC mode (ringing control mode)
* Bit[0] PD
* 0: Normal operation mode
* 1: Power down mode
* DW9768 requires waiting time of Topr after PD reset takes place.
*/
#define DW9768_RING_PD_CONTROL_REG 0x02
#define DW9768_PD_MODE_OFF 0x00
#define DW9768_PD_MODE_EN BIT(0)
#define DW9768_AAC_MODE_EN BIT(1)
/*
* DW9768 separates two registers to control the VCM position.
* One for MSB value, another is LSB value.
* DAC_MSB: D[9:8] (ADD: 0x03)
* DAC_LSB: D[7:0] (ADD: 0x04)
* D[9:0] DAC data input: positive output current = D[9:0] / 1023 * 100[mA]
*/
#define DW9768_MSB_ADDR 0x03
#define DW9768_LSB_ADDR 0x04
#define DW9768_STATUS_ADDR 0x05
/*
* AAC mode control & prescale register
* Bit[7:5] Namely AC[2:0], decide the VCM mode and operation time.
* 001 AAC2 0.48 x Tvib
* 010 AAC3 0.70 x Tvib
* 011 AAC4 0.75 x Tvib
* 101 AAC8 1.13 x Tvib
* Bit[2:0] Namely PRESC[2:0], set the internal clock dividing rate as follow.
* 000 2
* 001 1
* 010 1/2
* 011 1/4
* 100 8
* 101 4
*/
#define DW9768_AAC_PRESC_REG 0x06
#define DW9768_AAC_MODE_SEL_MASK GENMASK(7, 5)
#define DW9768_CLOCK_PRE_SCALE_SEL_MASK GENMASK(2, 0)
/*
* VCM period of vibration register
* Bit[5:0] Defined as VCM rising periodic time (Tvib) together with PRESC[2:0]
* Tvib = (6.3ms + AACT[5:0] * 0.1ms) * Dividing Rate
* Dividing Rate is the internal clock dividing rate that is defined at
* PRESCALE register (ADD: 0x06)
*/
#define DW9768_AAC_TIME_REG 0x07
/*
* DW9768 requires waiting time (delay time) of t_OPR after power-up,
* or in the case of PD reset taking place.
*/
#define DW9768_T_OPR_US 1000
#define DW9768_TVIB_MS_BASE10 (64 - 1)
#define DW9768_AAC_MODE_DEFAULT 2
#define DW9768_AAC_TIME_DEFAULT 0x20
#define DW9768_CLOCK_PRE_SCALE_DEFAULT 1
/*
* This acts as the minimum granularity of lens movement.
* Keep this value power of 2, so the control steps can be
* uniformly adjusted for gradual lens movement, with desired
* number of control steps.
*/
#define DW9768_MOVE_STEPS 16
static const char * const dw9768_supply_names[] = {
"vin", /* Digital I/O power */
"vdd", /* Digital core power */
};
/* dw9768 device structure */
struct dw9768 {
struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)];
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *focus;
struct v4l2_subdev sd;
u32 aac_mode;
u32 aac_timing;
u32 clock_presc;
u32 move_delay_us;
};
static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
{
return container_of(subdev, struct dw9768, sd);
}
struct regval_list {
u8 reg_num;
u8 value;
};
struct dw9768_aac_mode_ot_multi {
u32 aac_mode_enum;
u32 ot_multi_base100;
};
struct dw9768_clk_presc_dividing_rate {
u32 clk_presc_enum;
u32 dividing_rate_base100;
};
static const struct dw9768_aac_mode_ot_multi aac_mode_ot_multi[] = {
{1, 48},
{2, 70},
{3, 75},
{5, 113},
};
static const struct dw9768_clk_presc_dividing_rate presc_dividing_rate[] = {
{0, 200},
{1, 100},
{2, 50},
{3, 25},
{4, 800},
{5, 400},
};
static u32 dw9768_find_ot_multi(u32 aac_mode_param)
{
u32 cur_ot_multi_base100 = 70;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(aac_mode_ot_multi); i++) {
if (aac_mode_ot_multi[i].aac_mode_enum == aac_mode_param) {
cur_ot_multi_base100 =
aac_mode_ot_multi[i].ot_multi_base100;
}
}
return cur_ot_multi_base100;
}
static u32 dw9768_find_dividing_rate(u32 presc_param)
{
u32 cur_clk_dividing_rate_base100 = 100;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(presc_dividing_rate); i++) {
if (presc_dividing_rate[i].clk_presc_enum == presc_param) {
cur_clk_dividing_rate_base100 =
presc_dividing_rate[i].dividing_rate_base100;
}
}
return cur_clk_dividing_rate_base100;
}
/*
* DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time.
* For current VCM mode: AAC3, Operation Time would be 0.70 x Tvib.
* Tvib = (6.3ms + AACT[5:0] * 0.1MS) * Dividing Rate.
* Below is calculation of the operation delay for each step.
*/
static inline u32 dw9768_cal_move_delay(u32 aac_mode_param, u32 presc_param,
u32 aac_timing_param)
{
u32 Tvib_us;
u32 ot_multi_base100;
u32 clk_dividing_rate_base100;
ot_multi_base100 = dw9768_find_ot_multi(aac_mode_param);
clk_dividing_rate_base100 = dw9768_find_dividing_rate(presc_param);
Tvib_us = (DW9768_TVIB_MS_BASE10 + aac_timing_param) *
clk_dividing_rate_base100;
return Tvib_us * ot_multi_base100 / 100;
}
static int dw9768_mod_reg(struct dw9768 *dw9768, u8 reg, u8 mask, u8 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0)
return ret;
val = ((unsigned char)ret & ~mask) | (val & mask);
return i2c_smbus_write_byte_data(client, reg, val);
}
static int dw9768_set_dac(struct dw9768 *dw9768, u16 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
/* Write VCM position to registers */
return i2c_smbus_write_word_swapped(client, DW9768_MSB_ADDR, val);
}
static int dw9768_init(struct dw9768 *dw9768)
{
struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
int ret, val;
/* Reset DW9768_RING_PD_CONTROL_REG to default status 0x00 */
ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG,
DW9768_PD_MODE_OFF);
if (ret < 0)
return ret;
/*
* DW9769 requires waiting delay time of t_OPR
* after PD reset takes place.
*/
usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100);
/* Set DW9768_RING_PD_CONTROL_REG to DW9768_AAC_MODE_EN(0x01) */
ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG,
DW9768_AAC_MODE_EN);
if (ret < 0)
return ret;
/* Set AAC mode */
ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG,
DW9768_AAC_MODE_SEL_MASK,
dw9768->aac_mode << 5);
if (ret < 0)
return ret;
/* Set clock presc */
if (dw9768->clock_presc != DW9768_CLOCK_PRE_SCALE_DEFAULT) {
ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG,
DW9768_CLOCK_PRE_SCALE_SEL_MASK,
dw9768->clock_presc);
if (ret < 0)
return ret;
}
/* Set AAC Timing */
if (dw9768->aac_timing != DW9768_AAC_TIME_DEFAULT) {
ret = i2c_smbus_write_byte_data(client, DW9768_AAC_TIME_REG,
dw9768->aac_timing);
if (ret < 0)
return ret;
}
for (val = dw9768->focus->val % DW9768_MOVE_STEPS;
val <= dw9768->focus->val;
val += DW9768_MOVE_STEPS) {
ret = dw9768_set_dac(dw9768, val);
if (ret) {
dev_err(&client->dev, "I2C failure: %d", ret);
return ret;
}
usleep_range(dw9768->move_delay_us,
dw9768->move_delay_us + 1000);
}
return 0;
}
static int dw9768_release(struct dw9768 *dw9768)
{
struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd);
int ret, val;
val = round_down(dw9768->focus->val, DW9768_MOVE_STEPS);
for ( ; val >= 0; val -= DW9768_MOVE_STEPS) {
ret = dw9768_set_dac(dw9768, val);
if (ret) {
dev_err(&client->dev, "I2C write fail: %d", ret);
return ret;
}
usleep_range(dw9768->move_delay_us,
dw9768->move_delay_us + 1000);
}
ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG,
DW9768_PD_MODE_EN);
if (ret < 0)
return ret;
/*
* DW9769 requires waiting delay time of t_OPR
* after PD reset takes place.
*/
usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100);
return 0;
}
static int dw9768_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct dw9768 *dw9768 = sd_to_dw9768(sd);
dw9768_release(dw9768);
regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies);
return 0;
}
static int dw9768_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct dw9768 *dw9768 = sd_to_dw9768(sd);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies);
if (ret < 0) {
dev_err(dev, "failed to enable regulators\n");
return ret;
}
/*
* The datasheet refers to t_OPR that needs to be waited before sending
* I2C commands after power-up.
*/
usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100);
ret = dw9768_init(dw9768);
if (ret < 0)
goto disable_regulator;
return 0;
disable_regulator:
regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies);
return ret;
}
static int dw9768_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct dw9768 *dw9768 = container_of(ctrl->handler,
struct dw9768, ctrls);
if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE)
return dw9768_set_dac(dw9768, ctrl->val);
return 0;
}
static const struct v4l2_ctrl_ops dw9768_ctrl_ops = {
.s_ctrl = dw9768_set_ctrl,
};
static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
int ret;
ret = pm_runtime_get_sync(sd->dev);
if (ret < 0) {
pm_runtime_put_noidle(sd->dev);
return ret;
}
return 0;
}
static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
pm_runtime_put(sd->dev);
return 0;
}
static const struct v4l2_subdev_internal_ops dw9768_int_ops = {
.open = dw9768_open,
.close = dw9768_close,
};
static const struct v4l2_subdev_ops dw9768_ops = { };
static int dw9768_init_controls(struct dw9768 *dw9768)
{
struct v4l2_ctrl_handler *hdl = &dw9768->ctrls;
const struct v4l2_ctrl_ops *ops = &dw9768_ctrl_ops;
v4l2_ctrl_handler_init(hdl, 1);
dw9768->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, 0,
DW9768_MAX_FOCUS_POS,
DW9768_FOCUS_STEPS, 0);
if (hdl->error)
return hdl->error;
dw9768->sd.ctrl_handler = hdl;
return 0;
}
static int dw9768_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct dw9768 *dw9768;
unsigned int i;
int ret;
dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL);
if (!dw9768)
return -ENOMEM;
/* Initialize subdev */
v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops);
dw9768->aac_mode = DW9768_AAC_MODE_DEFAULT;
dw9768->aac_timing = DW9768_AAC_TIME_DEFAULT;
dw9768->clock_presc = DW9768_CLOCK_PRE_SCALE_DEFAULT;
/* Optional indication of AAC mode select */
fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode",
&dw9768->aac_mode);
/* Optional indication of clock pre-scale select */
fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,clock-presc",
&dw9768->clock_presc);
/* Optional indication of AAC Timing */
fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing",
&dw9768->aac_timing);
dw9768->move_delay_us = dw9768_cal_move_delay(dw9768->aac_mode,
dw9768->clock_presc,
dw9768->aac_timing);
for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++)
dw9768->supplies[i].supply = dw9768_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies);
if (ret) {
dev_err(dev, "failed to get regulators\n");
return ret;
}
/* Initialize controls */
ret = dw9768_init_controls(dw9768);
if (ret)
goto err_free_handler;
/* Initialize subdev */
dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
dw9768->sd.internal_ops = &dw9768_int_ops;
ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL);
if (ret < 0)
goto err_free_handler;
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = dw9768_runtime_resume(dev);
if (ret < 0) {
dev_err(dev, "failed to power on: %d\n", ret);
goto err_clean_entity;
}
}
ret = v4l2_async_register_subdev(&dw9768->sd);
if (ret < 0) {
dev_err(dev, "failed to register V4L2 subdev: %d", ret);
goto err_power_off;
}
return 0;
err_power_off:
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
dw9768_runtime_suspend(dev);
err_clean_entity:
media_entity_cleanup(&dw9768->sd.entity);
err_free_handler:
v4l2_ctrl_handler_free(&dw9768->ctrls);
return ret;
}
static int dw9768_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct dw9768 *dw9768 = sd_to_dw9768(sd);
v4l2_async_unregister_subdev(&dw9768->sd);
v4l2_ctrl_handler_free(&dw9768->ctrls);
media_entity_cleanup(&dw9768->sd.entity);
pm_runtime_disable(&client->dev);
if (!pm_runtime_status_suspended(&client->dev))
dw9768_runtime_suspend(&client->dev);
pm_runtime_set_suspended(&client->dev);
return 0;
}
static const struct of_device_id dw9768_of_table[] = {
{ .compatible = "dongwoon,dw9768" },
{ .compatible = "giantec,gt9769" },
{}
};
MODULE_DEVICE_TABLE(of, dw9768_of_table);
static const struct dev_pm_ops dw9768_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(dw9768_runtime_suspend, dw9768_runtime_resume, NULL)
};
static struct i2c_driver dw9768_i2c_driver = {
.driver = {
.name = DW9768_NAME,
.pm = &dw9768_pm_ops,
.of_match_table = dw9768_of_table,
},
.probe_new = dw9768_probe,
.remove = dw9768_remove,
};
module_i2c_driver(dw9768_i2c_driver);
MODULE_AUTHOR("Dongchun Zhu <dongchun.zhu@mediatek.com>");
MODULE_DESCRIPTION("DW9768 VCM driver");
MODULE_LICENSE("GPL v2");

View File

@ -25,9 +25,19 @@
#define IMX290_STANDBY 0x3000
#define IMX290_REGHOLD 0x3001
#define IMX290_XMSTA 0x3002
#define IMX290_FR_FDG_SEL 0x3009
#define IMX290_BLKLEVEL_LOW 0x300a
#define IMX290_BLKLEVEL_HIGH 0x300b
#define IMX290_GAIN 0x3014
#define IMX290_HMAX_LOW 0x301c
#define IMX290_HMAX_HIGH 0x301d
#define IMX290_PGCTRL 0x308c
#define IMX290_PHY_LANE_NUM 0x3407
#define IMX290_CSI_LANE_MODE 0x3443
#define IMX290_DEFAULT_LINK_FREQ 445500000
#define IMX290_PGCTRL_REGEN BIT(0)
#define IMX290_PGCTRL_THRU BIT(1)
#define IMX290_PGCTRL_MODE(n) ((n) << 4)
static const char * const imx290_supply_name[] = {
"vdda",
@ -45,8 +55,8 @@ struct imx290_regval {
struct imx290_mode {
u32 width;
u32 height;
u32 pixel_rate;
u32 link_freq_index;
u32 hmax;
u8 link_freq_index;
const struct imx290_regval *data;
u32 data_size;
@ -56,9 +66,10 @@ struct imx290 {
struct device *dev;
struct clk *xclk;
struct regmap *regmap;
u8 nlanes;
u8 bpp;
struct v4l2_subdev sd;
struct v4l2_fwnode_endpoint ep;
struct media_pad pad;
struct v4l2_mbus_framefmt current_format;
const struct imx290_mode *current_mode;
@ -75,10 +86,12 @@ struct imx290 {
struct imx290_pixfmt {
u32 code;
u8 bpp;
};
static const struct imx290_pixfmt imx290_formats[] = {
{ MEDIA_BUS_FMT_SRGGB10_1X10 },
{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
};
static const struct regmap_config imx290_regmap_config = {
@ -87,16 +100,24 @@ static const struct regmap_config imx290_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
static const char * const imx290_test_pattern_menu[] = {
"Disabled",
"Sequence Pattern 1",
"Horizontal Color-bar Chart",
"Vertical Color-bar Chart",
"Sequence Pattern 2",
"Gradation Pattern 1",
"Gradation Pattern 2",
"000/555h Toggle Pattern",
};
static const struct imx290_regval imx290_global_init_settings[] = {
{ 0x3007, 0x00 },
{ 0x3009, 0x00 },
{ 0x3018, 0x65 },
{ 0x3019, 0x04 },
{ 0x301a, 0x00 },
{ 0x3443, 0x03 },
{ 0x3444, 0x20 },
{ 0x3445, 0x25 },
{ 0x3407, 0x03 },
{ 0x303a, 0x0c },
{ 0x3040, 0x00 },
{ 0x3041, 0x00 },
@ -169,7 +190,6 @@ static const struct imx290_regval imx290_1080p_settings[] = {
{ 0x3164, 0x1a },
{ 0x3480, 0x49 },
/* data rate settings */
{ 0x3009, 0x01 },
{ 0x3405, 0x10 },
{ 0x3446, 0x57 },
{ 0x3447, 0x00 },
@ -187,8 +207,6 @@ static const struct imx290_regval imx290_1080p_settings[] = {
{ 0x3453, 0x00 },
{ 0x3454, 0x17 },
{ 0x3455, 0x00 },
{ 0x301c, 0x98 },
{ 0x301d, 0x08 },
};
static const struct imx290_regval imx290_720p_settings[] = {
@ -210,7 +228,6 @@ static const struct imx290_regval imx290_720p_settings[] = {
{ 0x3164, 0x1a },
{ 0x3480, 0x49 },
/* data rate settings */
{ 0x3009, 0x01 },
{ 0x3405, 0x10 },
{ 0x3446, 0x4f },
{ 0x3447, 0x00 },
@ -228,8 +245,6 @@ static const struct imx290_regval imx290_720p_settings[] = {
{ 0x3453, 0x00 },
{ 0x3454, 0x17 },
{ 0x3455, 0x00 },
{ 0x301c, 0xe4 },
{ 0x301d, 0x0c },
};
static const struct imx290_regval imx290_10bit_settings[] = {
@ -244,31 +259,105 @@ static const struct imx290_regval imx290_10bit_settings[] = {
{ 0x300b, 0x00},
};
/* supported link frequencies */
static const s64 imx290_link_freq[] = {
IMX290_DEFAULT_LINK_FREQ,
static const struct imx290_regval imx290_12bit_settings[] = {
{ 0x3005, 0x01 },
{ 0x3046, 0x01 },
{ 0x3129, 0x00 },
{ 0x317c, 0x00 },
{ 0x31ec, 0x0e },
{ 0x3441, 0x0c },
{ 0x3442, 0x0c },
{ 0x300a, 0xf0 },
{ 0x300b, 0x00 },
};
/* supported link frequencies */
#define FREQ_INDEX_1080P 0
#define FREQ_INDEX_720P 1
static const s64 imx290_link_freq_2lanes[] = {
[FREQ_INDEX_1080P] = 445500000,
[FREQ_INDEX_720P] = 297000000,
};
static const s64 imx290_link_freq_4lanes[] = {
[FREQ_INDEX_1080P] = 222750000,
[FREQ_INDEX_720P] = 148500000,
};
/*
* In this function and in the similar ones below We rely on imx290_probe()
* to ensure that nlanes is either 2 or 4.
*/
static inline const s64 *imx290_link_freqs_ptr(const struct imx290 *imx290)
{
if (imx290->nlanes == 2)
return imx290_link_freq_2lanes;
else
return imx290_link_freq_4lanes;
}
static inline int imx290_link_freqs_num(const struct imx290 *imx290)
{
if (imx290->nlanes == 2)
return ARRAY_SIZE(imx290_link_freq_2lanes);
else
return ARRAY_SIZE(imx290_link_freq_4lanes);
}
/* Mode configs */
static const struct imx290_mode imx290_modes[] = {
static const struct imx290_mode imx290_modes_2lanes[] = {
{
.width = 1920,
.height = 1080,
.hmax = 0x1130,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
.pixel_rate = 178200000,
.link_freq_index = 0,
},
{
.width = 1280,
.height = 720,
.hmax = 0x19c8,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
.pixel_rate = 178200000,
.link_freq_index = 0,
},
};
static const struct imx290_mode imx290_modes_4lanes[] = {
{
.width = 1920,
.height = 1080,
.hmax = 0x0898,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
},
{
.width = 1280,
.height = 720,
.hmax = 0x0ce4,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
},
};
static inline const struct imx290_mode *imx290_modes_ptr(const struct imx290 *imx290)
{
if (imx290->nlanes == 2)
return imx290_modes_2lanes;
else
return imx290_modes_4lanes;
}
static inline int imx290_modes_num(const struct imx290 *imx290)
{
if (imx290->nlanes == 2)
return ARRAY_SIZE(imx290_modes_2lanes);
else
return ARRAY_SIZE(imx290_modes_4lanes);
}
static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
{
return container_of(_sd, struct imx290, sd);
@ -314,11 +403,11 @@ static int imx290_set_register_array(struct imx290 *imx290,
ret = imx290_write_reg(imx290, settings->reg, settings->val);
if (ret < 0)
return ret;
/* Settle time is 10ms for all registers */
msleep(10);
}
/* Provide 10ms settle time */
usleep_range(10000, 11000);
return 0;
}
@ -391,6 +480,27 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_GAIN:
ret = imx290_set_gain(imx290, ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00);
usleep_range(10000, 11000);
imx290_write_reg(imx290, IMX290_PGCTRL,
(u8)(IMX290_PGCTRL_REGEN |
IMX290_PGCTRL_THRU |
IMX290_PGCTRL_MODE(ctrl->val)));
} else {
imx290_write_reg(imx290, IMX290_PGCTRL, 0x00);
usleep_range(10000, 11000);
if (imx290->bpp == 10)
imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW,
0x3c);
else /* 12 bits per pixel */
imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW,
0xf0);
imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00);
}
break;
default:
ret = -EINVAL;
break;
@ -417,6 +527,28 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
static int imx290_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
if ((fse->code != imx290_formats[0].code) &&
(fse->code != imx290_formats[1].code))
return -EINVAL;
if (fse->index >= imx290_modes_num(imx290))
return -EINVAL;
fse->min_width = imx290_modes[fse->index].width;
fse->max_width = imx290_modes[fse->index].width;
fse->min_height = imx290_modes[fse->index].height;
fse->max_height = imx290_modes[fse->index].height;
return 0;
}
static int imx290_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
@ -439,6 +571,30 @@ static int imx290_get_fmt(struct v4l2_subdev *sd,
return 0;
}
static inline u8 imx290_get_link_freq_index(struct imx290 *imx290)
{
return imx290->current_mode->link_freq_index;
}
static s64 imx290_get_link_freq(struct imx290 *imx290)
{
u8 index = imx290_get_link_freq_index(imx290);
return *(imx290_link_freqs_ptr(imx290) + index);
}
static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
{
s64 link_freq = imx290_get_link_freq(imx290);
u8 nlanes = imx290->nlanes;
u64 pixel_rate;
/* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
pixel_rate = link_freq * 2 * nlanes;
do_div(pixel_rate, imx290->bpp);
return pixel_rate;
}
static int imx290_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
@ -450,9 +606,8 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&imx290->lock);
mode = v4l2_find_nearest_size(imx290_modes,
ARRAY_SIZE(imx290_modes),
width, height,
mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290),
imx290_modes_num(imx290), width, height,
fmt->format.width, fmt->format.height);
fmt->format.width = mode->width;
@ -472,10 +627,15 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
} else {
format = &imx290->current_format;
__v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index);
__v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, mode->pixel_rate);
imx290->current_mode = mode;
imx290->bpp = imx290_formats[i].bpp;
if (imx290->link_freq)
__v4l2_ctrl_s_ctrl(imx290->link_freq,
imx290_get_link_freq_index(imx290));
if (imx290->pixel_rate)
__v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
imx290_calc_pixel_rate(imx290));
}
*format = fmt->format;
@ -499,12 +659,11 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
return 0;
}
static int imx290_write_current_format(struct imx290 *imx290,
struct v4l2_mbus_framefmt *format)
static int imx290_write_current_format(struct imx290 *imx290)
{
int ret;
switch (format->code) {
switch (imx290->current_format.code) {
case MEDIA_BUS_FMT_SRGGB10_1X10:
ret = imx290_set_register_array(imx290, imx290_10bit_settings,
ARRAY_SIZE(
@ -514,6 +673,15 @@ static int imx290_write_current_format(struct imx290 *imx290,
return ret;
}
break;
case MEDIA_BUS_FMT_SRGGB12_1X12:
ret = imx290_set_register_array(imx290, imx290_12bit_settings,
ARRAY_SIZE(
imx290_12bit_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set format registers\n");
return ret;
}
break;
default:
dev_err(imx290->dev, "Unknown pixel format\n");
return -EINVAL;
@ -522,6 +690,25 @@ static int imx290_write_current_format(struct imx290 *imx290,
return 0;
}
static int imx290_set_hmax(struct imx290 *imx290, u32 val)
{
int ret;
ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff));
if (ret) {
dev_err(imx290->dev, "Error setting HMAX register\n");
return ret;
}
ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff));
if (ret) {
dev_err(imx290->dev, "Error setting HMAX register\n");
return ret;
}
return 0;
}
/* Start streaming */
static int imx290_start_streaming(struct imx290 *imx290)
{
@ -536,8 +723,8 @@ static int imx290_start_streaming(struct imx290 *imx290)
return ret;
}
/* Set current frame format */
ret = imx290_write_current_format(imx290, &imx290->current_format);
/* Apply the register values related to current frame format */
ret = imx290_write_current_format(imx290);
if (ret < 0) {
dev_err(imx290->dev, "Could not set frame format\n");
return ret;
@ -550,6 +737,9 @@ static int imx290_start_streaming(struct imx290 *imx290)
dev_err(imx290->dev, "Could not set current mode\n");
return ret;
}
ret = imx290_set_hmax(imx290, imx290->current_mode->hmax);
if (ret < 0)
return ret;
/* Apply customized values from user */
ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
@ -607,6 +797,49 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
imx290->supplies);
}
static int imx290_set_data_lanes(struct imx290 *imx290)
{
int ret = 0, laneval, frsel;
switch (imx290->nlanes) {
case 2:
laneval = 0x01;
frsel = 0x02;
break;
case 4:
laneval = 0x03;
frsel = 0x01;
break;
default:
/*
* We should never hit this since the data lane count is
* validated in probe itself
*/
dev_err(imx290->dev, "Lane configuration not supported\n");
ret = -EINVAL;
goto exit;
}
ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval);
if (ret) {
dev_err(imx290->dev, "Error setting Physical Lane number register\n");
goto exit;
}
ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval);
if (ret) {
dev_err(imx290->dev, "Error setting CSI Lane mode register\n");
goto exit;
}
ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel);
if (ret)
dev_err(imx290->dev, "Error setting FR/FDG SEL register\n");
exit:
return ret;
}
static int imx290_power_on(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@ -628,9 +861,12 @@ static int imx290_power_on(struct device *dev)
}
usleep_range(1, 2);
gpiod_set_value_cansleep(imx290->rst_gpio, 1);
gpiod_set_value_cansleep(imx290->rst_gpio, 0);
usleep_range(30000, 31000);
/* Set data lane count */
imx290_set_data_lanes(imx290);
return 0;
}
@ -641,14 +877,14 @@ static int imx290_power_off(struct device *dev)
struct imx290 *imx290 = to_imx290(sd);
clk_disable_unprepare(imx290->xclk);
gpiod_set_value_cansleep(imx290->rst_gpio, 0);
gpiod_set_value_cansleep(imx290->rst_gpio, 1);
regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies);
return 0;
}
static const struct dev_pm_ops imx290_pm_ops = {
SET_RUNTIME_PM_OPS(imx290_power_on, imx290_power_off, NULL)
SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL)
};
static const struct v4l2_subdev_video_ops imx290_video_ops = {
@ -658,6 +894,7 @@ static const struct v4l2_subdev_video_ops imx290_video_ops = {
static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
.init_cfg = imx290_entity_init_cfg,
.enum_mbus_code = imx290_enum_mbus_code,
.enum_frame_size = imx290_enum_frame_size,
.get_fmt = imx290_get_fmt,
.set_fmt = imx290_set_fmt,
};
@ -671,12 +908,39 @@ static const struct media_entity_operations imx290_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
/*
* Returns 0 if all link frequencies used by the driver for the given number
* of MIPI data lanes are mentioned in the device tree, or the value of the
* first missing frequency otherwise.
*/
static s64 imx290_check_link_freqs(const struct imx290 *imx290,
const struct v4l2_fwnode_endpoint *ep)
{
int i, j;
const s64 *freqs = imx290_link_freqs_ptr(imx290);
int freqs_count = imx290_link_freqs_num(imx290);
for (i = 0; i < freqs_count; i++) {
for (j = 0; j < ep->nr_of_link_frequencies; j++)
if (freqs[i] == ep->link_frequencies[j])
break;
if (j == ep->nr_of_link_frequencies)
return freqs[i];
}
return 0;
}
static int imx290_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct fwnode_handle *endpoint;
/* Only CSI2 is supported for now: */
struct v4l2_fwnode_endpoint ep = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
struct imx290 *imx290;
u32 xclk_freq;
s64 fq;
int ret;
imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL);
@ -696,35 +960,40 @@ static int imx290_probe(struct i2c_client *client)
return -EINVAL;
}
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &imx290->ep);
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
fwnode_handle_put(endpoint);
if (ret) {
if (ret == -ENXIO) {
dev_err(dev, "Unsupported bus type, should be CSI2\n");
goto free_err;
} else if (ret) {
dev_err(dev, "Parsing endpoint node failed\n");
goto free_err;
}
if (!imx290->ep.nr_of_link_frequencies) {
/* Get number of data lanes */
imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes;
if (imx290->nlanes != 2 && imx290->nlanes != 4) {
dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes);
ret = -EINVAL;
goto free_err;
}
dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
if (!ep.nr_of_link_frequencies) {
dev_err(dev, "link-frequency property not found in DT\n");
ret = -EINVAL;
goto free_err;
}
if (imx290->ep.link_frequencies[0] != IMX290_DEFAULT_LINK_FREQ) {
dev_err(dev, "Unsupported link frequency\n");
/* Check that link frequences for all the modes are in device tree */
fq = imx290_check_link_freqs(imx290, &ep);
if (fq) {
dev_err(dev, "Link frequency of %lld is not supported\n", fq);
ret = -EINVAL;
goto free_err;
}
/* Only CSI2 is supported for now */
if (imx290->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "Unsupported bus type, should be CSI2\n");
ret = -EINVAL;
goto free_err;
}
/* Set default mode to max resolution */
imx290->current_mode = &imx290_modes[0];
/* get system clock (xclk) */
imx290->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(imx290->xclk)) {
@ -760,7 +1029,8 @@ static int imx290_probe(struct i2c_client *client)
goto free_err;
}
imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(imx290->rst_gpio)) {
dev_err(dev, "Cannot get reset gpio\n");
ret = PTR_ERR(imx290->rst_gpio);
@ -769,23 +1039,35 @@ static int imx290_probe(struct i2c_client *client)
mutex_init(&imx290->lock);
v4l2_ctrl_handler_init(&imx290->ctrls, 3);
/*
* Initialize the frame format. In particular, imx290->current_mode
* and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call
* below relies on these fields.
*/
imx290_entity_init_cfg(&imx290->sd, NULL);
v4l2_ctrl_handler_init(&imx290->ctrls, 4);
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_GAIN, 0, 72, 1, 0);
imx290->link_freq =
v4l2_ctrl_new_int_menu(&imx290->ctrls,
&imx290_ctrl_ops,
v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx290_link_freq) - 1,
0, imx290_link_freq);
imx290_link_freqs_num(imx290) - 1, 0,
imx290_link_freqs_ptr(imx290));
if (imx290->link_freq)
imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_PIXEL_RATE, 1,
INT_MAX, 1,
imx290_modes[0].pixel_rate);
V4L2_CID_PIXEL_RATE,
1, INT_MAX, 1,
imx290_calc_pixel_rate(imx290));
v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx290_test_pattern_menu) - 1,
0, 0, imx290_test_pattern_menu);
imx290->sd.ctrl_handler = &imx290->ctrls;
@ -826,7 +1108,7 @@ static int imx290_probe(struct i2c_client *client)
pm_runtime_enable(dev);
pm_runtime_idle(dev);
v4l2_fwnode_endpoint_free(&imx290->ep);
v4l2_fwnode_endpoint_free(&ep);
return 0;
@ -836,7 +1118,7 @@ free_ctrl:
v4l2_ctrl_handler_free(&imx290->ctrls);
mutex_destroy(&imx290->lock);
free_err:
v4l2_fwnode_endpoint_free(&imx290->ep);
v4l2_fwnode_endpoint_free(&ep);
return ret;
}

341
drivers/media/i2c/max9271.c Normal file
View File

@ -0,0 +1,341 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017-2020 Jacopo Mondi
* Copyright (C) 2017-2020 Kieran Bingham
* Copyright (C) 2017-2020 Laurent Pinchart
* Copyright (C) 2017-2020 Niklas Söderlund
* Copyright (C) 2016 Renesas Electronics Corporation
* Copyright (C) 2015 Cogent Embedded, Inc.
*
* This file exports functions to control the Maxim MAX9271 GMSL serializer
* chip. This is not a self-contained driver, as MAX9271 is usually embedded in
* camera modules with at least one image sensor and optional additional
* components, such as uController units or ISPs/DSPs.
*
* Drivers for the camera modules (i.e. rdacm20/21) are expected to use
* functions exported from this library driver to maximize code re-use.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include "max9271.h"
static int max9271_read(struct max9271_device *dev, u8 reg)
{
int ret;
dev_dbg(&dev->client->dev, "%s(0x%02x)\n", __func__, reg);
ret = i2c_smbus_read_byte_data(dev->client, reg);
if (ret < 0)
dev_dbg(&dev->client->dev,
"%s: register 0x%02x read failed (%d)\n",
__func__, reg, ret);
return ret;
}
static int max9271_write(struct max9271_device *dev, u8 reg, u8 val)
{
int ret;
dev_dbg(&dev->client->dev, "%s(0x%02x, 0x%02x)\n", __func__, reg, val);
ret = i2c_smbus_write_byte_data(dev->client, reg, val);
if (ret < 0)
dev_err(&dev->client->dev,
"%s: register 0x%02x write failed (%d)\n",
__func__, reg, ret);
return ret;
}
/*
* max9271_pclk_detect() - Detect valid pixel clock from image sensor
*
* Wait up to 10ms for a valid pixel clock.
*
* Returns 0 for success, < 0 for pixel clock not properly detected
*/
static int max9271_pclk_detect(struct max9271_device *dev)
{
unsigned int i;
int ret;
for (i = 0; i < 100; i++) {
ret = max9271_read(dev, 0x15);
if (ret < 0)
return ret;
if (ret & MAX9271_PCLKDET)
return 0;
usleep_range(50, 100);
}
dev_err(&dev->client->dev, "Unable to detect valid pixel clock\n");
return -EIO;
}
int max9271_set_serial_link(struct max9271_device *dev, bool enable)
{
int ret;
u8 val = MAX9271_REVCCEN | MAX9271_FWDCCEN;
if (enable) {
ret = max9271_pclk_detect(dev);
if (ret)
return ret;
val |= MAX9271_SEREN;
} else {
val |= MAX9271_CLINKEN;
}
/*
* The serializer temporarily disables the reverse control channel for
* 350µs after starting/stopping the forward serial link, but the
* deserializer synchronization time isn't clearly documented.
*
* According to the serializer datasheet we should wait 3ms, while
* according to the deserializer datasheet we should wait 5ms.
*
* Short delays here appear to show bit-errors in the writes following.
* Therefore a conservative delay seems best here.
*/
max9271_write(dev, 0x04, val);
usleep_range(5000, 8000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_serial_link);
int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
{
int ret;
ret = max9271_write(dev, 0x0d, i2c_config);
if (ret)
return ret;
/* The delay required after an I2C bus configuration change is not
* characterized in the serializer manual. Sleep up to 5msec to
* stay safe.
*/
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_configure_i2c);
int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
{
int ret;
ret = max9271_read(dev, 0x08);
if (ret < 0)
return ret;
/*
* Enable or disable reverse channel high threshold to increase
* immunity to power supply noise.
*/
max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
usleep_range(2000, 2500);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
int max9271_configure_gmsl_link(struct max9271_device *dev)
{
/*
* Configure the GMSL link:
*
* - Double input mode, high data rate, 24-bit mode
* - Latch input data on PCLKIN rising edge
* - Enable HS/VS encoding
* - 1-bit parity error detection
*
* TODO: Make the GMSL link configuration parametric.
*/
max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
MAX9271_EDC_1BIT_PARITY);
usleep_range(5000, 8000);
/*
* Adjust spread spectrum to +4% and auto-detect pixel clock
* and serial link rate.
*/
max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
usleep_range(5000, 8000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_configure_gmsl_link);
int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask)
{
int ret;
ret = max9271_read(dev, 0x0f);
if (ret < 0)
return 0;
ret |= gpio_mask;
ret = max9271_write(dev, 0x0f, ret);
if (ret < 0) {
dev_err(&dev->client->dev, "Failed to set gpio (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_gpios);
int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask)
{
int ret;
ret = max9271_read(dev, 0x0f);
if (ret < 0)
return 0;
ret &= ~gpio_mask;
ret = max9271_write(dev, 0x0f, ret);
if (ret < 0) {
dev_err(&dev->client->dev, "Failed to clear gpio (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_clear_gpios);
int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask)
{
int ret;
ret = max9271_read(dev, 0x0f);
if (ret < 0)
return 0;
/* BIT(0) reserved: GPO is always enabled. */
ret |= gpio_mask | BIT(0);
ret = max9271_write(dev, 0x0e, ret);
if (ret < 0) {
dev_err(&dev->client->dev, "Failed to enable gpio (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_enable_gpios);
int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask)
{
int ret;
ret = max9271_read(dev, 0x0f);
if (ret < 0)
return 0;
/* BIT(0) reserved: GPO cannot be disabled */
ret &= (~gpio_mask | BIT(0));
ret = max9271_write(dev, 0x0e, ret);
if (ret < 0) {
dev_err(&dev->client->dev, "Failed to disable gpio (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_disable_gpios);
int max9271_verify_id(struct max9271_device *dev)
{
int ret;
ret = max9271_read(dev, 0x1e);
if (ret < 0) {
dev_err(&dev->client->dev, "MAX9271 ID read failed (%d)\n",
ret);
return ret;
}
if (ret != MAX9271_ID) {
dev_err(&dev->client->dev, "MAX9271 ID mismatch (0x%02x)\n",
ret);
return -ENXIO;
}
return 0;
}
EXPORT_SYMBOL_GPL(max9271_verify_id);
int max9271_set_address(struct max9271_device *dev, u8 addr)
{
int ret;
ret = max9271_write(dev, 0x00, addr << 1);
if (ret < 0) {
dev_err(&dev->client->dev,
"MAX9271 I2C address change failed (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_address);
int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr)
{
int ret;
ret = max9271_write(dev, 0x01, addr << 1);
if (ret < 0) {
dev_err(&dev->client->dev,
"MAX9271 deserializer address set failed (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_deserializer_address);
int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest)
{
int ret;
ret = max9271_write(dev, 0x09, source << 1);
if (ret < 0) {
dev_err(&dev->client->dev,
"MAX9271 I2C translation setup failed (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
ret = max9271_write(dev, 0x0a, dest << 1);
if (ret < 0) {
dev_err(&dev->client->dev,
"MAX9271 I2C translation setup failed (%d)\n", ret);
return ret;
}
usleep_range(3500, 5000);
return 0;
}
EXPORT_SYMBOL_GPL(max9271_set_translation);

224
drivers/media/i2c/max9271.h Normal file
View File

@ -0,0 +1,224 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2017-2020 Jacopo Mondi
* Copyright (C) 2017-2020 Kieran Bingham
* Copyright (C) 2017-2020 Laurent Pinchart
* Copyright (C) 2017-2020 Niklas Söderlund
* Copyright (C) 2016 Renesas Electronics Corporation
* Copyright (C) 2015 Cogent Embedded, Inc.
*/
#include <linux/i2c.h>
#define MAX9271_DEFAULT_ADDR 0x40
/* Register 0x02 */
#define MAX9271_SPREAD_SPECT_0 (0 << 5)
#define MAX9271_SPREAD_SPECT_05 (1 << 5)
#define MAX9271_SPREAD_SPECT_15 (2 << 5)
#define MAX9271_SPREAD_SPECT_1 (5 << 5)
#define MAX9271_SPREAD_SPECT_2 (3 << 5)
#define MAX9271_SPREAD_SPECT_3 (6 << 5)
#define MAX9271_SPREAD_SPECT_4 (7 << 5)
#define MAX9271_R02_RES BIT(4)
#define MAX9271_PCLK_AUTODETECT (3 << 2)
#define MAX9271_SERIAL_AUTODETECT (0x03)
/* Register 0x04 */
#define MAX9271_SEREN BIT(7)
#define MAX9271_CLINKEN BIT(6)
#define MAX9271_PRBSEN BIT(5)
#define MAX9271_SLEEP BIT(4)
#define MAX9271_INTTYPE_I2C (0 << 2)
#define MAX9271_INTTYPE_UART (1 << 2)
#define MAX9271_INTTYPE_NONE (2 << 2)
#define MAX9271_REVCCEN BIT(1)
#define MAX9271_FWDCCEN BIT(0)
/* Register 0x07 */
#define MAX9271_DBL BIT(7)
#define MAX9271_DRS BIT(6)
#define MAX9271_BWS BIT(5)
#define MAX9271_ES BIT(4)
#define MAX9271_HVEN BIT(2)
#define MAX9271_EDC_1BIT_PARITY (0 << 0)
#define MAX9271_EDC_6BIT_CRC (1 << 0)
#define MAX9271_EDC_6BIT_HAMMING (2 << 0)
/* Register 0x08 */
#define MAX9271_INVVS BIT(7)
#define MAX9271_INVHS BIT(6)
#define MAX9271_REV_LOGAIN BIT(3)
#define MAX9271_REV_HIVTH BIT(0)
/* Register 0x09 */
#define MAX9271_ID 0x09
/* Register 0x0d */
#define MAX9271_I2CLOCACK BIT(7)
#define MAX9271_I2CSLVSH_1046NS_469NS (3 << 5)
#define MAX9271_I2CSLVSH_938NS_352NS (2 << 5)
#define MAX9271_I2CSLVSH_469NS_234NS (1 << 5)
#define MAX9271_I2CSLVSH_352NS_117NS (0 << 5)
#define MAX9271_I2CMSTBT_837KBPS (7 << 2)
#define MAX9271_I2CMSTBT_533KBPS (6 << 2)
#define MAX9271_I2CMSTBT_339KBPS (5 << 2)
#define MAX9271_I2CMSTBT_173KBPS (4 << 2)
#define MAX9271_I2CMSTBT_105KBPS (3 << 2)
#define MAX9271_I2CMSTBT_84KBPS (2 << 2)
#define MAX9271_I2CMSTBT_28KBPS (1 << 2)
#define MAX9271_I2CMSTBT_8KBPS (0 << 2)
#define MAX9271_I2CSLVTO_NONE (3 << 0)
#define MAX9271_I2CSLVTO_1024US (2 << 0)
#define MAX9271_I2CSLVTO_256US (1 << 0)
#define MAX9271_I2CSLVTO_64US (0 << 0)
/* Register 0x0f */
#define MAX9271_GPIO5OUT BIT(5)
#define MAX9271_GPIO4OUT BIT(4)
#define MAX9271_GPIO3OUT BIT(3)
#define MAX9271_GPIO2OUT BIT(2)
#define MAX9271_GPIO1OUT BIT(1)
#define MAX9271_GPO BIT(0)
/* Register 0x15 */
#define MAX9271_PCLKDET BIT(0)
/**
* struct max9271_device - max9271 device
* @client: The i2c client for the max9271 instance
*/
struct max9271_device {
struct i2c_client *client;
};
/**
* max9271_set_serial_link() - Enable/disable serial link
* @dev: The max9271 device
* @enable: Serial link enable/disable flag
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_serial_link(struct max9271_device *dev, bool enable);
/**
* max9271_configure_i2c() - Configure I2C bus parameters
* @dev: The max9271 device
* @i2c_config: The I2C bus configuration bit mask
*
* Configure MAX9271 I2C interface. The bus configuration provided in the
* @i2c_config parameter shall be assembled using bit values defined by the
* MAX9271_I2C* macros.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config);
/**
* max9271_set_high_threshold() - Enable or disable reverse channel high
* threshold
* @dev: The max9271 device
* @enable: High threshold enable/disable flag
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_high_threshold(struct max9271_device *dev, bool enable);
/**
* max9271_configure_gmsl_link() - Configure the GMSL link
* @dev: The max9271 device
*
* FIXME: the GMSL link configuration is currently hardcoded and performed
* by programming registers 0x04, 0x07 and 0x02.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_configure_gmsl_link(struct max9271_device *dev);
/**
* max9271_set_gpios() - Set gpio lines to physical high value
* @dev: The max9271 device
* @gpio_mask: The mask of gpio lines to set to high value
*
* The @gpio_mask parameter shall be assembled using the MAX9271_GP[IO|O]*
* bit values.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask);
/**
* max9271_clear_gpios() - Set gpio lines to physical low value
* @dev: The max9271 device
* @gpio_mask: The mask of gpio lines to set to low value
*
* The @gpio_mask parameter shall be assembled using the MAX9271_GP[IO|O]*
* bit values.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask);
/**
* max9271_enable_gpios() - Enable gpio lines
* @dev: The max9271 device
* @gpio_mask: The mask of gpio lines to enable
*
* The @gpio_mask parameter shall be assembled using the MAX9271_GPIO*
* bit values. GPO line is always enabled by default.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask);
/**
* max9271_disable_gpios() - Disable gpio lines
* @dev: The max9271 device
* @gpio_mask: The mask of gpio lines to disable
*
* The @gpio_mask parameter shall be assembled using the MAX9271_GPIO*
* bit values. GPO line is always enabled by default and cannot be disabled.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask);
/**
* max9271_verify_id() - Read and verify MAX9271 id
* @dev: The max9271 device
*
* Return 0 on success or a negative error code on failure
*/
int max9271_verify_id(struct max9271_device *dev);
/**
* max9271_set_address() - Program a new I2C address
* @dev: The max9271 device
* @addr: The new I2C address in 7-bit format
*
* This function only takes care of programming the new I2C address @addr to
* in the MAX9271 chip registers, it is responsiblity of the caller to set
* the i2c address client to the @addr value to be able to communicate with
* the MAX9271 chip using the I2C framework APIs after this function returns.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_address(struct max9271_device *dev, u8 addr);
/**
* max9271_set_deserializer_address() - Program the remote deserializer address
* @dev: The max9271 device
* @addr: The deserializer I2C address in 7-bit format
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr);
/**
* max9271_set_translation() - Program I2C address translation
* @dev: The max9271 device
* @source: The I2C source address
* @dest: The I2C destination address
*
* Program address translation from @source to @dest. This is required to
* communicate with local devices that do not support address reprogramming.
*
* TODO: The device supports translation of two address, this function currently
* supports a single one.
*
* Return 0 on success or a negative error code on failure
*/
int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest);

1320
drivers/media/i2c/max9286.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,8 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@ -59,6 +61,21 @@
#define OV2740_TEST_PATTERN_ENABLE BIT(7)
#define OV2740_TEST_PATTERN_BAR_SHIFT 2
/* ISP CTRL00 */
#define OV2740_REG_ISP_CTRL00 0x5000
/* ISP CTRL01 */
#define OV2740_REG_ISP_CTRL01 0x5001
/* Customer Addresses: 0x7010 - 0x710F */
#define CUSTOMER_USE_OTP_SIZE 0x100
/* OTP registers from sensor */
#define OV2740_REG_OTP_CUSTOMER 0x7010
struct nvm_data {
char *nvm_buffer;
struct nvmem_device *nvmem;
struct regmap *regmap;
};
enum {
OV2740_LINK_FREQ_360MHZ_INDEX,
};
@ -915,6 +932,130 @@ static int ov2740_remove(struct i2c_client *client)
return 0;
}
static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm)
{
struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client));
u32 isp_ctrl00 = 0;
u32 isp_ctrl01 = 0;
int ret;
ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00);
if (ret) {
dev_err(&client->dev, "failed to read ISP CTRL00\n");
goto exit;
}
ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01);
if (ret) {
dev_err(&client->dev, "failed to read ISP CTRL01\n");
goto exit;
}
/* Clear bit 5 of ISP CTRL00 */
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1,
isp_ctrl00 & ~BIT(5));
if (ret) {
dev_err(&client->dev, "failed to write ISP CTRL00\n");
goto exit;
}
/* Clear bit 7 of ISP CTRL01 */
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1,
isp_ctrl01 & ~BIT(7));
if (ret) {
dev_err(&client->dev, "failed to write ISP CTRL01\n");
goto exit;
}
ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STREAMING);
if (ret) {
dev_err(&client->dev, "failed to start streaming\n");
goto exit;
}
/*
* Users are not allowed to access OTP-related registers and memory
* during the 20 ms period after streaming starts (0x100 = 0x01).
*/
msleep(20);
ret = regmap_bulk_read(nvm->regmap, OV2740_REG_OTP_CUSTOMER,
nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE);
if (ret) {
dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret);
goto exit;
}
ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STANDBY);
ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01);
ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00);
exit:
return ret;
}
static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
size_t count)
{
struct nvm_data *nvm = priv;
memcpy(val, nvm->nvm_buffer + off, count);
return 0;
}
static int ov2740_register_nvmem(struct i2c_client *client)
{
struct nvm_data *nvm;
struct regmap_config regmap_config = { };
struct nvmem_config nvmem_config = { };
struct regmap *regmap;
struct device *dev = &client->dev;
int ret = 0;
nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL);
if (!nvm)
return -ENOMEM;
regmap_config.val_bits = 8;
regmap_config.reg_bits = 16;
regmap_config.disable_locking = true;
regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
nvm->regmap = regmap;
nvmem_config.name = dev_name(dev);
nvmem_config.dev = dev;
nvmem_config.read_only = true;
nvmem_config.root_only = true;
nvmem_config.owner = THIS_MODULE;
nvmem_config.compat = true;
nvmem_config.base_dev = dev;
nvmem_config.reg_read = ov2740_nvmem_read;
nvmem_config.reg_write = NULL;
nvmem_config.priv = nvm;
nvmem_config.stride = 1;
nvmem_config.word_size = 1;
nvmem_config.size = CUSTOMER_USE_OTP_SIZE;
nvm->nvmem = devm_nvmem_register(dev, &nvmem_config);
if (IS_ERR(nvm->nvmem))
return PTR_ERR(nvm->nvmem);
nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
if (!nvm->nvm_buffer)
return -ENOMEM;
ret = ov2740_load_otp_data(client, nvm);
if (ret)
dev_err(dev, "failed to load OTP data, ret %d\n", ret);
return ret;
}
static int ov2740_probe(struct i2c_client *client)
{
struct ov2740 *ov2740;
@ -964,6 +1105,10 @@ static int ov2740_probe(struct i2c_client *client)
goto probe_error_media_entity_cleanup;
}
ret = ov2740_register_nvmem(client);
if (ret)
dev_err(&client->dev, "register nvmem failed, ret %d\n", ret);
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
@ -988,20 +1133,18 @@ static const struct dev_pm_ops ov2740_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov2740_suspend, ov2740_resume)
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id ov2740_acpi_ids[] = {
{"INT3474"},
{}
};
MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids);
#endif
static struct i2c_driver ov2740_i2c_driver = {
.driver = {
.name = "ov2740",
.pm = &ov2740_pm_ops,
.acpi_match_table = ACPI_PTR(ov2740_acpi_ids),
.acpi_match_table = ov2740_acpi_ids,
},
.probe_new = ov2740_probe,
.remove = ov2740_remove,

View File

@ -772,6 +772,6 @@ static struct i2c_driver ov9640_i2c_driver = {
module_i2c_driver(ov9640_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
MODULE_DESCRIPTION("OmniVision OV96xx CMOS Image Sensor driver");
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_LICENSE("GPL v2");

667
drivers/media/i2c/rdacm20.c Normal file
View File

@ -0,0 +1,667 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* IMI RDACM20 GMSL Camera Driver
*
* Copyright (C) 2017-2020 Jacopo Mondi
* Copyright (C) 2017-2020 Kieran Bingham
* Copyright (C) 2017-2019 Laurent Pinchart
* Copyright (C) 2017-2019 Niklas Söderlund
* Copyright (C) 2016 Renesas Electronics Corporation
* Copyright (C) 2015 Cogent Embedded, Inc.
*/
/*
* The camera is made of an Omnivision OV10635 sensor connected to a Maxim
* MAX9271 GMSL serializer.
*/
#include <linux/delay.h>
#include <linux/fwnode.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include "max9271.h"
#define OV10635_I2C_ADDRESS 0x30
#define OV10635_SOFTWARE_RESET 0x0103
#define OV10635_PID 0x300a
#define OV10635_VER 0x300b
#define OV10635_SC_CMMN_SCCB_ID 0x300c
#define OV10635_SC_CMMN_SCCB_ID_SELECT BIT(0)
#define OV10635_VERSION 0xa635
#define OV10635_WIDTH 1280
#define OV10635_HEIGHT 800
/* VTS = PCLK / FPS / HTS / 2 (= 88MHz / 1572 / 30 / 2) */
#define OV10635_HTS 1572
/* FPS = 29,9998 */
#define OV10635_VTS 933
/*
* As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 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.
*
* Pixelrate = PCLK / 2
* FPS = (OV10635_VTS * OV10635_HTS) / PixelRate
* = 29,9998
*/
#define OV10635_PIXEL_RATE (44000000)
static const struct ov10635_reg {
u16 reg;
u8 val;
} ov10635_regs_wizard[] = {
{ 0x301b, 0xff }, { 0x301c, 0xff }, { 0x301a, 0xff }, { 0x3011, 0x42 },
{ 0x6900, 0x0c }, { 0x6901, 0x19 }, { 0x3503, 0x10 }, { 0x3025, 0x03 },
{ 0x3003, 0x16 }, { 0x3004, 0x30 }, { 0x3005, 0x40 }, { 0x3006, 0x91 },
{ 0x3600, 0x74 }, { 0x3601, 0x2b }, { 0x3612, 0x00 }, { 0x3611, 0x67 },
{ 0x3633, 0xca }, { 0x3602, 0xaf }, { 0x3603, 0x04 }, { 0x3630, 0x28 },
{ 0x3631, 0x16 }, { 0x3714, 0x10 }, { 0x371d, 0x01 }, { 0x4300, 0x3a },
{ 0x3007, 0x01 }, { 0x3024, 0x03 }, { 0x3020, 0x0a }, { 0x3702, 0x0d },
{ 0x3703, 0x20 }, { 0x3704, 0x15 }, { 0x3709, 0xa8 }, { 0x370c, 0xc7 },
{ 0x370d, 0x80 }, { 0x3712, 0x00 }, { 0x3713, 0x20 }, { 0x3715, 0x04 },
{ 0x381d, 0x40 }, { 0x381c, 0x00 }, { 0x3822, 0x50 }, { 0x3824, 0x10 },
{ 0x3815, 0x8c }, { 0x3804, 0x05 }, { 0x3805, 0x1f }, { 0x3800, 0x00 },
{ 0x3801, 0x00 }, { 0x3806, 0x03 }, { 0x3807, 0x28 }, { 0x3802, 0x00 },
{ 0x3803, 0x07 }, { 0x3808, 0x05 }, { 0x3809, 0x00 }, { 0x380a, 0x03 },
{ 0x380b, 0x20 }, { 0x380c, OV10635_HTS >> 8 },
{ 0x380d, OV10635_HTS & 0xff }, { 0x380e, OV10635_VTS >> 8 },
{ 0x380f, OV10635_VTS & 0xff }, { 0x3813, 0x02 }, { 0x3811, 0x08 },
{ 0x381f, 0x0c }, { 0x3819, 0x04 }, { 0x3804, 0x01 }, { 0x3805, 0x00 },
{ 0x3828, 0x03 }, { 0x3829, 0x10 }, { 0x382a, 0x10 }, { 0x3621, 0x63 },
{ 0x5005, 0x08 }, { 0x56d5, 0x00 }, { 0x56d6, 0x80 }, { 0x56d7, 0x00 },
{ 0x56d8, 0x00 }, { 0x56d9, 0x00 }, { 0x56da, 0x80 }, { 0x56db, 0x00 },
{ 0x56dc, 0x00 }, { 0x56e8, 0x00 }, { 0x56e9, 0x7f }, { 0x56ea, 0x00 },
{ 0x56eb, 0x7f }, { 0x5100, 0x00 }, { 0x5101, 0x80 }, { 0x5102, 0x00 },
{ 0x5103, 0x80 }, { 0x5104, 0x00 }, { 0x5105, 0x80 }, { 0x5106, 0x00 },
{ 0x5107, 0x80 }, { 0x5108, 0x00 }, { 0x5109, 0x00 }, { 0x510a, 0x00 },
{ 0x510b, 0x00 }, { 0x510c, 0x00 }, { 0x510d, 0x00 }, { 0x510e, 0x00 },
{ 0x510f, 0x00 }, { 0x5110, 0x00 }, { 0x5111, 0x80 }, { 0x5112, 0x00 },
{ 0x5113, 0x80 }, { 0x5114, 0x00 }, { 0x5115, 0x80 }, { 0x5116, 0x00 },
{ 0x5117, 0x80 }, { 0x5118, 0x00 }, { 0x5119, 0x00 }, { 0x511a, 0x00 },
{ 0x511b, 0x00 }, { 0x511c, 0x00 }, { 0x511d, 0x00 }, { 0x511e, 0x00 },
{ 0x511f, 0x00 }, { 0x56d0, 0x00 }, { 0x5006, 0x04 }, { 0x5608, 0x05 },
{ 0x52d7, 0x06 }, { 0x528d, 0x08 }, { 0x5293, 0x12 }, { 0x52d3, 0x12 },
{ 0x5288, 0x06 }, { 0x5289, 0x20 }, { 0x52c8, 0x06 }, { 0x52c9, 0x20 },
{ 0x52cd, 0x04 }, { 0x5381, 0x00 }, { 0x5382, 0xff }, { 0x5589, 0x76 },
{ 0x558a, 0x47 }, { 0x558b, 0xef }, { 0x558c, 0xc9 }, { 0x558d, 0x49 },
{ 0x558e, 0x30 }, { 0x558f, 0x67 }, { 0x5590, 0x3f }, { 0x5591, 0xf0 },
{ 0x5592, 0x10 }, { 0x55a2, 0x6d }, { 0x55a3, 0x55 }, { 0x55a4, 0xc3 },
{ 0x55a5, 0xb5 }, { 0x55a6, 0x43 }, { 0x55a7, 0x38 }, { 0x55a8, 0x5f },
{ 0x55a9, 0x4b }, { 0x55aa, 0xf0 }, { 0x55ab, 0x10 }, { 0x5581, 0x52 },
{ 0x5300, 0x01 }, { 0x5301, 0x00 }, { 0x5302, 0x00 }, { 0x5303, 0x0e },
{ 0x5304, 0x00 }, { 0x5305, 0x0e }, { 0x5306, 0x00 }, { 0x5307, 0x36 },
{ 0x5308, 0x00 }, { 0x5309, 0xd9 }, { 0x530a, 0x00 }, { 0x530b, 0x0f },
{ 0x530c, 0x00 }, { 0x530d, 0x2c }, { 0x530e, 0x00 }, { 0x530f, 0x59 },
{ 0x5310, 0x00 }, { 0x5311, 0x7b }, { 0x5312, 0x00 }, { 0x5313, 0x22 },
{ 0x5314, 0x00 }, { 0x5315, 0xd5 }, { 0x5316, 0x00 }, { 0x5317, 0x13 },
{ 0x5318, 0x00 }, { 0x5319, 0x18 }, { 0x531a, 0x00 }, { 0x531b, 0x26 },
{ 0x531c, 0x00 }, { 0x531d, 0xdc }, { 0x531e, 0x00 }, { 0x531f, 0x02 },
{ 0x5320, 0x00 }, { 0x5321, 0x24 }, { 0x5322, 0x00 }, { 0x5323, 0x56 },
{ 0x5324, 0x00 }, { 0x5325, 0x85 }, { 0x5326, 0x00 }, { 0x5327, 0x20 },
{ 0x5609, 0x01 }, { 0x560a, 0x40 }, { 0x560b, 0x01 }, { 0x560c, 0x40 },
{ 0x560d, 0x00 }, { 0x560e, 0xfa }, { 0x560f, 0x00 }, { 0x5610, 0xfa },
{ 0x5611, 0x02 }, { 0x5612, 0x80 }, { 0x5613, 0x02 }, { 0x5614, 0x80 },
{ 0x5615, 0x01 }, { 0x5616, 0x2c }, { 0x5617, 0x01 }, { 0x5618, 0x2c },
{ 0x563b, 0x01 }, { 0x563c, 0x01 }, { 0x563d, 0x01 }, { 0x563e, 0x01 },
{ 0x563f, 0x03 }, { 0x5640, 0x03 }, { 0x5641, 0x03 }, { 0x5642, 0x05 },
{ 0x5643, 0x09 }, { 0x5644, 0x05 }, { 0x5645, 0x05 }, { 0x5646, 0x05 },
{ 0x5647, 0x05 }, { 0x5651, 0x00 }, { 0x5652, 0x80 }, { 0x521a, 0x01 },
{ 0x521b, 0x03 }, { 0x521c, 0x06 }, { 0x521d, 0x0a }, { 0x521e, 0x0e },
{ 0x521f, 0x12 }, { 0x5220, 0x16 }, { 0x5223, 0x02 }, { 0x5225, 0x04 },
{ 0x5227, 0x08 }, { 0x5229, 0x0c }, { 0x522b, 0x12 }, { 0x522d, 0x18 },
{ 0x522f, 0x1e }, { 0x5241, 0x04 }, { 0x5242, 0x01 }, { 0x5243, 0x03 },
{ 0x5244, 0x06 }, { 0x5245, 0x0a }, { 0x5246, 0x0e }, { 0x5247, 0x12 },
{ 0x5248, 0x16 }, { 0x524a, 0x03 }, { 0x524c, 0x04 }, { 0x524e, 0x08 },
{ 0x5250, 0x0c }, { 0x5252, 0x12 }, { 0x5254, 0x18 }, { 0x5256, 0x1e },
/* fifo_line_length = 2*hts */
{ 0x4606, (2 * OV10635_HTS) >> 8 }, { 0x4607, (2 * OV10635_HTS) & 0xff },
/* fifo_hsync_start = 2*(hts - xres) */
{ 0x460a, (2 * (OV10635_HTS - OV10635_WIDTH)) >> 8 },
{ 0x460b, (2 * (OV10635_HTS - OV10635_WIDTH)) & 0xff },
{ 0x460c, 0x00 }, { 0x4620, 0x0e },
/* BT601: 0x08 is also acceptable as HS/VS mode */
{ 0x4700, 0x04 }, { 0x4701, 0x00 }, { 0x4702, 0x01 }, { 0x4004, 0x04 },
{ 0x4005, 0x18 }, { 0x4001, 0x06 }, { 0x4050, 0x22 }, { 0x4051, 0x24 },
{ 0x4052, 0x02 }, { 0x4057, 0x9c }, { 0x405a, 0x00 }, { 0x4202, 0x02 },
{ 0x3023, 0x10 }, { 0x0100, 0x01 }, { 0x0100, 0x01 }, { 0x6f10, 0x07 },
{ 0x6f11, 0x82 }, { 0x6f12, 0x04 }, { 0x6f13, 0x00 }, { 0xd000, 0x19 },
{ 0xd001, 0xa0 }, { 0xd002, 0x00 }, { 0xd003, 0x01 }, { 0xd004, 0xa9 },
{ 0xd005, 0xad }, { 0xd006, 0x10 }, { 0xd007, 0x40 }, { 0xd008, 0x44 },
{ 0xd009, 0x00 }, { 0xd00a, 0x68 }, { 0xd00b, 0x00 }, { 0xd00c, 0x15 },
{ 0xd00d, 0x00 }, { 0xd00e, 0x00 }, { 0xd00f, 0x00 }, { 0xd040, 0x9c },
{ 0xd041, 0x21 }, { 0xd042, 0xff }, { 0xd043, 0xf8 }, { 0xd044, 0xd4 },
{ 0xd045, 0x01 }, { 0xd046, 0x48 }, { 0xd047, 0x00 }, { 0xd048, 0xd4 },
{ 0xd049, 0x01 }, { 0xd04a, 0x50 }, { 0xd04b, 0x04 }, { 0xd04c, 0x18 },
{ 0xd04d, 0x60 }, { 0xd04e, 0x00 }, { 0xd04f, 0x01 }, { 0xd050, 0xa8 },
{ 0xd051, 0x63 }, { 0xd052, 0x02 }, { 0xd053, 0xa4 }, { 0xd054, 0x85 },
{ 0xd055, 0x43 }, { 0xd056, 0x00 }, { 0xd057, 0x00 }, { 0xd058, 0x18 },
{ 0xd059, 0x60 }, { 0xd05a, 0x00 }, { 0xd05b, 0x01 }, { 0xd05c, 0xa8 },
{ 0xd05d, 0x63 }, { 0xd05e, 0x03 }, { 0xd05f, 0xf0 }, { 0xd060, 0x98 },
{ 0xd061, 0xa3 }, { 0xd062, 0x00 }, { 0xd063, 0x00 }, { 0xd064, 0x8c },
{ 0xd065, 0x6a }, { 0xd066, 0x00 }, { 0xd067, 0x6e }, { 0xd068, 0xe5 },
{ 0xd069, 0x85 }, { 0xd06a, 0x18 }, { 0xd06b, 0x00 }, { 0xd06c, 0x10 },
{ 0xd06d, 0x00 }, { 0xd06e, 0x00 }, { 0xd06f, 0x10 }, { 0xd070, 0x9c },
{ 0xd071, 0x80 }, { 0xd072, 0x00 }, { 0xd073, 0x03 }, { 0xd074, 0x18 },
{ 0xd075, 0x60 }, { 0xd076, 0x00 }, { 0xd077, 0x01 }, { 0xd078, 0xa8 },
{ 0xd079, 0x63 }, { 0xd07a, 0x07 }, { 0xd07b, 0x80 }, { 0xd07c, 0x07 },
{ 0xd07d, 0xff }, { 0xd07e, 0xf9 }, { 0xd07f, 0x03 }, { 0xd080, 0x8c },
{ 0xd081, 0x63 }, { 0xd082, 0x00 }, { 0xd083, 0x00 }, { 0xd084, 0xa5 },
{ 0xd085, 0x6b }, { 0xd086, 0x00 }, { 0xd087, 0xff }, { 0xd088, 0x18 },
{ 0xd089, 0x80 }, { 0xd08a, 0x00 }, { 0xd08b, 0x01 }, { 0xd08c, 0xa8 },
{ 0xd08d, 0x84 }, { 0xd08e, 0x01 }, { 0xd08f, 0x04 }, { 0xd090, 0xe1 },
{ 0xd091, 0x6b }, { 0xd092, 0x58 }, { 0xd093, 0x00 }, { 0xd094, 0x94 },
{ 0xd095, 0x6a }, { 0xd096, 0x00 }, { 0xd097, 0x70 }, { 0xd098, 0xe1 },
{ 0xd099, 0x6b }, { 0xd09a, 0x20 }, { 0xd09b, 0x00 }, { 0xd09c, 0x95 },
{ 0xd09d, 0x6b }, { 0xd09e, 0x00 }, { 0xd09f, 0x00 }, { 0xd0a0, 0xe4 },
{ 0xd0a1, 0x8b }, { 0xd0a2, 0x18 }, { 0xd0a3, 0x00 }, { 0xd0a4, 0x0c },
{ 0xd0a5, 0x00 }, { 0xd0a6, 0x00 }, { 0xd0a7, 0x23 }, { 0xd0a8, 0x15 },
{ 0xd0a9, 0x00 }, { 0xd0aa, 0x00 }, { 0xd0ab, 0x00 }, { 0xd0ac, 0x18 },
{ 0xd0ad, 0x60 }, { 0xd0ae, 0x80 }, { 0xd0af, 0x06 }, { 0xd0b0, 0xa8 },
{ 0xd0b1, 0x83 }, { 0xd0b2, 0x40 }, { 0xd0b3, 0x08 }, { 0xd0b4, 0xa8 },
{ 0xd0b5, 0xe3 }, { 0xd0b6, 0x38 }, { 0xd0b7, 0x2a }, { 0xd0b8, 0xa8 },
{ 0xd0b9, 0xc3 }, { 0xd0ba, 0x40 }, { 0xd0bb, 0x09 }, { 0xd0bc, 0xa8 },
{ 0xd0bd, 0xa3 }, { 0xd0be, 0x38 }, { 0xd0bf, 0x29 }, { 0xd0c0, 0x8c },
{ 0xd0c1, 0x65 }, { 0xd0c2, 0x00 }, { 0xd0c3, 0x00 }, { 0xd0c4, 0xd8 },
{ 0xd0c5, 0x04 }, { 0xd0c6, 0x18 }, { 0xd0c7, 0x00 }, { 0xd0c8, 0x8c },
{ 0xd0c9, 0x67 }, { 0xd0ca, 0x00 }, { 0xd0cb, 0x00 }, { 0xd0cc, 0xd8 },
{ 0xd0cd, 0x06 }, { 0xd0ce, 0x18 }, { 0xd0cf, 0x00 }, { 0xd0d0, 0x18 },
{ 0xd0d1, 0x60 }, { 0xd0d2, 0x80 }, { 0xd0d3, 0x06 }, { 0xd0d4, 0xa8 },
{ 0xd0d5, 0xe3 }, { 0xd0d6, 0x67 }, { 0xd0d7, 0x02 }, { 0xd0d8, 0xa9 },
{ 0xd0d9, 0x03 }, { 0xd0da, 0x67 }, { 0xd0db, 0x03 }, { 0xd0dc, 0xa8 },
{ 0xd0dd, 0xc3 }, { 0xd0de, 0x3d }, { 0xd0df, 0x05 }, { 0xd0e0, 0x8c },
{ 0xd0e1, 0x66 }, { 0xd0e2, 0x00 }, { 0xd0e3, 0x00 }, { 0xd0e4, 0xb8 },
{ 0xd0e5, 0x63 }, { 0xd0e6, 0x00 }, { 0xd0e7, 0x18 }, { 0xd0e8, 0xb8 },
{ 0xd0e9, 0x63 }, { 0xd0ea, 0x00 }, { 0xd0eb, 0x98 }, { 0xd0ec, 0xbc },
{ 0xd0ed, 0x03 }, { 0xd0ee, 0x00 }, { 0xd0ef, 0x00 }, { 0xd0f0, 0x10 },
{ 0xd0f1, 0x00 }, { 0xd0f2, 0x00 }, { 0xd0f3, 0x16 }, { 0xd0f4, 0xb8 },
{ 0xd0f5, 0x83 }, { 0xd0f6, 0x00 }, { 0xd0f7, 0x19 }, { 0xd0f8, 0x8c },
{ 0xd0f9, 0x67 }, { 0xd0fa, 0x00 }, { 0xd0fb, 0x00 }, { 0xd0fc, 0xb8 },
{ 0xd0fd, 0xa4 }, { 0xd0fe, 0x00 }, { 0xd0ff, 0x98 }, { 0xd100, 0xb8 },
{ 0xd101, 0x83 }, { 0xd102, 0x00 }, { 0xd103, 0x08 }, { 0xd104, 0x8c },
{ 0xd105, 0x68 }, { 0xd106, 0x00 }, { 0xd107, 0x00 }, { 0xd108, 0xe0 },
{ 0xd109, 0x63 }, { 0xd10a, 0x20 }, { 0xd10b, 0x04 }, { 0xd10c, 0xe0 },
{ 0xd10d, 0x65 }, { 0xd10e, 0x18 }, { 0xd10f, 0x00 }, { 0xd110, 0xa4 },
{ 0xd111, 0x83 }, { 0xd112, 0xff }, { 0xd113, 0xff }, { 0xd114, 0xb8 },
{ 0xd115, 0x64 }, { 0xd116, 0x00 }, { 0xd117, 0x48 }, { 0xd118, 0xd8 },
{ 0xd119, 0x07 }, { 0xd11a, 0x18 }, { 0xd11b, 0x00 }, { 0xd11c, 0xd8 },
{ 0xd11d, 0x08 }, { 0xd11e, 0x20 }, { 0xd11f, 0x00 }, { 0xd120, 0x9c },
{ 0xd121, 0x60 }, { 0xd122, 0x00 }, { 0xd123, 0x00 }, { 0xd124, 0xd8 },
{ 0xd125, 0x06 }, { 0xd126, 0x18 }, { 0xd127, 0x00 }, { 0xd128, 0x00 },
{ 0xd129, 0x00 }, { 0xd12a, 0x00 }, { 0xd12b, 0x08 }, { 0xd12c, 0x15 },
{ 0xd12d, 0x00 }, { 0xd12e, 0x00 }, { 0xd12f, 0x00 }, { 0xd130, 0x8c },
{ 0xd131, 0x6a }, { 0xd132, 0x00 }, { 0xd133, 0x76 }, { 0xd134, 0xbc },
{ 0xd135, 0x23 }, { 0xd136, 0x00 }, { 0xd137, 0x00 }, { 0xd138, 0x13 },
{ 0xd139, 0xff }, { 0xd13a, 0xff }, { 0xd13b, 0xe6 }, { 0xd13c, 0x18 },
{ 0xd13d, 0x60 }, { 0xd13e, 0x80 }, { 0xd13f, 0x06 }, { 0xd140, 0x03 },
{ 0xd141, 0xff }, { 0xd142, 0xff }, { 0xd143, 0xdd }, { 0xd144, 0xa8 },
{ 0xd145, 0x83 }, { 0xd146, 0x40 }, { 0xd147, 0x08 }, { 0xd148, 0x85 },
{ 0xd149, 0x21 }, { 0xd14a, 0x00 }, { 0xd14b, 0x00 }, { 0xd14c, 0x85 },
{ 0xd14d, 0x41 }, { 0xd14e, 0x00 }, { 0xd14f, 0x04 }, { 0xd150, 0x44 },
{ 0xd151, 0x00 }, { 0xd152, 0x48 }, { 0xd153, 0x00 }, { 0xd154, 0x9c },
{ 0xd155, 0x21 }, { 0xd156, 0x00 }, { 0xd157, 0x08 }, { 0x6f0e, 0x03 },
{ 0x6f0f, 0x00 }, { 0x460e, 0x08 }, { 0x460f, 0x01 }, { 0x4610, 0x00 },
{ 0x4611, 0x01 }, { 0x4612, 0x00 }, { 0x4613, 0x01 },
/* 8 bits */
{ 0x4605, 0x08 },
/* Swap data bits order [9:0] -> [0:9] */
{ 0x4709, 0x10 }, { 0x4608, 0x00 }, { 0x4609, 0x08 }, { 0x6804, 0x00 },
{ 0x6805, 0x06 }, { 0x6806, 0x00 }, { 0x5120, 0x00 }, { 0x3510, 0x00 },
{ 0x3504, 0x00 }, { 0x6800, 0x00 }, { 0x6f0d, 0x01 },
/* PCLK falling edge */
{ 0x4708, 0x01 }, { 0x5000, 0xff }, { 0x5001, 0xbf }, { 0x5002, 0x7e },
{ 0x503d, 0x00 }, { 0xc450, 0x01 }, { 0xc452, 0x04 }, { 0xc453, 0x00 },
{ 0xc454, 0x00 }, { 0xc455, 0x01 }, { 0xc456, 0x01 }, { 0xc457, 0x00 },
{ 0xc458, 0x00 }, { 0xc459, 0x00 }, { 0xc45b, 0x00 }, { 0xc45c, 0x01 },
{ 0xc45d, 0x00 }, { 0xc45e, 0x00 }, { 0xc45f, 0x00 }, { 0xc460, 0x00 },
{ 0xc461, 0x01 }, { 0xc462, 0x01 }, { 0xc464, 0x03 }, { 0xc465, 0x00 },
{ 0xc466, 0x8a }, { 0xc467, 0x00 }, { 0xc468, 0x86 }, { 0xc469, 0x00 },
{ 0xc46a, 0x40 }, { 0xc46b, 0x50 }, { 0xc46c, 0x30 }, { 0xc46d, 0x28 },
{ 0xc46e, 0x60 }, { 0xc46f, 0x40 }, { 0xc47c, 0x01 }, { 0xc47d, 0x38 },
{ 0xc47e, 0x00 }, { 0xc47f, 0x00 }, { 0xc480, 0x00 }, { 0xc481, 0xff },
{ 0xc482, 0x00 }, { 0xc483, 0x40 }, { 0xc484, 0x00 }, { 0xc485, 0x18 },
{ 0xc486, 0x00 }, { 0xc487, 0x18 },
{ 0xc488, (OV10635_VTS - 8) * 16 >> 8},
{ 0xc489, (OV10635_VTS - 8) * 16 & 0xff},
{ 0xc48a, (OV10635_VTS - 8) * 16 >> 8},
{ 0xc48b, (OV10635_VTS - 8) * 16 & 0xff}, { 0xc48c, 0x00 },
{ 0xc48d, 0x04 }, { 0xc48e, 0x00 }, { 0xc48f, 0x04 }, { 0xc490, 0x03 },
{ 0xc492, 0x20 }, { 0xc493, 0x08 }, { 0xc498, 0x02 }, { 0xc499, 0x00 },
{ 0xc49a, 0x02 }, { 0xc49b, 0x00 }, { 0xc49c, 0x02 }, { 0xc49d, 0x00 },
{ 0xc49e, 0x02 }, { 0xc49f, 0x60 }, { 0xc4a0, 0x03 }, { 0xc4a1, 0x00 },
{ 0xc4a2, 0x04 }, { 0xc4a3, 0x00 }, { 0xc4a4, 0x00 }, { 0xc4a5, 0x10 },
{ 0xc4a6, 0x00 }, { 0xc4a7, 0x40 }, { 0xc4a8, 0x00 }, { 0xc4a9, 0x80 },
{ 0xc4aa, 0x0d }, { 0xc4ab, 0x00 }, { 0xc4ac, 0x0f }, { 0xc4ad, 0xc0 },
{ 0xc4b4, 0x01 }, { 0xc4b5, 0x01 }, { 0xc4b6, 0x00 }, { 0xc4b7, 0x01 },
{ 0xc4b8, 0x00 }, { 0xc4b9, 0x01 }, { 0xc4ba, 0x01 }, { 0xc4bb, 0x00 },
{ 0xc4bc, 0x01 }, { 0xc4bd, 0x60 }, { 0xc4be, 0x02 }, { 0xc4bf, 0x33 },
{ 0xc4c8, 0x03 }, { 0xc4c9, 0xd0 }, { 0xc4ca, 0x0e }, { 0xc4cb, 0x00 },
{ 0xc4cc, 0x0e }, { 0xc4cd, 0x51 }, { 0xc4ce, 0x0e }, { 0xc4cf, 0x51 },
{ 0xc4d0, 0x04 }, { 0xc4d1, 0x80 }, { 0xc4e0, 0x04 }, { 0xc4e1, 0x02 },
{ 0xc4e2, 0x01 }, { 0xc4e4, 0x10 }, { 0xc4e5, 0x20 }, { 0xc4e6, 0x30 },
{ 0xc4e7, 0x40 }, { 0xc4e8, 0x50 }, { 0xc4e9, 0x60 }, { 0xc4ea, 0x70 },
{ 0xc4eb, 0x80 }, { 0xc4ec, 0x90 }, { 0xc4ed, 0xa0 }, { 0xc4ee, 0xb0 },
{ 0xc4ef, 0xc0 }, { 0xc4f0, 0xd0 }, { 0xc4f1, 0xe0 }, { 0xc4f2, 0xf0 },
{ 0xc4f3, 0x80 }, { 0xc4f4, 0x00 }, { 0xc4f5, 0x20 }, { 0xc4f6, 0x02 },
{ 0xc4f7, 0x00 }, { 0xc4f8, 0x00 }, { 0xc4f9, 0x00 }, { 0xc4fa, 0x00 },
{ 0xc4fb, 0x01 }, { 0xc4fc, 0x01 }, { 0xc4fd, 0x00 }, { 0xc4fe, 0x04 },
{ 0xc4ff, 0x02 }, { 0xc500, 0x48 }, { 0xc501, 0x74 }, { 0xc502, 0x58 },
{ 0xc503, 0x80 }, { 0xc504, 0x05 }, { 0xc505, 0x80 }, { 0xc506, 0x03 },
{ 0xc507, 0x80 }, { 0xc508, 0x01 }, { 0xc509, 0xc0 }, { 0xc50a, 0x01 },
{ 0xc50b, 0xa0 }, { 0xc50c, 0x01 }, { 0xc50d, 0x2c }, { 0xc50e, 0x01 },
{ 0xc50f, 0x0a }, { 0xc510, 0x00 }, { 0xc511, 0x00 }, { 0xc512, 0xe5 },
{ 0xc513, 0x14 }, { 0xc514, 0x04 }, { 0xc515, 0x00 }, { 0xc518, OV10635_VTS >> 8},
{ 0xc519, OV10635_VTS & 0xff}, { 0xc51a, OV10635_HTS >> 8},
{ 0xc51b, OV10635_HTS & 0xff}, { 0xc2e0, 0x00 }, { 0xc2e1, 0x51 },
{ 0xc2e2, 0x00 }, { 0xc2e3, 0xd6 }, { 0xc2e4, 0x01 }, { 0xc2e5, 0x5e },
{ 0xc2e9, 0x01 }, { 0xc2ea, 0x7a }, { 0xc2eb, 0x90 }, { 0xc2ed, 0x00 },
{ 0xc2ee, 0x7a }, { 0xc2ef, 0x64 }, { 0xc308, 0x00 }, { 0xc309, 0x00 },
{ 0xc30a, 0x00 }, { 0xc30c, 0x00 }, { 0xc30d, 0x01 }, { 0xc30e, 0x00 },
{ 0xc30f, 0x00 }, { 0xc310, 0x01 }, { 0xc311, 0x60 }, { 0xc312, 0xff },
{ 0xc313, 0x08 }, { 0xc314, 0x01 }, { 0xc315, 0x00 }, { 0xc316, 0xff },
{ 0xc317, 0x0b }, { 0xc318, 0x00 }, { 0xc319, 0x0c }, { 0xc31a, 0x00 },
{ 0xc31b, 0xe0 }, { 0xc31c, 0x00 }, { 0xc31d, 0x14 }, { 0xc31e, 0x00 },
{ 0xc31f, 0xc5 }, { 0xc320, 0xff }, { 0xc321, 0x4b }, { 0xc322, 0xff },
{ 0xc323, 0xf0 }, { 0xc324, 0xff }, { 0xc325, 0xe8 }, { 0xc326, 0x00 },
{ 0xc327, 0x46 }, { 0xc328, 0xff }, { 0xc329, 0xd2 }, { 0xc32a, 0xff },
{ 0xc32b, 0xe4 }, { 0xc32c, 0xff }, { 0xc32d, 0xbb }, { 0xc32e, 0x00 },
{ 0xc32f, 0x61 }, { 0xc330, 0xff }, { 0xc331, 0xf9 }, { 0xc332, 0x00 },
{ 0xc333, 0xd9 }, { 0xc334, 0x00 }, { 0xc335, 0x2e }, { 0xc336, 0x00 },
{ 0xc337, 0xb1 }, { 0xc338, 0xff }, { 0xc339, 0x64 }, { 0xc33a, 0xff },
{ 0xc33b, 0xeb }, { 0xc33c, 0xff }, { 0xc33d, 0xe8 }, { 0xc33e, 0x00 },
{ 0xc33f, 0x48 }, { 0xc340, 0xff }, { 0xc341, 0xd0 }, { 0xc342, 0xff },
{ 0xc343, 0xed }, { 0xc344, 0xff }, { 0xc345, 0xad }, { 0xc346, 0x00 },
{ 0xc347, 0x66 }, { 0xc348, 0x01 }, { 0xc349, 0x00 }, { 0x6700, 0x04 },
{ 0x6701, 0x7b }, { 0x6702, 0xfd }, { 0x6703, 0xf9 }, { 0x6704, 0x3d },
{ 0x6705, 0x71 }, { 0x6706, 0x78 }, { 0x6708, 0x05 }, { 0x6f06, 0x6f },
{ 0x6f07, 0x00 }, { 0x6f0a, 0x6f }, { 0x6f0b, 0x00 }, { 0x6f00, 0x03 },
{ 0xc34c, 0x01 }, { 0xc34d, 0x00 }, { 0xc34e, 0x46 }, { 0xc34f, 0x55 },
{ 0xc350, 0x00 }, { 0xc351, 0x40 }, { 0xc352, 0x00 }, { 0xc353, 0xff },
{ 0xc354, 0x04 }, { 0xc355, 0x08 }, { 0xc356, 0x01 }, { 0xc357, 0xef },
{ 0xc358, 0x30 }, { 0xc359, 0x01 }, { 0xc35a, 0x64 }, { 0xc35b, 0x46 },
{ 0xc35c, 0x00 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 },
{ 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0xc261, 0x01 },
{ 0x301b, 0xf0 }, { 0x301c, 0xf0 }, { 0x301a, 0xf0 }, { 0x6f00, 0xc3 },
{ 0xc46a, 0x30 }, { 0xc46d, 0x20 }, { 0xc464, 0x84 }, { 0xc465, 0x00 },
{ 0x6f00, 0x03 }, { 0x6f00, 0x43 }, { 0x381c, 0x00 }, { 0x381d, 0x40 },
{ 0xc454, 0x01 }, { 0x6f00, 0xc3 }, { 0xc454, 0x00 }, { 0xc4b1, 0x02 },
{ 0xc4b2, 0x01 }, { 0xc4b3, 0x03 }, { 0x6f00, 0x03 }, { 0x6f00, 0x43 },
/* enable FSIN (FRAMESYNC input) functionality */
{ 0x3832, (0x0d + 2 * 0x20 + 0x15 + 38) >> 8 },
{ 0x3833, (0x0d + 2 * 0x20 + 0x15 + 38) & 0xff },
{ 0x3834, OV10635_VTS >> 8 }, { 0x3835, OV10635_VTS & 0xff },
{ 0x302e, 0x01 },
};
struct rdacm20_device {
struct device *dev;
struct max9271_device *serializer;
struct i2c_client *sensor;
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrls;
u32 addrs[2];
};
static inline struct rdacm20_device *sd_to_rdacm20(struct v4l2_subdev *sd)
{
return container_of(sd, struct rdacm20_device, sd);
}
static inline struct rdacm20_device *i2c_to_rdacm20(struct i2c_client *client)
{
return sd_to_rdacm20(i2c_get_clientdata(client));
}
static int ov10635_read16(struct rdacm20_device *dev, u16 reg)
{
u8 buf[2] = { reg >> 8, reg & 0xff };
int ret;
ret = i2c_master_send(dev->sensor, buf, 2);
if (ret != 2) {
dev_dbg(dev->dev, "%s: register 0x%04x write failed (%d)\n",
__func__, reg, ret);
return ret;
}
ret = i2c_master_recv(dev->sensor, buf, 2);
if (ret < 0) {
dev_dbg(dev->dev, "%s: register 0x%04x read failed (%d)\n",
__func__, reg, ret);
return ret;
}
return (buf[0] << 8) | buf[1];
}
static int __ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val)
{
u8 buf[3] = { reg >> 8, reg & 0xff, val };
int ret;
dev_dbg(dev->dev, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
ret = i2c_master_send(dev->sensor, buf, 3);
return ret < 0 ? ret : 0;
}
static int ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val)
{
int ret;
ret = __ov10635_write(dev, reg, val);
if (ret < 0)
dev_err(dev->dev, "%s: register 0x%04x write failed (%d)\n",
__func__, reg, ret);
return ret;
}
static int ov10635_set_regs(struct rdacm20_device *dev,
const struct ov10635_reg *regs,
unsigned int nr_regs)
{
unsigned int i;
int ret;
for (i = 0; i < nr_regs; i++) {
ret = __ov10635_write(dev, regs[i].reg, regs[i].val);
if (ret) {
dev_err(dev->dev,
"%s: register %u (0x%04x) write failed (%d)\n",
__func__, i, regs[i].reg, ret);
return ret;
}
}
return 0;
}
static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rdacm20_device *dev = sd_to_rdacm20(sd);
return max9271_set_serial_link(dev->serializer, enable);
}
static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_UYVY8_2X8;
return 0;
}
static int rdacm20_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
if (format->pad)
return -EINVAL;
mf->width = OV10635_WIDTH;
mf->height = OV10635_HEIGHT;
mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_RAW;
mf->field = V4L2_FIELD_NONE;
mf->ycbcr_enc = V4L2_YCBCR_ENC_601;
mf->quantization = V4L2_QUANTIZATION_FULL_RANGE;
mf->xfer_func = V4L2_XFER_FUNC_NONE;
return 0;
}
static struct v4l2_subdev_video_ops rdacm20_video_ops = {
.s_stream = rdacm20_s_stream,
};
static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = {
.enum_mbus_code = rdacm20_enum_mbus_code,
.get_fmt = rdacm20_get_fmt,
.set_fmt = rdacm20_get_fmt,
};
static struct v4l2_subdev_ops rdacm20_subdev_ops = {
.video = &rdacm20_video_ops,
.pad = &rdacm20_subdev_pad_ops,
};
static int rdacm20_initialize(struct rdacm20_device *dev)
{
unsigned int retry = 3;
int ret;
/* Verify communication with the MAX9271: ping to wakeup. */
dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
i2c_smbus_read_byte(dev->serializer->client);
/* Serial link disabled during config as it needs a valid pixel clock. */
ret = max9271_set_serial_link(dev->serializer, false);
if (ret)
return ret;
/*
* Ensure that we have a good link configuration before attempting to
* identify the device.
*/
max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
MAX9271_I2CSLVTO_1024US |
MAX9271_I2CMSTBT_105KBPS);
max9271_configure_gmsl_link(dev->serializer);
ret = max9271_verify_id(dev->serializer);
if (ret < 0)
return ret;
ret = max9271_set_address(dev->serializer, dev->addrs[0]);
if (ret < 0)
return ret;
dev->serializer->client->addr = dev->addrs[0];
/*
* Reset the sensor by cycling the OV10635 reset signal connected to the
* MAX9271 GPIO1 and verify communication with the OV10635.
*/
max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT);
usleep_range(10000, 15000);
max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT);
usleep_range(10000, 15000);
again:
ret = ov10635_read16(dev, OV10635_PID);
if (ret < 0) {
if (retry--)
goto again;
dev_err(dev->dev, "OV10635 ID read failed (%d)\n",
ret);
return -ENXIO;
}
if (ret != OV10635_VERSION) {
if (retry--)
goto again;
dev_err(dev->dev, "OV10635 ID mismatch (0x%04x)\n",
ret);
return -ENXIO;
}
/* Change the sensor I2C address. */
ret = ov10635_write(dev, OV10635_SC_CMMN_SCCB_ID,
(dev->addrs[1] << 1) |
OV10635_SC_CMMN_SCCB_ID_SELECT);
if (ret < 0) {
dev_err(dev->dev,
"OV10635 I2C address change failed (%d)\n", ret);
return ret;
}
dev->sensor->addr = dev->addrs[1];
usleep_range(3500, 5000);
/* Program the 0V10635 initial configuration. */
ret = ov10635_set_regs(dev, ov10635_regs_wizard,
ARRAY_SIZE(ov10635_regs_wizard));
if (ret)
return ret;
dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
return 0;
}
static int rdacm20_probe(struct i2c_client *client)
{
struct rdacm20_device *dev;
struct fwnode_handle *ep;
int ret;
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->dev = &client->dev;
dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
GFP_KERNEL);
if (!dev->serializer)
return -ENOMEM;
dev->serializer->client = client;
ret = of_property_read_u32_array(client->dev.of_node, "reg",
dev->addrs, 2);
if (ret < 0) {
dev_err(dev->dev, "Invalid DT reg property: %d\n", ret);
return -EINVAL;
}
/* Create the dummy I2C client for the sensor. */
dev->sensor = i2c_new_dummy_device(client->adapter,
OV10635_I2C_ADDRESS);
if (IS_ERR(dev->sensor)) {
ret = PTR_ERR(dev->sensor);
goto error;
}
/* Initialize the hardware. */
ret = rdacm20_initialize(dev);
if (ret < 0)
goto error;
/* Initialize and register the subdevice. */
v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops);
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_ctrl_handler_init(&dev->ctrls, 1);
v4l2_ctrl_new_std(&dev->ctrls, NULL, V4L2_CID_PIXEL_RATE,
OV10635_PIXEL_RATE, OV10635_PIXEL_RATE, 1,
OV10635_PIXEL_RATE);
dev->sd.ctrl_handler = &dev->ctrls;
ret = dev->ctrls.error;
if (ret)
goto error_free_ctrls;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret < 0)
goto error_free_ctrls;
ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
if (!ep) {
dev_err(&client->dev,
"Unable to get endpoint in node %pOF\n",
client->dev.of_node);
ret = -ENOENT;
goto error_free_ctrls;
}
dev->sd.fwnode = ep;
ret = v4l2_async_register_subdev(&dev->sd);
if (ret)
goto error_put_node;
return 0;
error_put_node:
fwnode_handle_put(ep);
error_free_ctrls:
v4l2_ctrl_handler_free(&dev->ctrls);
error:
media_entity_cleanup(&dev->sd.entity);
if (dev->sensor)
i2c_unregister_device(dev->sensor);
dev_err(&client->dev, "probe failed\n");
return ret;
}
static int rdacm20_remove(struct i2c_client *client)
{
struct rdacm20_device *dev = i2c_to_rdacm20(client);
fwnode_handle_put(dev->sd.fwnode);
v4l2_async_unregister_subdev(&dev->sd);
v4l2_ctrl_handler_free(&dev->ctrls);
media_entity_cleanup(&dev->sd.entity);
i2c_unregister_device(dev->sensor);
return 0;
}
static void rdacm20_shutdown(struct i2c_client *client)
{
struct rdacm20_device *dev = i2c_to_rdacm20(client);
/* make sure stream off during shutdown (reset/reboot) */
rdacm20_s_stream(&dev->sd, 0);
}
static const struct of_device_id rdacm20_of_ids[] = {
{ .compatible = "imi,rdacm20", },
{ }
};
MODULE_DEVICE_TABLE(of, rdacm20_of_ids);
static struct i2c_driver rdacm20_i2c_driver = {
.driver = {
.name = "rdacm20",
.of_match_table = rdacm20_of_ids,
},
.probe_new = rdacm20_probe,
.remove = rdacm20_remove,
.shutdown = rdacm20_shutdown,
};
module_i2c_driver(rdacm20_i2c_driver);
MODULE_DESCRIPTION("GMSL Camera driver for RDACM20");
MODULE_AUTHOR("Vladimir Barinov");
MODULE_LICENSE("GPL");

View File

@ -197,7 +197,7 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
ret = pm_runtime_get(sensor->dev);
if (ret < 0)
return ret;
goto error_rpm_put;
ret = regulator_enable(sensor->supplies[i].consumer);
if (ret < 0)

View File

@ -508,9 +508,7 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
pm_runtime_get_noresume(&client->dev);
pm_status = pm_runtime_get_if_in_use(&client->dev);
pm_runtime_put_noidle(&client->dev);
pm_status = pm_runtime_get_if_active(&client->dev, true);
if (!pm_status)
return 0;
@ -3103,6 +3101,7 @@ static int smiapp_probe(struct i2c_client *client)
return 0;
out_disable_runtime_pm:
pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev);
out_media_entity_cleanup:

View File

@ -1664,8 +1664,10 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
return 0;
err:
for (i = 0; i < decoder->connectors_num; i++)
for (i = 0; i < decoder->connectors_num; i++) {
media_device_unregister_entity(&decoder->connectors[i].ent);
media_entity_cleanup(&decoder->connectors[i].ent);
}
return ret;
#endif
@ -2248,8 +2250,10 @@ static int tvp5150_remove(struct i2c_client *c)
for (i = 0; i < decoder->connectors_num; i++)
v4l2_fwnode_connector_free(&decoder->connectors[i].base);
for (i = 0; i < decoder->connectors_num; i++)
for (i = 0; i < decoder->connectors_num; i++) {
media_device_unregister_entity(&decoder->connectors[i].ent);
media_entity_cleanup(&decoder->connectors[i].ent);
}
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
pm_runtime_disable(&c->dev);

View File

@ -296,9 +296,18 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
return -ENOMEM;
if (mdev->ops->req_alloc)
req = mdev->ops->req_alloc(mdev);
else
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0)
return fd;
if (fd < 0) {
ret = fd;
goto err_free_req;
}
filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
if (IS_ERR(filp)) {
@ -306,15 +315,6 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
goto err_put_fd;
}
if (mdev->ops->req_alloc)
req = mdev->ops->req_alloc(mdev);
else
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) {
ret = -ENOMEM;
goto err_fput;
}
filp->private_data = req;
req->mdev = mdev;
req->state = MEDIA_REQUEST_STATE_IDLE;
@ -336,12 +336,15 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
return 0;
err_fput:
fput(filp);
err_put_fd:
put_unused_fd(fd);
err_free_req:
if (mdev->ops->req_free)
mdev->ops->req_free(req);
else
kfree(req);
return ret;
}

View File

@ -35,7 +35,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_nxp = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
/* Please add new PCI IDs to: https://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */

View File

@ -2235,9 +2235,6 @@ static struct pci_driver cx23885_pci_driver = {
.id_table = cx23885_pci_tbl,
.probe = cx23885_initdev,
.remove = cx23885_finidev,
/* TODO */
.suspend = NULL,
.resume = NULL,
};
static int __init cx23885_init(void)

View File

@ -175,19 +175,6 @@ static inline u16 count_to_clock_divider(unsigned int d)
return (u16) d;
}
static inline u16 ns_to_clock_divider(unsigned int ns)
{
return count_to_clock_divider(
DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
}
static inline unsigned int clock_divider_to_ns(unsigned int divider)
{
/* Period of the Rx or Tx clock in ns */
return DIV_ROUND_CLOSEST((divider + 1) * 1000,
CX23888_IR_REFCLK_FREQ / 1000000);
}
static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
{
return count_to_clock_divider(
@ -199,13 +186,6 @@ static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16);
}
static inline u16 freq_to_clock_divider(unsigned int freq,
unsigned int rollovers)
{
return count_to_clock_divider(
DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers));
}
static inline unsigned int clock_divider_to_freq(unsigned int divider,
unsigned int rollovers)
{

View File

@ -1374,9 +1374,6 @@ static struct pci_driver cx25821_pci_driver = {
.id_table = cx25821_pci_tbl,
.probe = cx25821_initdev,
.remove = cx25821_finidev,
/* TODO */
.suspend = NULL,
.resume = NULL,
};
static int __init cx25821_init(void)

View File

@ -385,8 +385,7 @@ static int start_video_dma(struct cx8800_dev *dev,
return 0;
}
#ifdef CONFIG_PM
static int stop_video_dma(struct cx8800_dev *dev)
static int __maybe_unused stop_video_dma(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;
@ -402,8 +401,8 @@ static int stop_video_dma(struct cx8800_dev *dev)
return 0;
}
static int restart_video_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
static int __maybe_unused restart_video_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_buffer *buf;
@ -415,7 +414,6 @@ static int restart_video_queue(struct cx8800_dev *dev,
}
return 0;
}
#endif
/* ------------------------------------------------------------------ */
@ -1551,10 +1549,9 @@ static void cx8800_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
#ifdef CONFIG_PM
static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
static int __maybe_unused cx8800_suspend(struct device *dev_d)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
unsigned long flags;
@ -1575,40 +1572,17 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
/* FIXME -- shutdown device */
cx88_shutdown(core);
pci_save_state(pci_dev);
if (pci_set_power_state(pci_dev,
pci_choose_state(pci_dev, state)) != 0) {
pci_disable_device(pci_dev);
dev->state.disabled = 1;
}
dev->state.disabled = 1;
return 0;
}
static int cx8800_resume(struct pci_dev *pci_dev)
static int __maybe_unused cx8800_resume(struct device *dev_d)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
unsigned long flags;
int err;
if (dev->state.disabled) {
err = pci_enable_device(pci_dev);
if (err) {
pr_err("can't enable device\n");
return err;
}
dev->state.disabled = 0;
}
err = pci_set_power_state(pci_dev, PCI_D0);
if (err) {
pr_err("can't set power state\n");
pci_disable_device(pci_dev);
dev->state.disabled = 1;
return err;
}
pci_restore_state(pci_dev);
dev->state.disabled = 0;
/* FIXME: re-initialize hardware */
cx88_reset(core);
@ -1631,7 +1605,6 @@ static int cx8800_resume(struct pci_dev *pci_dev)
return 0;
}
#endif
/* ----------------------------------------------------------- */
@ -1647,15 +1620,14 @@ static const struct pci_device_id cx8800_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);
static SIMPLE_DEV_PM_OPS(cx8800_pm_ops, cx8800_suspend, cx8800_resume);
static struct pci_driver cx8800_pci_driver = {
.name = "cx8800",
.id_table = cx8800_pci_tbl,
.probe = cx8800_initdev,
.remove = cx8800_finidev,
#ifdef CONFIG_PM
.suspend = cx8800_suspend,
.resume = cx8800_resume,
#endif
.name = "cx8800",
.id_table = cx8800_pci_tbl,
.probe = cx8800_initdev,
.remove = cx8800_finidev,
.driver.pm = &cx8800_pm_ops,
};
module_pci_driver(cx8800_pci_driver);

View File

@ -426,7 +426,7 @@ static int dt3155_init_board(struct dt3155_priv *pd)
iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
iowrite32(0x00000020, pd->regs + FIFO_TRIGGER);
iowrite32(0x00000103, pd->regs + XFER_MODE);
iowrite32(0, pd->regs + RETRY_WAIT_CNT);
iowrite32(0, pd->regs + INT_CSR);

View File

@ -31,7 +31,7 @@
#define ODD_DMA_STRIDE 0x24
#define EVEN_PIXEL_FMT 0x30
#define ODD_PIXEL_FMT 0x34
#define FIFO_TRIGER 0x38
#define FIFO_TRIGGER 0x38
#define XFER_MODE 0x3C
#define CSR1 0x40
#define RETRY_WAIT_CNT 0x44

View File

@ -53,7 +53,7 @@ static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
/********************** card configuration *******************************/
/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
/* Please add new PCI IDs to: https://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */

View File

@ -1528,19 +1528,16 @@ static const struct v4l2_ctrl_ops meye_ctrl_ops = {
.s_ctrl = meye_s_ctrl,
};
#ifdef CONFIG_PM
static int meye_suspend(struct pci_dev *pdev, pm_message_t state)
static int __maybe_unused meye_suspend(struct device *dev)
{
pci_save_state(pdev);
meye.pm_mchip_mode = meye.mchip_mode;
mchip_hic_stop();
mchip_set(MCHIP_MM_INTA, 0x0);
return 0;
}
static int meye_resume(struct pci_dev *pdev)
static int __maybe_unused meye_resume(struct device *dev)
{
pci_restore_state(pdev);
pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
mchip_delay(MCHIP_HIC_CMD, 0);
@ -1562,7 +1559,6 @@ static int meye_resume(struct pci_dev *pdev)
}
return 0;
}
#endif
static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
@ -1788,15 +1784,14 @@ static const struct pci_device_id meye_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume);
static struct pci_driver meye_driver = {
.name = "meye",
.id_table = meye_pci_tbl,
.probe = meye_probe,
.remove = meye_remove,
#ifdef CONFIG_PM
.suspend = meye_suspend,
.resume = meye_resume,
#endif
.driver.pm = &meye_pm_ops,
};
static int __init meye_init(void)

View File

@ -305,9 +305,7 @@ struct meye {
u16 colour;
struct meye_params params; /* additional parameters */
unsigned long in_use; /* set to 1 if the device is in use */
#ifdef CONFIG_PM
u8 pm_mchip_mode; /* old mchip mode */
#endif
};
#endif

View File

@ -1539,9 +1539,6 @@ static struct pci_driver saa7164_pci_driver = {
.id_table = saa7164_pci_tbl,
.probe = saa7164_initdev,
.remove = saa7164_finidev,
/* TODO */
.suspend = NULL,
.resume = NULL,
};
static int __init saa7164_init(void)

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
* Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com>
*
* Original author:
* Ben Collins <bcollins@ubuntu.com>

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
* Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com>
*
* Original author:
* Ben Collins <bcollins@ubuntu.com>

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