mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
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:
commit
fa73e21231
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
100
Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
Normal file
100
Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
366
Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
Normal file
366
Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
66
Documentation/devicetree/bindings/media/renesas,fcp.yaml
Normal file
66
Documentation/devicetree/bindings/media/renesas,fcp.yaml
Normal 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>;
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
69
Documentation/devicetree/bindings/media/renesas,fdp1.yaml
Normal file
69
Documentation/devicetree/bindings/media/renesas,fdp1.yaml
Normal 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>;
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
97
Documentation/devicetree/bindings/media/renesas,vsp1.yaml
Normal file
97
Documentation/devicetree/bindings/media/renesas,vsp1.yaml
Normal 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>;
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -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,.*":
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
753
Documentation/userspace-api/media/v4l/dev-encoder.rst
Normal file
753
Documentation/userspace-api/media/v4l/dev-encoder.rst
Normal 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.
|
@ -46,4 +46,5 @@ devices are given in the following sections.
|
||||
:maxdepth: 1
|
||||
|
||||
dev-decoder
|
||||
dev-encoder
|
||||
dev-stateless-decoder
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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>`.
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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``
|
||||
|
@ -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
|
||||
============
|
||||
|
@ -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
|
||||
|
64
MAINTAINERS
64
MAINTAINERS
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
@ -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) {}
|
||||
|
@ -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")
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,2 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-y += core/ platform/ usb/
|
||||
obj-y += core/ i2c/ platform/ usb/
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
14
drivers/media/cec/i2c/Kconfig
Normal file
14
drivers/media/cec/i2c/Kconfig
Normal 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.
|
5
drivers/media/cec/i2c/Makefile
Normal file
5
drivers/media/cec/i2c/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the CEC I2C device drivers.
|
||||
#
|
||||
obj-$(CONFIG_CEC_CH7322) += ch7322.o
|
604
drivers/media/cec/i2c/ch7322.c
Normal file
604
drivers/media/cec/i2c/ch7322.c
Normal 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");
|
@ -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,
|
||||
|
@ -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
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
554
drivers/media/i2c/dw9768.c
Normal 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");
|
@ -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
341
drivers/media/i2c/max9271.c
Normal 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
224
drivers/media/i2c/max9271.h
Normal 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
1320
drivers/media/i2c/max9286.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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, ®map_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,
|
||||
|
@ -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
667
drivers/media/i2c/rdacm20.c
Normal 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");
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user