media updates for v6.6-rc1
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmTxzmEACgkQCF8+vY7k 4RWP6A/+Ljbwdoq92qOcaKAG2h2HzJa/H+xKMQwqIYjpbXnjNuFD2S9FCRfhNa9b Pt4K2g4lH2IJvYiJ3qhBbMxV8GPmovnHFX5LvyTFpRmrtZBAKp+TPXpbPt+a2/WL IPfQ0I52/c/JNqhm3fnmKgpXorp0wHYNbfY/LXztslimZj95+t0qjW62BoBmsJ3s hR+j/Xlgnd+9gld1OqX6OndH3mpeqDzBl4KZatQzw6yuIo8SK0ASEpu/vzgZoVy+ WiBtbzMuta2ZghnEHbnCkurwBSU/oLXhBmXsgp+Zdy0gglSk1RBdxM+3O65OVQt3 CCWSXMS0vGOk6JiogMpcPzO5piaUePcHEIjgAaaepTOzbKaf6PbEd9dj73LT9qcx 4TYFtGaDDhyDU4nzKTngfNiwmYrL1h+NuG119ZLHfrdH3MT7itIaydwFJRqLC+6D 7K6/1H2LKq25i+hRp5ZK2pgv0dAJw/nSdwFGFVgWM3Tuyt5dGdL/4SlZO4nIFKF2 pPWJUTJJP/0t9GUtwWmCh1fdgDr0A6Zg5M2OduyhC/YkqyLuD/02Bb4aR8hzloPj pym+94/PFaT5S7zvKywpvyIc8U+87/M2tw+mAPN2r3i4c0RFJa7CkyKqlKTKFw13 jw7NLLlrRbZ3a3zlhpJVqGLKgF2FlWudLUo4Y4kddWvxTMbwYXs= =yuz5 -----END PGP SIGNATURE----- Merge tag 'media/v6.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media updates from Mauro Carvalho Chehab: - new i2c drivers: ds90ub913, ds90ub953, ds90ub960, dw9719, ds90ub913 - new Intel IVSC MEI drivers - some Mediatek platform drivers were moved to a common location - Intel atomisp2 driver is now working with the main ov2680 driver. Due to that, the atomisp2 ov2680 staging one was removed - the bttv driver was finally converted to videobuf2 framework. This was the last one upstream using videobuf version 1 core. We'll likely remove the old videobuf framework on 6.7 - lots of improvements at atomisp driver: it now works with normal I2C sensors. Several compile-mode dependecies to select between ISP2400 and ISP2401 are now solved in runtime - a new ipu-bridge logic was added to work with IVSC MEI drivers - venus driver gained better support for new VPU versions - the v4l core async framework has gained lots of improvements and cleanups - lots of other cleanups, improvements and driver fixes * tag 'media/v6.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (358 commits) media: ivsc: Add ACPI dependency media: bttv: convert to vb2 media: bttv: use audio defaults for winfast2000 media: bttv: refactor bttv_set_dma() media: bttv: move vbi_skip/vbi_count out of buffer media: bttv: remove crop info from bttv_buffer media: bttv: remove tvnorm field from bttv_buffer media: bttv: remove format field from bttv_buffer media: bttv: move do_crop flag out of bttv_fh media: bttv: copy vbi_fmt from bttv_fh media: bttv: copy vid fmt/width/height from fh media: bttv: radio use v4l2_fh instead of bttv_fh media: bttv: replace BUG with WARN_ON media: bttv: use video_drvdata to get bttv media: i2c: rdacm21: Fix uninitialized value media: coda: Remove duplicated include media: vivid: fix the racy dev->radio_tx_rds_owner media: i2c: ccs: Check rules is non-NULL media: i2c: ds90ub960: Fix PLL config for 1200 MHz CSI rate media: i2c: ds90ub953: Fix use of uninitialized variables ...
This commit is contained in:
commit
307d59039f
@ -18,7 +18,7 @@ The driver implements V4L2, Media controller and V4L2 subdev interfaces.
|
||||
Camera sensor using V4L2 subdev interface in the kernel is supported.
|
||||
|
||||
The driver is implemented using as a reference the Qualcomm Camera Subsystem
|
||||
driver for Android as found in Code Aurora [#f1]_ [#f2]_.
|
||||
driver for Android as found in Code Linaro [#f1]_ [#f2]_.
|
||||
|
||||
|
||||
Qualcomm Camera Subsystem hardware
|
||||
@ -181,5 +181,5 @@ Referenced 2018-06-22.
|
||||
References
|
||||
----------
|
||||
|
||||
.. [#f1] https://source.codeaurora.org/quic/la/kernel/msm-3.10/
|
||||
.. [#f2] https://source.codeaurora.org/quic/la/kernel/msm-3.18/
|
||||
.. [#f1] https://git.codelinaro.org/clo/la/kernel/msm-3.10/
|
||||
.. [#f2] https://git.codelinaro.org/clo/la/kernel/msm-3.18/
|
||||
|
34
Documentation/devicetree/bindings/i2c/i2c-atr.yaml
Normal file
34
Documentation/devicetree/bindings/i2c/i2c-atr.yaml
Normal file
@ -0,0 +1,34 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/i2c-atr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common i2c address translator properties
|
||||
|
||||
maintainers:
|
||||
- Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
description:
|
||||
An I2C Address Translator (ATR) is a device with an I2C slave parent
|
||||
("upstream") port and N I2C master child ("downstream") ports, and
|
||||
forwards transactions from upstream to the appropriate downstream port
|
||||
with a modified slave address. The address used on the parent bus is
|
||||
called the "alias" and is (potentially) different from the physical
|
||||
slave address of the child bus. Address translation is done by the
|
||||
hardware.
|
||||
|
||||
properties:
|
||||
i2c-alias-pool:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
I2C alias pool is a pool of I2C addresses on the main I2C bus that can be
|
||||
used to access the remote peripherals on the serializer's I2C bus. The
|
||||
addresses must be available, not used by any other peripheral. Each
|
||||
remote peripheral is assigned an alias from the pool, and transactions to
|
||||
that address will be forwarded to the remote peripheral, with the address
|
||||
translated to the remote peripheral's real address. This property is not
|
||||
needed if there are no I2C addressable remote peripherals.
|
||||
|
||||
additionalProperties: true
|
||||
...
|
@ -47,7 +47,7 @@ patternProperties:
|
||||
$ref: ../mailbox/fsl,mu.yaml#
|
||||
|
||||
|
||||
"^vpu_core@[0-9a-f]+$":
|
||||
"^vpu-core@[0-9a-f]+$":
|
||||
description:
|
||||
Each core correspond a decoder or encoder, need to configure them
|
||||
separately. NXP i.MX8QM SoC has one decoder and two encoder, i.MX8QXP SoC
|
||||
@ -143,7 +143,7 @@ examples:
|
||||
power-domains = <&pd IMX_SC_R_VPU_MU_2>;
|
||||
};
|
||||
|
||||
vpu_core0: vpu_core@2d080000 {
|
||||
vpu_core0: vpu-core@2d080000 {
|
||||
compatible = "nxp,imx8q-vpu-decoder";
|
||||
reg = <0x2d080000 0x10000>;
|
||||
power-domains = <&pd IMX_SC_R_VPU_DEC_0>;
|
||||
@ -154,7 +154,7 @@ examples:
|
||||
memory-region = <&decoder_boot>, <&decoder_rpc>;
|
||||
};
|
||||
|
||||
vpu_core1: vpu_core@2d090000 {
|
||||
vpu_core1: vpu-core@2d090000 {
|
||||
compatible = "nxp,imx8q-vpu-encoder";
|
||||
reg = <0x2d090000 0x10000>;
|
||||
power-domains = <&pd IMX_SC_R_VPU_ENC_0>;
|
||||
@ -165,7 +165,7 @@ examples:
|
||||
memory-region = <&encoder1_boot>, <&encoder1_rpc>;
|
||||
};
|
||||
|
||||
vpu_core2: vpu_core@2d0a0000 {
|
||||
vpu_core2: vpu-core@2d0a0000 {
|
||||
reg = <0x2d0a0000 0x10000>;
|
||||
compatible = "nxp,imx8q-vpu-encoder";
|
||||
power-domains = <&pd IMX_SC_R_VPU_ENC_1>;
|
||||
|
@ -1,100 +0,0 @@
|
||||
Cadence MIPI-CSI2 RX controller
|
||||
===============================
|
||||
|
||||
The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI
|
||||
lanes in input, and 4 different pixel streams in output.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be set to "cdns,csi2rx" and an SoC-specific compatible
|
||||
- reg: base address and size of the memory mapped region
|
||||
- clocks: phandles to the clocks driving the controller
|
||||
- clock-names: must contain:
|
||||
* sys_clk: main clock
|
||||
* p_clk: register bank clock
|
||||
* pixel_if[0-3]_clk: pixel stream output clock, one for each stream
|
||||
implemented in hardware, between 0 and 3
|
||||
|
||||
Optional properties:
|
||||
- phys: phandle to the external D-PHY, phy-names must be provided
|
||||
- phy-names: must contain "dphy", if the implementation uses an
|
||||
external D-PHY
|
||||
|
||||
Required subnodes:
|
||||
- ports: A ports node with one port child node per device input and output
|
||||
port, in accordance with the video interface bindings defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
port nodes are numbered as follows:
|
||||
|
||||
Port Description
|
||||
-----------------------------
|
||||
0 CSI-2 input
|
||||
1 Stream 0 output
|
||||
2 Stream 1 output
|
||||
3 Stream 2 output
|
||||
4 Stream 3 output
|
||||
|
||||
The stream output port nodes are optional if they are not
|
||||
connected to anything at the hardware level or implemented
|
||||
in the design.Since there is only one endpoint per port,
|
||||
the endpoints are not numbered.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
csi2rx: csi-bridge@0d060000 {
|
||||
compatible = "cdns,csi2rx";
|
||||
reg = <0x0d060000 0x1000>;
|
||||
clocks = <&byteclock>, <&byteclock>
|
||||
<&coreclock>, <&coreclock>,
|
||||
<&coreclock>, <&coreclock>;
|
||||
clock-names = "sys_clk", "p_clk",
|
||||
"pixel_if0_clk", "pixel_if1_clk",
|
||||
"pixel_if2_clk", "pixel_if3_clk";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
csi2rx_in_sensor: endpoint {
|
||||
remote-endpoint = <&sensor_out_csi2rx>;
|
||||
clock-lanes = <0>;
|
||||
data-lanes = <1 2>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
csi2rx_out_grabber0: endpoint {
|
||||
remote-endpoint = <&grabber0_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
csi2rx_out_grabber1: endpoint {
|
||||
remote-endpoint = <&grabber1_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
csi2rx_out_grabber2: endpoint {
|
||||
remote-endpoint = <&grabber2_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
|
||||
csi2rx_out_grabber3: endpoint {
|
||||
remote-endpoint = <&grabber3_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
201
Documentation/devicetree/bindings/media/cdns,csi2rx.yaml
Normal file
201
Documentation/devicetree/bindings/media/cdns,csi2rx.yaml
Normal file
@ -0,0 +1,201 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/cdns,csi2rx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cadence MIPI-CSI2 RX controller
|
||||
|
||||
maintainers:
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description:
|
||||
The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI
|
||||
lanes in input, and 4 different pixel streams in output.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- starfive,jh7110-csi2rx
|
||||
- const: cdns,csi2rx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: CSI2Rx system clock
|
||||
- description: Gated Register bank clock for APB interface
|
||||
- description: pixel Clock for Stream interface 0
|
||||
- description: pixel Clock for Stream interface 1
|
||||
- description: pixel Clock for Stream interface 2
|
||||
- description: pixel Clock for Stream interface 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: sys_clk
|
||||
- const: p_clk
|
||||
- const: pixel_if0_clk
|
||||
- const: pixel_if1_clk
|
||||
- const: pixel_if2_clk
|
||||
- const: pixel_if3_clk
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: CSI2Rx system reset
|
||||
- description: Gated Register bank reset for APB interface
|
||||
- description: pixel reset for Stream interface 0
|
||||
- description: pixel reset for Stream interface 1
|
||||
- description: pixel reset for Stream interface 2
|
||||
- description: pixel reset for Stream interface 3
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: sys
|
||||
- const: reg_bank
|
||||
- const: pixel_if0
|
||||
- const: pixel_if1
|
||||
- const: pixel_if2
|
||||
- const: pixel_if3
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
description: MIPI D-PHY
|
||||
|
||||
phy-names:
|
||||
items:
|
||||
- const: dphy
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Input port node, single endpoint describing the CSI-2 transmitter.
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
bus-type:
|
||||
const: 4
|
||||
|
||||
clock-lanes:
|
||||
const: 0
|
||||
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
maximum: 4
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Stream 0 Output port node
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Stream 1 Output port node
|
||||
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Stream 2 Output port node
|
||||
|
||||
port@4:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Stream 3 Output port node
|
||||
|
||||
required:
|
||||
- port@0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
csi@d060000 {
|
||||
compatible = "starfive,jh7110-csi2rx", "cdns,csi2rx";
|
||||
reg = <0x0d060000 0x1000>;
|
||||
clocks = <&byteclock 7>, <&byteclock 6>,
|
||||
<&coreclock 8>, <&coreclock 9>,
|
||||
<&coreclock 10>, <&coreclock 11>;
|
||||
clock-names = "sys_clk", "p_clk",
|
||||
"pixel_if0_clk", "pixel_if1_clk",
|
||||
"pixel_if2_clk", "pixel_if3_clk";
|
||||
resets = <&bytereset 9>, <&bytereset 4>,
|
||||
<&corereset 5>, <&corereset 6>,
|
||||
<&corereset 7>, <&corereset 8>;
|
||||
reset-names = "sys", "reg_bank",
|
||||
"pixel_if0", "pixel_if1",
|
||||
"pixel_if2", "pixel_if3";
|
||||
phys = <&csi_phy>;
|
||||
phy-names = "dphy";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
csi2rx_in_sensor: endpoint {
|
||||
remote-endpoint = <&sensor_out_csi2rx>;
|
||||
clock-lanes = <0>;
|
||||
data-lanes = <1 2>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
csi2rx_out_grabber0: endpoint {
|
||||
remote-endpoint = <&grabber0_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
csi2rx_out_grabber1: endpoint {
|
||||
remote-endpoint = <&grabber1_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
csi2rx_out_grabber2: endpoint {
|
||||
remote-endpoint = <&grabber2_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
|
||||
csi2rx_out_grabber3: endpoint {
|
||||
remote-endpoint = <&grabber3_in_csi2rx>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -53,6 +53,5 @@ examples:
|
||||
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&tegra_car TEGRA124_CLK_CEC>;
|
||||
clock-names = "cec";
|
||||
status = "disabled";
|
||||
hdmi-phandle = <&hdmi>;
|
||||
};
|
||||
|
@ -143,7 +143,6 @@ examples:
|
||||
mipid02: csi2rx@14 {
|
||||
compatible = "st,st-mipid02";
|
||||
reg = <0x14>;
|
||||
status = "okay";
|
||||
clocks = <&clk_ext_camera_12>;
|
||||
clock-names = "xclk";
|
||||
VDDE-supply = <&vdd>;
|
||||
|
133
Documentation/devicetree/bindings/media/i2c/ti,ds90ub913.yaml
Normal file
133
Documentation/devicetree/bindings/media/i2c/ti,ds90ub913.yaml
Normal file
@ -0,0 +1,133 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/ti,ds90ub913.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DS90UB913 FPD-Link III Serializer
|
||||
|
||||
maintainers:
|
||||
- Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
description:
|
||||
The TI DS90UB913 is an FPD-Link III video serializer for parallel video.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,ds90ub913a-q1
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
description:
|
||||
First cell is the GPO pin number, second cell is the flags. The GPO pin
|
||||
number must be in range of [0, 3]. Note that GPOs 2 and 3 are not
|
||||
available in external oscillator mode.
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Reference clock connected to the CLKIN pin.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: clkin
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: Parallel input port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- pclk-sample
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link III output port
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
i2c:
|
||||
$ref: /schemas/i2c/i2c-controller.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#gpio-cells'
|
||||
- gpio-controller
|
||||
- '#clock-cells'
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
serializer {
|
||||
compatible = "ti,ds90ub913a-q1";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
clocks = <&clk_cam_48M>;
|
||||
clock-names = "clkin";
|
||||
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ub913_in: endpoint {
|
||||
remote-endpoint = <&sensor_out>;
|
||||
pclk-sample = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
endpoint {
|
||||
remote-endpoint = <&deser_fpd_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@48 {
|
||||
compatible = "aptina,mt9v111";
|
||||
reg = <0x48>;
|
||||
|
||||
clocks = <&fixed_clock>;
|
||||
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
remote-endpoint = <&ub913_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
134
Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml
Normal file
134
Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml
Normal file
@ -0,0 +1,134 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/ti,ds90ub953.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DS90UB953 FPD-Link III Serializer
|
||||
|
||||
maintainers:
|
||||
- Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
description:
|
||||
The TI DS90UB953 is an FPD-Link III video serializer for MIPI CSI-2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,ds90ub953-q1
|
||||
- ti,ds90ub971-q1
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
description:
|
||||
First cell is the GPIO pin number, second cell is the flags. The GPIO pin
|
||||
number must be in range of [0, 3].
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Reference clock connected to the CLKIN pin.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: clkin
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: CSI-2 input port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link III output port
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
i2c:
|
||||
$ref: /schemas/i2c/i2c-controller.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#gpio-cells'
|
||||
- gpio-controller
|
||||
- '#clock-cells'
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
serializer {
|
||||
compatible = "ti,ds90ub953-q1";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ub953_in: endpoint {
|
||||
clock-lanes = <0>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
remote-endpoint = <&sensor_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
endpoint {
|
||||
remote-endpoint = <&deser_fpd_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@1a {
|
||||
compatible = "sony,imx274";
|
||||
reg = <0x1a>;
|
||||
|
||||
reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
clocks = <&serializer>;
|
||||
clock-names = "inck";
|
||||
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
remote-endpoint = <&ub953_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
427
Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml
Normal file
427
Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml
Normal file
@ -0,0 +1,427 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/ti,ds90ub960.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DS90UB9XX Family FPD-Link Deserializer Hubs
|
||||
|
||||
maintainers:
|
||||
- Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
description:
|
||||
The TI DS90UB9XX devices are FPD-Link video deserializers with I2C and GPIO
|
||||
forwarding.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-atr.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,ds90ub960-q1
|
||||
- ti,ds90ub9702-q1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Reference clock connected to the REFCLK pin.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: refclk
|
||||
|
||||
powerdown-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
Specifier for the GPIO connected to the PDB pin.
|
||||
|
||||
i2c-alias-pool:
|
||||
minItems: 1
|
||||
maxItems: 32
|
||||
|
||||
links:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
ti,manual-strobe:
|
||||
type: boolean
|
||||
description:
|
||||
Enable manual strobe position and EQ level
|
||||
|
||||
patternProperties:
|
||||
'^link@[0-3]$':
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
reg:
|
||||
description: The link number
|
||||
maxItems: 1
|
||||
|
||||
i2c-alias:
|
||||
description:
|
||||
The I2C address used for the serializer. Transactions to this
|
||||
address on the I2C bus where the deserializer resides are
|
||||
forwarded to the serializer.
|
||||
|
||||
ti,rx-mode:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # RAW10
|
||||
- 1 # RAW12 HF
|
||||
- 2 # RAW12 LF
|
||||
- 3 # CSI2 SYNC
|
||||
- 4 # CSI2 NON-SYNC
|
||||
description:
|
||||
FPD-Link Input Mode. This should reflect the hardware and the
|
||||
default mode of the connected device.
|
||||
|
||||
ti,cdr-mode:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # FPD-Link III
|
||||
- 1 # FPD-Link IV
|
||||
description:
|
||||
FPD-Link CDR Mode. This should reflect the hardware and the
|
||||
default mode of the connected device.
|
||||
|
||||
ti,strobe-pos:
|
||||
$ref: /schemas/types.yaml#/definitions/int32
|
||||
minimum: -13
|
||||
maximum: 13
|
||||
description: Manual strobe position
|
||||
|
||||
ti,eq-level:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 14
|
||||
description: Manual EQ level
|
||||
|
||||
serializer:
|
||||
type: object
|
||||
description: FPD-Link Serializer node
|
||||
|
||||
required:
|
||||
- reg
|
||||
- i2c-alias
|
||||
- ti,rx-mode
|
||||
- serializer
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link input 0
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Endpoint for FPD-Link port. If the RX mode for this port is RAW,
|
||||
hsync-active and vsync-active must be defined.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link input 1
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Endpoint for FPD-Link port. If the RX mode for this port is RAW,
|
||||
hsync-active and vsync-active must be defined.
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link input 2
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Endpoint for FPD-Link port. If the RX mode for this port is RAW,
|
||||
hsync-active and vsync-active must be defined.
|
||||
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: FPD-Link input 3
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Endpoint for FPD-Link port. If the RX mode for this port is RAW,
|
||||
hsync-active and vsync-active must be defined.
|
||||
|
||||
port@4:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: CSI-2 Output 0
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
link-frequencies:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
port@5:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: CSI-2 Output 1
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
link-frequencies:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
- port@3
|
||||
- port@4
|
||||
- port@5
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- ports
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
deser@3d {
|
||||
compatible = "ti,ds90ub960-q1";
|
||||
reg = <0x3d>;
|
||||
|
||||
clock-names = "refclk";
|
||||
clocks = <&fixed_clock>;
|
||||
|
||||
powerdown-gpios = <&pca9555 7 GPIO_ACTIVE_LOW>;
|
||||
|
||||
i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* Port 0, Camera 0 */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
ub960_fpd3_1_in: endpoint {
|
||||
remote-endpoint = <&ub953_1_out>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Port 1, Camera 1 */
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
ub960_fpd3_2_in: endpoint {
|
||||
remote-endpoint = <&ub913_2_out>;
|
||||
hsync-active = <0>;
|
||||
vsync-active = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Port 2, unconnected */
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
|
||||
/* Port 3, unconnected */
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
};
|
||||
|
||||
/* Port 4, CSI-2 TX */
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
ds90ub960_0_csi_out: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <800000000>;
|
||||
remote-endpoint = <&csi2_phy0>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Port 5, unconnected */
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
};
|
||||
};
|
||||
|
||||
links {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* Link 0 has DS90UB953 serializer and IMX274 sensor */
|
||||
|
||||
link@0 {
|
||||
reg = <0>;
|
||||
i2c-alias = <0x44>;
|
||||
|
||||
ti,rx-mode = <3>;
|
||||
|
||||
serializer1: serializer {
|
||||
compatible = "ti,ds90ub953-q1";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ub953_1_in: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
remote-endpoint = <&sensor_1_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
ub953_1_out: endpoint {
|
||||
remote-endpoint = <&ub960_fpd3_1_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@1a {
|
||||
compatible = "sony,imx274";
|
||||
reg = <0x1a>;
|
||||
|
||||
reset-gpios = <&serializer1 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
sensor_1_out: endpoint {
|
||||
remote-endpoint = <&ub953_1_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}; /* End of link@0 */
|
||||
|
||||
/* Link 1 has DS90UB913 serializer and MT9V111 sensor */
|
||||
|
||||
link@1 {
|
||||
reg = <1>;
|
||||
i2c-alias = <0x45>;
|
||||
|
||||
ti,rx-mode = <0>;
|
||||
|
||||
serializer2: serializer {
|
||||
compatible = "ti,ds90ub913a-q1";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
clocks = <&clk_cam_48M>;
|
||||
clock-names = "clkin";
|
||||
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ub913_2_in: endpoint {
|
||||
remote-endpoint = <&sensor_2_out>;
|
||||
pclk-sample = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
ub913_2_out: endpoint {
|
||||
remote-endpoint = <&ub960_fpd3_2_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@48 {
|
||||
compatible = "aptina,mt9v111";
|
||||
reg = <0x48>;
|
||||
|
||||
clocks = <&serializer2>;
|
||||
|
||||
port {
|
||||
sensor_2_out: endpoint {
|
||||
remote-endpoint = <&ub913_2_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}; /* End of link@1 */
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -21,24 +21,33 @@ properties:
|
||||
- mediatek,mt8183-vcodec-dec
|
||||
|
||||
reg:
|
||||
maxItems: 12
|
||||
minItems: 11
|
||||
maxItems: 11
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: misc
|
||||
- const: ld
|
||||
- const: top
|
||||
- const: cm
|
||||
- const: ad
|
||||
- const: av
|
||||
- const: pp
|
||||
- const: hwd
|
||||
- const: hwq
|
||||
- const: hwb
|
||||
- const: hwg
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 8
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: vcodecpll
|
||||
- const: univpll_d2
|
||||
- const: clk_cci400_sel
|
||||
- const: vdec_sel
|
||||
- const: vdecpll
|
||||
- const: vencpll
|
||||
- const: venc_lt_sel
|
||||
- const: vdec_bus_clk_src
|
||||
minItems: 1
|
||||
maxItems: 8
|
||||
|
||||
assigned-clocks: true
|
||||
|
||||
@ -66,6 +75,10 @@ properties:
|
||||
description:
|
||||
Describes point to scp.
|
||||
|
||||
mediatek,vdecsys:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the vdecsys syscon node.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -73,8 +86,7 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- iommus
|
||||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
- mediatek,vdecsys
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
@ -88,6 +100,15 @@ allOf:
|
||||
required:
|
||||
- mediatek,scp
|
||||
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: vdec
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
@ -99,6 +120,22 @@ allOf:
|
||||
required:
|
||||
- mediatek,vpu
|
||||
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 8
|
||||
maxItems: 8
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: vcodecpll
|
||||
- const: univpll_d2
|
||||
- const: clk_cci400_sel
|
||||
- const: vdec_sel
|
||||
- const: vdecpll
|
||||
- const: vencpll
|
||||
- const: venc_lt_sel
|
||||
- const: vdec_bus_clk_src
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -109,10 +146,9 @@ examples:
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
|
||||
vcodec_dec: vcodec@16000000 {
|
||||
vcodec_dec: vcodec@16020000 {
|
||||
compatible = "mediatek,mt8173-vcodec-dec";
|
||||
reg = <0x16000000 0x100>, /*VDEC_SYS*/
|
||||
<0x16020000 0x1000>, /*VDEC_MISC*/
|
||||
reg = <0x16020000 0x1000>, /*VDEC_MISC*/
|
||||
<0x16021000 0x800>, /*VDEC_LD*/
|
||||
<0x16021800 0x800>, /*VDEC_TOP*/
|
||||
<0x16022000 0x1000>, /*VDEC_CM*/
|
||||
@ -133,6 +169,7 @@ examples:
|
||||
<&iommu M4U_PORT_HW_VDEC_VLD_EXT>,
|
||||
<&iommu M4U_PORT_HW_VDEC_VLD2_EXT>;
|
||||
mediatek,vpu = <&vpu>;
|
||||
mediatek,vdecsys = <&vdecsys>;
|
||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>,
|
||||
<&topckgen CLK_TOP_UNIVPLL_D2>,
|
||||
|
@ -21,6 +21,7 @@ properties:
|
||||
enum:
|
||||
- fsl,imx8mn-isi
|
||||
- fsl,imx8mp-isi
|
||||
- fsl,imx93-isi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -72,7 +73,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx8mn-isi
|
||||
enum:
|
||||
- fsl,imx8mn-isi
|
||||
- fsl,imx93-isi
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
@ -109,9 +109,11 @@ your driver:
|
||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||
void (*adap_configured)(struct cec_adapter *adap, bool configured);
|
||||
void (*adap_unconfigured)(struct cec_adapter *adap);
|
||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg);
|
||||
void (*adap_nb_transmit_canceled)(struct cec_adapter *adap,
|
||||
const struct cec_msg *msg);
|
||||
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
||||
void (*adap_free)(struct cec_adapter *adap);
|
||||
|
||||
@ -122,8 +124,8 @@ your driver:
|
||||
...
|
||||
};
|
||||
|
||||
The seven low-level ops deal with various aspects of controlling the CEC adapter
|
||||
hardware:
|
||||
These low-level ops deal with various aspects of controlling the CEC adapter
|
||||
hardware. They are all called with the mutex adap->lock held.
|
||||
|
||||
|
||||
To enable/disable the hardware::
|
||||
@ -179,14 +181,12 @@ can receive directed messages to that address.
|
||||
Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID.
|
||||
|
||||
|
||||
Called when the adapter is fully configured or unconfigured::
|
||||
Called when the adapter is unconfigured::
|
||||
|
||||
void (*adap_configured)(struct cec_adapter *adap, bool configured);
|
||||
void (*adap_unconfigured)(struct cec_adapter *adap);
|
||||
|
||||
If configured == true, then the adapter is fully configured, i.e. all logical
|
||||
addresses have been successfully claimed. If configured == false, then the
|
||||
adapter is unconfigured. If the driver has to take specific actions after
|
||||
(un)configuration, then that can be done through this optional callback.
|
||||
The adapter is unconfigured. If the driver has to take specific actions after
|
||||
unconfiguration, then that can be done through this optional callback.
|
||||
|
||||
|
||||
To transmit a new message::
|
||||
@ -207,6 +207,19 @@ The CEC_FREE_TIME_TO_USEC macro can be used to convert signal_free_time to
|
||||
microseconds (one data bit period is 2.4 ms).
|
||||
|
||||
|
||||
To pass on the result of a canceled non-blocking transmit::
|
||||
|
||||
void (*adap_nb_transmit_canceled)(struct cec_adapter *adap,
|
||||
const struct cec_msg *msg);
|
||||
|
||||
This optional callback can be used to obtain the result of a canceled
|
||||
non-blocking transmit with sequence number msg->sequence. This is
|
||||
called if the transmit was aborted, the transmit timed out (i.e. the
|
||||
hardware never signaled that the transmit finished), or the transmit
|
||||
was successful, but the wait for the expected reply was either aborted
|
||||
or it timed out.
|
||||
|
||||
|
||||
To log the current CEC hardware status::
|
||||
|
||||
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
||||
@ -372,7 +385,8 @@ Implementing the High-Level CEC Adapter
|
||||
---------------------------------------
|
||||
|
||||
The low-level operations drive the hardware, the high-level operations are
|
||||
CEC protocol driven. The following high-level callbacks are available:
|
||||
CEC protocol driven. The high-level callbacks are called without the adap->lock
|
||||
mutex being held. The following high-level callbacks are available:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@ -384,9 +398,19 @@ CEC protocol driven. The following high-level callbacks are available:
|
||||
...
|
||||
|
||||
/* High-level CEC message callback */
|
||||
void (*configured)(struct cec_adapter *adap);
|
||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
||||
};
|
||||
|
||||
Called when the adapter is configured::
|
||||
|
||||
void (*configured)(struct cec_adapter *adap);
|
||||
|
||||
The adapter is fully configured, i.e. all logical addresses have been
|
||||
successfully claimed. If the driver has to take specific actions after
|
||||
configuration, then that can be done through this optional callback.
|
||||
|
||||
|
||||
The received() callback allows the driver to optionally handle a newly
|
||||
received CEC message::
|
||||
|
||||
|
5
Documentation/driver-api/media/v4l2-cci.rst
Normal file
5
Documentation/driver-api/media/v4l2-cci.rst
Normal file
@ -0,0 +1,5 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
V4L2 CCI kAPI
|
||||
^^^^^^^^^^^^^
|
||||
.. kernel-doc:: include/media/v4l2-cci.h
|
@ -22,6 +22,7 @@ Video4Linux devices
|
||||
v4l2-mem2mem
|
||||
v4l2-async
|
||||
v4l2-fwnode
|
||||
v4l2-cci
|
||||
v4l2-rect
|
||||
v4l2-tuner
|
||||
v4l2-common
|
||||
|
@ -157,6 +157,9 @@ below.
|
||||
Using one or the other registration method only affects the probing process, the
|
||||
run-time bridge-subdevice interaction is in both cases the same.
|
||||
|
||||
Registering synchronous sub-devices
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the **synchronous** case a device (bridge) driver needs to register the
|
||||
:c:type:`v4l2_subdev` with the v4l2_device:
|
||||
|
||||
@ -175,10 +178,12 @@ You can unregister a sub-device using:
|
||||
:c:func:`v4l2_device_unregister_subdev <v4l2_device_unregister_subdev>`
|
||||
(:c:type:`sd <v4l2_subdev>`).
|
||||
|
||||
|
||||
Afterwards the subdev module can be unloaded and
|
||||
:c:type:`sd <v4l2_subdev>`->dev == ``NULL``.
|
||||
|
||||
Registering asynchronous sub-devices
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the **asynchronous** case subdevice probing can be invoked independently of
|
||||
the bridge driver availability. The subdevice driver then has to verify whether
|
||||
all the requirements for a successful probing are satisfied. This can include a
|
||||
@ -190,64 +195,89 @@ performed using the :c:func:`v4l2_async_unregister_subdev` call. Subdevices
|
||||
registered this way are stored in a global list of subdevices, ready to be
|
||||
picked up by bridge drivers.
|
||||
|
||||
Bridge drivers in turn have to register a notifier object. This is
|
||||
performed using the :c:func:`v4l2_async_nf_register` call. To
|
||||
unregister the notifier the driver has to call
|
||||
:c:func:`v4l2_async_nf_unregister`. The former of the two functions
|
||||
takes two arguments: a pointer to struct :c:type:`v4l2_device` and a
|
||||
pointer to struct :c:type:`v4l2_async_notifier`.
|
||||
Asynchronous sub-device notifiers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Bridge drivers in turn have to register a notifier object. This is performed
|
||||
using the :c:func:`v4l2_async_nf_register` call. To unregister the notifier the
|
||||
driver has to call :c:func:`v4l2_async_nf_unregister`. Before releasing memory
|
||||
of an unregister notifier, it must be cleaned up by calling
|
||||
:c:func:`v4l2_async_nf_cleanup`.
|
||||
|
||||
Before registering the notifier, bridge drivers must do two things: first, the
|
||||
notifier must be initialized using the :c:func:`v4l2_async_nf_init`.
|
||||
Second, bridge drivers can then begin to form a list of subdevice descriptors
|
||||
that the bridge device needs for its operation. Several functions are available
|
||||
to add subdevice descriptors to a notifier, depending on the type of device and
|
||||
the needs of the driver.
|
||||
notifier must be initialized using the :c:func:`v4l2_async_nf_init`. Second,
|
||||
bridge drivers can then begin to form a list of async connection descriptors
|
||||
that the bridge device needs for its
|
||||
operation. :c:func:`v4l2_async_nf_add_fwnode`,
|
||||
:c:func:`v4l2_async_nf_add_fwnode_remote` and :c:func:`v4l2_async_nf_add_i2c`
|
||||
|
||||
:c:func:`v4l2_async_nf_add_fwnode_remote` and
|
||||
:c:func:`v4l2_async_nf_add_i2c` are for bridge and ISP drivers for
|
||||
registering their async sub-devices with the notifier.
|
||||
Async connection descriptors describe connections to external sub-devices the
|
||||
drivers for which are not yet probed. Based on an async connection, a media data
|
||||
or ancillary link may be created when the related sub-device becomes
|
||||
available. There may be one or more async connections to a given sub-device but
|
||||
this is not known at the time of adding the connections to the notifier. Async
|
||||
connections are bound as matching async sub-devices are found, one by one.
|
||||
|
||||
:c:func:`v4l2_async_register_subdev_sensor` is a helper function for
|
||||
sensor drivers registering their own async sub-device, but it also registers a
|
||||
notifier and further registers async sub-devices for lens and flash devices
|
||||
found in firmware. The notifier for the sub-device is unregistered with the
|
||||
async sub-device.
|
||||
Asynchronous sub-device notifier for sub-devices
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These functions allocate an async sub-device descriptor which is of type struct
|
||||
:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
|
||||
:c:type:`v4l2_async_subdev` shall be the first member of this struct:
|
||||
A driver that registers an asynchronous sub-device may also register an
|
||||
asynchronous notifier. This is called an asynchronous sub-device notifier andthe
|
||||
process is similar to that of a bridge driver apart from that the notifier is
|
||||
initialised using :c:func:`v4l2_async_subdev_nf_init` instead. A sub-device
|
||||
notifier may complete only after the V4L2 device becomes available, i.e. there's
|
||||
a path via async sub-devices and notifiers to a notifier that is not an
|
||||
asynchronous sub-device notifier.
|
||||
|
||||
Asynchronous sub-device registration helper for camera sensor drivers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:c:func:`v4l2_async_register_subdev_sensor` is a helper function for sensor
|
||||
drivers registering their own async connection, but it also registers a notifier
|
||||
and further registers async connections for lens and flash devices found in
|
||||
firmware. The notifier for the sub-device is unregistered and cleaned up with
|
||||
the async sub-device, using :c:func:`v4l2_async_unregister_subdev`.
|
||||
|
||||
Asynchronous sub-device notifier example
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These functions allocate an async connection descriptor which is of type struct
|
||||
:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
|
||||
:c:type:`v4l2_async_connection` shall be the first member of this struct:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct my_async_subdev {
|
||||
struct v4l2_async_subdev asd;
|
||||
struct my_async_connection {
|
||||
struct v4l2_async_connection asc;
|
||||
...
|
||||
};
|
||||
|
||||
struct my_async_subdev *my_asd;
|
||||
struct my_async_connection *my_asc;
|
||||
struct fwnode_handle *ep;
|
||||
|
||||
...
|
||||
|
||||
my_asd = v4l2_async_nf_add_fwnode_remote(¬ifier, ep,
|
||||
struct my_async_subdev);
|
||||
my_asc = v4l2_async_nf_add_fwnode_remote(¬ifier, ep,
|
||||
struct my_async_connection);
|
||||
fwnode_handle_put(ep);
|
||||
|
||||
if (IS_ERR(asd))
|
||||
return PTR_ERR(asd);
|
||||
if (IS_ERR(my_asc))
|
||||
return PTR_ERR(my_asc);
|
||||
|
||||
The V4L2 core will then use these descriptors to match asynchronously
|
||||
registered subdevices to them. If a match is detected the ``.bound()``
|
||||
notifier callback is called. After all subdevices have been located the
|
||||
.complete() callback is called. When a subdevice is removed from the
|
||||
system the .unbind() method is called. All three callbacks are optional.
|
||||
Asynchronous sub-device notifier callbacks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The V4L2 core will then use these connection descriptors to match asynchronously
|
||||
registered subdevices to them. If a match is detected the ``.bound()`` notifier
|
||||
callback is called. After all connections have been bound the .complete()
|
||||
callback is called. When a connection is removed from the system the
|
||||
``.unbind()`` method is called. All three callbacks are optional.
|
||||
|
||||
Drivers can store any type of custom data in their driver-specific
|
||||
:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
|
||||
:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
|
||||
handling when the structure is freed, drivers must implement the ``.destroy()``
|
||||
notifier callback. The framework will call it right before freeing the
|
||||
:c:type:`v4l2_async_subdev`.
|
||||
:c:type:`v4l2_async_connection`.
|
||||
|
||||
Calling subdev operations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
96
Documentation/i2c/i2c-address-translators.rst
Normal file
96
Documentation/i2c/i2c-address-translators.rst
Normal file
@ -0,0 +1,96 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=======================
|
||||
I2C Address Translators
|
||||
=======================
|
||||
|
||||
Author: Luca Ceresoli <luca@lucaceresoli.net>
|
||||
Author: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
An I2C Address Translator (ATR) is a device with an I2C slave parent
|
||||
("upstream") port and N I2C master child ("downstream") ports, and
|
||||
forwards transactions from upstream to the appropriate downstream port
|
||||
with a modified slave address. The address used on the parent bus is
|
||||
called the "alias" and is (potentially) different from the physical
|
||||
slave address of the child bus. Address translation is done by the
|
||||
hardware.
|
||||
|
||||
An ATR looks similar to an i2c-mux except:
|
||||
- the address on the parent and child busses can be different
|
||||
- there is normally no need to select the child port; the alias used on the
|
||||
parent bus implies it
|
||||
|
||||
The ATR functionality can be provided by a chip with many other features.
|
||||
The kernel i2c-atr provides a helper to implement an ATR within a driver.
|
||||
|
||||
The ATR creates a new I2C "child" adapter on each child bus. Adding
|
||||
devices on the child bus ends up in invoking the driver code to select
|
||||
an available alias. Maintaining an appropriate pool of available aliases
|
||||
and picking one for each new device is up to the driver implementer. The
|
||||
ATR maintains a table of currently assigned alias and uses it to modify
|
||||
all I2C transactions directed to devices on the child buses.
|
||||
|
||||
A typical example follows.
|
||||
|
||||
Topology::
|
||||
|
||||
Slave X @ 0x10
|
||||
.-----. |
|
||||
.-----. | |---+---- B
|
||||
| CPU |--A--| ATR |
|
||||
`-----' | |---+---- C
|
||||
`-----' |
|
||||
Slave Y @ 0x10
|
||||
|
||||
Alias table:
|
||||
|
||||
A, B and C are three physical I2C busses, electrically independent from
|
||||
each other. The ATR receives the transactions initiated on bus A and
|
||||
propagates them on bus B or bus C or none depending on the device address
|
||||
in the transaction and based on the alias table.
|
||||
|
||||
Alias table:
|
||||
|
||||
.. table::
|
||||
|
||||
=============== =====
|
||||
Client Alias
|
||||
=============== =====
|
||||
X (bus B, 0x10) 0x20
|
||||
Y (bus C, 0x10) 0x30
|
||||
=============== =====
|
||||
|
||||
Transaction:
|
||||
|
||||
- Slave X driver requests a transaction (on adapter B), slave address 0x10
|
||||
- ATR driver finds slave X is on bus B and has alias 0x20, rewrites
|
||||
messages with address 0x20, forwards to adapter A
|
||||
- Physical I2C transaction on bus A, slave address 0x20
|
||||
- ATR chip detects transaction on address 0x20, finds it in table,
|
||||
propagates transaction on bus B with address translated to 0x10,
|
||||
keeps clock streched on bus A waiting for reply
|
||||
- Slave X chip (on bus B) detects transaction at its own physical
|
||||
address 0x10 and replies normally
|
||||
- ATR chip stops clock stretching and forwards reply on bus A,
|
||||
with address translated back to 0x20
|
||||
- ATR driver receives the reply, rewrites messages with address 0x10
|
||||
as they were initially
|
||||
- Slave X driver gets back the msgs[], with reply and address 0x10
|
||||
|
||||
Usage:
|
||||
|
||||
1. In the driver (typically in the probe function) add an ATR by
|
||||
calling i2c_atr_new() passing attach/detach callbacks
|
||||
2. When the attach callback is called pick an appropriate alias,
|
||||
configure it in the chip and return the chosen alias in the
|
||||
alias_id parameter
|
||||
3. When the detach callback is called, deconfigure the alias from
|
||||
the chip and put the alias back in the pool for later usage
|
||||
|
||||
I2C ATR functions and data structures
|
||||
-------------------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/i2c-atr.h
|
@ -18,6 +18,7 @@ Introduction
|
||||
i2c-topology
|
||||
muxes/i2c-mux-gpio
|
||||
i2c-sysfs
|
||||
i2c-address-translators
|
||||
|
||||
Writing device drivers
|
||||
======================
|
||||
|
@ -277,7 +277,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``sizeimage``
|
||||
adjusted size of ``OUTPUT`` buffers.
|
||||
@ -311,7 +311,7 @@ Initialization
|
||||
``memory``
|
||||
follows standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
the actual number of buffers allocated.
|
||||
@ -339,7 +339,7 @@ Initialization
|
||||
``format``
|
||||
follows standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
adjusted to the number of allocated buffers.
|
||||
@ -410,7 +410,7 @@ Capture Setup
|
||||
``type``
|
||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``width``, ``height``
|
||||
frame buffer resolution for the decoded frames.
|
||||
@ -443,7 +443,7 @@ Capture Setup
|
||||
``target``
|
||||
set to ``V4L2_SEL_TGT_COMPOSE``.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||
the visible rectangle; it must fit within the frame buffer resolution
|
||||
@ -552,7 +552,7 @@ Capture Setup
|
||||
frame is written; defaults to ``V4L2_SEL_TGT_COMPOSE_DEFAULT``;
|
||||
read-only on hardware without additional compose/scaling capabilities.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||
the visible rectangle; it must fit within the frame buffer resolution
|
||||
@ -629,7 +629,7 @@ Capture Setup
|
||||
``memory``
|
||||
follows standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
actual number of buffers allocated.
|
||||
@ -668,7 +668,7 @@ Capture Setup
|
||||
a format representing the maximum framebuffer resolution to be
|
||||
accommodated by newly allocated buffers.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
adjusted to the number of allocated buffers.
|
||||
|
@ -115,8 +115,8 @@ Querying Capabilities
|
||||
|
||||
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`
|
||||
format in :c:type:`v4l2_frmivalenum` ``pixel_format`` and the resolution
|
||||
in :c:type:`v4l2_frmivalenum` ``width`` and :c:type:`v4l2_frmivalenum`
|
||||
``height``.
|
||||
|
||||
* Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a coded pixel
|
||||
@ -163,7 +163,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``sizeimage``
|
||||
adjusted size of ``CAPTURE`` buffers.
|
||||
@ -189,7 +189,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``pixelformat``
|
||||
raw format supported for the coded format currently selected on
|
||||
@ -215,7 +215,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``width``, ``height``
|
||||
may be adjusted to match encoder minimums, maximums and alignment
|
||||
@ -233,7 +233,7 @@ Initialization
|
||||
:c:func:`VIDIOC_S_PARM`. This also sets the coded frame interval on the
|
||||
``CAPTURE`` queue to the same value.
|
||||
|
||||
* ** Required fields:**
|
||||
* **Required fields:**
|
||||
|
||||
``type``
|
||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
|
||||
@ -245,7 +245,7 @@ Initialization
|
||||
the desired frame interval; the encoder may adjust it to
|
||||
match hardware requirements.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``parm.output.timeperframe``
|
||||
the adjusted frame interval.
|
||||
@ -284,7 +284,7 @@ Initialization
|
||||
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:**
|
||||
* **Required fields:**
|
||||
|
||||
``type``
|
||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
||||
@ -296,7 +296,7 @@ Initialization
|
||||
the desired coded frame interval; the encoder may adjust it to
|
||||
match hardware requirements.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``parm.capture.timeperframe``
|
||||
the adjusted frame interval.
|
||||
@ -339,7 +339,7 @@ Initialization
|
||||
rectangle and may be subject to adjustment to match codec and
|
||||
hardware constraints.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||
visible rectangle adjusted by the encoder.
|
||||
@ -387,7 +387,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
actual number of buffers allocated.
|
||||
@ -420,7 +420,7 @@ Initialization
|
||||
other fields
|
||||
follow standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
adjusted to the number of allocated buffers.
|
||||
|
@ -180,7 +180,7 @@ Initialization
|
||||
``memory``
|
||||
follows standard semantics.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
actual number of buffers allocated.
|
||||
@ -208,7 +208,7 @@ Initialization
|
||||
follows standard semantics. ``V4L2_MEMORY_USERPTR`` is not supported
|
||||
for ``CAPTURE`` buffers.
|
||||
|
||||
* **Return fields:**
|
||||
* **Returned fields:**
|
||||
|
||||
``count``
|
||||
adjusted to allocated number of buffers, in case the codec requires
|
||||
|
@ -275,6 +275,19 @@ please make a proposal on the linux-media mailing list.
|
||||
|
||||
Decoder's implementation can be found here,
|
||||
`aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
|
||||
* .. _V4L2-PIX-FMT-MT2110T:
|
||||
|
||||
- ``V4L2_PIX_FMT_MT2110T``
|
||||
- 'MT2110T'
|
||||
- This format is two-planar 10-Bit tile mode and having similitude with
|
||||
``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for VP9, AV1
|
||||
and HEVC.
|
||||
* .. _V4L2-PIX-FMT-MT2110R:
|
||||
|
||||
- ``V4L2_PIX_FMT_MT2110R``
|
||||
- 'MT2110R'
|
||||
- This format is two-planar 10-Bit raster mode and having similitude with
|
||||
``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for AVC.
|
||||
.. raw:: latex
|
||||
|
||||
\normalsize
|
||||
|
@ -58,6 +58,9 @@ the subdevice exposes, drivers return the ENOSPC error code and adjust the
|
||||
value of the ``num_routes`` field. Application should then reserve enough memory
|
||||
for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again.
|
||||
|
||||
On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the
|
||||
``num_routes`` field to reflect the actual number of routes returned.
|
||||
|
||||
.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
|
||||
|
||||
.. c:type:: v4l2_subdev_routing
|
||||
@ -138,9 +141,7 @@ ENOSPC
|
||||
|
||||
EINVAL
|
||||
The sink or source pad identifiers reference a non-existing pad, or reference
|
||||
pads of different types (ie. the sink_pad identifiers refers to a source pad)
|
||||
or the sink or source stream identifiers reference a non-existing stream on
|
||||
the sink or source pad.
|
||||
pads of different types (ie. the sink_pad identifiers refers to a source pad).
|
||||
|
||||
E2BIG
|
||||
The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is
|
||||
|
86
MAINTAINERS
86
MAINTAINERS
@ -1086,7 +1086,6 @@ F: include/soc/amlogic/
|
||||
|
||||
AMPHION VPU CODEC V4L2 DRIVER
|
||||
M: Ming Qian <ming.qian@nxp.com>
|
||||
M: Shijie Qin <shijie.qin@nxp.com>
|
||||
M: Zhou Peng <eagle.zhou@nxp.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -4469,6 +4468,7 @@ M: Maxime Ripard <mripard@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/cdns,*.txt
|
||||
F: Documentation/devicetree/bindings/media/cdns,csi2rx.yaml
|
||||
F: drivers/media/platform/cadence/cdns-csi2*
|
||||
|
||||
CADENCE NAND DRIVER
|
||||
@ -6275,11 +6275,17 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml
|
||||
F: drivers/media/i2c/dw9714.c
|
||||
|
||||
DONGWOON DW9768 LENS VOICE COIL DRIVER
|
||||
M: Dongchun Zhu <dongchun.zhu@mediatek.com>
|
||||
DONGWOON DW9719 LENS VOICE COIL DRIVER
|
||||
M: Daniel Scally <djrscally@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/i2c/dw9719.c
|
||||
|
||||
DONGWOON DW9768 LENS VOICE COIL DRIVER
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Orphan
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
|
||||
F: drivers/media/i2c/dw9768.c
|
||||
|
||||
@ -9668,7 +9674,7 @@ S: Maintained
|
||||
F: arch/x86/kernel/cpu/hygon.c
|
||||
|
||||
HYNIX HI556 SENSOR DRIVER
|
||||
M: Shawn Tu <shawnx.tu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
@ -9681,7 +9687,7 @@ S: Maintained
|
||||
F: drivers/media/i2c/hi846.c
|
||||
|
||||
HYNIX HI847 SENSOR DRIVER
|
||||
M: Shawn Tu <shawnx.tu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/i2c/hi847.c
|
||||
@ -9752,6 +9758,14 @@ L: linux-acpi@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/i2c-core-acpi.c
|
||||
|
||||
I2C ADDRESS TRANSLATOR (ATR)
|
||||
M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
R: Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/i2c-atr.c
|
||||
F: include/linux/i2c-atr.h
|
||||
|
||||
I2C CONTROLLER DRIVER FOR NVIDIA GPU
|
||||
M: Ajay Gupta <ajayg@nvidia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
@ -13094,17 +13108,21 @@ F: drivers/staging/media/imx/
|
||||
F: include/linux/imx-media.h
|
||||
F: include/media/imx.h
|
||||
|
||||
MEDIA DRIVERS FOR FREESCALE IMX7
|
||||
MEDIA DRIVERS FOR FREESCALE IMX7/8
|
||||
M: Rui Miguel Silva <rmfrfs@gmail.com>
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
M: Martin Kepplinger <martin.kepplinger@puri.sm>
|
||||
R: Purism Kernel Team <kernel@puri.sm>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/admin-guide/media/imx7.rst
|
||||
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
|
||||
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
|
||||
F: Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
|
||||
F: drivers/media/platform/nxp/imx-mipi-csis.c
|
||||
F: drivers/media/platform/nxp/imx7-media-csi.c
|
||||
F: drivers/media/platform/nxp/imx8mq-mipi-csi2.c
|
||||
|
||||
MEDIA DRIVERS FOR HELENE
|
||||
M: Abylay Ospan <aospan@netup.ru>
|
||||
@ -15652,7 +15670,7 @@ F: Documentation/filesystems/omfs.rst
|
||||
F: fs/omfs/
|
||||
|
||||
OMNIVISION OG01A1B SENSOR DRIVER
|
||||
M: Shawn Tu <shawnx.tu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/i2c/og01a1b.c
|
||||
@ -15665,9 +15683,8 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/i2c/ov01a10.c
|
||||
|
||||
OMNIVISION OV02A10 SENSOR DRIVER
|
||||
M: Dongchun Zhu <dongchun.zhu@mediatek.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Orphan
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml
|
||||
F: drivers/media/i2c/ov02a10.c
|
||||
@ -15702,6 +15719,7 @@ F: drivers/media/i2c/ov13b10.c
|
||||
|
||||
OMNIVISION OV2680 SENSOR DRIVER
|
||||
M: Rui Miguel Silva <rmfrfs@gmail.com>
|
||||
M: Hans de Goede <hansg@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
@ -15718,7 +15736,7 @@ F: drivers/media/i2c/ov2685.c
|
||||
|
||||
OMNIVISION OV2740 SENSOR DRIVER
|
||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
R: Shawn Tu <shawnx.tu@intel.com>
|
||||
R: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -15750,7 +15768,7 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov5647.yaml
|
||||
F: drivers/media/i2c/ov5647.c
|
||||
|
||||
OMNIVISION OV5670 SENSOR DRIVER
|
||||
M: Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
@ -15758,7 +15776,7 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml
|
||||
F: drivers/media/i2c/ov5670.c
|
||||
|
||||
OMNIVISION OV5675 SENSOR DRIVER
|
||||
M: Shawn Tu <shawnx.tu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
@ -15797,9 +15815,8 @@ F: drivers/media/i2c/ov772x.c
|
||||
F: include/media/i2c/ov772x.h
|
||||
|
||||
OMNIVISION OV7740 SENSOR DRIVER
|
||||
M: Wenyou Yang <wenyou.yang@microchip.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Orphan
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
|
||||
F: drivers/media/i2c/ov7740.c
|
||||
@ -21503,6 +21520,14 @@ F: drivers/misc/tifm*
|
||||
F: drivers/mmc/host/tifm_sd.c
|
||||
F: include/linux/tifm.h
|
||||
|
||||
TI FPD-LINK DRIVERS
|
||||
M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/ti,ds90*
|
||||
F: drivers/media/i2c/ds90*
|
||||
F: include/media/i2c/ds90*
|
||||
|
||||
TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
|
||||
M: Nishanth Menon <nm@ti.com>
|
||||
M: Santosh Shilimkar <ssantosh@kernel.org>
|
||||
@ -22447,6 +22472,39 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/clk/ux500/
|
||||
|
||||
V4L2 ASYNC AND FWNODE FRAMEWORKS
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/v4l2-core/v4l2-async.c
|
||||
F: drivers/media/v4l2-core/v4l2-fwnode.c
|
||||
F: include/media/v4l2-async.h
|
||||
F: include/media/v4l2-fwnode.h
|
||||
|
||||
V4L2 LENS DRIVERS
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/i2c/ak*
|
||||
F: drivers/media/i2c/dw*
|
||||
F: drivers/media/i2c/lm*
|
||||
|
||||
V4L2 CAMERA SENSOR DRIVERS
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/driver-api/media/camera-sensor.rst
|
||||
F: Documentation/driver-api/media/tx-rx.rst
|
||||
F: drivers/media/i2c/ar*
|
||||
F: drivers/media/i2c/hi*
|
||||
F: drivers/media/i2c/imx*
|
||||
F: drivers/media/i2c/mt*
|
||||
F: drivers/media/i2c/og*
|
||||
F: drivers/media/i2c/ov*
|
||||
F: drivers/media/i2c/s5*
|
||||
F: drivers/media/i2c/st-vgxy61.c
|
||||
|
||||
VF610 NAND DRIVER
|
||||
M: Stefan Agner <stefan@agner.ch>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
|
@ -1159,7 +1159,6 @@ CONFIG_XEN_GNTDEV=y
|
||||
CONFIG_XEN_GRANT_DEV_ALLOC=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_STAGING_MEDIA=y
|
||||
CONFIG_VIDEO_IMX_MEDIA=m
|
||||
CONFIG_VIDEO_MAX96712=m
|
||||
CONFIG_CHROME_PLATFORMS=y
|
||||
CONFIG_CROS_EC=y
|
||||
|
@ -71,6 +71,15 @@ config I2C_MUX
|
||||
|
||||
source "drivers/i2c/muxes/Kconfig"
|
||||
|
||||
config I2C_ATR
|
||||
tristate "I2C Address Translator (ATR) support"
|
||||
help
|
||||
Enable support for I2C Address Translator (ATR) chips.
|
||||
|
||||
An ATR allows accessing multiple I2C busses from a single
|
||||
physical bus via address translation instead of bus selection as
|
||||
i2c-muxes do.
|
||||
|
||||
config I2C_HELPER_AUTO
|
||||
bool "Autoselect pertinent helper modules"
|
||||
default y
|
||||
|
@ -13,6 +13,7 @@ i2c-core-$(CONFIG_OF) += i2c-core-of.o
|
||||
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
|
||||
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
|
||||
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
||||
obj-$(CONFIG_I2C_ATR) += i2c-atr.o
|
||||
obj-y += algos/ busses/ muxes/
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
|
||||
|
710
drivers/i2c/i2c-atr.c
Normal file
710
drivers/i2c/i2c-atr.c
Normal file
@ -0,0 +1,710 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* I2C Address Translator
|
||||
*
|
||||
* Copyright (c) 2019,2022 Luca Ceresoli <luca@lucaceresoli.net>
|
||||
* Copyright (c) 2022,2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
*
|
||||
* Originally based on i2c-mux.c
|
||||
*/
|
||||
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/i2c-atr.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define ATR_MAX_ADAPTERS 100 /* Just a sanity limit */
|
||||
#define ATR_MAX_SYMLINK_LEN 11 /* Longest name is 10 chars: "channel-99" */
|
||||
|
||||
/**
|
||||
* struct i2c_atr_alias_pair - Holds the alias assigned to a client.
|
||||
* @node: List node
|
||||
* @client: Pointer to the client on the child bus
|
||||
* @alias: I2C alias address assigned by the driver.
|
||||
* This is the address that will be used to issue I2C transactions
|
||||
* on the parent (physical) bus.
|
||||
*/
|
||||
struct i2c_atr_alias_pair {
|
||||
struct list_head node;
|
||||
const struct i2c_client *client;
|
||||
u16 alias;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct i2c_atr_chan - Data for a channel.
|
||||
* @adap: The &struct i2c_adapter for the channel
|
||||
* @atr: The parent I2C ATR
|
||||
* @chan_id: The ID of this channel
|
||||
* @alias_list: List of @struct i2c_atr_alias_pair containing the
|
||||
* assigned aliases
|
||||
* @orig_addrs_lock: Mutex protecting @orig_addrs
|
||||
* @orig_addrs: Buffer used to store the original addresses during transmit
|
||||
* @orig_addrs_size: Size of @orig_addrs
|
||||
*/
|
||||
struct i2c_atr_chan {
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_atr *atr;
|
||||
u32 chan_id;
|
||||
|
||||
struct list_head alias_list;
|
||||
|
||||
/* Lock orig_addrs during xfer */
|
||||
struct mutex orig_addrs_lock;
|
||||
u16 *orig_addrs;
|
||||
unsigned int orig_addrs_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct i2c_atr - The I2C ATR instance
|
||||
* @parent: The parent &struct i2c_adapter
|
||||
* @dev: The device that owns the I2C ATR instance
|
||||
* @ops: &struct i2c_atr_ops
|
||||
* @priv: Private driver data, set with i2c_atr_set_driver_data()
|
||||
* @algo: The &struct i2c_algorithm for adapters
|
||||
* @lock: Lock for the I2C bus segment (see &struct i2c_lock_operations)
|
||||
* @max_adapters: Maximum number of adapters this I2C ATR can have
|
||||
* @num_aliases: Number of aliases in the aliases array
|
||||
* @aliases: The aliases array
|
||||
* @alias_mask_lock: Lock protecting alias_use_mask
|
||||
* @alias_use_mask: Bitmask for used aliases in aliases array
|
||||
* @i2c_nb: Notifier for remote client add & del events
|
||||
* @adapter: Array of adapters
|
||||
*/
|
||||
struct i2c_atr {
|
||||
struct i2c_adapter *parent;
|
||||
struct device *dev;
|
||||
const struct i2c_atr_ops *ops;
|
||||
|
||||
void *priv;
|
||||
|
||||
struct i2c_algorithm algo;
|
||||
/* lock for the I2C bus segment (see struct i2c_lock_operations) */
|
||||
struct mutex lock;
|
||||
int max_adapters;
|
||||
|
||||
size_t num_aliases;
|
||||
const u16 *aliases;
|
||||
/* Protects alias_use_mask */
|
||||
spinlock_t alias_mask_lock;
|
||||
unsigned long *alias_use_mask;
|
||||
|
||||
struct notifier_block i2c_nb;
|
||||
|
||||
struct i2c_adapter *adapter[];
|
||||
};
|
||||
|
||||
static struct i2c_atr_alias_pair *
|
||||
i2c_atr_find_mapping_by_client(const struct list_head *list,
|
||||
const struct i2c_client *client)
|
||||
{
|
||||
struct i2c_atr_alias_pair *c2a;
|
||||
|
||||
list_for_each_entry(c2a, list, node) {
|
||||
if (c2a->client == client)
|
||||
return c2a;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct i2c_atr_alias_pair *
|
||||
i2c_atr_find_mapping_by_addr(const struct list_head *list, u16 phys_addr)
|
||||
{
|
||||
struct i2c_atr_alias_pair *c2a;
|
||||
|
||||
list_for_each_entry(c2a, list, node) {
|
||||
if (c2a->client->addr == phys_addr)
|
||||
return c2a;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace all message addresses with their aliases, saving the original
|
||||
* addresses.
|
||||
*
|
||||
* This function is internal for use in i2c_atr_master_xfer(). It must be
|
||||
* followed by i2c_atr_unmap_msgs() to restore the original addresses.
|
||||
*/
|
||||
static int i2c_atr_map_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
static struct i2c_atr_alias_pair *c2a;
|
||||
int i;
|
||||
|
||||
/* Ensure we have enough room to save the original addresses */
|
||||
if (unlikely(chan->orig_addrs_size < num)) {
|
||||
u16 *new_buf;
|
||||
|
||||
/* We don't care about old data, hence no realloc() */
|
||||
new_buf = kmalloc_array(num, sizeof(*new_buf), GFP_KERNEL);
|
||||
if (!new_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
kfree(chan->orig_addrs);
|
||||
chan->orig_addrs = new_buf;
|
||||
chan->orig_addrs_size = num;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
chan->orig_addrs[i] = msgs[i].addr;
|
||||
|
||||
c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list,
|
||||
msgs[i].addr);
|
||||
if (!c2a) {
|
||||
dev_err(atr->dev, "client 0x%02x not mapped!\n",
|
||||
msgs[i].addr);
|
||||
|
||||
while (i--)
|
||||
msgs[i].addr = chan->orig_addrs[i];
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
msgs[i].addr = c2a->alias;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore all message address aliases with the original addresses. This
|
||||
* function is internal for use in i2c_atr_master_xfer() and for this reason it
|
||||
* needs no null and size checks on orig_addr.
|
||||
*
|
||||
* @see i2c_atr_map_msgs()
|
||||
*/
|
||||
static void i2c_atr_unmap_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
msgs[i].addr = chan->orig_addrs[i];
|
||||
}
|
||||
|
||||
static int i2c_atr_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adap->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
struct i2c_adapter *parent = atr->parent;
|
||||
int ret;
|
||||
|
||||
/* Translate addresses */
|
||||
mutex_lock(&chan->orig_addrs_lock);
|
||||
|
||||
ret = i2c_atr_map_msgs(chan, msgs, num);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
|
||||
/* Perform the transfer */
|
||||
ret = i2c_transfer(parent, msgs, num);
|
||||
|
||||
/* Restore addresses */
|
||||
i2c_atr_unmap_msgs(chan, msgs, num);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&chan->orig_addrs_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_atr_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write, u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adap->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
struct i2c_adapter *parent = atr->parent;
|
||||
struct i2c_atr_alias_pair *c2a;
|
||||
|
||||
c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list, addr);
|
||||
if (!c2a) {
|
||||
dev_err(atr->dev, "client 0x%02x not mapped!\n", addr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return i2c_smbus_xfer(parent, c2a->alias, flags, read_write, command,
|
||||
size, data);
|
||||
}
|
||||
|
||||
static u32 i2c_atr_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adap->algo_data;
|
||||
struct i2c_adapter *parent = chan->atr->parent;
|
||||
|
||||
return parent->algo->functionality(parent);
|
||||
}
|
||||
|
||||
static void i2c_atr_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adapter->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
|
||||
mutex_lock(&atr->lock);
|
||||
}
|
||||
|
||||
static int i2c_atr_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adapter->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
|
||||
return mutex_trylock(&atr->lock);
|
||||
}
|
||||
|
||||
static void i2c_atr_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adapter->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
|
||||
mutex_unlock(&atr->lock);
|
||||
}
|
||||
|
||||
static const struct i2c_lock_operations i2c_atr_lock_ops = {
|
||||
.lock_bus = i2c_atr_lock_bus,
|
||||
.trylock_bus = i2c_atr_trylock_bus,
|
||||
.unlock_bus = i2c_atr_unlock_bus,
|
||||
};
|
||||
|
||||
static int i2c_atr_reserve_alias(struct i2c_atr *atr)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
spin_lock(&atr->alias_mask_lock);
|
||||
|
||||
idx = find_first_zero_bit(atr->alias_use_mask, atr->num_aliases);
|
||||
if (idx >= atr->num_aliases) {
|
||||
spin_unlock(&atr->alias_mask_lock);
|
||||
dev_err(atr->dev, "failed to find a free alias\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
set_bit(idx, atr->alias_use_mask);
|
||||
|
||||
spin_unlock(&atr->alias_mask_lock);
|
||||
|
||||
return atr->aliases[idx];
|
||||
}
|
||||
|
||||
static void i2c_atr_release_alias(struct i2c_atr *atr, u16 alias)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
spin_lock(&atr->alias_mask_lock);
|
||||
|
||||
for (idx = 0; idx < atr->num_aliases; ++idx) {
|
||||
if (atr->aliases[idx] == alias) {
|
||||
clear_bit(idx, atr->alias_use_mask);
|
||||
spin_unlock(&atr->alias_mask_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&atr->alias_mask_lock);
|
||||
|
||||
/* This should never happen */
|
||||
dev_warn(atr->dev, "Unable to find mapped alias\n");
|
||||
}
|
||||
|
||||
static int i2c_atr_attach_client(struct i2c_adapter *adapter,
|
||||
const struct i2c_client *client)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adapter->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
struct i2c_atr_alias_pair *c2a;
|
||||
u16 alias;
|
||||
int ret;
|
||||
|
||||
ret = i2c_atr_reserve_alias(atr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
alias = ret;
|
||||
|
||||
c2a = kzalloc(sizeof(*c2a), GFP_KERNEL);
|
||||
if (!c2a) {
|
||||
ret = -ENOMEM;
|
||||
goto err_release_alias;
|
||||
}
|
||||
|
||||
ret = atr->ops->attach_client(atr, chan->chan_id, client, alias);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
dev_dbg(atr->dev, "chan%u: client 0x%02x mapped at alias 0x%02x (%s)\n",
|
||||
chan->chan_id, client->addr, alias, client->name);
|
||||
|
||||
c2a->client = client;
|
||||
c2a->alias = alias;
|
||||
list_add(&c2a->node, &chan->alias_list);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(c2a);
|
||||
err_release_alias:
|
||||
i2c_atr_release_alias(atr, alias);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_atr_detach_client(struct i2c_adapter *adapter,
|
||||
const struct i2c_client *client)
|
||||
{
|
||||
struct i2c_atr_chan *chan = adapter->algo_data;
|
||||
struct i2c_atr *atr = chan->atr;
|
||||
struct i2c_atr_alias_pair *c2a;
|
||||
|
||||
atr->ops->detach_client(atr, chan->chan_id, client);
|
||||
|
||||
c2a = i2c_atr_find_mapping_by_client(&chan->alias_list, client);
|
||||
if (!c2a) {
|
||||
/* This should never happen */
|
||||
dev_warn(atr->dev, "Unable to find address mapping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
i2c_atr_release_alias(atr, c2a->alias);
|
||||
|
||||
dev_dbg(atr->dev,
|
||||
"chan%u: client 0x%02x unmapped from alias 0x%02x (%s)\n",
|
||||
chan->chan_id, client->addr, c2a->alias, client->name);
|
||||
|
||||
list_del(&c2a->node);
|
||||
kfree(c2a);
|
||||
}
|
||||
|
||||
static int i2c_atr_bus_notifier_call(struct notifier_block *nb,
|
||||
unsigned long event, void *device)
|
||||
{
|
||||
struct i2c_atr *atr = container_of(nb, struct i2c_atr, i2c_nb);
|
||||
struct device *dev = device;
|
||||
struct i2c_client *client;
|
||||
u32 chan_id;
|
||||
int ret;
|
||||
|
||||
client = i2c_verify_client(dev);
|
||||
if (!client)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Is the client in one of our adapters? */
|
||||
for (chan_id = 0; chan_id < atr->max_adapters; ++chan_id) {
|
||||
if (client->adapter == atr->adapter[chan_id])
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan_id == atr->max_adapters)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
switch (event) {
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
ret = i2c_atr_attach_client(client->adapter, client);
|
||||
if (ret)
|
||||
dev_err(atr->dev,
|
||||
"Failed to attach remote client '%s': %d\n",
|
||||
dev_name(dev), ret);
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_DEL_DEVICE:
|
||||
i2c_atr_detach_client(client->adapter, client);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int i2c_atr_parse_alias_pool(struct i2c_atr *atr)
|
||||
{
|
||||
struct device *dev = atr->dev;
|
||||
unsigned long *alias_use_mask;
|
||||
size_t num_aliases;
|
||||
unsigned int i;
|
||||
u32 *aliases32;
|
||||
u16 *aliases16;
|
||||
int ret;
|
||||
|
||||
ret = fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool");
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
num_aliases = ret;
|
||||
|
||||
if (!num_aliases)
|
||||
return 0;
|
||||
|
||||
aliases32 = kcalloc(num_aliases, sizeof(*aliases32), GFP_KERNEL);
|
||||
if (!aliases32)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fwnode_property_read_u32_array(dev_fwnode(dev), "i2c-alias-pool",
|
||||
aliases32, num_aliases);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read 'i2c-alias-pool' property: %d\n",
|
||||
ret);
|
||||
goto err_free_aliases32;
|
||||
}
|
||||
|
||||
aliases16 = kcalloc(num_aliases, sizeof(*aliases16), GFP_KERNEL);
|
||||
if (!aliases16) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_aliases32;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_aliases; i++) {
|
||||
if (!(aliases32[i] & 0xffff0000)) {
|
||||
aliases16[i] = aliases32[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_err(dev, "Failed to parse 'i2c-alias-pool' property: I2C flags are not supported\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_aliases16;
|
||||
}
|
||||
|
||||
alias_use_mask = bitmap_zalloc(num_aliases, GFP_KERNEL);
|
||||
if (!alias_use_mask) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_aliases16;
|
||||
}
|
||||
|
||||
kfree(aliases32);
|
||||
|
||||
atr->num_aliases = num_aliases;
|
||||
atr->aliases = aliases16;
|
||||
atr->alias_use_mask = alias_use_mask;
|
||||
|
||||
dev_dbg(dev, "i2c-alias-pool has %zu aliases", atr->num_aliases);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_aliases16:
|
||||
kfree(aliases16);
|
||||
err_free_aliases32:
|
||||
kfree(aliases32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev,
|
||||
const struct i2c_atr_ops *ops, int max_adapters)
|
||||
{
|
||||
struct i2c_atr *atr;
|
||||
int ret;
|
||||
|
||||
if (max_adapters > ATR_MAX_ADAPTERS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!ops || !ops->attach_client || !ops->detach_client)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
atr = kzalloc(struct_size(atr, adapter, max_adapters), GFP_KERNEL);
|
||||
if (!atr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mutex_init(&atr->lock);
|
||||
spin_lock_init(&atr->alias_mask_lock);
|
||||
|
||||
atr->parent = parent;
|
||||
atr->dev = dev;
|
||||
atr->ops = ops;
|
||||
atr->max_adapters = max_adapters;
|
||||
|
||||
if (parent->algo->master_xfer)
|
||||
atr->algo.master_xfer = i2c_atr_master_xfer;
|
||||
if (parent->algo->smbus_xfer)
|
||||
atr->algo.smbus_xfer = i2c_atr_smbus_xfer;
|
||||
atr->algo.functionality = i2c_atr_functionality;
|
||||
|
||||
ret = i2c_atr_parse_alias_pool(atr);
|
||||
if (ret)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
atr->i2c_nb.notifier_call = i2c_atr_bus_notifier_call;
|
||||
ret = bus_register_notifier(&i2c_bus_type, &atr->i2c_nb);
|
||||
if (ret)
|
||||
goto err_free_aliases;
|
||||
|
||||
return atr;
|
||||
|
||||
err_free_aliases:
|
||||
bitmap_free(atr->alias_use_mask);
|
||||
kfree(atr->aliases);
|
||||
err_destroy_mutex:
|
||||
mutex_destroy(&atr->lock);
|
||||
kfree(atr);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_new, I2C_ATR);
|
||||
|
||||
void i2c_atr_delete(struct i2c_atr *atr)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < atr->max_adapters; ++i)
|
||||
WARN_ON(atr->adapter[i]);
|
||||
|
||||
bus_unregister_notifier(&i2c_bus_type, &atr->i2c_nb);
|
||||
bitmap_free(atr->alias_use_mask);
|
||||
kfree(atr->aliases);
|
||||
mutex_destroy(&atr->lock);
|
||||
kfree(atr);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, I2C_ATR);
|
||||
|
||||
int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
|
||||
struct device *adapter_parent,
|
||||
struct fwnode_handle *bus_handle)
|
||||
{
|
||||
struct i2c_adapter *parent = atr->parent;
|
||||
struct device *dev = atr->dev;
|
||||
struct i2c_atr_chan *chan;
|
||||
char symlink_name[ATR_MAX_SYMLINK_LEN];
|
||||
int ret;
|
||||
|
||||
if (chan_id >= atr->max_adapters) {
|
||||
dev_err(dev, "No room for more i2c-atr adapters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (atr->adapter[chan_id]) {
|
||||
dev_err(dev, "Adapter %d already present\n", chan_id);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
|
||||
if (!chan)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!adapter_parent)
|
||||
adapter_parent = dev;
|
||||
|
||||
chan->atr = atr;
|
||||
chan->chan_id = chan_id;
|
||||
INIT_LIST_HEAD(&chan->alias_list);
|
||||
mutex_init(&chan->orig_addrs_lock);
|
||||
|
||||
snprintf(chan->adap.name, sizeof(chan->adap.name), "i2c-%d-atr-%d",
|
||||
i2c_adapter_id(parent), chan_id);
|
||||
chan->adap.owner = THIS_MODULE;
|
||||
chan->adap.algo = &atr->algo;
|
||||
chan->adap.algo_data = chan;
|
||||
chan->adap.dev.parent = adapter_parent;
|
||||
chan->adap.retries = parent->retries;
|
||||
chan->adap.timeout = parent->timeout;
|
||||
chan->adap.quirks = parent->quirks;
|
||||
chan->adap.lock_ops = &i2c_atr_lock_ops;
|
||||
|
||||
if (bus_handle) {
|
||||
device_set_node(&chan->adap.dev, fwnode_handle_get(bus_handle));
|
||||
} else {
|
||||
struct fwnode_handle *atr_node;
|
||||
struct fwnode_handle *child;
|
||||
u32 reg;
|
||||
|
||||
atr_node = device_get_named_child_node(dev, "i2c-atr");
|
||||
|
||||
fwnode_for_each_child_node(atr_node, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
continue;
|
||||
if (chan_id == reg)
|
||||
break;
|
||||
}
|
||||
|
||||
device_set_node(&chan->adap.dev, child);
|
||||
fwnode_handle_put(atr_node);
|
||||
}
|
||||
|
||||
atr->adapter[chan_id] = &chan->adap;
|
||||
|
||||
ret = i2c_add_adapter(&chan->adap);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add atr-adapter %u (error=%d)\n",
|
||||
chan_id, ret);
|
||||
goto err_fwnode_put;
|
||||
}
|
||||
|
||||
snprintf(symlink_name, sizeof(symlink_name), "channel-%u",
|
||||
chan->chan_id);
|
||||
|
||||
ret = sysfs_create_link(&chan->adap.dev.kobj, &dev->kobj, "atr_device");
|
||||
if (ret)
|
||||
dev_warn(dev, "can't create symlink to atr device\n");
|
||||
ret = sysfs_create_link(&dev->kobj, &chan->adap.dev.kobj, symlink_name);
|
||||
if (ret)
|
||||
dev_warn(dev, "can't create symlink for channel %u\n", chan_id);
|
||||
|
||||
dev_dbg(dev, "Added ATR child bus %d\n", i2c_adapter_id(&chan->adap));
|
||||
|
||||
return 0;
|
||||
|
||||
err_fwnode_put:
|
||||
fwnode_handle_put(dev_fwnode(&chan->adap.dev));
|
||||
mutex_destroy(&chan->orig_addrs_lock);
|
||||
kfree(chan);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_add_adapter, I2C_ATR);
|
||||
|
||||
void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id)
|
||||
{
|
||||
char symlink_name[ATR_MAX_SYMLINK_LEN];
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_atr_chan *chan;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct device *dev = atr->dev;
|
||||
|
||||
adap = atr->adapter[chan_id];
|
||||
if (!adap)
|
||||
return;
|
||||
|
||||
chan = adap->algo_data;
|
||||
fwnode = dev_fwnode(&adap->dev);
|
||||
|
||||
dev_dbg(dev, "Removing ATR child bus %d\n", i2c_adapter_id(adap));
|
||||
|
||||
snprintf(symlink_name, sizeof(symlink_name), "channel-%u",
|
||||
chan->chan_id);
|
||||
sysfs_remove_link(&dev->kobj, symlink_name);
|
||||
sysfs_remove_link(&chan->adap.dev.kobj, "atr_device");
|
||||
|
||||
i2c_del_adapter(adap);
|
||||
|
||||
atr->adapter[chan_id] = NULL;
|
||||
|
||||
fwnode_handle_put(fwnode);
|
||||
mutex_destroy(&chan->orig_addrs_lock);
|
||||
kfree(chan->orig_addrs);
|
||||
kfree(chan);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_del_adapter, I2C_ATR);
|
||||
|
||||
void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data)
|
||||
{
|
||||
atr->priv = data;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_set_driver_data, I2C_ATR);
|
||||
|
||||
void *i2c_atr_get_driver_data(struct i2c_atr *atr)
|
||||
{
|
||||
return atr->priv;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(i2c_atr_get_driver_data, I2C_ATR);
|
||||
|
||||
MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
|
||||
MODULE_DESCRIPTION("I2C Address Translator");
|
||||
MODULE_LICENSE("GPL");
|
@ -385,8 +385,8 @@ static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status)
|
||||
cec_queue_msg_monitor(adap, &data->msg, 1);
|
||||
|
||||
if (!data->blocking && data->msg.sequence)
|
||||
/* Allow drivers to process the message first */
|
||||
call_op(adap, received, &data->msg);
|
||||
/* Allow drivers to react to a canceled transmit */
|
||||
call_void_op(adap, adap_nb_transmit_canceled, &data->msg);
|
||||
|
||||
cec_data_completed(data);
|
||||
}
|
||||
@ -1348,7 +1348,7 @@ static void cec_adap_unconfigure(struct cec_adapter *adap)
|
||||
cec_flush(adap);
|
||||
wake_up_interruptible(&adap->kthread_waitq);
|
||||
cec_post_state_event(adap);
|
||||
call_void_op(adap, adap_configured, false);
|
||||
call_void_op(adap, adap_unconfigured);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1539,7 +1539,7 @@ configured:
|
||||
adap->kthread_config = NULL;
|
||||
complete(&adap->config_completion);
|
||||
mutex_unlock(&adap->lock);
|
||||
call_void_op(adap, adap_configured, true);
|
||||
call_void_op(adap, configured);
|
||||
return 0;
|
||||
|
||||
unconfigure:
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -183,6 +183,7 @@ struct cec_pin {
|
||||
u16 la_mask;
|
||||
bool monitor_all;
|
||||
bool rx_eom;
|
||||
bool enabled_irq;
|
||||
bool enable_irq_failed;
|
||||
enum cec_pin_state state;
|
||||
struct cec_msg tx_msg;
|
||||
|
@ -982,7 +982,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
||||
}
|
||||
if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL ||
|
||||
pin->enable_irq_failed || adap->is_configuring ||
|
||||
adap->is_configured || adap->monitor_all_cnt)
|
||||
adap->is_configured || adap->monitor_all_cnt || !adap->monitor_pin_cnt)
|
||||
break;
|
||||
/* Switch to interrupt mode */
|
||||
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_ENABLE);
|
||||
@ -1033,8 +1033,9 @@ static int cec_pin_thread_func(void *_adap)
|
||||
{
|
||||
struct cec_adapter *adap = _adap;
|
||||
struct cec_pin *pin = adap->pin;
|
||||
bool irq_enabled = false;
|
||||
|
||||
pin->enabled_irq = false;
|
||||
pin->enable_irq_failed = false;
|
||||
for (;;) {
|
||||
wait_event_interruptible(pin->kthread_waitq,
|
||||
kthread_should_stop() ||
|
||||
@ -1088,9 +1089,10 @@ static int cec_pin_thread_func(void *_adap)
|
||||
switch (atomic_xchg(&pin->work_irq_change,
|
||||
CEC_PIN_IRQ_UNCHANGED)) {
|
||||
case CEC_PIN_IRQ_DISABLE:
|
||||
if (irq_enabled) {
|
||||
call_void_pin_op(pin, disable_irq);
|
||||
irq_enabled = false;
|
||||
if (pin->enabled_irq) {
|
||||
pin->ops->disable_irq(adap);
|
||||
pin->enabled_irq = false;
|
||||
pin->enable_irq_failed = false;
|
||||
}
|
||||
cec_pin_high(pin);
|
||||
if (pin->state == CEC_ST_OFF)
|
||||
@ -1100,21 +1102,29 @@ static int cec_pin_thread_func(void *_adap)
|
||||
HRTIMER_MODE_REL);
|
||||
break;
|
||||
case CEC_PIN_IRQ_ENABLE:
|
||||
if (irq_enabled)
|
||||
if (pin->enabled_irq || !pin->ops->enable_irq ||
|
||||
pin->adap->devnode.unregistered)
|
||||
break;
|
||||
pin->enable_irq_failed = !call_pin_op(pin, enable_irq);
|
||||
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
|
||||
if (pin->enable_irq_failed) {
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
} else {
|
||||
irq_enabled = true;
|
||||
pin->enabled_irq = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pin->enabled_irq) {
|
||||
pin->ops->disable_irq(pin->adap);
|
||||
pin->enabled_irq = false;
|
||||
pin->enable_irq_failed = false;
|
||||
cec_pin_high(pin);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1215,7 +1225,9 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
|
||||
seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read));
|
||||
seq_printf(file, "cec pin events dropped: %u\n",
|
||||
pin->work_pin_events_dropped_cnt);
|
||||
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
|
||||
if (pin->ops->enable_irq)
|
||||
seq_printf(file, "irq %s\n", pin->enabled_irq ? "enabled" :
|
||||
(pin->enable_irq_failed ? "failed" : "disabled"));
|
||||
if (pin->timer_100us_overruns) {
|
||||
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
||||
pin->timer_100us_overruns, pin->timer_cnt);
|
||||
@ -1305,7 +1317,7 @@ void cec_pin_changed(struct cec_adapter *adap, bool value)
|
||||
|
||||
cec_pin_update(pin, value, false);
|
||||
if (!value && (adap->is_configuring || adap->is_configured ||
|
||||
adap->monitor_all_cnt))
|
||||
adap->monitor_all_cnt || !adap->monitor_pin_cnt))
|
||||
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_pin_changed);
|
||||
|
@ -589,7 +589,7 @@ 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),
|
||||
.of_match_table = ch7322_of_match,
|
||||
},
|
||||
.probe = ch7322_probe,
|
||||
.remove = ch7322_remove,
|
||||
|
@ -159,11 +159,6 @@ static int cec_gpio_read_5v(struct cec_adapter *adap)
|
||||
return gpiod_get_value(cec->v5_gpio);
|
||||
}
|
||||
|
||||
static void cec_gpio_free(struct cec_adapter *adap)
|
||||
{
|
||||
cec_gpio_disable_irq(adap);
|
||||
}
|
||||
|
||||
static const struct cec_pin_ops cec_gpio_pin_ops = {
|
||||
.read = cec_gpio_read,
|
||||
.low = cec_gpio_low,
|
||||
@ -171,7 +166,6 @@ static const struct cec_pin_ops cec_gpio_pin_ops = {
|
||||
.enable_irq = cec_gpio_enable_irq,
|
||||
.disable_irq = cec_gpio_disable_irq,
|
||||
.status = cec_gpio_status,
|
||||
.free = cec_gpio_free,
|
||||
.read_hpd = cec_gpio_read_hpd,
|
||||
.read_5v = cec_gpio_read_5v,
|
||||
};
|
||||
@ -215,13 +209,11 @@ static int cec_gpio_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(cec->adap);
|
||||
|
||||
ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
|
||||
cec->adap->name, cec);
|
||||
if (ret)
|
||||
goto del_adap;
|
||||
|
||||
cec_gpio_disable_irq(cec->adap);
|
||||
|
||||
if (cec->hpd_gpio) {
|
||||
cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio);
|
||||
ret = devm_request_threaded_irq(dev, cec->hpd_irq,
|
||||
|
@ -717,7 +717,7 @@ static struct platform_driver meson_ao_cec_driver = {
|
||||
.remove_new = meson_ao_cec_remove,
|
||||
.driver = {
|
||||
.name = "meson-ao-cec",
|
||||
.of_match_table = of_match_ptr(meson_ao_cec_of_match),
|
||||
.of_match_table = meson_ao_cec_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
@ -348,8 +348,8 @@ static int tegra_cec_probe(struct platform_device *pdev)
|
||||
|
||||
cec->tegra_cec_irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (cec->tegra_cec_irq <= 0)
|
||||
return -EBUSY;
|
||||
if (cec->tegra_cec_irq < 0)
|
||||
return cec->tegra_cec_irq;
|
||||
|
||||
cec->cec_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
@ -462,7 +462,7 @@ static const struct of_device_id tegra_cec_of_match[] = {
|
||||
static struct platform_driver tegra_cec_driver = {
|
||||
.driver = {
|
||||
.name = TEGRA_CEC_NAME,
|
||||
.of_match_table = of_match_ptr(tegra_cec_of_match),
|
||||
.of_match_table = tegra_cec_of_match,
|
||||
},
|
||||
.probe = tegra_cec_probe,
|
||||
.remove_new = tegra_cec_remove,
|
||||
|
@ -45,89 +45,48 @@ static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\n", p->is_rf_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\n", p->is_demod_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d\n", p->SNR);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber = %d\n", p->ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"FIB_CRC = %d\n", p->FIB_CRC);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ts_per = %d\n", p->ts_per);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"MFER = %d\n", p->MFER);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d\n", p->RSSI);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d\n", p->in_band_pwr);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\n", p->carrier_offset);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\n", p->modem_state);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d\n", p->frequency);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\n", p->bandwidth);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\n", p->transmission_mode);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\n", p->modem_state);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"code_rate = %d\n", p->code_rate);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"lp_code_rate = %d\n", p->lp_code_rate);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"hierarchy = %d\n", p->hierarchy);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"constellation = %d\n", p->constellation);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_size = %d\n", p->burst_size);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_duration = %d\n", p->burst_duration);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_cycle_time = %d\n", p->burst_cycle_time);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"calc_burst_cycle_time = %d\n",
|
||||
p->calc_burst_cycle_time);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_rows = %d\n", p->num_of_rows);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_padd_cols = %d\n", p->num_of_padd_cols);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_punct_cols = %d\n", p->num_of_punct_cols);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"error_ts_packets = %d\n", p->error_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"total_ts_packets = %d\n", p->total_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber_error_count = %d\n", p->ber_error_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber_bit_count = %d\n", p->ber_bit_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"pre_ber = %d\n", p->pre_ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"cell_id = %d\n", p->cell_id);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_mpe_received = %d\n", p->num_mpe_received);
|
||||
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\n", p->is_rf_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_demod_locked = %d\n", p->is_demod_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += sysfs_emit_at(buf, n, "SNR = %d\n", p->SNR);
|
||||
n += sysfs_emit_at(buf, n, "ber = %d\n", p->ber);
|
||||
n += sysfs_emit_at(buf, n, "FIB_CRC = %d\n", p->FIB_CRC);
|
||||
n += sysfs_emit_at(buf, n, "ts_per = %d\n", p->ts_per);
|
||||
n += sysfs_emit_at(buf, n, "MFER = %d\n", p->MFER);
|
||||
n += sysfs_emit_at(buf, n, "RSSI = %d\n", p->RSSI);
|
||||
n += sysfs_emit_at(buf, n, "in_band_pwr = %d\n", p->in_band_pwr);
|
||||
n += sysfs_emit_at(buf, n, "carrier_offset = %d\n", p->carrier_offset);
|
||||
n += sysfs_emit_at(buf, n, "modem_state = %d\n", p->modem_state);
|
||||
n += sysfs_emit_at(buf, n, "frequency = %d\n", p->frequency);
|
||||
n += sysfs_emit_at(buf, n, "bandwidth = %d\n", p->bandwidth);
|
||||
n += sysfs_emit_at(buf, n, "transmission_mode = %d\n", p->transmission_mode);
|
||||
n += sysfs_emit_at(buf, n, "modem_state = %d\n", p->modem_state);
|
||||
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||
n += sysfs_emit_at(buf, n, "code_rate = %d\n", p->code_rate);
|
||||
n += sysfs_emit_at(buf, n, "lp_code_rate = %d\n", p->lp_code_rate);
|
||||
n += sysfs_emit_at(buf, n, "hierarchy = %d\n", p->hierarchy);
|
||||
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->constellation);
|
||||
n += sysfs_emit_at(buf, n, "burst_size = %d\n", p->burst_size);
|
||||
n += sysfs_emit_at(buf, n, "burst_duration = %d\n", p->burst_duration);
|
||||
n += sysfs_emit_at(buf, n, "burst_cycle_time = %d\n", p->burst_cycle_time);
|
||||
n += sysfs_emit_at(buf, n, "calc_burst_cycle_time = %d\n", p->calc_burst_cycle_time);
|
||||
n += sysfs_emit_at(buf, n, "num_of_rows = %d\n", p->num_of_rows);
|
||||
n += sysfs_emit_at(buf, n, "num_of_padd_cols = %d\n", p->num_of_padd_cols);
|
||||
n += sysfs_emit_at(buf, n, "num_of_punct_cols = %d\n", p->num_of_punct_cols);
|
||||
n += sysfs_emit_at(buf, n, "error_ts_packets = %d\n", p->error_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "total_ts_packets = %d\n", p->total_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
|
||||
n += sysfs_emit_at(buf, n, "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
|
||||
n += sysfs_emit_at(buf, n, "num_of_corrected_mpe_tlbs = %d\n",
|
||||
p->num_of_corrected_mpe_tlbs);
|
||||
n += sysfs_emit_at(buf, n, "ber_error_count = %d\n", p->ber_error_count);
|
||||
n += sysfs_emit_at(buf, n, "ber_bit_count = %d\n", p->ber_bit_count);
|
||||
n += sysfs_emit_at(buf, n, "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
n += sysfs_emit_at(buf, n, "pre_ber = %d\n", p->pre_ber);
|
||||
n += sysfs_emit_at(buf, n, "cell_id = %d\n", p->cell_id);
|
||||
n += sysfs_emit_at(buf, n, "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
|
||||
n += sysfs_emit_at(buf, n, "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
|
||||
n += sysfs_emit_at(buf, n, "num_mpe_received = %d\n", p->num_mpe_received);
|
||||
|
||||
debug_data->stats_count = n;
|
||||
spin_unlock(&debug_data->lock);
|
||||
@ -148,78 +107,49 @@ static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"statistics_type = %d\t", p->statistics_type);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"full_size = %d\n", p->full_size);
|
||||
n += sysfs_emit_at(buf, n, "statistics_type = %d\t", p->statistics_type);
|
||||
n += sysfs_emit_at(buf, n, "full_size = %d\n", p->full_size);
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d dB\t\t", p->SNR);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\t", p->carrier_offset);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\t\t", p->bandwidth);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d Hz\n", p->frequency);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\t", p->transmission_mode);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\t\t", p->modem_state);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"system_type = %d\t\t", p->system_type);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"partial_reception = %d\t", p->partial_reception);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_layers = %d\n", p->num_of_layers);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += sysfs_emit_at(buf, n, "SNR = %d dB\t\t", p->SNR);
|
||||
n += sysfs_emit_at(buf, n, "RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += sysfs_emit_at(buf, n, "in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += sysfs_emit_at(buf, n, "carrier_offset = %d\t", p->carrier_offset);
|
||||
n += sysfs_emit_at(buf, n, "bandwidth = %d\t\t", p->bandwidth);
|
||||
n += sysfs_emit_at(buf, n, "frequency = %d Hz\n", p->frequency);
|
||||
n += sysfs_emit_at(buf, n, "transmission_mode = %d\t", p->transmission_mode);
|
||||
n += sysfs_emit_at(buf, n, "modem_state = %d\t\t", p->modem_state);
|
||||
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||
n += sysfs_emit_at(buf, n, "system_type = %d\t\t", p->system_type);
|
||||
n += sysfs_emit_at(buf, n, "partial_reception = %d\t", p->partial_reception);
|
||||
n += sysfs_emit_at(buf, n, "num_of_layers = %d\n", p->num_of_layers);
|
||||
n += sysfs_emit_at(buf, n, "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->layer_info[i].number_of_segments < 1 ||
|
||||
p->layer_info[i].number_of_segments > 13)
|
||||
continue;
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
||||
p->layer_info[i].code_rate);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
||||
p->layer_info[i].constellation);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
||||
p->layer_info[i].ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
||||
p->layer_info[i].pre_ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
||||
p->layer_info[i].ts_per);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
|
||||
p->layer_info[i].ti_ldepth_i);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
|
||||
p->layer_info[i].tmcc_errors);
|
||||
n += sysfs_emit_at(buf, n, "\nLayer %d\n", i);
|
||||
n += sysfs_emit_at(buf, n, "\tcode_rate = %d\t", p->layer_info[i].code_rate);
|
||||
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->layer_info[i].constellation);
|
||||
n += sysfs_emit_at(buf, n, "\tber = %-5d\t", p->layer_info[i].ber);
|
||||
n += sysfs_emit_at(buf, n, "\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += sysfs_emit_at(buf, n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += sysfs_emit_at(buf, n, "\tpre_ber = %-5d\t", p->layer_info[i].pre_ber);
|
||||
n += sysfs_emit_at(buf, n, "\tts_per = %-5d\n", p->layer_info[i].ts_per);
|
||||
n += sysfs_emit_at(buf, n, "\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "ti_ldepth_i = %d\n", p->layer_info[i].ti_ldepth_i);
|
||||
n += sysfs_emit_at(buf, n, "\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += sysfs_emit_at(buf, n, "tmcc_errors = %d\n", p->layer_info[i].tmcc_errors);
|
||||
}
|
||||
|
||||
debug_data->stats_count = n;
|
||||
@ -241,80 +171,50 @@ static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"statistics_type = %d\t", p->statistics_type);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"full_size = %d\n", p->full_size);
|
||||
n += sysfs_emit_at(buf, n, "statistics_type = %d\t", p->statistics_type);
|
||||
n += sysfs_emit_at(buf, n, "full_size = %d\n", p->full_size);
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d dB\t\t", p->SNR);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\t", p->carrier_offset);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\t\t", p->bandwidth);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d Hz\n", p->frequency);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\t", p->transmission_mode);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\t\t", p->modem_state);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"system_type = %d\t\t", p->system_type);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"partial_reception = %d\t", p->partial_reception);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_layers = %d\n", p->num_of_layers);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
|
||||
p->segment_number);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
|
||||
p->tune_bw);
|
||||
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += sysfs_emit_at(buf, n, "SNR = %d dB\t\t", p->SNR);
|
||||
n += sysfs_emit_at(buf, n, "RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += sysfs_emit_at(buf, n, "in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += sysfs_emit_at(buf, n, "carrier_offset = %d\t", p->carrier_offset);
|
||||
n += sysfs_emit_at(buf, n, "bandwidth = %d\t\t", p->bandwidth);
|
||||
n += sysfs_emit_at(buf, n, "frequency = %d Hz\n", p->frequency);
|
||||
n += sysfs_emit_at(buf, n, "transmission_mode = %d\t", p->transmission_mode);
|
||||
n += sysfs_emit_at(buf, n, "modem_state = %d\t\t", p->modem_state);
|
||||
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||
n += sysfs_emit_at(buf, n, "system_type = %d\t\t", p->system_type);
|
||||
n += sysfs_emit_at(buf, n, "partial_reception = %d\t", p->partial_reception);
|
||||
n += sysfs_emit_at(buf, n, "num_of_layers = %d\n", p->num_of_layers);
|
||||
n += sysfs_emit_at(buf, n, "segment_number = %d\t", p->segment_number);
|
||||
n += sysfs_emit_at(buf, n, "tune_bw = %d\n", p->tune_bw);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->layer_info[i].number_of_segments < 1 ||
|
||||
p->layer_info[i].number_of_segments > 13)
|
||||
continue;
|
||||
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
||||
p->layer_info[i].code_rate);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
||||
p->layer_info[i].constellation);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
||||
p->layer_info[i].ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
||||
p->layer_info[i].pre_ber);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
||||
p->layer_info[i].ts_per);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
|
||||
p->layer_info[i].ti_ldepth_i);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
|
||||
p->layer_info[i].tmcc_errors);
|
||||
n += sysfs_emit_at(buf, n, "\nLayer %d\n", i);
|
||||
n += sysfs_emit_at(buf, n, "\tcode_rate = %d\t", p->layer_info[i].code_rate);
|
||||
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->layer_info[i].constellation);
|
||||
n += sysfs_emit_at(buf, n, "\tber = %-5d\t", p->layer_info[i].ber);
|
||||
n += sysfs_emit_at(buf, n, "\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += sysfs_emit_at(buf, n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += sysfs_emit_at(buf, n, "\tpre_ber = %-5d\t", p->layer_info[i].pre_ber);
|
||||
n += sysfs_emit_at(buf, n, "\tts_per = %-5d\n", p->layer_info[i].ts_per);
|
||||
n += sysfs_emit_at(buf, n, "\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += sysfs_emit_at(buf, n, "ti_ldepth_i = %d\n", p->layer_info[i].ti_ldepth_i);
|
||||
n += sysfs_emit_at(buf, n, "\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += sysfs_emit_at(buf, n, "tmcc_errors = %d\n", p->layer_info[i].tmcc_errors);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
void smsendian_handle_tx_message(void *buffer)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
|
||||
struct sms_msg_data *msg = buffer;
|
||||
int i;
|
||||
int msg_words;
|
||||
|
||||
|
@ -973,7 +973,9 @@ static void cx24120_set_clock_ratios(struct dvb_frontend *fe)
|
||||
cmd.arg[8] = (clock_ratios_table[idx].rate >> 8) & 0xff;
|
||||
cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 0xff;
|
||||
|
||||
cx24120_message_send(state, &cmd);
|
||||
ret = cx24120_message_send(state, &cmd);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
/* Calculate ber window rates for stat work */
|
||||
cx24120_calculate_ber_window(state, clock_ratios_table[idx].rate);
|
||||
|
@ -497,7 +497,7 @@ static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth
|
||||
prediv = reg_1856 & 0x3f;
|
||||
loopdiv = (reg_1856 >> 6) & 0x3f;
|
||||
|
||||
if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
|
||||
if (loopdiv && bw && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
|
||||
dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
|
||||
reg_1856 &= 0xf000;
|
||||
reg_1857 = dib7000p_read_word(state, 1857);
|
||||
|
@ -229,13 +229,8 @@ static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
|
||||
struct i2c_msg msg = {
|
||||
.addr = adr, .flags = 0, .buf = data, .len = len };
|
||||
|
||||
dprintk(3, ":");
|
||||
if (debug > 2) {
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
pr_cont(" %02x", data[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
dprintk(3, ": %*ph\n", len, data);
|
||||
|
||||
status = drxk_i2c_transfer(state, &msg, 1);
|
||||
if (status >= 0 && status != 1)
|
||||
status = -EIO;
|
||||
@ -267,16 +262,7 @@ static int i2c_read(struct drxk_state *state,
|
||||
pr_err("i2c read error at addr 0x%02x\n", adr);
|
||||
return status;
|
||||
}
|
||||
if (debug > 2) {
|
||||
int i;
|
||||
dprintk(2, ": read from");
|
||||
for (i = 0; i < len; i++)
|
||||
pr_cont(" %02x", msg[i]);
|
||||
pr_cont(", value = ");
|
||||
for (i = 0; i < alen; i++)
|
||||
pr_cont(" %02x", answ[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
dprintk(3, ": read from %*ph, value = %*ph\n", len, msg, alen, answ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -441,13 +427,8 @@ static int write_block(struct drxk_state *state, u32 address,
|
||||
}
|
||||
memcpy(&state->chunk[adr_length], p_block, chunk);
|
||||
dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
|
||||
if (debug > 1) {
|
||||
int i;
|
||||
if (p_block)
|
||||
for (i = 0; i < chunk; i++)
|
||||
pr_cont(" %02x", p_block[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
if (p_block)
|
||||
dprintk(2, "%*ph\n", chunk, p_block);
|
||||
status = i2c_write(state, state->demod_address,
|
||||
&state->chunk[0], chunk + adr_length);
|
||||
if (status < 0) {
|
||||
|
@ -1487,10 +1487,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
|
||||
}
|
||||
}
|
||||
|
||||
mb86a16_read(state, 0x15, &agcval);
|
||||
mb86a16_read(state, 0x26, &cnmval);
|
||||
dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
|
||||
|
||||
if (mb86a16_read(state, 0x15, &agcval) != 2 || mb86a16_read(state, 0x26, &cnmval) != 2) {
|
||||
dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
|
||||
ret = -EREMOTEIO;
|
||||
} else {
|
||||
dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/int_log.h>
|
||||
|
||||
|
@ -597,7 +597,8 @@ int avc_tuner_dsd(struct firedtv *fdtv,
|
||||
case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
|
||||
case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
|
||||
default:
|
||||
BUG();
|
||||
ret = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
pad_operands(c, pos);
|
||||
|
||||
@ -612,6 +613,7 @@ int avc_tuner_dsd(struct firedtv *fdtv,
|
||||
if (status)
|
||||
*status = r->operand[2];
|
||||
#endif
|
||||
unlock:
|
||||
mutex_unlock(&fdtv->avc_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
|
@ -25,8 +25,15 @@ config VIDEO_IR_I2C
|
||||
# V4L2 I2C drivers that are related with Camera support
|
||||
#
|
||||
|
||||
menu "Camera sensor devices"
|
||||
visible if MEDIA_CAMERA_SUPPORT
|
||||
menuconfig VIDEO_CAMERA_SENSOR
|
||||
bool "Camera sensor devices"
|
||||
depends on MEDIA_CAMERA_SUPPORT && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
default y
|
||||
|
||||
if VIDEO_CAMERA_SENSOR
|
||||
|
||||
config VIDEO_APTINA_PLL
|
||||
tristate
|
||||
@ -36,10 +43,6 @@ config VIDEO_CCS_PLL
|
||||
|
||||
config VIDEO_AR0521
|
||||
tristate "ON Semiconductor AR0521 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the ON Semiconductor
|
||||
AR0521 camera.
|
||||
@ -49,10 +52,6 @@ config VIDEO_AR0521
|
||||
|
||||
config VIDEO_HI556
|
||||
tristate "Hynix Hi-556 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Hynix
|
||||
Hi-556 camera.
|
||||
@ -62,10 +61,6 @@ config VIDEO_HI556
|
||||
|
||||
config VIDEO_HI846
|
||||
tristate "Hynix Hi-846 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Hynix
|
||||
Hi-846 camera.
|
||||
@ -75,10 +70,6 @@ config VIDEO_HI846
|
||||
|
||||
config VIDEO_HI847
|
||||
tristate "Hynix Hi-847 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Hynix
|
||||
Hi-847 camera.
|
||||
@ -88,10 +79,6 @@ config VIDEO_HI847
|
||||
|
||||
config VIDEO_IMX208
|
||||
tristate "Sony IMX208 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX208 camera.
|
||||
@ -101,10 +88,7 @@ config VIDEO_IMX208
|
||||
|
||||
config VIDEO_IMX214
|
||||
tristate "Sony IMX214 sensor support"
|
||||
depends on GPIOLIB && I2C && VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
depends on GPIOLIB
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
@ -115,10 +99,6 @@ config VIDEO_IMX214
|
||||
|
||||
config VIDEO_IMX219
|
||||
tristate "Sony IMX219 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX219 camera.
|
||||
@ -128,9 +108,6 @@ config VIDEO_IMX219
|
||||
|
||||
config VIDEO_IMX258
|
||||
tristate "Sony IMX258 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX258 camera.
|
||||
@ -140,9 +117,6 @@ config VIDEO_IMX258
|
||||
|
||||
config VIDEO_IMX274
|
||||
tristate "Sony IMX274 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This is a V4L2 sensor driver for the Sony IMX274
|
||||
@ -150,11 +124,8 @@ config VIDEO_IMX274
|
||||
|
||||
config VIDEO_IMX290
|
||||
tristate "Sony IMX290 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select REGMAP_I2C
|
||||
select V4L2_FWNODE
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX290 camera sensor.
|
||||
@ -164,10 +135,6 @@ config VIDEO_IMX290
|
||||
|
||||
config VIDEO_IMX296
|
||||
tristate "Sony IMX296 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX296 camera.
|
||||
@ -177,9 +144,6 @@ config VIDEO_IMX296
|
||||
|
||||
config VIDEO_IMX319
|
||||
tristate "Sony IMX319 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX319 camera.
|
||||
@ -190,10 +154,6 @@ config VIDEO_IMX319
|
||||
config VIDEO_IMX334
|
||||
tristate "Sony IMX334 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_DEV
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX334 camera.
|
||||
@ -204,10 +164,6 @@ config VIDEO_IMX334
|
||||
config VIDEO_IMX335
|
||||
tristate "Sony IMX335 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_DEV
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX335 camera.
|
||||
@ -217,9 +173,6 @@ config VIDEO_IMX335
|
||||
|
||||
config VIDEO_IMX355
|
||||
tristate "Sony IMX355 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX355 camera.
|
||||
@ -230,10 +183,6 @@ config VIDEO_IMX355
|
||||
config VIDEO_IMX412
|
||||
tristate "Sony IMX412 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_DEV
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX412 camera.
|
||||
@ -244,10 +193,6 @@ config VIDEO_IMX412
|
||||
config VIDEO_IMX415
|
||||
tristate "Sony IMX415 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_DEV
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX415 camera.
|
||||
@ -260,35 +205,25 @@ config VIDEO_MAX9271_LIB
|
||||
|
||||
config VIDEO_MT9M001
|
||||
tristate "mt9m001 support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This driver supports MT9M001 cameras from Micron, monochrome
|
||||
and colour models.
|
||||
|
||||
config VIDEO_MT9M111
|
||||
tristate "mt9m111, mt9m112 and mt9m131 support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This driver supports MT9M111, MT9M112 and MT9M131 cameras from
|
||||
Micron/Aptina
|
||||
|
||||
config VIDEO_MT9P031
|
||||
tristate "Aptina MT9P031 support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select VIDEO_APTINA_PLL
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Aptina
|
||||
(Micron) mt9p031 5 Mpixel camera.
|
||||
|
||||
config VIDEO_MT9T112
|
||||
tristate "Aptina MT9T111/MT9T112 support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Aptina
|
||||
(Micron) MT9T111 and MT9T112 3 Mpixel camera.
|
||||
@ -298,7 +233,6 @@ config VIDEO_MT9T112
|
||||
|
||||
config VIDEO_MT9V011
|
||||
tristate "Micron mt9v011 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Micron
|
||||
mt0v011 1.3 Mpixel camera. It currently only works with the
|
||||
@ -306,18 +240,13 @@ config VIDEO_MT9V011
|
||||
|
||||
config VIDEO_MT9V032
|
||||
tristate "Micron MT9V032 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select REGMAP_I2C
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Micron
|
||||
MT9V032 752x480 CMOS sensor.
|
||||
|
||||
config VIDEO_MT9V111
|
||||
tristate "Aptina MT9V111 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Aptina/Micron
|
||||
MT9V111 sensor.
|
||||
@ -327,10 +256,6 @@ config VIDEO_MT9V111
|
||||
|
||||
config VIDEO_OG01A1B
|
||||
tristate "OmniVision OG01A1B sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OG01A1B camera.
|
||||
@ -340,10 +265,6 @@ config VIDEO_OG01A1B
|
||||
|
||||
config VIDEO_OV01A10
|
||||
tristate "OmniVision OV01A10 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV01A10 camera.
|
||||
@ -353,10 +274,6 @@ config VIDEO_OV01A10
|
||||
|
||||
config VIDEO_OV02A10
|
||||
tristate "OmniVision OV02A10 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV02A10 camera.
|
||||
@ -366,10 +283,6 @@ config VIDEO_OV02A10
|
||||
|
||||
config VIDEO_OV08D10
|
||||
tristate "OmniVision OV08D10 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV08D10 camera sensor.
|
||||
@ -379,10 +292,6 @@ config VIDEO_OV08D10
|
||||
|
||||
config VIDEO_OV08X40
|
||||
tristate "OmniVision OV08X40 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV08X40 camera.
|
||||
@ -392,28 +301,18 @@ config VIDEO_OV08X40
|
||||
|
||||
config VIDEO_OV13858
|
||||
tristate "OmniVision OV13858 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV13858 camera.
|
||||
|
||||
config VIDEO_OV13B10
|
||||
tristate "OmniVision OV13B10 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV13B10 camera.
|
||||
|
||||
config VIDEO_OV2640
|
||||
tristate "OmniVision OV2640 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select V4L2_ASYNC
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV2640 camera.
|
||||
@ -423,8 +322,7 @@ config VIDEO_OV2640
|
||||
|
||||
config VIDEO_OV2659
|
||||
tristate "OmniVision OV2659 sensor support"
|
||||
depends on VIDEO_DEV && I2C && GPIOLIB
|
||||
select V4L2_FWNODE
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV2659 camera.
|
||||
@ -434,9 +332,7 @@ config VIDEO_OV2659
|
||||
|
||||
config VIDEO_OV2680
|
||||
tristate "OmniVision OV2680 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV2680 camera.
|
||||
@ -446,10 +342,6 @@ config VIDEO_OV2680
|
||||
|
||||
config VIDEO_OV2685
|
||||
tristate "OmniVision OV2685 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV2685 camera.
|
||||
@ -459,11 +351,7 @@ config VIDEO_OV2685
|
||||
|
||||
config VIDEO_OV2740
|
||||
tristate "OmniVision OV2740 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
depends on ACPI || COMPILE_TEST
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
@ -474,10 +362,7 @@ config VIDEO_OV2740
|
||||
|
||||
config VIDEO_OV4689
|
||||
tristate "OmniVision OV4689 sensor support"
|
||||
depends on GPIOLIB && VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||
OV4689 camera.
|
||||
@ -488,10 +373,7 @@ config VIDEO_OV4689
|
||||
config VIDEO_OV5640
|
||||
tristate "OmniVision OV5640 sensor support"
|
||||
depends on OF
|
||||
depends on GPIOLIB && VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Omnivision
|
||||
OV5640 camera sensor with a MIPI CSI-2 interface.
|
||||
@ -499,10 +381,6 @@ config VIDEO_OV5640
|
||||
config VIDEO_OV5645
|
||||
tristate "OmniVision OV5645 sensor support"
|
||||
depends on OF
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5645 camera.
|
||||
@ -512,10 +390,6 @@ config VIDEO_OV5645
|
||||
|
||||
config VIDEO_OV5647
|
||||
tristate "OmniVision OV5647 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5647 camera.
|
||||
@ -525,10 +399,7 @@ config VIDEO_OV5647
|
||||
|
||||
config VIDEO_OV5648
|
||||
tristate "OmniVision OV5648 sensor support"
|
||||
depends on I2C && PM && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on PM
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5648 camera.
|
||||
@ -538,10 +409,6 @@ config VIDEO_OV5648
|
||||
|
||||
config VIDEO_OV5670
|
||||
tristate "OmniVision OV5670 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5670 camera.
|
||||
@ -551,10 +418,6 @@ config VIDEO_OV5670
|
||||
|
||||
config VIDEO_OV5675
|
||||
tristate "OmniVision OV5675 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5675 camera.
|
||||
@ -564,8 +427,7 @@ config VIDEO_OV5675
|
||||
|
||||
config VIDEO_OV5693
|
||||
tristate "OmniVision OV5693 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5693 camera.
|
||||
@ -575,8 +437,6 @@ config VIDEO_OV5693
|
||||
|
||||
config VIDEO_OV5695
|
||||
tristate "OmniVision OV5695 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV5695 camera.
|
||||
@ -586,7 +446,6 @@ config VIDEO_OV5695
|
||||
|
||||
config VIDEO_OV6650
|
||||
tristate "OmniVision OV6650 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV6650 camera.
|
||||
@ -596,10 +455,6 @@ config VIDEO_OV6650
|
||||
|
||||
config VIDEO_OV7251
|
||||
tristate "OmniVision OV7251 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV7251 camera.
|
||||
@ -609,7 +464,6 @@ config VIDEO_OV7251
|
||||
|
||||
config VIDEO_OV7640
|
||||
tristate "OmniVision OV7640 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV7640 camera.
|
||||
@ -619,8 +473,6 @@ config VIDEO_OV7640
|
||||
|
||||
config VIDEO_OV7670
|
||||
tristate "OmniVision OV7670 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV7670 VGA camera. It currently only works with the M88ALP01
|
||||
@ -628,9 +480,7 @@ config VIDEO_OV7670
|
||||
|
||||
config VIDEO_OV772X
|
||||
tristate "OmniVision OV772x sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select REGMAP_SCCB
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV772x camera.
|
||||
@ -640,7 +490,6 @@ config VIDEO_OV772X
|
||||
|
||||
config VIDEO_OV7740
|
||||
tristate "OmniVision OV7740 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select REGMAP_SCCB
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
@ -648,10 +497,6 @@ config VIDEO_OV7740
|
||||
|
||||
config VIDEO_OV8856
|
||||
tristate "OmniVision OV8856 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV8856 camera sensor.
|
||||
@ -661,10 +506,7 @@ config VIDEO_OV8856
|
||||
|
||||
config VIDEO_OV8858
|
||||
tristate "OmniVision OV8858 sensor support"
|
||||
depends on I2C && PM && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on PM
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for OmniVision
|
||||
OV8858 camera sensor.
|
||||
@ -674,10 +516,7 @@ config VIDEO_OV8858
|
||||
|
||||
config VIDEO_OV8865
|
||||
tristate "OmniVision OV8865 sensor support"
|
||||
depends on I2C && PM && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on PM
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for OmniVision
|
||||
OV8865 camera sensor.
|
||||
@ -688,10 +527,6 @@ config VIDEO_OV8865
|
||||
config VIDEO_OV9282
|
||||
tristate "OmniVision OV9282 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_DEV
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV9282 camera sensor.
|
||||
@ -701,16 +536,12 @@ config VIDEO_OV9282
|
||||
|
||||
config VIDEO_OV9640
|
||||
tristate "OmniVision OV9640 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV9640 camera sensor.
|
||||
|
||||
config VIDEO_OV9650
|
||||
tristate "OmniVision OV9650/OV9652 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select REGMAP_SCCB
|
||||
help
|
||||
This is a V4L2 sensor driver for the Omnivision
|
||||
@ -718,11 +549,7 @@ config VIDEO_OV9650
|
||||
|
||||
config VIDEO_OV9734
|
||||
tristate "OmniVision OV9734 sensor support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
depends on ACPI || COMPILE_TEST
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV9734 camera.
|
||||
@ -732,10 +559,6 @@ config VIDEO_OV9734
|
||||
|
||||
config VIDEO_RDACM20
|
||||
tristate "IMI RDACM20 camera support"
|
||||
depends on I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_MAX9271_LIB
|
||||
help
|
||||
This driver supports the IMI RDACM20 GMSL camera, used in
|
||||
@ -746,10 +569,6 @@ config VIDEO_RDACM20
|
||||
|
||||
config VIDEO_RDACM21
|
||||
tristate "IMI RDACM21 camera support"
|
||||
depends on I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_MAX9271_LIB
|
||||
help
|
||||
This driver supports the IMI RDACM21 GMSL camera, used in
|
||||
@ -760,7 +579,6 @@ config VIDEO_RDACM21
|
||||
|
||||
config VIDEO_RJ54N1
|
||||
tristate "Sharp RJ54N1CB0C sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
help
|
||||
This is a V4L2 sensor driver for Sharp RJ54N1CB0C CMOS image
|
||||
sensor.
|
||||
@ -770,39 +588,26 @@ config VIDEO_RJ54N1
|
||||
|
||||
config VIDEO_S5C73M3
|
||||
tristate "Samsung S5C73M3 sensor support"
|
||||
depends on I2C && SPI && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on SPI
|
||||
help
|
||||
This is a V4L2 sensor driver for Samsung S5C73M3
|
||||
8 Mpixel camera.
|
||||
|
||||
config VIDEO_S5K5BAF
|
||||
tristate "Samsung S5K5BAF sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a V4L2 sensor driver for Samsung S5K5BAF 2M
|
||||
camera sensor with an embedded SoC image signal processor.
|
||||
|
||||
config VIDEO_S5K6A3
|
||||
tristate "Samsung S5K6A3 sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
This is a V4L2 sensor driver for Samsung S5K6A3 raw
|
||||
camera sensor.
|
||||
|
||||
config VIDEO_ST_VGXY61
|
||||
tristate "ST VGXY61 sensor support"
|
||||
depends on OF && GPIOLIB && VIDEO_DEV && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
depends on OF && GPIOLIB
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the ST VGXY61
|
||||
camera sensor.
|
||||
@ -810,7 +615,7 @@ config VIDEO_ST_VGXY61
|
||||
source "drivers/media/i2c/ccs/Kconfig"
|
||||
source "drivers/media/i2c/et8ek8/Kconfig"
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
menu "Lens drivers"
|
||||
visible if MEDIA_CAMERA_SUPPORT
|
||||
@ -848,6 +653,18 @@ config VIDEO_DW9714
|
||||
capability. This is designed for linear control of
|
||||
voice coil motors, controlled via I2C serial interface.
|
||||
|
||||
config VIDEO_DW9719
|
||||
tristate "DW9719 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_ASYNC
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a driver for the DW9719 camera lens voice coil.
|
||||
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_DEV
|
||||
@ -1625,4 +1442,51 @@ config VIDEO_THS7303
|
||||
|
||||
endmenu
|
||||
|
||||
#
|
||||
# Video serializers and deserializers (e.g. FPD-Link)
|
||||
#
|
||||
|
||||
menu "Video serializers and deserializers"
|
||||
|
||||
config VIDEO_DS90UB913
|
||||
tristate "TI DS90UB913 FPD-Link III Serializer"
|
||||
depends on OF && I2C && VIDEO_DEV && COMMON_CLK
|
||||
select I2C_ATR
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
select REGMAP_I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
Device driver for the Texas Instruments DS90UB913
|
||||
FPD-Link III Serializer.
|
||||
|
||||
config VIDEO_DS90UB953
|
||||
tristate "TI FPD-Link III/IV CSI-2 Serializers"
|
||||
depends on OF && I2C && VIDEO_DEV && COMMON_CLK
|
||||
select I2C_ATR
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
select REGMAP_I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
Device driver for the Texas Instruments DS90UB953
|
||||
FPD-Link III Serializer and DS90UB971 FPD-Link IV Serializer.
|
||||
|
||||
config VIDEO_DS90UB960
|
||||
tristate "TI FPD-Link III/IV Deserializers"
|
||||
depends on OF && I2C && VIDEO_DEV && COMMON_CLK
|
||||
select I2C_ATR
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
select REGMAP_I2C
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
help
|
||||
Device driver for the Texas Instruments DS90UB960
|
||||
FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # VIDEO_DEV
|
||||
|
@ -28,7 +28,11 @@ obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
|
||||
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
|
||||
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
|
||||
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
|
||||
obj-$(CONFIG_VIDEO_DS90UB913) += ds90ub913.o
|
||||
obj-$(CONFIG_VIDEO_DS90UB953) += ds90ub953.o
|
||||
obj-$(CONFIG_VIDEO_DS90UB960) += ds90ub960.o
|
||||
obj-$(CONFIG_VIDEO_DW9714) += dw9714.o
|
||||
obj-$(CONFIG_VIDEO_DW9719) += dw9719.o
|
||||
obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
|
||||
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
|
||||
obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
|
||||
|
@ -349,7 +349,6 @@ static void ad5820_remove(struct i2c_client *client)
|
||||
static const struct i2c_device_id ad5820_id_table[] = {
|
||||
{ "ad5820", 0 },
|
||||
{ "ad5821", 0 },
|
||||
{ "ad5823", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad5820_id_table);
|
||||
@ -357,7 +356,6 @@ MODULE_DEVICE_TABLE(i2c, ad5820_id_table);
|
||||
static const struct of_device_id ad5820_of_table[] = {
|
||||
{ .compatible = "adi,ad5820" },
|
||||
{ .compatible = "adi,ad5821" },
|
||||
{ .compatible = "adi,ad5823" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad5820_of_table);
|
||||
|
@ -300,9 +300,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
|
||||
MEDIA_ENT_F_VID_IF_BRIDGE,
|
||||
is_txa(tx) ? "txa" : "txb");
|
||||
|
||||
/* Ensure that matching is based upon the endpoint fwnodes */
|
||||
tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
|
||||
|
||||
/* Register internal ops for incremental subdev registration */
|
||||
tx->sd.internal_ops = &adv748x_csi2_internal_ops;
|
||||
|
||||
@ -314,10 +311,15 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adv748x_csi2_init_controls(tx);
|
||||
ret = v4l2_async_subdev_endpoint_add(&tx->sd,
|
||||
of_fwnode_handle(state->endpoints[tx->port]));
|
||||
if (ret)
|
||||
goto err_free_media;
|
||||
|
||||
ret = adv748x_csi2_init_controls(tx);
|
||||
if (ret)
|
||||
goto err_cleanup_subdev;
|
||||
|
||||
ret = v4l2_async_register_subdev(&tx->sd);
|
||||
if (ret)
|
||||
goto err_free_ctrl;
|
||||
@ -326,6 +328,8 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
|
||||
|
||||
err_free_ctrl:
|
||||
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
|
||||
err_cleanup_subdev:
|
||||
v4l2_subdev_cleanup(&tx->sd);
|
||||
err_free_media:
|
||||
media_entity_cleanup(&tx->sd.entity);
|
||||
|
||||
@ -340,4 +344,5 @@ void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
|
||||
v4l2_async_unregister_subdev(&tx->sd);
|
||||
media_entity_cleanup(&tx->sd.entity);
|
||||
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
|
||||
v4l2_subdev_cleanup(&tx->sd);
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ __ccs_pll_calculate_vt_tree(struct device *dev,
|
||||
struct ccs_pll_branch_fr *pll_fr = &pll->vt_fr;
|
||||
struct ccs_pll_branch_bk *pll_bk = &pll->vt_bk;
|
||||
u32 more_mul;
|
||||
u16 best_pix_div = SHRT_MAX >> 1, best_div;
|
||||
u16 best_pix_div = SHRT_MAX >> 1, best_div = lim_bk->max_sys_clk_div;
|
||||
u16 vt_div, min_sys_div, max_sys_div, sys_div;
|
||||
|
||||
pll_fr->pll_ip_clk_freq_hz =
|
||||
|
@ -1,11 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config VIDEO_CCS
|
||||
tristate "MIPI CCS/SMIA++/SMIA sensor support"
|
||||
depends on I2C && VIDEO_DEV && HAVE_CLK
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
depends on HAVE_CLK
|
||||
select VIDEO_CCS_PLL
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant
|
||||
camera sensors.
|
||||
|
@ -464,8 +464,7 @@ static int ccs_data_parse_rules(struct bin_container *bin,
|
||||
rule_payload = __rule_type + 1;
|
||||
rule_plen2 = rule_plen - sizeof(*__rule_type);
|
||||
|
||||
switch (*__rule_type) {
|
||||
case CCS_DATA_BLOCK_RULE_ID_IF: {
|
||||
if (*__rule_type == CCS_DATA_BLOCK_RULE_ID_IF) {
|
||||
const struct __ccs_data_block_rule_if *__if_rules =
|
||||
rule_payload;
|
||||
const size_t __num_if_rules =
|
||||
@ -514,49 +513,61 @@ static int ccs_data_parse_rules(struct bin_container *bin,
|
||||
rules->if_rules = if_rule;
|
||||
rules->num_if_rules = __num_if_rules;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
|
||||
rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
|
||||
&rules->num_read_only_regs,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_FFD:
|
||||
rval = ccs_data_parse_ffd(bin, &rules->frame_format,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_MSR:
|
||||
rval = ccs_data_parse_reg_rules(bin,
|
||||
&rules->manufacturer_regs,
|
||||
&rules->num_manufacturer_regs,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
|
||||
rval = ccs_data_parse_pdaf_readout(bin,
|
||||
&rules->pdaf_readout,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev,
|
||||
"Don't know how to handle rule type %u!\n",
|
||||
*__rule_type);
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* Check there was an if rule before any other rules */
|
||||
if (bin->base && !rules)
|
||||
return -EINVAL;
|
||||
|
||||
switch (*__rule_type) {
|
||||
case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
|
||||
rval = ccs_data_parse_reg_rules(bin,
|
||||
rules ?
|
||||
&rules->read_only_regs : NULL,
|
||||
rules ?
|
||||
&rules->num_read_only_regs : NULL,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_FFD:
|
||||
rval = ccs_data_parse_ffd(bin, rules ?
|
||||
&rules->frame_format : NULL,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_MSR:
|
||||
rval = ccs_data_parse_reg_rules(bin,
|
||||
rules ?
|
||||
&rules->manufacturer_regs : NULL,
|
||||
rules ?
|
||||
&rules->num_manufacturer_regs : NULL,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
|
||||
rval = ccs_data_parse_pdaf_readout(bin,
|
||||
rules ?
|
||||
&rules->pdaf_readout : NULL,
|
||||
rule_payload,
|
||||
rule_payload + rule_plen2,
|
||||
dev);
|
||||
if (rval)
|
||||
return rval;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev,
|
||||
"Don't know how to handle rule type %u!\n",
|
||||
*__rule_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
__next_rule = __next_rule + rule_hlen + rule_plen;
|
||||
}
|
||||
|
903
drivers/media/i2c/ds90ub913.c
Normal file
903
drivers/media/i2c/ds90ub913.c
Normal file
@ -0,0 +1,903 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for the Texas Instruments DS90UB913 video serializer
|
||||
*
|
||||
* Based on a driver from Luca Ceresoli <luca@lucaceresoli.net>
|
||||
*
|
||||
* Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net>
|
||||
* Copyright (c) 2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c-atr.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <media/i2c/ds90ub9xx.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-mediabus.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#define UB913_PAD_SINK 0
|
||||
#define UB913_PAD_SOURCE 1
|
||||
|
||||
/*
|
||||
* UB913 has 4 gpios, but gpios 3 and 4 are reserved for external oscillator
|
||||
* mode. Thus we only support 2 gpios for now.
|
||||
*/
|
||||
#define UB913_NUM_GPIOS 2
|
||||
|
||||
#define UB913_REG_RESET_CTL 0x01
|
||||
#define UB913_REG_RESET_CTL_DIGITAL_RESET_1 BIT(1)
|
||||
#define UB913_REG_RESET_CTL_DIGITAL_RESET_0 BIT(0)
|
||||
|
||||
#define UB913_REG_GENERAL_CFG 0x03
|
||||
#define UB913_REG_GENERAL_CFG_CRC_ERR_RESET BIT(5)
|
||||
#define UB913_REG_GENERAL_CFG_PCLK_RISING BIT(0)
|
||||
|
||||
#define UB913_REG_MODE_SEL 0x05
|
||||
#define UB913_REG_MODE_SEL_MODE_OVERRIDE BIT(5)
|
||||
#define UB913_REG_MODE_SEL_MODE_UP_TO_DATE BIT(4)
|
||||
#define UB913_REG_MODE_SEL_MODE_MASK GENMASK(3, 0)
|
||||
|
||||
#define UB913_REG_CRC_ERRORS_LSB 0x0a
|
||||
#define UB913_REG_CRC_ERRORS_MSB 0x0b
|
||||
|
||||
#define UB913_REG_GENERAL_STATUS 0x0c
|
||||
|
||||
#define UB913_REG_GPIO_CFG(n) (0x0d + (n))
|
||||
#define UB913_REG_GPIO_CFG_ENABLE(n) BIT(0 + (n) * 4)
|
||||
#define UB913_REG_GPIO_CFG_DIR_INPUT(n) BIT(1 + (n) * 4)
|
||||
#define UB913_REG_GPIO_CFG_REMOTE_EN(n) BIT(2 + (n) * 4)
|
||||
#define UB913_REG_GPIO_CFG_OUT_VAL(n) BIT(3 + (n) * 4)
|
||||
#define UB913_REG_GPIO_CFG_MASK(n) (0xf << ((n) * 4))
|
||||
|
||||
#define UB913_REG_SCL_HIGH_TIME 0x11
|
||||
#define UB913_REG_SCL_LOW_TIME 0x12
|
||||
|
||||
#define UB913_REG_PLL_OVR 0x35
|
||||
|
||||
struct ub913_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct clk *clkin;
|
||||
|
||||
struct gpio_chip gpio_chip;
|
||||
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pads[2];
|
||||
|
||||
struct v4l2_async_notifier notifier;
|
||||
|
||||
struct v4l2_subdev *source_sd;
|
||||
u16 source_sd_pad;
|
||||
|
||||
u64 enabled_source_streams;
|
||||
|
||||
struct clk_hw *clkout_clk_hw;
|
||||
|
||||
struct ds90ub9xx_platform_data *plat_data;
|
||||
|
||||
bool pclk_polarity_rising;
|
||||
};
|
||||
|
||||
static inline struct ub913_data *sd_to_ub913(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct ub913_data, sd);
|
||||
}
|
||||
|
||||
struct ub913_format_info {
|
||||
u32 incode;
|
||||
u32 outcode;
|
||||
};
|
||||
|
||||
static const struct ub913_format_info ub913_formats[] = {
|
||||
/* Only RAW10 with 8-bit payload is supported at the moment */
|
||||
{ .incode = MEDIA_BUS_FMT_YUYV8_2X8, .outcode = MEDIA_BUS_FMT_YUYV8_1X16 },
|
||||
{ .incode = MEDIA_BUS_FMT_UYVY8_2X8, .outcode = MEDIA_BUS_FMT_UYVY8_1X16 },
|
||||
{ .incode = MEDIA_BUS_FMT_VYUY8_2X8, .outcode = MEDIA_BUS_FMT_VYUY8_1X16 },
|
||||
{ .incode = MEDIA_BUS_FMT_YVYU8_2X8, .outcode = MEDIA_BUS_FMT_YVYU8_1X16 },
|
||||
};
|
||||
|
||||
static const struct ub913_format_info *ub913_find_format(u32 incode)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ub913_formats); i++) {
|
||||
if (ub913_formats[i].incode == incode)
|
||||
return &ub913_formats[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ub913_read(const struct ub913_data *priv, u8 reg, u8 *val)
|
||||
{
|
||||
unsigned int v;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(priv->regmap, reg, &v);
|
||||
if (ret < 0) {
|
||||
dev_err(&priv->client->dev,
|
||||
"Cannot read register 0x%02x: %d!\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_write(const struct ub913_data *priv, u8 reg, u8 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(priv->regmap, reg, val);
|
||||
if (ret < 0)
|
||||
dev_err(&priv->client->dev,
|
||||
"Cannot write register 0x%02x: %d!\n", reg, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPIO chip
|
||||
*/
|
||||
static int ub913_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int ub913_gpio_direction_out(struct gpio_chip *gc, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct ub913_data *priv = gpiochip_get_data(gc);
|
||||
unsigned int reg_idx = offset / 2;
|
||||
unsigned int field_idx = offset % 2;
|
||||
|
||||
return regmap_update_bits(priv->regmap, UB913_REG_GPIO_CFG(reg_idx),
|
||||
UB913_REG_GPIO_CFG_MASK(field_idx),
|
||||
UB913_REG_GPIO_CFG_ENABLE(field_idx) |
|
||||
(value ? UB913_REG_GPIO_CFG_OUT_VAL(field_idx) :
|
||||
0));
|
||||
}
|
||||
|
||||
static void ub913_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
ub913_gpio_direction_out(gc, offset, value);
|
||||
}
|
||||
|
||||
static int ub913_gpio_of_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags)
|
||||
{
|
||||
if (flags)
|
||||
*flags = gpiospec->args[1];
|
||||
|
||||
return gpiospec->args[0];
|
||||
}
|
||||
|
||||
static int ub913_gpiochip_probe(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct gpio_chip *gc = &priv->gpio_chip;
|
||||
int ret;
|
||||
|
||||
/* Initialize GPIOs 0 and 1 to local control, tri-state */
|
||||
ub913_write(priv, UB913_REG_GPIO_CFG(0), 0);
|
||||
|
||||
gc->label = dev_name(dev);
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->base = -1;
|
||||
gc->can_sleep = true;
|
||||
gc->ngpio = UB913_NUM_GPIOS;
|
||||
gc->get_direction = ub913_gpio_get_direction;
|
||||
gc->direction_output = ub913_gpio_direction_out;
|
||||
gc->set = ub913_gpio_set;
|
||||
gc->of_xlate = ub913_gpio_of_xlate;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
ret = gpiochip_add_data(gc, priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add GPIOs: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ub913_gpiochip_remove(struct ub913_data *priv)
|
||||
{
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
}
|
||||
|
||||
static const struct regmap_config ub913_regmap_config = {
|
||||
.name = "ds90ub913",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.reg_format_endian = REGMAP_ENDIAN_DEFAULT,
|
||||
.val_format_endian = REGMAP_ENDIAN_DEFAULT,
|
||||
};
|
||||
|
||||
/*
|
||||
* V4L2
|
||||
*/
|
||||
|
||||
static int ub913_enable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state, u32 pad,
|
||||
u64 streams_mask)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
u64 sink_streams;
|
||||
int ret;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, UB913_PAD_SOURCE,
|
||||
UB913_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
ret = v4l2_subdev_enable_streams(priv->source_sd, priv->source_sd_pad,
|
||||
sink_streams);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->enabled_source_streams |= streams_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_disable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state, u32 pad,
|
||||
u64 streams_mask)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
u64 sink_streams;
|
||||
int ret;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, UB913_PAD_SOURCE,
|
||||
UB913_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
ret = v4l2_subdev_disable_streams(priv->source_sd, priv->source_sd_pad,
|
||||
sink_streams);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->enabled_source_streams &= ~streams_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ub913_set_routing(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_krouting *routing)
|
||||
{
|
||||
static const struct v4l2_mbus_framefmt in_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.code = MEDIA_BUS_FMT_UYVY8_2X8,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.ycbcr_enc = V4L2_YCBCR_ENC_601,
|
||||
.quantization = V4L2_QUANTIZATION_LIM_RANGE,
|
||||
.xfer_func = V4L2_XFER_FUNC_SRGB,
|
||||
};
|
||||
static const struct v4l2_mbus_framefmt out_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.code = MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.ycbcr_enc = V4L2_YCBCR_ENC_601,
|
||||
.quantization = V4L2_QUANTIZATION_LIM_RANGE,
|
||||
.xfer_func = V4L2_XFER_FUNC_SRGB,
|
||||
};
|
||||
struct v4l2_subdev_stream_configs *stream_configs;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
|
||||
* frame desc is made dynamically allocated.
|
||||
*/
|
||||
|
||||
if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = v4l2_subdev_set_routing(sd, state, routing);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
stream_configs = &state->stream_configs;
|
||||
|
||||
for (i = 0; i < stream_configs->num_configs; i++) {
|
||||
if (stream_configs->configs[i].pad == UB913_PAD_SINK)
|
||||
stream_configs->configs[i].fmt = in_format;
|
||||
else
|
||||
stream_configs->configs[i].fmt = out_format;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_set_routing(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
enum v4l2_subdev_format_whence which,
|
||||
struct v4l2_subdev_krouting *routing)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
|
||||
if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
|
||||
return -EBUSY;
|
||||
|
||||
return _ub913_set_routing(sd, state, routing);
|
||||
}
|
||||
|
||||
static int ub913_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
|
||||
struct v4l2_mbus_frame_desc *fd)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
const struct v4l2_subdev_krouting *routing;
|
||||
struct v4l2_mbus_frame_desc source_fd;
|
||||
struct v4l2_subdev_route *route;
|
||||
struct v4l2_subdev_state *state;
|
||||
int ret;
|
||||
|
||||
if (pad != UB913_PAD_SOURCE)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_subdev_call(priv->source_sd, pad, get_frame_desc,
|
||||
priv->source_sd_pad, &source_fd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(fd, 0, sizeof(*fd));
|
||||
|
||||
fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
|
||||
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
|
||||
routing = &state->routing;
|
||||
|
||||
for_each_active_route(routing, route) {
|
||||
unsigned int i;
|
||||
|
||||
if (route->source_pad != pad)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < source_fd.num_entries; i++) {
|
||||
if (source_fd.entry[i].stream == route->sink_stream)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == source_fd.num_entries) {
|
||||
dev_err(&priv->client->dev,
|
||||
"Failed to find stream from source frame desc\n");
|
||||
ret = -EPIPE;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
fd->entry[fd->num_entries].stream = route->source_stream;
|
||||
fd->entry[fd->num_entries].flags = source_fd.entry[i].flags;
|
||||
fd->entry[fd->num_entries].length = source_fd.entry[i].length;
|
||||
fd->entry[fd->num_entries].pixelcode =
|
||||
source_fd.entry[i].pixelcode;
|
||||
|
||||
fd->num_entries++;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
v4l2_subdev_unlock_state(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ub913_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
const struct ub913_format_info *finfo;
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
|
||||
priv->enabled_source_streams)
|
||||
return -EBUSY;
|
||||
|
||||
/* Source format is fully defined by the sink format, so not settable */
|
||||
if (format->pad == UB913_PAD_SOURCE)
|
||||
return v4l2_subdev_get_fmt(sd, state, format);
|
||||
|
||||
finfo = ub913_find_format(format->format.code);
|
||||
if (!finfo) {
|
||||
finfo = &ub913_formats[0];
|
||||
format->format.code = finfo->incode;
|
||||
}
|
||||
|
||||
/* Set sink format */
|
||||
fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
|
||||
format->stream);
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
*fmt = format->format;
|
||||
|
||||
/* Propagate to source format, and adjust the mbus code */
|
||||
fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
|
||||
format->stream);
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
format->format.code = finfo->outcode;
|
||||
|
||||
*fmt = format->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_init_cfg(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
struct v4l2_subdev_route routes[] = {
|
||||
{
|
||||
.sink_pad = UB913_PAD_SINK,
|
||||
.sink_stream = 0,
|
||||
.source_pad = UB913_PAD_SOURCE,
|
||||
.source_stream = 0,
|
||||
.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
|
||||
},
|
||||
};
|
||||
|
||||
struct v4l2_subdev_krouting routing = {
|
||||
.num_routes = ARRAY_SIZE(routes),
|
||||
.routes = routes,
|
||||
};
|
||||
|
||||
return _ub913_set_routing(sd, state, &routing);
|
||||
}
|
||||
|
||||
static int ub913_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
struct device *dev = &priv->client->dev;
|
||||
u8 v = 0, v1 = 0, v2 = 0;
|
||||
|
||||
ub913_read(priv, UB913_REG_MODE_SEL, &v);
|
||||
dev_info(dev, "MODE_SEL %#02x\n", v);
|
||||
|
||||
ub913_read(priv, UB913_REG_CRC_ERRORS_LSB, &v1);
|
||||
ub913_read(priv, UB913_REG_CRC_ERRORS_MSB, &v2);
|
||||
dev_info(dev, "CRC errors %u\n", v1 | (v2 << 8));
|
||||
|
||||
/* clear CRC errors */
|
||||
ub913_read(priv, UB913_REG_GENERAL_CFG, &v);
|
||||
ub913_write(priv, UB913_REG_GENERAL_CFG,
|
||||
v | UB913_REG_GENERAL_CFG_CRC_ERR_RESET);
|
||||
ub913_write(priv, UB913_REG_GENERAL_CFG, v);
|
||||
|
||||
ub913_read(priv, UB913_REG_GENERAL_STATUS, &v);
|
||||
dev_info(dev, "GENERAL_STATUS %#02x\n", v);
|
||||
|
||||
ub913_read(priv, UB913_REG_PLL_OVR, &v);
|
||||
dev_info(dev, "PLL_OVR %#02x\n", v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_core_ops ub913_subdev_core_ops = {
|
||||
.log_status = ub913_log_status,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops ub913_pad_ops = {
|
||||
.enable_streams = ub913_enable_streams,
|
||||
.disable_streams = ub913_disable_streams,
|
||||
.set_routing = ub913_set_routing,
|
||||
.get_frame_desc = ub913_get_frame_desc,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = ub913_set_fmt,
|
||||
.init_cfg = ub913_init_cfg,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops ub913_subdev_ops = {
|
||||
.core = &ub913_subdev_core_ops,
|
||||
.pad = &ub913_pad_ops,
|
||||
};
|
||||
|
||||
static const struct media_entity_operations ub913_entity_ops = {
|
||||
.link_validate = v4l2_subdev_link_validate,
|
||||
};
|
||||
|
||||
static int ub913_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *source_subdev,
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct ub913_data *priv = sd_to_ub913(notifier->sd);
|
||||
struct device *dev = &priv->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = media_entity_get_fwnode_pad(&source_subdev->entity,
|
||||
source_subdev->fwnode,
|
||||
MEDIA_PAD_FL_SOURCE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to find pad for %s\n",
|
||||
source_subdev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->source_sd = source_subdev;
|
||||
priv->source_sd_pad = ret;
|
||||
|
||||
ret = media_create_pad_link(&source_subdev->entity, priv->source_sd_pad,
|
||||
&priv->sd.entity, UB913_PAD_SINK,
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to link %s:%u -> %s:0\n",
|
||||
source_subdev->name, priv->source_sd_pad,
|
||||
priv->sd.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_async_notifier_operations ub913_notify_ops = {
|
||||
.bound = ub913_notify_bound,
|
||||
};
|
||||
|
||||
static int ub913_v4l2_notifier_register(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct v4l2_async_connection *asd;
|
||||
struct fwnode_handle *ep_fwnode;
|
||||
int ret;
|
||||
|
||||
ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
|
||||
UB913_PAD_SINK, 0, 0);
|
||||
if (!ep_fwnode) {
|
||||
dev_err(dev, "No graph endpoint\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
|
||||
|
||||
asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep_fwnode,
|
||||
struct v4l2_async_connection);
|
||||
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
|
||||
if (IS_ERR(asd)) {
|
||||
dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd));
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
return PTR_ERR(asd);
|
||||
}
|
||||
|
||||
priv->notifier.ops = &ub913_notify_ops;
|
||||
|
||||
ret = v4l2_async_nf_register(&priv->notifier);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register subdev_notifier");
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ub913_v4l2_nf_unregister(struct ub913_data *priv)
|
||||
{
|
||||
v4l2_async_nf_unregister(&priv->notifier);
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
}
|
||||
|
||||
static int ub913_register_clkout(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "ds90ub913.%s.clk_out", dev_name(dev));
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->clkout_clk_hw = devm_clk_hw_register_fixed_factor(dev, name,
|
||||
__clk_get_name(priv->clkin), 0, 1, 2);
|
||||
|
||||
kfree(name);
|
||||
|
||||
if (IS_ERR(priv->clkout_clk_hw))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clkout_clk_hw),
|
||||
"Cannot register clkout hw\n");
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
priv->clkout_clk_hw);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Cannot add OF clock provider\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_i2c_master_init(struct ub913_data *priv)
|
||||
{
|
||||
/* i2c fast mode */
|
||||
u32 scl_high = 600 + 300; /* high period + rise time, ns */
|
||||
u32 scl_low = 1300 + 300; /* low period + fall time, ns */
|
||||
unsigned long ref;
|
||||
int ret;
|
||||
|
||||
ref = clk_get_rate(priv->clkin) / 2;
|
||||
|
||||
scl_high = div64_u64((u64)scl_high * ref, 1000000000);
|
||||
scl_low = div64_u64((u64)scl_low * ref, 1000000000);
|
||||
|
||||
ret = ub913_write(priv, UB913_REG_SCL_HIGH_TIME, scl_high);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ub913_write(priv, UB913_REG_SCL_LOW_TIME, scl_low);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_add_i2c_adapter(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct fwnode_handle *i2c_handle;
|
||||
int ret;
|
||||
|
||||
i2c_handle = device_get_named_child_node(dev, "i2c");
|
||||
if (!i2c_handle)
|
||||
return 0;
|
||||
|
||||
ret = i2c_atr_add_adapter(priv->plat_data->atr, priv->plat_data->port,
|
||||
dev, i2c_handle);
|
||||
|
||||
fwnode_handle_put(i2c_handle);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_parse_dt(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct v4l2_fwnode_endpoint vep = {
|
||||
.bus_type = V4L2_MBUS_PARALLEL,
|
||||
};
|
||||
struct fwnode_handle *ep_fwnode;
|
||||
int ret;
|
||||
|
||||
ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
|
||||
UB913_PAD_SINK, 0, 0);
|
||||
if (!ep_fwnode)
|
||||
return dev_err_probe(dev, -ENOENT, "No sink endpoint\n");
|
||||
|
||||
ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep);
|
||||
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to parse sink endpoint data\n");
|
||||
|
||||
if (vep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
|
||||
priv->pclk_polarity_rising = true;
|
||||
else if (vep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
|
||||
priv->pclk_polarity_rising = false;
|
||||
else
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"bad value for 'pclk-sample'\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_hw_init(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
bool mode_override;
|
||||
u8 mode;
|
||||
int ret;
|
||||
u8 v;
|
||||
|
||||
ret = ub913_read(priv, UB913_REG_MODE_SEL, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(v & UB913_REG_MODE_SEL_MODE_UP_TO_DATE))
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"Mode value not stabilized\n");
|
||||
|
||||
mode_override = v & UB913_REG_MODE_SEL_MODE_OVERRIDE;
|
||||
mode = v & UB913_REG_MODE_SEL_MODE_MASK;
|
||||
|
||||
dev_dbg(dev, "mode from %s: %#x\n",
|
||||
mode_override ? "reg" : "deserializer", mode);
|
||||
|
||||
ret = ub913_i2c_master_init(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "i2c master init failed\n");
|
||||
|
||||
ub913_read(priv, UB913_REG_GENERAL_CFG, &v);
|
||||
v &= ~UB913_REG_GENERAL_CFG_PCLK_RISING;
|
||||
v |= priv->pclk_polarity_rising ? UB913_REG_GENERAL_CFG_PCLK_RISING : 0;
|
||||
ub913_write(priv, UB913_REG_GENERAL_CFG, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub913_subdev_init(struct ub913_data *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
int ret;
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub913_subdev_ops);
|
||||
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
|
||||
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
|
||||
priv->sd.entity.ops = &ub913_entity_ops;
|
||||
|
||||
priv->pads[0].flags = MEDIA_PAD_FL_SINK;
|
||||
priv->pads[1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to init pads\n");
|
||||
|
||||
ret = v4l2_subdev_init_finalize(&priv->sd);
|
||||
if (ret)
|
||||
goto err_entity_cleanup;
|
||||
|
||||
ret = ub913_v4l2_notifier_register(priv);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret,
|
||||
"v4l2 subdev notifier register failed\n");
|
||||
goto err_subdev_cleanup;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev(&priv->sd);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "v4l2_async_register_subdev error\n");
|
||||
goto err_unreg_notif;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unreg_notif:
|
||||
ub913_v4l2_nf_unregister(priv);
|
||||
err_subdev_cleanup:
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
err_entity_cleanup:
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ub913_subdev_uninit(struct ub913_data *priv)
|
||||
{
|
||||
v4l2_async_unregister_subdev(&priv->sd);
|
||||
ub913_v4l2_nf_unregister(priv);
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
fwnode_handle_put(priv->sd.fwnode);
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
}
|
||||
|
||||
static int ub913_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct ub913_data *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->client = client;
|
||||
|
||||
priv->plat_data = dev_get_platdata(&client->dev);
|
||||
if (!priv->plat_data)
|
||||
return dev_err_probe(dev, -ENODEV, "Platform data missing\n");
|
||||
|
||||
priv->regmap = devm_regmap_init_i2c(client, &ub913_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->regmap),
|
||||
"Failed to init regmap\n");
|
||||
|
||||
/*
|
||||
* ub913 can also work without ext clock, but that is not supported by
|
||||
* the driver yet.
|
||||
*/
|
||||
priv->clkin = devm_clk_get(dev, "clkin");
|
||||
if (IS_ERR(priv->clkin))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clkin),
|
||||
"Cannot get CLKIN\n");
|
||||
|
||||
ret = ub913_parse_dt(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ub913_hw_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ub913_gpiochip_probe(priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to init gpiochip\n");
|
||||
|
||||
ret = ub913_register_clkout(priv);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "Failed to register clkout\n");
|
||||
goto err_gpiochip_remove;
|
||||
}
|
||||
|
||||
ret = ub913_subdev_init(priv);
|
||||
if (ret)
|
||||
goto err_gpiochip_remove;
|
||||
|
||||
ret = ub913_add_i2c_adapter(priv);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to add remote i2c adapter\n");
|
||||
goto err_subdev_uninit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_subdev_uninit:
|
||||
ub913_subdev_uninit(priv);
|
||||
err_gpiochip_remove:
|
||||
ub913_gpiochip_remove(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ub913_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ub913_data *priv = sd_to_ub913(sd);
|
||||
|
||||
i2c_atr_del_adapter(priv->plat_data->atr, priv->plat_data->port);
|
||||
|
||||
ub913_subdev_uninit(priv);
|
||||
|
||||
ub913_gpiochip_remove(priv);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ub913_id[] = { { "ds90ub913a-q1", 0 }, {} };
|
||||
MODULE_DEVICE_TABLE(i2c, ub913_id);
|
||||
|
||||
static const struct of_device_id ub913_dt_ids[] = {
|
||||
{ .compatible = "ti,ds90ub913a-q1" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ub913_dt_ids);
|
||||
|
||||
static struct i2c_driver ds90ub913_driver = {
|
||||
.probe = ub913_probe,
|
||||
.remove = ub913_remove,
|
||||
.id_table = ub913_id,
|
||||
.driver = {
|
||||
.name = "ds90ub913a",
|
||||
.of_match_table = ub913_dt_ids,
|
||||
},
|
||||
};
|
||||
module_i2c_driver(ds90ub913_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Texas Instruments DS90UB913 FPD-Link III Serializer Driver");
|
||||
MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
|
||||
MODULE_IMPORT_NS(I2C_ATR);
|
1430
drivers/media/i2c/ds90ub953.c
Normal file
1430
drivers/media/i2c/ds90ub953.c
Normal file
File diff suppressed because it is too large
Load Diff
4059
drivers/media/i2c/ds90ub960.c
Normal file
4059
drivers/media/i2c/ds90ub960.c
Normal file
File diff suppressed because it is too large
Load Diff
350
drivers/media/i2c/dw9719.c
Normal file
350
drivers/media/i2c/dw9719.c
Normal file
@ -0,0 +1,350 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2012 Intel Corporation
|
||||
|
||||
/*
|
||||
* Based on linux/modules/camera/drivers/media/i2c/imx/dw9719.c in this repo:
|
||||
* https://github.com/ZenfoneArea/android_kernel_asus_zenfone5
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#define DW9719_MAX_FOCUS_POS 1023
|
||||
#define DW9719_CTRL_STEPS 16
|
||||
#define DW9719_CTRL_DELAY_US 1000
|
||||
|
||||
#define DW9719_INFO CCI_REG8(0)
|
||||
#define DW9719_ID 0xF1
|
||||
|
||||
#define DW9719_CONTROL CCI_REG8(2)
|
||||
#define DW9719_ENABLE_RINGING 0x02
|
||||
|
||||
#define DW9719_VCM_CURRENT CCI_REG16(3)
|
||||
|
||||
#define DW9719_MODE CCI_REG8(6)
|
||||
#define DW9719_MODE_SAC_SHIFT 4
|
||||
#define DW9719_MODE_SAC3 4
|
||||
|
||||
#define DW9719_VCM_FREQ CCI_REG8(7)
|
||||
#define DW9719_DEFAULT_VCM_FREQ 0x60
|
||||
|
||||
#define to_dw9719_device(x) container_of(x, struct dw9719_device, sd)
|
||||
|
||||
struct dw9719_device {
|
||||
struct v4l2_subdev sd;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regulator *regulator;
|
||||
u32 sac_mode;
|
||||
u32 vcm_freq;
|
||||
|
||||
struct dw9719_v4l2_ctrls {
|
||||
struct v4l2_ctrl_handler handler;
|
||||
struct v4l2_ctrl *focus;
|
||||
} ctrls;
|
||||
};
|
||||
|
||||
static int dw9719_detect(struct dw9719_device *dw9719)
|
||||
{
|
||||
int ret;
|
||||
u64 val;
|
||||
|
||||
ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (val != DW9719_ID) {
|
||||
dev_err(dw9719->dev, "Failed to detect correct id\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw9719_power_down(struct dw9719_device *dw9719)
|
||||
{
|
||||
return regulator_disable(dw9719->regulator);
|
||||
}
|
||||
|
||||
static int dw9719_power_up(struct dw9719_device *dw9719)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(dw9719->regulator);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Jiggle SCL pin to wake up device */
|
||||
cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret);
|
||||
|
||||
/* Need 100us to transit from SHUTDOWN to STANDBY */
|
||||
fsleep(100);
|
||||
|
||||
cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret);
|
||||
cci_write(dw9719->regmap, DW9719_MODE,
|
||||
dw9719->sac_mode << DW9719_MODE_SAC_SHIFT, &ret);
|
||||
cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret);
|
||||
|
||||
if (ret)
|
||||
dw9719_power_down(dw9719);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw9719_t_focus_abs(struct dw9719_device *dw9719, s32 value)
|
||||
{
|
||||
return cci_write(dw9719->regmap, DW9719_VCM_CURRENT, value, NULL);
|
||||
}
|
||||
|
||||
static int dw9719_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct dw9719_device *dw9719 = container_of(ctrl->handler,
|
||||
struct dw9719_device,
|
||||
ctrls.handler);
|
||||
int ret;
|
||||
|
||||
/* Only apply changes to the controls if the device is powered up */
|
||||
if (!pm_runtime_get_if_in_use(dw9719->dev))
|
||||
return 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_FOCUS_ABSOLUTE:
|
||||
ret = dw9719_t_focus_abs(dw9719, ctrl->val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_put(dw9719->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops dw9719_ctrl_ops = {
|
||||
.s_ctrl = dw9719_set_ctrl,
|
||||
};
|
||||
|
||||
static int dw9719_suspend(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct dw9719_device *dw9719 = to_dw9719_device(sd);
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
for (val = dw9719->ctrls.focus->val; val >= 0;
|
||||
val -= DW9719_CTRL_STEPS) {
|
||||
ret = dw9719_t_focus_abs(dw9719, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(DW9719_CTRL_DELAY_US, DW9719_CTRL_DELAY_US + 10);
|
||||
}
|
||||
|
||||
return dw9719_power_down(dw9719);
|
||||
}
|
||||
|
||||
static int dw9719_resume(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct dw9719_device *dw9719 = to_dw9719_device(sd);
|
||||
int current_focus = dw9719->ctrls.focus->val;
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
ret = dw9719_power_up(dw9719);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (val = current_focus % DW9719_CTRL_STEPS; val < current_focus;
|
||||
val += DW9719_CTRL_STEPS) {
|
||||
ret = dw9719_t_focus_abs(dw9719, val);
|
||||
if (ret)
|
||||
goto err_power_down;
|
||||
|
||||
usleep_range(DW9719_CTRL_DELAY_US, DW9719_CTRL_DELAY_US + 10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_down:
|
||||
dw9719_power_down(dw9719);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw9719_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
return pm_runtime_resume_and_get(sd->dev);
|
||||
}
|
||||
|
||||
static int dw9719_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
pm_runtime_put(sd->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops dw9719_internal_ops = {
|
||||
.open = dw9719_open,
|
||||
.close = dw9719_close,
|
||||
};
|
||||
|
||||
static int dw9719_init_controls(struct dw9719_device *dw9719)
|
||||
{
|
||||
const struct v4l2_ctrl_ops *ops = &dw9719_ctrl_ops;
|
||||
int ret;
|
||||
|
||||
v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1);
|
||||
|
||||
dw9719->ctrls.focus = v4l2_ctrl_new_std(&dw9719->ctrls.handler, ops,
|
||||
V4L2_CID_FOCUS_ABSOLUTE, 0,
|
||||
DW9719_MAX_FOCUS_POS, 1, 0);
|
||||
|
||||
if (dw9719->ctrls.handler.error) {
|
||||
dev_err(dw9719->dev, "Error initialising v4l2 ctrls\n");
|
||||
ret = dw9719->ctrls.handler.error;
|
||||
goto err_free_handler;
|
||||
}
|
||||
|
||||
dw9719->sd.ctrl_handler = &dw9719->ctrls.handler;
|
||||
return 0;
|
||||
|
||||
err_free_handler:
|
||||
v4l2_ctrl_handler_free(&dw9719->ctrls.handler);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_ops dw9719_ops = { };
|
||||
|
||||
static int dw9719_probe(struct i2c_client *client)
|
||||
{
|
||||
struct dw9719_device *dw9719;
|
||||
int ret;
|
||||
|
||||
dw9719 = devm_kzalloc(&client->dev, sizeof(*dw9719), GFP_KERNEL);
|
||||
if (!dw9719)
|
||||
return -ENOMEM;
|
||||
|
||||
dw9719->regmap = devm_cci_regmap_init_i2c(client, 8);
|
||||
if (IS_ERR(dw9719->regmap))
|
||||
return PTR_ERR(dw9719->regmap);
|
||||
|
||||
dw9719->dev = &client->dev;
|
||||
dw9719->sac_mode = DW9719_MODE_SAC3;
|
||||
dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ;
|
||||
|
||||
/* Optional indication of SAC mode select */
|
||||
device_property_read_u32(&client->dev, "dongwoon,sac-mode",
|
||||
&dw9719->sac_mode);
|
||||
|
||||
/* Optional indication of VCM frequency */
|
||||
device_property_read_u32(&client->dev, "dongwoon,vcm-freq",
|
||||
&dw9719->vcm_freq);
|
||||
|
||||
dw9719->regulator = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(dw9719->regulator))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(dw9719->regulator),
|
||||
"getting regulator\n");
|
||||
|
||||
v4l2_i2c_subdev_init(&dw9719->sd, client, &dw9719_ops);
|
||||
dw9719->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
dw9719->sd.internal_ops = &dw9719_internal_ops;
|
||||
|
||||
ret = dw9719_init_controls(dw9719);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = media_entity_pads_init(&dw9719->sd.entity, 0, NULL);
|
||||
if (ret < 0)
|
||||
goto err_free_ctrl_handler;
|
||||
|
||||
dw9719->sd.entity.function = MEDIA_ENT_F_LENS;
|
||||
|
||||
/*
|
||||
* We need the driver to work in the event that pm runtime is disable in
|
||||
* the kernel, so power up and verify the chip now. In the event that
|
||||
* runtime pm is disabled this will leave the chip on, so that the lens
|
||||
* will work.
|
||||
*/
|
||||
|
||||
ret = dw9719_power_up(dw9719);
|
||||
if (ret)
|
||||
goto err_cleanup_media;
|
||||
|
||||
ret = dw9719_detect(dw9719);
|
||||
if (ret)
|
||||
goto err_powerdown;
|
||||
|
||||
pm_runtime_set_active(&client->dev);
|
||||
pm_runtime_get_noresume(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
||||
ret = v4l2_async_register_subdev(&dw9719->sd);
|
||||
if (ret < 0)
|
||||
goto err_pm_runtime;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
pm_runtime_put_autosuspend(&client->dev);
|
||||
|
||||
return ret;
|
||||
|
||||
err_pm_runtime:
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
err_powerdown:
|
||||
dw9719_power_down(dw9719);
|
||||
err_cleanup_media:
|
||||
media_entity_cleanup(&dw9719->sd.entity);
|
||||
err_free_ctrl_handler:
|
||||
v4l2_ctrl_handler_free(&dw9719->ctrls.handler);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dw9719_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct dw9719_device *dw9719 =
|
||||
container_of(sd, struct dw9719_device, sd);
|
||||
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&dw9719->ctrls.handler);
|
||||
media_entity_cleanup(&dw9719->sd.entity);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
dw9719_power_down(dw9719);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id dw9719_id_table[] = {
|
||||
{ "dw9719" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, dw9719_id_table);
|
||||
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(dw9719_pm_ops, dw9719_suspend, dw9719_resume,
|
||||
NULL);
|
||||
|
||||
static struct i2c_driver dw9719_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "dw9719",
|
||||
.pm = pm_sleep_ptr(&dw9719_pm_ops),
|
||||
},
|
||||
.probe = dw9719_probe,
|
||||
.remove = dw9719_remove,
|
||||
.id_table = dw9719_id_table,
|
||||
};
|
||||
module_i2c_driver(dw9719_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
|
||||
MODULE_DESCRIPTION("DW9719 VCM Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,10 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config VIDEO_ET8EK8
|
||||
tristate "ET8EK8 camera sensor support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a driver for the Toshiba ET8EK8 5 MP camera sensor.
|
||||
It is used for example in Nokia N900 (RX-51).
|
||||
|
@ -1357,6 +1357,6 @@ static struct i2c_driver hi556_i2c_driver = {
|
||||
|
||||
module_i2c_driver(hi556_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("Hynix HI556 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -3005,6 +3005,6 @@ static struct i2c_driver hi847_i2c_driver = {
|
||||
|
||||
module_i2c_driver(hi847_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("Hynix HI847 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1109,6 +1109,6 @@ module_i2c_driver(imx208_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
|
||||
MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("Sony IMX208 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -345,7 +345,7 @@ static const char * const imx219_supply_name[] = {
|
||||
* - v flip
|
||||
* - h&v flips
|
||||
*/
|
||||
static const u32 codes[] = {
|
||||
static const u32 imx219_mbus_formats[] = {
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
@ -460,8 +460,6 @@ struct imx219 {
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
||||
struct v4l2_mbus_framefmt fmt;
|
||||
|
||||
struct clk *xclk; /* system clock to IMX219 */
|
||||
u32 xclk_freq;
|
||||
|
||||
@ -481,12 +479,6 @@ struct imx219 {
|
||||
/* Current mode */
|
||||
const struct imx219_mode *mode;
|
||||
|
||||
/*
|
||||
* Mutex for serialized access:
|
||||
* Protect sensor module set pad format and start/stop streaming safely.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
|
||||
/* Streaming on/off */
|
||||
bool streaming;
|
||||
|
||||
@ -576,64 +568,17 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
lockdep_assert_held(&imx219->mutex);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(codes); i++)
|
||||
if (codes[i] == code)
|
||||
for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
|
||||
if (imx219_mbus_formats[i] == code)
|
||||
break;
|
||||
|
||||
if (i >= ARRAY_SIZE(codes))
|
||||
if (i >= ARRAY_SIZE(imx219_mbus_formats))
|
||||
i = 0;
|
||||
|
||||
i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
|
||||
(imx219->hflip->val ? 1 : 0);
|
||||
|
||||
return codes[i];
|
||||
}
|
||||
|
||||
static void imx219_set_default_format(struct imx219 *imx219)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
fmt = &imx219->fmt;
|
||||
fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
|
||||
fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
|
||||
fmt->colorspace,
|
||||
fmt->ycbcr_enc);
|
||||
fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
|
||||
fmt->width = supported_modes[0].width;
|
||||
fmt->height = supported_modes[0].height;
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
}
|
||||
|
||||
static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
struct v4l2_mbus_framefmt *try_fmt =
|
||||
v4l2_subdev_get_try_format(sd, fh->state, 0);
|
||||
struct v4l2_rect *try_crop;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
|
||||
/* Initialize try_fmt */
|
||||
try_fmt->width = supported_modes[0].width;
|
||||
try_fmt->height = supported_modes[0].height;
|
||||
try_fmt->code = imx219_get_format_code(imx219,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10);
|
||||
try_fmt->field = V4L2_FIELD_NONE;
|
||||
|
||||
/* Initialize try_crop rectangle. */
|
||||
try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
|
||||
try_crop->top = IMX219_PIXEL_ARRAY_TOP;
|
||||
try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
|
||||
try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
|
||||
try_crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
|
||||
|
||||
mutex_unlock(&imx219->mutex);
|
||||
|
||||
return 0;
|
||||
return imx219_mbus_formats[i];
|
||||
}
|
||||
|
||||
static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
@ -725,18 +670,52 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
|
||||
.s_ctrl = imx219_set_ctrl,
|
||||
};
|
||||
|
||||
static void imx219_update_pad_format(struct imx219 *imx219,
|
||||
const struct imx219_mode *mode,
|
||||
struct v4l2_mbus_framefmt *fmt, u32 code)
|
||||
{
|
||||
/* Bayer order varies with flips */
|
||||
fmt->code = imx219_get_format_code(imx219, code);
|
||||
fmt->width = mode->width;
|
||||
fmt->height = mode->height;
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
fmt->colorspace = V4L2_COLORSPACE_RAW;
|
||||
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
|
||||
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
|
||||
}
|
||||
|
||||
static int imx219_init_cfg(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
struct v4l2_rect *crop;
|
||||
|
||||
/* Initialize try_fmt */
|
||||
format = v4l2_subdev_get_pad_format(sd, state, 0);
|
||||
imx219_update_pad_format(imx219, &supported_modes[0], format,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10);
|
||||
|
||||
/* Initialize crop rectangle. */
|
||||
crop = v4l2_subdev_get_pad_crop(sd, state, 0);
|
||||
crop->top = IMX219_PIXEL_ARRAY_TOP;
|
||||
crop->left = IMX219_PIXEL_ARRAY_LEFT;
|
||||
crop->width = IMX219_PIXEL_ARRAY_WIDTH;
|
||||
crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
|
||||
if (code->index >= (ARRAY_SIZE(codes) / 4))
|
||||
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
|
||||
mutex_unlock(&imx219->mutex);
|
||||
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -751,9 +730,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
|
||||
if (fse->index >= ARRAY_SIZE(supported_modes))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
code = imx219_get_format_code(imx219, fse->code);
|
||||
mutex_unlock(&imx219->mutex);
|
||||
if (fse->code != code)
|
||||
return -EINVAL;
|
||||
|
||||
@ -765,92 +742,27 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
|
||||
fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
|
||||
fmt->colorspace,
|
||||
fmt->ycbcr_enc);
|
||||
fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
|
||||
}
|
||||
|
||||
static void imx219_update_pad_format(struct imx219 *imx219,
|
||||
const struct imx219_mode *mode,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
fmt->format.width = mode->width;
|
||||
fmt->format.height = mode->height;
|
||||
fmt->format.field = V4L2_FIELD_NONE;
|
||||
imx219_reset_colorspace(&fmt->format);
|
||||
}
|
||||
|
||||
static int __imx219_get_pad_format(struct imx219 *imx219,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
struct v4l2_mbus_framefmt *try_fmt =
|
||||
v4l2_subdev_get_try_format(&imx219->sd, sd_state,
|
||||
fmt->pad);
|
||||
/* update the code which could change due to vflip or hflip: */
|
||||
try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
|
||||
fmt->format = *try_fmt;
|
||||
} else {
|
||||
imx219_update_pad_format(imx219, imx219->mode, fmt);
|
||||
fmt->format.code = imx219_get_format_code(imx219,
|
||||
imx219->fmt.code);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx219_get_pad_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
ret = __imx219_get_pad_format(imx219, sd_state, fmt);
|
||||
mutex_unlock(&imx219->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx219_set_pad_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
const struct imx219_mode *mode;
|
||||
struct v4l2_mbus_framefmt *framefmt;
|
||||
int exposure_max, exposure_def, hblank;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(codes); i++)
|
||||
if (codes[i] == fmt->format.code)
|
||||
break;
|
||||
if (i >= ARRAY_SIZE(codes))
|
||||
i = 0;
|
||||
|
||||
/* Bayer order varies with flips */
|
||||
fmt->format.code = imx219_get_format_code(imx219, codes[i]);
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
mode = v4l2_find_nearest_size(supported_modes,
|
||||
ARRAY_SIZE(supported_modes),
|
||||
width, height,
|
||||
fmt->format.width, fmt->format.height);
|
||||
imx219_update_pad_format(imx219, mode, fmt);
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
|
||||
*framefmt = fmt->format;
|
||||
} else if (imx219->mode != mode ||
|
||||
imx219->fmt.code != fmt->format.code) {
|
||||
imx219->fmt = fmt->format;
|
||||
|
||||
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
|
||||
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
|
||||
|
||||
if (imx219->mode == mode && format->code == fmt->format.code)
|
||||
return 0;
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||
imx219->mode = mode;
|
||||
/* Update limits and set FPS to default */
|
||||
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
|
||||
@ -876,14 +788,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
|
||||
hblank);
|
||||
}
|
||||
|
||||
mutex_unlock(&imx219->mutex);
|
||||
*format = fmt->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx219_set_framefmt(struct imx219 *imx219)
|
||||
static int imx219_set_framefmt(struct imx219 *imx219,
|
||||
const struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
switch (imx219->fmt.code) {
|
||||
switch (format->code) {
|
||||
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
@ -902,7 +815,8 @@ static int imx219_set_framefmt(struct imx219 *imx219)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int imx219_set_binning(struct imx219 *imx219)
|
||||
static int imx219_set_binning(struct imx219 *imx219,
|
||||
const struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
if (!imx219->mode->binning) {
|
||||
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
||||
@ -910,7 +824,7 @@ static int imx219_set_binning(struct imx219 *imx219)
|
||||
IMX219_BINNING_NONE);
|
||||
}
|
||||
|
||||
switch (imx219->fmt.code) {
|
||||
switch (format->code) {
|
||||
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
@ -931,34 +845,13 @@ static int imx219_set_binning(struct imx219 *imx219)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct v4l2_rect *
|
||||
__imx219_get_pad_crop(struct imx219 *imx219,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
unsigned int pad, enum v4l2_subdev_format_whence which)
|
||||
{
|
||||
switch (which) {
|
||||
case V4L2_SUBDEV_FORMAT_TRY:
|
||||
return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
|
||||
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||
return &imx219->mode->crop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int imx219_get_selection(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_selection *sel)
|
||||
{
|
||||
switch (sel->target) {
|
||||
case V4L2_SEL_TGT_CROP: {
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
|
||||
sel->which);
|
||||
mutex_unlock(&imx219->mutex);
|
||||
|
||||
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -990,9 +883,11 @@ static int imx219_configure_lanes(struct imx219 *imx219)
|
||||
IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
|
||||
};
|
||||
|
||||
static int imx219_start_streaming(struct imx219 *imx219)
|
||||
static int imx219_start_streaming(struct imx219 *imx219,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
const struct imx219_reg_list *reg_list;
|
||||
int ret;
|
||||
|
||||
@ -1022,14 +917,15 @@ static int imx219_start_streaming(struct imx219 *imx219)
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
ret = imx219_set_framefmt(imx219);
|
||||
format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
|
||||
ret = imx219_set_framefmt(imx219, format);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed to set frame format: %d\n",
|
||||
__func__, ret);
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
ret = imx219_set_binning(imx219);
|
||||
ret = imx219_set_binning(imx219, format);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed to set binning: %d\n",
|
||||
__func__, ret);
|
||||
@ -1078,35 +974,30 @@ static void imx219_stop_streaming(struct imx219 *imx219)
|
||||
static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
struct v4l2_subdev_state *state;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&imx219->mutex);
|
||||
if (imx219->streaming == enable) {
|
||||
mutex_unlock(&imx219->mutex);
|
||||
return 0;
|
||||
}
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
|
||||
if (imx219->streaming == enable)
|
||||
goto unlock;
|
||||
|
||||
if (enable) {
|
||||
/*
|
||||
* Apply default & customized values
|
||||
* and then start streaming.
|
||||
*/
|
||||
ret = imx219_start_streaming(imx219);
|
||||
ret = imx219_start_streaming(imx219, state);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
goto unlock;
|
||||
} else {
|
||||
imx219_stop_streaming(imx219);
|
||||
}
|
||||
|
||||
imx219->streaming = enable;
|
||||
|
||||
mutex_unlock(&imx219->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&imx219->mutex);
|
||||
|
||||
unlock:
|
||||
v4l2_subdev_unlock_state(state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1171,10 +1062,13 @@ static int __maybe_unused imx219_resume(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
struct v4l2_subdev_state *state;
|
||||
int ret;
|
||||
|
||||
if (imx219->streaming) {
|
||||
ret = imx219_start_streaming(imx219);
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
ret = imx219_start_streaming(imx219, state);
|
||||
v4l2_subdev_unlock_state(state);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
@ -1235,8 +1129,9 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = {
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
|
||||
.init_cfg = imx219_init_cfg,
|
||||
.enum_mbus_code = imx219_enum_mbus_code,
|
||||
.get_fmt = imx219_get_pad_format,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = imx219_set_pad_format,
|
||||
.get_selection = imx219_get_selection,
|
||||
.enum_frame_size = imx219_enum_frame_size,
|
||||
@ -1248,9 +1143,6 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = {
|
||||
.pad = &imx219_pad_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
|
||||
.open = imx219_open,
|
||||
};
|
||||
|
||||
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
|
||||
{
|
||||
@ -1272,9 +1164,6 @@ static int imx219_init_controls(struct imx219 *imx219)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&imx219->mutex);
|
||||
ctrl_hdlr->lock = &imx219->mutex;
|
||||
|
||||
/* By default, PIXEL_RATE is read only */
|
||||
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE,
|
||||
@ -1371,7 +1260,6 @@ static int imx219_init_controls(struct imx219 *imx219)
|
||||
|
||||
error:
|
||||
v4l2_ctrl_handler_free(ctrl_hdlr);
|
||||
mutex_destroy(&imx219->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1379,7 +1267,6 @@ error:
|
||||
static void imx219_free_controls(struct imx219 *imx219)
|
||||
{
|
||||
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
|
||||
mutex_destroy(&imx219->mutex);
|
||||
}
|
||||
|
||||
static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
|
||||
@ -1509,7 +1396,6 @@ static int imx219_probe(struct i2c_client *client)
|
||||
goto error_power_off;
|
||||
|
||||
/* Initialize subdev */
|
||||
imx219->sd.internal_ops = &imx219_internal_ops;
|
||||
imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
@ -1517,19 +1403,23 @@ static int imx219_probe(struct i2c_client *client)
|
||||
/* Initialize source pad */
|
||||
imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
/* Initialize default format */
|
||||
imx219_set_default_format(imx219);
|
||||
|
||||
ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init entity pads: %d\n", ret);
|
||||
goto error_handler_free;
|
||||
}
|
||||
|
||||
imx219->sd.state_lock = imx219->ctrl_handler.lock;
|
||||
ret = v4l2_subdev_init_finalize(&imx219->sd);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "subdev init error: %d\n", ret);
|
||||
goto error_media_entity;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev_sensor(&imx219->sd);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
|
||||
goto error_media_entity;
|
||||
goto error_subdev_cleanup;
|
||||
}
|
||||
|
||||
/* Enable runtime PM and turn off the device */
|
||||
@ -1539,6 +1429,9 @@ static int imx219_probe(struct i2c_client *client)
|
||||
|
||||
return 0;
|
||||
|
||||
error_subdev_cleanup:
|
||||
v4l2_subdev_cleanup(&imx219->sd);
|
||||
|
||||
error_media_entity:
|
||||
media_entity_cleanup(&imx219->sd.entity);
|
||||
|
||||
@ -1557,6 +1450,7 @@ static void imx219_remove(struct i2c_client *client)
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
v4l2_subdev_cleanup(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
imx219_free_controls(imx219);
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -21,91 +21,86 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#define IMX290_REG_SIZE_SHIFT 16
|
||||
#define IMX290_REG_ADDR_MASK 0xffff
|
||||
#define IMX290_REG_8BIT(n) ((1U << IMX290_REG_SIZE_SHIFT) | (n))
|
||||
#define IMX290_REG_16BIT(n) ((2U << IMX290_REG_SIZE_SHIFT) | (n))
|
||||
#define IMX290_REG_24BIT(n) ((3U << IMX290_REG_SIZE_SHIFT) | (n))
|
||||
|
||||
#define IMX290_STANDBY IMX290_REG_8BIT(0x3000)
|
||||
#define IMX290_REGHOLD IMX290_REG_8BIT(0x3001)
|
||||
#define IMX290_XMSTA IMX290_REG_8BIT(0x3002)
|
||||
#define IMX290_ADBIT IMX290_REG_8BIT(0x3005)
|
||||
#define IMX290_STANDBY CCI_REG8(0x3000)
|
||||
#define IMX290_REGHOLD CCI_REG8(0x3001)
|
||||
#define IMX290_XMSTA CCI_REG8(0x3002)
|
||||
#define IMX290_ADBIT CCI_REG8(0x3005)
|
||||
#define IMX290_ADBIT_10BIT (0 << 0)
|
||||
#define IMX290_ADBIT_12BIT (1 << 0)
|
||||
#define IMX290_CTRL_07 IMX290_REG_8BIT(0x3007)
|
||||
#define IMX290_CTRL_07 CCI_REG8(0x3007)
|
||||
#define IMX290_VREVERSE BIT(0)
|
||||
#define IMX290_HREVERSE BIT(1)
|
||||
#define IMX290_WINMODE_1080P (0 << 4)
|
||||
#define IMX290_WINMODE_720P (1 << 4)
|
||||
#define IMX290_WINMODE_CROP (4 << 4)
|
||||
#define IMX290_FR_FDG_SEL IMX290_REG_8BIT(0x3009)
|
||||
#define IMX290_BLKLEVEL IMX290_REG_16BIT(0x300a)
|
||||
#define IMX290_GAIN IMX290_REG_8BIT(0x3014)
|
||||
#define IMX290_VMAX IMX290_REG_24BIT(0x3018)
|
||||
#define IMX290_FR_FDG_SEL CCI_REG8(0x3009)
|
||||
#define IMX290_BLKLEVEL CCI_REG16(0x300a)
|
||||
#define IMX290_GAIN CCI_REG8(0x3014)
|
||||
#define IMX290_VMAX CCI_REG24(0x3018)
|
||||
#define IMX290_VMAX_MAX 0x3ffff
|
||||
#define IMX290_HMAX IMX290_REG_16BIT(0x301c)
|
||||
#define IMX290_HMAX CCI_REG16(0x301c)
|
||||
#define IMX290_HMAX_MAX 0xffff
|
||||
#define IMX290_SHS1 IMX290_REG_24BIT(0x3020)
|
||||
#define IMX290_WINWV_OB IMX290_REG_8BIT(0x303a)
|
||||
#define IMX290_WINPV IMX290_REG_16BIT(0x303c)
|
||||
#define IMX290_WINWV IMX290_REG_16BIT(0x303e)
|
||||
#define IMX290_WINPH IMX290_REG_16BIT(0x3040)
|
||||
#define IMX290_WINWH IMX290_REG_16BIT(0x3042)
|
||||
#define IMX290_OUT_CTRL IMX290_REG_8BIT(0x3046)
|
||||
#define IMX290_SHS1 CCI_REG24(0x3020)
|
||||
#define IMX290_WINWV_OB CCI_REG8(0x303a)
|
||||
#define IMX290_WINPV CCI_REG16(0x303c)
|
||||
#define IMX290_WINWV CCI_REG16(0x303e)
|
||||
#define IMX290_WINPH CCI_REG16(0x3040)
|
||||
#define IMX290_WINWH CCI_REG16(0x3042)
|
||||
#define IMX290_OUT_CTRL CCI_REG8(0x3046)
|
||||
#define IMX290_ODBIT_10BIT (0 << 0)
|
||||
#define IMX290_ODBIT_12BIT (1 << 0)
|
||||
#define IMX290_OPORTSEL_PARALLEL (0x0 << 4)
|
||||
#define IMX290_OPORTSEL_LVDS_2CH (0xd << 4)
|
||||
#define IMX290_OPORTSEL_LVDS_4CH (0xe << 4)
|
||||
#define IMX290_OPORTSEL_LVDS_8CH (0xf << 4)
|
||||
#define IMX290_XSOUTSEL IMX290_REG_8BIT(0x304b)
|
||||
#define IMX290_XSOUTSEL CCI_REG8(0x304b)
|
||||
#define IMX290_XSOUTSEL_XVSOUTSEL_HIGH (0 << 0)
|
||||
#define IMX290_XSOUTSEL_XVSOUTSEL_VSYNC (2 << 0)
|
||||
#define IMX290_XSOUTSEL_XHSOUTSEL_HIGH (0 << 2)
|
||||
#define IMX290_XSOUTSEL_XHSOUTSEL_HSYNC (2 << 2)
|
||||
#define IMX290_INCKSEL1 IMX290_REG_8BIT(0x305c)
|
||||
#define IMX290_INCKSEL2 IMX290_REG_8BIT(0x305d)
|
||||
#define IMX290_INCKSEL3 IMX290_REG_8BIT(0x305e)
|
||||
#define IMX290_INCKSEL4 IMX290_REG_8BIT(0x305f)
|
||||
#define IMX290_PGCTRL IMX290_REG_8BIT(0x308c)
|
||||
#define IMX290_ADBIT1 IMX290_REG_8BIT(0x3129)
|
||||
#define IMX290_INCKSEL1 CCI_REG8(0x305c)
|
||||
#define IMX290_INCKSEL2 CCI_REG8(0x305d)
|
||||
#define IMX290_INCKSEL3 CCI_REG8(0x305e)
|
||||
#define IMX290_INCKSEL4 CCI_REG8(0x305f)
|
||||
#define IMX290_PGCTRL CCI_REG8(0x308c)
|
||||
#define IMX290_ADBIT1 CCI_REG8(0x3129)
|
||||
#define IMX290_ADBIT1_10BIT 0x1d
|
||||
#define IMX290_ADBIT1_12BIT 0x00
|
||||
#define IMX290_INCKSEL5 IMX290_REG_8BIT(0x315e)
|
||||
#define IMX290_INCKSEL6 IMX290_REG_8BIT(0x3164)
|
||||
#define IMX290_ADBIT2 IMX290_REG_8BIT(0x317c)
|
||||
#define IMX290_INCKSEL5 CCI_REG8(0x315e)
|
||||
#define IMX290_INCKSEL6 CCI_REG8(0x3164)
|
||||
#define IMX290_ADBIT2 CCI_REG8(0x317c)
|
||||
#define IMX290_ADBIT2_10BIT 0x12
|
||||
#define IMX290_ADBIT2_12BIT 0x00
|
||||
#define IMX290_CHIP_ID IMX290_REG_16BIT(0x319a)
|
||||
#define IMX290_ADBIT3 IMX290_REG_8BIT(0x31ec)
|
||||
#define IMX290_CHIP_ID CCI_REG16(0x319a)
|
||||
#define IMX290_ADBIT3 CCI_REG8(0x31ec)
|
||||
#define IMX290_ADBIT3_10BIT 0x37
|
||||
#define IMX290_ADBIT3_12BIT 0x0e
|
||||
#define IMX290_REPETITION IMX290_REG_8BIT(0x3405)
|
||||
#define IMX290_PHY_LANE_NUM IMX290_REG_8BIT(0x3407)
|
||||
#define IMX290_OPB_SIZE_V IMX290_REG_8BIT(0x3414)
|
||||
#define IMX290_Y_OUT_SIZE IMX290_REG_16BIT(0x3418)
|
||||
#define IMX290_CSI_DT_FMT IMX290_REG_16BIT(0x3441)
|
||||
#define IMX290_REPETITION CCI_REG8(0x3405)
|
||||
#define IMX290_PHY_LANE_NUM CCI_REG8(0x3407)
|
||||
#define IMX290_OPB_SIZE_V CCI_REG8(0x3414)
|
||||
#define IMX290_Y_OUT_SIZE CCI_REG16(0x3418)
|
||||
#define IMX290_CSI_DT_FMT CCI_REG16(0x3441)
|
||||
#define IMX290_CSI_DT_FMT_RAW10 0x0a0a
|
||||
#define IMX290_CSI_DT_FMT_RAW12 0x0c0c
|
||||
#define IMX290_CSI_LANE_MODE IMX290_REG_8BIT(0x3443)
|
||||
#define IMX290_EXTCK_FREQ IMX290_REG_16BIT(0x3444)
|
||||
#define IMX290_TCLKPOST IMX290_REG_16BIT(0x3446)
|
||||
#define IMX290_THSZERO IMX290_REG_16BIT(0x3448)
|
||||
#define IMX290_THSPREPARE IMX290_REG_16BIT(0x344a)
|
||||
#define IMX290_TCLKTRAIL IMX290_REG_16BIT(0x344c)
|
||||
#define IMX290_THSTRAIL IMX290_REG_16BIT(0x344e)
|
||||
#define IMX290_TCLKZERO IMX290_REG_16BIT(0x3450)
|
||||
#define IMX290_TCLKPREPARE IMX290_REG_16BIT(0x3452)
|
||||
#define IMX290_TLPX IMX290_REG_16BIT(0x3454)
|
||||
#define IMX290_X_OUT_SIZE IMX290_REG_16BIT(0x3472)
|
||||
#define IMX290_INCKSEL7 IMX290_REG_8BIT(0x3480)
|
||||
#define IMX290_CSI_LANE_MODE CCI_REG8(0x3443)
|
||||
#define IMX290_EXTCK_FREQ CCI_REG16(0x3444)
|
||||
#define IMX290_TCLKPOST CCI_REG16(0x3446)
|
||||
#define IMX290_THSZERO CCI_REG16(0x3448)
|
||||
#define IMX290_THSPREPARE CCI_REG16(0x344a)
|
||||
#define IMX290_TCLKTRAIL CCI_REG16(0x344c)
|
||||
#define IMX290_THSTRAIL CCI_REG16(0x344e)
|
||||
#define IMX290_TCLKZERO CCI_REG16(0x3450)
|
||||
#define IMX290_TCLKPREPARE CCI_REG16(0x3452)
|
||||
#define IMX290_TLPX CCI_REG16(0x3454)
|
||||
#define IMX290_X_OUT_SIZE CCI_REG16(0x3472)
|
||||
#define IMX290_INCKSEL7 CCI_REG8(0x3480)
|
||||
|
||||
#define IMX290_PGCTRL_REGEN BIT(0)
|
||||
#define IMX290_PGCTRL_THRU BIT(1)
|
||||
@ -181,7 +176,7 @@ enum imx290_model {
|
||||
|
||||
struct imx290_model_info {
|
||||
enum imx290_colour_variant colour_variant;
|
||||
const struct imx290_regval *init_regs;
|
||||
const struct cci_reg_sequence *init_regs;
|
||||
size_t init_regs_num;
|
||||
const char *name;
|
||||
};
|
||||
@ -192,11 +187,6 @@ enum imx290_clk_freq {
|
||||
IMX290_NUM_CLK
|
||||
};
|
||||
|
||||
struct imx290_regval {
|
||||
u32 reg;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
/*
|
||||
* Clock configuration for registers INCKSEL1 to INCKSEL6.
|
||||
*/
|
||||
@ -217,7 +207,7 @@ struct imx290_mode {
|
||||
u8 link_freq_index;
|
||||
u8 ctrl_07;
|
||||
|
||||
const struct imx290_regval *data;
|
||||
const struct cci_reg_sequence *data;
|
||||
u32 data_size;
|
||||
|
||||
const struct imx290_clk_cfg *clk_cfg;
|
||||
@ -271,7 +261,7 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
|
||||
* Modes and formats
|
||||
*/
|
||||
|
||||
static const struct imx290_regval imx290_global_init_settings[] = {
|
||||
static const struct cci_reg_sequence imx290_global_init_settings[] = {
|
||||
{ IMX290_WINWV_OB, 12 },
|
||||
{ IMX290_WINPH, 0 },
|
||||
{ IMX290_WINPV, 0 },
|
||||
@ -279,56 +269,56 @@ static const struct imx290_regval imx290_global_init_settings[] = {
|
||||
{ IMX290_WINWV, 1097 },
|
||||
{ IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC |
|
||||
IMX290_XSOUTSEL_XHSOUTSEL_HSYNC },
|
||||
{ IMX290_REG_8BIT(0x3011), 0x02 },
|
||||
{ IMX290_REG_8BIT(0x3012), 0x64 },
|
||||
{ IMX290_REG_8BIT(0x3013), 0x00 },
|
||||
{ CCI_REG8(0x3011), 0x02 },
|
||||
{ CCI_REG8(0x3012), 0x64 },
|
||||
{ CCI_REG8(0x3013), 0x00 },
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_global_init_settings_290[] = {
|
||||
{ IMX290_REG_8BIT(0x300f), 0x00 },
|
||||
{ IMX290_REG_8BIT(0x3010), 0x21 },
|
||||
{ IMX290_REG_8BIT(0x3016), 0x09 },
|
||||
{ IMX290_REG_8BIT(0x3070), 0x02 },
|
||||
{ IMX290_REG_8BIT(0x3071), 0x11 },
|
||||
{ IMX290_REG_8BIT(0x309b), 0x10 },
|
||||
{ IMX290_REG_8BIT(0x309c), 0x22 },
|
||||
{ IMX290_REG_8BIT(0x30a2), 0x02 },
|
||||
{ IMX290_REG_8BIT(0x30a6), 0x20 },
|
||||
{ IMX290_REG_8BIT(0x30a8), 0x20 },
|
||||
{ IMX290_REG_8BIT(0x30aa), 0x20 },
|
||||
{ IMX290_REG_8BIT(0x30ac), 0x20 },
|
||||
{ IMX290_REG_8BIT(0x30b0), 0x43 },
|
||||
{ IMX290_REG_8BIT(0x3119), 0x9e },
|
||||
{ IMX290_REG_8BIT(0x311c), 0x1e },
|
||||
{ IMX290_REG_8BIT(0x311e), 0x08 },
|
||||
{ IMX290_REG_8BIT(0x3128), 0x05 },
|
||||
{ IMX290_REG_8BIT(0x313d), 0x83 },
|
||||
{ IMX290_REG_8BIT(0x3150), 0x03 },
|
||||
{ IMX290_REG_8BIT(0x317e), 0x00 },
|
||||
{ IMX290_REG_8BIT(0x32b8), 0x50 },
|
||||
{ IMX290_REG_8BIT(0x32b9), 0x10 },
|
||||
{ IMX290_REG_8BIT(0x32ba), 0x00 },
|
||||
{ IMX290_REG_8BIT(0x32bb), 0x04 },
|
||||
{ IMX290_REG_8BIT(0x32c8), 0x50 },
|
||||
{ IMX290_REG_8BIT(0x32c9), 0x10 },
|
||||
{ IMX290_REG_8BIT(0x32ca), 0x00 },
|
||||
{ IMX290_REG_8BIT(0x32cb), 0x04 },
|
||||
{ IMX290_REG_8BIT(0x332c), 0xd3 },
|
||||
{ IMX290_REG_8BIT(0x332d), 0x10 },
|
||||
{ IMX290_REG_8BIT(0x332e), 0x0d },
|
||||
{ IMX290_REG_8BIT(0x3358), 0x06 },
|
||||
{ IMX290_REG_8BIT(0x3359), 0xe1 },
|
||||
{ IMX290_REG_8BIT(0x335a), 0x11 },
|
||||
{ IMX290_REG_8BIT(0x3360), 0x1e },
|
||||
{ IMX290_REG_8BIT(0x3361), 0x61 },
|
||||
{ IMX290_REG_8BIT(0x3362), 0x10 },
|
||||
{ IMX290_REG_8BIT(0x33b0), 0x50 },
|
||||
{ IMX290_REG_8BIT(0x33b2), 0x1a },
|
||||
{ IMX290_REG_8BIT(0x33b3), 0x04 },
|
||||
static const struct cci_reg_sequence imx290_global_init_settings_290[] = {
|
||||
{ CCI_REG8(0x300f), 0x00 },
|
||||
{ CCI_REG8(0x3010), 0x21 },
|
||||
{ CCI_REG8(0x3016), 0x09 },
|
||||
{ CCI_REG8(0x3070), 0x02 },
|
||||
{ CCI_REG8(0x3071), 0x11 },
|
||||
{ CCI_REG8(0x309b), 0x10 },
|
||||
{ CCI_REG8(0x309c), 0x22 },
|
||||
{ CCI_REG8(0x30a2), 0x02 },
|
||||
{ CCI_REG8(0x30a6), 0x20 },
|
||||
{ CCI_REG8(0x30a8), 0x20 },
|
||||
{ CCI_REG8(0x30aa), 0x20 },
|
||||
{ CCI_REG8(0x30ac), 0x20 },
|
||||
{ CCI_REG8(0x30b0), 0x43 },
|
||||
{ CCI_REG8(0x3119), 0x9e },
|
||||
{ CCI_REG8(0x311c), 0x1e },
|
||||
{ CCI_REG8(0x311e), 0x08 },
|
||||
{ CCI_REG8(0x3128), 0x05 },
|
||||
{ CCI_REG8(0x313d), 0x83 },
|
||||
{ CCI_REG8(0x3150), 0x03 },
|
||||
{ CCI_REG8(0x317e), 0x00 },
|
||||
{ CCI_REG8(0x32b8), 0x50 },
|
||||
{ CCI_REG8(0x32b9), 0x10 },
|
||||
{ CCI_REG8(0x32ba), 0x00 },
|
||||
{ CCI_REG8(0x32bb), 0x04 },
|
||||
{ CCI_REG8(0x32c8), 0x50 },
|
||||
{ CCI_REG8(0x32c9), 0x10 },
|
||||
{ CCI_REG8(0x32ca), 0x00 },
|
||||
{ CCI_REG8(0x32cb), 0x04 },
|
||||
{ CCI_REG8(0x332c), 0xd3 },
|
||||
{ CCI_REG8(0x332d), 0x10 },
|
||||
{ CCI_REG8(0x332e), 0x0d },
|
||||
{ CCI_REG8(0x3358), 0x06 },
|
||||
{ CCI_REG8(0x3359), 0xe1 },
|
||||
{ CCI_REG8(0x335a), 0x11 },
|
||||
{ CCI_REG8(0x3360), 0x1e },
|
||||
{ CCI_REG8(0x3361), 0x61 },
|
||||
{ CCI_REG8(0x3362), 0x10 },
|
||||
{ CCI_REG8(0x33b0), 0x50 },
|
||||
{ CCI_REG8(0x33b2), 0x1a },
|
||||
{ CCI_REG8(0x33b3), 0x04 },
|
||||
};
|
||||
|
||||
#define IMX290_NUM_CLK_REGS 2
|
||||
static const struct imx290_regval xclk_regs[][IMX290_NUM_CLK_REGS] = {
|
||||
static const struct cci_reg_sequence xclk_regs[][IMX290_NUM_CLK_REGS] = {
|
||||
[IMX290_CLK_37_125] = {
|
||||
{ IMX290_EXTCK_FREQ, (37125 * 256) / 1000 },
|
||||
{ IMX290_INCKSEL7, 0x49 },
|
||||
@ -339,13 +329,13 @@ static const struct imx290_regval xclk_regs[][IMX290_NUM_CLK_REGS] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_global_init_settings_327[] = {
|
||||
{ IMX290_REG_8BIT(0x309e), 0x4A },
|
||||
{ IMX290_REG_8BIT(0x309f), 0x4A },
|
||||
{ IMX290_REG_8BIT(0x313b), 0x61 },
|
||||
static const struct cci_reg_sequence imx290_global_init_settings_327[] = {
|
||||
{ CCI_REG8(0x309e), 0x4A },
|
||||
{ CCI_REG8(0x309f), 0x4A },
|
||||
{ CCI_REG8(0x313b), 0x61 },
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_1080p_settings[] = {
|
||||
static const struct cci_reg_sequence imx290_1080p_settings[] = {
|
||||
/* mode settings */
|
||||
{ IMX290_WINWV_OB, 12 },
|
||||
{ IMX290_OPB_SIZE_V, 10 },
|
||||
@ -353,7 +343,7 @@ static const struct imx290_regval imx290_1080p_settings[] = {
|
||||
{ IMX290_Y_OUT_SIZE, 1080 },
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_720p_settings[] = {
|
||||
static const struct cci_reg_sequence imx290_720p_settings[] = {
|
||||
/* mode settings */
|
||||
{ IMX290_WINWV_OB, 6 },
|
||||
{ IMX290_OPB_SIZE_V, 4 },
|
||||
@ -361,7 +351,7 @@ static const struct imx290_regval imx290_720p_settings[] = {
|
||||
{ IMX290_Y_OUT_SIZE, 720 },
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_10bit_settings[] = {
|
||||
static const struct cci_reg_sequence imx290_10bit_settings[] = {
|
||||
{ IMX290_ADBIT, IMX290_ADBIT_10BIT },
|
||||
{ IMX290_OUT_CTRL, IMX290_ODBIT_10BIT },
|
||||
{ IMX290_ADBIT1, IMX290_ADBIT1_10BIT },
|
||||
@ -370,7 +360,7 @@ static const struct imx290_regval imx290_10bit_settings[] = {
|
||||
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 },
|
||||
};
|
||||
|
||||
static const struct imx290_regval imx290_12bit_settings[] = {
|
||||
static const struct cci_reg_sequence imx290_12bit_settings[] = {
|
||||
{ IMX290_ADBIT, IMX290_ADBIT_12BIT },
|
||||
{ IMX290_OUT_CTRL, IMX290_ODBIT_12BIT },
|
||||
{ IMX290_ADBIT1, IMX290_ADBIT1_12BIT },
|
||||
@ -576,7 +566,7 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
|
||||
struct imx290_format_info {
|
||||
u32 code[IMX290_VARIANT_MAX];
|
||||
u8 bpp;
|
||||
const struct imx290_regval *regs;
|
||||
const struct cci_reg_sequence *regs;
|
||||
unsigned int num_regs;
|
||||
};
|
||||
|
||||
@ -615,63 +605,15 @@ imx290_format_info(const struct imx290 *imx290, u32 code)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Register access
|
||||
*/
|
||||
|
||||
static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value)
|
||||
{
|
||||
u8 data[3] = { 0, 0, 0 };
|
||||
int ret;
|
||||
|
||||
ret = regmap_raw_read(imx290->regmap, addr & IMX290_REG_ADDR_MASK,
|
||||
data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
|
||||
if (ret < 0) {
|
||||
dev_err(imx290->dev, "%u-bit read from 0x%04x failed: %d\n",
|
||||
((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
|
||||
addr & IMX290_REG_ADDR_MASK, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*value = get_unaligned_le24(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx290_write(struct imx290 *imx290, u32 addr, u32 value, int *err)
|
||||
{
|
||||
u8 data[3];
|
||||
int ret;
|
||||
|
||||
if (err && *err)
|
||||
return *err;
|
||||
|
||||
put_unaligned_le24(value, data);
|
||||
|
||||
ret = regmap_raw_write(imx290->regmap, addr & IMX290_REG_ADDR_MASK,
|
||||
data, (addr >> IMX290_REG_SIZE_SHIFT) & 3);
|
||||
if (ret < 0) {
|
||||
dev_err(imx290->dev, "%u-bit write to 0x%04x failed: %d\n",
|
||||
((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8,
|
||||
addr & IMX290_REG_ADDR_MASK, ret);
|
||||
if (err)
|
||||
*err = ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx290_set_register_array(struct imx290 *imx290,
|
||||
const struct imx290_regval *settings,
|
||||
const struct cci_reg_sequence *settings,
|
||||
unsigned int num_settings)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num_settings; ++i, ++settings) {
|
||||
ret = imx290_write(imx290, settings->reg, settings->val, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = cci_multi_reg_write(imx290->regmap, settings, num_settings, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Provide 10ms settle time */
|
||||
usleep_range(10000, 11000);
|
||||
@ -689,12 +631,12 @@ static int imx290_set_clock(struct imx290 *imx290)
|
||||
ret = imx290_set_register_array(imx290, xclk_regs[clk_idx],
|
||||
IMX290_NUM_CLK_REGS);
|
||||
|
||||
imx290_write(imx290, IMX290_INCKSEL1, clk_cfg->incksel1, &ret);
|
||||
imx290_write(imx290, IMX290_INCKSEL2, clk_cfg->incksel2, &ret);
|
||||
imx290_write(imx290, IMX290_INCKSEL3, clk_cfg->incksel3, &ret);
|
||||
imx290_write(imx290, IMX290_INCKSEL4, clk_cfg->incksel4, &ret);
|
||||
imx290_write(imx290, IMX290_INCKSEL5, clk_cfg->incksel5, &ret);
|
||||
imx290_write(imx290, IMX290_INCKSEL6, clk_cfg->incksel6, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL1, clk_cfg->incksel1, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL2, clk_cfg->incksel2, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL3, clk_cfg->incksel3, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL4, clk_cfg->incksel4, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL5, clk_cfg->incksel5, &ret);
|
||||
cci_write(imx290->regmap, IMX290_INCKSEL6, clk_cfg->incksel6, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -703,9 +645,11 @@ static int imx290_set_data_lanes(struct imx290 *imx290)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret);
|
||||
imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret);
|
||||
imx290_write(imx290, IMX290_FR_FDG_SEL, 0x01, &ret);
|
||||
cci_write(imx290->regmap, IMX290_PHY_LANE_NUM, imx290->nlanes - 1,
|
||||
&ret);
|
||||
cci_write(imx290->regmap, IMX290_CSI_LANE_MODE, imx290->nlanes - 1,
|
||||
&ret);
|
||||
cci_write(imx290->regmap, IMX290_FR_FDG_SEL, 0x01, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -716,8 +660,8 @@ static int imx290_set_black_level(struct imx290 *imx290,
|
||||
{
|
||||
unsigned int bpp = imx290_format_info(imx290, format->code)->bpp;
|
||||
|
||||
return imx290_write(imx290, IMX290_BLKLEVEL,
|
||||
black_level >> (16 - bpp), err);
|
||||
return cci_write(imx290->regmap, IMX290_BLKLEVEL,
|
||||
black_level >> (16 - bpp), err);
|
||||
}
|
||||
|
||||
static int imx290_set_csi_config(struct imx290 *imx290)
|
||||
@ -743,15 +687,16 @@ static int imx290_set_csi_config(struct imx290 *imx290)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imx290_write(imx290, IMX290_REPETITION, csi_cfg->repetition, &ret);
|
||||
imx290_write(imx290, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret);
|
||||
imx290_write(imx290, IMX290_THSZERO, csi_cfg->thszero, &ret);
|
||||
imx290_write(imx290, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret);
|
||||
imx290_write(imx290, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret);
|
||||
imx290_write(imx290, IMX290_THSTRAIL, csi_cfg->thstrail, &ret);
|
||||
imx290_write(imx290, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret);
|
||||
imx290_write(imx290, IMX290_TCLKPREPARE, csi_cfg->tclkprepare, &ret);
|
||||
imx290_write(imx290, IMX290_TLPX, csi_cfg->tlpx, &ret);
|
||||
cci_write(imx290->regmap, IMX290_REPETITION, csi_cfg->repetition, &ret);
|
||||
cci_write(imx290->regmap, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret);
|
||||
cci_write(imx290->regmap, IMX290_THSZERO, csi_cfg->thszero, &ret);
|
||||
cci_write(imx290->regmap, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret);
|
||||
cci_write(imx290->regmap, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret);
|
||||
cci_write(imx290->regmap, IMX290_THSTRAIL, csi_cfg->thstrail, &ret);
|
||||
cci_write(imx290->regmap, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret);
|
||||
cci_write(imx290->regmap, IMX290_TCLKPREPARE, csi_cfg->tclkprepare,
|
||||
&ret);
|
||||
cci_write(imx290->regmap, IMX290_TLPX, csi_cfg->tlpx, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -817,13 +762,12 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL);
|
||||
ret = cci_write(imx290->regmap, IMX290_GAIN, ctrl->val, NULL);
|
||||
break;
|
||||
|
||||
case V4L2_CID_VBLANK:
|
||||
ret = imx290_write(imx290, IMX290_VMAX,
|
||||
ctrl->val + imx290->current_mode->height,
|
||||
NULL);
|
||||
ret = cci_write(imx290->regmap, IMX290_VMAX,
|
||||
ctrl->val + imx290->current_mode->height, NULL);
|
||||
/*
|
||||
* Due to the way that exposure is programmed in this sensor in
|
||||
* relation to VMAX, we have to reprogramme it whenever VMAX is
|
||||
@ -835,20 +779,20 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
fallthrough;
|
||||
case V4L2_CID_EXPOSURE:
|
||||
vmax = imx290->vblank->val + imx290->current_mode->height;
|
||||
ret = imx290_write(imx290, IMX290_SHS1,
|
||||
vmax - ctrl->val - 1, NULL);
|
||||
ret = cci_write(imx290->regmap, IMX290_SHS1,
|
||||
vmax - ctrl->val - 1, NULL);
|
||||
break;
|
||||
|
||||
case V4L2_CID_TEST_PATTERN:
|
||||
if (ctrl->val) {
|
||||
imx290_set_black_level(imx290, format, 0, &ret);
|
||||
usleep_range(10000, 11000);
|
||||
imx290_write(imx290, IMX290_PGCTRL,
|
||||
(u8)(IMX290_PGCTRL_REGEN |
|
||||
IMX290_PGCTRL_THRU |
|
||||
IMX290_PGCTRL_MODE(ctrl->val)), &ret);
|
||||
cci_write(imx290->regmap, IMX290_PGCTRL,
|
||||
(u8)(IMX290_PGCTRL_REGEN |
|
||||
IMX290_PGCTRL_THRU |
|
||||
IMX290_PGCTRL_MODE(ctrl->val)), &ret);
|
||||
} else {
|
||||
imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret);
|
||||
cci_write(imx290->regmap, IMX290_PGCTRL, 0x00, &ret);
|
||||
usleep_range(10000, 11000);
|
||||
imx290_set_black_level(imx290, format,
|
||||
IMX290_BLACK_LEVEL_DEFAULT, &ret);
|
||||
@ -856,9 +800,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
break;
|
||||
|
||||
case V4L2_CID_HBLANK:
|
||||
ret = imx290_write(imx290, IMX290_HMAX,
|
||||
ctrl->val + imx290->current_mode->width,
|
||||
NULL);
|
||||
ret = cci_write(imx290->regmap, IMX290_HMAX,
|
||||
ctrl->val + imx290->current_mode->width, NULL);
|
||||
break;
|
||||
|
||||
case V4L2_CID_HFLIP:
|
||||
@ -871,7 +814,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
reg |= IMX290_HREVERSE;
|
||||
if (imx290->vflip->val)
|
||||
reg |= IMX290_VREVERSE;
|
||||
ret = imx290_write(imx290, IMX290_CTRL_07, reg, NULL);
|
||||
ret = cci_write(imx290->regmap, IMX290_CTRL_07, reg, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -902,7 +845,6 @@ static const char * const imx290_test_pattern_menu[] = {
|
||||
};
|
||||
|
||||
static void imx290_ctrl_update(struct imx290 *imx290,
|
||||
const struct v4l2_mbus_framefmt *format,
|
||||
const struct imx290_mode *mode)
|
||||
{
|
||||
unsigned int hblank_min = mode->hmax_min - mode->width;
|
||||
@ -1074,12 +1016,12 @@ static int imx290_start_streaming(struct imx290 *imx290,
|
||||
return ret;
|
||||
}
|
||||
|
||||
imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
|
||||
cci_write(imx290->regmap, IMX290_STANDBY, 0x00, &ret);
|
||||
|
||||
msleep(30);
|
||||
|
||||
/* Start streaming */
|
||||
return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
|
||||
return cci_write(imx290->regmap, IMX290_XMSTA, 0x00, &ret);
|
||||
}
|
||||
|
||||
/* Stop streaming */
|
||||
@ -1087,11 +1029,11 @@ static int imx290_stop_streaming(struct imx290 *imx290)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
|
||||
cci_write(imx290->regmap, IMX290_STANDBY, 0x01, &ret);
|
||||
|
||||
msleep(30);
|
||||
|
||||
return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
|
||||
return cci_write(imx290->regmap, IMX290_XMSTA, 0x01, &ret);
|
||||
}
|
||||
|
||||
static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
|
||||
@ -1195,7 +1137,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||
imx290->current_mode = mode;
|
||||
|
||||
imx290_ctrl_update(imx290, &fmt->format, mode);
|
||||
imx290_ctrl_update(imx290, mode);
|
||||
imx290_exposure_update(imx290, mode);
|
||||
}
|
||||
|
||||
@ -1300,7 +1242,6 @@ static const struct media_entity_operations imx290_subdev_entity_ops = {
|
||||
static int imx290_subdev_init(struct imx290 *imx290)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(imx290->dev);
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct v4l2_subdev_state *state;
|
||||
int ret;
|
||||
|
||||
@ -1335,8 +1276,7 @@ static int imx290_subdev_init(struct imx290 *imx290)
|
||||
}
|
||||
|
||||
state = v4l2_subdev_lock_and_get_active_state(&imx290->sd);
|
||||
format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
|
||||
imx290_ctrl_update(imx290, format, imx290->current_mode);
|
||||
imx290_ctrl_update(imx290, imx290->current_mode);
|
||||
v4l2_subdev_unlock_state(state);
|
||||
|
||||
return 0;
|
||||
@ -1417,11 +1357,6 @@ static const struct dev_pm_ops imx290_pm_ops = {
|
||||
* Probe & remove
|
||||
*/
|
||||
|
||||
static const struct regmap_config imx290_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = {
|
||||
"vdda",
|
||||
"vddd",
|
||||
@ -1588,7 +1523,7 @@ static int imx290_probe(struct i2c_client *client)
|
||||
return -ENOMEM;
|
||||
|
||||
imx290->dev = dev;
|
||||
imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config);
|
||||
imx290->regmap = devm_cci_regmap_init_i2c(client, 16);
|
||||
if (IS_ERR(imx290->regmap)) {
|
||||
dev_err(dev, "Unable to initialize I2C\n");
|
||||
return -ENODEV;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
@ -2565,7 +2565,7 @@ static struct i2c_driver imx319_i2c_driver = {
|
||||
module_i2c_driver(imx319_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi");
|
||||
MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
|
||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||
MODULE_DESCRIPTION("Sony imx319 sensor driver");
|
||||
|
@ -1851,7 +1851,7 @@ static struct i2c_driver imx355_i2c_driver = {
|
||||
module_i2c_driver(imx355_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi");
|
||||
MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
|
||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||
MODULE_DESCRIPTION("Sony imx355 sensor driver");
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
@ -1611,7 +1611,7 @@ static const struct dev_pm_ops isl7998x_pm_ops = {
|
||||
static struct i2c_driver isl7998x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "isl7998x",
|
||||
.of_match_table = of_match_ptr(isl7998x_of_match),
|
||||
.of_match_table = isl7998x_of_match,
|
||||
.pm = &isl7998x_pm_ops,
|
||||
},
|
||||
.probe = isl7998x_probe,
|
||||
|
@ -161,11 +161,12 @@ struct max9286_source {
|
||||
};
|
||||
|
||||
struct max9286_asd {
|
||||
struct v4l2_async_subdev base;
|
||||
struct v4l2_async_connection base;
|
||||
struct max9286_source *source;
|
||||
};
|
||||
|
||||
static inline struct max9286_asd *to_max9286_asd(struct v4l2_async_subdev *asd)
|
||||
static inline struct max9286_asd *
|
||||
to_max9286_asd(struct v4l2_async_connection *asd)
|
||||
{
|
||||
return container_of(asd, struct max9286_asd, base);
|
||||
}
|
||||
@ -659,7 +660,7 @@ static int max9286_set_pixelrate(struct max9286_priv *priv)
|
||||
|
||||
static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(notifier->sd);
|
||||
struct max9286_source *source = to_max9286_asd(asd)->source;
|
||||
@ -721,7 +722,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
|
||||
static void max9286_notify_unbind(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(notifier->sd);
|
||||
struct max9286_source *source = to_max9286_asd(asd)->source;
|
||||
@ -745,7 +746,7 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv)
|
||||
if (!priv->nsources)
|
||||
return 0;
|
||||
|
||||
v4l2_async_nf_init(&priv->notifier);
|
||||
v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
|
||||
|
||||
for_each_source(priv, source) {
|
||||
unsigned int i = to_index(priv, source);
|
||||
@ -765,7 +766,7 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv)
|
||||
|
||||
priv->notifier.ops = &max9286_notify_ops;
|
||||
|
||||
ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier);
|
||||
ret = v4l2_async_nf_register(&priv->notifier);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register subdev_notifier");
|
||||
v4l2_async_nf_cleanup(&priv->notifier);
|
||||
@ -1051,7 +1052,6 @@ static const struct v4l2_ctrl_ops max9286_ctrl_ops = {
|
||||
static int max9286_v4l2_register(struct max9286_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->client->dev;
|
||||
struct fwnode_handle *ep;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@ -1093,25 +1093,14 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
||||
if (ret)
|
||||
goto err_async;
|
||||
|
||||
ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), MAX9286_SRC_PAD,
|
||||
0, 0);
|
||||
if (!ep) {
|
||||
dev_err(dev, "Unable to retrieve endpoint on \"port@4\"\n");
|
||||
ret = -ENOENT;
|
||||
goto err_async;
|
||||
}
|
||||
priv->sd.fwnode = ep;
|
||||
|
||||
ret = v4l2_async_register_subdev(&priv->sd);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to register subdevice\n");
|
||||
goto err_put_node;
|
||||
goto err_async;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_node:
|
||||
fwnode_handle_put(ep);
|
||||
err_async:
|
||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||
max9286_v4l2_notifier_unregister(priv);
|
||||
@ -1714,7 +1703,7 @@ MODULE_DEVICE_TABLE(of, max9286_dt_ids);
|
||||
static struct i2c_driver max9286_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max9286",
|
||||
.of_match_table = of_match_ptr(max9286_dt_ids),
|
||||
.of_match_table = max9286_dt_ids,
|
||||
},
|
||||
.probe = max9286_probe,
|
||||
.remove = max9286_remove,
|
||||
|
@ -1382,7 +1382,7 @@ MODULE_DEVICE_TABLE(i2c, mt9m111_id);
|
||||
static struct i2c_driver mt9m111_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "mt9m111",
|
||||
.of_match_table = of_match_ptr(mt9m111_of_match),
|
||||
.of_match_table = mt9m111_of_match,
|
||||
},
|
||||
.probe = mt9m111_probe,
|
||||
.remove = mt9m111_remove,
|
||||
|
@ -1121,6 +1121,6 @@ static struct i2c_driver og01a1b_i2c_driver = {
|
||||
|
||||
module_i2c_driver(og01a1b_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("OmniVision OG01A1B sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -992,7 +992,7 @@ static struct i2c_driver ov01a10_i2c_driver = {
|
||||
.pm = &ov01a10_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(ov01a10_acpi_ids),
|
||||
},
|
||||
.probe_new = ov01a10_probe,
|
||||
.probe = ov01a10_probe,
|
||||
.remove = ov01a10_remove,
|
||||
};
|
||||
|
||||
|
@ -110,8 +110,6 @@ struct ov08x40_reg_list {
|
||||
|
||||
/* Link frequency config */
|
||||
struct ov08x40_link_freq_config {
|
||||
u32 pixels_per_line;
|
||||
|
||||
/* registers for this link frequency */
|
||||
struct ov08x40_reg_list reg_list;
|
||||
};
|
||||
@ -128,6 +126,9 @@ struct ov08x40_mode {
|
||||
u32 vts_def;
|
||||
u32 vts_min;
|
||||
|
||||
/* HTS */
|
||||
u32 hts;
|
||||
|
||||
/* Index of Link frequency config to be used */
|
||||
u32 link_freq_index;
|
||||
/* Default register values */
|
||||
@ -2391,6 +2392,7 @@ static const struct ov08x40_mode supported_modes[] = {
|
||||
.height = 2416,
|
||||
.vts_def = OV08X40_VTS_30FPS,
|
||||
.vts_min = OV08X40_VTS_30FPS,
|
||||
.hts = 640,
|
||||
.lanes = 4,
|
||||
.reg_list = {
|
||||
.num_of_regs = ARRAY_SIZE(mode_3856x2416_regs),
|
||||
@ -2403,6 +2405,7 @@ static const struct ov08x40_mode supported_modes[] = {
|
||||
.height = 1208,
|
||||
.vts_def = OV08X40_VTS_BIN_30FPS,
|
||||
.vts_min = OV08X40_VTS_BIN_30FPS,
|
||||
.hts = 720,
|
||||
.lanes = 4,
|
||||
.reg_list = {
|
||||
.num_of_regs = ARRAY_SIZE(mode_1928x1208_regs),
|
||||
@ -2846,9 +2849,7 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd,
|
||||
1,
|
||||
vblank_def);
|
||||
__v4l2_ctrl_s_ctrl(ov08x->vblank, vblank_def);
|
||||
h_blank =
|
||||
link_freq_configs[mode->link_freq_index].pixels_per_line
|
||||
- ov08x->cur_mode->width;
|
||||
h_blank = ov08x->cur_mode->hts;
|
||||
__v4l2_ctrl_modify_range(ov08x->hblank, h_blank,
|
||||
h_blank, 1, h_blank);
|
||||
}
|
||||
@ -3074,8 +3075,7 @@ static int ov08x40_init_controls(struct ov08x40 *ov08x)
|
||||
OV08X40_VTS_MAX - mode->height, 1,
|
||||
vblank_def);
|
||||
|
||||
hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
|
||||
mode->width;
|
||||
hblank = ov08x->cur_mode->hts;
|
||||
ov08x->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
|
||||
V4L2_CID_HBLANK,
|
||||
hblank, hblank, 1, hblank);
|
||||
@ -3320,6 +3320,6 @@ static struct i2c_driver ov08x40_i2c_driver = {
|
||||
module_i2c_driver(ov08x40_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Jason Chen <jason.z.chen@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("OmniVision OV08X40 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1814,7 +1814,7 @@ static struct i2c_driver ov13858_i2c_driver = {
|
||||
module_i2c_driver(ov13858_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Kan, Chris <chris.kan@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi");
|
||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||
MODULE_DESCRIPTION("Omnivision ov13858 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Copyright (c) 2021 Intel Corporation.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -573,6 +576,11 @@ struct ov13b10 {
|
||||
struct media_pad pad;
|
||||
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
|
||||
struct clk *img_clk;
|
||||
struct regulator *avdd;
|
||||
struct gpio_desc *reset;
|
||||
|
||||
/* V4L2 Controls */
|
||||
struct v4l2_ctrl *link_freq;
|
||||
struct v4l2_ctrl *pixel_rate;
|
||||
@ -1051,6 +1059,49 @@ static int ov13b10_identify_module(struct ov13b10 *ov13b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov13b10_power_off(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct ov13b10 *ov13b10 = to_ov13b10(sd);
|
||||
|
||||
gpiod_set_value_cansleep(ov13b10->reset, 1);
|
||||
|
||||
if (ov13b10->avdd)
|
||||
regulator_disable(ov13b10->avdd);
|
||||
|
||||
clk_disable_unprepare(ov13b10->img_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov13b10_power_on(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct ov13b10 *ov13b10 = to_ov13b10(sd);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(ov13b10->img_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable imaging clock: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ov13b10->avdd) {
|
||||
ret = regulator_enable(ov13b10->avdd);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable avdd: %d", ret);
|
||||
clk_disable_unprepare(ov13b10->img_clk);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ov13b10->reset, 0);
|
||||
/* 5ms to wait ready after XSHUTDN assert */
|
||||
usleep_range(5000, 5500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov13b10_start_streaming(struct ov13b10 *ov13b)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
|
||||
@ -1145,7 +1196,7 @@ err_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ov13b10_suspend(struct device *dev)
|
||||
static int ov13b10_suspend(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct ov13b10 *ov13b = to_ov13b10(sd);
|
||||
@ -1153,26 +1204,35 @@ static int __maybe_unused ov13b10_suspend(struct device *dev)
|
||||
if (ov13b->streaming)
|
||||
ov13b10_stop_streaming(ov13b);
|
||||
|
||||
ov13b10_power_off(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ov13b10_resume(struct device *dev)
|
||||
static int ov13b10_resume(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct ov13b10 *ov13b = to_ov13b10(sd);
|
||||
int ret;
|
||||
|
||||
ret = ov13b10_power_on(dev);
|
||||
if (ret)
|
||||
goto pm_fail;
|
||||
|
||||
if (ov13b->streaming) {
|
||||
ret = ov13b10_start_streaming(ov13b);
|
||||
if (ret)
|
||||
goto error;
|
||||
goto stop_streaming;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
stop_streaming:
|
||||
ov13b10_stop_streaming(ov13b);
|
||||
ov13b10_power_off(dev);
|
||||
pm_fail:
|
||||
ov13b->streaming = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1317,6 +1377,34 @@ static void ov13b10_free_controls(struct ov13b10 *ov13b)
|
||||
mutex_destroy(&ov13b->mutex);
|
||||
}
|
||||
|
||||
static int ov13b10_get_pm_resources(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct ov13b10 *ov13b = to_ov13b10(sd);
|
||||
int ret;
|
||||
|
||||
ov13b->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ov13b->reset))
|
||||
return dev_err_probe(dev, PTR_ERR(ov13b->reset),
|
||||
"failed to get reset gpio\n");
|
||||
|
||||
ov13b->img_clk = devm_clk_get_optional(dev, NULL);
|
||||
if (IS_ERR(ov13b->img_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ov13b->img_clk),
|
||||
"failed to get imaging clock\n");
|
||||
|
||||
ov13b->avdd = devm_regulator_get_optional(dev, "avdd");
|
||||
if (IS_ERR(ov13b->avdd)) {
|
||||
ret = PTR_ERR(ov13b->avdd);
|
||||
ov13b->avdd = NULL;
|
||||
if (ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get avdd regulator\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov13b10_check_hwcfg(struct device *dev)
|
||||
{
|
||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||
@ -1331,6 +1419,10 @@ static int ov13b10_check_hwcfg(struct device *dev)
|
||||
if (!fwnode)
|
||||
return -ENXIO;
|
||||
|
||||
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||
if (!ep)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
||||
&ext_clk);
|
||||
if (ret) {
|
||||
@ -1344,10 +1436,6 @@ static int ov13b10_check_hwcfg(struct device *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||
if (!ep)
|
||||
return -ENXIO;
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
|
||||
fwnode_handle_put(ep);
|
||||
if (ret)
|
||||
@ -1407,13 +1495,23 @@ static int ov13b10_probe(struct i2c_client *client)
|
||||
/* Initialize subdev */
|
||||
v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
|
||||
|
||||
ret = ov13b10_get_pm_resources(&client->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
full_power = acpi_dev_state_d0(&client->dev);
|
||||
if (full_power) {
|
||||
ov13b10_power_on(&client->dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to power on\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check module identity */
|
||||
ret = ov13b10_identify_module(ov13b);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to find sensor: %d\n", ret);
|
||||
return ret;
|
||||
goto error_power_off;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1422,7 +1520,7 @@ static int ov13b10_probe(struct i2c_client *client)
|
||||
|
||||
ret = ov13b10_init_controls(ov13b);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto error_power_off;
|
||||
|
||||
/* Initialize subdev */
|
||||
ov13b->sd.internal_ops = &ov13b10_internal_ops;
|
||||
@ -1462,6 +1560,9 @@ error_handler_free:
|
||||
ov13b10_free_controls(ov13b);
|
||||
dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
|
||||
|
||||
error_power_off:
|
||||
ov13b10_power_off(&client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1477,13 +1578,13 @@ static void ov13b10_remove(struct i2c_client *client)
|
||||
pm_runtime_disable(&client->dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ov13b10_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ov13b10_suspend, ov13b10_resume)
|
||||
};
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend,
|
||||
ov13b10_resume, NULL);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id ov13b10_acpi_ids[] = {
|
||||
{"OVTIDB10"},
|
||||
{"OVTI13B1"},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@ -1493,7 +1594,7 @@ MODULE_DEVICE_TABLE(acpi, ov13b10_acpi_ids);
|
||||
static struct i2c_driver ov13b10_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ov13b10",
|
||||
.pm = &ov13b10_pm_ops,
|
||||
.pm = pm_ptr(&ov13b10_pm_ops),
|
||||
.acpi_match_table = ACPI_PTR(ov13b10_acpi_ids),
|
||||
},
|
||||
.probe = ov13b10_probe,
|
||||
|
@ -1296,7 +1296,7 @@ MODULE_DEVICE_TABLE(of, ov2640_of_match);
|
||||
static struct i2c_driver ov2640_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ov2640",
|
||||
.of_match_table = of_match_ptr(ov2640_of_match),
|
||||
.of_match_table = ov2640_of_match,
|
||||
},
|
||||
.probe = ov2640_probe,
|
||||
.remove = ov2640_remove,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1223,7 +1223,7 @@ static struct i2c_driver ov2740_i2c_driver = {
|
||||
module_i2c_driver(ov2740_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
|
||||
MODULE_DESCRIPTION("OmniVision OV2740 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
@ -568,9 +568,7 @@ static const struct reg_value ov5640_init_setting[] = {
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
|
||||
{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
|
||||
{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
|
||||
{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
|
||||
{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
|
||||
{0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x4837, 0x0a, 0, 0},
|
||||
{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
|
||||
{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
|
||||
{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
|
||||
@ -634,7 +632,8 @@ static const struct reg_value ov5640_setting_low_res[] = {
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_720P_1280_720[] = {
|
||||
@ -2453,16 +2452,13 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable)
|
||||
static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
|
||||
{
|
||||
if (sensor->pwdn_gpio) {
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
|
||||
|
||||
/* camera power cycle */
|
||||
ov5640_power(sensor, false);
|
||||
usleep_range(5000, 10000);
|
||||
usleep_range(5000, 10000); /* t2 */
|
||||
ov5640_power(sensor, true);
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
|
||||
usleep_range(1000, 2000);
|
||||
usleep_range(1000, 2000); /* t3 */
|
||||
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
||||
} else {
|
||||
@ -2470,7 +2466,7 @@ static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
|
||||
ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
|
||||
OV5640_REG_SYS_CTRL0_SW_RST);
|
||||
}
|
||||
usleep_range(20000, 25000);
|
||||
usleep_range(20000, 25000); /* t4 */
|
||||
|
||||
/*
|
||||
* software standby: allows registers programming;
|
||||
@ -2543,9 +2539,9 @@ static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
|
||||
* "ov5640_set_stream_mipi()")
|
||||
* [4] = 0 : Power up MIPI HS Tx
|
||||
* [3] = 0 : Power up MIPI LS Rx
|
||||
* [2] = 0 : MIPI interface disabled
|
||||
* [2] = 1 : MIPI interface enabled
|
||||
*/
|
||||
ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
|
||||
ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x44);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -2860,7 +2860,7 @@ static struct i2c_driver ov5670_i2c_driver = {
|
||||
|
||||
module_i2c_driver(ov5670_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
|
||||
MODULE_AUTHOR("Rapolu, Chiranjeevi");
|
||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||
MODULE_DESCRIPTION("Omnivision ov5670 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1442,6 +1442,6 @@ static struct i2c_driver ov5675_i2c_driver = {
|
||||
|
||||
module_i2c_driver(ov5675_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
||||
MODULE_AUTHOR("Shawn Tu");
|
||||
MODULE_DESCRIPTION("OmniVision OV5675 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -12,7 +12,6 @@
|
||||
* Jake Day
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
@ -23,36 +22,32 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
|
||||
#define OV5693_REG_8BIT(n) ((1 << 16) | (n))
|
||||
#define OV5693_REG_16BIT(n) ((2 << 16) | (n))
|
||||
#define OV5693_REG_24BIT(n) ((3 << 16) | (n))
|
||||
#define OV5693_REG_SIZE_SHIFT 16
|
||||
#define OV5693_REG_ADDR_MASK 0xffff
|
||||
|
||||
/* System Control */
|
||||
#define OV5693_SW_RESET_REG OV5693_REG_8BIT(0x0103)
|
||||
#define OV5693_SW_STREAM_REG OV5693_REG_8BIT(0x0100)
|
||||
#define OV5693_SW_RESET_REG CCI_REG8(0x0103)
|
||||
#define OV5693_SW_STREAM_REG CCI_REG8(0x0100)
|
||||
#define OV5693_START_STREAMING 0x01
|
||||
#define OV5693_STOP_STREAMING 0x00
|
||||
#define OV5693_SW_RESET 0x01
|
||||
|
||||
#define OV5693_REG_CHIP_ID OV5693_REG_16BIT(0x300a)
|
||||
#define OV5693_REG_CHIP_ID CCI_REG16(0x300a)
|
||||
/* Yes, this is right. The datasheet for the OV5693 gives its ID as 0x5690 */
|
||||
#define OV5693_CHIP_ID 0x5690
|
||||
|
||||
/* Exposure */
|
||||
#define OV5693_EXPOSURE_CTRL_REG OV5693_REG_24BIT(0x3500)
|
||||
#define OV5693_EXPOSURE_CTRL_REG CCI_REG24(0x3500)
|
||||
#define OV5693_EXPOSURE_CTRL_MASK GENMASK(19, 4)
|
||||
#define OV5693_INTEGRATION_TIME_MARGIN 8
|
||||
#define OV5693_EXPOSURE_MIN 1
|
||||
#define OV5693_EXPOSURE_STEP 1
|
||||
|
||||
/* Analogue Gain */
|
||||
#define OV5693_GAIN_CTRL_REG OV5693_REG_16BIT(0x350a)
|
||||
#define OV5693_GAIN_CTRL_REG CCI_REG16(0x350a)
|
||||
#define OV5693_GAIN_CTRL_MASK GENMASK(10, 4)
|
||||
#define OV5693_GAIN_MIN 1
|
||||
#define OV5693_GAIN_MAX 127
|
||||
@ -60,9 +55,9 @@
|
||||
#define OV5693_GAIN_STEP 1
|
||||
|
||||
/* Digital Gain */
|
||||
#define OV5693_MWB_RED_GAIN_REG OV5693_REG_16BIT(0x3400)
|
||||
#define OV5693_MWB_GREEN_GAIN_REG OV5693_REG_16BIT(0x3402)
|
||||
#define OV5693_MWB_BLUE_GAIN_REG OV5693_REG_16BIT(0x3404)
|
||||
#define OV5693_MWB_RED_GAIN_REG CCI_REG16(0x3400)
|
||||
#define OV5693_MWB_GREEN_GAIN_REG CCI_REG16(0x3402)
|
||||
#define OV5693_MWB_BLUE_GAIN_REG CCI_REG16(0x3404)
|
||||
#define OV5693_MWB_GAIN_MASK GENMASK(11, 0)
|
||||
#define OV5693_MWB_GAIN_MAX 0x0fff
|
||||
#define OV5693_DIGITAL_GAIN_MIN 1
|
||||
@ -71,36 +66,36 @@
|
||||
#define OV5693_DIGITAL_GAIN_STEP 1
|
||||
|
||||
/* Timing and Format */
|
||||
#define OV5693_CROP_START_X_REG OV5693_REG_16BIT(0x3800)
|
||||
#define OV5693_CROP_START_Y_REG OV5693_REG_16BIT(0x3802)
|
||||
#define OV5693_CROP_END_X_REG OV5693_REG_16BIT(0x3804)
|
||||
#define OV5693_CROP_END_Y_REG OV5693_REG_16BIT(0x3806)
|
||||
#define OV5693_OUTPUT_SIZE_X_REG OV5693_REG_16BIT(0x3808)
|
||||
#define OV5693_OUTPUT_SIZE_Y_REG OV5693_REG_16BIT(0x380a)
|
||||
#define OV5693_CROP_START_X_REG CCI_REG16(0x3800)
|
||||
#define OV5693_CROP_START_Y_REG CCI_REG16(0x3802)
|
||||
#define OV5693_CROP_END_X_REG CCI_REG16(0x3804)
|
||||
#define OV5693_CROP_END_Y_REG CCI_REG16(0x3806)
|
||||
#define OV5693_OUTPUT_SIZE_X_REG CCI_REG16(0x3808)
|
||||
#define OV5693_OUTPUT_SIZE_Y_REG CCI_REG16(0x380a)
|
||||
|
||||
#define OV5693_TIMING_HTS_REG OV5693_REG_16BIT(0x380c)
|
||||
#define OV5693_TIMING_HTS_REG CCI_REG16(0x380c)
|
||||
#define OV5693_FIXED_PPL 2688U
|
||||
#define OV5693_TIMING_VTS_REG OV5693_REG_16BIT(0x380e)
|
||||
#define OV5693_TIMING_VTS_REG CCI_REG16(0x380e)
|
||||
#define OV5693_TIMING_MAX_VTS 0xffff
|
||||
#define OV5693_TIMING_MIN_VTS 0x04
|
||||
|
||||
#define OV5693_OFFSET_START_X_REG OV5693_REG_16BIT(0x3810)
|
||||
#define OV5693_OFFSET_START_Y_REG OV5693_REG_16BIT(0x3812)
|
||||
#define OV5693_OFFSET_START_X_REG CCI_REG16(0x3810)
|
||||
#define OV5693_OFFSET_START_Y_REG CCI_REG16(0x3812)
|
||||
|
||||
#define OV5693_SUB_INC_X_REG OV5693_REG_8BIT(0x3814)
|
||||
#define OV5693_SUB_INC_Y_REG OV5693_REG_8BIT(0x3815)
|
||||
#define OV5693_SUB_INC_X_REG CCI_REG8(0x3814)
|
||||
#define OV5693_SUB_INC_Y_REG CCI_REG8(0x3815)
|
||||
|
||||
#define OV5693_FORMAT1_REG OV5693_REG_8BIT(0x3820)
|
||||
#define OV5693_FORMAT1_REG CCI_REG8(0x3820)
|
||||
#define OV5693_FORMAT1_FLIP_VERT_ISP_EN BIT(6)
|
||||
#define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1)
|
||||
#define OV5693_FORMAT1_VBIN_EN BIT(0)
|
||||
#define OV5693_FORMAT2_REG OV5693_REG_8BIT(0x3821)
|
||||
#define OV5693_FORMAT2_REG CCI_REG8(0x3821)
|
||||
#define OV5693_FORMAT2_HDR_EN BIT(7)
|
||||
#define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2)
|
||||
#define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1)
|
||||
#define OV5693_FORMAT2_HBIN_EN BIT(0)
|
||||
|
||||
#define OV5693_ISP_CTRL2_REG OV5693_REG_8BIT(0x5002)
|
||||
#define OV5693_ISP_CTRL2_REG CCI_REG8(0x5002)
|
||||
#define OV5693_ISP_SCALE_ENABLE BIT(7)
|
||||
|
||||
/* Pixel Array */
|
||||
@ -116,7 +111,7 @@
|
||||
#define OV5693_MIN_CROP_HEIGHT 2
|
||||
|
||||
/* Test Pattern */
|
||||
#define OV5693_TEST_PATTERN_REG OV5693_REG_8BIT(0x5e00)
|
||||
#define OV5693_TEST_PATTERN_REG CCI_REG8(0x5e00)
|
||||
#define OV5693_TEST_PATTERN_ENABLE BIT(7)
|
||||
#define OV5693_TEST_PATTERN_ROLLING BIT(6)
|
||||
#define OV5693_TEST_PATTERN_RANDOM 0x01
|
||||
@ -137,19 +132,9 @@ static const char * const ov5693_supply_names[] = {
|
||||
|
||||
#define OV5693_NUM_SUPPLIES ARRAY_SIZE(ov5693_supply_names)
|
||||
|
||||
struct ov5693_reg {
|
||||
u32 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct ov5693_reg_list {
|
||||
u32 num_regs;
|
||||
const struct ov5693_reg *regs;
|
||||
};
|
||||
|
||||
struct ov5693_device {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
/* Protect against concurrent changes to controls */
|
||||
struct mutex lock;
|
||||
@ -189,156 +174,151 @@ struct ov5693_device {
|
||||
} ctrls;
|
||||
};
|
||||
|
||||
static const struct ov5693_reg ov5693_global_regs[] = {
|
||||
{OV5693_REG_8BIT(0x3016), 0xf0},
|
||||
{OV5693_REG_8BIT(0x3017), 0xf0},
|
||||
{OV5693_REG_8BIT(0x3018), 0xf0},
|
||||
{OV5693_REG_8BIT(0x3022), 0x01},
|
||||
{OV5693_REG_8BIT(0x3028), 0x44},
|
||||
{OV5693_REG_8BIT(0x3098), 0x02},
|
||||
{OV5693_REG_8BIT(0x3099), 0x19},
|
||||
{OV5693_REG_8BIT(0x309a), 0x02},
|
||||
{OV5693_REG_8BIT(0x309b), 0x01},
|
||||
{OV5693_REG_8BIT(0x309c), 0x00},
|
||||
{OV5693_REG_8BIT(0x30a0), 0xd2},
|
||||
{OV5693_REG_8BIT(0x30a2), 0x01},
|
||||
{OV5693_REG_8BIT(0x30b2), 0x00},
|
||||
{OV5693_REG_8BIT(0x30b3), 0x83},
|
||||
{OV5693_REG_8BIT(0x30b4), 0x03},
|
||||
{OV5693_REG_8BIT(0x30b5), 0x04},
|
||||
{OV5693_REG_8BIT(0x30b6), 0x01},
|
||||
{OV5693_REG_8BIT(0x3080), 0x01},
|
||||
{OV5693_REG_8BIT(0x3104), 0x21},
|
||||
{OV5693_REG_8BIT(0x3106), 0x00},
|
||||
{OV5693_REG_8BIT(0x3406), 0x01},
|
||||
{OV5693_REG_8BIT(0x3503), 0x07},
|
||||
{OV5693_REG_8BIT(0x350b), 0x40},
|
||||
{OV5693_REG_8BIT(0x3601), 0x0a},
|
||||
{OV5693_REG_8BIT(0x3602), 0x38},
|
||||
{OV5693_REG_8BIT(0x3612), 0x80},
|
||||
{OV5693_REG_8BIT(0x3620), 0x54},
|
||||
{OV5693_REG_8BIT(0x3621), 0xc7},
|
||||
{OV5693_REG_8BIT(0x3622), 0x0f},
|
||||
{OV5693_REG_8BIT(0x3625), 0x10},
|
||||
{OV5693_REG_8BIT(0x3630), 0x55},
|
||||
{OV5693_REG_8BIT(0x3631), 0xf4},
|
||||
{OV5693_REG_8BIT(0x3632), 0x00},
|
||||
{OV5693_REG_8BIT(0x3633), 0x34},
|
||||
{OV5693_REG_8BIT(0x3634), 0x02},
|
||||
{OV5693_REG_8BIT(0x364d), 0x0d},
|
||||
{OV5693_REG_8BIT(0x364f), 0xdd},
|
||||
{OV5693_REG_8BIT(0x3660), 0x04},
|
||||
{OV5693_REG_8BIT(0x3662), 0x10},
|
||||
{OV5693_REG_8BIT(0x3663), 0xf1},
|
||||
{OV5693_REG_8BIT(0x3665), 0x00},
|
||||
{OV5693_REG_8BIT(0x3666), 0x20},
|
||||
{OV5693_REG_8BIT(0x3667), 0x00},
|
||||
{OV5693_REG_8BIT(0x366a), 0x80},
|
||||
{OV5693_REG_8BIT(0x3680), 0xe0},
|
||||
{OV5693_REG_8BIT(0x3681), 0x00},
|
||||
{OV5693_REG_8BIT(0x3700), 0x42},
|
||||
{OV5693_REG_8BIT(0x3701), 0x14},
|
||||
{OV5693_REG_8BIT(0x3702), 0xa0},
|
||||
{OV5693_REG_8BIT(0x3703), 0xd8},
|
||||
{OV5693_REG_8BIT(0x3704), 0x78},
|
||||
{OV5693_REG_8BIT(0x3705), 0x02},
|
||||
{OV5693_REG_8BIT(0x370a), 0x00},
|
||||
{OV5693_REG_8BIT(0x370b), 0x20},
|
||||
{OV5693_REG_8BIT(0x370c), 0x0c},
|
||||
{OV5693_REG_8BIT(0x370d), 0x11},
|
||||
{OV5693_REG_8BIT(0x370e), 0x00},
|
||||
{OV5693_REG_8BIT(0x370f), 0x40},
|
||||
{OV5693_REG_8BIT(0x3710), 0x00},
|
||||
{OV5693_REG_8BIT(0x371a), 0x1c},
|
||||
{OV5693_REG_8BIT(0x371b), 0x05},
|
||||
{OV5693_REG_8BIT(0x371c), 0x01},
|
||||
{OV5693_REG_8BIT(0x371e), 0xa1},
|
||||
{OV5693_REG_8BIT(0x371f), 0x0c},
|
||||
{OV5693_REG_8BIT(0x3721), 0x00},
|
||||
{OV5693_REG_8BIT(0x3724), 0x10},
|
||||
{OV5693_REG_8BIT(0x3726), 0x00},
|
||||
{OV5693_REG_8BIT(0x372a), 0x01},
|
||||
{OV5693_REG_8BIT(0x3730), 0x10},
|
||||
{OV5693_REG_8BIT(0x3738), 0x22},
|
||||
{OV5693_REG_8BIT(0x3739), 0xe5},
|
||||
{OV5693_REG_8BIT(0x373a), 0x50},
|
||||
{OV5693_REG_8BIT(0x373b), 0x02},
|
||||
{OV5693_REG_8BIT(0x373c), 0x41},
|
||||
{OV5693_REG_8BIT(0x373f), 0x02},
|
||||
{OV5693_REG_8BIT(0x3740), 0x42},
|
||||
{OV5693_REG_8BIT(0x3741), 0x02},
|
||||
{OV5693_REG_8BIT(0x3742), 0x18},
|
||||
{OV5693_REG_8BIT(0x3743), 0x01},
|
||||
{OV5693_REG_8BIT(0x3744), 0x02},
|
||||
{OV5693_REG_8BIT(0x3747), 0x10},
|
||||
{OV5693_REG_8BIT(0x374c), 0x04},
|
||||
{OV5693_REG_8BIT(0x3751), 0xf0},
|
||||
{OV5693_REG_8BIT(0x3752), 0x00},
|
||||
{OV5693_REG_8BIT(0x3753), 0x00},
|
||||
{OV5693_REG_8BIT(0x3754), 0xc0},
|
||||
{OV5693_REG_8BIT(0x3755), 0x00},
|
||||
{OV5693_REG_8BIT(0x3756), 0x1a},
|
||||
{OV5693_REG_8BIT(0x3758), 0x00},
|
||||
{OV5693_REG_8BIT(0x3759), 0x0f},
|
||||
{OV5693_REG_8BIT(0x376b), 0x44},
|
||||
{OV5693_REG_8BIT(0x375c), 0x04},
|
||||
{OV5693_REG_8BIT(0x3774), 0x10},
|
||||
{OV5693_REG_8BIT(0x3776), 0x00},
|
||||
{OV5693_REG_8BIT(0x377f), 0x08},
|
||||
{OV5693_REG_8BIT(0x3780), 0x22},
|
||||
{OV5693_REG_8BIT(0x3781), 0x0c},
|
||||
{OV5693_REG_8BIT(0x3784), 0x2c},
|
||||
{OV5693_REG_8BIT(0x3785), 0x1e},
|
||||
{OV5693_REG_8BIT(0x378f), 0xf5},
|
||||
{OV5693_REG_8BIT(0x3791), 0xb0},
|
||||
{OV5693_REG_8BIT(0x3795), 0x00},
|
||||
{OV5693_REG_8BIT(0x3796), 0x64},
|
||||
{OV5693_REG_8BIT(0x3797), 0x11},
|
||||
{OV5693_REG_8BIT(0x3798), 0x30},
|
||||
{OV5693_REG_8BIT(0x3799), 0x41},
|
||||
{OV5693_REG_8BIT(0x379a), 0x07},
|
||||
{OV5693_REG_8BIT(0x379b), 0xb0},
|
||||
{OV5693_REG_8BIT(0x379c), 0x0c},
|
||||
{OV5693_REG_8BIT(0x3a04), 0x06},
|
||||
{OV5693_REG_8BIT(0x3a05), 0x14},
|
||||
{OV5693_REG_8BIT(0x3e07), 0x20},
|
||||
{OV5693_REG_8BIT(0x4000), 0x08},
|
||||
{OV5693_REG_8BIT(0x4001), 0x04},
|
||||
{OV5693_REG_8BIT(0x4004), 0x08},
|
||||
{OV5693_REG_8BIT(0x4006), 0x20},
|
||||
{OV5693_REG_8BIT(0x4008), 0x24},
|
||||
{OV5693_REG_8BIT(0x4009), 0x10},
|
||||
{OV5693_REG_8BIT(0x4058), 0x00},
|
||||
{OV5693_REG_8BIT(0x4101), 0xb2},
|
||||
{OV5693_REG_8BIT(0x4307), 0x31},
|
||||
{OV5693_REG_8BIT(0x4511), 0x05},
|
||||
{OV5693_REG_8BIT(0x4512), 0x01},
|
||||
{OV5693_REG_8BIT(0x481f), 0x30},
|
||||
{OV5693_REG_8BIT(0x4826), 0x2c},
|
||||
{OV5693_REG_8BIT(0x4d02), 0xfd},
|
||||
{OV5693_REG_8BIT(0x4d03), 0xf5},
|
||||
{OV5693_REG_8BIT(0x4d04), 0x0c},
|
||||
{OV5693_REG_8BIT(0x4d05), 0xcc},
|
||||
{OV5693_REG_8BIT(0x4837), 0x0a},
|
||||
{OV5693_REG_8BIT(0x5003), 0x20},
|
||||
{OV5693_REG_8BIT(0x5013), 0x00},
|
||||
{OV5693_REG_8BIT(0x5842), 0x01},
|
||||
{OV5693_REG_8BIT(0x5843), 0x2b},
|
||||
{OV5693_REG_8BIT(0x5844), 0x01},
|
||||
{OV5693_REG_8BIT(0x5845), 0x92},
|
||||
{OV5693_REG_8BIT(0x5846), 0x01},
|
||||
{OV5693_REG_8BIT(0x5847), 0x8f},
|
||||
{OV5693_REG_8BIT(0x5848), 0x01},
|
||||
{OV5693_REG_8BIT(0x5849), 0x0c},
|
||||
{OV5693_REG_8BIT(0x5e10), 0x0c},
|
||||
{OV5693_REG_8BIT(0x3820), 0x00},
|
||||
{OV5693_REG_8BIT(0x3821), 0x1e},
|
||||
{OV5693_REG_8BIT(0x5041), 0x14}
|
||||
};
|
||||
|
||||
static const struct ov5693_reg_list ov5693_global_setting = {
|
||||
.num_regs = ARRAY_SIZE(ov5693_global_regs),
|
||||
.regs = ov5693_global_regs,
|
||||
static const struct cci_reg_sequence ov5693_global_regs[] = {
|
||||
{CCI_REG8(0x3016), 0xf0},
|
||||
{CCI_REG8(0x3017), 0xf0},
|
||||
{CCI_REG8(0x3018), 0xf0},
|
||||
{CCI_REG8(0x3022), 0x01},
|
||||
{CCI_REG8(0x3028), 0x44},
|
||||
{CCI_REG8(0x3098), 0x02},
|
||||
{CCI_REG8(0x3099), 0x19},
|
||||
{CCI_REG8(0x309a), 0x02},
|
||||
{CCI_REG8(0x309b), 0x01},
|
||||
{CCI_REG8(0x309c), 0x00},
|
||||
{CCI_REG8(0x30a0), 0xd2},
|
||||
{CCI_REG8(0x30a2), 0x01},
|
||||
{CCI_REG8(0x30b2), 0x00},
|
||||
{CCI_REG8(0x30b3), 0x83},
|
||||
{CCI_REG8(0x30b4), 0x03},
|
||||
{CCI_REG8(0x30b5), 0x04},
|
||||
{CCI_REG8(0x30b6), 0x01},
|
||||
{CCI_REG8(0x3080), 0x01},
|
||||
{CCI_REG8(0x3104), 0x21},
|
||||
{CCI_REG8(0x3106), 0x00},
|
||||
{CCI_REG8(0x3406), 0x01},
|
||||
{CCI_REG8(0x3503), 0x07},
|
||||
{CCI_REG8(0x350b), 0x40},
|
||||
{CCI_REG8(0x3601), 0x0a},
|
||||
{CCI_REG8(0x3602), 0x38},
|
||||
{CCI_REG8(0x3612), 0x80},
|
||||
{CCI_REG8(0x3620), 0x54},
|
||||
{CCI_REG8(0x3621), 0xc7},
|
||||
{CCI_REG8(0x3622), 0x0f},
|
||||
{CCI_REG8(0x3625), 0x10},
|
||||
{CCI_REG8(0x3630), 0x55},
|
||||
{CCI_REG8(0x3631), 0xf4},
|
||||
{CCI_REG8(0x3632), 0x00},
|
||||
{CCI_REG8(0x3633), 0x34},
|
||||
{CCI_REG8(0x3634), 0x02},
|
||||
{CCI_REG8(0x364d), 0x0d},
|
||||
{CCI_REG8(0x364f), 0xdd},
|
||||
{CCI_REG8(0x3660), 0x04},
|
||||
{CCI_REG8(0x3662), 0x10},
|
||||
{CCI_REG8(0x3663), 0xf1},
|
||||
{CCI_REG8(0x3665), 0x00},
|
||||
{CCI_REG8(0x3666), 0x20},
|
||||
{CCI_REG8(0x3667), 0x00},
|
||||
{CCI_REG8(0x366a), 0x80},
|
||||
{CCI_REG8(0x3680), 0xe0},
|
||||
{CCI_REG8(0x3681), 0x00},
|
||||
{CCI_REG8(0x3700), 0x42},
|
||||
{CCI_REG8(0x3701), 0x14},
|
||||
{CCI_REG8(0x3702), 0xa0},
|
||||
{CCI_REG8(0x3703), 0xd8},
|
||||
{CCI_REG8(0x3704), 0x78},
|
||||
{CCI_REG8(0x3705), 0x02},
|
||||
{CCI_REG8(0x370a), 0x00},
|
||||
{CCI_REG8(0x370b), 0x20},
|
||||
{CCI_REG8(0x370c), 0x0c},
|
||||
{CCI_REG8(0x370d), 0x11},
|
||||
{CCI_REG8(0x370e), 0x00},
|
||||
{CCI_REG8(0x370f), 0x40},
|
||||
{CCI_REG8(0x3710), 0x00},
|
||||
{CCI_REG8(0x371a), 0x1c},
|
||||
{CCI_REG8(0x371b), 0x05},
|
||||
{CCI_REG8(0x371c), 0x01},
|
||||
{CCI_REG8(0x371e), 0xa1},
|
||||
{CCI_REG8(0x371f), 0x0c},
|
||||
{CCI_REG8(0x3721), 0x00},
|
||||
{CCI_REG8(0x3724), 0x10},
|
||||
{CCI_REG8(0x3726), 0x00},
|
||||
{CCI_REG8(0x372a), 0x01},
|
||||
{CCI_REG8(0x3730), 0x10},
|
||||
{CCI_REG8(0x3738), 0x22},
|
||||
{CCI_REG8(0x3739), 0xe5},
|
||||
{CCI_REG8(0x373a), 0x50},
|
||||
{CCI_REG8(0x373b), 0x02},
|
||||
{CCI_REG8(0x373c), 0x41},
|
||||
{CCI_REG8(0x373f), 0x02},
|
||||
{CCI_REG8(0x3740), 0x42},
|
||||
{CCI_REG8(0x3741), 0x02},
|
||||
{CCI_REG8(0x3742), 0x18},
|
||||
{CCI_REG8(0x3743), 0x01},
|
||||
{CCI_REG8(0x3744), 0x02},
|
||||
{CCI_REG8(0x3747), 0x10},
|
||||
{CCI_REG8(0x374c), 0x04},
|
||||
{CCI_REG8(0x3751), 0xf0},
|
||||
{CCI_REG8(0x3752), 0x00},
|
||||
{CCI_REG8(0x3753), 0x00},
|
||||
{CCI_REG8(0x3754), 0xc0},
|
||||
{CCI_REG8(0x3755), 0x00},
|
||||
{CCI_REG8(0x3756), 0x1a},
|
||||
{CCI_REG8(0x3758), 0x00},
|
||||
{CCI_REG8(0x3759), 0x0f},
|
||||
{CCI_REG8(0x376b), 0x44},
|
||||
{CCI_REG8(0x375c), 0x04},
|
||||
{CCI_REG8(0x3774), 0x10},
|
||||
{CCI_REG8(0x3776), 0x00},
|
||||
{CCI_REG8(0x377f), 0x08},
|
||||
{CCI_REG8(0x3780), 0x22},
|
||||
{CCI_REG8(0x3781), 0x0c},
|
||||
{CCI_REG8(0x3784), 0x2c},
|
||||
{CCI_REG8(0x3785), 0x1e},
|
||||
{CCI_REG8(0x378f), 0xf5},
|
||||
{CCI_REG8(0x3791), 0xb0},
|
||||
{CCI_REG8(0x3795), 0x00},
|
||||
{CCI_REG8(0x3796), 0x64},
|
||||
{CCI_REG8(0x3797), 0x11},
|
||||
{CCI_REG8(0x3798), 0x30},
|
||||
{CCI_REG8(0x3799), 0x41},
|
||||
{CCI_REG8(0x379a), 0x07},
|
||||
{CCI_REG8(0x379b), 0xb0},
|
||||
{CCI_REG8(0x379c), 0x0c},
|
||||
{CCI_REG8(0x3a04), 0x06},
|
||||
{CCI_REG8(0x3a05), 0x14},
|
||||
{CCI_REG8(0x3e07), 0x20},
|
||||
{CCI_REG8(0x4000), 0x08},
|
||||
{CCI_REG8(0x4001), 0x04},
|
||||
{CCI_REG8(0x4004), 0x08},
|
||||
{CCI_REG8(0x4006), 0x20},
|
||||
{CCI_REG8(0x4008), 0x24},
|
||||
{CCI_REG8(0x4009), 0x10},
|
||||
{CCI_REG8(0x4058), 0x00},
|
||||
{CCI_REG8(0x4101), 0xb2},
|
||||
{CCI_REG8(0x4307), 0x31},
|
||||
{CCI_REG8(0x4511), 0x05},
|
||||
{CCI_REG8(0x4512), 0x01},
|
||||
{CCI_REG8(0x481f), 0x30},
|
||||
{CCI_REG8(0x4826), 0x2c},
|
||||
{CCI_REG8(0x4d02), 0xfd},
|
||||
{CCI_REG8(0x4d03), 0xf5},
|
||||
{CCI_REG8(0x4d04), 0x0c},
|
||||
{CCI_REG8(0x4d05), 0xcc},
|
||||
{CCI_REG8(0x4837), 0x0a},
|
||||
{CCI_REG8(0x5003), 0x20},
|
||||
{CCI_REG8(0x5013), 0x00},
|
||||
{CCI_REG8(0x5842), 0x01},
|
||||
{CCI_REG8(0x5843), 0x2b},
|
||||
{CCI_REG8(0x5844), 0x01},
|
||||
{CCI_REG8(0x5845), 0x92},
|
||||
{CCI_REG8(0x5846), 0x01},
|
||||
{CCI_REG8(0x5847), 0x8f},
|
||||
{CCI_REG8(0x5848), 0x01},
|
||||
{CCI_REG8(0x5849), 0x0c},
|
||||
{CCI_REG8(0x5e10), 0x0c},
|
||||
{CCI_REG8(0x3820), 0x00},
|
||||
{CCI_REG8(0x3821), 0x1e},
|
||||
{CCI_REG8(0x5041), 0x14}
|
||||
};
|
||||
|
||||
static const struct v4l2_rect ov5693_default_crop = {
|
||||
@ -373,115 +353,6 @@ static const u8 ov5693_test_pattern_bits[] = {
|
||||
OV5693_TEST_PATTERN_ROLLING,
|
||||
};
|
||||
|
||||
/* I2C I/O Operations */
|
||||
|
||||
static int ov5693_read_reg(struct ov5693_device *ov5693, u32 addr, u32 *value)
|
||||
{
|
||||
struct i2c_client *client = ov5693->client;
|
||||
__be16 reg;
|
||||
u8 val[4];
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = (u8 *)®,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = (u8 *)&val,
|
||||
},
|
||||
};
|
||||
unsigned int len = ((addr >> OV5693_REG_SIZE_SHIFT) & 3);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
reg = cpu_to_be16(addr & OV5693_REG_ADDR_MASK);
|
||||
|
||||
msg[1].len = len;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"Failed to read register 0x%04x\n",
|
||||
addr & OV5693_REG_ADDR_MASK);
|
||||
|
||||
*value = 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
*value <<= 8;
|
||||
*value |= val[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ov5693_write_reg(struct ov5693_device *ov5693, u32 addr, u32 value,
|
||||
int *error)
|
||||
{
|
||||
struct i2c_client *client = ov5693->client;
|
||||
struct {
|
||||
__be16 reg;
|
||||
u8 val[4];
|
||||
} __packed buf;
|
||||
struct i2c_msg msg = {
|
||||
.addr = client->addr,
|
||||
.buf = (u8 *)&buf,
|
||||
};
|
||||
unsigned int len = ((addr >> OV5693_REG_SIZE_SHIFT) & 3);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (*error < 0)
|
||||
return;
|
||||
|
||||
buf.reg = cpu_to_be16(addr & OV5693_REG_ADDR_MASK);
|
||||
for (i = 0; i < len; ++i) {
|
||||
buf.val[len - i - 1] = value & 0xff;
|
||||
value >>= 8;
|
||||
}
|
||||
|
||||
msg.len = len + 2;
|
||||
|
||||
ret = i2c_transfer(client->adapter, &msg, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failed to write register 0x%04x: %d\n",
|
||||
addr & OV5693_REG_ADDR_MASK, ret);
|
||||
*error = ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int ov5693_write_reg_array(struct ov5693_device *ov5693,
|
||||
const struct ov5693_reg_list *reglist)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < reglist->num_regs; i++)
|
||||
ov5693_write_reg(ov5693, reglist->regs[i].reg,
|
||||
reglist->regs[i].val, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5693_update_bits(struct ov5693_device *ov5693, u32 address,
|
||||
u32 mask, u32 bits)
|
||||
{
|
||||
u32 value = 0;
|
||||
int ret;
|
||||
|
||||
ret = ov5693_read_reg(ov5693, address, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
value &= ~mask;
|
||||
value |= bits;
|
||||
|
||||
ov5693_write_reg(ov5693, address, value, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* V4L2 Controls Functions */
|
||||
|
||||
static int ov5693_flip_vert_configure(struct ov5693_device *ov5693,
|
||||
@ -491,8 +362,8 @@ static int ov5693_flip_vert_configure(struct ov5693_device *ov5693,
|
||||
OV5693_FORMAT1_FLIP_VERT_SENSOR_EN;
|
||||
int ret;
|
||||
|
||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, bits,
|
||||
enable ? bits : 0);
|
||||
ret = cci_update_bits(ov5693->regmap, OV5693_FORMAT1_REG, bits,
|
||||
enable ? bits : 0, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -506,8 +377,8 @@ static int ov5693_flip_horz_configure(struct ov5693_device *ov5693,
|
||||
OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN;
|
||||
int ret;
|
||||
|
||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, bits,
|
||||
enable ? bits : 0);
|
||||
ret = cci_update_bits(ov5693->regmap, OV5693_FORMAT2_REG, bits,
|
||||
enable ? bits : 0, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -516,10 +387,11 @@ static int ov5693_flip_horz_configure(struct ov5693_device *ov5693,
|
||||
|
||||
static int ov5693_get_exposure(struct ov5693_device *ov5693, s32 *value)
|
||||
{
|
||||
u32 exposure;
|
||||
u64 exposure;
|
||||
int ret;
|
||||
|
||||
ret = ov5693_read_reg(ov5693, OV5693_EXPOSURE_CTRL_REG, &exposure);
|
||||
ret = cci_read(ov5693->regmap, OV5693_EXPOSURE_CTRL_REG, &exposure,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -536,17 +408,17 @@ static int ov5693_exposure_configure(struct ov5693_device *ov5693,
|
||||
|
||||
exposure = (exposure << 4) & OV5693_EXPOSURE_CTRL_MASK;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_EXPOSURE_CTRL_REG, exposure, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_EXPOSURE_CTRL_REG, exposure, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain)
|
||||
{
|
||||
u32 value;
|
||||
u64 value;
|
||||
int ret;
|
||||
|
||||
ret = ov5693_read_reg(ov5693, OV5693_GAIN_CTRL_REG, &value);
|
||||
ret = cci_read(ov5693->regmap, OV5693_GAIN_CTRL_REG, &value, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -563,9 +435,9 @@ static int ov5693_digital_gain_configure(struct ov5693_device *ov5693,
|
||||
|
||||
gain &= OV5693_MWB_GAIN_MASK;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_MWB_RED_GAIN_REG, gain, &ret);
|
||||
ov5693_write_reg(ov5693, OV5693_MWB_GREEN_GAIN_REG, gain, &ret);
|
||||
ov5693_write_reg(ov5693, OV5693_MWB_BLUE_GAIN_REG, gain, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_MWB_RED_GAIN_REG, gain, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_MWB_GREEN_GAIN_REG, gain, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_MWB_BLUE_GAIN_REG, gain, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -576,7 +448,7 @@ static int ov5693_analog_gain_configure(struct ov5693_device *ov5693, u32 gain)
|
||||
|
||||
gain = (gain << 4) & OV5693_GAIN_CTRL_MASK;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_GAIN_CTRL_REG, gain, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_GAIN_CTRL_REG, gain, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -586,7 +458,7 @@ static int ov5693_vts_configure(struct ov5693_device *ov5693, u32 vblank)
|
||||
u16 vts = ov5693->mode.format.height + vblank;
|
||||
int ret = 0;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_TIMING_VTS_REG, vts, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_TIMING_VTS_REG, vts, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -595,8 +467,8 @@ static int ov5693_test_pattern_configure(struct ov5693_device *ov5693, u32 idx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_TEST_PATTERN_REG,
|
||||
ov5693_test_pattern_bits[idx], &ret);
|
||||
cci_write(ov5693->regmap, OV5693_TEST_PATTERN_REG,
|
||||
ov5693_test_pattern_bits[idx], &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -685,59 +557,54 @@ static int ov5693_mode_configure(struct ov5693_device *ov5693)
|
||||
int ret = 0;
|
||||
|
||||
/* Crop Start X */
|
||||
ov5693_write_reg(ov5693, OV5693_CROP_START_X_REG, mode->crop.left,
|
||||
&ret);
|
||||
cci_write(ov5693->regmap, OV5693_CROP_START_X_REG, mode->crop.left,
|
||||
&ret);
|
||||
|
||||
/* Offset X */
|
||||
ov5693_write_reg(ov5693, OV5693_OFFSET_START_X_REG, 0, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_OFFSET_START_X_REG, 0, &ret);
|
||||
|
||||
/* Output Size X */
|
||||
ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_X_REG, mode->format.width,
|
||||
&ret);
|
||||
cci_write(ov5693->regmap, OV5693_OUTPUT_SIZE_X_REG, mode->format.width,
|
||||
&ret);
|
||||
|
||||
/* Crop End X */
|
||||
ov5693_write_reg(ov5693, OV5693_CROP_END_X_REG,
|
||||
mode->crop.left + mode->crop.width, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_CROP_END_X_REG,
|
||||
mode->crop.left + mode->crop.width, &ret);
|
||||
|
||||
/* Horizontal Total Size */
|
||||
ov5693_write_reg(ov5693, OV5693_TIMING_HTS_REG, OV5693_FIXED_PPL,
|
||||
&ret);
|
||||
cci_write(ov5693->regmap, OV5693_TIMING_HTS_REG, OV5693_FIXED_PPL,
|
||||
&ret);
|
||||
|
||||
/* Crop Start Y */
|
||||
ov5693_write_reg(ov5693, OV5693_CROP_START_Y_REG, mode->crop.top,
|
||||
&ret);
|
||||
cci_write(ov5693->regmap, OV5693_CROP_START_Y_REG, mode->crop.top,
|
||||
&ret);
|
||||
|
||||
/* Offset Y */
|
||||
ov5693_write_reg(ov5693, OV5693_OFFSET_START_Y_REG, 0, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_OFFSET_START_Y_REG, 0, &ret);
|
||||
|
||||
/* Output Size Y */
|
||||
ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_Y_REG, mode->format.height,
|
||||
&ret);
|
||||
cci_write(ov5693->regmap, OV5693_OUTPUT_SIZE_Y_REG, mode->format.height,
|
||||
&ret);
|
||||
|
||||
/* Crop End Y */
|
||||
ov5693_write_reg(ov5693, OV5693_CROP_END_Y_REG,
|
||||
mode->crop.top + mode->crop.height, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_CROP_END_Y_REG,
|
||||
mode->crop.top + mode->crop.height, &ret);
|
||||
|
||||
/* Subsample X increase */
|
||||
ov5693_write_reg(ov5693, OV5693_SUB_INC_X_REG,
|
||||
((mode->inc_x_odd << 4) & 0xf0) | 0x01, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_SUB_INC_X_REG,
|
||||
((mode->inc_x_odd << 4) & 0xf0) | 0x01, &ret);
|
||||
/* Subsample Y increase */
|
||||
ov5693_write_reg(ov5693, OV5693_SUB_INC_Y_REG,
|
||||
((mode->inc_y_odd << 4) & 0xf0) | 0x01, &ret);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
cci_write(ov5693->regmap, OV5693_SUB_INC_Y_REG,
|
||||
((mode->inc_y_odd << 4) & 0xf0) | 0x01, &ret);
|
||||
|
||||
/* Binning */
|
||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG,
|
||||
OV5693_FORMAT1_VBIN_EN,
|
||||
mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
cci_update_bits(ov5693->regmap, OV5693_FORMAT1_REG,
|
||||
OV5693_FORMAT1_VBIN_EN,
|
||||
mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0, &ret);
|
||||
|
||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG,
|
||||
OV5693_FORMAT2_HBIN_EN,
|
||||
mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0);
|
||||
cci_update_bits(ov5693->regmap, OV5693_FORMAT2_REG,
|
||||
OV5693_FORMAT2_HBIN_EN,
|
||||
mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -746,9 +613,9 @@ static int ov5693_enable_streaming(struct ov5693_device *ov5693, bool enable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_SW_STREAM_REG,
|
||||
enable ? OV5693_START_STREAMING :
|
||||
OV5693_STOP_STREAMING, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_SW_STREAM_REG,
|
||||
enable ? OV5693_START_STREAMING : OV5693_STOP_STREAMING,
|
||||
&ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -757,7 +624,7 @@ static int ov5693_sw_reset(struct ov5693_device *ov5693)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ov5693_write_reg(ov5693, OV5693_SW_RESET_REG, OV5693_SW_RESET, &ret);
|
||||
cci_write(ov5693->regmap, OV5693_SW_RESET_REG, OV5693_SW_RESET, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -771,7 +638,8 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
|
||||
return dev_err_probe(ov5693->dev, ret,
|
||||
"software reset error\n");
|
||||
|
||||
ret = ov5693_write_reg_array(ov5693, &ov5693_global_setting);
|
||||
ret = cci_multi_reg_write(ov5693->regmap, ov5693_global_regs,
|
||||
ARRAY_SIZE(ov5693_global_regs), NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(ov5693->dev, ret,
|
||||
"global settings error\n");
|
||||
@ -871,15 +739,15 @@ out_unlock:
|
||||
static int ov5693_detect(struct ov5693_device *ov5693)
|
||||
{
|
||||
int ret;
|
||||
u32 id;
|
||||
u64 id;
|
||||
|
||||
ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID, &id);
|
||||
ret = cci_read(ov5693->regmap, OV5693_REG_CHIP_ID, &id, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id != OV5693_CHIP_ID)
|
||||
return dev_err_probe(ov5693->dev, -ENODEV,
|
||||
"sensor ID mismatch. Found 0x%04x\n", id);
|
||||
"sensor ID mismatch. Got 0x%04llx\n", id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1407,9 +1275,12 @@ static int ov5693_probe(struct i2c_client *client)
|
||||
if (!ov5693)
|
||||
return -ENOMEM;
|
||||
|
||||
ov5693->client = client;
|
||||
ov5693->dev = &client->dev;
|
||||
|
||||
ov5693->regmap = devm_cci_regmap_init_i2c(client, 16);
|
||||
if (IS_ERR(ov5693->regmap))
|
||||
return PTR_ERR(ov5693->regmap);
|
||||
|
||||
ret = ov5693_check_hwcfg(ov5693);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1210,7 +1210,7 @@ static struct i2c_driver ov7740_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ov7740",
|
||||
.pm = &ov7740_pm_ops,
|
||||
.of_match_table = of_match_ptr(ov7740_of_match),
|
||||
.of_match_table = ov7740_of_match,
|
||||
},
|
||||
.probe = ov7740_probe,
|
||||
.remove = ov7740_remove,
|
||||
|
@ -567,7 +567,6 @@ again:
|
||||
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);
|
||||
@ -616,24 +615,12 @@ static int rdacm20_probe(struct i2c_client *client)
|
||||
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;
|
||||
goto error_free_ctrls;
|
||||
|
||||
return 0;
|
||||
|
||||
error_put_node:
|
||||
fwnode_handle_put(ep);
|
||||
error_free_ctrls:
|
||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||
error:
|
||||
@ -650,7 +637,6 @@ static void 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);
|
||||
|
@ -351,7 +351,7 @@ static void ov10640_power_up(struct rdacm21_device *dev)
|
||||
static int ov10640_check_id(struct rdacm21_device *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 val;
|
||||
u8 val = 0;
|
||||
|
||||
/* Read OV10640 ID to test communications. */
|
||||
for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
|
||||
@ -543,7 +543,6 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
|
||||
static int rdacm21_probe(struct i2c_client *client)
|
||||
{
|
||||
struct rdacm21_device *dev;
|
||||
struct fwnode_handle *ep;
|
||||
int ret;
|
||||
|
||||
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
|
||||
@ -588,24 +587,12 @@ static int rdacm21_probe(struct i2c_client *client)
|
||||
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;
|
||||
goto error_free_ctrls;
|
||||
|
||||
return 0;
|
||||
|
||||
error_put_node:
|
||||
fwnode_handle_put(dev->sd.fwnode);
|
||||
error_free_ctrls:
|
||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||
error:
|
||||
|
@ -545,7 +545,14 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge)
|
||||
static int mipid02_stream_disable(struct mipid02_dev *bridge)
|
||||
{
|
||||
struct i2c_client *client = bridge->i2c_client;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!bridge->s_subdev)
|
||||
goto error;
|
||||
|
||||
ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Disable all lanes */
|
||||
ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0);
|
||||
@ -633,6 +640,10 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge)
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@ -829,7 +840,7 @@ static const struct media_entity_operations mipid02_subdev_entity_ops = {
|
||||
|
||||
static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *s_subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
|
||||
struct i2c_client *client = bridge->i2c_client;
|
||||
@ -863,7 +874,7 @@ static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
|
||||
|
||||
static void mipid02_async_unbind(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *s_subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
|
||||
|
||||
@ -879,7 +890,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
|
||||
{
|
||||
struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
|
||||
struct i2c_client *client = bridge->i2c_client;
|
||||
struct v4l2_async_subdev *asd;
|
||||
struct v4l2_async_connection *asd;
|
||||
struct device_node *ep_node;
|
||||
int ret;
|
||||
|
||||
@ -911,10 +922,10 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
|
||||
bridge->rx = ep;
|
||||
|
||||
/* register async notifier so we get noticed when sensor is connected */
|
||||
v4l2_async_nf_init(&bridge->notifier);
|
||||
v4l2_async_subdev_nf_init(&bridge->notifier, &bridge->sd);
|
||||
asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier,
|
||||
of_fwnode_handle(ep_node),
|
||||
struct v4l2_async_subdev);
|
||||
struct v4l2_async_connection);
|
||||
of_node_put(ep_node);
|
||||
|
||||
if (IS_ERR(asd)) {
|
||||
@ -924,7 +935,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
|
||||
}
|
||||
bridge->notifier.ops = &mipid02_notifier_ops;
|
||||
|
||||
ret = v4l2_async_subdev_nf_register(&bridge->sd, &bridge->notifier);
|
||||
ret = v4l2_async_nf_register(&bridge->notifier);
|
||||
if (ret)
|
||||
v4l2_async_nf_cleanup(&bridge->notifier);
|
||||
|
||||
|
@ -133,8 +133,8 @@ static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
||||
|
||||
err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (err != ARRAY_SIZE(msgs)) {
|
||||
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
|
||||
__func__, reg, client->addr);
|
||||
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n",
|
||||
__func__, reg, client->addr, err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,8 +165,8 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
||||
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
if (err != 1) {
|
||||
v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
|
||||
__func__, reg, client->addr);
|
||||
v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed: %d\n",
|
||||
__func__, reg, client->addr, err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1426,7 +1426,7 @@ static int tc358746_init_controls(struct tc358746 *tc358746)
|
||||
|
||||
static int tc358746_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *sd,
|
||||
struct v4l2_async_subdev *asd)
|
||||
struct v4l2_async_connection *asd)
|
||||
{
|
||||
struct tc358746 *tc358746 =
|
||||
container_of(notifier, struct tc358746, notifier);
|
||||
@ -1445,7 +1445,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
||||
struct v4l2_fwnode_endpoint vep = {
|
||||
.bus_type = V4L2_MBUS_PARALLEL,
|
||||
};
|
||||
struct v4l2_async_subdev *asd;
|
||||
struct v4l2_async_connection *asd;
|
||||
struct fwnode_handle *ep;
|
||||
int err;
|
||||
|
||||
@ -1460,9 +1460,9 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
||||
return err;
|
||||
}
|
||||
|
||||
v4l2_async_nf_init(&tc358746->notifier);
|
||||
v4l2_async_subdev_nf_init(&tc358746->notifier, &tc358746->sd);
|
||||
asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep,
|
||||
struct v4l2_async_subdev);
|
||||
struct v4l2_async_connection);
|
||||
fwnode_handle_put(ep);
|
||||
|
||||
if (IS_ERR(asd)) {
|
||||
@ -1472,13 +1472,10 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
||||
|
||||
tc358746->notifier.ops = &tc358746_notify_ops;
|
||||
|
||||
err = v4l2_async_subdev_nf_register(&tc358746->sd, &tc358746->notifier);
|
||||
err = v4l2_async_nf_register(&tc358746->notifier);
|
||||
if (err)
|
||||
goto err_cleanup;
|
||||
|
||||
tc358746->sd.fwnode = fwnode_graph_get_endpoint_by_id(
|
||||
dev_fwnode(tc358746->sd.dev), TC358746_SOURCE, 0, 0);
|
||||
|
||||
err = v4l2_async_register_subdev(&tc358746->sd);
|
||||
if (err)
|
||||
goto err_unregister;
|
||||
@ -1486,7 +1483,6 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
||||
return 0;
|
||||
|
||||
err_unregister:
|
||||
fwnode_handle_put(tc358746->sd.fwnode);
|
||||
v4l2_async_nf_unregister(&tc358746->notifier);
|
||||
err_cleanup:
|
||||
v4l2_async_nf_cleanup(&tc358746->notifier);
|
||||
@ -1605,7 +1601,6 @@ static void tc358746_remove(struct i2c_client *client)
|
||||
v4l2_fwnode_endpoint_free(&tc358746->csi_vep);
|
||||
v4l2_async_nf_unregister(&tc358746->notifier);
|
||||
v4l2_async_nf_cleanup(&tc358746->notifier);
|
||||
fwnode_handle_put(sd->fwnode);
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
|
||||
|
@ -2068,6 +2068,10 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
|
||||
tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
|
||||
v4l2c->name, v4l2c->label ?
|
||||
v4l2c->label : "");
|
||||
if (!tvpc->ent.name) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0);
|
||||
|
@ -16,9 +16,9 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
@ -73,7 +73,7 @@ config VIDEO_PCI_SKELETON
|
||||
Enable build of the skeleton PCI driver, used as a reference
|
||||
when developing new drivers.
|
||||
|
||||
source "drivers/media/pci/intel/ipu3/Kconfig"
|
||||
source "drivers/media/pci/intel/Kconfig"
|
||||
|
||||
endif #MEDIA_PCI_SUPPORT
|
||||
endif #PCI
|
||||
|
@ -3,7 +3,7 @@ config VIDEO_BT848
|
||||
tristate "BT848 Video For Linux"
|
||||
depends on PCI && I2C && VIDEO_DEV
|
||||
select I2C_ALGOBIT
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEOBUF2_DMA_SG
|
||||
depends on RC_CORE
|
||||
depends on MEDIA_RADIO_SUPPORT
|
||||
select VIDEO_TUNER
|
||||
|
@ -231,7 +231,15 @@
|
||||
|
||||
#define BT848_INT_ETBF (1<<23)
|
||||
|
||||
#define BT848_RISC_VIDEO 1
|
||||
#define BT848_RISC_TOP 2
|
||||
#define BT848_RISC_VBI 4
|
||||
|
||||
#define BT848_INT_RISCS (0xf<<28)
|
||||
#define BT848_INT_RISCS_VIDEO (BT848_RISC_VIDEO << 28)
|
||||
#define BT848_INT_RISCS_TOP (BT848_RISC_TOP << 28)
|
||||
#define BT848_INT_RISCS_VBI (BT848_RISC_VBI << 28)
|
||||
|
||||
#define BT848_INT_RISC_EN (1<<27)
|
||||
#define BT848_INT_RACK (1<<25)
|
||||
#define BT848_INT_FIELD (1<<24)
|
||||
|
@ -293,16 +293,8 @@ void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (!set) {
|
||||
/* Not much to do here */
|
||||
t->audmode = V4L2_TUNER_MODE_LANG1;
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO |
|
||||
V4L2_TUNER_SUB_STEREO |
|
||||
V4L2_TUNER_SUB_LANG1 |
|
||||
V4L2_TUNER_SUB_LANG2;
|
||||
|
||||
if (!set)
|
||||
return;
|
||||
}
|
||||
|
||||
/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
|
||||
switch (t->audmode) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,8 +67,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
/* scan lines */
|
||||
sg = sglist;
|
||||
for (line = 0; line < store_lines; line++) {
|
||||
if ((btv->opt_vcr_hack) &&
|
||||
(line >= (store_lines - VCR_HACK_LINES)))
|
||||
if ((line >= (store_lines - VCR_HACK_LINES)) &&
|
||||
(btv->opt_vcr_hack ||
|
||||
(V4L2_FIELD_HAS_BOTH(btv->field) ||
|
||||
btv->field == V4L2_FIELD_ALTERNATE)))
|
||||
continue;
|
||||
while (offset && offset >= sg_dma_len(sg)) {
|
||||
offset -= sg_dma_len(sg);
|
||||
@ -106,7 +108,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -227,7 +229,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -360,21 +362,75 @@ bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
|
||||
/* ---------------------------------------------------------- */
|
||||
/* risc group / risc main loop / dma management */
|
||||
|
||||
void
|
||||
bttv_set_dma(struct bttv *btv, int override)
|
||||
static void bttv_set_risc_status(struct bttv *btv)
|
||||
{
|
||||
unsigned long cmd;
|
||||
int capctl;
|
||||
unsigned long cmd = BT848_RISC_JUMP;
|
||||
if (btv->loop_irq) {
|
||||
cmd |= BT848_RISC_IRQ;
|
||||
cmd |= (btv->loop_irq & 0x0f) << 16;
|
||||
cmd |= (~btv->loop_irq & 0x0f) << 20;
|
||||
}
|
||||
btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
|
||||
}
|
||||
|
||||
btv->cap_ctl = 0;
|
||||
if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
|
||||
if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
|
||||
if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
|
||||
static void bttv_set_irq_timer(struct bttv *btv)
|
||||
{
|
||||
if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi)
|
||||
mod_timer(&btv->timeout, jiffies + BTTV_TIMEOUT);
|
||||
else
|
||||
del_timer(&btv->timeout);
|
||||
}
|
||||
|
||||
capctl = 0;
|
||||
capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
|
||||
capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
|
||||
capctl |= override;
|
||||
static int bttv_set_capture_control(struct bttv *btv, int start_capture)
|
||||
{
|
||||
int capctl = 0;
|
||||
|
||||
if (btv->curr.top || btv->curr.bottom)
|
||||
capctl = BT848_CAP_CTL_CAPTURE_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_EVEN;
|
||||
|
||||
if (btv->cvbi)
|
||||
capctl |= BT848_CAP_CTL_CAPTURE_VBI_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_VBI_EVEN;
|
||||
|
||||
capctl |= start_capture;
|
||||
|
||||
btaor(capctl, ~0x0f, BT848_CAP_CTL);
|
||||
|
||||
return capctl;
|
||||
}
|
||||
|
||||
static void bttv_start_dma(struct bttv *btv)
|
||||
{
|
||||
if (btv->dma_on)
|
||||
return;
|
||||
btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
|
||||
btor(BT848_GPIO_DMA_CTL_RISC_ENABLE | BT848_GPIO_DMA_CTL_FIFO_ENABLE,
|
||||
BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 1;
|
||||
}
|
||||
|
||||
static void bttv_stop_dma(struct bttv *btv)
|
||||
{
|
||||
if (!btv->dma_on)
|
||||
return;
|
||||
btand(~(BT848_GPIO_DMA_CTL_RISC_ENABLE |
|
||||
BT848_GPIO_DMA_CTL_FIFO_ENABLE), BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 0;
|
||||
}
|
||||
|
||||
void bttv_set_dma(struct bttv *btv, int start_capture)
|
||||
{
|
||||
int capctl = 0;
|
||||
|
||||
bttv_set_risc_status(btv);
|
||||
bttv_set_irq_timer(btv);
|
||||
capctl = bttv_set_capture_control(btv, start_capture);
|
||||
|
||||
if (capctl)
|
||||
bttv_start_dma(btv);
|
||||
else
|
||||
bttv_stop_dma(btv);
|
||||
|
||||
d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
|
||||
btv->c.nr,capctl,btv->loop_irq,
|
||||
@ -382,34 +438,6 @@ bttv_set_dma(struct bttv *btv, int override)
|
||||
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
|
||||
btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
|
||||
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
|
||||
|
||||
cmd = BT848_RISC_JUMP;
|
||||
if (btv->loop_irq) {
|
||||
cmd |= BT848_RISC_IRQ;
|
||||
cmd |= (btv->loop_irq & 0x0f) << 16;
|
||||
cmd |= (~btv->loop_irq & 0x0f) << 20;
|
||||
}
|
||||
if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
|
||||
mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
|
||||
} else {
|
||||
del_timer(&btv->timeout);
|
||||
}
|
||||
btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
|
||||
|
||||
btaor(capctl, ~0x0f, BT848_CAP_CTL);
|
||||
if (capctl) {
|
||||
if (btv->dma_on)
|
||||
return;
|
||||
btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
|
||||
btor(3, BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 1;
|
||||
} else {
|
||||
if (!btv->dma_on)
|
||||
return;
|
||||
btand(~3, BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
@ -478,17 +506,50 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
|
||||
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
|
||||
{
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
int r = 0;
|
||||
unsigned int offset;
|
||||
unsigned int bpl = 2044; /* max. vbipack */
|
||||
unsigned int padding = VBI_BPL - bpl;
|
||||
unsigned int skip_lines0 = 0;
|
||||
unsigned int skip_lines1 = 0;
|
||||
unsigned int min_vdelay = MIN_VDELAY;
|
||||
|
||||
videobuf_waiton(q, &buf->vb, 0, 0);
|
||||
videobuf_dma_unmap(q->dev, dma);
|
||||
videobuf_dma_free(dma);
|
||||
btcx_riscmem_free(btv->c.pci,&buf->bottom);
|
||||
btcx_riscmem_free(btv->c.pci,&buf->top);
|
||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
||||
const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||
struct scatterlist *list = sgt->sgl;
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[0] > 0)
|
||||
skip_lines0 = max(0, (btv->vbi_fmt.fmt.start[0] -
|
||||
tvnorm->vbistart[0]));
|
||||
if (btv->vbi_fmt.fmt.count[1] > 0)
|
||||
skip_lines1 = max(0, (btv->vbi_fmt.fmt.start[1] -
|
||||
tvnorm->vbistart[1]));
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[0] > 0) {
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, padding,
|
||||
skip_lines0, btv->vbi_fmt.fmt.count[0]);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[1] > 0) {
|
||||
offset = btv->vbi_fmt.fmt.count[0] * VBI_BPL;
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, offset, bpl,
|
||||
padding, skip_lines1,
|
||||
btv->vbi_fmt.fmt.count[1]);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (btv->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
|
||||
min_vdelay += btv->vbi_fmt.end - tvnorm->cropcap.bounds.top;
|
||||
|
||||
/* For bttv_buffer_activate_vbi(). */
|
||||
buf->geo.vdelay = min_vdelay;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
@ -508,8 +569,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
if (vbi) {
|
||||
unsigned int crop, vdelay;
|
||||
|
||||
vbi->vb.state = VIDEOBUF_ACTIVE;
|
||||
list_del(&vbi->vb.queue);
|
||||
list_del(&vbi->list);
|
||||
|
||||
/* VDELAY is start of video, end of VBI capturing. */
|
||||
crop = btread(BT848_E_CROP);
|
||||
@ -525,12 +585,12 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
btwrite(crop, BT848_O_CROP);
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[0] > 0) {
|
||||
if (btv->vbi_count[0] > 0) {
|
||||
top = &vbi->top;
|
||||
top_irq_flags = 4;
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[1] > 0) {
|
||||
if (btv->vbi_count[1] > 0) {
|
||||
top_irq_flags = 0;
|
||||
bottom = &vbi->bottom;
|
||||
bottom_irq_flags = 4;
|
||||
@ -550,16 +610,13 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
/* video capture */
|
||||
if (NULL != set->top && NULL != set->bottom) {
|
||||
if (set->top == set->bottom) {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
} else {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->bottom->vb.queue.next)
|
||||
list_del(&set->bottom->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
if (set->bottom->list.next)
|
||||
list_del(&set->bottom->list);
|
||||
}
|
||||
bttv_apply_geo(btv, &set->top->geo, 1);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
||||
@ -572,9 +629,8 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
|
||||
~0x0f, BT848_COLOR_CTL);
|
||||
} else if (NULL != set->top) {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
bttv_apply_geo(btv, &set->top->geo,1);
|
||||
bttv_apply_geo(btv, &set->top->geo,0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
|
||||
@ -583,9 +639,8 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
|
||||
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
|
||||
} else if (NULL != set->bottom) {
|
||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->bottom->vb.queue.next)
|
||||
list_del(&set->bottom->vb.queue);
|
||||
if (set->bottom->list.next)
|
||||
list_del(&set->bottom->list);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,1);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
|
||||
@ -606,156 +661,146 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
int
|
||||
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
|
||||
dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n",
|
||||
btv->c.nr, v4l2_field_names[buf->vb.field],
|
||||
buf->fmt->fourcc, buf->vb.width, buf->vb.height);
|
||||
int r = 0;
|
||||
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||
struct scatterlist *list = sgt->sgl;
|
||||
unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;
|
||||
|
||||
/* packed pixel modes */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
|
||||
int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
|
||||
int bpf = bpl * (buf->vb.height >> 1);
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
|
||||
int bpl = (btv->fmt->depth >> 3) * btv->width;
|
||||
int bpf = bpl * (btv->height >> 1);
|
||||
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
|
||||
V4L2_FIELD_HAS_BOTH(buf->vb.field),
|
||||
tvnorm,&buf->crop);
|
||||
|
||||
switch (buf->vb.field) {
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
switch (buf->vbuf.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
/* offset */ 0,bpl,
|
||||
/* padding */ 0,/* skip_lines */ 0,
|
||||
buf->vb.height);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||
0, btv->height);
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
0,bpl,0,0,buf->vb.height);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
|
||||
0, 0, btv->height);
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
0,bpl,bpl,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
bpl,bpl,bpl,0,buf->vb.height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
|
||||
bpl, 0, btv->height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
|
||||
bpl, bpl, 0, btv->height >> 1);
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
0,bpl,0,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
bpf,bpl,0,0,buf->vb.height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||
0, btv->height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
|
||||
bpl, 0, 0, btv->height >> 1);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* planar modes */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
||||
int uoffset, voffset;
|
||||
int ypadding, cpadding, lines;
|
||||
|
||||
/* calculate chroma offsets */
|
||||
uoffset = buf->vb.width * buf->vb.height;
|
||||
voffset = buf->vb.width * buf->vb.height;
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
|
||||
uoffset = btv->width * btv->height;
|
||||
voffset = btv->width * btv->height;
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
|
||||
/* Y-Cr-Cb plane order */
|
||||
uoffset >>= buf->fmt->hshift;
|
||||
uoffset >>= buf->fmt->vshift;
|
||||
uoffset >>= btv->fmt->hshift;
|
||||
uoffset >>= btv->fmt->vshift;
|
||||
uoffset += voffset;
|
||||
} else {
|
||||
/* Y-Cb-Cr plane order */
|
||||
voffset >>= buf->fmt->hshift;
|
||||
voffset >>= buf->fmt->vshift;
|
||||
voffset >>= btv->fmt->hshift;
|
||||
voffset >>= btv->fmt->vshift;
|
||||
voffset += uoffset;
|
||||
}
|
||||
|
||||
switch (buf->vb.field) {
|
||||
switch (buf->vbuf.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,/* both_fields */ 0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->top, dma->sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
buf->fmt->vshift,0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
0, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, 0, btv->height,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->bottom, dma->sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
buf->fmt->vshift,0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
0, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list, 0,
|
||||
btv->width, 0, btv->height,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
bttv_risc_planar(btv,&buf->top,
|
||||
dma->sglist,
|
||||
0,buf->vb.width,ypadding,lines,
|
||||
uoffset,voffset,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
cpadding);
|
||||
bttv_risc_planar(btv,&buf->bottom,
|
||||
dma->sglist,
|
||||
ypadding,buf->vb.width,ypadding,lines,
|
||||
uoffset+cpadding,
|
||||
voffset+cpadding,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
cpadding);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
1, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
lines = btv->height >> 1;
|
||||
ypadding = btv->width;
|
||||
cpadding = btv->width >> btv->fmt->hshift;
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, ypadding, lines,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, cpadding);
|
||||
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||
ypadding, btv->width, ypadding,
|
||||
lines, uoffset + cpadding,
|
||||
voffset + cpadding,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, cpadding);
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
bttv_risc_planar(btv,&buf->top,
|
||||
dma->sglist,
|
||||
0,buf->vb.width,0,lines,
|
||||
uoffset >> 1,
|
||||
voffset >> 1,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
0);
|
||||
bttv_risc_planar(btv,&buf->bottom,
|
||||
dma->sglist,
|
||||
lines * ypadding,buf->vb.width,0,lines,
|
||||
lines * ypadding + (uoffset >> 1),
|
||||
lines * ypadding + (voffset >> 1),
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
1, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
lines = btv->height >> 1;
|
||||
ypadding = btv->width;
|
||||
cpadding = btv->width >> btv->fmt->hshift;
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, 0, lines,
|
||||
uoffset >> 1, voffset >> 1,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||
lines * ypadding,
|
||||
btv->width, 0, lines,
|
||||
lines * ypadding + (uoffset >> 1),
|
||||
lines * ypadding + (voffset >> 1),
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* raw data */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
|
||||
/* build risc code */
|
||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
||||
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
|
||||
1,tvnorm,&buf->crop);
|
||||
bttv_risc_packed(btv, &buf->top, dma->sglist,
|
||||
/* offset */ 0, RAW_BPL, /* padding */ 0,
|
||||
/* skip_lines */ 0, RAW_LINES);
|
||||
bttv_risc_packed(btv, &buf->bottom, dma->sglist,
|
||||
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
|
||||
buf->vbuf.field = V4L2_FIELD_SEQ_TB;
|
||||
bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
|
||||
1, tvnorm, &btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
|
||||
RAW_LINES);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
|
||||
RAW_BPL, 0, 0, RAW_LINES);
|
||||
}
|
||||
|
||||
/* copy format info */
|
||||
buf->btformat = buf->fmt->btformat;
|
||||
buf->btswap = buf->fmt->btswap;
|
||||
return 0;
|
||||
buf->btformat = btv->fmt->btformat;
|
||||
buf->btswap = btv->fmt->btswap;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -34,16 +34,6 @@
|
||||
to be about 244. */
|
||||
#define VBI_OFFSET 244
|
||||
|
||||
/* 2048 for compatibility with earlier driver versions. The driver
|
||||
really stores 1024 + tvnorm->vbipack * 4 samples per line in the
|
||||
buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
|
||||
is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
|
||||
four bytes of the VBI image. */
|
||||
#define VBI_BPL 2048
|
||||
|
||||
/* Compatibility. */
|
||||
#define VBI_DEFLINES 16
|
||||
|
||||
static unsigned int vbibufs = 4;
|
||||
static unsigned int vbi_debug;
|
||||
|
||||
@ -67,165 +57,123 @@ do { \
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* vbi risc code + mm */
|
||||
|
||||
static int vbi_buffer_setup(struct videobuf_queue *q,
|
||||
unsigned int *count, unsigned int *size)
|
||||
static int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
|
||||
unsigned int *num_planes, unsigned int sizes[],
|
||||
struct device *alloc_devs[])
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
|
||||
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
|
||||
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
|
||||
dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
|
||||
fh->vbi_fmt.fmt.samples_per_line,
|
||||
fh->vbi_fmt.fmt.start[0],
|
||||
fh->vbi_fmt.fmt.start[1],
|
||||
fh->vbi_fmt.fmt.count[0],
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
if (*num_planes)
|
||||
return sizes[0] < size ? -EINVAL : 0;
|
||||
*num_planes = 1;
|
||||
sizes[0] = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vbi_buffer_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
static void buf_queue_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
unsigned int skip_lines0, skip_lines1, min_vdelay;
|
||||
int redo_dma_risc;
|
||||
int rc;
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
unsigned long flags;
|
||||
|
||||
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
||||
spin_lock_irqsave(&btv->s_lock, flags);
|
||||
if (list_empty(&btv->vcapture)) {
|
||||
btv->loop_irq = BT848_RISC_VBI;
|
||||
if (vb2_is_streaming(&btv->capq))
|
||||
btv->loop_irq |= BT848_RISC_VIDEO;
|
||||
bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_VBI_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_VBI_EVEN);
|
||||
}
|
||||
list_add_tail(&buf->list, &btv->vcapture);
|
||||
spin_unlock_irqrestore(&btv->s_lock, flags);
|
||||
}
|
||||
|
||||
static int buf_prepare_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size)
|
||||
return -EINVAL;
|
||||
vb2_set_plane_payload(vb, 0, size);
|
||||
buf->vbuf.field = V4L2_FIELD_NONE;
|
||||
ret = bttv_buffer_risc_vbi(btv, buf);
|
||||
|
||||
tvnorm = fh->vbi_fmt.tvnorm;
|
||||
|
||||
/* There's no VBI_VDELAY register, RISC must skip the lines
|
||||
we don't want. With default parameters we skip zero lines
|
||||
as earlier driver versions did. The driver permits video
|
||||
standard changes while capturing, so we use vbi_fmt.tvnorm
|
||||
instead of btv->tvnorm to skip zero lines after video
|
||||
standard changes as well. */
|
||||
|
||||
skip_lines0 = 0;
|
||||
skip_lines1 = 0;
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0)
|
||||
skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
|
||||
- tvnorm->vbistart[0]));
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0)
|
||||
skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
|
||||
- tvnorm->vbistart[1]));
|
||||
|
||||
redo_dma_risc = 0;
|
||||
|
||||
if (buf->vbi_skip[0] != skip_lines0 ||
|
||||
buf->vbi_skip[1] != skip_lines1 ||
|
||||
buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
|
||||
buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
|
||||
buf->vbi_skip[0] = skip_lines0;
|
||||
buf->vbi_skip[1] = skip_lines1;
|
||||
buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
|
||||
buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
|
||||
redo_dma_risc = 1;
|
||||
}
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
redo_dma_risc = 1;
|
||||
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (redo_dma_risc) {
|
||||
unsigned int bpl, padding, offset;
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
|
||||
bpl = 2044; /* max. vbipack */
|
||||
padding = VBI_BPL - bpl;
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0) {
|
||||
rc = bttv_risc_packed(btv, &buf->top,
|
||||
dma->sglist,
|
||||
/* offset */ 0, bpl,
|
||||
padding, skip_lines0,
|
||||
fh->vbi_fmt.fmt.count[0]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0) {
|
||||
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
|
||||
|
||||
rc = bttv_risc_packed(btv, &buf->bottom,
|
||||
dma->sglist,
|
||||
offset, bpl,
|
||||
padding, skip_lines1,
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* VBI capturing ends at VDELAY, start of video capturing,
|
||||
no matter where the RISC program ends. VDELAY minimum is 2,
|
||||
bounds.top is the corresponding first field line number
|
||||
times two. VDELAY counts half field lines. */
|
||||
min_vdelay = MIN_VDELAY;
|
||||
if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
|
||||
min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
|
||||
|
||||
/* For bttv_buffer_activate_vbi(). */
|
||||
buf->geo.vdelay = min_vdelay;
|
||||
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
buf->vb.field = field;
|
||||
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
|
||||
vb, &buf->top, &buf->bottom,
|
||||
v4l2_field_names[buf->vb.field]);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bttv_dma_free(q,btv,buf);
|
||||
return rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
static void buf_cleanup_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
|
||||
dprintk("queue %p\n",vb);
|
||||
buf->vb.state = VIDEOBUF_QUEUED;
|
||||
list_add_tail(&buf->vb.queue,&btv->vcapture);
|
||||
if (NULL == btv->cvbi) {
|
||||
fh->btv->loop_irq |= 4;
|
||||
bttv_set_dma(btv,0x0c);
|
||||
}
|
||||
btcx_riscmem_free(btv->c.pci, &buf->top);
|
||||
btcx_riscmem_free(btv->c.pci, &buf->bottom);
|
||||
}
|
||||
|
||||
static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
int ret;
|
||||
int seqnr = 0;
|
||||
struct bttv_buffer *buf;
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
|
||||
dprintk("free %p\n",vb);
|
||||
bttv_dma_free(q,fh->btv,buf);
|
||||
btv->framedrop = 0;
|
||||
ret = check_alloc_btres_lock(btv, RESOURCE_VBI);
|
||||
if (ret == 0) {
|
||||
if (btv->field_count)
|
||||
seqnr++;
|
||||
while (!list_empty(&btv->vcapture)) {
|
||||
buf = list_entry(btv->vcapture.next,
|
||||
struct bttv_buffer, list);
|
||||
list_del(&buf->list);
|
||||
buf->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
|
||||
vb2_buffer_done(&buf->vbuf.vb2_buf,
|
||||
VB2_BUF_STATE_QUEUED);
|
||||
}
|
||||
return !ret;
|
||||
}
|
||||
if (!vb2_is_streaming(&btv->capq)) {
|
||||
init_irqreg(btv);
|
||||
btv->field_count = 0;
|
||||
}
|
||||
return !ret;
|
||||
}
|
||||
|
||||
const struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
.buf_setup = vbi_buffer_setup,
|
||||
.buf_prepare = vbi_buffer_prepare,
|
||||
.buf_queue = vbi_buffer_queue,
|
||||
.buf_release = vbi_buffer_release,
|
||||
static void stop_streaming_vbi(struct vb2_queue *q)
|
||||
{
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
unsigned long flags;
|
||||
|
||||
vb2_wait_for_all_buffers(q);
|
||||
spin_lock_irqsave(&btv->s_lock, flags);
|
||||
free_btres_lock(btv, RESOURCE_VBI);
|
||||
if (!vb2_is_streaming(&btv->capq)) {
|
||||
/* stop field counter */
|
||||
btand(~BT848_INT_VSYNC, BT848_INT_MASK);
|
||||
}
|
||||
spin_unlock_irqrestore(&btv->s_lock, flags);
|
||||
}
|
||||
|
||||
const struct vb2_ops bttv_vbi_qops = {
|
||||
.queue_setup = queue_setup_vbi,
|
||||
.buf_queue = buf_queue_vbi,
|
||||
.buf_prepare = buf_prepare_vbi,
|
||||
.buf_cleanup = buf_cleanup_vbi,
|
||||
.start_streaming = start_streaming_vbi,
|
||||
.stop_streaming = stop_streaming_vbi,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@ -250,7 +198,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
|
||||
if (min_start > max_start)
|
||||
return -EBUSY;
|
||||
|
||||
BUG_ON(max_start >= max_end);
|
||||
WARN_ON(max_start >= max_end);
|
||||
|
||||
f->sampling_rate = tvnorm->Fsc;
|
||||
f->samples_per_line = VBI_BPL;
|
||||
@ -299,8 +247,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
|
||||
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 crop_start;
|
||||
|
||||
@ -317,8 +264,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 start1, end;
|
||||
int rc;
|
||||
@ -326,7 +272,7 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
mutex_lock(&btv->lock);
|
||||
|
||||
rc = -EBUSY;
|
||||
if (fh->resources & RESOURCE_VBI)
|
||||
if (btv->resources & RESOURCE_VBI)
|
||||
goto fail;
|
||||
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
@ -346,13 +292,9 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
because vbi_fmt.end counts field lines times two. */
|
||||
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
|
||||
|
||||
mutex_lock(&fh->vbi.vb_lock);
|
||||
|
||||
fh->vbi_fmt.fmt = frt->fmt.vbi;
|
||||
fh->vbi_fmt.tvnorm = tvnorm;
|
||||
fh->vbi_fmt.end = end;
|
||||
|
||||
mutex_unlock(&fh->vbi.vb_lock);
|
||||
btv->vbi_fmt.fmt = frt->fmt.vbi;
|
||||
btv->vbi_fmt.tvnorm = tvnorm;
|
||||
btv->vbi_fmt.end = end;
|
||||
|
||||
rc = 0;
|
||||
|
||||
@ -365,14 +307,14 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
|
||||
frt->fmt.vbi = fh->vbi_fmt.fmt;
|
||||
frt->fmt.vbi = btv->vbi_fmt.fmt;
|
||||
|
||||
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
|
||||
if (tvnorm != fh->vbi_fmt.tvnorm) {
|
||||
if (tvnorm != btv->vbi_fmt.tvnorm) {
|
||||
__s32 max_end;
|
||||
unsigned int i;
|
||||
|
||||
@ -388,9 +330,8 @@ int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
for (i = 0; i < 2; ++i) {
|
||||
__s32 new_start;
|
||||
|
||||
new_start = frt->fmt.vbi.start[i]
|
||||
+ tvnorm->vbistart[i]
|
||||
- fh->vbi_fmt.tvnorm->vbistart[i];
|
||||
new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i]
|
||||
- btv->vbi_fmt.tvnorm->vbistart[i];
|
||||
|
||||
frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
|
||||
frt->fmt.vbi.count[i] =
|
||||
@ -430,8 +371,8 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
|
||||
real_count = ((tvnorm->cropcap.defrect.top >> 1)
|
||||
- tvnorm->vbistart[0]);
|
||||
|
||||
BUG_ON(real_samples_per_line > VBI_BPL);
|
||||
BUG_ON(real_count > VBI_DEFLINES);
|
||||
WARN_ON(real_samples_per_line > VBI_BPL);
|
||||
WARN_ON(real_count > VBI_DEFLINES);
|
||||
|
||||
f->tvnorm = tvnorm;
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/rc-core.h>
|
||||
#include <media/i2c/ir-kbd-i2c.h>
|
||||
@ -142,19 +142,15 @@ struct bttv_geometry {
|
||||
|
||||
struct bttv_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
struct vb2_v4l2_buffer vbuf;
|
||||
struct list_head list;
|
||||
|
||||
/* bttv specific */
|
||||
const struct bttv_format *fmt;
|
||||
unsigned int tvnorm;
|
||||
int btformat;
|
||||
int btswap;
|
||||
struct bttv_geometry geo;
|
||||
struct btcx_riscmem top;
|
||||
struct btcx_riscmem bottom;
|
||||
struct v4l2_rect crop;
|
||||
unsigned int vbi_skip[2];
|
||||
unsigned int vbi_count[2];
|
||||
};
|
||||
|
||||
struct bttv_buffer_set {
|
||||
@ -176,6 +172,8 @@ struct bttv_vbi_fmt {
|
||||
};
|
||||
|
||||
/* bttv-vbi.c */
|
||||
extern const struct vb2_ops bttv_vbi_qops;
|
||||
|
||||
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
|
||||
|
||||
struct bttv_crop {
|
||||
@ -192,31 +190,6 @@ struct bttv_crop {
|
||||
__s32 max_scaled_height;
|
||||
};
|
||||
|
||||
struct bttv_fh {
|
||||
/* This must be the first field in this struct */
|
||||
struct v4l2_fh fh;
|
||||
|
||||
struct bttv *btv;
|
||||
int resources;
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
/* video capture */
|
||||
struct videobuf_queue cap;
|
||||
const struct bttv_format *fmt;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* Application called VIDIOC_S_SELECTION. */
|
||||
int do_crop;
|
||||
|
||||
/* vbi capture */
|
||||
struct videobuf_queue vbi;
|
||||
/* Current VBI capture window as seen through this fh (cannot
|
||||
be global for compatibility with earlier drivers). Protected
|
||||
by struct bttv.lock and struct bttv_fh.vbi.lock. */
|
||||
struct bttv_vbi_fmt vbi_fmt;
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-risc.c */
|
||||
|
||||
@ -237,20 +210,27 @@ int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
|
||||
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
|
||||
int bttv_buffer_activate_video(struct bttv *btv,
|
||||
struct bttv_buffer_set *set);
|
||||
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf);
|
||||
int bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
struct bttv_buffer *vbi);
|
||||
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
|
||||
struct bttv_buffer *buf);
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-vbi.c */
|
||||
|
||||
/*
|
||||
* 2048 for compatibility with earlier driver versions. The driver really
|
||||
* stores 1024 + tvnorm->vbipack * 4 samples per line in the buffer. Note
|
||||
* tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI is 0x1FF DWORDs) and
|
||||
* VBI read()s store a frame counter in the last four bytes of the VBI image.
|
||||
*/
|
||||
#define VBI_BPL 2048
|
||||
|
||||
#define VBI_DEFLINES 16
|
||||
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
|
||||
extern const struct videobuf_queue_ops bttv_vbi_qops;
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-gpio.c */
|
||||
|
||||
@ -275,6 +255,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
|
||||
extern unsigned int bttv_verbose;
|
||||
extern unsigned int bttv_debug;
|
||||
extern unsigned int bttv_gpio;
|
||||
int check_alloc_btres_lock(struct bttv *btv, int bit);
|
||||
void free_btres_lock(struct bttv *btv, int bits);
|
||||
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
|
||||
|
||||
#define dprintk(fmt, ...) \
|
||||
@ -396,7 +378,7 @@ struct bttv {
|
||||
v4l2_std_id std;
|
||||
int hue, contrast, bright, saturation;
|
||||
struct v4l2_framebuffer fbuf;
|
||||
unsigned int field_count;
|
||||
__u32 field_count;
|
||||
|
||||
/* various options */
|
||||
int opt_combfilter;
|
||||
@ -436,7 +418,6 @@ struct bttv {
|
||||
int loop_irq;
|
||||
int new_input;
|
||||
|
||||
unsigned long cap_ctl;
|
||||
unsigned long dma_on;
|
||||
struct timer_list timeout;
|
||||
struct bttv_suspend_state state;
|
||||
@ -448,7 +429,25 @@ struct bttv {
|
||||
unsigned int irq_me;
|
||||
|
||||
unsigned int users;
|
||||
struct bttv_fh init;
|
||||
struct v4l2_fh fh;
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
enum v4l2_field field;
|
||||
int field_last;
|
||||
|
||||
/* video capture */
|
||||
struct vb2_queue capq;
|
||||
const struct bttv_format *fmt;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* vbi capture */
|
||||
struct vb2_queue vbiq;
|
||||
struct bttv_vbi_fmt vbi_fmt;
|
||||
unsigned int vbi_count[2];
|
||||
|
||||
/* Application called VIDIOC_S_SELECTION. */
|
||||
int do_crop;
|
||||
|
||||
/* used to make dvb-bt8xx autoloadable */
|
||||
struct work_struct request_module_wk;
|
||||
@ -487,6 +486,8 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
|
||||
|
||||
#endif
|
||||
|
||||
void init_irqreg(struct bttv *btv);
|
||||
|
||||
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
|
||||
#define btread(adr) readl(btv->bt848_mmio+(adr))
|
||||
|
||||
|
@ -307,7 +307,7 @@ int cx18_gpio_register(struct cx18 *cx, u32 hw)
|
||||
|
||||
void cx18_reset_ir_gpio(void *data)
|
||||
{
|
||||
struct cx18 *cx = to_cx18((struct v4l2_device *)data);
|
||||
struct cx18 *cx = to_cx18(data);
|
||||
|
||||
if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
|
||||
return;
|
||||
|
@ -30,7 +30,7 @@ static void epu_cmd(struct cx18 *cx, u32 sw1)
|
||||
|
||||
irqreturn_t cx18_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct cx18 *cx = (struct cx18 *)dev_id;
|
||||
struct cx18 *cx = dev_id;
|
||||
u32 sw1, sw2, hw2;
|
||||
|
||||
sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask;
|
||||
|
@ -554,14 +554,14 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
risc = cx_read(ch->cmds_start + 4 * (i + 14));
|
||||
pr_warn("%s: risc%d: ", dev->name, i);
|
||||
pr_warn("%s: risc%d:", dev->name, i);
|
||||
cx23885_risc_decode(risc);
|
||||
}
|
||||
for (i = 0; i < (64 >> 2); i += n) {
|
||||
risc = cx_read(ch->ctrl_start + 4 * i);
|
||||
/* No consideration for bits 63-32 */
|
||||
|
||||
pr_warn("%s: (0x%08x) iq %x: ", dev->name,
|
||||
pr_warn("%s: (0x%08x) iq %x:", dev->name,
|
||||
ch->ctrl_start + 4 * i, i);
|
||||
n = cx23885_risc_decode(risc);
|
||||
for (j = 1; j < n; j++) {
|
||||
@ -594,7 +594,7 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
|
||||
pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
|
||||
dev->name, risc->cpu, (unsigned long)risc->dma);
|
||||
for (i = 0; i < (risc->size >> 2); i += n) {
|
||||
pr_info("%s: %04d: ", dev->name, i);
|
||||
pr_info("%s: %04d:", dev->name, i);
|
||||
n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
|
||||
for (j = 1; j < n; j++)
|
||||
pr_info("%s: %04d: 0x%08x [ arg #%d ]\n",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user