mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 08:03:01 +09:00
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:
@@ -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.
|
Camera sensor using V4L2 subdev interface in the kernel is supported.
|
||||||
|
|
||||||
The driver is implemented using as a reference the Qualcomm Camera Subsystem
|
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
|
Qualcomm Camera Subsystem hardware
|
||||||
@@ -181,5 +181,5 @@ Referenced 2018-06-22.
|
|||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
|
|
||||||
.. [#f1] https://source.codeaurora.org/quic/la/kernel/msm-3.10/
|
.. [#f1] https://git.codelinaro.org/clo/la/kernel/msm-3.10/
|
||||||
.. [#f2] https://source.codeaurora.org/quic/la/kernel/msm-3.18/
|
.. [#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#
|
$ref: ../mailbox/fsl,mu.yaml#
|
||||||
|
|
||||||
|
|
||||||
"^vpu_core@[0-9a-f]+$":
|
"^vpu-core@[0-9a-f]+$":
|
||||||
description:
|
description:
|
||||||
Each core correspond a decoder or encoder, need to configure them
|
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
|
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>;
|
power-domains = <&pd IMX_SC_R_VPU_MU_2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
vpu_core0: vpu_core@2d080000 {
|
vpu_core0: vpu-core@2d080000 {
|
||||||
compatible = "nxp,imx8q-vpu-decoder";
|
compatible = "nxp,imx8q-vpu-decoder";
|
||||||
reg = <0x2d080000 0x10000>;
|
reg = <0x2d080000 0x10000>;
|
||||||
power-domains = <&pd IMX_SC_R_VPU_DEC_0>;
|
power-domains = <&pd IMX_SC_R_VPU_DEC_0>;
|
||||||
@@ -154,7 +154,7 @@ examples:
|
|||||||
memory-region = <&decoder_boot>, <&decoder_rpc>;
|
memory-region = <&decoder_boot>, <&decoder_rpc>;
|
||||||
};
|
};
|
||||||
|
|
||||||
vpu_core1: vpu_core@2d090000 {
|
vpu_core1: vpu-core@2d090000 {
|
||||||
compatible = "nxp,imx8q-vpu-encoder";
|
compatible = "nxp,imx8q-vpu-encoder";
|
||||||
reg = <0x2d090000 0x10000>;
|
reg = <0x2d090000 0x10000>;
|
||||||
power-domains = <&pd IMX_SC_R_VPU_ENC_0>;
|
power-domains = <&pd IMX_SC_R_VPU_ENC_0>;
|
||||||
@@ -165,7 +165,7 @@ examples:
|
|||||||
memory-region = <&encoder1_boot>, <&encoder1_rpc>;
|
memory-region = <&encoder1_boot>, <&encoder1_rpc>;
|
||||||
};
|
};
|
||||||
|
|
||||||
vpu_core2: vpu_core@2d0a0000 {
|
vpu_core2: vpu-core@2d0a0000 {
|
||||||
reg = <0x2d0a0000 0x10000>;
|
reg = <0x2d0a0000 0x10000>;
|
||||||
compatible = "nxp,imx8q-vpu-encoder";
|
compatible = "nxp,imx8q-vpu-encoder";
|
||||||
power-domains = <&pd IMX_SC_R_VPU_ENC_1>;
|
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>;
|
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
clocks = <&tegra_car TEGRA124_CLK_CEC>;
|
clocks = <&tegra_car TEGRA124_CLK_CEC>;
|
||||||
clock-names = "cec";
|
clock-names = "cec";
|
||||||
status = "disabled";
|
|
||||||
hdmi-phandle = <&hdmi>;
|
hdmi-phandle = <&hdmi>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -143,7 +143,6 @@ examples:
|
|||||||
mipid02: csi2rx@14 {
|
mipid02: csi2rx@14 {
|
||||||
compatible = "st,st-mipid02";
|
compatible = "st,st-mipid02";
|
||||||
reg = <0x14>;
|
reg = <0x14>;
|
||||||
status = "okay";
|
|
||||||
clocks = <&clk_ext_camera_12>;
|
clocks = <&clk_ext_camera_12>;
|
||||||
clock-names = "xclk";
|
clock-names = "xclk";
|
||||||
VDDE-supply = <&vdd>;
|
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
|
- mediatek,mt8183-vcodec-dec
|
||||||
|
|
||||||
reg:
|
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:
|
interrupts:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
|
minItems: 1
|
||||||
maxItems: 8
|
maxItems: 8
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
items:
|
minItems: 1
|
||||||
- const: vcodecpll
|
maxItems: 8
|
||||||
- const: univpll_d2
|
|
||||||
- const: clk_cci400_sel
|
|
||||||
- const: vdec_sel
|
|
||||||
- const: vdecpll
|
|
||||||
- const: vencpll
|
|
||||||
- const: venc_lt_sel
|
|
||||||
- const: vdec_bus_clk_src
|
|
||||||
|
|
||||||
assigned-clocks: true
|
assigned-clocks: true
|
||||||
|
|
||||||
@@ -66,6 +75,10 @@ properties:
|
|||||||
description:
|
description:
|
||||||
Describes point to scp.
|
Describes point to scp.
|
||||||
|
|
||||||
|
mediatek,vdecsys:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: Phandle to the vdecsys syscon node.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
@@ -73,8 +86,7 @@ required:
|
|||||||
- clocks
|
- clocks
|
||||||
- clock-names
|
- clock-names
|
||||||
- iommus
|
- iommus
|
||||||
- assigned-clocks
|
- mediatek,vdecsys
|
||||||
- assigned-clock-parents
|
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- if:
|
- if:
|
||||||
@@ -88,6 +100,15 @@ allOf:
|
|||||||
required:
|
required:
|
||||||
- mediatek,scp
|
- mediatek,scp
|
||||||
|
|
||||||
|
properties:
|
||||||
|
clocks:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: vdec
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
@@ -99,6 +120,22 @@ allOf:
|
|||||||
required:
|
required:
|
||||||
- mediatek,vpu
|
- 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
|
additionalProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
@@ -109,10 +146,9 @@ examples:
|
|||||||
#include <dt-bindings/interrupt-controller/irq.h>
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
#include <dt-bindings/power/mt8173-power.h>
|
#include <dt-bindings/power/mt8173-power.h>
|
||||||
|
|
||||||
vcodec_dec: vcodec@16000000 {
|
vcodec_dec: vcodec@16020000 {
|
||||||
compatible = "mediatek,mt8173-vcodec-dec";
|
compatible = "mediatek,mt8173-vcodec-dec";
|
||||||
reg = <0x16000000 0x100>, /*VDEC_SYS*/
|
reg = <0x16020000 0x1000>, /*VDEC_MISC*/
|
||||||
<0x16020000 0x1000>, /*VDEC_MISC*/
|
|
||||||
<0x16021000 0x800>, /*VDEC_LD*/
|
<0x16021000 0x800>, /*VDEC_LD*/
|
||||||
<0x16021800 0x800>, /*VDEC_TOP*/
|
<0x16021800 0x800>, /*VDEC_TOP*/
|
||||||
<0x16022000 0x1000>, /*VDEC_CM*/
|
<0x16022000 0x1000>, /*VDEC_CM*/
|
||||||
@@ -133,6 +169,7 @@ examples:
|
|||||||
<&iommu M4U_PORT_HW_VDEC_VLD_EXT>,
|
<&iommu M4U_PORT_HW_VDEC_VLD_EXT>,
|
||||||
<&iommu M4U_PORT_HW_VDEC_VLD2_EXT>;
|
<&iommu M4U_PORT_HW_VDEC_VLD2_EXT>;
|
||||||
mediatek,vpu = <&vpu>;
|
mediatek,vpu = <&vpu>;
|
||||||
|
mediatek,vdecsys = <&vdecsys>;
|
||||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
|
power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
|
||||||
clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>,
|
clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>,
|
||||||
<&topckgen CLK_TOP_UNIVPLL_D2>,
|
<&topckgen CLK_TOP_UNIVPLL_D2>,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ properties:
|
|||||||
enum:
|
enum:
|
||||||
- fsl,imx8mn-isi
|
- fsl,imx8mn-isi
|
||||||
- fsl,imx8mp-isi
|
- fsl,imx8mp-isi
|
||||||
|
- fsl,imx93-isi
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
@@ -72,7 +73,9 @@ allOf:
|
|||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
const: fsl,imx8mn-isi
|
enum:
|
||||||
|
- fsl,imx8mn-isi
|
||||||
|
- fsl,imx93-isi
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
interrupts:
|
interrupts:
|
||||||
|
|||||||
@@ -109,9 +109,11 @@ your driver:
|
|||||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||||
int (*adap_monitor_pin_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);
|
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,
|
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||||
u32 signal_free_time, struct cec_msg *msg);
|
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_status)(struct cec_adapter *adap, struct seq_file *file);
|
||||||
void (*adap_free)(struct cec_adapter *adap);
|
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
|
These low-level ops deal with various aspects of controlling the CEC adapter
|
||||||
hardware:
|
hardware. They are all called with the mutex adap->lock held.
|
||||||
|
|
||||||
|
|
||||||
To enable/disable the hardware::
|
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.
|
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
|
The adapter is unconfigured. If the driver has to take specific actions after
|
||||||
addresses have been successfully claimed. If configured == false, then the
|
unconfiguration, then that can be done through this optional callback.
|
||||||
adapter is unconfigured. If the driver has to take specific actions after
|
|
||||||
(un)configuration, then that can be done through this optional callback.
|
|
||||||
|
|
||||||
|
|
||||||
To transmit a new message::
|
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).
|
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::
|
To log the current CEC hardware status::
|
||||||
|
|
||||||
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
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
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
@@ -384,9 +398,19 @@ CEC protocol driven. The following high-level callbacks are available:
|
|||||||
...
|
...
|
||||||
|
|
||||||
/* High-level CEC message callback */
|
/* High-level CEC message callback */
|
||||||
|
void (*configured)(struct cec_adapter *adap);
|
||||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
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
|
The received() callback allows the driver to optionally handle a newly
|
||||||
received CEC message::
|
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-mem2mem
|
||||||
v4l2-async
|
v4l2-async
|
||||||
v4l2-fwnode
|
v4l2-fwnode
|
||||||
|
v4l2-cci
|
||||||
v4l2-rect
|
v4l2-rect
|
||||||
v4l2-tuner
|
v4l2-tuner
|
||||||
v4l2-common
|
v4l2-common
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ below.
|
|||||||
Using one or the other registration method only affects the probing process, the
|
Using one or the other registration method only affects the probing process, the
|
||||||
run-time bridge-subdevice interaction is in both cases the same.
|
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
|
In the **synchronous** case a device (bridge) driver needs to register the
|
||||||
:c:type:`v4l2_subdev` with the v4l2_device:
|
: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:func:`v4l2_device_unregister_subdev <v4l2_device_unregister_subdev>`
|
||||||
(:c:type:`sd <v4l2_subdev>`).
|
(:c:type:`sd <v4l2_subdev>`).
|
||||||
|
|
||||||
|
|
||||||
Afterwards the subdev module can be unloaded and
|
Afterwards the subdev module can be unloaded and
|
||||||
:c:type:`sd <v4l2_subdev>`->dev == ``NULL``.
|
:c:type:`sd <v4l2_subdev>`->dev == ``NULL``.
|
||||||
|
|
||||||
|
Registering asynchronous sub-devices
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
In the **asynchronous** case subdevice probing can be invoked independently of
|
In the **asynchronous** case subdevice probing can be invoked independently of
|
||||||
the bridge driver availability. The subdevice driver then has to verify whether
|
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
|
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
|
registered this way are stored in a global list of subdevices, ready to be
|
||||||
picked up by bridge drivers.
|
picked up by bridge drivers.
|
||||||
|
|
||||||
Bridge drivers in turn have to register a notifier object. This is
|
Asynchronous sub-device notifiers
|
||||||
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
|
Bridge drivers in turn have to register a notifier object. This is performed
|
||||||
takes two arguments: a pointer to struct :c:type:`v4l2_device` and a
|
using the :c:func:`v4l2_async_nf_register` call. To unregister the notifier the
|
||||||
pointer to struct :c:type:`v4l2_async_notifier`.
|
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
|
Before registering the notifier, bridge drivers must do two things: first, the
|
||||||
notifier must be initialized using the :c:func:`v4l2_async_nf_init`.
|
notifier must be initialized using the :c:func:`v4l2_async_nf_init`. Second,
|
||||||
Second, bridge drivers can then begin to form a list of subdevice descriptors
|
bridge drivers can then begin to form a list of async connection descriptors
|
||||||
that the bridge device needs for its operation. Several functions are available
|
that the bridge device needs for its
|
||||||
to add subdevice descriptors to a notifier, depending on the type of device and
|
operation. :c:func:`v4l2_async_nf_add_fwnode`,
|
||||||
the needs of the driver.
|
: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
|
Async connection descriptors describe connections to external sub-devices the
|
||||||
:c:func:`v4l2_async_nf_add_i2c` are for bridge and ISP drivers for
|
drivers for which are not yet probed. Based on an async connection, a media data
|
||||||
registering their async sub-devices with the notifier.
|
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
|
Asynchronous sub-device notifier for sub-devices
|
||||||
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.
|
|
||||||
|
|
||||||
These functions allocate an async sub-device descriptor which is of type struct
|
A driver that registers an asynchronous sub-device may also register an
|
||||||
:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
|
asynchronous notifier. This is called an asynchronous sub-device notifier andthe
|
||||||
:c:type:`v4l2_async_subdev` shall be the first member of this struct:
|
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
|
.. code-block:: c
|
||||||
|
|
||||||
struct my_async_subdev {
|
struct my_async_connection {
|
||||||
struct v4l2_async_subdev asd;
|
struct v4l2_async_connection asc;
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
struct my_async_subdev *my_asd;
|
struct my_async_connection *my_asc;
|
||||||
struct fwnode_handle *ep;
|
struct fwnode_handle *ep;
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
my_asd = v4l2_async_nf_add_fwnode_remote(¬ifier, ep,
|
my_asc = v4l2_async_nf_add_fwnode_remote(¬ifier, ep,
|
||||||
struct my_async_subdev);
|
struct my_async_connection);
|
||||||
fwnode_handle_put(ep);
|
fwnode_handle_put(ep);
|
||||||
|
|
||||||
if (IS_ERR(asd))
|
if (IS_ERR(my_asc))
|
||||||
return PTR_ERR(asd);
|
return PTR_ERR(my_asc);
|
||||||
|
|
||||||
The V4L2 core will then use these descriptors to match asynchronously
|
Asynchronous sub-device notifier callbacks
|
||||||
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
|
The V4L2 core will then use these connection descriptors to match asynchronously
|
||||||
system the .unbind() method is called. All three callbacks are optional.
|
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
|
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()``
|
handling when the structure is freed, drivers must implement the ``.destroy()``
|
||||||
notifier callback. The framework will call it right before freeing the
|
notifier callback. The framework will call it right before freeing the
|
||||||
:c:type:`v4l2_async_subdev`.
|
:c:type:`v4l2_async_connection`.
|
||||||
|
|
||||||
Calling subdev operations
|
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
|
i2c-topology
|
||||||
muxes/i2c-mux-gpio
|
muxes/i2c-mux-gpio
|
||||||
i2c-sysfs
|
i2c-sysfs
|
||||||
|
i2c-address-translators
|
||||||
|
|
||||||
Writing device drivers
|
Writing device drivers
|
||||||
======================
|
======================
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``sizeimage``
|
``sizeimage``
|
||||||
adjusted size of ``OUTPUT`` buffers.
|
adjusted size of ``OUTPUT`` buffers.
|
||||||
@@ -311,7 +311,7 @@ Initialization
|
|||||||
``memory``
|
``memory``
|
||||||
follows standard semantics.
|
follows standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
the actual number of buffers allocated.
|
the actual number of buffers allocated.
|
||||||
@@ -339,7 +339,7 @@ Initialization
|
|||||||
``format``
|
``format``
|
||||||
follows standard semantics.
|
follows standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
adjusted to the number of allocated buffers.
|
adjusted to the number of allocated buffers.
|
||||||
@@ -410,7 +410,7 @@ Capture Setup
|
|||||||
``type``
|
``type``
|
||||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``width``, ``height``
|
``width``, ``height``
|
||||||
frame buffer resolution for the decoded frames.
|
frame buffer resolution for the decoded frames.
|
||||||
@@ -443,7 +443,7 @@ Capture Setup
|
|||||||
``target``
|
``target``
|
||||||
set to ``V4L2_SEL_TGT_COMPOSE``.
|
set to ``V4L2_SEL_TGT_COMPOSE``.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||||
the visible rectangle; it must fit within the frame buffer resolution
|
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``;
|
frame is written; defaults to ``V4L2_SEL_TGT_COMPOSE_DEFAULT``;
|
||||||
read-only on hardware without additional compose/scaling capabilities.
|
read-only on hardware without additional compose/scaling capabilities.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||||
the visible rectangle; it must fit within the frame buffer resolution
|
the visible rectangle; it must fit within the frame buffer resolution
|
||||||
@@ -629,7 +629,7 @@ Capture Setup
|
|||||||
``memory``
|
``memory``
|
||||||
follows standard semantics.
|
follows standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
actual number of buffers allocated.
|
actual number of buffers allocated.
|
||||||
@@ -668,7 +668,7 @@ Capture Setup
|
|||||||
a format representing the maximum framebuffer resolution to be
|
a format representing the maximum framebuffer resolution to be
|
||||||
accommodated by newly allocated buffers.
|
accommodated by newly allocated buffers.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
adjusted to the number of allocated buffers.
|
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
|
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
|
frame intervals for a given format and resolution, passing the desired pixel
|
||||||
format in :c:type:`v4l2_frmsizeenum` ``pixel_format`` and the resolution
|
format in :c:type:`v4l2_frmivalenum` ``pixel_format`` and the resolution
|
||||||
in :c:type:`v4l2_frmsizeenum` ``width`` and :c:type:`v4l2_frmsizeenum`
|
in :c:type:`v4l2_frmivalenum` ``width`` and :c:type:`v4l2_frmivalenum`
|
||||||
``height``.
|
``height``.
|
||||||
|
|
||||||
* Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a coded pixel
|
* Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a coded pixel
|
||||||
@@ -163,7 +163,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``sizeimage``
|
``sizeimage``
|
||||||
adjusted size of ``CAPTURE`` buffers.
|
adjusted size of ``CAPTURE`` buffers.
|
||||||
@@ -189,7 +189,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``pixelformat``
|
``pixelformat``
|
||||||
raw format supported for the coded format currently selected on
|
raw format supported for the coded format currently selected on
|
||||||
@@ -215,7 +215,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``width``, ``height``
|
``width``, ``height``
|
||||||
may be adjusted to match encoder minimums, maximums and alignment
|
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
|
:c:func:`VIDIOC_S_PARM`. This also sets the coded frame interval on the
|
||||||
``CAPTURE`` queue to the same value.
|
``CAPTURE`` queue to the same value.
|
||||||
|
|
||||||
* ** Required fields:**
|
* **Required fields:**
|
||||||
|
|
||||||
``type``
|
``type``
|
||||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``.
|
||||||
@@ -245,7 +245,7 @@ Initialization
|
|||||||
the desired frame interval; the encoder may adjust it to
|
the desired frame interval; the encoder may adjust it to
|
||||||
match hardware requirements.
|
match hardware requirements.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``parm.output.timeperframe``
|
``parm.output.timeperframe``
|
||||||
the adjusted frame interval.
|
the adjusted frame interval.
|
||||||
@@ -284,7 +284,7 @@ Initialization
|
|||||||
the case for off-line encoding. Support for this feature is signalled
|
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.
|
by the :ref:`V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL <fmtdesc-flags>` format flag.
|
||||||
|
|
||||||
* ** Required fields:**
|
* **Required fields:**
|
||||||
|
|
||||||
``type``
|
``type``
|
||||||
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``.
|
||||||
@@ -296,7 +296,7 @@ Initialization
|
|||||||
the desired coded frame interval; the encoder may adjust it to
|
the desired coded frame interval; the encoder may adjust it to
|
||||||
match hardware requirements.
|
match hardware requirements.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``parm.capture.timeperframe``
|
``parm.capture.timeperframe``
|
||||||
the adjusted frame interval.
|
the adjusted frame interval.
|
||||||
@@ -339,7 +339,7 @@ Initialization
|
|||||||
rectangle and may be subject to adjustment to match codec and
|
rectangle and may be subject to adjustment to match codec and
|
||||||
hardware constraints.
|
hardware constraints.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
``r.left``, ``r.top``, ``r.width``, ``r.height``
|
||||||
visible rectangle adjusted by the encoder.
|
visible rectangle adjusted by the encoder.
|
||||||
@@ -387,7 +387,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
actual number of buffers allocated.
|
actual number of buffers allocated.
|
||||||
@@ -420,7 +420,7 @@ Initialization
|
|||||||
other fields
|
other fields
|
||||||
follow standard semantics.
|
follow standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
adjusted to the number of allocated buffers.
|
adjusted to the number of allocated buffers.
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ Initialization
|
|||||||
``memory``
|
``memory``
|
||||||
follows standard semantics.
|
follows standard semantics.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
actual number of buffers allocated.
|
actual number of buffers allocated.
|
||||||
@@ -208,7 +208,7 @@ Initialization
|
|||||||
follows standard semantics. ``V4L2_MEMORY_USERPTR`` is not supported
|
follows standard semantics. ``V4L2_MEMORY_USERPTR`` is not supported
|
||||||
for ``CAPTURE`` buffers.
|
for ``CAPTURE`` buffers.
|
||||||
|
|
||||||
* **Return fields:**
|
* **Returned fields:**
|
||||||
|
|
||||||
``count``
|
``count``
|
||||||
adjusted to allocated number of buffers, in case the codec requires
|
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,
|
Decoder's implementation can be found here,
|
||||||
`aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
|
`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
|
.. raw:: latex
|
||||||
|
|
||||||
\normalsize
|
\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
|
value of the ``num_routes`` field. Application should then reserve enough memory
|
||||||
for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again.
|
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}|
|
.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
|
||||||
|
|
||||||
.. c:type:: v4l2_subdev_routing
|
.. c:type:: v4l2_subdev_routing
|
||||||
@@ -138,9 +141,7 @@ ENOSPC
|
|||||||
|
|
||||||
EINVAL
|
EINVAL
|
||||||
The sink or source pad identifiers reference a non-existing pad, or reference
|
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)
|
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.
|
|
||||||
|
|
||||||
E2BIG
|
E2BIG
|
||||||
The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is
|
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
|
AMPHION VPU CODEC V4L2 DRIVER
|
||||||
M: Ming Qian <ming.qian@nxp.com>
|
M: Ming Qian <ming.qian@nxp.com>
|
||||||
M: Shijie Qin <shijie.qin@nxp.com>
|
|
||||||
M: Zhou Peng <eagle.zhou@nxp.com>
|
M: Zhou Peng <eagle.zhou@nxp.com>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -4469,6 +4468,7 @@ M: Maxime Ripard <mripard@kernel.org>
|
|||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/media/cdns,*.txt
|
F: Documentation/devicetree/bindings/media/cdns,*.txt
|
||||||
|
F: Documentation/devicetree/bindings/media/cdns,csi2rx.yaml
|
||||||
F: drivers/media/platform/cadence/cdns-csi2*
|
F: drivers/media/platform/cadence/cdns-csi2*
|
||||||
|
|
||||||
CADENCE NAND DRIVER
|
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: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml
|
||||||
F: drivers/media/i2c/dw9714.c
|
F: drivers/media/i2c/dw9714.c
|
||||||
|
|
||||||
DONGWOON DW9768 LENS VOICE COIL DRIVER
|
DONGWOON DW9719 LENS VOICE COIL DRIVER
|
||||||
M: Dongchun Zhu <dongchun.zhu@mediatek.com>
|
M: Daniel Scally <djrscally@gmail.com>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
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: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
|
||||||
F: drivers/media/i2c/dw9768.c
|
F: drivers/media/i2c/dw9768.c
|
||||||
|
|
||||||
@@ -9668,7 +9674,7 @@ S: Maintained
|
|||||||
F: arch/x86/kernel/cpu/hygon.c
|
F: arch/x86/kernel/cpu/hygon.c
|
||||||
|
|
||||||
HYNIX HI556 SENSOR DRIVER
|
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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
@@ -9681,7 +9687,7 @@ S: Maintained
|
|||||||
F: drivers/media/i2c/hi846.c
|
F: drivers/media/i2c/hi846.c
|
||||||
|
|
||||||
HYNIX HI847 SENSOR DRIVER
|
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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/media/i2c/hi847.c
|
F: drivers/media/i2c/hi847.c
|
||||||
@@ -9752,6 +9758,14 @@ L: linux-acpi@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/i2c/i2c-core-acpi.c
|
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
|
I2C CONTROLLER DRIVER FOR NVIDIA GPU
|
||||||
M: Ajay Gupta <ajayg@nvidia.com>
|
M: Ajay Gupta <ajayg@nvidia.com>
|
||||||
L: linux-i2c@vger.kernel.org
|
L: linux-i2c@vger.kernel.org
|
||||||
@@ -13094,17 +13108,21 @@ F: drivers/staging/media/imx/
|
|||||||
F: include/linux/imx-media.h
|
F: include/linux/imx-media.h
|
||||||
F: include/media/imx.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: Rui Miguel Silva <rmfrfs@gmail.com>
|
||||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
F: Documentation/admin-guide/media/imx7.rst
|
F: Documentation/admin-guide/media/imx7.rst
|
||||||
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
|
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,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/imx-mipi-csis.c
|
||||||
F: drivers/media/platform/nxp/imx7-media-csi.c
|
F: drivers/media/platform/nxp/imx7-media-csi.c
|
||||||
|
F: drivers/media/platform/nxp/imx8mq-mipi-csi2.c
|
||||||
|
|
||||||
MEDIA DRIVERS FOR HELENE
|
MEDIA DRIVERS FOR HELENE
|
||||||
M: Abylay Ospan <aospan@netup.ru>
|
M: Abylay Ospan <aospan@netup.ru>
|
||||||
@@ -15652,7 +15670,7 @@ F: Documentation/filesystems/omfs.rst
|
|||||||
F: fs/omfs/
|
F: fs/omfs/
|
||||||
|
|
||||||
OMNIVISION OG01A1B SENSOR DRIVER
|
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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/media/i2c/og01a1b.c
|
F: drivers/media/i2c/og01a1b.c
|
||||||
@@ -15665,9 +15683,8 @@ T: git git://linuxtv.org/media_tree.git
|
|||||||
F: drivers/media/i2c/ov01a10.c
|
F: drivers/media/i2c/ov01a10.c
|
||||||
|
|
||||||
OMNIVISION OV02A10 SENSOR DRIVER
|
OMNIVISION OV02A10 SENSOR DRIVER
|
||||||
M: Dongchun Zhu <dongchun.zhu@mediatek.com>
|
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Orphan
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml
|
F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml
|
||||||
F: drivers/media/i2c/ov02a10.c
|
F: drivers/media/i2c/ov02a10.c
|
||||||
@@ -15702,6 +15719,7 @@ F: drivers/media/i2c/ov13b10.c
|
|||||||
|
|
||||||
OMNIVISION OV2680 SENSOR DRIVER
|
OMNIVISION OV2680 SENSOR DRIVER
|
||||||
M: Rui Miguel Silva <rmfrfs@gmail.com>
|
M: Rui Miguel Silva <rmfrfs@gmail.com>
|
||||||
|
M: Hans de Goede <hansg@kernel.org>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
@@ -15718,7 +15736,7 @@ F: drivers/media/i2c/ov2685.c
|
|||||||
|
|
||||||
OMNIVISION OV2740 SENSOR DRIVER
|
OMNIVISION OV2740 SENSOR DRIVER
|
||||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
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>
|
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -15750,7 +15768,7 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov5647.yaml
|
|||||||
F: drivers/media/i2c/ov5647.c
|
F: drivers/media/i2c/ov5647.c
|
||||||
|
|
||||||
OMNIVISION OV5670 SENSOR DRIVER
|
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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
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
|
F: drivers/media/i2c/ov5670.c
|
||||||
|
|
||||||
OMNIVISION OV5675 SENSOR DRIVER
|
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
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
@@ -15797,9 +15815,8 @@ F: drivers/media/i2c/ov772x.c
|
|||||||
F: include/media/i2c/ov772x.h
|
F: include/media/i2c/ov772x.h
|
||||||
|
|
||||||
OMNIVISION OV7740 SENSOR DRIVER
|
OMNIVISION OV7740 SENSOR DRIVER
|
||||||
M: Wenyou Yang <wenyou.yang@microchip.com>
|
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
S: Maintained
|
S: Orphan
|
||||||
T: git git://linuxtv.org/media_tree.git
|
T: git git://linuxtv.org/media_tree.git
|
||||||
F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
|
F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
|
||||||
F: drivers/media/i2c/ov7740.c
|
F: drivers/media/i2c/ov7740.c
|
||||||
@@ -21503,6 +21520,14 @@ F: drivers/misc/tifm*
|
|||||||
F: drivers/mmc/host/tifm_sd.c
|
F: drivers/mmc/host/tifm_sd.c
|
||||||
F: include/linux/tifm.h
|
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
|
TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
|
||||||
M: Nishanth Menon <nm@ti.com>
|
M: Nishanth Menon <nm@ti.com>
|
||||||
M: Santosh Shilimkar <ssantosh@kernel.org>
|
M: Santosh Shilimkar <ssantosh@kernel.org>
|
||||||
@@ -22447,6 +22472,39 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/clk/ux500/
|
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
|
VF610 NAND DRIVER
|
||||||
M: Stefan Agner <stefan@agner.ch>
|
M: Stefan Agner <stefan@agner.ch>
|
||||||
L: linux-mtd@lists.infradead.org
|
L: linux-mtd@lists.infradead.org
|
||||||
|
|||||||
@@ -1159,7 +1159,6 @@ CONFIG_XEN_GNTDEV=y
|
|||||||
CONFIG_XEN_GRANT_DEV_ALLOC=y
|
CONFIG_XEN_GRANT_DEV_ALLOC=y
|
||||||
CONFIG_STAGING=y
|
CONFIG_STAGING=y
|
||||||
CONFIG_STAGING_MEDIA=y
|
CONFIG_STAGING_MEDIA=y
|
||||||
CONFIG_VIDEO_IMX_MEDIA=m
|
|
||||||
CONFIG_VIDEO_MAX96712=m
|
CONFIG_VIDEO_MAX96712=m
|
||||||
CONFIG_CHROME_PLATFORMS=y
|
CONFIG_CHROME_PLATFORMS=y
|
||||||
CONFIG_CROS_EC=y
|
CONFIG_CROS_EC=y
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ config I2C_MUX
|
|||||||
|
|
||||||
source "drivers/i2c/muxes/Kconfig"
|
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
|
config I2C_HELPER_AUTO
|
||||||
bool "Autoselect pertinent helper modules"
|
bool "Autoselect pertinent helper modules"
|
||||||
default y
|
default y
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ i2c-core-$(CONFIG_OF) += i2c-core-of.o
|
|||||||
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
|
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
|
||||||
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
|
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
|
||||||
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
||||||
|
obj-$(CONFIG_I2C_ATR) += i2c-atr.o
|
||||||
obj-y += algos/ busses/ muxes/
|
obj-y += algos/ busses/ muxes/
|
||||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||||
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.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);
|
cec_queue_msg_monitor(adap, &data->msg, 1);
|
||||||
|
|
||||||
if (!data->blocking && data->msg.sequence)
|
if (!data->blocking && data->msg.sequence)
|
||||||
/* Allow drivers to process the message first */
|
/* Allow drivers to react to a canceled transmit */
|
||||||
call_op(adap, received, &data->msg);
|
call_void_op(adap, adap_nb_transmit_canceled, &data->msg);
|
||||||
|
|
||||||
cec_data_completed(data);
|
cec_data_completed(data);
|
||||||
}
|
}
|
||||||
@@ -1348,7 +1348,7 @@ static void cec_adap_unconfigure(struct cec_adapter *adap)
|
|||||||
cec_flush(adap);
|
cec_flush(adap);
|
||||||
wake_up_interruptible(&adap->kthread_waitq);
|
wake_up_interruptible(&adap->kthread_waitq);
|
||||||
cec_post_state_event(adap);
|
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;
|
adap->kthread_config = NULL;
|
||||||
complete(&adap->config_completion);
|
complete(&adap->config_completion);
|
||||||
mutex_unlock(&adap->lock);
|
mutex_unlock(&adap->lock);
|
||||||
call_void_op(adap, adap_configured, true);
|
call_void_op(adap, configured);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unconfigure:
|
unconfigure:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ struct cec_pin {
|
|||||||
u16 la_mask;
|
u16 la_mask;
|
||||||
bool monitor_all;
|
bool monitor_all;
|
||||||
bool rx_eom;
|
bool rx_eom;
|
||||||
|
bool enabled_irq;
|
||||||
bool enable_irq_failed;
|
bool enable_irq_failed;
|
||||||
enum cec_pin_state state;
|
enum cec_pin_state state;
|
||||||
struct cec_msg tx_msg;
|
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 ||
|
if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL ||
|
||||||
pin->enable_irq_failed || adap->is_configuring ||
|
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;
|
break;
|
||||||
/* Switch to interrupt mode */
|
/* Switch to interrupt mode */
|
||||||
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_ENABLE);
|
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_adapter *adap = _adap;
|
||||||
struct cec_pin *pin = adap->pin;
|
struct cec_pin *pin = adap->pin;
|
||||||
bool irq_enabled = false;
|
|
||||||
|
|
||||||
|
pin->enabled_irq = false;
|
||||||
|
pin->enable_irq_failed = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
wait_event_interruptible(pin->kthread_waitq,
|
wait_event_interruptible(pin->kthread_waitq,
|
||||||
kthread_should_stop() ||
|
kthread_should_stop() ||
|
||||||
@@ -1088,9 +1089,10 @@ static int cec_pin_thread_func(void *_adap)
|
|||||||
switch (atomic_xchg(&pin->work_irq_change,
|
switch (atomic_xchg(&pin->work_irq_change,
|
||||||
CEC_PIN_IRQ_UNCHANGED)) {
|
CEC_PIN_IRQ_UNCHANGED)) {
|
||||||
case CEC_PIN_IRQ_DISABLE:
|
case CEC_PIN_IRQ_DISABLE:
|
||||||
if (irq_enabled) {
|
if (pin->enabled_irq) {
|
||||||
call_void_pin_op(pin, disable_irq);
|
pin->ops->disable_irq(adap);
|
||||||
irq_enabled = false;
|
pin->enabled_irq = false;
|
||||||
|
pin->enable_irq_failed = false;
|
||||||
}
|
}
|
||||||
cec_pin_high(pin);
|
cec_pin_high(pin);
|
||||||
if (pin->state == CEC_ST_OFF)
|
if (pin->state == CEC_ST_OFF)
|
||||||
@@ -1100,21 +1102,29 @@ static int cec_pin_thread_func(void *_adap)
|
|||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
break;
|
break;
|
||||||
case CEC_PIN_IRQ_ENABLE:
|
case CEC_PIN_IRQ_ENABLE:
|
||||||
if (irq_enabled)
|
if (pin->enabled_irq || !pin->ops->enable_irq ||
|
||||||
|
pin->adap->devnode.unregistered)
|
||||||
break;
|
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) {
|
if (pin->enable_irq_failed) {
|
||||||
cec_pin_to_idle(pin);
|
cec_pin_to_idle(pin);
|
||||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
} else {
|
} else {
|
||||||
irq_enabled = true;
|
pin->enabled_irq = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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;
|
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: %d\n", call_pin_op(pin, read));
|
||||||
seq_printf(file, "cec pin events dropped: %u\n",
|
seq_printf(file, "cec pin events dropped: %u\n",
|
||||||
pin->work_pin_events_dropped_cnt);
|
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) {
|
if (pin->timer_100us_overruns) {
|
||||||
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
||||||
pin->timer_100us_overruns, pin->timer_cnt);
|
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);
|
cec_pin_update(pin, value, false);
|
||||||
if (!value && (adap->is_configuring || adap->is_configured ||
|
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);
|
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cec_pin_changed);
|
EXPORT_SYMBOL_GPL(cec_pin_changed);
|
||||||
|
|||||||
@@ -589,7 +589,7 @@ MODULE_DEVICE_TABLE(of, ch7322_of_match);
|
|||||||
static struct i2c_driver ch7322_i2c_driver = {
|
static struct i2c_driver ch7322_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ch7322",
|
.name = "ch7322",
|
||||||
.of_match_table = of_match_ptr(ch7322_of_match),
|
.of_match_table = ch7322_of_match,
|
||||||
},
|
},
|
||||||
.probe = ch7322_probe,
|
.probe = ch7322_probe,
|
||||||
.remove = ch7322_remove,
|
.remove = ch7322_remove,
|
||||||
|
|||||||
@@ -159,11 +159,6 @@ static int cec_gpio_read_5v(struct cec_adapter *adap)
|
|||||||
return gpiod_get_value(cec->v5_gpio);
|
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 = {
|
static const struct cec_pin_ops cec_gpio_pin_ops = {
|
||||||
.read = cec_gpio_read,
|
.read = cec_gpio_read,
|
||||||
.low = cec_gpio_low,
|
.low = cec_gpio_low,
|
||||||
@@ -171,7 +166,6 @@ static const struct cec_pin_ops cec_gpio_pin_ops = {
|
|||||||
.enable_irq = cec_gpio_enable_irq,
|
.enable_irq = cec_gpio_enable_irq,
|
||||||
.disable_irq = cec_gpio_disable_irq,
|
.disable_irq = cec_gpio_disable_irq,
|
||||||
.status = cec_gpio_status,
|
.status = cec_gpio_status,
|
||||||
.free = cec_gpio_free,
|
|
||||||
.read_hpd = cec_gpio_read_hpd,
|
.read_hpd = cec_gpio_read_hpd,
|
||||||
.read_5v = cec_gpio_read_5v,
|
.read_5v = cec_gpio_read_5v,
|
||||||
};
|
};
|
||||||
@@ -215,13 +209,11 @@ static int cec_gpio_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(cec->adap);
|
return PTR_ERR(cec->adap);
|
||||||
|
|
||||||
ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler,
|
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);
|
cec->adap->name, cec);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto del_adap;
|
goto del_adap;
|
||||||
|
|
||||||
cec_gpio_disable_irq(cec->adap);
|
|
||||||
|
|
||||||
if (cec->hpd_gpio) {
|
if (cec->hpd_gpio) {
|
||||||
cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio);
|
cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio);
|
||||||
ret = devm_request_threaded_irq(dev, cec->hpd_irq,
|
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,
|
.remove_new = meson_ao_cec_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "meson-ao-cec",
|
.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/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.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);
|
cec->tegra_cec_irq = platform_get_irq(pdev, 0);
|
||||||
|
|
||||||
if (cec->tegra_cec_irq <= 0)
|
if (cec->tegra_cec_irq < 0)
|
||||||
return -EBUSY;
|
return cec->tegra_cec_irq;
|
||||||
|
|
||||||
cec->cec_base = devm_ioremap(&pdev->dev, res->start,
|
cec->cec_base = devm_ioremap(&pdev->dev, res->start,
|
||||||
resource_size(res));
|
resource_size(res));
|
||||||
@@ -462,7 +462,7 @@ static const struct of_device_id tegra_cec_of_match[] = {
|
|||||||
static struct platform_driver tegra_cec_driver = {
|
static struct platform_driver tegra_cec_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = TEGRA_CEC_NAME,
|
.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,
|
.probe = tegra_cec_probe,
|
||||||
.remove_new = tegra_cec_remove,
|
.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;
|
buf = debug_data->stats_data;
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\n", p->is_rf_locked);
|
||||||
"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 += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||||
"is_demod_locked = %d\n", p->is_demod_locked);
|
n += sysfs_emit_at(buf, n, "SNR = %d\n", p->SNR);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "ber = %d\n", p->ber);
|
||||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
n += sysfs_emit_at(buf, n, "FIB_CRC = %d\n", p->FIB_CRC);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "ts_per = %d\n", p->ts_per);
|
||||||
"SNR = %d\n", p->SNR);
|
n += sysfs_emit_at(buf, n, "MFER = %d\n", p->MFER);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "RSSI = %d\n", p->RSSI);
|
||||||
"ber = %d\n", p->ber);
|
n += sysfs_emit_at(buf, n, "in_band_pwr = %d\n", p->in_band_pwr);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "carrier_offset = %d\n", p->carrier_offset);
|
||||||
"FIB_CRC = %d\n", p->FIB_CRC);
|
n += sysfs_emit_at(buf, n, "modem_state = %d\n", p->modem_state);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "frequency = %d\n", p->frequency);
|
||||||
"ts_per = %d\n", p->ts_per);
|
n += sysfs_emit_at(buf, n, "bandwidth = %d\n", p->bandwidth);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "transmission_mode = %d\n", p->transmission_mode);
|
||||||
"MFER = %d\n", p->MFER);
|
n += sysfs_emit_at(buf, n, "modem_state = %d\n", p->modem_state);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||||
"RSSI = %d\n", p->RSSI);
|
n += sysfs_emit_at(buf, n, "code_rate = %d\n", p->code_rate);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "lp_code_rate = %d\n", p->lp_code_rate);
|
||||||
"in_band_pwr = %d\n", p->in_band_pwr);
|
n += sysfs_emit_at(buf, n, "hierarchy = %d\n", p->hierarchy);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->constellation);
|
||||||
"carrier_offset = %d\n", p->carrier_offset);
|
n += sysfs_emit_at(buf, n, "burst_size = %d\n", p->burst_size);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "burst_duration = %d\n", p->burst_duration);
|
||||||
"modem_state = %d\n", p->modem_state);
|
n += sysfs_emit_at(buf, n, "burst_cycle_time = %d\n", p->burst_cycle_time);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "calc_burst_cycle_time = %d\n", p->calc_burst_cycle_time);
|
||||||
"frequency = %d\n", p->frequency);
|
n += sysfs_emit_at(buf, n, "num_of_rows = %d\n", p->num_of_rows);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "num_of_padd_cols = %d\n", p->num_of_padd_cols);
|
||||||
"bandwidth = %d\n", p->bandwidth);
|
n += sysfs_emit_at(buf, n, "num_of_punct_cols = %d\n", p->num_of_punct_cols);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "error_ts_packets = %d\n", p->error_ts_packets);
|
||||||
"transmission_mode = %d\n", p->transmission_mode);
|
n += sysfs_emit_at(buf, n, "total_ts_packets = %d\n", p->total_ts_packets);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
|
||||||
"modem_state = %d\n", p->modem_state);
|
n += sysfs_emit_at(buf, n, "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "num_of_corrected_mpe_tlbs = %d\n",
|
||||||
"guard_interval = %d\n", p->guard_interval);
|
p->num_of_corrected_mpe_tlbs);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "ber_error_count = %d\n", p->ber_error_count);
|
||||||
"code_rate = %d\n", p->code_rate);
|
n += sysfs_emit_at(buf, n, "ber_bit_count = %d\n", p->ber_bit_count);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||||
"lp_code_rate = %d\n", p->lp_code_rate);
|
n += sysfs_emit_at(buf, n, "pre_ber = %d\n", p->pre_ber);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "cell_id = %d\n", p->cell_id);
|
||||||
"hierarchy = %d\n", p->hierarchy);
|
n += sysfs_emit_at(buf, n, "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
|
||||||
"constellation = %d\n", p->constellation);
|
n += sysfs_emit_at(buf, n, "num_mpe_received = %d\n", p->num_mpe_received);
|
||||||
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);
|
|
||||||
|
|
||||||
debug_data->stats_count = n;
|
debug_data->stats_count = n;
|
||||||
spin_unlock(&debug_data->lock);
|
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;
|
buf = debug_data->stats_data;
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "statistics_type = %d\t", p->statistics_type);
|
||||||
"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,
|
|
||||||
"full_size = %d\n", p->full_size);
|
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||||
"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 += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
n += sysfs_emit_at(buf, n, "SNR = %d dB\t\t", p->SNR);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "RSSI = %d dBm\t\t", p->RSSI);
|
||||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
n += sysfs_emit_at(buf, n, "in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "carrier_offset = %d\t", p->carrier_offset);
|
||||||
"SNR = %d dB\t\t", p->SNR);
|
n += sysfs_emit_at(buf, n, "bandwidth = %d\t\t", p->bandwidth);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "frequency = %d Hz\n", p->frequency);
|
||||||
"RSSI = %d dBm\t\t", p->RSSI);
|
n += sysfs_emit_at(buf, n, "transmission_mode = %d\t", p->transmission_mode);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "modem_state = %d\t\t", p->modem_state);
|
||||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "system_type = %d\t\t", p->system_type);
|
||||||
"carrier_offset = %d\t", p->carrier_offset);
|
n += sysfs_emit_at(buf, n, "partial_reception = %d\t", p->partial_reception);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "num_of_layers = %d\n", p->num_of_layers);
|
||||||
"bandwidth = %d\t\t", p->bandwidth);
|
n += sysfs_emit_at(buf, n, "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||||
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);
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
if (p->layer_info[i].number_of_segments < 1 ||
|
if (p->layer_info[i].number_of_segments < 1 ||
|
||||||
p->layer_info[i].number_of_segments > 13)
|
p->layer_info[i].number_of_segments > 13)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
n += sysfs_emit_at(buf, n, "\nLayer %d\n", i);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
n += sysfs_emit_at(buf, n, "\tcode_rate = %d\t", p->layer_info[i].code_rate);
|
||||||
p->layer_info[i].code_rate);
|
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->layer_info[i].constellation);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
n += sysfs_emit_at(buf, n, "\tber = %-5d\t", p->layer_info[i].ber);
|
||||||
p->layer_info[i].constellation);
|
n += sysfs_emit_at(buf, n, "\tber_error_count = %-5d\t",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
p->layer_info[i].ber_error_count);
|
||||||
p->layer_info[i].ber);
|
n += sysfs_emit_at(buf, n, "ber_bit_count = %-5d\n",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
p->layer_info[i].ber_bit_count);
|
||||||
"\tber_error_count = %-5d\t",
|
n += sysfs_emit_at(buf, n, "\tpre_ber = %-5d\t", p->layer_info[i].pre_ber);
|
||||||
p->layer_info[i].ber_error_count);
|
n += sysfs_emit_at(buf, n, "\tts_per = %-5d\n", p->layer_info[i].ts_per);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
n += sysfs_emit_at(buf, n, "\terror_ts_packets = %-5d\t",
|
||||||
p->layer_info[i].ber_bit_count);
|
p->layer_info[i].error_ts_packets);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
n += sysfs_emit_at(buf, n, "total_ts_packets = %-5d\t",
|
||||||
p->layer_info[i].pre_ber);
|
p->layer_info[i].total_ts_packets);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
n += sysfs_emit_at(buf, n, "ti_ldepth_i = %d\n", p->layer_info[i].ti_ldepth_i);
|
||||||
p->layer_info[i].ts_per);
|
n += sysfs_emit_at(buf, n, "\tnumber_of_segments = %d\t",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
p->layer_info[i].number_of_segments);
|
||||||
"\terror_ts_packets = %-5d\t",
|
n += sysfs_emit_at(buf, n, "tmcc_errors = %d\n", p->layer_info[i].tmcc_errors);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_data->stats_count = n;
|
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;
|
buf = debug_data->stats_data;
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "statistics_type = %d\t", p->statistics_type);
|
||||||
"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,
|
|
||||||
"full_size = %d\n", p->full_size);
|
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||||
"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 += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
n += sysfs_emit_at(buf, n, "SNR = %d dB\t\t", p->SNR);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "RSSI = %d dBm\t\t", p->RSSI);
|
||||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
n += sysfs_emit_at(buf, n, "in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "carrier_offset = %d\t", p->carrier_offset);
|
||||||
"SNR = %d dB\t\t", p->SNR);
|
n += sysfs_emit_at(buf, n, "bandwidth = %d\t\t", p->bandwidth);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "frequency = %d Hz\n", p->frequency);
|
||||||
"RSSI = %d dBm\t\t", p->RSSI);
|
n += sysfs_emit_at(buf, n, "transmission_mode = %d\t", p->transmission_mode);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "modem_state = %d\t\t", p->modem_state);
|
||||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
n += sysfs_emit_at(buf, n, "guard_interval = %d\n", p->guard_interval);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "system_type = %d\t\t", p->system_type);
|
||||||
"carrier_offset = %d\t", p->carrier_offset);
|
n += sysfs_emit_at(buf, n, "partial_reception = %d\t", p->partial_reception);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "num_of_layers = %d\n", p->num_of_layers);
|
||||||
"bandwidth = %d\t\t", p->bandwidth);
|
n += sysfs_emit_at(buf, n, "segment_number = %d\t", p->segment_number);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
n += sysfs_emit_at(buf, n, "tune_bw = %d\n", p->tune_bw);
|
||||||
"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);
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
if (p->layer_info[i].number_of_segments < 1 ||
|
if (p->layer_info[i].number_of_segments < 1 ||
|
||||||
p->layer_info[i].number_of_segments > 13)
|
p->layer_info[i].number_of_segments > 13)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
n += sysfs_emit_at(buf, n, "\nLayer %d\n", i);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
n += sysfs_emit_at(buf, n, "\tcode_rate = %d\t", p->layer_info[i].code_rate);
|
||||||
p->layer_info[i].code_rate);
|
n += sysfs_emit_at(buf, n, "constellation = %d\n", p->layer_info[i].constellation);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
n += sysfs_emit_at(buf, n, "\tber = %-5d\t", p->layer_info[i].ber);
|
||||||
p->layer_info[i].constellation);
|
n += sysfs_emit_at(buf, n, "\tber_error_count = %-5d\t",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
p->layer_info[i].ber_error_count);
|
||||||
p->layer_info[i].ber);
|
n += sysfs_emit_at(buf, n, "ber_bit_count = %-5d\n",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
p->layer_info[i].ber_bit_count);
|
||||||
"\tber_error_count = %-5d\t",
|
n += sysfs_emit_at(buf, n, "\tpre_ber = %-5d\t", p->layer_info[i].pre_ber);
|
||||||
p->layer_info[i].ber_error_count);
|
n += sysfs_emit_at(buf, n, "\tts_per = %-5d\n", p->layer_info[i].ts_per);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
n += sysfs_emit_at(buf, n, "\terror_ts_packets = %-5d\t",
|
||||||
p->layer_info[i].ber_bit_count);
|
p->layer_info[i].error_ts_packets);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
n += sysfs_emit_at(buf, n, "total_ts_packets = %-5d\t",
|
||||||
p->layer_info[i].pre_ber);
|
p->layer_info[i].total_ts_packets);
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
n += sysfs_emit_at(buf, n, "ti_ldepth_i = %d\n", p->layer_info[i].ti_ldepth_i);
|
||||||
p->layer_info[i].ts_per);
|
n += sysfs_emit_at(buf, n, "\tnumber_of_segments = %d\t",
|
||||||
n += scnprintf(&buf[n], PAGE_SIZE - n,
|
p->layer_info[i].number_of_segments);
|
||||||
"\terror_ts_packets = %-5d\t",
|
n += sysfs_emit_at(buf, n, "tmcc_errors = %d\n", p->layer_info[i].tmcc_errors);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
void smsendian_handle_tx_message(void *buffer)
|
void smsendian_handle_tx_message(void *buffer)
|
||||||
{
|
{
|
||||||
#ifdef __BIG_ENDIAN
|
#ifdef __BIG_ENDIAN
|
||||||
struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
|
struct sms_msg_data *msg = buffer;
|
||||||
int i;
|
int i;
|
||||||
int msg_words;
|
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[8] = (clock_ratios_table[idx].rate >> 8) & 0xff;
|
||||||
cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 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 */
|
/* Calculate ber window rates for stat work */
|
||||||
cx24120_calculate_ber_window(state, clock_ratios_table[idx].rate);
|
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;
|
prediv = reg_1856 & 0x3f;
|
||||||
loopdiv = (reg_1856 >> 6) & 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);
|
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_1856 &= 0xf000;
|
||||||
reg_1857 = dib7000p_read_word(state, 1857);
|
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 = {
|
struct i2c_msg msg = {
|
||||||
.addr = adr, .flags = 0, .buf = data, .len = len };
|
.addr = adr, .flags = 0, .buf = data, .len = len };
|
||||||
|
|
||||||
dprintk(3, ":");
|
dprintk(3, ": %*ph\n", len, data);
|
||||||
if (debug > 2) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
pr_cont(" %02x", data[i]);
|
|
||||||
pr_cont("\n");
|
|
||||||
}
|
|
||||||
status = drxk_i2c_transfer(state, &msg, 1);
|
status = drxk_i2c_transfer(state, &msg, 1);
|
||||||
if (status >= 0 && status != 1)
|
if (status >= 0 && status != 1)
|
||||||
status = -EIO;
|
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);
|
pr_err("i2c read error at addr 0x%02x\n", adr);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if (debug > 2) {
|
dprintk(3, ": read from %*ph, value = %*ph\n", len, msg, alen, answ);
|
||||||
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");
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,13 +427,8 @@ static int write_block(struct drxk_state *state, u32 address,
|
|||||||
}
|
}
|
||||||
memcpy(&state->chunk[adr_length], p_block, chunk);
|
memcpy(&state->chunk[adr_length], p_block, chunk);
|
||||||
dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
|
dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
|
||||||
if (debug > 1) {
|
if (p_block)
|
||||||
int i;
|
dprintk(2, "%*ph\n", chunk, p_block);
|
||||||
if (p_block)
|
|
||||||
for (i = 0; i < chunk; i++)
|
|
||||||
pr_cont(" %02x", p_block[i]);
|
|
||||||
pr_cont("\n");
|
|
||||||
}
|
|
||||||
status = i2c_write(state, state->demod_address,
|
status = i2c_write(state, state->demod_address,
|
||||||
&state->chunk[0], chunk + adr_length);
|
&state->chunk[0], chunk + adr_length);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
|||||||
@@ -1487,10 +1487,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mb86a16_read(state, 0x15, &agcval);
|
if (mb86a16_read(state, 0x15, &agcval) != 2 || mb86a16_read(state, 0x26, &cnmval) != 2) {
|
||||||
mb86a16_read(state, 0x26, &cnmval);
|
dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
|
||||||
dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
|
ret = -EREMOTEIO;
|
||||||
|
} else {
|
||||||
|
dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/int_log.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_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
|
||||||
case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
|
case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
ret = -EIO;
|
||||||
|
goto unlock;
|
||||||
}
|
}
|
||||||
pad_operands(c, pos);
|
pad_operands(c, pos);
|
||||||
|
|
||||||
@@ -612,6 +613,7 @@ int avc_tuner_dsd(struct firedtv *fdtv,
|
|||||||
if (status)
|
if (status)
|
||||||
*status = r->operand[2];
|
*status = r->operand[2];
|
||||||
#endif
|
#endif
|
||||||
|
unlock:
|
||||||
mutex_unlock(&fdtv->avc_mutex);
|
mutex_unlock(&fdtv->avc_mutex);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
|||||||
@@ -25,8 +25,15 @@ config VIDEO_IR_I2C
|
|||||||
# V4L2 I2C drivers that are related with Camera support
|
# V4L2 I2C drivers that are related with Camera support
|
||||||
#
|
#
|
||||||
|
|
||||||
menu "Camera sensor devices"
|
menuconfig VIDEO_CAMERA_SENSOR
|
||||||
visible if MEDIA_CAMERA_SUPPORT
|
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
|
config VIDEO_APTINA_PLL
|
||||||
tristate
|
tristate
|
||||||
@@ -36,10 +43,6 @@ config VIDEO_CCS_PLL
|
|||||||
|
|
||||||
config VIDEO_AR0521
|
config VIDEO_AR0521
|
||||||
tristate "ON Semiconductor AR0521 sensor support"
|
tristate "ON Semiconductor AR0521 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the ON Semiconductor
|
This is a Video4Linux2 sensor driver for the ON Semiconductor
|
||||||
AR0521 camera.
|
AR0521 camera.
|
||||||
@@ -49,10 +52,6 @@ config VIDEO_AR0521
|
|||||||
|
|
||||||
config VIDEO_HI556
|
config VIDEO_HI556
|
||||||
tristate "Hynix Hi-556 sensor support"
|
tristate "Hynix Hi-556 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Hynix
|
This is a Video4Linux2 sensor driver for the Hynix
|
||||||
Hi-556 camera.
|
Hi-556 camera.
|
||||||
@@ -62,10 +61,6 @@ config VIDEO_HI556
|
|||||||
|
|
||||||
config VIDEO_HI846
|
config VIDEO_HI846
|
||||||
tristate "Hynix Hi-846 sensor support"
|
tristate "Hynix Hi-846 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Hynix
|
This is a Video4Linux2 sensor driver for the Hynix
|
||||||
Hi-846 camera.
|
Hi-846 camera.
|
||||||
@@ -75,10 +70,6 @@ config VIDEO_HI846
|
|||||||
|
|
||||||
config VIDEO_HI847
|
config VIDEO_HI847
|
||||||
tristate "Hynix Hi-847 sensor support"
|
tristate "Hynix Hi-847 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Hynix
|
This is a Video4Linux2 sensor driver for the Hynix
|
||||||
Hi-847 camera.
|
Hi-847 camera.
|
||||||
@@ -88,10 +79,6 @@ config VIDEO_HI847
|
|||||||
|
|
||||||
config VIDEO_IMX208
|
config VIDEO_IMX208
|
||||||
tristate "Sony IMX208 sensor support"
|
tristate "Sony IMX208 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
depends on MEDIA_CAMERA_SUPPORT
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX208 camera.
|
IMX208 camera.
|
||||||
@@ -101,10 +88,7 @@ config VIDEO_IMX208
|
|||||||
|
|
||||||
config VIDEO_IMX214
|
config VIDEO_IMX214
|
||||||
tristate "Sony IMX214 sensor support"
|
tristate "Sony IMX214 sensor support"
|
||||||
depends on GPIOLIB && I2C && VIDEO_DEV
|
depends on GPIOLIB
|
||||||
select V4L2_FWNODE
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
@@ -115,10 +99,6 @@ config VIDEO_IMX214
|
|||||||
|
|
||||||
config VIDEO_IMX219
|
config VIDEO_IMX219
|
||||||
tristate "Sony IMX219 sensor support"
|
tristate "Sony IMX219 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX219 camera.
|
IMX219 camera.
|
||||||
@@ -128,9 +108,6 @@ config VIDEO_IMX219
|
|||||||
|
|
||||||
config VIDEO_IMX258
|
config VIDEO_IMX258
|
||||||
tristate "Sony IMX258 sensor support"
|
tristate "Sony IMX258 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX258 camera.
|
IMX258 camera.
|
||||||
@@ -140,9 +117,6 @@ config VIDEO_IMX258
|
|||||||
|
|
||||||
config VIDEO_IMX274
|
config VIDEO_IMX274
|
||||||
tristate "Sony IMX274 sensor support"
|
tristate "Sony IMX274 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for the Sony IMX274
|
This is a V4L2 sensor driver for the Sony IMX274
|
||||||
@@ -150,11 +124,8 @@ config VIDEO_IMX274
|
|||||||
|
|
||||||
config VIDEO_IMX290
|
config VIDEO_IMX290
|
||||||
tristate "Sony IMX290 sensor support"
|
tristate "Sony IMX290 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
select V4L2_FWNODE
|
select V4L2_CCI_I2C
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX290 camera sensor.
|
IMX290 camera sensor.
|
||||||
@@ -164,10 +135,6 @@ config VIDEO_IMX290
|
|||||||
|
|
||||||
config VIDEO_IMX296
|
config VIDEO_IMX296
|
||||||
tristate "Sony IMX296 sensor support"
|
tristate "Sony IMX296 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX296 camera.
|
IMX296 camera.
|
||||||
@@ -177,9 +144,6 @@ config VIDEO_IMX296
|
|||||||
|
|
||||||
config VIDEO_IMX319
|
config VIDEO_IMX319
|
||||||
tristate "Sony IMX319 sensor support"
|
tristate "Sony IMX319 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX319 camera.
|
IMX319 camera.
|
||||||
@@ -190,10 +154,6 @@ config VIDEO_IMX319
|
|||||||
config VIDEO_IMX334
|
config VIDEO_IMX334
|
||||||
tristate "Sony IMX334 sensor support"
|
tristate "Sony IMX334 sensor support"
|
||||||
depends on OF_GPIO
|
depends on OF_GPIO
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX334 camera.
|
IMX334 camera.
|
||||||
@@ -204,10 +164,6 @@ config VIDEO_IMX334
|
|||||||
config VIDEO_IMX335
|
config VIDEO_IMX335
|
||||||
tristate "Sony IMX335 sensor support"
|
tristate "Sony IMX335 sensor support"
|
||||||
depends on OF_GPIO
|
depends on OF_GPIO
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX335 camera.
|
IMX335 camera.
|
||||||
@@ -217,9 +173,6 @@ config VIDEO_IMX335
|
|||||||
|
|
||||||
config VIDEO_IMX355
|
config VIDEO_IMX355
|
||||||
tristate "Sony IMX355 sensor support"
|
tristate "Sony IMX355 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX355 camera.
|
IMX355 camera.
|
||||||
@@ -230,10 +183,6 @@ config VIDEO_IMX355
|
|||||||
config VIDEO_IMX412
|
config VIDEO_IMX412
|
||||||
tristate "Sony IMX412 sensor support"
|
tristate "Sony IMX412 sensor support"
|
||||||
depends on OF_GPIO
|
depends on OF_GPIO
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX412 camera.
|
IMX412 camera.
|
||||||
@@ -244,10 +193,6 @@ config VIDEO_IMX412
|
|||||||
config VIDEO_IMX415
|
config VIDEO_IMX415
|
||||||
tristate "Sony IMX415 sensor support"
|
tristate "Sony IMX415 sensor support"
|
||||||
depends on OF_GPIO
|
depends on OF_GPIO
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Sony
|
This is a Video4Linux2 sensor driver for the Sony
|
||||||
IMX415 camera.
|
IMX415 camera.
|
||||||
@@ -260,35 +205,25 @@ config VIDEO_MAX9271_LIB
|
|||||||
|
|
||||||
config VIDEO_MT9M001
|
config VIDEO_MT9M001
|
||||||
tristate "mt9m001 support"
|
tristate "mt9m001 support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This driver supports MT9M001 cameras from Micron, monochrome
|
This driver supports MT9M001 cameras from Micron, monochrome
|
||||||
and colour models.
|
and colour models.
|
||||||
|
|
||||||
config VIDEO_MT9M111
|
config VIDEO_MT9M111
|
||||||
tristate "mt9m111, mt9m112 and mt9m131 support"
|
tristate "mt9m111, mt9m112 and mt9m131 support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This driver supports MT9M111, MT9M112 and MT9M131 cameras from
|
This driver supports MT9M111, MT9M112 and MT9M131 cameras from
|
||||||
Micron/Aptina
|
Micron/Aptina
|
||||||
|
|
||||||
config VIDEO_MT9P031
|
config VIDEO_MT9P031
|
||||||
tristate "Aptina MT9P031 support"
|
tristate "Aptina MT9P031 support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select VIDEO_APTINA_PLL
|
select VIDEO_APTINA_PLL
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Aptina
|
This is a Video4Linux2 sensor driver for the Aptina
|
||||||
(Micron) mt9p031 5 Mpixel camera.
|
(Micron) mt9p031 5 Mpixel camera.
|
||||||
|
|
||||||
config VIDEO_MT9T112
|
config VIDEO_MT9T112
|
||||||
tristate "Aptina MT9T111/MT9T112 support"
|
tristate "Aptina MT9T111/MT9T112 support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Aptina
|
This is a Video4Linux2 sensor driver for the Aptina
|
||||||
(Micron) MT9T111 and MT9T112 3 Mpixel camera.
|
(Micron) MT9T111 and MT9T112 3 Mpixel camera.
|
||||||
@@ -298,7 +233,6 @@ config VIDEO_MT9T112
|
|||||||
|
|
||||||
config VIDEO_MT9V011
|
config VIDEO_MT9V011
|
||||||
tristate "Micron mt9v011 sensor support"
|
tristate "Micron mt9v011 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Micron
|
This is a Video4Linux2 sensor driver for the Micron
|
||||||
mt0v011 1.3 Mpixel camera. It currently only works with the
|
mt0v011 1.3 Mpixel camera. It currently only works with the
|
||||||
@@ -306,18 +240,13 @@ config VIDEO_MT9V011
|
|||||||
|
|
||||||
config VIDEO_MT9V032
|
config VIDEO_MT9V032
|
||||||
tristate "Micron MT9V032 sensor support"
|
tristate "Micron MT9V032 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Micron
|
This is a Video4Linux2 sensor driver for the Micron
|
||||||
MT9V032 752x480 CMOS sensor.
|
MT9V032 752x480 CMOS sensor.
|
||||||
|
|
||||||
config VIDEO_MT9V111
|
config VIDEO_MT9V111
|
||||||
tristate "Aptina MT9V111 sensor support"
|
tristate "Aptina MT9V111 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Aptina/Micron
|
This is a Video4Linux2 sensor driver for the Aptina/Micron
|
||||||
MT9V111 sensor.
|
MT9V111 sensor.
|
||||||
@@ -327,10 +256,6 @@ config VIDEO_MT9V111
|
|||||||
|
|
||||||
config VIDEO_OG01A1B
|
config VIDEO_OG01A1B
|
||||||
tristate "OmniVision OG01A1B sensor support"
|
tristate "OmniVision OG01A1B sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OG01A1B camera.
|
OG01A1B camera.
|
||||||
@@ -340,10 +265,6 @@ config VIDEO_OG01A1B
|
|||||||
|
|
||||||
config VIDEO_OV01A10
|
config VIDEO_OV01A10
|
||||||
tristate "OmniVision OV01A10 sensor support"
|
tristate "OmniVision OV01A10 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV01A10 camera.
|
OV01A10 camera.
|
||||||
@@ -353,10 +274,6 @@ config VIDEO_OV01A10
|
|||||||
|
|
||||||
config VIDEO_OV02A10
|
config VIDEO_OV02A10
|
||||||
tristate "OmniVision OV02A10 sensor support"
|
tristate "OmniVision OV02A10 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV02A10 camera.
|
OV02A10 camera.
|
||||||
@@ -366,10 +283,6 @@ config VIDEO_OV02A10
|
|||||||
|
|
||||||
config VIDEO_OV08D10
|
config VIDEO_OV08D10
|
||||||
tristate "OmniVision OV08D10 sensor support"
|
tristate "OmniVision OV08D10 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV08D10 camera sensor.
|
OV08D10 camera sensor.
|
||||||
@@ -379,10 +292,6 @@ config VIDEO_OV08D10
|
|||||||
|
|
||||||
config VIDEO_OV08X40
|
config VIDEO_OV08X40
|
||||||
tristate "OmniVision OV08X40 sensor support"
|
tristate "OmniVision OV08X40 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV08X40 camera.
|
OV08X40 camera.
|
||||||
@@ -392,28 +301,18 @@ config VIDEO_OV08X40
|
|||||||
|
|
||||||
config VIDEO_OV13858
|
config VIDEO_OV13858
|
||||||
tristate "OmniVision OV13858 sensor support"
|
tristate "OmniVision OV13858 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV13858 camera.
|
OV13858 camera.
|
||||||
|
|
||||||
config VIDEO_OV13B10
|
config VIDEO_OV13B10
|
||||||
tristate "OmniVision OV13B10 sensor support"
|
tristate "OmniVision OV13B10 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV13B10 camera.
|
OV13B10 camera.
|
||||||
|
|
||||||
config VIDEO_OV2640
|
config VIDEO_OV2640
|
||||||
tristate "OmniVision OV2640 sensor support"
|
tristate "OmniVision OV2640 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
select V4L2_ASYNC
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV2640 camera.
|
OV2640 camera.
|
||||||
@@ -423,8 +322,7 @@ config VIDEO_OV2640
|
|||||||
|
|
||||||
config VIDEO_OV2659
|
config VIDEO_OV2659
|
||||||
tristate "OmniVision OV2659 sensor support"
|
tristate "OmniVision OV2659 sensor support"
|
||||||
depends on VIDEO_DEV && I2C && GPIOLIB
|
depends on GPIOLIB
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV2659 camera.
|
OV2659 camera.
|
||||||
@@ -434,9 +332,7 @@ config VIDEO_OV2659
|
|||||||
|
|
||||||
config VIDEO_OV2680
|
config VIDEO_OV2680
|
||||||
tristate "OmniVision OV2680 sensor support"
|
tristate "OmniVision OV2680 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
select V4L2_CCI_I2C
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV2680 camera.
|
OV2680 camera.
|
||||||
@@ -446,10 +342,6 @@ config VIDEO_OV2680
|
|||||||
|
|
||||||
config VIDEO_OV2685
|
config VIDEO_OV2685
|
||||||
tristate "OmniVision OV2685 sensor support"
|
tristate "OmniVision OV2685 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV2685 camera.
|
OV2685 camera.
|
||||||
@@ -459,11 +351,7 @@ config VIDEO_OV2685
|
|||||||
|
|
||||||
config VIDEO_OV2740
|
config VIDEO_OV2740
|
||||||
tristate "OmniVision OV2740 sensor support"
|
tristate "OmniVision OV2740 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
depends on ACPI || COMPILE_TEST
|
depends on ACPI || COMPILE_TEST
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
@@ -474,10 +362,7 @@ config VIDEO_OV2740
|
|||||||
|
|
||||||
config VIDEO_OV4689
|
config VIDEO_OV4689
|
||||||
tristate "OmniVision OV4689 sensor support"
|
tristate "OmniVision OV4689 sensor support"
|
||||||
depends on GPIOLIB && VIDEO_DEV && I2C
|
depends on GPIOLIB
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||||
OV4689 camera.
|
OV4689 camera.
|
||||||
@@ -488,10 +373,7 @@ config VIDEO_OV4689
|
|||||||
config VIDEO_OV5640
|
config VIDEO_OV5640
|
||||||
tristate "OmniVision OV5640 sensor support"
|
tristate "OmniVision OV5640 sensor support"
|
||||||
depends on OF
|
depends on OF
|
||||||
depends on GPIOLIB && VIDEO_DEV && I2C
|
depends on GPIOLIB
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the Omnivision
|
This is a Video4Linux2 sensor driver for the Omnivision
|
||||||
OV5640 camera sensor with a MIPI CSI-2 interface.
|
OV5640 camera sensor with a MIPI CSI-2 interface.
|
||||||
@@ -499,10 +381,6 @@ config VIDEO_OV5640
|
|||||||
config VIDEO_OV5645
|
config VIDEO_OV5645
|
||||||
tristate "OmniVision OV5645 sensor support"
|
tristate "OmniVision OV5645 sensor support"
|
||||||
depends on OF
|
depends on OF
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5645 camera.
|
OV5645 camera.
|
||||||
@@ -512,10 +390,6 @@ config VIDEO_OV5645
|
|||||||
|
|
||||||
config VIDEO_OV5647
|
config VIDEO_OV5647
|
||||||
tristate "OmniVision OV5647 sensor support"
|
tristate "OmniVision OV5647 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5647 camera.
|
OV5647 camera.
|
||||||
@@ -525,10 +399,7 @@ config VIDEO_OV5647
|
|||||||
|
|
||||||
config VIDEO_OV5648
|
config VIDEO_OV5648
|
||||||
tristate "OmniVision OV5648 sensor support"
|
tristate "OmniVision OV5648 sensor support"
|
||||||
depends on I2C && PM && VIDEO_DEV
|
depends on PM
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5648 camera.
|
OV5648 camera.
|
||||||
@@ -538,10 +409,6 @@ config VIDEO_OV5648
|
|||||||
|
|
||||||
config VIDEO_OV5670
|
config VIDEO_OV5670
|
||||||
tristate "OmniVision OV5670 sensor support"
|
tristate "OmniVision OV5670 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5670 camera.
|
OV5670 camera.
|
||||||
@@ -551,10 +418,6 @@ config VIDEO_OV5670
|
|||||||
|
|
||||||
config VIDEO_OV5675
|
config VIDEO_OV5675
|
||||||
tristate "OmniVision OV5675 sensor support"
|
tristate "OmniVision OV5675 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5675 camera.
|
OV5675 camera.
|
||||||
@@ -564,8 +427,7 @@ config VIDEO_OV5675
|
|||||||
|
|
||||||
config VIDEO_OV5693
|
config VIDEO_OV5693
|
||||||
tristate "OmniVision OV5693 sensor support"
|
tristate "OmniVision OV5693 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
select V4L2_CCI_I2C
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5693 camera.
|
OV5693 camera.
|
||||||
@@ -575,8 +437,6 @@ config VIDEO_OV5693
|
|||||||
|
|
||||||
config VIDEO_OV5695
|
config VIDEO_OV5695
|
||||||
tristate "OmniVision OV5695 sensor support"
|
tristate "OmniVision OV5695 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV5695 camera.
|
OV5695 camera.
|
||||||
@@ -586,7 +446,6 @@ config VIDEO_OV5695
|
|||||||
|
|
||||||
config VIDEO_OV6650
|
config VIDEO_OV6650
|
||||||
tristate "OmniVision OV6650 sensor support"
|
tristate "OmniVision OV6650 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV6650 camera.
|
OV6650 camera.
|
||||||
@@ -596,10 +455,6 @@ config VIDEO_OV6650
|
|||||||
|
|
||||||
config VIDEO_OV7251
|
config VIDEO_OV7251
|
||||||
tristate "OmniVision OV7251 sensor support"
|
tristate "OmniVision OV7251 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV7251 camera.
|
OV7251 camera.
|
||||||
@@ -609,7 +464,6 @@ config VIDEO_OV7251
|
|||||||
|
|
||||||
config VIDEO_OV7640
|
config VIDEO_OV7640
|
||||||
tristate "OmniVision OV7640 sensor support"
|
tristate "OmniVision OV7640 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV7640 camera.
|
OV7640 camera.
|
||||||
@@ -619,8 +473,6 @@ config VIDEO_OV7640
|
|||||||
|
|
||||||
config VIDEO_OV7670
|
config VIDEO_OV7670
|
||||||
tristate "OmniVision OV7670 sensor support"
|
tristate "OmniVision OV7670 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV7670 VGA camera. It currently only works with the M88ALP01
|
OV7670 VGA camera. It currently only works with the M88ALP01
|
||||||
@@ -628,9 +480,7 @@ config VIDEO_OV7670
|
|||||||
|
|
||||||
config VIDEO_OV772X
|
config VIDEO_OV772X
|
||||||
tristate "OmniVision OV772x sensor support"
|
tristate "OmniVision OV772x sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select REGMAP_SCCB
|
select REGMAP_SCCB
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV772x camera.
|
OV772x camera.
|
||||||
@@ -640,7 +490,6 @@ config VIDEO_OV772X
|
|||||||
|
|
||||||
config VIDEO_OV7740
|
config VIDEO_OV7740
|
||||||
tristate "OmniVision OV7740 sensor support"
|
tristate "OmniVision OV7740 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select REGMAP_SCCB
|
select REGMAP_SCCB
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
@@ -648,10 +497,6 @@ config VIDEO_OV7740
|
|||||||
|
|
||||||
config VIDEO_OV8856
|
config VIDEO_OV8856
|
||||||
tristate "OmniVision OV8856 sensor support"
|
tristate "OmniVision OV8856 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV8856 camera sensor.
|
OV8856 camera sensor.
|
||||||
@@ -661,10 +506,7 @@ config VIDEO_OV8856
|
|||||||
|
|
||||||
config VIDEO_OV8858
|
config VIDEO_OV8858
|
||||||
tristate "OmniVision OV8858 sensor support"
|
tristate "OmniVision OV8858 sensor support"
|
||||||
depends on I2C && PM && VIDEO_DEV
|
depends on PM
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for OmniVision
|
This is a Video4Linux2 sensor driver for OmniVision
|
||||||
OV8858 camera sensor.
|
OV8858 camera sensor.
|
||||||
@@ -674,10 +516,7 @@ config VIDEO_OV8858
|
|||||||
|
|
||||||
config VIDEO_OV8865
|
config VIDEO_OV8865
|
||||||
tristate "OmniVision OV8865 sensor support"
|
tristate "OmniVision OV8865 sensor support"
|
||||||
depends on I2C && PM && VIDEO_DEV
|
depends on PM
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for OmniVision
|
This is a Video4Linux2 sensor driver for OmniVision
|
||||||
OV8865 camera sensor.
|
OV8865 camera sensor.
|
||||||
@@ -688,10 +527,6 @@ config VIDEO_OV8865
|
|||||||
config VIDEO_OV9282
|
config VIDEO_OV9282
|
||||||
tristate "OmniVision OV9282 sensor support"
|
tristate "OmniVision OV9282 sensor support"
|
||||||
depends on OF_GPIO
|
depends on OF_GPIO
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV9282 camera sensor.
|
OV9282 camera sensor.
|
||||||
@@ -701,16 +536,12 @@ config VIDEO_OV9282
|
|||||||
|
|
||||||
config VIDEO_OV9640
|
config VIDEO_OV9640
|
||||||
tristate "OmniVision OV9640 sensor support"
|
tristate "OmniVision OV9640 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV9640 camera sensor.
|
OV9640 camera sensor.
|
||||||
|
|
||||||
config VIDEO_OV9650
|
config VIDEO_OV9650
|
||||||
tristate "OmniVision OV9650/OV9652 sensor support"
|
tristate "OmniVision OV9650/OV9652 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select REGMAP_SCCB
|
select REGMAP_SCCB
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for the Omnivision
|
This is a V4L2 sensor driver for the Omnivision
|
||||||
@@ -718,11 +549,7 @@ config VIDEO_OV9650
|
|||||||
|
|
||||||
config VIDEO_OV9734
|
config VIDEO_OV9734
|
||||||
tristate "OmniVision OV9734 sensor support"
|
tristate "OmniVision OV9734 sensor support"
|
||||||
depends on VIDEO_DEV && I2C
|
|
||||||
depends on ACPI || COMPILE_TEST
|
depends on ACPI || COMPILE_TEST
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the OmniVision
|
This is a Video4Linux2 sensor driver for the OmniVision
|
||||||
OV9734 camera.
|
OV9734 camera.
|
||||||
@@ -732,10 +559,6 @@ config VIDEO_OV9734
|
|||||||
|
|
||||||
config VIDEO_RDACM20
|
config VIDEO_RDACM20
|
||||||
tristate "IMI RDACM20 camera support"
|
tristate "IMI RDACM20 camera support"
|
||||||
depends on I2C
|
|
||||||
select V4L2_FWNODE
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_MAX9271_LIB
|
select VIDEO_MAX9271_LIB
|
||||||
help
|
help
|
||||||
This driver supports the IMI RDACM20 GMSL camera, used in
|
This driver supports the IMI RDACM20 GMSL camera, used in
|
||||||
@@ -746,10 +569,6 @@ config VIDEO_RDACM20
|
|||||||
|
|
||||||
config VIDEO_RDACM21
|
config VIDEO_RDACM21
|
||||||
tristate "IMI RDACM21 camera support"
|
tristate "IMI RDACM21 camera support"
|
||||||
depends on I2C
|
|
||||||
select V4L2_FWNODE
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_MAX9271_LIB
|
select VIDEO_MAX9271_LIB
|
||||||
help
|
help
|
||||||
This driver supports the IMI RDACM21 GMSL camera, used in
|
This driver supports the IMI RDACM21 GMSL camera, used in
|
||||||
@@ -760,7 +579,6 @@ config VIDEO_RDACM21
|
|||||||
|
|
||||||
config VIDEO_RJ54N1
|
config VIDEO_RJ54N1
|
||||||
tristate "Sharp RJ54N1CB0C sensor support"
|
tristate "Sharp RJ54N1CB0C sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for Sharp RJ54N1CB0C CMOS image
|
This is a V4L2 sensor driver for Sharp RJ54N1CB0C CMOS image
|
||||||
sensor.
|
sensor.
|
||||||
@@ -770,39 +588,26 @@ config VIDEO_RJ54N1
|
|||||||
|
|
||||||
config VIDEO_S5C73M3
|
config VIDEO_S5C73M3
|
||||||
tristate "Samsung S5C73M3 sensor support"
|
tristate "Samsung S5C73M3 sensor support"
|
||||||
depends on I2C && SPI && VIDEO_DEV
|
depends on SPI
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for Samsung S5C73M3
|
This is a V4L2 sensor driver for Samsung S5C73M3
|
||||||
8 Mpixel camera.
|
8 Mpixel camera.
|
||||||
|
|
||||||
config VIDEO_S5K5BAF
|
config VIDEO_S5K5BAF
|
||||||
tristate "Samsung S5K5BAF sensor support"
|
tristate "Samsung S5K5BAF sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for Samsung S5K5BAF 2M
|
This is a V4L2 sensor driver for Samsung S5K5BAF 2M
|
||||||
camera sensor with an embedded SoC image signal processor.
|
camera sensor with an embedded SoC image signal processor.
|
||||||
|
|
||||||
config VIDEO_S5K6A3
|
config VIDEO_S5K6A3
|
||||||
tristate "Samsung S5K6A3 sensor support"
|
tristate "Samsung S5K6A3 sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
help
|
help
|
||||||
This is a V4L2 sensor driver for Samsung S5K6A3 raw
|
This is a V4L2 sensor driver for Samsung S5K6A3 raw
|
||||||
camera sensor.
|
camera sensor.
|
||||||
|
|
||||||
config VIDEO_ST_VGXY61
|
config VIDEO_ST_VGXY61
|
||||||
tristate "ST VGXY61 sensor support"
|
tristate "ST VGXY61 sensor support"
|
||||||
depends on OF && GPIOLIB && VIDEO_DEV && I2C
|
depends on OF && GPIOLIB
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a Video4Linux2 sensor driver for the ST VGXY61
|
This is a Video4Linux2 sensor driver for the ST VGXY61
|
||||||
camera sensor.
|
camera sensor.
|
||||||
@@ -810,7 +615,7 @@ config VIDEO_ST_VGXY61
|
|||||||
source "drivers/media/i2c/ccs/Kconfig"
|
source "drivers/media/i2c/ccs/Kconfig"
|
||||||
source "drivers/media/i2c/et8ek8/Kconfig"
|
source "drivers/media/i2c/et8ek8/Kconfig"
|
||||||
|
|
||||||
endmenu
|
endif
|
||||||
|
|
||||||
menu "Lens drivers"
|
menu "Lens drivers"
|
||||||
visible if MEDIA_CAMERA_SUPPORT
|
visible if MEDIA_CAMERA_SUPPORT
|
||||||
@@ -848,6 +653,18 @@ config VIDEO_DW9714
|
|||||||
capability. This is designed for linear control of
|
capability. This is designed for linear control of
|
||||||
voice coil motors, controlled via I2C serial interface.
|
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
|
config VIDEO_DW9768
|
||||||
tristate "DW9768 lens voice coil support"
|
tristate "DW9768 lens voice coil support"
|
||||||
depends on I2C && VIDEO_DEV
|
depends on I2C && VIDEO_DEV
|
||||||
@@ -1625,4 +1442,51 @@ config VIDEO_THS7303
|
|||||||
|
|
||||||
endmenu
|
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
|
endif # VIDEO_DEV
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
|
|||||||
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
|
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
|
||||||
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
|
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
|
||||||
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
|
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_DW9714) += dw9714.o
|
||||||
|
obj-$(CONFIG_VIDEO_DW9719) += dw9719.o
|
||||||
obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
|
obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
|
||||||
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
|
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
|
||||||
obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
|
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[] = {
|
static const struct i2c_device_id ad5820_id_table[] = {
|
||||||
{ "ad5820", 0 },
|
{ "ad5820", 0 },
|
||||||
{ "ad5821", 0 },
|
{ "ad5821", 0 },
|
||||||
{ "ad5823", 0 },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, ad5820_id_table);
|
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[] = {
|
static const struct of_device_id ad5820_of_table[] = {
|
||||||
{ .compatible = "adi,ad5820" },
|
{ .compatible = "adi,ad5820" },
|
||||||
{ .compatible = "adi,ad5821" },
|
{ .compatible = "adi,ad5821" },
|
||||||
{ .compatible = "adi,ad5823" },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, ad5820_of_table);
|
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,
|
MEDIA_ENT_F_VID_IF_BRIDGE,
|
||||||
is_txa(tx) ? "txa" : "txb");
|
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 */
|
/* Register internal ops for incremental subdev registration */
|
||||||
tx->sd.internal_ops = &adv748x_csi2_internal_ops;
|
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)
|
if (ret)
|
||||||
return 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)
|
if (ret)
|
||||||
goto err_free_media;
|
goto err_free_media;
|
||||||
|
|
||||||
|
ret = adv748x_csi2_init_controls(tx);
|
||||||
|
if (ret)
|
||||||
|
goto err_cleanup_subdev;
|
||||||
|
|
||||||
ret = v4l2_async_register_subdev(&tx->sd);
|
ret = v4l2_async_register_subdev(&tx->sd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_ctrl;
|
goto err_free_ctrl;
|
||||||
@@ -326,6 +328,8 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
|
|||||||
|
|
||||||
err_free_ctrl:
|
err_free_ctrl:
|
||||||
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
|
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
|
||||||
|
err_cleanup_subdev:
|
||||||
|
v4l2_subdev_cleanup(&tx->sd);
|
||||||
err_free_media:
|
err_free_media:
|
||||||
media_entity_cleanup(&tx->sd.entity);
|
media_entity_cleanup(&tx->sd.entity);
|
||||||
|
|
||||||
@@ -340,4 +344,5 @@ void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
|
|||||||
v4l2_async_unregister_subdev(&tx->sd);
|
v4l2_async_unregister_subdev(&tx->sd);
|
||||||
media_entity_cleanup(&tx->sd.entity);
|
media_entity_cleanup(&tx->sd.entity);
|
||||||
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
|
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_fr *pll_fr = &pll->vt_fr;
|
||||||
struct ccs_pll_branch_bk *pll_bk = &pll->vt_bk;
|
struct ccs_pll_branch_bk *pll_bk = &pll->vt_bk;
|
||||||
u32 more_mul;
|
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;
|
u16 vt_div, min_sys_div, max_sys_div, sys_div;
|
||||||
|
|
||||||
pll_fr->pll_ip_clk_freq_hz =
|
pll_fr->pll_ip_clk_freq_hz =
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
config VIDEO_CCS
|
config VIDEO_CCS
|
||||||
tristate "MIPI CCS/SMIA++/SMIA sensor support"
|
tristate "MIPI CCS/SMIA++/SMIA sensor support"
|
||||||
depends on I2C && VIDEO_DEV && HAVE_CLK
|
depends on HAVE_CLK
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select VIDEO_CCS_PLL
|
select VIDEO_CCS_PLL
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant
|
This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant
|
||||||
camera sensors.
|
camera sensors.
|
||||||
|
|||||||
@@ -464,8 +464,7 @@ static int ccs_data_parse_rules(struct bin_container *bin,
|
|||||||
rule_payload = __rule_type + 1;
|
rule_payload = __rule_type + 1;
|
||||||
rule_plen2 = rule_plen - sizeof(*__rule_type);
|
rule_plen2 = rule_plen - sizeof(*__rule_type);
|
||||||
|
|
||||||
switch (*__rule_type) {
|
if (*__rule_type == CCS_DATA_BLOCK_RULE_ID_IF) {
|
||||||
case CCS_DATA_BLOCK_RULE_ID_IF: {
|
|
||||||
const struct __ccs_data_block_rule_if *__if_rules =
|
const struct __ccs_data_block_rule_if *__if_rules =
|
||||||
rule_payload;
|
rule_payload;
|
||||||
const size_t __num_if_rules =
|
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->if_rules = if_rule;
|
||||||
rules->num_if_rules = __num_if_rules;
|
rules->num_if_rules = __num_if_rules;
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
}
|
/* Check there was an if rule before any other rules */
|
||||||
case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
|
if (bin->base && !rules)
|
||||||
rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
|
return -EINVAL;
|
||||||
&rules->num_read_only_regs,
|
|
||||||
rule_payload,
|
switch (*__rule_type) {
|
||||||
rule_payload + rule_plen2,
|
case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
|
||||||
dev);
|
rval = ccs_data_parse_reg_rules(bin,
|
||||||
if (rval)
|
rules ?
|
||||||
return rval;
|
&rules->read_only_regs : NULL,
|
||||||
break;
|
rules ?
|
||||||
case CCS_DATA_BLOCK_RULE_ID_FFD:
|
&rules->num_read_only_regs : NULL,
|
||||||
rval = ccs_data_parse_ffd(bin, &rules->frame_format,
|
rule_payload,
|
||||||
rule_payload,
|
rule_payload + rule_plen2,
|
||||||
rule_payload + rule_plen2,
|
dev);
|
||||||
dev);
|
if (rval)
|
||||||
if (rval)
|
return rval;
|
||||||
return rval;
|
break;
|
||||||
break;
|
case CCS_DATA_BLOCK_RULE_ID_FFD:
|
||||||
case CCS_DATA_BLOCK_RULE_ID_MSR:
|
rval = ccs_data_parse_ffd(bin, rules ?
|
||||||
rval = ccs_data_parse_reg_rules(bin,
|
&rules->frame_format : NULL,
|
||||||
&rules->manufacturer_regs,
|
rule_payload,
|
||||||
&rules->num_manufacturer_regs,
|
rule_payload + rule_plen2,
|
||||||
rule_payload,
|
dev);
|
||||||
rule_payload + rule_plen2,
|
if (rval)
|
||||||
dev);
|
return rval;
|
||||||
if (rval)
|
break;
|
||||||
return rval;
|
case CCS_DATA_BLOCK_RULE_ID_MSR:
|
||||||
break;
|
rval = ccs_data_parse_reg_rules(bin,
|
||||||
case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
|
rules ?
|
||||||
rval = ccs_data_parse_pdaf_readout(bin,
|
&rules->manufacturer_regs : NULL,
|
||||||
&rules->pdaf_readout,
|
rules ?
|
||||||
rule_payload,
|
&rules->num_manufacturer_regs : NULL,
|
||||||
rule_payload + rule_plen2,
|
rule_payload,
|
||||||
dev);
|
rule_payload + rule_plen2,
|
||||||
if (rval)
|
dev);
|
||||||
return rval;
|
if (rval)
|
||||||
break;
|
return rval;
|
||||||
default:
|
break;
|
||||||
dev_dbg(dev,
|
case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
|
||||||
"Don't know how to handle rule type %u!\n",
|
rval = ccs_data_parse_pdaf_readout(bin,
|
||||||
*__rule_type);
|
rules ?
|
||||||
return -EINVAL;
|
&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;
|
__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
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
config VIDEO_ET8EK8
|
config VIDEO_ET8EK8
|
||||||
tristate "ET8EK8 camera sensor support"
|
tristate "ET8EK8 camera sensor support"
|
||||||
depends on I2C && VIDEO_DEV
|
|
||||||
select MEDIA_CONTROLLER
|
|
||||||
select VIDEO_V4L2_SUBDEV_API
|
|
||||||
select V4L2_FWNODE
|
|
||||||
help
|
help
|
||||||
This is a driver for the Toshiba ET8EK8 5 MP camera sensor.
|
This is a driver for the Toshiba ET8EK8 5 MP camera sensor.
|
||||||
It is used for example in Nokia N900 (RX-51).
|
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_i2c_driver(hi556_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
|
MODULE_AUTHOR("Shawn Tu");
|
||||||
MODULE_DESCRIPTION("Hynix HI556 sensor driver");
|
MODULE_DESCRIPTION("Hynix HI556 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -3005,6 +3005,6 @@ static struct i2c_driver hi847_i2c_driver = {
|
|||||||
|
|
||||||
module_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_DESCRIPTION("Hynix HI847 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -1109,6 +1109,6 @@ module_i2c_driver(imx208_i2c_driver);
|
|||||||
|
|
||||||
MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
|
MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
|
||||||
MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@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_DESCRIPTION("Sony IMX208 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ static const char * const imx219_supply_name[] = {
|
|||||||
* - v flip
|
* - v flip
|
||||||
* - h&v flips
|
* - h&v flips
|
||||||
*/
|
*/
|
||||||
static const u32 codes[] = {
|
static const u32 imx219_mbus_formats[] = {
|
||||||
MEDIA_BUS_FMT_SRGGB10_1X10,
|
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||||
@@ -460,8 +460,6 @@ struct imx219 {
|
|||||||
struct v4l2_subdev sd;
|
struct v4l2_subdev sd;
|
||||||
struct media_pad pad;
|
struct media_pad pad;
|
||||||
|
|
||||||
struct v4l2_mbus_framefmt fmt;
|
|
||||||
|
|
||||||
struct clk *xclk; /* system clock to IMX219 */
|
struct clk *xclk; /* system clock to IMX219 */
|
||||||
u32 xclk_freq;
|
u32 xclk_freq;
|
||||||
|
|
||||||
@@ -481,12 +479,6 @@ struct imx219 {
|
|||||||
/* Current mode */
|
/* Current mode */
|
||||||
const struct imx219_mode *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 */
|
/* Streaming on/off */
|
||||||
bool streaming;
|
bool streaming;
|
||||||
|
|
||||||
@@ -576,64 +568,17 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
lockdep_assert_held(&imx219->mutex);
|
for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++)
|
||||||
|
if (imx219_mbus_formats[i] == code)
|
||||||
for (i = 0; i < ARRAY_SIZE(codes); i++)
|
|
||||||
if (codes[i] == code)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i >= ARRAY_SIZE(codes))
|
if (i >= ARRAY_SIZE(imx219_mbus_formats))
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
|
i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
|
||||||
(imx219->hflip->val ? 1 : 0);
|
(imx219->hflip->val ? 1 : 0);
|
||||||
|
|
||||||
return codes[i];
|
return imx219_mbus_formats[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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
|
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,
|
.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,
|
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
|
||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_mbus_code_enum *code)
|
struct v4l2_subdev_mbus_code_enum *code)
|
||||||
{
|
{
|
||||||
struct imx219 *imx219 = to_imx219(sd);
|
struct imx219 *imx219 = to_imx219(sd);
|
||||||
|
|
||||||
if (code->index >= (ARRAY_SIZE(codes) / 4))
|
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&imx219->mutex);
|
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
|
||||||
code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
|
|
||||||
mutex_unlock(&imx219->mutex);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -751,9 +730,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
|
|||||||
if (fse->index >= ARRAY_SIZE(supported_modes))
|
if (fse->index >= ARRAY_SIZE(supported_modes))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&imx219->mutex);
|
|
||||||
code = imx219_get_format_code(imx219, fse->code);
|
code = imx219_get_format_code(imx219, fse->code);
|
||||||
mutex_unlock(&imx219->mutex);
|
|
||||||
if (fse->code != code)
|
if (fse->code != code)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -765,92 +742,27 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
|
|||||||
return 0;
|
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,
|
static int imx219_set_pad_format(struct v4l2_subdev *sd,
|
||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_format *fmt)
|
struct v4l2_subdev_format *fmt)
|
||||||
{
|
{
|
||||||
struct imx219 *imx219 = to_imx219(sd);
|
struct imx219 *imx219 = to_imx219(sd);
|
||||||
const struct imx219_mode *mode;
|
const struct imx219_mode *mode;
|
||||||
struct v4l2_mbus_framefmt *framefmt;
|
|
||||||
int exposure_max, exposure_def, hblank;
|
int exposure_max, exposure_def, hblank;
|
||||||
unsigned int i;
|
struct v4l2_mbus_framefmt *format;
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
mode = v4l2_find_nearest_size(supported_modes,
|
mode = v4l2_find_nearest_size(supported_modes,
|
||||||
ARRAY_SIZE(supported_modes),
|
ARRAY_SIZE(supported_modes),
|
||||||
width, height,
|
width, height,
|
||||||
fmt->format.width, fmt->format.height);
|
fmt->format.width, fmt->format.height);
|
||||||
imx219_update_pad_format(imx219, mode, fmt);
|
|
||||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
|
||||||
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
|
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
|
||||||
*framefmt = fmt->format;
|
|
||||||
} else if (imx219->mode != mode ||
|
if (imx219->mode == mode && format->code == fmt->format.code)
|
||||||
imx219->fmt.code != fmt->format.code) {
|
return 0;
|
||||||
imx219->fmt = fmt->format;
|
|
||||||
|
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||||
imx219->mode = mode;
|
imx219->mode = mode;
|
||||||
/* Update limits and set FPS to default */
|
/* Update limits and set FPS to default */
|
||||||
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
|
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
|
||||||
@@ -876,14 +788,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
|
|||||||
hblank);
|
hblank);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&imx219->mutex);
|
*format = fmt->format;
|
||||||
|
|
||||||
return 0;
|
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_SRGGB8_1X8:
|
||||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||||
@@ -902,7 +815,8 @@ static int imx219_set_framefmt(struct imx219 *imx219)
|
|||||||
return -EINVAL;
|
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) {
|
if (!imx219->mode->binning) {
|
||||||
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
||||||
@@ -910,7 +824,7 @@ static int imx219_set_binning(struct imx219 *imx219)
|
|||||||
IMX219_BINNING_NONE);
|
IMX219_BINNING_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (imx219->fmt.code) {
|
switch (format->code) {
|
||||||
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||||
@@ -931,34 +845,13 @@ static int imx219_set_binning(struct imx219 *imx219)
|
|||||||
return -EINVAL;
|
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,
|
static int imx219_get_selection(struct v4l2_subdev *sd,
|
||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_selection *sel)
|
struct v4l2_subdev_selection *sel)
|
||||||
{
|
{
|
||||||
switch (sel->target) {
|
switch (sel->target) {
|
||||||
case V4L2_SEL_TGT_CROP: {
|
case V4L2_SEL_TGT_CROP: {
|
||||||
struct imx219 *imx219 = to_imx219(sd);
|
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
|
||||||
|
|
||||||
mutex_lock(&imx219->mutex);
|
|
||||||
sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
|
|
||||||
sel->which);
|
|
||||||
mutex_unlock(&imx219->mutex);
|
|
||||||
|
|
||||||
return 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);
|
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);
|
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
|
||||||
|
const struct v4l2_mbus_framefmt *format;
|
||||||
const struct imx219_reg_list *reg_list;
|
const struct imx219_reg_list *reg_list;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1022,14 +917,15 @@ static int imx219_start_streaming(struct imx219 *imx219)
|
|||||||
goto err_rpm_put;
|
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) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "%s failed to set frame format: %d\n",
|
dev_err(&client->dev, "%s failed to set frame format: %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
goto err_rpm_put;
|
goto err_rpm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = imx219_set_binning(imx219);
|
ret = imx219_set_binning(imx219, format);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "%s failed to set binning: %d\n",
|
dev_err(&client->dev, "%s failed to set binning: %d\n",
|
||||||
__func__, ret);
|
__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)
|
static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
|
||||||
{
|
{
|
||||||
struct imx219 *imx219 = to_imx219(sd);
|
struct imx219 *imx219 = to_imx219(sd);
|
||||||
|
struct v4l2_subdev_state *state;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&imx219->mutex);
|
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||||
if (imx219->streaming == enable) {
|
|
||||||
mutex_unlock(&imx219->mutex);
|
if (imx219->streaming == enable)
|
||||||
return 0;
|
goto unlock;
|
||||||
}
|
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
/*
|
/*
|
||||||
* Apply default & customized values
|
* Apply default & customized values
|
||||||
* and then start streaming.
|
* and then start streaming.
|
||||||
*/
|
*/
|
||||||
ret = imx219_start_streaming(imx219);
|
ret = imx219_start_streaming(imx219, state);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_unlock;
|
goto unlock;
|
||||||
} else {
|
} else {
|
||||||
imx219_stop_streaming(imx219);
|
imx219_stop_streaming(imx219);
|
||||||
}
|
}
|
||||||
|
|
||||||
imx219->streaming = enable;
|
imx219->streaming = enable;
|
||||||
|
|
||||||
mutex_unlock(&imx219->mutex);
|
unlock:
|
||||||
|
v4l2_subdev_unlock_state(state);
|
||||||
return ret;
|
|
||||||
|
|
||||||
err_unlock:
|
|
||||||
mutex_unlock(&imx219->mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,10 +1062,13 @@ static int __maybe_unused imx219_resume(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||||
struct imx219 *imx219 = to_imx219(sd);
|
struct imx219 *imx219 = to_imx219(sd);
|
||||||
|
struct v4l2_subdev_state *state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (imx219->streaming) {
|
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)
|
if (ret)
|
||||||
goto error;
|
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 = {
|
static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
|
||||||
|
.init_cfg = imx219_init_cfg,
|
||||||
.enum_mbus_code = imx219_enum_mbus_code,
|
.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,
|
.set_fmt = imx219_set_pad_format,
|
||||||
.get_selection = imx219_get_selection,
|
.get_selection = imx219_get_selection,
|
||||||
.enum_frame_size = imx219_enum_frame_size,
|
.enum_frame_size = imx219_enum_frame_size,
|
||||||
@@ -1248,9 +1143,6 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = {
|
|||||||
.pad = &imx219_pad_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)
|
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
|
||||||
{
|
{
|
||||||
@@ -1272,9 +1164,6 @@ static int imx219_init_controls(struct imx219 *imx219)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mutex_init(&imx219->mutex);
|
|
||||||
ctrl_hdlr->lock = &imx219->mutex;
|
|
||||||
|
|
||||||
/* By default, PIXEL_RATE is read only */
|
/* By default, PIXEL_RATE is read only */
|
||||||
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
|
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
|
||||||
V4L2_CID_PIXEL_RATE,
|
V4L2_CID_PIXEL_RATE,
|
||||||
@@ -1371,7 +1260,6 @@ static int imx219_init_controls(struct imx219 *imx219)
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
v4l2_ctrl_handler_free(ctrl_hdlr);
|
v4l2_ctrl_handler_free(ctrl_hdlr);
|
||||||
mutex_destroy(&imx219->mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1379,7 +1267,6 @@ error:
|
|||||||
static void imx219_free_controls(struct imx219 *imx219)
|
static void imx219_free_controls(struct imx219 *imx219)
|
||||||
{
|
{
|
||||||
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
|
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
|
||||||
mutex_destroy(&imx219->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
|
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;
|
goto error_power_off;
|
||||||
|
|
||||||
/* Initialize subdev */
|
/* Initialize subdev */
|
||||||
imx219->sd.internal_ops = &imx219_internal_ops;
|
|
||||||
imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||||
imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||||
@@ -1517,19 +1403,23 @@ static int imx219_probe(struct i2c_client *client)
|
|||||||
/* Initialize source pad */
|
/* Initialize source pad */
|
||||||
imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
|
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);
|
ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to init entity pads: %d\n", ret);
|
dev_err(dev, "failed to init entity pads: %d\n", ret);
|
||||||
goto error_handler_free;
|
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);
|
ret = v4l2_async_register_subdev_sensor(&imx219->sd);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
|
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 */
|
/* Enable runtime PM and turn off the device */
|
||||||
@@ -1539,6 +1429,9 @@ static int imx219_probe(struct i2c_client *client)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error_subdev_cleanup:
|
||||||
|
v4l2_subdev_cleanup(&imx219->sd);
|
||||||
|
|
||||||
error_media_entity:
|
error_media_entity:
|
||||||
media_entity_cleanup(&imx219->sd.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);
|
struct imx219 *imx219 = to_imx219(sd);
|
||||||
|
|
||||||
v4l2_async_unregister_subdev(sd);
|
v4l2_async_unregister_subdev(sd);
|
||||||
|
v4l2_subdev_cleanup(sd);
|
||||||
media_entity_cleanup(&sd->entity);
|
media_entity_cleanup(&sd->entity);
|
||||||
imx219_free_controls(imx219);
|
imx219_free_controls(imx219);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
@@ -21,91 +21,86 @@
|
|||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include <media/media-entity.h>
|
#include <media/media-entity.h>
|
||||||
|
#include <media/v4l2-cci.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-event.h>
|
#include <media/v4l2-event.h>
|
||||||
#include <media/v4l2-fwnode.h>
|
#include <media/v4l2-fwnode.h>
|
||||||
#include <media/v4l2-subdev.h>
|
#include <media/v4l2-subdev.h>
|
||||||
|
|
||||||
#define IMX290_REG_SIZE_SHIFT 16
|
#define IMX290_STANDBY CCI_REG8(0x3000)
|
||||||
#define IMX290_REG_ADDR_MASK 0xffff
|
#define IMX290_REGHOLD CCI_REG8(0x3001)
|
||||||
#define IMX290_REG_8BIT(n) ((1U << IMX290_REG_SIZE_SHIFT) | (n))
|
#define IMX290_XMSTA CCI_REG8(0x3002)
|
||||||
#define IMX290_REG_16BIT(n) ((2U << IMX290_REG_SIZE_SHIFT) | (n))
|
#define IMX290_ADBIT CCI_REG8(0x3005)
|
||||||
#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_ADBIT_10BIT (0 << 0)
|
#define IMX290_ADBIT_10BIT (0 << 0)
|
||||||
#define IMX290_ADBIT_12BIT (1 << 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_VREVERSE BIT(0)
|
||||||
#define IMX290_HREVERSE BIT(1)
|
#define IMX290_HREVERSE BIT(1)
|
||||||
#define IMX290_WINMODE_1080P (0 << 4)
|
#define IMX290_WINMODE_1080P (0 << 4)
|
||||||
#define IMX290_WINMODE_720P (1 << 4)
|
#define IMX290_WINMODE_720P (1 << 4)
|
||||||
#define IMX290_WINMODE_CROP (4 << 4)
|
#define IMX290_WINMODE_CROP (4 << 4)
|
||||||
#define IMX290_FR_FDG_SEL IMX290_REG_8BIT(0x3009)
|
#define IMX290_FR_FDG_SEL CCI_REG8(0x3009)
|
||||||
#define IMX290_BLKLEVEL IMX290_REG_16BIT(0x300a)
|
#define IMX290_BLKLEVEL CCI_REG16(0x300a)
|
||||||
#define IMX290_GAIN IMX290_REG_8BIT(0x3014)
|
#define IMX290_GAIN CCI_REG8(0x3014)
|
||||||
#define IMX290_VMAX IMX290_REG_24BIT(0x3018)
|
#define IMX290_VMAX CCI_REG24(0x3018)
|
||||||
#define IMX290_VMAX_MAX 0x3ffff
|
#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_HMAX_MAX 0xffff
|
||||||
#define IMX290_SHS1 IMX290_REG_24BIT(0x3020)
|
#define IMX290_SHS1 CCI_REG24(0x3020)
|
||||||
#define IMX290_WINWV_OB IMX290_REG_8BIT(0x303a)
|
#define IMX290_WINWV_OB CCI_REG8(0x303a)
|
||||||
#define IMX290_WINPV IMX290_REG_16BIT(0x303c)
|
#define IMX290_WINPV CCI_REG16(0x303c)
|
||||||
#define IMX290_WINWV IMX290_REG_16BIT(0x303e)
|
#define IMX290_WINWV CCI_REG16(0x303e)
|
||||||
#define IMX290_WINPH IMX290_REG_16BIT(0x3040)
|
#define IMX290_WINPH CCI_REG16(0x3040)
|
||||||
#define IMX290_WINWH IMX290_REG_16BIT(0x3042)
|
#define IMX290_WINWH CCI_REG16(0x3042)
|
||||||
#define IMX290_OUT_CTRL IMX290_REG_8BIT(0x3046)
|
#define IMX290_OUT_CTRL CCI_REG8(0x3046)
|
||||||
#define IMX290_ODBIT_10BIT (0 << 0)
|
#define IMX290_ODBIT_10BIT (0 << 0)
|
||||||
#define IMX290_ODBIT_12BIT (1 << 0)
|
#define IMX290_ODBIT_12BIT (1 << 0)
|
||||||
#define IMX290_OPORTSEL_PARALLEL (0x0 << 4)
|
#define IMX290_OPORTSEL_PARALLEL (0x0 << 4)
|
||||||
#define IMX290_OPORTSEL_LVDS_2CH (0xd << 4)
|
#define IMX290_OPORTSEL_LVDS_2CH (0xd << 4)
|
||||||
#define IMX290_OPORTSEL_LVDS_4CH (0xe << 4)
|
#define IMX290_OPORTSEL_LVDS_4CH (0xe << 4)
|
||||||
#define IMX290_OPORTSEL_LVDS_8CH (0xf << 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_HIGH (0 << 0)
|
||||||
#define IMX290_XSOUTSEL_XVSOUTSEL_VSYNC (2 << 0)
|
#define IMX290_XSOUTSEL_XVSOUTSEL_VSYNC (2 << 0)
|
||||||
#define IMX290_XSOUTSEL_XHSOUTSEL_HIGH (0 << 2)
|
#define IMX290_XSOUTSEL_XHSOUTSEL_HIGH (0 << 2)
|
||||||
#define IMX290_XSOUTSEL_XHSOUTSEL_HSYNC (2 << 2)
|
#define IMX290_XSOUTSEL_XHSOUTSEL_HSYNC (2 << 2)
|
||||||
#define IMX290_INCKSEL1 IMX290_REG_8BIT(0x305c)
|
#define IMX290_INCKSEL1 CCI_REG8(0x305c)
|
||||||
#define IMX290_INCKSEL2 IMX290_REG_8BIT(0x305d)
|
#define IMX290_INCKSEL2 CCI_REG8(0x305d)
|
||||||
#define IMX290_INCKSEL3 IMX290_REG_8BIT(0x305e)
|
#define IMX290_INCKSEL3 CCI_REG8(0x305e)
|
||||||
#define IMX290_INCKSEL4 IMX290_REG_8BIT(0x305f)
|
#define IMX290_INCKSEL4 CCI_REG8(0x305f)
|
||||||
#define IMX290_PGCTRL IMX290_REG_8BIT(0x308c)
|
#define IMX290_PGCTRL CCI_REG8(0x308c)
|
||||||
#define IMX290_ADBIT1 IMX290_REG_8BIT(0x3129)
|
#define IMX290_ADBIT1 CCI_REG8(0x3129)
|
||||||
#define IMX290_ADBIT1_10BIT 0x1d
|
#define IMX290_ADBIT1_10BIT 0x1d
|
||||||
#define IMX290_ADBIT1_12BIT 0x00
|
#define IMX290_ADBIT1_12BIT 0x00
|
||||||
#define IMX290_INCKSEL5 IMX290_REG_8BIT(0x315e)
|
#define IMX290_INCKSEL5 CCI_REG8(0x315e)
|
||||||
#define IMX290_INCKSEL6 IMX290_REG_8BIT(0x3164)
|
#define IMX290_INCKSEL6 CCI_REG8(0x3164)
|
||||||
#define IMX290_ADBIT2 IMX290_REG_8BIT(0x317c)
|
#define IMX290_ADBIT2 CCI_REG8(0x317c)
|
||||||
#define IMX290_ADBIT2_10BIT 0x12
|
#define IMX290_ADBIT2_10BIT 0x12
|
||||||
#define IMX290_ADBIT2_12BIT 0x00
|
#define IMX290_ADBIT2_12BIT 0x00
|
||||||
#define IMX290_CHIP_ID IMX290_REG_16BIT(0x319a)
|
#define IMX290_CHIP_ID CCI_REG16(0x319a)
|
||||||
#define IMX290_ADBIT3 IMX290_REG_8BIT(0x31ec)
|
#define IMX290_ADBIT3 CCI_REG8(0x31ec)
|
||||||
#define IMX290_ADBIT3_10BIT 0x37
|
#define IMX290_ADBIT3_10BIT 0x37
|
||||||
#define IMX290_ADBIT3_12BIT 0x0e
|
#define IMX290_ADBIT3_12BIT 0x0e
|
||||||
#define IMX290_REPETITION IMX290_REG_8BIT(0x3405)
|
#define IMX290_REPETITION CCI_REG8(0x3405)
|
||||||
#define IMX290_PHY_LANE_NUM IMX290_REG_8BIT(0x3407)
|
#define IMX290_PHY_LANE_NUM CCI_REG8(0x3407)
|
||||||
#define IMX290_OPB_SIZE_V IMX290_REG_8BIT(0x3414)
|
#define IMX290_OPB_SIZE_V CCI_REG8(0x3414)
|
||||||
#define IMX290_Y_OUT_SIZE IMX290_REG_16BIT(0x3418)
|
#define IMX290_Y_OUT_SIZE CCI_REG16(0x3418)
|
||||||
#define IMX290_CSI_DT_FMT IMX290_REG_16BIT(0x3441)
|
#define IMX290_CSI_DT_FMT CCI_REG16(0x3441)
|
||||||
#define IMX290_CSI_DT_FMT_RAW10 0x0a0a
|
#define IMX290_CSI_DT_FMT_RAW10 0x0a0a
|
||||||
#define IMX290_CSI_DT_FMT_RAW12 0x0c0c
|
#define IMX290_CSI_DT_FMT_RAW12 0x0c0c
|
||||||
#define IMX290_CSI_LANE_MODE IMX290_REG_8BIT(0x3443)
|
#define IMX290_CSI_LANE_MODE CCI_REG8(0x3443)
|
||||||
#define IMX290_EXTCK_FREQ IMX290_REG_16BIT(0x3444)
|
#define IMX290_EXTCK_FREQ CCI_REG16(0x3444)
|
||||||
#define IMX290_TCLKPOST IMX290_REG_16BIT(0x3446)
|
#define IMX290_TCLKPOST CCI_REG16(0x3446)
|
||||||
#define IMX290_THSZERO IMX290_REG_16BIT(0x3448)
|
#define IMX290_THSZERO CCI_REG16(0x3448)
|
||||||
#define IMX290_THSPREPARE IMX290_REG_16BIT(0x344a)
|
#define IMX290_THSPREPARE CCI_REG16(0x344a)
|
||||||
#define IMX290_TCLKTRAIL IMX290_REG_16BIT(0x344c)
|
#define IMX290_TCLKTRAIL CCI_REG16(0x344c)
|
||||||
#define IMX290_THSTRAIL IMX290_REG_16BIT(0x344e)
|
#define IMX290_THSTRAIL CCI_REG16(0x344e)
|
||||||
#define IMX290_TCLKZERO IMX290_REG_16BIT(0x3450)
|
#define IMX290_TCLKZERO CCI_REG16(0x3450)
|
||||||
#define IMX290_TCLKPREPARE IMX290_REG_16BIT(0x3452)
|
#define IMX290_TCLKPREPARE CCI_REG16(0x3452)
|
||||||
#define IMX290_TLPX IMX290_REG_16BIT(0x3454)
|
#define IMX290_TLPX CCI_REG16(0x3454)
|
||||||
#define IMX290_X_OUT_SIZE IMX290_REG_16BIT(0x3472)
|
#define IMX290_X_OUT_SIZE CCI_REG16(0x3472)
|
||||||
#define IMX290_INCKSEL7 IMX290_REG_8BIT(0x3480)
|
#define IMX290_INCKSEL7 CCI_REG8(0x3480)
|
||||||
|
|
||||||
#define IMX290_PGCTRL_REGEN BIT(0)
|
#define IMX290_PGCTRL_REGEN BIT(0)
|
||||||
#define IMX290_PGCTRL_THRU BIT(1)
|
#define IMX290_PGCTRL_THRU BIT(1)
|
||||||
@@ -181,7 +176,7 @@ enum imx290_model {
|
|||||||
|
|
||||||
struct imx290_model_info {
|
struct imx290_model_info {
|
||||||
enum imx290_colour_variant colour_variant;
|
enum imx290_colour_variant colour_variant;
|
||||||
const struct imx290_regval *init_regs;
|
const struct cci_reg_sequence *init_regs;
|
||||||
size_t init_regs_num;
|
size_t init_regs_num;
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
@@ -192,11 +187,6 @@ enum imx290_clk_freq {
|
|||||||
IMX290_NUM_CLK
|
IMX290_NUM_CLK
|
||||||
};
|
};
|
||||||
|
|
||||||
struct imx290_regval {
|
|
||||||
u32 reg;
|
|
||||||
u32 val;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clock configuration for registers INCKSEL1 to INCKSEL6.
|
* Clock configuration for registers INCKSEL1 to INCKSEL6.
|
||||||
*/
|
*/
|
||||||
@@ -217,7 +207,7 @@ struct imx290_mode {
|
|||||||
u8 link_freq_index;
|
u8 link_freq_index;
|
||||||
u8 ctrl_07;
|
u8 ctrl_07;
|
||||||
|
|
||||||
const struct imx290_regval *data;
|
const struct cci_reg_sequence *data;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
|
|
||||||
const struct imx290_clk_cfg *clk_cfg;
|
const struct imx290_clk_cfg *clk_cfg;
|
||||||
@@ -271,7 +261,7 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
|
|||||||
* Modes and formats
|
* 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_WINWV_OB, 12 },
|
||||||
{ IMX290_WINPH, 0 },
|
{ IMX290_WINPH, 0 },
|
||||||
{ IMX290_WINPV, 0 },
|
{ IMX290_WINPV, 0 },
|
||||||
@@ -279,56 +269,56 @@ static const struct imx290_regval imx290_global_init_settings[] = {
|
|||||||
{ IMX290_WINWV, 1097 },
|
{ IMX290_WINWV, 1097 },
|
||||||
{ IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC |
|
{ IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC |
|
||||||
IMX290_XSOUTSEL_XHSOUTSEL_HSYNC },
|
IMX290_XSOUTSEL_XHSOUTSEL_HSYNC },
|
||||||
{ IMX290_REG_8BIT(0x3011), 0x02 },
|
{ CCI_REG8(0x3011), 0x02 },
|
||||||
{ IMX290_REG_8BIT(0x3012), 0x64 },
|
{ CCI_REG8(0x3012), 0x64 },
|
||||||
{ IMX290_REG_8BIT(0x3013), 0x00 },
|
{ CCI_REG8(0x3013), 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct imx290_regval imx290_global_init_settings_290[] = {
|
static const struct cci_reg_sequence imx290_global_init_settings_290[] = {
|
||||||
{ IMX290_REG_8BIT(0x300f), 0x00 },
|
{ CCI_REG8(0x300f), 0x00 },
|
||||||
{ IMX290_REG_8BIT(0x3010), 0x21 },
|
{ CCI_REG8(0x3010), 0x21 },
|
||||||
{ IMX290_REG_8BIT(0x3016), 0x09 },
|
{ CCI_REG8(0x3016), 0x09 },
|
||||||
{ IMX290_REG_8BIT(0x3070), 0x02 },
|
{ CCI_REG8(0x3070), 0x02 },
|
||||||
{ IMX290_REG_8BIT(0x3071), 0x11 },
|
{ CCI_REG8(0x3071), 0x11 },
|
||||||
{ IMX290_REG_8BIT(0x309b), 0x10 },
|
{ CCI_REG8(0x309b), 0x10 },
|
||||||
{ IMX290_REG_8BIT(0x309c), 0x22 },
|
{ CCI_REG8(0x309c), 0x22 },
|
||||||
{ IMX290_REG_8BIT(0x30a2), 0x02 },
|
{ CCI_REG8(0x30a2), 0x02 },
|
||||||
{ IMX290_REG_8BIT(0x30a6), 0x20 },
|
{ CCI_REG8(0x30a6), 0x20 },
|
||||||
{ IMX290_REG_8BIT(0x30a8), 0x20 },
|
{ CCI_REG8(0x30a8), 0x20 },
|
||||||
{ IMX290_REG_8BIT(0x30aa), 0x20 },
|
{ CCI_REG8(0x30aa), 0x20 },
|
||||||
{ IMX290_REG_8BIT(0x30ac), 0x20 },
|
{ CCI_REG8(0x30ac), 0x20 },
|
||||||
{ IMX290_REG_8BIT(0x30b0), 0x43 },
|
{ CCI_REG8(0x30b0), 0x43 },
|
||||||
{ IMX290_REG_8BIT(0x3119), 0x9e },
|
{ CCI_REG8(0x3119), 0x9e },
|
||||||
{ IMX290_REG_8BIT(0x311c), 0x1e },
|
{ CCI_REG8(0x311c), 0x1e },
|
||||||
{ IMX290_REG_8BIT(0x311e), 0x08 },
|
{ CCI_REG8(0x311e), 0x08 },
|
||||||
{ IMX290_REG_8BIT(0x3128), 0x05 },
|
{ CCI_REG8(0x3128), 0x05 },
|
||||||
{ IMX290_REG_8BIT(0x313d), 0x83 },
|
{ CCI_REG8(0x313d), 0x83 },
|
||||||
{ IMX290_REG_8BIT(0x3150), 0x03 },
|
{ CCI_REG8(0x3150), 0x03 },
|
||||||
{ IMX290_REG_8BIT(0x317e), 0x00 },
|
{ CCI_REG8(0x317e), 0x00 },
|
||||||
{ IMX290_REG_8BIT(0x32b8), 0x50 },
|
{ CCI_REG8(0x32b8), 0x50 },
|
||||||
{ IMX290_REG_8BIT(0x32b9), 0x10 },
|
{ CCI_REG8(0x32b9), 0x10 },
|
||||||
{ IMX290_REG_8BIT(0x32ba), 0x00 },
|
{ CCI_REG8(0x32ba), 0x00 },
|
||||||
{ IMX290_REG_8BIT(0x32bb), 0x04 },
|
{ CCI_REG8(0x32bb), 0x04 },
|
||||||
{ IMX290_REG_8BIT(0x32c8), 0x50 },
|
{ CCI_REG8(0x32c8), 0x50 },
|
||||||
{ IMX290_REG_8BIT(0x32c9), 0x10 },
|
{ CCI_REG8(0x32c9), 0x10 },
|
||||||
{ IMX290_REG_8BIT(0x32ca), 0x00 },
|
{ CCI_REG8(0x32ca), 0x00 },
|
||||||
{ IMX290_REG_8BIT(0x32cb), 0x04 },
|
{ CCI_REG8(0x32cb), 0x04 },
|
||||||
{ IMX290_REG_8BIT(0x332c), 0xd3 },
|
{ CCI_REG8(0x332c), 0xd3 },
|
||||||
{ IMX290_REG_8BIT(0x332d), 0x10 },
|
{ CCI_REG8(0x332d), 0x10 },
|
||||||
{ IMX290_REG_8BIT(0x332e), 0x0d },
|
{ CCI_REG8(0x332e), 0x0d },
|
||||||
{ IMX290_REG_8BIT(0x3358), 0x06 },
|
{ CCI_REG8(0x3358), 0x06 },
|
||||||
{ IMX290_REG_8BIT(0x3359), 0xe1 },
|
{ CCI_REG8(0x3359), 0xe1 },
|
||||||
{ IMX290_REG_8BIT(0x335a), 0x11 },
|
{ CCI_REG8(0x335a), 0x11 },
|
||||||
{ IMX290_REG_8BIT(0x3360), 0x1e },
|
{ CCI_REG8(0x3360), 0x1e },
|
||||||
{ IMX290_REG_8BIT(0x3361), 0x61 },
|
{ CCI_REG8(0x3361), 0x61 },
|
||||||
{ IMX290_REG_8BIT(0x3362), 0x10 },
|
{ CCI_REG8(0x3362), 0x10 },
|
||||||
{ IMX290_REG_8BIT(0x33b0), 0x50 },
|
{ CCI_REG8(0x33b0), 0x50 },
|
||||||
{ IMX290_REG_8BIT(0x33b2), 0x1a },
|
{ CCI_REG8(0x33b2), 0x1a },
|
||||||
{ IMX290_REG_8BIT(0x33b3), 0x04 },
|
{ CCI_REG8(0x33b3), 0x04 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IMX290_NUM_CLK_REGS 2
|
#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_CLK_37_125] = {
|
||||||
{ IMX290_EXTCK_FREQ, (37125 * 256) / 1000 },
|
{ IMX290_EXTCK_FREQ, (37125 * 256) / 1000 },
|
||||||
{ IMX290_INCKSEL7, 0x49 },
|
{ 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[] = {
|
static const struct cci_reg_sequence imx290_global_init_settings_327[] = {
|
||||||
{ IMX290_REG_8BIT(0x309e), 0x4A },
|
{ CCI_REG8(0x309e), 0x4A },
|
||||||
{ IMX290_REG_8BIT(0x309f), 0x4A },
|
{ CCI_REG8(0x309f), 0x4A },
|
||||||
{ IMX290_REG_8BIT(0x313b), 0x61 },
|
{ CCI_REG8(0x313b), 0x61 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct imx290_regval imx290_1080p_settings[] = {
|
static const struct cci_reg_sequence imx290_1080p_settings[] = {
|
||||||
/* mode settings */
|
/* mode settings */
|
||||||
{ IMX290_WINWV_OB, 12 },
|
{ IMX290_WINWV_OB, 12 },
|
||||||
{ IMX290_OPB_SIZE_V, 10 },
|
{ IMX290_OPB_SIZE_V, 10 },
|
||||||
@@ -353,7 +343,7 @@ static const struct imx290_regval imx290_1080p_settings[] = {
|
|||||||
{ IMX290_Y_OUT_SIZE, 1080 },
|
{ IMX290_Y_OUT_SIZE, 1080 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct imx290_regval imx290_720p_settings[] = {
|
static const struct cci_reg_sequence imx290_720p_settings[] = {
|
||||||
/* mode settings */
|
/* mode settings */
|
||||||
{ IMX290_WINWV_OB, 6 },
|
{ IMX290_WINWV_OB, 6 },
|
||||||
{ IMX290_OPB_SIZE_V, 4 },
|
{ IMX290_OPB_SIZE_V, 4 },
|
||||||
@@ -361,7 +351,7 @@ static const struct imx290_regval imx290_720p_settings[] = {
|
|||||||
{ IMX290_Y_OUT_SIZE, 720 },
|
{ 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_ADBIT, IMX290_ADBIT_10BIT },
|
||||||
{ IMX290_OUT_CTRL, IMX290_ODBIT_10BIT },
|
{ IMX290_OUT_CTRL, IMX290_ODBIT_10BIT },
|
||||||
{ IMX290_ADBIT1, IMX290_ADBIT1_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 },
|
{ 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_ADBIT, IMX290_ADBIT_12BIT },
|
||||||
{ IMX290_OUT_CTRL, IMX290_ODBIT_12BIT },
|
{ IMX290_OUT_CTRL, IMX290_ODBIT_12BIT },
|
||||||
{ IMX290_ADBIT1, IMX290_ADBIT1_12BIT },
|
{ IMX290_ADBIT1, IMX290_ADBIT1_12BIT },
|
||||||
@@ -576,7 +566,7 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
|
|||||||
struct imx290_format_info {
|
struct imx290_format_info {
|
||||||
u32 code[IMX290_VARIANT_MAX];
|
u32 code[IMX290_VARIANT_MAX];
|
||||||
u8 bpp;
|
u8 bpp;
|
||||||
const struct imx290_regval *regs;
|
const struct cci_reg_sequence *regs;
|
||||||
unsigned int num_regs;
|
unsigned int num_regs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -615,63 +605,15 @@ imx290_format_info(const struct imx290 *imx290, u32 code)
|
|||||||
return NULL;
|
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,
|
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 num_settings)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for (i = 0; i < num_settings; ++i, ++settings) {
|
ret = cci_multi_reg_write(imx290->regmap, settings, num_settings, NULL);
|
||||||
ret = imx290_write(imx290, settings->reg, settings->val, NULL);
|
if (ret < 0)
|
||||||
if (ret < 0)
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Provide 10ms settle time */
|
/* Provide 10ms settle time */
|
||||||
usleep_range(10000, 11000);
|
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],
|
ret = imx290_set_register_array(imx290, xclk_regs[clk_idx],
|
||||||
IMX290_NUM_CLK_REGS);
|
IMX290_NUM_CLK_REGS);
|
||||||
|
|
||||||
imx290_write(imx290, IMX290_INCKSEL1, clk_cfg->incksel1, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL1, clk_cfg->incksel1, &ret);
|
||||||
imx290_write(imx290, IMX290_INCKSEL2, clk_cfg->incksel2, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL2, clk_cfg->incksel2, &ret);
|
||||||
imx290_write(imx290, IMX290_INCKSEL3, clk_cfg->incksel3, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL3, clk_cfg->incksel3, &ret);
|
||||||
imx290_write(imx290, IMX290_INCKSEL4, clk_cfg->incksel4, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL4, clk_cfg->incksel4, &ret);
|
||||||
imx290_write(imx290, IMX290_INCKSEL5, clk_cfg->incksel5, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL5, clk_cfg->incksel5, &ret);
|
||||||
imx290_write(imx290, IMX290_INCKSEL6, clk_cfg->incksel6, &ret);
|
cci_write(imx290->regmap, IMX290_INCKSEL6, clk_cfg->incksel6, &ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -703,9 +645,11 @@ static int imx290_set_data_lanes(struct imx290 *imx290)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret);
|
cci_write(imx290->regmap, IMX290_PHY_LANE_NUM, imx290->nlanes - 1,
|
||||||
imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret);
|
&ret);
|
||||||
imx290_write(imx290, IMX290_FR_FDG_SEL, 0x01, &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;
|
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;
|
unsigned int bpp = imx290_format_info(imx290, format->code)->bpp;
|
||||||
|
|
||||||
return imx290_write(imx290, IMX290_BLKLEVEL,
|
return cci_write(imx290->regmap, IMX290_BLKLEVEL,
|
||||||
black_level >> (16 - bpp), err);
|
black_level >> (16 - bpp), err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx290_set_csi_config(struct imx290 *imx290)
|
static int imx290_set_csi_config(struct imx290 *imx290)
|
||||||
@@ -743,15 +687,16 @@ static int imx290_set_csi_config(struct imx290 *imx290)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
imx290_write(imx290, IMX290_REPETITION, csi_cfg->repetition, &ret);
|
cci_write(imx290->regmap, IMX290_REPETITION, csi_cfg->repetition, &ret);
|
||||||
imx290_write(imx290, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret);
|
cci_write(imx290->regmap, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret);
|
||||||
imx290_write(imx290, IMX290_THSZERO, csi_cfg->thszero, &ret);
|
cci_write(imx290->regmap, IMX290_THSZERO, csi_cfg->thszero, &ret);
|
||||||
imx290_write(imx290, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret);
|
cci_write(imx290->regmap, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret);
|
||||||
imx290_write(imx290, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret);
|
cci_write(imx290->regmap, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret);
|
||||||
imx290_write(imx290, IMX290_THSTRAIL, csi_cfg->thstrail, &ret);
|
cci_write(imx290->regmap, IMX290_THSTRAIL, csi_cfg->thstrail, &ret);
|
||||||
imx290_write(imx290, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret);
|
cci_write(imx290->regmap, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret);
|
||||||
imx290_write(imx290, IMX290_TCLKPREPARE, csi_cfg->tclkprepare, &ret);
|
cci_write(imx290->regmap, IMX290_TCLKPREPARE, csi_cfg->tclkprepare,
|
||||||
imx290_write(imx290, IMX290_TLPX, csi_cfg->tlpx, &ret);
|
&ret);
|
||||||
|
cci_write(imx290->regmap, IMX290_TLPX, csi_cfg->tlpx, &ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -817,13 +762,12 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_ANALOGUE_GAIN:
|
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;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_VBLANK:
|
case V4L2_CID_VBLANK:
|
||||||
ret = imx290_write(imx290, IMX290_VMAX,
|
ret = cci_write(imx290->regmap, IMX290_VMAX,
|
||||||
ctrl->val + imx290->current_mode->height,
|
ctrl->val + imx290->current_mode->height, NULL);
|
||||||
NULL);
|
|
||||||
/*
|
/*
|
||||||
* Due to the way that exposure is programmed in this sensor in
|
* Due to the way that exposure is programmed in this sensor in
|
||||||
* relation to VMAX, we have to reprogramme it whenever VMAX is
|
* 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;
|
fallthrough;
|
||||||
case V4L2_CID_EXPOSURE:
|
case V4L2_CID_EXPOSURE:
|
||||||
vmax = imx290->vblank->val + imx290->current_mode->height;
|
vmax = imx290->vblank->val + imx290->current_mode->height;
|
||||||
ret = imx290_write(imx290, IMX290_SHS1,
|
ret = cci_write(imx290->regmap, IMX290_SHS1,
|
||||||
vmax - ctrl->val - 1, NULL);
|
vmax - ctrl->val - 1, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_TEST_PATTERN:
|
case V4L2_CID_TEST_PATTERN:
|
||||||
if (ctrl->val) {
|
if (ctrl->val) {
|
||||||
imx290_set_black_level(imx290, format, 0, &ret);
|
imx290_set_black_level(imx290, format, 0, &ret);
|
||||||
usleep_range(10000, 11000);
|
usleep_range(10000, 11000);
|
||||||
imx290_write(imx290, IMX290_PGCTRL,
|
cci_write(imx290->regmap, IMX290_PGCTRL,
|
||||||
(u8)(IMX290_PGCTRL_REGEN |
|
(u8)(IMX290_PGCTRL_REGEN |
|
||||||
IMX290_PGCTRL_THRU |
|
IMX290_PGCTRL_THRU |
|
||||||
IMX290_PGCTRL_MODE(ctrl->val)), &ret);
|
IMX290_PGCTRL_MODE(ctrl->val)), &ret);
|
||||||
} else {
|
} else {
|
||||||
imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret);
|
cci_write(imx290->regmap, IMX290_PGCTRL, 0x00, &ret);
|
||||||
usleep_range(10000, 11000);
|
usleep_range(10000, 11000);
|
||||||
imx290_set_black_level(imx290, format,
|
imx290_set_black_level(imx290, format,
|
||||||
IMX290_BLACK_LEVEL_DEFAULT, &ret);
|
IMX290_BLACK_LEVEL_DEFAULT, &ret);
|
||||||
@@ -856,9 +800,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_HBLANK:
|
case V4L2_CID_HBLANK:
|
||||||
ret = imx290_write(imx290, IMX290_HMAX,
|
ret = cci_write(imx290->regmap, IMX290_HMAX,
|
||||||
ctrl->val + imx290->current_mode->width,
|
ctrl->val + imx290->current_mode->width, NULL);
|
||||||
NULL);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_HFLIP:
|
case V4L2_CID_HFLIP:
|
||||||
@@ -871,7 +814,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||||||
reg |= IMX290_HREVERSE;
|
reg |= IMX290_HREVERSE;
|
||||||
if (imx290->vflip->val)
|
if (imx290->vflip->val)
|
||||||
reg |= IMX290_VREVERSE;
|
reg |= IMX290_VREVERSE;
|
||||||
ret = imx290_write(imx290, IMX290_CTRL_07, reg, NULL);
|
ret = cci_write(imx290->regmap, IMX290_CTRL_07, reg, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,7 +845,6 @@ static const char * const imx290_test_pattern_menu[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void imx290_ctrl_update(struct imx290 *imx290,
|
static void imx290_ctrl_update(struct imx290 *imx290,
|
||||||
const struct v4l2_mbus_framefmt *format,
|
|
||||||
const struct imx290_mode *mode)
|
const struct imx290_mode *mode)
|
||||||
{
|
{
|
||||||
unsigned int hblank_min = mode->hmax_min - mode->width;
|
unsigned int hblank_min = mode->hmax_min - mode->width;
|
||||||
@@ -1074,12 +1016,12 @@ static int imx290_start_streaming(struct imx290 *imx290,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
|
cci_write(imx290->regmap, IMX290_STANDBY, 0x00, &ret);
|
||||||
|
|
||||||
msleep(30);
|
msleep(30);
|
||||||
|
|
||||||
/* Start streaming */
|
/* Start streaming */
|
||||||
return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
|
return cci_write(imx290->regmap, IMX290_XMSTA, 0x00, &ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop streaming */
|
/* Stop streaming */
|
||||||
@@ -1087,11 +1029,11 @@ static int imx290_stop_streaming(struct imx290 *imx290)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
|
cci_write(imx290->regmap, IMX290_STANDBY, 0x01, &ret);
|
||||||
|
|
||||||
msleep(30);
|
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)
|
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) {
|
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||||
imx290->current_mode = mode;
|
imx290->current_mode = mode;
|
||||||
|
|
||||||
imx290_ctrl_update(imx290, &fmt->format, mode);
|
imx290_ctrl_update(imx290, mode);
|
||||||
imx290_exposure_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)
|
static int imx290_subdev_init(struct imx290 *imx290)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(imx290->dev);
|
struct i2c_client *client = to_i2c_client(imx290->dev);
|
||||||
const struct v4l2_mbus_framefmt *format;
|
|
||||||
struct v4l2_subdev_state *state;
|
struct v4l2_subdev_state *state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1335,8 +1276,7 @@ static int imx290_subdev_init(struct imx290 *imx290)
|
|||||||
}
|
}
|
||||||
|
|
||||||
state = v4l2_subdev_lock_and_get_active_state(&imx290->sd);
|
state = v4l2_subdev_lock_and_get_active_state(&imx290->sd);
|
||||||
format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
|
imx290_ctrl_update(imx290, imx290->current_mode);
|
||||||
imx290_ctrl_update(imx290, format, imx290->current_mode);
|
|
||||||
v4l2_subdev_unlock_state(state);
|
v4l2_subdev_unlock_state(state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1417,11 +1357,6 @@ static const struct dev_pm_ops imx290_pm_ops = {
|
|||||||
* Probe & remove
|
* 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] = {
|
static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = {
|
||||||
"vdda",
|
"vdda",
|
||||||
"vddd",
|
"vddd",
|
||||||
@@ -1588,7 +1523,7 @@ static int imx290_probe(struct i2c_client *client)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
imx290->dev = dev;
|
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)) {
|
if (IS_ERR(imx290->regmap)) {
|
||||||
dev_err(dev, "Unable to initialize I2C\n");
|
dev_err(dev, "Unable to initialize I2C\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|||||||
@@ -2565,7 +2565,7 @@ static struct i2c_driver imx319_i2c_driver = {
|
|||||||
module_i2c_driver(imx319_i2c_driver);
|
module_i2c_driver(imx319_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
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("Bingbu Cao <bingbu.cao@intel.com>");
|
||||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||||
MODULE_DESCRIPTION("Sony imx319 sensor driver");
|
MODULE_DESCRIPTION("Sony imx319 sensor driver");
|
||||||
|
|||||||
@@ -1851,7 +1851,7 @@ static struct i2c_driver imx355_i2c_driver = {
|
|||||||
module_i2c_driver(imx355_i2c_driver);
|
module_i2c_driver(imx355_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
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("Bingbu Cao <bingbu.cao@intel.com>");
|
||||||
MODULE_AUTHOR("Yang, Hyungwoo");
|
MODULE_AUTHOR("Yang, Hyungwoo");
|
||||||
MODULE_DESCRIPTION("Sony imx355 sensor driver");
|
MODULE_DESCRIPTION("Sony imx355 sensor driver");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.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 = {
|
static struct i2c_driver isl7998x_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "isl7998x",
|
.name = "isl7998x",
|
||||||
.of_match_table = of_match_ptr(isl7998x_of_match),
|
.of_match_table = isl7998x_of_match,
|
||||||
.pm = &isl7998x_pm_ops,
|
.pm = &isl7998x_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = isl7998x_probe,
|
.probe = isl7998x_probe,
|
||||||
|
|||||||
@@ -161,11 +161,12 @@ struct max9286_source {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct max9286_asd {
|
struct max9286_asd {
|
||||||
struct v4l2_async_subdev base;
|
struct v4l2_async_connection base;
|
||||||
struct max9286_source *source;
|
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);
|
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,
|
static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
|
||||||
struct v4l2_subdev *subdev,
|
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_priv *priv = sd_to_max9286(notifier->sd);
|
||||||
struct max9286_source *source = to_max9286_asd(asd)->source;
|
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,
|
static void max9286_notify_unbind(struct v4l2_async_notifier *notifier,
|
||||||
struct v4l2_subdev *subdev,
|
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_priv *priv = sd_to_max9286(notifier->sd);
|
||||||
struct max9286_source *source = to_max9286_asd(asd)->source;
|
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)
|
if (!priv->nsources)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
v4l2_async_nf_init(&priv->notifier);
|
v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
|
||||||
|
|
||||||
for_each_source(priv, source) {
|
for_each_source(priv, source) {
|
||||||
unsigned int i = to_index(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;
|
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) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to register subdev_notifier");
|
dev_err(dev, "Failed to register subdev_notifier");
|
||||||
v4l2_async_nf_cleanup(&priv->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)
|
static int max9286_v4l2_register(struct max9286_priv *priv)
|
||||||
{
|
{
|
||||||
struct device *dev = &priv->client->dev;
|
struct device *dev = &priv->client->dev;
|
||||||
struct fwnode_handle *ep;
|
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1093,25 +1093,14 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_async;
|
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);
|
ret = v4l2_async_register_subdev(&priv->sd);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "Unable to register subdevice\n");
|
dev_err(dev, "Unable to register subdevice\n");
|
||||||
goto err_put_node;
|
goto err_async;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_put_node:
|
|
||||||
fwnode_handle_put(ep);
|
|
||||||
err_async:
|
err_async:
|
||||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||||
max9286_v4l2_notifier_unregister(priv);
|
max9286_v4l2_notifier_unregister(priv);
|
||||||
@@ -1714,7 +1703,7 @@ MODULE_DEVICE_TABLE(of, max9286_dt_ids);
|
|||||||
static struct i2c_driver max9286_i2c_driver = {
|
static struct i2c_driver max9286_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "max9286",
|
.name = "max9286",
|
||||||
.of_match_table = of_match_ptr(max9286_dt_ids),
|
.of_match_table = max9286_dt_ids,
|
||||||
},
|
},
|
||||||
.probe = max9286_probe,
|
.probe = max9286_probe,
|
||||||
.remove = max9286_remove,
|
.remove = max9286_remove,
|
||||||
|
|||||||
@@ -1382,7 +1382,7 @@ MODULE_DEVICE_TABLE(i2c, mt9m111_id);
|
|||||||
static struct i2c_driver mt9m111_i2c_driver = {
|
static struct i2c_driver mt9m111_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "mt9m111",
|
.name = "mt9m111",
|
||||||
.of_match_table = of_match_ptr(mt9m111_of_match),
|
.of_match_table = mt9m111_of_match,
|
||||||
},
|
},
|
||||||
.probe = mt9m111_probe,
|
.probe = mt9m111_probe,
|
||||||
.remove = mt9m111_remove,
|
.remove = mt9m111_remove,
|
||||||
|
|||||||
@@ -1121,6 +1121,6 @@ static struct i2c_driver og01a1b_i2c_driver = {
|
|||||||
|
|
||||||
module_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_DESCRIPTION("OmniVision OG01A1B sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -992,7 +992,7 @@ static struct i2c_driver ov01a10_i2c_driver = {
|
|||||||
.pm = &ov01a10_pm_ops,
|
.pm = &ov01a10_pm_ops,
|
||||||
.acpi_match_table = ACPI_PTR(ov01a10_acpi_ids),
|
.acpi_match_table = ACPI_PTR(ov01a10_acpi_ids),
|
||||||
},
|
},
|
||||||
.probe_new = ov01a10_probe,
|
.probe = ov01a10_probe,
|
||||||
.remove = ov01a10_remove,
|
.remove = ov01a10_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,6 @@ struct ov08x40_reg_list {
|
|||||||
|
|
||||||
/* Link frequency config */
|
/* Link frequency config */
|
||||||
struct ov08x40_link_freq_config {
|
struct ov08x40_link_freq_config {
|
||||||
u32 pixels_per_line;
|
|
||||||
|
|
||||||
/* registers for this link frequency */
|
/* registers for this link frequency */
|
||||||
struct ov08x40_reg_list reg_list;
|
struct ov08x40_reg_list reg_list;
|
||||||
};
|
};
|
||||||
@@ -128,6 +126,9 @@ struct ov08x40_mode {
|
|||||||
u32 vts_def;
|
u32 vts_def;
|
||||||
u32 vts_min;
|
u32 vts_min;
|
||||||
|
|
||||||
|
/* HTS */
|
||||||
|
u32 hts;
|
||||||
|
|
||||||
/* Index of Link frequency config to be used */
|
/* Index of Link frequency config to be used */
|
||||||
u32 link_freq_index;
|
u32 link_freq_index;
|
||||||
/* Default register values */
|
/* Default register values */
|
||||||
@@ -2391,6 +2392,7 @@ static const struct ov08x40_mode supported_modes[] = {
|
|||||||
.height = 2416,
|
.height = 2416,
|
||||||
.vts_def = OV08X40_VTS_30FPS,
|
.vts_def = OV08X40_VTS_30FPS,
|
||||||
.vts_min = OV08X40_VTS_30FPS,
|
.vts_min = OV08X40_VTS_30FPS,
|
||||||
|
.hts = 640,
|
||||||
.lanes = 4,
|
.lanes = 4,
|
||||||
.reg_list = {
|
.reg_list = {
|
||||||
.num_of_regs = ARRAY_SIZE(mode_3856x2416_regs),
|
.num_of_regs = ARRAY_SIZE(mode_3856x2416_regs),
|
||||||
@@ -2403,6 +2405,7 @@ static const struct ov08x40_mode supported_modes[] = {
|
|||||||
.height = 1208,
|
.height = 1208,
|
||||||
.vts_def = OV08X40_VTS_BIN_30FPS,
|
.vts_def = OV08X40_VTS_BIN_30FPS,
|
||||||
.vts_min = OV08X40_VTS_BIN_30FPS,
|
.vts_min = OV08X40_VTS_BIN_30FPS,
|
||||||
|
.hts = 720,
|
||||||
.lanes = 4,
|
.lanes = 4,
|
||||||
.reg_list = {
|
.reg_list = {
|
||||||
.num_of_regs = ARRAY_SIZE(mode_1928x1208_regs),
|
.num_of_regs = ARRAY_SIZE(mode_1928x1208_regs),
|
||||||
@@ -2846,9 +2849,7 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd,
|
|||||||
1,
|
1,
|
||||||
vblank_def);
|
vblank_def);
|
||||||
__v4l2_ctrl_s_ctrl(ov08x->vblank, vblank_def);
|
__v4l2_ctrl_s_ctrl(ov08x->vblank, vblank_def);
|
||||||
h_blank =
|
h_blank = ov08x->cur_mode->hts;
|
||||||
link_freq_configs[mode->link_freq_index].pixels_per_line
|
|
||||||
- ov08x->cur_mode->width;
|
|
||||||
__v4l2_ctrl_modify_range(ov08x->hblank, h_blank,
|
__v4l2_ctrl_modify_range(ov08x->hblank, h_blank,
|
||||||
h_blank, 1, 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,
|
OV08X40_VTS_MAX - mode->height, 1,
|
||||||
vblank_def);
|
vblank_def);
|
||||||
|
|
||||||
hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
|
hblank = ov08x->cur_mode->hts;
|
||||||
mode->width;
|
|
||||||
ov08x->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
|
ov08x->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops,
|
||||||
V4L2_CID_HBLANK,
|
V4L2_CID_HBLANK,
|
||||||
hblank, hblank, 1, hblank);
|
hblank, hblank, 1, hblank);
|
||||||
@@ -3320,6 +3320,6 @@ static struct i2c_driver ov08x40_i2c_driver = {
|
|||||||
module_i2c_driver(ov08x40_i2c_driver);
|
module_i2c_driver(ov08x40_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Jason Chen <jason.z.chen@intel.com>");
|
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_DESCRIPTION("OmniVision OV08X40 sensor driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
@@ -1814,7 +1814,7 @@ static struct i2c_driver ov13858_i2c_driver = {
|
|||||||
module_i2c_driver(ov13858_i2c_driver);
|
module_i2c_driver(ov13858_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Kan, Chris <chris.kan@intel.com>");
|
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_AUTHOR("Yang, Hyungwoo");
|
||||||
MODULE_DESCRIPTION("Omnivision ov13858 sensor driver");
|
MODULE_DESCRIPTION("Omnivision ov13858 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
// Copyright (c) 2021 Intel Corporation.
|
// Copyright (c) 2021 Intel Corporation.
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
@@ -573,6 +576,11 @@ struct ov13b10 {
|
|||||||
struct media_pad pad;
|
struct media_pad pad;
|
||||||
|
|
||||||
struct v4l2_ctrl_handler ctrl_handler;
|
struct v4l2_ctrl_handler ctrl_handler;
|
||||||
|
|
||||||
|
struct clk *img_clk;
|
||||||
|
struct regulator *avdd;
|
||||||
|
struct gpio_desc *reset;
|
||||||
|
|
||||||
/* V4L2 Controls */
|
/* V4L2 Controls */
|
||||||
struct v4l2_ctrl *link_freq;
|
struct v4l2_ctrl *link_freq;
|
||||||
struct v4l2_ctrl *pixel_rate;
|
struct v4l2_ctrl *pixel_rate;
|
||||||
@@ -1051,6 +1059,49 @@ static int ov13b10_identify_module(struct ov13b10 *ov13b)
|
|||||||
return 0;
|
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)
|
static int ov13b10_start_streaming(struct ov13b10 *ov13b)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
|
struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
|
||||||
@@ -1145,7 +1196,7 @@ err_unlock:
|
|||||||
return ret;
|
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 v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||||
struct ov13b10 *ov13b = to_ov13b10(sd);
|
struct ov13b10 *ov13b = to_ov13b10(sd);
|
||||||
@@ -1153,26 +1204,35 @@ static int __maybe_unused ov13b10_suspend(struct device *dev)
|
|||||||
if (ov13b->streaming)
|
if (ov13b->streaming)
|
||||||
ov13b10_stop_streaming(ov13b);
|
ov13b10_stop_streaming(ov13b);
|
||||||
|
|
||||||
|
ov13b10_power_off(dev);
|
||||||
|
|
||||||
return 0;
|
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 v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||||
struct ov13b10 *ov13b = to_ov13b10(sd);
|
struct ov13b10 *ov13b = to_ov13b10(sd);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = ov13b10_power_on(dev);
|
||||||
|
if (ret)
|
||||||
|
goto pm_fail;
|
||||||
|
|
||||||
if (ov13b->streaming) {
|
if (ov13b->streaming) {
|
||||||
ret = ov13b10_start_streaming(ov13b);
|
ret = ov13b10_start_streaming(ov13b);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto stop_streaming;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
stop_streaming:
|
||||||
ov13b10_stop_streaming(ov13b);
|
ov13b10_stop_streaming(ov13b);
|
||||||
|
ov13b10_power_off(dev);
|
||||||
|
pm_fail:
|
||||||
ov13b->streaming = false;
|
ov13b->streaming = false;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1317,6 +1377,34 @@ static void ov13b10_free_controls(struct ov13b10 *ov13b)
|
|||||||
mutex_destroy(&ov13b->mutex);
|
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)
|
static int ov13b10_check_hwcfg(struct device *dev)
|
||||||
{
|
{
|
||||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||||
@@ -1331,6 +1419,10 @@ static int ov13b10_check_hwcfg(struct device *dev)
|
|||||||
if (!fwnode)
|
if (!fwnode)
|
||||||
return -ENXIO;
|
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",
|
ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
||||||
&ext_clk);
|
&ext_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -1344,10 +1436,6 @@ static int ov13b10_check_hwcfg(struct device *dev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
|
||||||
if (!ep)
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
|
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
|
||||||
fwnode_handle_put(ep);
|
fwnode_handle_put(ep);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -1407,13 +1495,23 @@ static int ov13b10_probe(struct i2c_client *client)
|
|||||||
/* Initialize subdev */
|
/* Initialize subdev */
|
||||||
v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
|
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);
|
full_power = acpi_dev_state_d0(&client->dev);
|
||||||
if (full_power) {
|
if (full_power) {
|
||||||
|
ov13b10_power_on(&client->dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&client->dev, "failed to power on\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check module identity */
|
/* Check module identity */
|
||||||
ret = ov13b10_identify_module(ov13b);
|
ret = ov13b10_identify_module(ov13b);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "failed to find sensor: %d\n", 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);
|
ret = ov13b10_init_controls(ov13b);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto error_power_off;
|
||||||
|
|
||||||
/* Initialize subdev */
|
/* Initialize subdev */
|
||||||
ov13b->sd.internal_ops = &ov13b10_internal_ops;
|
ov13b->sd.internal_ops = &ov13b10_internal_ops;
|
||||||
@@ -1462,6 +1560,9 @@ error_handler_free:
|
|||||||
ov13b10_free_controls(ov13b);
|
ov13b10_free_controls(ov13b);
|
||||||
dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
|
dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
|
||||||
|
|
||||||
|
error_power_off:
|
||||||
|
ov13b10_power_off(&client->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1477,13 +1578,13 @@ static void ov13b10_remove(struct i2c_client *client)
|
|||||||
pm_runtime_disable(&client->dev);
|
pm_runtime_disable(&client->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops ov13b10_pm_ops = {
|
static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend,
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(ov13b10_suspend, ov13b10_resume)
|
ov13b10_resume, NULL);
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static const struct acpi_device_id ov13b10_acpi_ids[] = {
|
static const struct acpi_device_id ov13b10_acpi_ids[] = {
|
||||||
{"OVTIDB10"},
|
{"OVTIDB10"},
|
||||||
|
{"OVTI13B1"},
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1493,7 +1594,7 @@ MODULE_DEVICE_TABLE(acpi, ov13b10_acpi_ids);
|
|||||||
static struct i2c_driver ov13b10_i2c_driver = {
|
static struct i2c_driver ov13b10_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ov13b10",
|
.name = "ov13b10",
|
||||||
.pm = &ov13b10_pm_ops,
|
.pm = pm_ptr(&ov13b10_pm_ops),
|
||||||
.acpi_match_table = ACPI_PTR(ov13b10_acpi_ids),
|
.acpi_match_table = ACPI_PTR(ov13b10_acpi_ids),
|
||||||
},
|
},
|
||||||
.probe = ov13b10_probe,
|
.probe = ov13b10_probe,
|
||||||
|
|||||||
@@ -1296,7 +1296,7 @@ MODULE_DEVICE_TABLE(of, ov2640_of_match);
|
|||||||
static struct i2c_driver ov2640_i2c_driver = {
|
static struct i2c_driver ov2640_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ov2640",
|
.name = "ov2640",
|
||||||
.of_match_table = of_match_ptr(ov2640_of_match),
|
.of_match_table = ov2640_of_match,
|
||||||
},
|
},
|
||||||
.probe = ov2640_probe,
|
.probe = ov2640_probe,
|
||||||
.remove = ov2640_remove,
|
.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_i2c_driver(ov2740_i2c_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
|
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_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
|
||||||
MODULE_DESCRIPTION("OmniVision OV2740 sensor driver");
|
MODULE_DESCRIPTION("OmniVision OV2740 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.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},
|
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
|
||||||
{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
|
{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
|
||||||
{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
|
{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
|
||||||
{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
|
{0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x4837, 0x0a, 0, 0},
|
||||||
{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
|
||||||
{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
|
|
||||||
{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 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},
|
{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
|
||||||
{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 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},
|
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 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[] = {
|
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)
|
static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
|
||||||
{
|
{
|
||||||
if (sensor->pwdn_gpio) {
|
if (sensor->pwdn_gpio) {
|
||||||
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
|
||||||
|
|
||||||
/* camera power cycle */
|
/* camera power cycle */
|
||||||
ov5640_power(sensor, false);
|
ov5640_power(sensor, false);
|
||||||
usleep_range(5000, 10000);
|
usleep_range(5000, 10000); /* t2 */
|
||||||
ov5640_power(sensor, true);
|
ov5640_power(sensor, true);
|
||||||
usleep_range(5000, 10000);
|
usleep_range(1000, 2000); /* t3 */
|
||||||
|
|
||||||
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
|
|
||||||
usleep_range(1000, 2000);
|
|
||||||
|
|
||||||
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -2470,7 +2466,7 @@ static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
|
|||||||
ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
|
ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
|
||||||
OV5640_REG_SYS_CTRL0_SW_RST);
|
OV5640_REG_SYS_CTRL0_SW_RST);
|
||||||
}
|
}
|
||||||
usleep_range(20000, 25000);
|
usleep_range(20000, 25000); /* t4 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* software standby: allows registers programming;
|
* 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()")
|
* "ov5640_set_stream_mipi()")
|
||||||
* [4] = 0 : Power up MIPI HS Tx
|
* [4] = 0 : Power up MIPI HS Tx
|
||||||
* [3] = 0 : Power up MIPI LS Rx
|
* [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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|||||||
@@ -2860,7 +2860,7 @@ static struct i2c_driver ov5670_i2c_driver = {
|
|||||||
|
|
||||||
module_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_AUTHOR("Yang, Hyungwoo");
|
||||||
MODULE_DESCRIPTION("Omnivision ov5670 sensor driver");
|
MODULE_DESCRIPTION("Omnivision ov5670 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -1442,6 +1442,6 @@ static struct i2c_driver ov5675_i2c_driver = {
|
|||||||
|
|
||||||
module_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_DESCRIPTION("OmniVision OV5675 sensor driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
* Jake Day
|
* Jake Day
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/unaligned.h>
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
@@ -23,36 +22,32 @@
|
|||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <media/v4l2-cci.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-fwnode.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 */
|
/* System Control */
|
||||||
#define OV5693_SW_RESET_REG OV5693_REG_8BIT(0x0103)
|
#define OV5693_SW_RESET_REG CCI_REG8(0x0103)
|
||||||
#define OV5693_SW_STREAM_REG OV5693_REG_8BIT(0x0100)
|
#define OV5693_SW_STREAM_REG CCI_REG8(0x0100)
|
||||||
#define OV5693_START_STREAMING 0x01
|
#define OV5693_START_STREAMING 0x01
|
||||||
#define OV5693_STOP_STREAMING 0x00
|
#define OV5693_STOP_STREAMING 0x00
|
||||||
#define OV5693_SW_RESET 0x01
|
#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 */
|
/* Yes, this is right. The datasheet for the OV5693 gives its ID as 0x5690 */
|
||||||
#define OV5693_CHIP_ID 0x5690
|
#define OV5693_CHIP_ID 0x5690
|
||||||
|
|
||||||
/* Exposure */
|
/* 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_EXPOSURE_CTRL_MASK GENMASK(19, 4)
|
||||||
#define OV5693_INTEGRATION_TIME_MARGIN 8
|
#define OV5693_INTEGRATION_TIME_MARGIN 8
|
||||||
#define OV5693_EXPOSURE_MIN 1
|
#define OV5693_EXPOSURE_MIN 1
|
||||||
#define OV5693_EXPOSURE_STEP 1
|
#define OV5693_EXPOSURE_STEP 1
|
||||||
|
|
||||||
/* Analogue Gain */
|
/* 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_CTRL_MASK GENMASK(10, 4)
|
||||||
#define OV5693_GAIN_MIN 1
|
#define OV5693_GAIN_MIN 1
|
||||||
#define OV5693_GAIN_MAX 127
|
#define OV5693_GAIN_MAX 127
|
||||||
@@ -60,9 +55,9 @@
|
|||||||
#define OV5693_GAIN_STEP 1
|
#define OV5693_GAIN_STEP 1
|
||||||
|
|
||||||
/* Digital Gain */
|
/* Digital Gain */
|
||||||
#define OV5693_MWB_RED_GAIN_REG OV5693_REG_16BIT(0x3400)
|
#define OV5693_MWB_RED_GAIN_REG CCI_REG16(0x3400)
|
||||||
#define OV5693_MWB_GREEN_GAIN_REG OV5693_REG_16BIT(0x3402)
|
#define OV5693_MWB_GREEN_GAIN_REG CCI_REG16(0x3402)
|
||||||
#define OV5693_MWB_BLUE_GAIN_REG OV5693_REG_16BIT(0x3404)
|
#define OV5693_MWB_BLUE_GAIN_REG CCI_REG16(0x3404)
|
||||||
#define OV5693_MWB_GAIN_MASK GENMASK(11, 0)
|
#define OV5693_MWB_GAIN_MASK GENMASK(11, 0)
|
||||||
#define OV5693_MWB_GAIN_MAX 0x0fff
|
#define OV5693_MWB_GAIN_MAX 0x0fff
|
||||||
#define OV5693_DIGITAL_GAIN_MIN 1
|
#define OV5693_DIGITAL_GAIN_MIN 1
|
||||||
@@ -71,36 +66,36 @@
|
|||||||
#define OV5693_DIGITAL_GAIN_STEP 1
|
#define OV5693_DIGITAL_GAIN_STEP 1
|
||||||
|
|
||||||
/* Timing and Format */
|
/* Timing and Format */
|
||||||
#define OV5693_CROP_START_X_REG OV5693_REG_16BIT(0x3800)
|
#define OV5693_CROP_START_X_REG CCI_REG16(0x3800)
|
||||||
#define OV5693_CROP_START_Y_REG OV5693_REG_16BIT(0x3802)
|
#define OV5693_CROP_START_Y_REG CCI_REG16(0x3802)
|
||||||
#define OV5693_CROP_END_X_REG OV5693_REG_16BIT(0x3804)
|
#define OV5693_CROP_END_X_REG CCI_REG16(0x3804)
|
||||||
#define OV5693_CROP_END_Y_REG OV5693_REG_16BIT(0x3806)
|
#define OV5693_CROP_END_Y_REG CCI_REG16(0x3806)
|
||||||
#define OV5693_OUTPUT_SIZE_X_REG OV5693_REG_16BIT(0x3808)
|
#define OV5693_OUTPUT_SIZE_X_REG CCI_REG16(0x3808)
|
||||||
#define OV5693_OUTPUT_SIZE_Y_REG OV5693_REG_16BIT(0x380a)
|
#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_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_MAX_VTS 0xffff
|
||||||
#define OV5693_TIMING_MIN_VTS 0x04
|
#define OV5693_TIMING_MIN_VTS 0x04
|
||||||
|
|
||||||
#define OV5693_OFFSET_START_X_REG OV5693_REG_16BIT(0x3810)
|
#define OV5693_OFFSET_START_X_REG CCI_REG16(0x3810)
|
||||||
#define OV5693_OFFSET_START_Y_REG OV5693_REG_16BIT(0x3812)
|
#define OV5693_OFFSET_START_Y_REG CCI_REG16(0x3812)
|
||||||
|
|
||||||
#define OV5693_SUB_INC_X_REG OV5693_REG_8BIT(0x3814)
|
#define OV5693_SUB_INC_X_REG CCI_REG8(0x3814)
|
||||||
#define OV5693_SUB_INC_Y_REG OV5693_REG_8BIT(0x3815)
|
#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_ISP_EN BIT(6)
|
||||||
#define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1)
|
#define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1)
|
||||||
#define OV5693_FORMAT1_VBIN_EN BIT(0)
|
#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_HDR_EN BIT(7)
|
||||||
#define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2)
|
#define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2)
|
||||||
#define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1)
|
#define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1)
|
||||||
#define OV5693_FORMAT2_HBIN_EN BIT(0)
|
#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)
|
#define OV5693_ISP_SCALE_ENABLE BIT(7)
|
||||||
|
|
||||||
/* Pixel Array */
|
/* Pixel Array */
|
||||||
@@ -116,7 +111,7 @@
|
|||||||
#define OV5693_MIN_CROP_HEIGHT 2
|
#define OV5693_MIN_CROP_HEIGHT 2
|
||||||
|
|
||||||
/* Test Pattern */
|
/* 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_ENABLE BIT(7)
|
||||||
#define OV5693_TEST_PATTERN_ROLLING BIT(6)
|
#define OV5693_TEST_PATTERN_ROLLING BIT(6)
|
||||||
#define OV5693_TEST_PATTERN_RANDOM 0x01
|
#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)
|
#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 ov5693_device {
|
||||||
struct i2c_client *client;
|
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
|
||||||
/* Protect against concurrent changes to controls */
|
/* Protect against concurrent changes to controls */
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
@@ -189,156 +174,151 @@ struct ov5693_device {
|
|||||||
} ctrls;
|
} ctrls;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ov5693_reg ov5693_global_regs[] = {
|
static const struct cci_reg_sequence ov5693_global_regs[] = {
|
||||||
{OV5693_REG_8BIT(0x3016), 0xf0},
|
{CCI_REG8(0x3016), 0xf0},
|
||||||
{OV5693_REG_8BIT(0x3017), 0xf0},
|
{CCI_REG8(0x3017), 0xf0},
|
||||||
{OV5693_REG_8BIT(0x3018), 0xf0},
|
{CCI_REG8(0x3018), 0xf0},
|
||||||
{OV5693_REG_8BIT(0x3022), 0x01},
|
{CCI_REG8(0x3022), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3028), 0x44},
|
{CCI_REG8(0x3028), 0x44},
|
||||||
{OV5693_REG_8BIT(0x3098), 0x02},
|
{CCI_REG8(0x3098), 0x02},
|
||||||
{OV5693_REG_8BIT(0x3099), 0x19},
|
{CCI_REG8(0x3099), 0x19},
|
||||||
{OV5693_REG_8BIT(0x309a), 0x02},
|
{CCI_REG8(0x309a), 0x02},
|
||||||
{OV5693_REG_8BIT(0x309b), 0x01},
|
{CCI_REG8(0x309b), 0x01},
|
||||||
{OV5693_REG_8BIT(0x309c), 0x00},
|
{CCI_REG8(0x309c), 0x00},
|
||||||
{OV5693_REG_8BIT(0x30a0), 0xd2},
|
{CCI_REG8(0x30a0), 0xd2},
|
||||||
{OV5693_REG_8BIT(0x30a2), 0x01},
|
{CCI_REG8(0x30a2), 0x01},
|
||||||
{OV5693_REG_8BIT(0x30b2), 0x00},
|
{CCI_REG8(0x30b2), 0x00},
|
||||||
{OV5693_REG_8BIT(0x30b3), 0x83},
|
{CCI_REG8(0x30b3), 0x83},
|
||||||
{OV5693_REG_8BIT(0x30b4), 0x03},
|
{CCI_REG8(0x30b4), 0x03},
|
||||||
{OV5693_REG_8BIT(0x30b5), 0x04},
|
{CCI_REG8(0x30b5), 0x04},
|
||||||
{OV5693_REG_8BIT(0x30b6), 0x01},
|
{CCI_REG8(0x30b6), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3080), 0x01},
|
{CCI_REG8(0x3080), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3104), 0x21},
|
{CCI_REG8(0x3104), 0x21},
|
||||||
{OV5693_REG_8BIT(0x3106), 0x00},
|
{CCI_REG8(0x3106), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3406), 0x01},
|
{CCI_REG8(0x3406), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3503), 0x07},
|
{CCI_REG8(0x3503), 0x07},
|
||||||
{OV5693_REG_8BIT(0x350b), 0x40},
|
{CCI_REG8(0x350b), 0x40},
|
||||||
{OV5693_REG_8BIT(0x3601), 0x0a},
|
{CCI_REG8(0x3601), 0x0a},
|
||||||
{OV5693_REG_8BIT(0x3602), 0x38},
|
{CCI_REG8(0x3602), 0x38},
|
||||||
{OV5693_REG_8BIT(0x3612), 0x80},
|
{CCI_REG8(0x3612), 0x80},
|
||||||
{OV5693_REG_8BIT(0x3620), 0x54},
|
{CCI_REG8(0x3620), 0x54},
|
||||||
{OV5693_REG_8BIT(0x3621), 0xc7},
|
{CCI_REG8(0x3621), 0xc7},
|
||||||
{OV5693_REG_8BIT(0x3622), 0x0f},
|
{CCI_REG8(0x3622), 0x0f},
|
||||||
{OV5693_REG_8BIT(0x3625), 0x10},
|
{CCI_REG8(0x3625), 0x10},
|
||||||
{OV5693_REG_8BIT(0x3630), 0x55},
|
{CCI_REG8(0x3630), 0x55},
|
||||||
{OV5693_REG_8BIT(0x3631), 0xf4},
|
{CCI_REG8(0x3631), 0xf4},
|
||||||
{OV5693_REG_8BIT(0x3632), 0x00},
|
{CCI_REG8(0x3632), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3633), 0x34},
|
{CCI_REG8(0x3633), 0x34},
|
||||||
{OV5693_REG_8BIT(0x3634), 0x02},
|
{CCI_REG8(0x3634), 0x02},
|
||||||
{OV5693_REG_8BIT(0x364d), 0x0d},
|
{CCI_REG8(0x364d), 0x0d},
|
||||||
{OV5693_REG_8BIT(0x364f), 0xdd},
|
{CCI_REG8(0x364f), 0xdd},
|
||||||
{OV5693_REG_8BIT(0x3660), 0x04},
|
{CCI_REG8(0x3660), 0x04},
|
||||||
{OV5693_REG_8BIT(0x3662), 0x10},
|
{CCI_REG8(0x3662), 0x10},
|
||||||
{OV5693_REG_8BIT(0x3663), 0xf1},
|
{CCI_REG8(0x3663), 0xf1},
|
||||||
{OV5693_REG_8BIT(0x3665), 0x00},
|
{CCI_REG8(0x3665), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3666), 0x20},
|
{CCI_REG8(0x3666), 0x20},
|
||||||
{OV5693_REG_8BIT(0x3667), 0x00},
|
{CCI_REG8(0x3667), 0x00},
|
||||||
{OV5693_REG_8BIT(0x366a), 0x80},
|
{CCI_REG8(0x366a), 0x80},
|
||||||
{OV5693_REG_8BIT(0x3680), 0xe0},
|
{CCI_REG8(0x3680), 0xe0},
|
||||||
{OV5693_REG_8BIT(0x3681), 0x00},
|
{CCI_REG8(0x3681), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3700), 0x42},
|
{CCI_REG8(0x3700), 0x42},
|
||||||
{OV5693_REG_8BIT(0x3701), 0x14},
|
{CCI_REG8(0x3701), 0x14},
|
||||||
{OV5693_REG_8BIT(0x3702), 0xa0},
|
{CCI_REG8(0x3702), 0xa0},
|
||||||
{OV5693_REG_8BIT(0x3703), 0xd8},
|
{CCI_REG8(0x3703), 0xd8},
|
||||||
{OV5693_REG_8BIT(0x3704), 0x78},
|
{CCI_REG8(0x3704), 0x78},
|
||||||
{OV5693_REG_8BIT(0x3705), 0x02},
|
{CCI_REG8(0x3705), 0x02},
|
||||||
{OV5693_REG_8BIT(0x370a), 0x00},
|
{CCI_REG8(0x370a), 0x00},
|
||||||
{OV5693_REG_8BIT(0x370b), 0x20},
|
{CCI_REG8(0x370b), 0x20},
|
||||||
{OV5693_REG_8BIT(0x370c), 0x0c},
|
{CCI_REG8(0x370c), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x370d), 0x11},
|
{CCI_REG8(0x370d), 0x11},
|
||||||
{OV5693_REG_8BIT(0x370e), 0x00},
|
{CCI_REG8(0x370e), 0x00},
|
||||||
{OV5693_REG_8BIT(0x370f), 0x40},
|
{CCI_REG8(0x370f), 0x40},
|
||||||
{OV5693_REG_8BIT(0x3710), 0x00},
|
{CCI_REG8(0x3710), 0x00},
|
||||||
{OV5693_REG_8BIT(0x371a), 0x1c},
|
{CCI_REG8(0x371a), 0x1c},
|
||||||
{OV5693_REG_8BIT(0x371b), 0x05},
|
{CCI_REG8(0x371b), 0x05},
|
||||||
{OV5693_REG_8BIT(0x371c), 0x01},
|
{CCI_REG8(0x371c), 0x01},
|
||||||
{OV5693_REG_8BIT(0x371e), 0xa1},
|
{CCI_REG8(0x371e), 0xa1},
|
||||||
{OV5693_REG_8BIT(0x371f), 0x0c},
|
{CCI_REG8(0x371f), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x3721), 0x00},
|
{CCI_REG8(0x3721), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3724), 0x10},
|
{CCI_REG8(0x3724), 0x10},
|
||||||
{OV5693_REG_8BIT(0x3726), 0x00},
|
{CCI_REG8(0x3726), 0x00},
|
||||||
{OV5693_REG_8BIT(0x372a), 0x01},
|
{CCI_REG8(0x372a), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3730), 0x10},
|
{CCI_REG8(0x3730), 0x10},
|
||||||
{OV5693_REG_8BIT(0x3738), 0x22},
|
{CCI_REG8(0x3738), 0x22},
|
||||||
{OV5693_REG_8BIT(0x3739), 0xe5},
|
{CCI_REG8(0x3739), 0xe5},
|
||||||
{OV5693_REG_8BIT(0x373a), 0x50},
|
{CCI_REG8(0x373a), 0x50},
|
||||||
{OV5693_REG_8BIT(0x373b), 0x02},
|
{CCI_REG8(0x373b), 0x02},
|
||||||
{OV5693_REG_8BIT(0x373c), 0x41},
|
{CCI_REG8(0x373c), 0x41},
|
||||||
{OV5693_REG_8BIT(0x373f), 0x02},
|
{CCI_REG8(0x373f), 0x02},
|
||||||
{OV5693_REG_8BIT(0x3740), 0x42},
|
{CCI_REG8(0x3740), 0x42},
|
||||||
{OV5693_REG_8BIT(0x3741), 0x02},
|
{CCI_REG8(0x3741), 0x02},
|
||||||
{OV5693_REG_8BIT(0x3742), 0x18},
|
{CCI_REG8(0x3742), 0x18},
|
||||||
{OV5693_REG_8BIT(0x3743), 0x01},
|
{CCI_REG8(0x3743), 0x01},
|
||||||
{OV5693_REG_8BIT(0x3744), 0x02},
|
{CCI_REG8(0x3744), 0x02},
|
||||||
{OV5693_REG_8BIT(0x3747), 0x10},
|
{CCI_REG8(0x3747), 0x10},
|
||||||
{OV5693_REG_8BIT(0x374c), 0x04},
|
{CCI_REG8(0x374c), 0x04},
|
||||||
{OV5693_REG_8BIT(0x3751), 0xf0},
|
{CCI_REG8(0x3751), 0xf0},
|
||||||
{OV5693_REG_8BIT(0x3752), 0x00},
|
{CCI_REG8(0x3752), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3753), 0x00},
|
{CCI_REG8(0x3753), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3754), 0xc0},
|
{CCI_REG8(0x3754), 0xc0},
|
||||||
{OV5693_REG_8BIT(0x3755), 0x00},
|
{CCI_REG8(0x3755), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3756), 0x1a},
|
{CCI_REG8(0x3756), 0x1a},
|
||||||
{OV5693_REG_8BIT(0x3758), 0x00},
|
{CCI_REG8(0x3758), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3759), 0x0f},
|
{CCI_REG8(0x3759), 0x0f},
|
||||||
{OV5693_REG_8BIT(0x376b), 0x44},
|
{CCI_REG8(0x376b), 0x44},
|
||||||
{OV5693_REG_8BIT(0x375c), 0x04},
|
{CCI_REG8(0x375c), 0x04},
|
||||||
{OV5693_REG_8BIT(0x3774), 0x10},
|
{CCI_REG8(0x3774), 0x10},
|
||||||
{OV5693_REG_8BIT(0x3776), 0x00},
|
{CCI_REG8(0x3776), 0x00},
|
||||||
{OV5693_REG_8BIT(0x377f), 0x08},
|
{CCI_REG8(0x377f), 0x08},
|
||||||
{OV5693_REG_8BIT(0x3780), 0x22},
|
{CCI_REG8(0x3780), 0x22},
|
||||||
{OV5693_REG_8BIT(0x3781), 0x0c},
|
{CCI_REG8(0x3781), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x3784), 0x2c},
|
{CCI_REG8(0x3784), 0x2c},
|
||||||
{OV5693_REG_8BIT(0x3785), 0x1e},
|
{CCI_REG8(0x3785), 0x1e},
|
||||||
{OV5693_REG_8BIT(0x378f), 0xf5},
|
{CCI_REG8(0x378f), 0xf5},
|
||||||
{OV5693_REG_8BIT(0x3791), 0xb0},
|
{CCI_REG8(0x3791), 0xb0},
|
||||||
{OV5693_REG_8BIT(0x3795), 0x00},
|
{CCI_REG8(0x3795), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3796), 0x64},
|
{CCI_REG8(0x3796), 0x64},
|
||||||
{OV5693_REG_8BIT(0x3797), 0x11},
|
{CCI_REG8(0x3797), 0x11},
|
||||||
{OV5693_REG_8BIT(0x3798), 0x30},
|
{CCI_REG8(0x3798), 0x30},
|
||||||
{OV5693_REG_8BIT(0x3799), 0x41},
|
{CCI_REG8(0x3799), 0x41},
|
||||||
{OV5693_REG_8BIT(0x379a), 0x07},
|
{CCI_REG8(0x379a), 0x07},
|
||||||
{OV5693_REG_8BIT(0x379b), 0xb0},
|
{CCI_REG8(0x379b), 0xb0},
|
||||||
{OV5693_REG_8BIT(0x379c), 0x0c},
|
{CCI_REG8(0x379c), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x3a04), 0x06},
|
{CCI_REG8(0x3a04), 0x06},
|
||||||
{OV5693_REG_8BIT(0x3a05), 0x14},
|
{CCI_REG8(0x3a05), 0x14},
|
||||||
{OV5693_REG_8BIT(0x3e07), 0x20},
|
{CCI_REG8(0x3e07), 0x20},
|
||||||
{OV5693_REG_8BIT(0x4000), 0x08},
|
{CCI_REG8(0x4000), 0x08},
|
||||||
{OV5693_REG_8BIT(0x4001), 0x04},
|
{CCI_REG8(0x4001), 0x04},
|
||||||
{OV5693_REG_8BIT(0x4004), 0x08},
|
{CCI_REG8(0x4004), 0x08},
|
||||||
{OV5693_REG_8BIT(0x4006), 0x20},
|
{CCI_REG8(0x4006), 0x20},
|
||||||
{OV5693_REG_8BIT(0x4008), 0x24},
|
{CCI_REG8(0x4008), 0x24},
|
||||||
{OV5693_REG_8BIT(0x4009), 0x10},
|
{CCI_REG8(0x4009), 0x10},
|
||||||
{OV5693_REG_8BIT(0x4058), 0x00},
|
{CCI_REG8(0x4058), 0x00},
|
||||||
{OV5693_REG_8BIT(0x4101), 0xb2},
|
{CCI_REG8(0x4101), 0xb2},
|
||||||
{OV5693_REG_8BIT(0x4307), 0x31},
|
{CCI_REG8(0x4307), 0x31},
|
||||||
{OV5693_REG_8BIT(0x4511), 0x05},
|
{CCI_REG8(0x4511), 0x05},
|
||||||
{OV5693_REG_8BIT(0x4512), 0x01},
|
{CCI_REG8(0x4512), 0x01},
|
||||||
{OV5693_REG_8BIT(0x481f), 0x30},
|
{CCI_REG8(0x481f), 0x30},
|
||||||
{OV5693_REG_8BIT(0x4826), 0x2c},
|
{CCI_REG8(0x4826), 0x2c},
|
||||||
{OV5693_REG_8BIT(0x4d02), 0xfd},
|
{CCI_REG8(0x4d02), 0xfd},
|
||||||
{OV5693_REG_8BIT(0x4d03), 0xf5},
|
{CCI_REG8(0x4d03), 0xf5},
|
||||||
{OV5693_REG_8BIT(0x4d04), 0x0c},
|
{CCI_REG8(0x4d04), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x4d05), 0xcc},
|
{CCI_REG8(0x4d05), 0xcc},
|
||||||
{OV5693_REG_8BIT(0x4837), 0x0a},
|
{CCI_REG8(0x4837), 0x0a},
|
||||||
{OV5693_REG_8BIT(0x5003), 0x20},
|
{CCI_REG8(0x5003), 0x20},
|
||||||
{OV5693_REG_8BIT(0x5013), 0x00},
|
{CCI_REG8(0x5013), 0x00},
|
||||||
{OV5693_REG_8BIT(0x5842), 0x01},
|
{CCI_REG8(0x5842), 0x01},
|
||||||
{OV5693_REG_8BIT(0x5843), 0x2b},
|
{CCI_REG8(0x5843), 0x2b},
|
||||||
{OV5693_REG_8BIT(0x5844), 0x01},
|
{CCI_REG8(0x5844), 0x01},
|
||||||
{OV5693_REG_8BIT(0x5845), 0x92},
|
{CCI_REG8(0x5845), 0x92},
|
||||||
{OV5693_REG_8BIT(0x5846), 0x01},
|
{CCI_REG8(0x5846), 0x01},
|
||||||
{OV5693_REG_8BIT(0x5847), 0x8f},
|
{CCI_REG8(0x5847), 0x8f},
|
||||||
{OV5693_REG_8BIT(0x5848), 0x01},
|
{CCI_REG8(0x5848), 0x01},
|
||||||
{OV5693_REG_8BIT(0x5849), 0x0c},
|
{CCI_REG8(0x5849), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x5e10), 0x0c},
|
{CCI_REG8(0x5e10), 0x0c},
|
||||||
{OV5693_REG_8BIT(0x3820), 0x00},
|
{CCI_REG8(0x3820), 0x00},
|
||||||
{OV5693_REG_8BIT(0x3821), 0x1e},
|
{CCI_REG8(0x3821), 0x1e},
|
||||||
{OV5693_REG_8BIT(0x5041), 0x14}
|
{CCI_REG8(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 v4l2_rect ov5693_default_crop = {
|
static const struct v4l2_rect ov5693_default_crop = {
|
||||||
@@ -373,115 +353,6 @@ static const u8 ov5693_test_pattern_bits[] = {
|
|||||||
OV5693_TEST_PATTERN_ROLLING,
|
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 */
|
/* V4L2 Controls Functions */
|
||||||
|
|
||||||
static int ov5693_flip_vert_configure(struct ov5693_device *ov5693,
|
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;
|
OV5693_FORMAT1_FLIP_VERT_SENSOR_EN;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, bits,
|
ret = cci_update_bits(ov5693->regmap, OV5693_FORMAT1_REG, bits,
|
||||||
enable ? bits : 0);
|
enable ? bits : 0, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -506,8 +377,8 @@ static int ov5693_flip_horz_configure(struct ov5693_device *ov5693,
|
|||||||
OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN;
|
OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, bits,
|
ret = cci_update_bits(ov5693->regmap, OV5693_FORMAT2_REG, bits,
|
||||||
enable ? bits : 0);
|
enable ? bits : 0, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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)
|
static int ov5693_get_exposure(struct ov5693_device *ov5693, s32 *value)
|
||||||
{
|
{
|
||||||
u32 exposure;
|
u64 exposure;
|
||||||
int ret;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -536,17 +408,17 @@ static int ov5693_exposure_configure(struct ov5693_device *ov5693,
|
|||||||
|
|
||||||
exposure = (exposure << 4) & OV5693_EXPOSURE_CTRL_MASK;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain)
|
static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain)
|
||||||
{
|
{
|
||||||
u32 value;
|
u64 value;
|
||||||
int ret;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -563,9 +435,9 @@ static int ov5693_digital_gain_configure(struct ov5693_device *ov5693,
|
|||||||
|
|
||||||
gain &= OV5693_MWB_GAIN_MASK;
|
gain &= OV5693_MWB_GAIN_MASK;
|
||||||
|
|
||||||
ov5693_write_reg(ov5693, OV5693_MWB_RED_GAIN_REG, gain, &ret);
|
cci_write(ov5693->regmap, OV5693_MWB_RED_GAIN_REG, gain, &ret);
|
||||||
ov5693_write_reg(ov5693, OV5693_MWB_GREEN_GAIN_REG, gain, &ret);
|
cci_write(ov5693->regmap, OV5693_MWB_GREEN_GAIN_REG, gain, &ret);
|
||||||
ov5693_write_reg(ov5693, OV5693_MWB_BLUE_GAIN_REG, gain, &ret);
|
cci_write(ov5693->regmap, OV5693_MWB_BLUE_GAIN_REG, gain, &ret);
|
||||||
|
|
||||||
return 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;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -586,7 +458,7 @@ static int ov5693_vts_configure(struct ov5693_device *ov5693, u32 vblank)
|
|||||||
u16 vts = ov5693->mode.format.height + vblank;
|
u16 vts = ov5693->mode.format.height + vblank;
|
||||||
int ret = 0;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -595,8 +467,8 @@ static int ov5693_test_pattern_configure(struct ov5693_device *ov5693, u32 idx)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ov5693_write_reg(ov5693, OV5693_TEST_PATTERN_REG,
|
cci_write(ov5693->regmap, OV5693_TEST_PATTERN_REG,
|
||||||
ov5693_test_pattern_bits[idx], &ret);
|
ov5693_test_pattern_bits[idx], &ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -685,59 +557,54 @@ static int ov5693_mode_configure(struct ov5693_device *ov5693)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Crop Start X */
|
/* Crop Start X */
|
||||||
ov5693_write_reg(ov5693, OV5693_CROP_START_X_REG, mode->crop.left,
|
cci_write(ov5693->regmap, OV5693_CROP_START_X_REG, mode->crop.left,
|
||||||
&ret);
|
&ret);
|
||||||
|
|
||||||
/* Offset X */
|
/* 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 */
|
/* Output Size X */
|
||||||
ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_X_REG, mode->format.width,
|
cci_write(ov5693->regmap, OV5693_OUTPUT_SIZE_X_REG, mode->format.width,
|
||||||
&ret);
|
&ret);
|
||||||
|
|
||||||
/* Crop End X */
|
/* Crop End X */
|
||||||
ov5693_write_reg(ov5693, OV5693_CROP_END_X_REG,
|
cci_write(ov5693->regmap, OV5693_CROP_END_X_REG,
|
||||||
mode->crop.left + mode->crop.width, &ret);
|
mode->crop.left + mode->crop.width, &ret);
|
||||||
|
|
||||||
/* Horizontal Total Size */
|
/* Horizontal Total Size */
|
||||||
ov5693_write_reg(ov5693, OV5693_TIMING_HTS_REG, OV5693_FIXED_PPL,
|
cci_write(ov5693->regmap, OV5693_TIMING_HTS_REG, OV5693_FIXED_PPL,
|
||||||
&ret);
|
&ret);
|
||||||
|
|
||||||
/* Crop Start Y */
|
/* Crop Start Y */
|
||||||
ov5693_write_reg(ov5693, OV5693_CROP_START_Y_REG, mode->crop.top,
|
cci_write(ov5693->regmap, OV5693_CROP_START_Y_REG, mode->crop.top,
|
||||||
&ret);
|
&ret);
|
||||||
|
|
||||||
/* Offset Y */
|
/* 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 */
|
/* Output Size Y */
|
||||||
ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_Y_REG, mode->format.height,
|
cci_write(ov5693->regmap, OV5693_OUTPUT_SIZE_Y_REG, mode->format.height,
|
||||||
&ret);
|
&ret);
|
||||||
|
|
||||||
/* Crop End Y */
|
/* Crop End Y */
|
||||||
ov5693_write_reg(ov5693, OV5693_CROP_END_Y_REG,
|
cci_write(ov5693->regmap, OV5693_CROP_END_Y_REG,
|
||||||
mode->crop.top + mode->crop.height, &ret);
|
mode->crop.top + mode->crop.height, &ret);
|
||||||
|
|
||||||
/* Subsample X increase */
|
/* Subsample X increase */
|
||||||
ov5693_write_reg(ov5693, OV5693_SUB_INC_X_REG,
|
cci_write(ov5693->regmap, OV5693_SUB_INC_X_REG,
|
||||||
((mode->inc_x_odd << 4) & 0xf0) | 0x01, &ret);
|
((mode->inc_x_odd << 4) & 0xf0) | 0x01, &ret);
|
||||||
/* Subsample Y increase */
|
/* Subsample Y increase */
|
||||||
ov5693_write_reg(ov5693, OV5693_SUB_INC_Y_REG,
|
cci_write(ov5693->regmap, OV5693_SUB_INC_Y_REG,
|
||||||
((mode->inc_y_odd << 4) & 0xf0) | 0x01, &ret);
|
((mode->inc_y_odd << 4) & 0xf0) | 0x01, &ret);
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Binning */
|
/* Binning */
|
||||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG,
|
cci_update_bits(ov5693->regmap, OV5693_FORMAT1_REG,
|
||||||
OV5693_FORMAT1_VBIN_EN,
|
OV5693_FORMAT1_VBIN_EN,
|
||||||
mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0);
|
mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0, &ret);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG,
|
cci_update_bits(ov5693->regmap, OV5693_FORMAT2_REG,
|
||||||
OV5693_FORMAT2_HBIN_EN,
|
OV5693_FORMAT2_HBIN_EN,
|
||||||
mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0);
|
mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0, &ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -746,9 +613,9 @@ static int ov5693_enable_streaming(struct ov5693_device *ov5693, bool enable)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ov5693_write_reg(ov5693, OV5693_SW_STREAM_REG,
|
cci_write(ov5693->regmap, OV5693_SW_STREAM_REG,
|
||||||
enable ? OV5693_START_STREAMING :
|
enable ? OV5693_START_STREAMING : OV5693_STOP_STREAMING,
|
||||||
OV5693_STOP_STREAMING, &ret);
|
&ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -757,7 +624,7 @@ static int ov5693_sw_reset(struct ov5693_device *ov5693)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -771,7 +638,8 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
|
|||||||
return dev_err_probe(ov5693->dev, ret,
|
return dev_err_probe(ov5693->dev, ret,
|
||||||
"software reset error\n");
|
"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)
|
if (ret)
|
||||||
return dev_err_probe(ov5693->dev, ret,
|
return dev_err_probe(ov5693->dev, ret,
|
||||||
"global settings error\n");
|
"global settings error\n");
|
||||||
@@ -871,15 +739,15 @@ out_unlock:
|
|||||||
static int ov5693_detect(struct ov5693_device *ov5693)
|
static int ov5693_detect(struct ov5693_device *ov5693)
|
||||||
{
|
{
|
||||||
int ret;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (id != OV5693_CHIP_ID)
|
if (id != OV5693_CHIP_ID)
|
||||||
return dev_err_probe(ov5693->dev, -ENODEV,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1407,9 +1275,12 @@ static int ov5693_probe(struct i2c_client *client)
|
|||||||
if (!ov5693)
|
if (!ov5693)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ov5693->client = client;
|
|
||||||
ov5693->dev = &client->dev;
|
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);
|
ret = ov5693_check_hwcfg(ov5693);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -1210,7 +1210,7 @@ static struct i2c_driver ov7740_i2c_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "ov7740",
|
.name = "ov7740",
|
||||||
.pm = &ov7740_pm_ops,
|
.pm = &ov7740_pm_ops,
|
||||||
.of_match_table = of_match_ptr(ov7740_of_match),
|
.of_match_table = ov7740_of_match,
|
||||||
},
|
},
|
||||||
.probe = ov7740_probe,
|
.probe = ov7740_probe,
|
||||||
.remove = ov7740_remove,
|
.remove = ov7740_remove,
|
||||||
|
|||||||
@@ -567,7 +567,6 @@ again:
|
|||||||
static int rdacm20_probe(struct i2c_client *client)
|
static int rdacm20_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct rdacm20_device *dev;
|
struct rdacm20_device *dev;
|
||||||
struct fwnode_handle *ep;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
|
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
|
||||||
@@ -616,24 +615,12 @@ static int rdacm20_probe(struct i2c_client *client)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error_free_ctrls;
|
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);
|
ret = v4l2_async_register_subdev(&dev->sd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_put_node;
|
goto error_free_ctrls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_put_node:
|
|
||||||
fwnode_handle_put(ep);
|
|
||||||
error_free_ctrls:
|
error_free_ctrls:
|
||||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||||
error:
|
error:
|
||||||
@@ -650,7 +637,6 @@ static void rdacm20_remove(struct i2c_client *client)
|
|||||||
{
|
{
|
||||||
struct rdacm20_device *dev = i2c_to_rdacm20(client);
|
struct rdacm20_device *dev = i2c_to_rdacm20(client);
|
||||||
|
|
||||||
fwnode_handle_put(dev->sd.fwnode);
|
|
||||||
v4l2_async_unregister_subdev(&dev->sd);
|
v4l2_async_unregister_subdev(&dev->sd);
|
||||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||||
media_entity_cleanup(&dev->sd.entity);
|
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)
|
static int ov10640_check_id(struct rdacm21_device *dev)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
u8 val;
|
u8 val = 0;
|
||||||
|
|
||||||
/* Read OV10640 ID to test communications. */
|
/* Read OV10640 ID to test communications. */
|
||||||
for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
|
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)
|
static int rdacm21_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct rdacm21_device *dev;
|
struct rdacm21_device *dev;
|
||||||
struct fwnode_handle *ep;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
|
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
|
||||||
@@ -588,24 +587,12 @@ static int rdacm21_probe(struct i2c_client *client)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error_free_ctrls;
|
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);
|
ret = v4l2_async_register_subdev(&dev->sd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_put_node;
|
goto error_free_ctrls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_put_node:
|
|
||||||
fwnode_handle_put(dev->sd.fwnode);
|
|
||||||
error_free_ctrls:
|
error_free_ctrls:
|
||||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||||
error:
|
error:
|
||||||
|
|||||||
@@ -545,7 +545,14 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge)
|
|||||||
static int mipid02_stream_disable(struct mipid02_dev *bridge)
|
static int mipid02_stream_disable(struct mipid02_dev *bridge)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = bridge->i2c_client;
|
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 */
|
/* Disable all lanes */
|
||||||
ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0);
|
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)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
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,
|
static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
|
||||||
struct v4l2_subdev *s_subdev,
|
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 mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
|
||||||
struct i2c_client *client = bridge->i2c_client;
|
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,
|
static void mipid02_async_unbind(struct v4l2_async_notifier *notifier,
|
||||||
struct v4l2_subdev *s_subdev,
|
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 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 v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
|
||||||
struct i2c_client *client = bridge->i2c_client;
|
struct i2c_client *client = bridge->i2c_client;
|
||||||
struct v4l2_async_subdev *asd;
|
struct v4l2_async_connection *asd;
|
||||||
struct device_node *ep_node;
|
struct device_node *ep_node;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -911,10 +922,10 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
|
|||||||
bridge->rx = ep;
|
bridge->rx = ep;
|
||||||
|
|
||||||
/* register async notifier so we get noticed when sensor is connected */
|
/* 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,
|
asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier,
|
||||||
of_fwnode_handle(ep_node),
|
of_fwnode_handle(ep_node),
|
||||||
struct v4l2_async_subdev);
|
struct v4l2_async_connection);
|
||||||
of_node_put(ep_node);
|
of_node_put(ep_node);
|
||||||
|
|
||||||
if (IS_ERR(asd)) {
|
if (IS_ERR(asd)) {
|
||||||
@@ -924,7 +935,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
|
|||||||
}
|
}
|
||||||
bridge->notifier.ops = &mipid02_notifier_ops;
|
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)
|
if (ret)
|
||||||
v4l2_async_nf_cleanup(&bridge->notifier);
|
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));
|
err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||||
if (err != ARRAY_SIZE(msgs)) {
|
if (err != ARRAY_SIZE(msgs)) {
|
||||||
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
|
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n",
|
||||||
__func__, reg, client->addr);
|
__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);
|
err = i2c_transfer(client->adapter, &msg, 1);
|
||||||
if (err != 1) {
|
if (err != 1) {
|
||||||
v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
|
v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed: %d\n",
|
||||||
__func__, reg, client->addr);
|
__func__, reg, client->addr, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1426,7 +1426,7 @@ static int tc358746_init_controls(struct tc358746 *tc358746)
|
|||||||
|
|
||||||
static int tc358746_notify_bound(struct v4l2_async_notifier *notifier,
|
static int tc358746_notify_bound(struct v4l2_async_notifier *notifier,
|
||||||
struct v4l2_subdev *sd,
|
struct v4l2_subdev *sd,
|
||||||
struct v4l2_async_subdev *asd)
|
struct v4l2_async_connection *asd)
|
||||||
{
|
{
|
||||||
struct tc358746 *tc358746 =
|
struct tc358746 *tc358746 =
|
||||||
container_of(notifier, struct tc358746, notifier);
|
container_of(notifier, struct tc358746, notifier);
|
||||||
@@ -1445,7 +1445,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
|||||||
struct v4l2_fwnode_endpoint vep = {
|
struct v4l2_fwnode_endpoint vep = {
|
||||||
.bus_type = V4L2_MBUS_PARALLEL,
|
.bus_type = V4L2_MBUS_PARALLEL,
|
||||||
};
|
};
|
||||||
struct v4l2_async_subdev *asd;
|
struct v4l2_async_connection *asd;
|
||||||
struct fwnode_handle *ep;
|
struct fwnode_handle *ep;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -1460,9 +1460,9 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
|||||||
return err;
|
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,
|
asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep,
|
||||||
struct v4l2_async_subdev);
|
struct v4l2_async_connection);
|
||||||
fwnode_handle_put(ep);
|
fwnode_handle_put(ep);
|
||||||
|
|
||||||
if (IS_ERR(asd)) {
|
if (IS_ERR(asd)) {
|
||||||
@@ -1472,13 +1472,10 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
|||||||
|
|
||||||
tc358746->notifier.ops = &tc358746_notify_ops;
|
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)
|
if (err)
|
||||||
goto err_cleanup;
|
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);
|
err = v4l2_async_register_subdev(&tc358746->sd);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unregister;
|
goto err_unregister;
|
||||||
@@ -1486,7 +1483,6 @@ static int tc358746_async_register(struct tc358746 *tc358746)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_unregister:
|
err_unregister:
|
||||||
fwnode_handle_put(tc358746->sd.fwnode);
|
|
||||||
v4l2_async_nf_unregister(&tc358746->notifier);
|
v4l2_async_nf_unregister(&tc358746->notifier);
|
||||||
err_cleanup:
|
err_cleanup:
|
||||||
v4l2_async_nf_cleanup(&tc358746->notifier);
|
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_fwnode_endpoint_free(&tc358746->csi_vep);
|
||||||
v4l2_async_nf_unregister(&tc358746->notifier);
|
v4l2_async_nf_unregister(&tc358746->notifier);
|
||||||
v4l2_async_nf_cleanup(&tc358746->notifier);
|
v4l2_async_nf_cleanup(&tc358746->notifier);
|
||||||
fwnode_handle_put(sd->fwnode);
|
|
||||||
v4l2_async_unregister_subdev(sd);
|
v4l2_async_unregister_subdev(sd);
|
||||||
media_entity_cleanup(&sd->entity);
|
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",
|
tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
|
||||||
v4l2c->name, v4l2c->label ?
|
v4l2c->name, v4l2c->label ?
|
||||||
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);
|
ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0);
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ config VIDEO_PCI_SKELETON
|
|||||||
Enable build of the skeleton PCI driver, used as a reference
|
Enable build of the skeleton PCI driver, used as a reference
|
||||||
when developing new drivers.
|
when developing new drivers.
|
||||||
|
|
||||||
source "drivers/media/pci/intel/ipu3/Kconfig"
|
source "drivers/media/pci/intel/Kconfig"
|
||||||
|
|
||||||
endif #MEDIA_PCI_SUPPORT
|
endif #MEDIA_PCI_SUPPORT
|
||||||
endif #PCI
|
endif #PCI
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ config VIDEO_BT848
|
|||||||
tristate "BT848 Video For Linux"
|
tristate "BT848 Video For Linux"
|
||||||
depends on PCI && I2C && VIDEO_DEV
|
depends on PCI && I2C && VIDEO_DEV
|
||||||
select I2C_ALGOBIT
|
select I2C_ALGOBIT
|
||||||
select VIDEOBUF_DMA_SG
|
select VIDEOBUF2_DMA_SG
|
||||||
depends on RC_CORE
|
depends on RC_CORE
|
||||||
depends on MEDIA_RADIO_SUPPORT
|
depends on MEDIA_RADIO_SUPPORT
|
||||||
select VIDEO_TUNER
|
select VIDEO_TUNER
|
||||||
|
|||||||
@@ -231,7 +231,15 @@
|
|||||||
|
|
||||||
#define BT848_INT_ETBF (1<<23)
|
#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 (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_RISC_EN (1<<27)
|
||||||
#define BT848_INT_RACK (1<<25)
|
#define BT848_INT_RACK (1<<25)
|
||||||
#define BT848_INT_FIELD (1<<24)
|
#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;
|
unsigned long val;
|
||||||
|
|
||||||
if (!set) {
|
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;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
|
/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
|
||||||
switch (t->audmode) {
|
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 */
|
/* scan lines */
|
||||||
sg = sglist;
|
sg = sglist;
|
||||||
for (line = 0; line < store_lines; line++) {
|
for (line = 0; line < store_lines; line++) {
|
||||||
if ((btv->opt_vcr_hack) &&
|
if ((line >= (store_lines - VCR_HACK_LINES)) &&
|
||||||
(line >= (store_lines - VCR_HACK_LINES)))
|
(btv->opt_vcr_hack ||
|
||||||
|
(V4L2_FIELD_HAS_BOTH(btv->field) ||
|
||||||
|
btv->field == V4L2_FIELD_ALTERNATE)))
|
||||||
continue;
|
continue;
|
||||||
while (offset && offset >= sg_dma_len(sg)) {
|
while (offset && offset >= sg_dma_len(sg)) {
|
||||||
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 */
|
/* save pointer to jmp instruction address */
|
||||||
risc->jmp = rp;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +229,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
|
|||||||
|
|
||||||
/* save pointer to jmp instruction address */
|
/* save pointer to jmp instruction address */
|
||||||
risc->jmp = rp;
|
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;
|
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 */
|
/* risc group / risc main loop / dma management */
|
||||||
|
|
||||||
void
|
static void bttv_set_risc_status(struct bttv *btv)
|
||||||
bttv_set_dma(struct bttv *btv, int override)
|
|
||||||
{
|
{
|
||||||
unsigned long cmd;
|
unsigned long cmd = BT848_RISC_JUMP;
|
||||||
int capctl;
|
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;
|
static void bttv_set_irq_timer(struct bttv *btv)
|
||||||
if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
|
{
|
||||||
if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
|
if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi)
|
||||||
if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
|
mod_timer(&btv->timeout, jiffies + BTTV_TIMEOUT);
|
||||||
|
else
|
||||||
|
del_timer(&btv->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
capctl = 0;
|
static int bttv_set_capture_control(struct bttv *btv, int start_capture)
|
||||||
capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
|
{
|
||||||
capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
|
int capctl = 0;
|
||||||
capctl |= override;
|
|
||||||
|
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",
|
d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
|
||||||
btv->c.nr,capctl,btv->loop_irq,
|
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->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
|
||||||
btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
|
btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
|
||||||
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->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
|
int
|
||||||
@@ -478,17 +506,50 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
|
||||||
bttv_dma_free(struct videobuf_queue *q,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);
|
const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
|
||||||
videobuf_dma_unmap(q->dev, dma);
|
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||||
videobuf_dma_free(dma);
|
struct scatterlist *list = sgt->sgl;
|
||||||
btcx_riscmem_free(btv->c.pci,&buf->bottom);
|
|
||||||
btcx_riscmem_free(btv->c.pci,&buf->top);
|
if (btv->vbi_fmt.fmt.count[0] > 0)
|
||||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
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
|
int
|
||||||
@@ -508,8 +569,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
|||||||
if (vbi) {
|
if (vbi) {
|
||||||
unsigned int crop, vdelay;
|
unsigned int crop, vdelay;
|
||||||
|
|
||||||
vbi->vb.state = VIDEOBUF_ACTIVE;
|
list_del(&vbi->list);
|
||||||
list_del(&vbi->vb.queue);
|
|
||||||
|
|
||||||
/* VDELAY is start of video, end of VBI capturing. */
|
/* VDELAY is start of video, end of VBI capturing. */
|
||||||
crop = btread(BT848_E_CROP);
|
crop = btread(BT848_E_CROP);
|
||||||
@@ -525,12 +585,12 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
|||||||
btwrite(crop, BT848_O_CROP);
|
btwrite(crop, BT848_O_CROP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vbi->vbi_count[0] > 0) {
|
if (btv->vbi_count[0] > 0) {
|
||||||
top = &vbi->top;
|
top = &vbi->top;
|
||||||
top_irq_flags = 4;
|
top_irq_flags = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vbi->vbi_count[1] > 0) {
|
if (btv->vbi_count[1] > 0) {
|
||||||
top_irq_flags = 0;
|
top_irq_flags = 0;
|
||||||
bottom = &vbi->bottom;
|
bottom = &vbi->bottom;
|
||||||
bottom_irq_flags = 4;
|
bottom_irq_flags = 4;
|
||||||
@@ -550,16 +610,13 @@ bttv_buffer_activate_video(struct bttv *btv,
|
|||||||
/* video capture */
|
/* video capture */
|
||||||
if (NULL != set->top && NULL != set->bottom) {
|
if (NULL != set->top && NULL != set->bottom) {
|
||||||
if (set->top == set->bottom) {
|
if (set->top == set->bottom) {
|
||||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
if (set->top->list.next)
|
||||||
if (set->top->vb.queue.next)
|
list_del(&set->top->list);
|
||||||
list_del(&set->top->vb.queue);
|
|
||||||
} else {
|
} else {
|
||||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
if (set->top->list.next)
|
||||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
list_del(&set->top->list);
|
||||||
if (set->top->vb.queue.next)
|
if (set->bottom->list.next)
|
||||||
list_del(&set->top->vb.queue);
|
list_del(&set->bottom->list);
|
||||||
if (set->bottom->vb.queue.next)
|
|
||||||
list_del(&set->bottom->vb.queue);
|
|
||||||
}
|
}
|
||||||
bttv_apply_geo(btv, &set->top->geo, 1);
|
bttv_apply_geo(btv, &set->top->geo, 1);
|
||||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
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),
|
btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
|
||||||
~0x0f, BT848_COLOR_CTL);
|
~0x0f, BT848_COLOR_CTL);
|
||||||
} else if (NULL != set->top) {
|
} else if (NULL != set->top) {
|
||||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
if (set->top->list.next)
|
||||||
if (set->top->vb.queue.next)
|
list_del(&set->top->list);
|
||||||
list_del(&set->top->vb.queue);
|
|
||||||
bttv_apply_geo(btv, &set->top->geo,1);
|
bttv_apply_geo(btv, &set->top->geo,1);
|
||||||
bttv_apply_geo(btv, &set->top->geo,0);
|
bttv_apply_geo(btv, &set->top->geo,0);
|
||||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
|
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->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
|
||||||
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
|
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
|
||||||
} else if (NULL != set->bottom) {
|
} else if (NULL != set->bottom) {
|
||||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
if (set->bottom->list.next)
|
||||||
if (set->bottom->vb.queue.next)
|
list_del(&set->bottom->list);
|
||||||
list_del(&set->bottom->vb.queue);
|
|
||||||
bttv_apply_geo(btv, &set->bottom->geo,1);
|
bttv_apply_geo(btv, &set->bottom->geo,1);
|
||||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
bttv_apply_geo(btv, &set->bottom->geo,0);
|
||||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
|
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
|
||||||
@@ -606,156 +661,146 @@ bttv_buffer_activate_video(struct bttv *btv,
|
|||||||
int
|
int
|
||||||
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||||
{
|
{
|
||||||
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
|
int r = 0;
|
||||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
|
||||||
|
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||||
dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n",
|
struct scatterlist *list = sgt->sgl;
|
||||||
btv->c.nr, v4l2_field_names[buf->vb.field],
|
unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;
|
||||||
buf->fmt->fourcc, buf->vb.width, buf->vb.height);
|
|
||||||
|
|
||||||
/* packed pixel modes */
|
/* packed pixel modes */
|
||||||
if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
|
if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
|
||||||
int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
|
int bpl = (btv->fmt->depth >> 3) * btv->width;
|
||||||
int bpf = bpl * (buf->vb.height >> 1);
|
int bpf = bpl * (btv->height >> 1);
|
||||||
|
|
||||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
|
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||||
V4L2_FIELD_HAS_BOTH(buf->vb.field),
|
V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
|
||||||
tvnorm,&buf->crop);
|
&btv->crop[!!btv->do_crop].rect);
|
||||||
|
switch (buf->vbuf.field) {
|
||||||
switch (buf->vb.field) {
|
|
||||||
case V4L2_FIELD_TOP:
|
case V4L2_FIELD_TOP:
|
||||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||||
/* offset */ 0,bpl,
|
0, btv->height);
|
||||||
/* padding */ 0,/* skip_lines */ 0,
|
|
||||||
buf->vb.height);
|
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_BOTTOM:
|
case V4L2_FIELD_BOTTOM:
|
||||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
|
||||||
0,bpl,0,0,buf->vb.height);
|
0, 0, btv->height);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_INTERLACED:
|
case V4L2_FIELD_INTERLACED:
|
||||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
|
||||||
0,bpl,bpl,0,buf->vb.height >> 1);
|
bpl, 0, btv->height >> 1);
|
||||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
|
||||||
bpl,bpl,bpl,0,buf->vb.height >> 1);
|
bpl, bpl, 0, btv->height >> 1);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_SEQ_TB:
|
case V4L2_FIELD_SEQ_TB:
|
||||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||||
0,bpl,0,0,buf->vb.height >> 1);
|
0, btv->height >> 1);
|
||||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
|
||||||
bpf,bpl,0,0,buf->vb.height >> 1);
|
bpl, 0, 0, btv->height >> 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
WARN_ON(1);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* planar modes */
|
/* planar modes */
|
||||||
if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
||||||
int uoffset, voffset;
|
int uoffset, voffset;
|
||||||
int ypadding, cpadding, lines;
|
int ypadding, cpadding, lines;
|
||||||
|
|
||||||
/* calculate chroma offsets */
|
/* calculate chroma offsets */
|
||||||
uoffset = buf->vb.width * buf->vb.height;
|
uoffset = btv->width * btv->height;
|
||||||
voffset = buf->vb.width * buf->vb.height;
|
voffset = btv->width * btv->height;
|
||||||
if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
|
if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
|
||||||
/* Y-Cr-Cb plane order */
|
/* Y-Cr-Cb plane order */
|
||||||
uoffset >>= buf->fmt->hshift;
|
uoffset >>= btv->fmt->hshift;
|
||||||
uoffset >>= buf->fmt->vshift;
|
uoffset >>= btv->fmt->vshift;
|
||||||
uoffset += voffset;
|
uoffset += voffset;
|
||||||
} else {
|
} else {
|
||||||
/* Y-Cb-Cr plane order */
|
/* Y-Cb-Cr plane order */
|
||||||
voffset >>= buf->fmt->hshift;
|
voffset >>= btv->fmt->hshift;
|
||||||
voffset >>= buf->fmt->vshift;
|
voffset >>= btv->fmt->vshift;
|
||||||
voffset += uoffset;
|
voffset += uoffset;
|
||||||
}
|
}
|
||||||
|
switch (buf->vbuf.field) {
|
||||||
switch (buf->vb.field) {
|
|
||||||
case V4L2_FIELD_TOP:
|
case V4L2_FIELD_TOP:
|
||||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||||
buf->vb.height,/* both_fields */ 0,
|
0, tvnorm,
|
||||||
tvnorm,&buf->crop);
|
&btv->crop[!!btv->do_crop].rect);
|
||||||
bttv_risc_planar(btv, &buf->top, dma->sglist,
|
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||||
0,buf->vb.width,0,buf->vb.height,
|
btv->width, 0, btv->height,
|
||||||
uoffset,voffset,buf->fmt->hshift,
|
uoffset, voffset,
|
||||||
buf->fmt->vshift,0);
|
btv->fmt->hshift,
|
||||||
|
btv->fmt->vshift, 0);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_BOTTOM:
|
case V4L2_FIELD_BOTTOM:
|
||||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||||
buf->vb.height,0,
|
0, tvnorm,
|
||||||
tvnorm,&buf->crop);
|
&btv->crop[!!btv->do_crop].rect);
|
||||||
bttv_risc_planar(btv, &buf->bottom, dma->sglist,
|
r = bttv_risc_planar(btv, &buf->bottom, list, 0,
|
||||||
0,buf->vb.width,0,buf->vb.height,
|
btv->width, 0, btv->height,
|
||||||
uoffset,voffset,buf->fmt->hshift,
|
uoffset, voffset,
|
||||||
buf->fmt->vshift,0);
|
btv->fmt->hshift,
|
||||||
|
btv->fmt->vshift, 0);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_INTERLACED:
|
case V4L2_FIELD_INTERLACED:
|
||||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||||
buf->vb.height,1,
|
1, tvnorm,
|
||||||
tvnorm,&buf->crop);
|
&btv->crop[!!btv->do_crop].rect);
|
||||||
lines = buf->vb.height >> 1;
|
lines = btv->height >> 1;
|
||||||
ypadding = buf->vb.width;
|
ypadding = btv->width;
|
||||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
cpadding = btv->width >> btv->fmt->hshift;
|
||||||
bttv_risc_planar(btv,&buf->top,
|
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||||
dma->sglist,
|
btv->width, ypadding, lines,
|
||||||
0,buf->vb.width,ypadding,lines,
|
uoffset, voffset,
|
||||||
uoffset,voffset,
|
btv->fmt->hshift,
|
||||||
buf->fmt->hshift,
|
btv->fmt->vshift, cpadding);
|
||||||
buf->fmt->vshift,
|
|
||||||
cpadding);
|
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||||
bttv_risc_planar(btv,&buf->bottom,
|
ypadding, btv->width, ypadding,
|
||||||
dma->sglist,
|
lines, uoffset + cpadding,
|
||||||
ypadding,buf->vb.width,ypadding,lines,
|
voffset + cpadding,
|
||||||
uoffset+cpadding,
|
btv->fmt->hshift,
|
||||||
voffset+cpadding,
|
btv->fmt->vshift, cpadding);
|
||||||
buf->fmt->hshift,
|
|
||||||
buf->fmt->vshift,
|
|
||||||
cpadding);
|
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_SEQ_TB:
|
case V4L2_FIELD_SEQ_TB:
|
||||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||||
buf->vb.height,1,
|
1, tvnorm,
|
||||||
tvnorm,&buf->crop);
|
&btv->crop[!!btv->do_crop].rect);
|
||||||
lines = buf->vb.height >> 1;
|
lines = btv->height >> 1;
|
||||||
ypadding = buf->vb.width;
|
ypadding = btv->width;
|
||||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
cpadding = btv->width >> btv->fmt->hshift;
|
||||||
bttv_risc_planar(btv,&buf->top,
|
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||||
dma->sglist,
|
btv->width, 0, lines,
|
||||||
0,buf->vb.width,0,lines,
|
uoffset >> 1, voffset >> 1,
|
||||||
uoffset >> 1,
|
btv->fmt->hshift,
|
||||||
voffset >> 1,
|
btv->fmt->vshift, 0);
|
||||||
buf->fmt->hshift,
|
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||||
buf->fmt->vshift,
|
lines * ypadding,
|
||||||
0);
|
btv->width, 0, lines,
|
||||||
bttv_risc_planar(btv,&buf->bottom,
|
lines * ypadding + (uoffset >> 1),
|
||||||
dma->sglist,
|
lines * ypadding + (voffset >> 1),
|
||||||
lines * ypadding,buf->vb.width,0,lines,
|
btv->fmt->hshift,
|
||||||
lines * ypadding + (uoffset >> 1),
|
btv->fmt->vshift, 0);
|
||||||
lines * ypadding + (voffset >> 1),
|
|
||||||
buf->fmt->hshift,
|
|
||||||
buf->fmt->vshift,
|
|
||||||
0);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
WARN_ON(1);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* raw data */
|
/* raw data */
|
||||||
if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
|
if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
|
||||||
/* build risc code */
|
/* build risc code */
|
||||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
buf->vbuf.field = V4L2_FIELD_SEQ_TB;
|
||||||
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
|
bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
|
||||||
1,tvnorm,&buf->crop);
|
1, tvnorm, &btv->crop[!!btv->do_crop].rect);
|
||||||
bttv_risc_packed(btv, &buf->top, dma->sglist,
|
r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
|
||||||
/* offset */ 0, RAW_BPL, /* padding */ 0,
|
RAW_LINES);
|
||||||
/* skip_lines */ 0, RAW_LINES);
|
r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
|
||||||
bttv_risc_packed(btv, &buf->bottom, dma->sglist,
|
RAW_BPL, 0, 0, RAW_LINES);
|
||||||
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy format info */
|
/* copy format info */
|
||||||
buf->btformat = buf->fmt->btformat;
|
buf->btformat = btv->fmt->btformat;
|
||||||
buf->btswap = buf->fmt->btswap;
|
buf->btswap = btv->fmt->btswap;
|
||||||
return 0;
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,16 +34,6 @@
|
|||||||
to be about 244. */
|
to be about 244. */
|
||||||
#define VBI_OFFSET 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 vbibufs = 4;
|
||||||
static unsigned int vbi_debug;
|
static unsigned int vbi_debug;
|
||||||
|
|
||||||
@@ -67,165 +57,123 @@ do { \
|
|||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* vbi risc code + mm */
|
/* vbi risc code + mm */
|
||||||
|
|
||||||
static int vbi_buffer_setup(struct videobuf_queue *q,
|
static int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
|
||||||
unsigned int *count, unsigned int *size)
|
unsigned int *num_planes, unsigned int sizes[],
|
||||||
|
struct device *alloc_devs[])
|
||||||
{
|
{
|
||||||
struct bttv_fh *fh = q->priv_data;
|
struct bttv *btv = vb2_get_drv_priv(q);
|
||||||
struct bttv *btv = fh->btv;
|
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
|
||||||
|
|
||||||
if (0 == *count)
|
if (*num_planes)
|
||||||
*count = vbibufs;
|
return sizes[0] < size ? -EINVAL : 0;
|
||||||
|
*num_planes = 1;
|
||||||
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
sizes[0] = size;
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vbi_buffer_prepare(struct videobuf_queue *q,
|
static void buf_queue_vbi(struct vb2_buffer *vb)
|
||||||
struct videobuf_buffer *vb,
|
|
||||||
enum v4l2_field field)
|
|
||||||
{
|
{
|
||||||
struct bttv_fh *fh = q->priv_data;
|
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||||
struct bttv *btv = fh->btv;
|
struct vb2_queue *vq = vb->vb2_queue;
|
||||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||||
const struct bttv_tvnorm *tvnorm;
|
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||||
unsigned int skip_lines0, skip_lines1, min_vdelay;
|
unsigned long flags;
|
||||||
int redo_dma_risc;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
spin_lock_irqsave(&btv->s_lock, flags);
|
||||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
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;
|
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;
|
return ret;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void buf_cleanup_vbi(struct vb2_buffer *vb)
|
||||||
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
|
||||||
{
|
{
|
||||||
struct bttv_fh *fh = q->priv_data;
|
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||||
struct bttv *btv = fh->btv;
|
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
struct vb2_queue *vq = vb->vb2_queue;
|
||||||
|
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||||
|
|
||||||
dprintk("queue %p\n",vb);
|
btcx_riscmem_free(btv->c.pci, &buf->top);
|
||||||
buf->vb.state = VIDEOBUF_QUEUED;
|
btcx_riscmem_free(btv->c.pci, &buf->bottom);
|
||||||
list_add_tail(&buf->vb.queue,&btv->vcapture);
|
|
||||||
if (NULL == btv->cvbi) {
|
|
||||||
fh->btv->loop_irq |= 4;
|
|
||||||
bttv_set_dma(btv,0x0c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
int ret;
|
||||||
struct bttv *btv = fh->btv;
|
int seqnr = 0;
|
||||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
struct bttv_buffer *buf;
|
||||||
|
struct bttv *btv = vb2_get_drv_priv(q);
|
||||||
|
|
||||||
dprintk("free %p\n",vb);
|
btv->framedrop = 0;
|
||||||
bttv_dma_free(q,fh->btv,buf);
|
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 = {
|
static void stop_streaming_vbi(struct vb2_queue *q)
|
||||||
.buf_setup = vbi_buffer_setup,
|
{
|
||||||
.buf_prepare = vbi_buffer_prepare,
|
struct bttv *btv = vb2_get_drv_priv(q);
|
||||||
.buf_queue = vbi_buffer_queue,
|
unsigned long flags;
|
||||||
.buf_release = vbi_buffer_release,
|
|
||||||
|
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)
|
if (min_start > max_start)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
BUG_ON(max_start >= max_end);
|
WARN_ON(max_start >= max_end);
|
||||||
|
|
||||||
f->sampling_rate = tvnorm->Fsc;
|
f->sampling_rate = tvnorm->Fsc;
|
||||||
f->samples_per_line = VBI_BPL;
|
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)
|
int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||||
{
|
{
|
||||||
struct bttv_fh *fh = f;
|
struct bttv *btv = video_drvdata(file);
|
||||||
struct bttv *btv = fh->btv;
|
|
||||||
const struct bttv_tvnorm *tvnorm;
|
const struct bttv_tvnorm *tvnorm;
|
||||||
__s32 crop_start;
|
__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)
|
int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||||
{
|
{
|
||||||
struct bttv_fh *fh = f;
|
struct bttv *btv = video_drvdata(file);
|
||||||
struct bttv *btv = fh->btv;
|
|
||||||
const struct bttv_tvnorm *tvnorm;
|
const struct bttv_tvnorm *tvnorm;
|
||||||
__s32 start1, end;
|
__s32 start1, end;
|
||||||
int rc;
|
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);
|
mutex_lock(&btv->lock);
|
||||||
|
|
||||||
rc = -EBUSY;
|
rc = -EBUSY;
|
||||||
if (fh->resources & RESOURCE_VBI)
|
if (btv->resources & RESOURCE_VBI)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
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. */
|
because vbi_fmt.end counts field lines times two. */
|
||||||
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
|
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
|
||||||
|
|
||||||
mutex_lock(&fh->vbi.vb_lock);
|
btv->vbi_fmt.fmt = frt->fmt.vbi;
|
||||||
|
btv->vbi_fmt.tvnorm = tvnorm;
|
||||||
fh->vbi_fmt.fmt = frt->fmt.vbi;
|
btv->vbi_fmt.end = end;
|
||||||
fh->vbi_fmt.tvnorm = tvnorm;
|
|
||||||
fh->vbi_fmt.end = end;
|
|
||||||
|
|
||||||
mutex_unlock(&fh->vbi.vb_lock);
|
|
||||||
|
|
||||||
rc = 0;
|
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)
|
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;
|
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;
|
__s32 max_end;
|
||||||
unsigned int i;
|
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) {
|
for (i = 0; i < 2; ++i) {
|
||||||
__s32 new_start;
|
__s32 new_start;
|
||||||
|
|
||||||
new_start = frt->fmt.vbi.start[i]
|
new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i]
|
||||||
+ tvnorm->vbistart[i]
|
- btv->vbi_fmt.tvnorm->vbistart[i];
|
||||||
- fh->vbi_fmt.tvnorm->vbistart[i];
|
|
||||||
|
|
||||||
frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
|
frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
|
||||||
frt->fmt.vbi.count[i] =
|
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)
|
real_count = ((tvnorm->cropcap.defrect.top >> 1)
|
||||||
- tvnorm->vbistart[0]);
|
- tvnorm->vbistart[0]);
|
||||||
|
|
||||||
BUG_ON(real_samples_per_line > VBI_BPL);
|
WARN_ON(real_samples_per_line > VBI_BPL);
|
||||||
BUG_ON(real_count > VBI_DEFLINES);
|
WARN_ON(real_count > VBI_DEFLINES);
|
||||||
|
|
||||||
f->tvnorm = tvnorm;
|
f->tvnorm = tvnorm;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <media/v4l2-common.h>
|
#include <media/v4l2-common.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
#include <media/v4l2-fh.h>
|
#include <media/v4l2-fh.h>
|
||||||
#include <media/videobuf-dma-sg.h>
|
#include <media/videobuf2-dma-sg.h>
|
||||||
#include <media/tveeprom.h>
|
#include <media/tveeprom.h>
|
||||||
#include <media/rc-core.h>
|
#include <media/rc-core.h>
|
||||||
#include <media/i2c/ir-kbd-i2c.h>
|
#include <media/i2c/ir-kbd-i2c.h>
|
||||||
@@ -142,19 +142,15 @@ struct bttv_geometry {
|
|||||||
|
|
||||||
struct bttv_buffer {
|
struct bttv_buffer {
|
||||||
/* common v4l buffer stuff -- must be first */
|
/* common v4l buffer stuff -- must be first */
|
||||||
struct videobuf_buffer vb;
|
struct vb2_v4l2_buffer vbuf;
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
/* bttv specific */
|
/* bttv specific */
|
||||||
const struct bttv_format *fmt;
|
|
||||||
unsigned int tvnorm;
|
|
||||||
int btformat;
|
int btformat;
|
||||||
int btswap;
|
int btswap;
|
||||||
struct bttv_geometry geo;
|
struct bttv_geometry geo;
|
||||||
struct btcx_riscmem top;
|
struct btcx_riscmem top;
|
||||||
struct btcx_riscmem bottom;
|
struct btcx_riscmem bottom;
|
||||||
struct v4l2_rect crop;
|
|
||||||
unsigned int vbi_skip[2];
|
|
||||||
unsigned int vbi_count[2];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bttv_buffer_set {
|
struct bttv_buffer_set {
|
||||||
@@ -176,6 +172,8 @@ struct bttv_vbi_fmt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* bttv-vbi.c */
|
/* bttv-vbi.c */
|
||||||
|
extern const struct vb2_ops bttv_vbi_qops;
|
||||||
|
|
||||||
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
|
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
|
||||||
|
|
||||||
struct bttv_crop {
|
struct bttv_crop {
|
||||||
@@ -192,31 +190,6 @@ struct bttv_crop {
|
|||||||
__s32 max_scaled_height;
|
__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 */
|
/* 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_risc(struct bttv *btv, struct bttv_buffer *buf);
|
||||||
int bttv_buffer_activate_video(struct bttv *btv,
|
int bttv_buffer_activate_video(struct bttv *btv,
|
||||||
struct bttv_buffer_set *set);
|
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,
|
int bttv_buffer_activate_vbi(struct bttv *btv,
|
||||||
struct bttv_buffer *vbi);
|
struct bttv_buffer *vbi);
|
||||||
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
|
|
||||||
struct bttv_buffer *buf);
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------- */
|
/* ---------------------------------------------------------- */
|
||||||
/* bttv-vbi.c */
|
/* 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_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_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);
|
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 */
|
/* bttv-gpio.c */
|
||||||
|
|
||||||
@@ -275,6 +255,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
|
|||||||
extern unsigned int bttv_verbose;
|
extern unsigned int bttv_verbose;
|
||||||
extern unsigned int bttv_debug;
|
extern unsigned int bttv_debug;
|
||||||
extern unsigned int bttv_gpio;
|
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);
|
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
|
||||||
|
|
||||||
#define dprintk(fmt, ...) \
|
#define dprintk(fmt, ...) \
|
||||||
@@ -396,7 +378,7 @@ struct bttv {
|
|||||||
v4l2_std_id std;
|
v4l2_std_id std;
|
||||||
int hue, contrast, bright, saturation;
|
int hue, contrast, bright, saturation;
|
||||||
struct v4l2_framebuffer fbuf;
|
struct v4l2_framebuffer fbuf;
|
||||||
unsigned int field_count;
|
__u32 field_count;
|
||||||
|
|
||||||
/* various options */
|
/* various options */
|
||||||
int opt_combfilter;
|
int opt_combfilter;
|
||||||
@@ -436,7 +418,6 @@ struct bttv {
|
|||||||
int loop_irq;
|
int loop_irq;
|
||||||
int new_input;
|
int new_input;
|
||||||
|
|
||||||
unsigned long cap_ctl;
|
|
||||||
unsigned long dma_on;
|
unsigned long dma_on;
|
||||||
struct timer_list timeout;
|
struct timer_list timeout;
|
||||||
struct bttv_suspend_state state;
|
struct bttv_suspend_state state;
|
||||||
@@ -448,7 +429,25 @@ struct bttv {
|
|||||||
unsigned int irq_me;
|
unsigned int irq_me;
|
||||||
|
|
||||||
unsigned int users;
|
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 */
|
/* used to make dvb-bt8xx autoloadable */
|
||||||
struct work_struct request_module_wk;
|
struct work_struct request_module_wk;
|
||||||
@@ -487,6 +486,8 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void init_irqreg(struct bttv *btv);
|
||||||
|
|
||||||
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
|
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
|
||||||
#define btread(adr) readl(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)
|
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)
|
if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static void epu_cmd(struct cx18 *cx, u32 sw1)
|
|||||||
|
|
||||||
irqreturn_t cx18_irq_handler(int irq, void *dev_id)
|
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;
|
u32 sw1, sw2, hw2;
|
||||||
|
|
||||||
sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask;
|
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++) {
|
for (i = 0; i < 4; i++) {
|
||||||
risc = cx_read(ch->cmds_start + 4 * (i + 14));
|
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);
|
cx23885_risc_decode(risc);
|
||||||
}
|
}
|
||||||
for (i = 0; i < (64 >> 2); i += n) {
|
for (i = 0; i < (64 >> 2); i += n) {
|
||||||
risc = cx_read(ch->ctrl_start + 4 * i);
|
risc = cx_read(ch->ctrl_start + 4 * i);
|
||||||
/* No consideration for bits 63-32 */
|
/* 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);
|
ch->ctrl_start + 4 * i, i);
|
||||||
n = cx23885_risc_decode(risc);
|
n = cx23885_risc_decode(risc);
|
||||||
for (j = 1; j < n; j++) {
|
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",
|
pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
|
||||||
dev->name, risc->cpu, (unsigned long)risc->dma);
|
dev->name, risc->cpu, (unsigned long)risc->dma);
|
||||||
for (i = 0; i < (risc->size >> 2); i += n) {
|
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]));
|
n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
|
||||||
for (j = 1; j < n; j++)
|
for (j = 1; j < n; j++)
|
||||||
pr_info("%s: %04d: 0x%08x [ arg #%d ]\n",
|
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
Reference in New Issue
Block a user