Merge 835d31d319
("Merge tag 'media/v5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media") into android-mainline
Steps on the way to 5.15-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: If6d4fd429292ea554534d7ae86147343207a2622
This commit is contained in:
commit
ce9e960b12
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/media/amlogic,meson-ir-tx.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Amlogic Meson IR transmitter
|
||||
|
||||
maintainers:
|
||||
- Viktor Prutyanov <viktor.prutyanov@phystech.edu>
|
||||
|
||||
description: |
|
||||
Some Amlogic SoCs such as A311D and T950D4 have IR transmitter
|
||||
(also called blaster) controller onboard. It is capable of
|
||||
sending IR signals with arbitrary carrier frequency and duty cycle.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: amlogic,meson-ir-tx
|
||||
- items:
|
||||
- const: amlogic,meson-g12a-ir-tx
|
||||
- const: amlogic,meson-ir-tx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: sysclk
|
||||
- const: xtal
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/g12a-clkc.h>
|
||||
|
||||
ir@ff80014c {
|
||||
compatible = "amlogic,meson-g12a-ir-tx", "amlogic,meson-ir-tx";
|
||||
reg = <0xff80014c 0x10>;
|
||||
interrupts = <0 198 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc CLKID_CLK81>, <&xtal>;
|
||||
clock-names = "sysclk", "xtal";
|
||||
};
|
|
@ -35,6 +35,14 @@ properties:
|
|||
powerdown-gpios:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
adv,force-bt656-4:
|
||||
description:
|
||||
Indicates that the output is a BT.656-4 compatible stream.
|
||||
type: boolean
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/ovti,ov9282.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: OmniVision OV9282 Sensor
|
||||
|
||||
maintainers:
|
||||
- Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
- Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
|
||||
description:
|
||||
OV9282 sensor is an OmniVision black & white CMOS active pixel digital image
|
||||
sensor with an active array size of 1296H x 816V. It is programmable through
|
||||
I2C interface. The I2C client address is fixed to 0x60/0x70 as per sensor data
|
||||
sheet. Image data is sent through MIPI CSI-2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ovti,ov9282
|
||||
reg:
|
||||
description: I2C address
|
||||
maxItems: 1
|
||||
|
||||
assigned-clocks: true
|
||||
assigned-clock-parents: true
|
||||
assigned-clock-rates: true
|
||||
|
||||
clocks:
|
||||
description: Clock frequency from 6 to 27MHz
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: Reference to the GPIO connected to the XCLR pin, if any.
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
additionalProperties: false
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes: true
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
camera@60 {
|
||||
compatible = "ovti,ov9282";
|
||||
reg = <0x60>;
|
||||
clocks = <&ov9282_clk>;
|
||||
|
||||
assigned-clocks = <&ov9282_clk>;
|
||||
assigned-clock-parents = <&ov9282_clk_parent>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
|
||||
port {
|
||||
ov9282: endpoint {
|
||||
remote-endpoint = <&cam>;
|
||||
data-lanes = <1 2>;
|
||||
link-frequencies = /bits/ 64 <800000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,91 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/sony,imx335.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony IMX335 Sensor
|
||||
|
||||
maintainers:
|
||||
- Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
- Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
|
||||
description:
|
||||
IMX335 sensor is a Sony CMOS active pixel digital image sensor with an active
|
||||
array size of 2592H x 1944V. It is programmable through I2C interface. The
|
||||
I2C client address is fixed to 0x1a as per sensor data sheet. Image data is
|
||||
sent through MIPI CSI-2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sony,imx335
|
||||
reg:
|
||||
description: I2C address
|
||||
maxItems: 1
|
||||
|
||||
assigned-clocks: true
|
||||
assigned-clock-parents: true
|
||||
assigned-clock-rates: true
|
||||
|
||||
clocks:
|
||||
description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: Reference to the GPIO connected to the XCLR pin, if any.
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
additionalProperties: false
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes: true
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
camera@1a {
|
||||
compatible = "sony,imx335";
|
||||
reg = <0x1a>;
|
||||
clocks = <&imx335_clk>;
|
||||
|
||||
assigned-clocks = <&imx335_clk>;
|
||||
assigned-clock-parents = <&imx335_clk_parent>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
|
||||
port {
|
||||
imx335: endpoint {
|
||||
remote-endpoint = <&cam>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <594000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,91 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/sony,imx412.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony IMX412 Sensor
|
||||
|
||||
maintainers:
|
||||
- Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
- Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
|
||||
description:
|
||||
IMX412 sensor is a Sony CMOS active pixel digital image sensor with an active
|
||||
array size of 4072H x 3176V. It is programmable through I2C interface. The
|
||||
I2C client address is fixed to 0x1a as per sensor data sheet. Image data is
|
||||
sent through MIPI CSI-2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sony,imx412
|
||||
reg:
|
||||
description: I2C address
|
||||
maxItems: 1
|
||||
|
||||
assigned-clocks: true
|
||||
assigned-clock-parents: true
|
||||
assigned-clock-rates: true
|
||||
|
||||
clocks:
|
||||
description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: Reference to the GPIO connected to the XCLR pin, if any.
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
additionalProperties: false
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes: true
|
||||
link-frequencies: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
camera@1a {
|
||||
compatible = "sony,imx412";
|
||||
reg = <0x1a>;
|
||||
clocks = <&imx412_clk>;
|
||||
|
||||
assigned-clocks = <&imx412_clk>;
|
||||
assigned-clock-parents = <&imx412_clk_parent>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
|
||||
port {
|
||||
imx412: endpoint {
|
||||
remote-endpoint = <&cam>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <600000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -4,7 +4,7 @@
|
|||
$id: http://devicetree.org/schemas/media/nxp,imx7-csi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: i.MX7 CMOS Sensor Interface
|
||||
title: i.MX7 and i.MX8 CSI bridge (CMOS Sensor Interface)
|
||||
|
||||
maintainers:
|
||||
- Rui Miguel Silva <rmfrfs@gmail.com>
|
||||
|
@ -15,9 +15,13 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx7-csi
|
||||
- fsl,imx6ul-csi
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx7-csi
|
||||
- fsl,imx6ul-csi
|
||||
- items:
|
||||
- const: fsl,imx8mm-csi
|
||||
- const: fsl,imx7-csi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/nxp,imx8mq-mipi-csi2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX8MQ MIPI CSI-2 receiver
|
||||
|
||||
maintainers:
|
||||
- Martin Kepplinger <martin.kepplinger@puri.sm>
|
||||
|
||||
description: |-
|
||||
This binding covers the CSI-2 RX PHY and host controller included in the
|
||||
NXP i.MX8MQ SoC. It handles the sensor/image input and process for all the
|
||||
input imaging devices.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8mq-mipi-csi2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: core is the RX Controller Core Clock input. This clock
|
||||
must be exactly equal to or faster than the receive
|
||||
byteclock from the RX DPHY.
|
||||
- description: esc is the Rx Escape Clock. This must be the same escape
|
||||
clock that the RX DPHY receives.
|
||||
- description: ui is the pixel clock (phy_ref up to 333Mhz).
|
||||
See the reference manual for details.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: esc
|
||||
- const: ui
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: CORE_RESET reset register bit definition
|
||||
- description: PHY_REF_RESET reset register bit definition
|
||||
- description: ESC_RESET reset register bit definition
|
||||
|
||||
fsl,mipi-phy-gpr:
|
||||
description: |
|
||||
The phandle to the imx8mq syscon iomux-gpr with the register
|
||||
for setting RX_ENABLE for the mipi receiver.
|
||||
|
||||
The format should be as follows:
|
||||
<gpr req_gpr>
|
||||
gpr is the phandle to general purpose register node.
|
||||
req_gpr is the gpr register offset of RX_ENABLE for the mipi phy.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
items:
|
||||
- description: The 'gpr' is the phandle to general purpose register node.
|
||||
- description: The 'req_gpr' is the gpr register offset containing
|
||||
CSI2_1_RX_ENABLE or CSI2_2_RX_ENABLE respectively.
|
||||
maximum: 0xff
|
||||
|
||||
interconnects:
|
||||
maxItems: 1
|
||||
|
||||
interconnect-names:
|
||||
const: dram
|
||||
|
||||
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:
|
||||
data-lanes:
|
||||
items:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Output port node
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- fsl,mipi-phy-gpr
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8mq-clock.h>
|
||||
#include <dt-bindings/interconnect/imx8mq.h>
|
||||
#include <dt-bindings/reset/imx8mq-reset.h>
|
||||
|
||||
csi@30a70000 {
|
||||
compatible = "fsl,imx8mq-mipi-csi2";
|
||||
reg = <0x30a70000 0x1000>;
|
||||
clocks = <&clk IMX8MQ_CLK_CSI1_CORE>,
|
||||
<&clk IMX8MQ_CLK_CSI1_ESC>,
|
||||
<&clk IMX8MQ_CLK_CSI1_PHY_REF>;
|
||||
clock-names = "core", "esc", "ui";
|
||||
assigned-clocks = <&clk IMX8MQ_CLK_CSI1_CORE>,
|
||||
<&clk IMX8MQ_CLK_CSI1_PHY_REF>,
|
||||
<&clk IMX8MQ_CLK_CSI1_ESC>;
|
||||
assigned-clock-rates = <266000000>, <200000000>, <66000000>;
|
||||
assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_266M>,
|
||||
<&clk IMX8MQ_SYS2_PLL_1000M>,
|
||||
<&clk IMX8MQ_SYS1_PLL_800M>;
|
||||
power-domains = <&pgc_mipi_csi1>;
|
||||
resets = <&src IMX8MQ_RESET_MIPI_CSI1_CORE_RESET>,
|
||||
<&src IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET>,
|
||||
<&src IMX8MQ_RESET_MIPI_CSI1_ESC_RESET>;
|
||||
fsl,mipi-phy-gpr = <&iomuxc_gpr 0x88>;
|
||||
interconnects = <&noc IMX8MQ_ICM_CSI1 &noc IMX8MQ_ICS_DRAM>;
|
||||
interconnect-names = "dram";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
imx8mm_mipi_csi_in: endpoint {
|
||||
remote-endpoint = <&imx477_out>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
imx8mm_mipi_csi_out: endpoint {
|
||||
remote-endpoint = <&csi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -22,6 +22,7 @@ properties:
|
|||
- rockchip,rk3288-vpu
|
||||
- rockchip,rk3328-vpu
|
||||
- rockchip,rk3399-vpu
|
||||
- rockchip,px30-vpu
|
||||
- items:
|
||||
- const: rockchip,rk3188-vpu
|
||||
- const: rockchip,rk3066-vpu
|
||||
|
|
|
@ -6,6 +6,7 @@ Required properties:
|
|||
"ti,da830-mcasp-audio" : for both DA830 & DA850 platforms
|
||||
"ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx)
|
||||
"ti,dra7-mcasp-audio" : for DRA7xx platforms
|
||||
"ti,omap4-mcasp-audio" : for OMAP4
|
||||
|
||||
- reg : Should contain reg specifiers for the entries in the reg-names property.
|
||||
- reg-names : Should contain:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Invensense ICS-43432 MEMS microphone with I2S output.
|
||||
Invensense ICS-43432-compatible MEMS microphone with I2S output.
|
||||
|
||||
There are no software configuration options for this device, indeed, the only
|
||||
host connection is the I2S interface. Apart from requirements on clock
|
||||
|
@ -8,7 +8,9 @@ contain audio data. A hardware pin determines if the device outputs data
|
|||
on the left or right channel of the I2S frame.
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "invensense,ics43432"
|
||||
- compatible: should be one of the following.
|
||||
"invensense,ics43432": For the Invensense ICS43432
|
||||
"cui,cmm-4030d-261": For the CUI CMM-4030D-261-I2S-TR
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mt8195-afe-pcm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek AFE PCM controller for mt8195
|
||||
|
||||
maintainers:
|
||||
- Trevor Wu <trevor.wu@mediatek.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt8195-audio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
mediatek,topckgen:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
description: The phandle of the mediatek topckgen controller
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: 26M clock
|
||||
- description: audio pll1 clock
|
||||
- description: audio pll2 clock
|
||||
- description: clock divider for i2si1_mck
|
||||
- description: clock divider for i2si2_mck
|
||||
- description: clock divider for i2so1_mck
|
||||
- description: clock divider for i2so2_mck
|
||||
- description: clock divider for dptx_mck
|
||||
- description: a1sys hoping clock
|
||||
- description: audio intbus clock
|
||||
- description: audio hires clock
|
||||
- description: audio local bus clock
|
||||
- description: mux for dptx_mck
|
||||
- description: mux for i2so1_mck
|
||||
- description: mux for i2so2_mck
|
||||
- description: mux for i2si1_mck
|
||||
- description: mux for i2si2_mck
|
||||
- description: audio infra 26M clock
|
||||
- description: infra bus clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: clk26m
|
||||
- const: apll1_ck
|
||||
- const: apll2_ck
|
||||
- const: apll12_div0
|
||||
- const: apll12_div1
|
||||
- const: apll12_div2
|
||||
- const: apll12_div3
|
||||
- const: apll12_div9
|
||||
- const: a1sys_hp_sel
|
||||
- const: aud_intbus_sel
|
||||
- const: audio_h_sel
|
||||
- const: audio_local_bus_sel
|
||||
- const: dptx_m_sel
|
||||
- const: i2so1_m_sel
|
||||
- const: i2so2_m_sel
|
||||
- const: i2si1_m_sel
|
||||
- const: i2si2_m_sel
|
||||
- const: infra_ao_audio_26m_b
|
||||
- const: scp_adsp_audiodsp
|
||||
|
||||
mediatek,etdm-in1-chn-disabled:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
maxItems: 24
|
||||
description: Specify which input channel should be disabled.
|
||||
|
||||
mediatek,etdm-in2-chn-disabled:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
maxItems: 16
|
||||
description: Specify which input channel should be disabled.
|
||||
|
||||
patternProperties:
|
||||
"^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
|
||||
description: Specify etdm in mclk output rate for always on case.
|
||||
|
||||
"^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
|
||||
description: Specify etdm out mclk output rate for always on case.
|
||||
|
||||
"^mediatek,etdm-in[1-2]-multi-pin-mode$":
|
||||
type: boolean
|
||||
description: if present, the etdm data mode is I2S.
|
||||
|
||||
"^mediatek,etdm-out[1-3]-multi-pin-mode$":
|
||||
type: boolean
|
||||
description: if present, the etdm data mode is I2S.
|
||||
|
||||
"^mediatek,etdm-in[1-2]-cowork-source$":
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
etdm modules can share the same external clock pin. Specify
|
||||
which etdm clock source is required by this etdm in moudule.
|
||||
enum:
|
||||
- 0 # etdm1_in
|
||||
- 1 # etdm2_in
|
||||
- 2 # etdm1_out
|
||||
- 3 # etdm2_out
|
||||
|
||||
"^mediatek,etdm-out[1-2]-cowork-source$":
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
etdm modules can share the same external clock pin. Specify
|
||||
which etdm clock source is required by this etdm out moudule.
|
||||
enum:
|
||||
- 0 # etdm1_in
|
||||
- 1 # etdm2_in
|
||||
- 2 # etdm1_out
|
||||
- 3 # etdm2_out
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- mediatek,topckgen
|
||||
- power-domains
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt8195-clk.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/power/mt8195-power.h>
|
||||
|
||||
afe: mt8195-afe-pcm@10890000 {
|
||||
compatible = "mediatek,mt8195-audio";
|
||||
reg = <0x10890000 0x10000>;
|
||||
interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
mediatek,topckgen = <&topckgen>;
|
||||
power-domains = <&spm MT8195_POWER_DOMAIN_AUDIO>;
|
||||
clocks = <&clk26m>,
|
||||
<&topckgen CLK_TOP_APLL1>,
|
||||
<&topckgen CLK_TOP_APLL2>,
|
||||
<&topckgen CLK_TOP_APLL12_DIV0>,
|
||||
<&topckgen CLK_TOP_APLL12_DIV1>,
|
||||
<&topckgen CLK_TOP_APLL12_DIV2>,
|
||||
<&topckgen CLK_TOP_APLL12_DIV3>,
|
||||
<&topckgen CLK_TOP_APLL12_DIV9>,
|
||||
<&topckgen CLK_TOP_A1SYS_HP_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_INTBUS_SEL>,
|
||||
<&topckgen CLK_TOP_AUDIO_H_SEL>,
|
||||
<&topckgen CLK_TOP_AUDIO_LOCAL_BUS_SEL>,
|
||||
<&topckgen CLK_TOP_DPTX_M_SEL>,
|
||||
<&topckgen CLK_TOP_I2SO1_M_SEL>,
|
||||
<&topckgen CLK_TOP_I2SO2_M_SEL>,
|
||||
<&topckgen CLK_TOP_I2SI1_M_SEL>,
|
||||
<&topckgen CLK_TOP_I2SI2_M_SEL>,
|
||||
<&infracfg_ao CLK_INFRA_AO_AUDIO_26M_B>,
|
||||
<&scp_adsp CLK_SCP_ADSP_AUDIODSP>;
|
||||
clock-names = "clk26m",
|
||||
"apll1_ck",
|
||||
"apll2_ck",
|
||||
"apll12_div0",
|
||||
"apll12_div1",
|
||||
"apll12_div2",
|
||||
"apll12_div3",
|
||||
"apll12_div9",
|
||||
"a1sys_hp_sel",
|
||||
"aud_intbus_sel",
|
||||
"audio_h_sel",
|
||||
"audio_local_bus_sel",
|
||||
"dptx_m_sel",
|
||||
"i2so1_m_sel",
|
||||
"i2so2_m_sel",
|
||||
"i2si1_m_sel",
|
||||
"i2si2_m_sel",
|
||||
"infra_ao_audio_26m_b",
|
||||
"scp_adsp_audiodsp";
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mt8195-mt6359-rt1019-rt5682.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek MT8195 with MT6359, RT1019 and RT5682 ASoC sound card driver
|
||||
|
||||
maintainers:
|
||||
- Trevor Wu <trevor.wu@mediatek.com>
|
||||
|
||||
description:
|
||||
This binding describes the MT8195 sound card.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt8195_mt6359_rt1019_rt5682
|
||||
|
||||
mediatek,platform:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
description: The phandle of MT8195 ASoC platform.
|
||||
|
||||
mediatek,dptx-codec:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
description: The phandle of MT8195 Display Port Tx codec node.
|
||||
|
||||
mediatek,hdmi-codec:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
description: The phandle of MT8195 HDMI codec node.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,platform
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
sound: mt8195-sound {
|
||||
compatible = "mediatek,mt8195_mt6359_rt1019_rt5682";
|
||||
mediatek,platform = <&afe>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&aud_pins_default>;
|
||||
};
|
||||
|
||||
...
|
|
@ -15,7 +15,9 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: realtek,rt1015p
|
||||
enum:
|
||||
- realtek,rt1015p
|
||||
- realtek,rt1019p
|
||||
|
||||
sdb-gpios:
|
||||
description:
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/renesas,rz-ssi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/G2L ASoC Sound Serial Interface (SSIF-2)
|
||||
|
||||
maintainers:
|
||||
- Biju Das <biju.das.jz@bp.renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g044-ssi # RZ/G2{L,LC}
|
||||
- const: renesas,rz-ssi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: int_req
|
||||
- const: dma_rx
|
||||
- const: dma_tx
|
||||
- const: dma_rt
|
||||
|
||||
clocks:
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ssi
|
||||
- const: ssi_sfr
|
||||
- const: audio_clk1
|
||||
- const: audio_clk2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
The first cell represents a phandle to dmac
|
||||
The second cell specifies the encoded MID/RID values of the SSI port
|
||||
connected to the DMA client and the slave channel configuration
|
||||
parameters.
|
||||
bits[0:9] - Specifies MID/RID value of a SSI channel as below
|
||||
MID/RID value of SSI rx0 = 0x256
|
||||
MID/RID value of SSI tx0 = 0x255
|
||||
MID/RID value of SSI rx1 = 0x25a
|
||||
MID/RID value of SSI tx1 = 0x259
|
||||
MID/RID value of SSI rt2 = 0x25f
|
||||
MID/RID value of SSI rx3 = 0x262
|
||||
MID/RID value of SSI tx3 = 0x261
|
||||
bit[10] - HIEN = 1, Detects a request in response to the rising edge
|
||||
of the signal
|
||||
bit[11] - LVL = 0, Detects based on the edge
|
||||
bits[12:14] - AM = 2, Bus cycle mode
|
||||
bit[15] - TM = 0, Single transfer mode
|
||||
|
||||
dma-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
- items:
|
||||
- const: rt
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- '#sound-dai-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/r9a07g044-cpg.h>
|
||||
|
||||
ssi0: ssi@10049c00 {
|
||||
compatible = "renesas,r9a07g044-ssi",
|
||||
"renesas,rz-ssi";
|
||||
reg = <0x10049c00 0x400>;
|
||||
interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 328 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 329 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "int_req", "dma_rx", "dma_tx", "dma_rt";
|
||||
clocks = <&cpg CPG_MOD R9A07G044_SSI0_PCLK2>,
|
||||
<&cpg CPG_MOD R9A07G044_SSI0_PCLK_SFR>,
|
||||
<&audio_clk1>,
|
||||
<&audio_clk2>;
|
||||
clock-names = "ssi", "ssi_sfr", "audio_clk1", "audio_clk2";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A07G044_SSI0_RST_M2_REG>;
|
||||
dmas = <&dmac 0x2655>,
|
||||
<&dmac 0x2656>;
|
||||
dma-names = "tx", "rx";
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
|
@ -20,7 +20,9 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- rockchip,px30-i2s
|
||||
- rockchip,rk1808-i2s
|
||||
- rockchip,rk3036-i2s
|
||||
- rockchip,rk3128-i2s
|
||||
- rockchip,rk3188-i2s
|
||||
- rockchip,rk3228-i2s
|
||||
- rockchip,rk3288-i2s
|
||||
|
@ -29,6 +31,7 @@ properties:
|
|||
- rockchip,rk3366-i2s
|
||||
- rockchip,rk3368-i2s
|
||||
- rockchip,rk3399-i2s
|
||||
- rockchip,rv1126-i2s
|
||||
- const: rockchip,rk3066-i2s
|
||||
|
||||
reg:
|
||||
|
@ -61,6 +64,14 @@ properties:
|
|||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: reset-m
|
||||
- const: reset-h
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
rockchip,capture-channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 2
|
||||
|
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- const: rockchip,rk3366-spdif
|
||||
- const: rockchip,rk3368-spdif
|
||||
- const: rockchip,rk3399-spdif
|
||||
- const: rockchip,rk3568-spdif
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3188-spdif
|
||||
|
|
|
@ -271,6 +271,8 @@ patternProperties:
|
|||
description: Shenzen Chuangsiqi Technology Co.,Ltd.
|
||||
"^cubietech,.*":
|
||||
description: Cubietech, Ltd.
|
||||
"^cui,.*":
|
||||
description: CUI Devices
|
||||
"^cypress,.*":
|
||||
description: Cypress Semiconductor Corporation
|
||||
"^cznic,.*":
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
Writing camera sensor drivers
|
||||
=============================
|
||||
|
||||
CSI-2
|
||||
-----
|
||||
CSI-2 and parallel (BT.601 and BT.656) busses
|
||||
---------------------------------------------
|
||||
|
||||
Please see what is written on :ref:`MIPI_CSI_2`.
|
||||
Please see :ref:`transmitter-receiver`.
|
||||
|
||||
Handling clocks
|
||||
---------------
|
||||
|
@ -26,15 +26,16 @@ user.
|
|||
ACPI
|
||||
~~~~
|
||||
|
||||
Read the "clock-frequency" _DSD property to denote the frequency. The driver can
|
||||
rely on this frequency being used.
|
||||
Read the ``clock-frequency`` _DSD property to denote the frequency. The driver
|
||||
can rely on this frequency being used.
|
||||
|
||||
Devicetree
|
||||
~~~~~~~~~~
|
||||
|
||||
The currently preferred way to achieve this is using "assigned-clock-rates"
|
||||
property. See Documentation/devicetree/bindings/clock/clock-bindings.txt for
|
||||
more information. The driver then gets the frequency using clk_get_rate().
|
||||
The currently preferred way to achieve this is using ``assigned-clocks``,
|
||||
``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See
|
||||
``Documentation/devicetree/bindings/clock/clock-bindings.txt`` for more
|
||||
information. The driver then gets the frequency using ``clk_get_rate()``.
|
||||
|
||||
This approach has the drawback that there's no guarantee that the frequency
|
||||
hasn't been modified directly or indirectly by another driver, or supported by
|
||||
|
@ -55,7 +56,7 @@ processing pipeline as one or more sub-devices with different cropping and
|
|||
scaling configurations. The output size of the device is the result of a series
|
||||
of cropping and scaling operations from the device's pixel array's size.
|
||||
|
||||
An example of such a driver is the smiapp driver (see drivers/media/i2c/smiapp).
|
||||
An example of such a driver is the CCS driver (see ``drivers/media/i2c/ccs``).
|
||||
|
||||
Register list based drivers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -67,7 +68,7 @@ level are independent. How a driver picks such configuration is based on the
|
|||
format set on a source pad at the end of the device's internal pipeline.
|
||||
|
||||
Most sensor drivers are implemented this way, see e.g.
|
||||
drivers/media/i2c/imx319.c for an example.
|
||||
``drivers/media/i2c/imx319.c`` for an example.
|
||||
|
||||
Frame interval configuration
|
||||
----------------------------
|
||||
|
@ -94,9 +95,10 @@ large variety of devices beyond camera sensors. Devices that have no analogue
|
|||
crop, use the full source image size, i.e. pixel array size.
|
||||
|
||||
Horizontal and vertical blanking are specified by ``V4L2_CID_HBLANK`` and
|
||||
``V4L2_CID_VBLANK``, respectively. The unit of these controls are lines. The
|
||||
pixel rate is specified by ``V4L2_CID_PIXEL_RATE`` in the same sub-device. The
|
||||
unit of that control is Hz.
|
||||
``V4L2_CID_VBLANK``, respectively. The unit of the ``V4L2_CID_HBLANK`` control
|
||||
is pixels and the unit of the ``V4L2_CID_VBLANK`` is lines. The pixel rate in
|
||||
the sensor's **pixel array** is specified by ``V4L2_CID_PIXEL_RATE`` in the same
|
||||
sub-device. The unit of that control is pixels per second.
|
||||
|
||||
Register list based drivers need to implement read-only sub-device nodes for the
|
||||
purpose. Devices that are not register list based need these to configure the
|
||||
|
@ -125,14 +127,14 @@ general, the device must be powered on at least when its registers are being
|
|||
accessed and when it is streaming.
|
||||
|
||||
Existing camera sensor drivers may rely on the old
|
||||
:c:type:`v4l2_subdev_core_ops`->s_power() callback for bridge or ISP drivers to
|
||||
struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to
|
||||
manage their power state. This is however **deprecated**. If you feel you need
|
||||
to begin calling an s_power from an ISP or a bridge driver, instead please add
|
||||
runtime PM support to the sensor driver you are using. Likewise, new drivers
|
||||
should not use s_power.
|
||||
|
||||
Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and
|
||||
``drivers/media/i2c/smiapp/smiapp-core.c``. The two drivers work in both ACPI
|
||||
``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI
|
||||
and DT based systems.
|
||||
|
||||
Control framework
|
||||
|
@ -149,16 +151,3 @@ used to obtain device's power state after the power state transition:
|
|||
The function returns a non-zero value if it succeeded getting the power count or
|
||||
runtime PM was disabled, in either of which cases the driver may proceed to
|
||||
access the device.
|
||||
|
||||
Controls
|
||||
--------
|
||||
|
||||
For camera sensors that are connected to a bus where transmitter and receiver
|
||||
require common configuration set by drivers, such as CSI-2 or parallel (BT.601
|
||||
or BT.656) bus, the ``V4L2_CID_LINK_FREQ`` control is mandatory on transmitter
|
||||
drivers. Receiver drivers can use the ``V4L2_CID_LINK_FREQ`` to query the
|
||||
frequency used on the bus.
|
||||
|
||||
The transmitter drivers should also implement ``V4L2_CID_PIXEL_RATE`` control in
|
||||
order to tell the maximum pixel rate to the receiver. This is required on raw
|
||||
camera sensors.
|
||||
|
|
|
@ -130,9 +130,12 @@ To enable/disable the hardware::
|
|||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||
|
||||
This callback enables or disables the CEC hardware. Enabling the CEC hardware
|
||||
means powering it up in a state where no logical addresses are claimed. This
|
||||
op assumes that the physical address (adap->phys_addr) is valid when enable is
|
||||
true and will not change while the CEC adapter remains enabled. The initial
|
||||
means powering it up in a state where no logical addresses are claimed. The
|
||||
physical address will always be valid if CEC_CAP_NEEDS_HPD is set. If that
|
||||
capability is not set, then the physical address can change while the CEC
|
||||
hardware is enabled. CEC drivers should not set CEC_CAP_NEEDS_HPD unless
|
||||
the hardware design requires that as this will make it impossible to wake
|
||||
up displays that pull the HPD low when in standby mode. The initial
|
||||
state of the CEC adapter after calling cec_allocate_adapter() is disabled.
|
||||
|
||||
Note that adap_enable must return 0 if enable is false.
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _MIPI_CSI_2:
|
||||
|
||||
MIPI CSI-2
|
||||
==========
|
||||
|
||||
CSI-2 is a data bus intended for transferring images from cameras to
|
||||
the host SoC. It is defined by the `MIPI alliance`_.
|
||||
|
||||
.. _`MIPI alliance`: http://www.mipi.org/
|
||||
|
||||
Media bus formats
|
||||
-----------------
|
||||
|
||||
See :ref:`v4l2-mbus-pixelcode` for details on which media bus formats should
|
||||
be used for CSI-2 interfaces.
|
||||
|
||||
Transmitter drivers
|
||||
-------------------
|
||||
|
||||
CSI-2 transmitter, such as a sensor or a TV tuner, drivers need to
|
||||
provide the CSI-2 receiver with information on the CSI-2 bus
|
||||
configuration. These include the V4L2_CID_LINK_FREQ and
|
||||
V4L2_CID_PIXEL_RATE controls and
|
||||
(:c:type:`v4l2_subdev_video_ops`->s_stream() callback). These
|
||||
interface elements must be present on the sub-device represents the
|
||||
CSI-2 transmitter.
|
||||
|
||||
The V4L2_CID_LINK_FREQ control is used to tell the receiver driver the
|
||||
frequency (and not the symbol rate) of the link. The V4L2_CID_PIXEL_RATE
|
||||
control may be used by the receiver to obtain the pixel rate the transmitter
|
||||
uses. The :c:type:`v4l2_subdev_video_ops`->s_stream() callback provides an
|
||||
ability to start and stop the stream.
|
||||
|
||||
The value of the V4L2_CID_PIXEL_RATE is calculated as follows::
|
||||
|
||||
pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample
|
||||
|
||||
where
|
||||
|
||||
.. list-table:: variables in pixel rate calculation
|
||||
:header-rows: 1
|
||||
|
||||
* - variable or constant
|
||||
- description
|
||||
* - link_freq
|
||||
- The value of the V4L2_CID_LINK_FREQ integer64 menu item.
|
||||
* - nr_of_lanes
|
||||
- Number of data lanes used on the CSI-2 link. This can
|
||||
be obtained from the OF endpoint configuration.
|
||||
* - 2
|
||||
- Two bits are transferred per clock cycle per lane.
|
||||
* - bits_per_sample
|
||||
- Number of bits per sample.
|
||||
* - k
|
||||
- 16 for D-PHY and 7 for C-PHY
|
||||
|
||||
The transmitter drivers must, if possible, configure the CSI-2
|
||||
transmitter to *LP-11 mode* whenever the transmitter is powered on but
|
||||
not active, and maintain *LP-11 mode* until stream on. Only at stream
|
||||
on should the transmitter activate the clock on the clock lane and
|
||||
transition to *HS mode*.
|
||||
|
||||
Some transmitters do this automatically but some have to be explicitly
|
||||
programmed to do so, and some are unable to do so altogether due to
|
||||
hardware constraints.
|
||||
|
||||
Stopping the transmitter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A transmitter stops sending the stream of images as a result of
|
||||
calling the ``.s_stream()`` callback. Some transmitters may stop the
|
||||
stream at a frame boundary whereas others stop immediately,
|
||||
effectively leaving the current frame unfinished. The receiver driver
|
||||
should not make assumptions either way, but function properly in both
|
||||
cases.
|
||||
|
||||
Receiver drivers
|
||||
----------------
|
||||
|
||||
Before the receiver driver may enable the CSI-2 transmitter by using
|
||||
the :c:type:`v4l2_subdev_video_ops`->s_stream(), it must have powered
|
||||
the transmitter up by using the
|
||||
:c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take
|
||||
place either indirectly by using :c:func:`v4l2_pipeline_pm_get` or
|
||||
directly.
|
||||
|
||||
Formats
|
||||
-------
|
||||
|
||||
The media bus pixel codes document parallel formats. Should the pixel data be
|
||||
transported over a serial bus, the media bus pixel code that describes a
|
||||
parallel format that transfers a sample on a single clock cycle is used.
|
|
@ -37,7 +37,7 @@ Documentation/userspace-api/media/index.rst
|
|||
rc-core
|
||||
mc-core
|
||||
cec-core
|
||||
csi2
|
||||
tx-rx
|
||||
camera-sensor
|
||||
|
||||
drivers/index
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _transmitter-receiver:
|
||||
|
||||
Pixel data transmitter and receiver drivers
|
||||
===========================================
|
||||
|
||||
V4L2 supports various devices that transmit and receive pixel data. Examples of
|
||||
these devices include a camera sensor, a TV tuner and a parallel or a CSI-2
|
||||
receiver in an SoC.
|
||||
|
||||
Bus types
|
||||
---------
|
||||
|
||||
The following busses are the most common. This section discusses these two only.
|
||||
|
||||
MIPI CSI-2
|
||||
^^^^^^^^^^
|
||||
|
||||
CSI-2 is a data bus intended for transferring images from cameras to
|
||||
the host SoC. It is defined by the `MIPI alliance`_.
|
||||
|
||||
.. _`MIPI alliance`: https://www.mipi.org/
|
||||
|
||||
Parallel
|
||||
^^^^^^^^
|
||||
|
||||
`BT.601`_ and `BT.656`_ are the most common parallel busses.
|
||||
|
||||
.. _`BT.601`: https://en.wikipedia.org/wiki/Rec._601
|
||||
.. _`BT.656`: https://en.wikipedia.org/wiki/ITU-R_BT.656
|
||||
|
||||
Transmitter drivers
|
||||
-------------------
|
||||
|
||||
Transmitter drivers generally need to provide the receiver drivers with the
|
||||
configuration of the transmitter. What is required depends on the type of the
|
||||
bus. These are common for both busses.
|
||||
|
||||
Media bus pixel code
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
See :ref:`v4l2-mbus-pixelcode`.
|
||||
|
||||
Link frequency
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The :ref:`V4L2_CID_LINK_FREQ <v4l2-cid-link-freq>` control is used to tell the
|
||||
receiver the frequency of the bus (i.e. it is not the same as the symbol rate).
|
||||
|
||||
``.s_stream()`` callback
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The struct struct v4l2_subdev_video_ops->s_stream() callback is used by the
|
||||
receiver driver to control the transmitter driver's streaming state.
|
||||
|
||||
|
||||
CSI-2 transmitter drivers
|
||||
-------------------------
|
||||
|
||||
Pixel rate
|
||||
^^^^^^^^^^
|
||||
|
||||
The pixel rate on the bus is calculated as follows::
|
||||
|
||||
pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample
|
||||
|
||||
where
|
||||
|
||||
.. list-table:: variables in pixel rate calculation
|
||||
:header-rows: 1
|
||||
|
||||
* - variable or constant
|
||||
- description
|
||||
* - link_freq
|
||||
- The value of the ``V4L2_CID_LINK_FREQ`` integer64 menu item.
|
||||
* - nr_of_lanes
|
||||
- Number of data lanes used on the CSI-2 link. This can
|
||||
be obtained from the OF endpoint configuration.
|
||||
* - 2
|
||||
- Data is transferred on both rising and falling edge of the signal.
|
||||
* - bits_per_sample
|
||||
- Number of bits per sample.
|
||||
* - k
|
||||
- 16 for D-PHY and 7 for C-PHY
|
||||
|
||||
.. note::
|
||||
|
||||
The pixel rate calculated this way is **not** the same thing as the
|
||||
pixel rate on the camera sensor's pixel array which is indicated by the
|
||||
:ref:`V4L2_CID_PIXEL_RATE <v4l2-cid-pixel-rate>` control.
|
||||
|
||||
LP-11 and LP-111 modes
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As part of transitioning to high speed mode, a CSI-2 transmitter typically
|
||||
briefly sets the bus to LP-11 or LP-111 state, depending on the PHY. This period
|
||||
may be as short as 100 µs, during which the receiver observes this state and
|
||||
proceeds its own part of high speed mode transition.
|
||||
|
||||
Most receivers are capable of autonomously handling this once the software has
|
||||
configured them to do so, but there are receivers which require software
|
||||
involvement in observing LP-11 or LP-111 state. 100 µs is a brief period to hit
|
||||
in software, especially when there is no interrupt telling something is
|
||||
happening.
|
||||
|
||||
One way to address this is to configure the transmitter side explicitly to LP-11
|
||||
or LP-111 mode, which requires support from the transmitter hardware. This is
|
||||
not universally available. Many devices return to this state once streaming is
|
||||
stopped while the state after power-on is LP-00 or LP-000.
|
||||
|
||||
The ``.pre_streamon()`` callback may be used to prepare a transmitter for
|
||||
transitioning to streaming state, but not yet start streaming. Similarly, the
|
||||
``.post_streamoff()`` callback is used to undo what was done by the
|
||||
``.pre_streamon()`` callback. The caller of ``.pre_streamon()`` is thus required
|
||||
to call ``.post_streamoff()`` for each successful call of ``.pre_streamon()``.
|
||||
|
||||
In the context of CSI-2, the ``.pre_streamon()`` callback is used to transition
|
||||
the transmitter to the LP-11 or LP-111 mode. This also requires powering on the
|
||||
device, so this should be only done when it is needed.
|
||||
|
||||
Receiver drivers that do not need explicit LP-11 or LP-111 mode setup are waived
|
||||
from calling the two callbacks.
|
||||
|
||||
Stopping the transmitter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A transmitter stops sending the stream of images as a result of
|
||||
calling the ``.s_stream()`` callback. Some transmitters may stop the
|
||||
stream at a frame boundary whereas others stop immediately,
|
||||
effectively leaving the current frame unfinished. The receiver driver
|
||||
should not make assumptions either way, but function properly in both
|
||||
cases.
|
|
@ -1059,6 +1059,12 @@ The model name ``generic`` is treated as a special case. When this
|
|||
model is given, the driver uses the generic codec parser without
|
||||
"codec-patch". It's sometimes good for testing and debugging.
|
||||
|
||||
The model option can be used also for aliasing to another PCI or codec
|
||||
SSID. When it's passed in the form of ``model=XXXX:YYYY`` where XXXX
|
||||
and YYYY are the sub-vendor and sub-device IDs in hex numbers,
|
||||
respectively, the driver will refer to that SSID as a reference to the
|
||||
quirk table.
|
||||
|
||||
If the default configuration doesn't work and one of the above
|
||||
matches with your device, report it together with alsa-info.sh
|
||||
output (with ``--no-upload`` option) to kernel bugzilla or alsa-devel
|
||||
|
@ -2252,6 +2258,27 @@ delayed_register
|
|||
The driver prints a message like "Found post-registration device
|
||||
assignment: 1234abcd:04" for such a device, so that user can
|
||||
notice the need.
|
||||
quirk_flags
|
||||
Contains the bit flags for various device specific workarounds.
|
||||
Applied to the corresponding card index.
|
||||
|
||||
* bit 0: Skip reading sample rate for devices
|
||||
* bit 1: Create Media Controller API entries
|
||||
* bit 2: Allow alignment on audio sub-slot at transfer
|
||||
* bit 3: Add length specifier to transfers
|
||||
* bit 4: Start playback stream at first in implement feedback mode
|
||||
* bit 5: Skip clock selector setup
|
||||
* bit 6: Ignore errors from clock source search
|
||||
* bit 7: Indicates ITF-USB DSD based DACs
|
||||
* bit 8: Add a delay of 20ms at each control message handling
|
||||
* bit 9: Add a delay of 1-2ms at each control message handling
|
||||
* bit 10: Add a delay of 5-6ms at each control message handling
|
||||
* bit 11: Add a delay of 50ms at each interface setup
|
||||
* bit 12: Perform sample rate validations at probe
|
||||
* bit 13: Disable runtime PM autosuspend
|
||||
* bit 14: Ignore errors for mixer access
|
||||
* bit 15: Support generic DSD raw U32_BE format
|
||||
* bit 16: Set up the interface at first like UAC1
|
||||
|
||||
This module supports multiple devices, autoprobe and hotplugging.
|
||||
|
||||
|
@ -2261,11 +2288,14 @@ check.
|
|||
|
||||
NB: ``ignore_ctl_error=1`` may help when you get an error at accessing
|
||||
the mixer element such as URB error -22. This happens on some
|
||||
buggy USB device or the controller.
|
||||
buggy USB device or the controller. This workaround corresponds to
|
||||
the ``quirk_flags`` bit 14, too.
|
||||
|
||||
NB: quirk_alias option is provided only for testing / development.
|
||||
NB: ``quirk_alias`` option is provided only for testing / development.
|
||||
If you want to have a proper support, contact to upstream for
|
||||
adding the matching quirk in the driver code statically.
|
||||
Ditto for ``quirk_flags``. If a device is known to require specific
|
||||
workarounds, please report to the upstream.
|
||||
|
||||
Module snd-usb-caiaq
|
||||
--------------------
|
||||
|
|
|
@ -215,6 +215,17 @@ There are a few special model option values:
|
|||
* when ``generic`` is passed, the codec-specific parser is skipped and
|
||||
only the generic parser is used.
|
||||
|
||||
A new style for the model option that was introduced since 5.15 kernel
|
||||
is to pass the PCI or codec SSID in the form of ``model=XXXX:YYYY``
|
||||
where XXXX and YYYY are the sub-vendor and sub-device IDs in hex
|
||||
numbers, respectively. This is a kind of aliasing to another device;
|
||||
when this form is given, the driver will refer to that SSID as a
|
||||
reference to the quirk table. It'd be useful especially when the
|
||||
target quirk isn't listed in the model table. For example, passing
|
||||
model=103c:8862 will apply the quirk for HP ProBook 445 G8 (which
|
||||
isn't found in the model table as of writing) as long as the device is
|
||||
handled equivalently by the same driver.
|
||||
|
||||
|
||||
Speaker and Headphone Output
|
||||
----------------------------
|
||||
|
|
|
@ -4172,6 +4172,39 @@ module license as GPL, etc., otherwise the system is shown as “tainted”.
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
Device-Managed Resources
|
||||
========================
|
||||
|
||||
In the examples above, all resources are allocated and released
|
||||
manually. But human beings are lazy in nature, especially developers
|
||||
are lazier. So there are some ways to automate the release part; it's
|
||||
the (device-)managed resources aka devres or devm family. For
|
||||
example, an object allocated via :c:func:`devm_kmalloc()` will be
|
||||
freed automatically at unbinding the device.
|
||||
|
||||
ALSA core provides also the device-managed helper, namely,
|
||||
:c:func:`snd_devm_card_new()` for creating a card object.
|
||||
Call this functions instead of the normal :c:func:`snd_card_new()`,
|
||||
and you can forget the explicit :c:func:`snd_card_free()` call, as
|
||||
it's called automagically at error and removal paths.
|
||||
|
||||
One caveat is that the call of :c:func:`snd_card_free()` would be put
|
||||
at the beginning of the call chain only after you call
|
||||
:c:func:`snd_card_register()`.
|
||||
|
||||
Also, the ``private_free`` callback is always called at the card free,
|
||||
so be careful to put the hardware clean-up procedure in
|
||||
``private_free`` callback. It might be called even before you
|
||||
actually set up at an earlier error path. For avoiding such an
|
||||
invalid initialization, you can set ``private_free`` callback after
|
||||
:c:func:`snd_card_register()` call succeeds.
|
||||
|
||||
Another thing to be remarked is that you should use device-managed
|
||||
helpers for each component as much as possible once when you manage
|
||||
the card in that way. Mixing up with the normal and the managed
|
||||
resources may screw up the release order.
|
||||
|
||||
|
||||
How To Put Your Driver Into ALSA Tree
|
||||
=====================================
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ ignore define CEC_OP_REC_SEQ_TUESDAY
|
|||
ignore define CEC_OP_REC_SEQ_WEDNESDAY
|
||||
ignore define CEC_OP_REC_SEQ_THURSDAY
|
||||
ignore define CEC_OP_REC_SEQ_FRIDAY
|
||||
ignore define CEC_OP_REC_SEQ_SATERDAY
|
||||
ignore define CEC_OP_REC_SEQ_SATURDAY
|
||||
ignore define CEC_OP_REC_SEQ_ONCE_ONLY
|
||||
|
||||
ignore define CEC_MSG_CLEAR_DIGITAL_TIMER
|
||||
|
|
|
@ -1174,7 +1174,24 @@ enum v4l2_mpeg_video_h264_entropy_mode -
|
|||
Cyclic intra macroblock refresh. This is the number of continuous
|
||||
macroblocks refreshed every frame. Each frame a successive set of
|
||||
macroblocks is refreshed until the cycle completes and starts from
|
||||
the top of the frame. Applicable to H264, H263 and MPEG4 encoder.
|
||||
the top of the frame. Setting this control to zero means that
|
||||
macroblocks will not be refreshed. Note that this control will not
|
||||
take effect when ``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD`` control
|
||||
is set to non zero value.
|
||||
Applicable to H264, H263 and MPEG4 encoder.
|
||||
|
||||
``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (integer)``
|
||||
Intra macroblock refresh period. This sets the period to refresh
|
||||
the whole frame. In other words, this defines the number of frames
|
||||
for which the whole frame will be intra-refreshed. An example:
|
||||
setting period to 1 means that the whole frame will be refreshed,
|
||||
setting period to 2 means that the half of macroblocks will be
|
||||
intra-refreshed on frameX and the other half of macroblocks
|
||||
will be refreshed in frameX + 1 and so on. Setting the period to
|
||||
zero means no period is specified.
|
||||
Note that if the client sets this control to non zero value the
|
||||
``V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB`` control shall be
|
||||
ignored. Applicable to H264 and HEVC encoders.
|
||||
|
||||
``V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (boolean)``
|
||||
Frame level rate control enable. If this control is disabled then
|
||||
|
@ -3000,6 +3017,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
|
|||
* - __u8
|
||||
- ``pic_struct``
|
||||
-
|
||||
* - __u32
|
||||
- ``slice_segment_addr``
|
||||
-
|
||||
* - __u8
|
||||
- ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
|
||||
- The list of L0 reference elements as indices in the DPB.
|
||||
|
|
|
@ -20,25 +20,26 @@ Image Process Control IDs
|
|||
``V4L2_CID_IMAGE_PROC_CLASS (class)``
|
||||
The IMAGE_PROC class descriptor.
|
||||
|
||||
.. _v4l2-cid-link-freq:
|
||||
|
||||
``V4L2_CID_LINK_FREQ (integer menu)``
|
||||
Data bus frequency. Together with the media bus pixel code, bus type
|
||||
(clock cycles per sample), the data bus frequency defines the pixel
|
||||
rate (``V4L2_CID_PIXEL_RATE``) in the pixel array (or possibly
|
||||
elsewhere, if the device is not an image sensor). The frame rate can
|
||||
be calculated from the pixel clock, image width and height and
|
||||
horizontal and vertical blanking. While the pixel rate control may
|
||||
be defined elsewhere than in the subdev containing the pixel array,
|
||||
the frame rate cannot be obtained from that information. This is
|
||||
because only on the pixel array it can be assumed that the vertical
|
||||
and horizontal blanking information is exact: no other blanking is
|
||||
allowed in the pixel array. The selection of frame rate is performed
|
||||
by selecting the desired horizontal and vertical blanking. The unit
|
||||
of this control is Hz.
|
||||
The frequency of the data bus (e.g. parallel or CSI-2).
|
||||
|
||||
.. _v4l2-cid-pixel-rate:
|
||||
|
||||
``V4L2_CID_PIXEL_RATE (64-bit integer)``
|
||||
Pixel rate in the source pads of the subdev. This control is
|
||||
Pixel sampling rate in the device's pixel array. This control is
|
||||
read-only and its unit is pixels / second.
|
||||
|
||||
Some devices use horizontal and vertical balanking to configure the frame
|
||||
rate. The frame rate can be calculated from the pixel rate, analogue crop
|
||||
rectangle as well as horizontal and vertical blanking. The pixel rate
|
||||
control may be present in a different sub-device than the blanking controls
|
||||
and the analogue crop rectangle configuration.
|
||||
|
||||
The configuration of the frame rate is performed by selecting the desired
|
||||
horizontal and vertical blanking. The unit of this control is Hz.
|
||||
|
||||
``V4L2_CID_TEST_PATTERN (menu)``
|
||||
Some capture/display/sensor devices have the capability to generate
|
||||
test pattern images. These hardware specific test patterns can be
|
||||
|
|
27
MAINTAINERS
27
MAINTAINERS
|
@ -13846,6 +13846,15 @@ T: git git://linuxtv.org/media_tree.git
|
|||
F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml
|
||||
F: drivers/media/i2c/ov8856.c
|
||||
|
||||
OMNIVISION OV9282 SENSOR DRIVER
|
||||
M: Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml
|
||||
F: drivers/media/i2c/ov9282.c
|
||||
|
||||
OMNIVISION OV9640 SENSOR DRIVER
|
||||
M: Petr Cvek <petrcvekcz@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -17379,6 +17388,15 @@ T: git git://linuxtv.org/media_tree.git
|
|||
F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml
|
||||
F: drivers/media/i2c/imx334.c
|
||||
|
||||
SONY IMX335 SENSOR DRIVER
|
||||
M: Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml
|
||||
F: drivers/media/i2c/imx335.c
|
||||
|
||||
SONY IMX355 SENSOR DRIVER
|
||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -17386,6 +17404,15 @@ S: Maintained
|
|||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/i2c/imx355.c
|
||||
|
||||
SONY IMX412 SENSOR DRIVER
|
||||
M: Paul J. Murphy <paul.j.murphy@intel.com>
|
||||
M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
|
||||
F: drivers/media/i2c/imx412.c
|
||||
|
||||
SONY MEMORYSTICK SUBSYSTEM
|
||||
M: Maxim Levitsky <maximlevitsky@gmail.com>
|
||||
M: Alex Dubov <oakad@yahoo.com>
|
||||
|
|
|
@ -209,8 +209,8 @@ struct cec_pin {
|
|||
u32 work_pin_events_dropped_cnt;
|
||||
ktime_t timer_ts;
|
||||
u32 timer_cnt;
|
||||
u32 timer_100ms_overruns;
|
||||
u32 timer_300ms_overruns;
|
||||
u32 timer_100us_overruns;
|
||||
u32 timer_300us_overruns;
|
||||
u32 timer_max_overrun;
|
||||
u32 timer_sum_overrun;
|
||||
|
||||
|
|
|
@ -854,9 +854,9 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
|||
if (delta > 100 && pin->state != CEC_ST_IDLE) {
|
||||
/* Keep track of timer overruns */
|
||||
pin->timer_sum_overrun += delta;
|
||||
pin->timer_100ms_overruns++;
|
||||
pin->timer_100us_overruns++;
|
||||
if (delta > 300)
|
||||
pin->timer_300ms_overruns++;
|
||||
pin->timer_300us_overruns++;
|
||||
if (delta > pin->timer_max_overrun)
|
||||
pin->timer_max_overrun = delta;
|
||||
}
|
||||
|
@ -1207,15 +1207,15 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
|
|||
seq_printf(file, "cec pin events dropped: %u\n",
|
||||
pin->work_pin_events_dropped_cnt);
|
||||
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
|
||||
if (pin->timer_100ms_overruns) {
|
||||
seq_printf(file, "timer overruns > 100ms: %u of %u\n",
|
||||
pin->timer_100ms_overruns, pin->timer_cnt);
|
||||
seq_printf(file, "timer overruns > 300ms: %u of %u\n",
|
||||
pin->timer_300ms_overruns, pin->timer_cnt);
|
||||
if (pin->timer_100us_overruns) {
|
||||
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
||||
pin->timer_100us_overruns, pin->timer_cnt);
|
||||
seq_printf(file, "timer overruns > 300us: %u of %u\n",
|
||||
pin->timer_300us_overruns, pin->timer_cnt);
|
||||
seq_printf(file, "max timer overrun: %u usecs\n",
|
||||
pin->timer_max_overrun);
|
||||
seq_printf(file, "avg timer overrun: %u usecs\n",
|
||||
pin->timer_sum_overrun / pin->timer_100ms_overruns);
|
||||
pin->timer_sum_overrun / pin->timer_100us_overruns);
|
||||
}
|
||||
if (pin->rx_start_bit_low_too_short_cnt)
|
||||
seq_printf(file,
|
||||
|
@ -1245,8 +1245,8 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
|
|||
seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt);
|
||||
pin->work_pin_events_dropped_cnt = 0;
|
||||
pin->timer_cnt = 0;
|
||||
pin->timer_100ms_overruns = 0;
|
||||
pin->timer_300ms_overruns = 0;
|
||||
pin->timer_100us_overruns = 0;
|
||||
pin->timer_300us_overruns = 0;
|
||||
pin->timer_max_overrun = 0;
|
||||
pin->timer_sum_overrun = 0;
|
||||
pin->rx_start_bit_low_too_short_cnt = 0;
|
||||
|
|
|
@ -305,14 +305,16 @@ static int stm32_cec_probe(struct platform_device *pdev)
|
|||
|
||||
cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
|
||||
if (IS_ERR(cec->clk_hdmi_cec) &&
|
||||
PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_unprepare_cec_clk;
|
||||
}
|
||||
|
||||
if (!IS_ERR(cec->clk_hdmi_cec)) {
|
||||
ret = clk_prepare(cec->clk_hdmi_cec);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n");
|
||||
return ret;
|
||||
goto err_unprepare_cec_clk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,19 +326,27 @@ static int stm32_cec_probe(struct platform_device *pdev)
|
|||
CEC_NAME, caps, CEC_MAX_LOG_ADDRS);
|
||||
ret = PTR_ERR_OR_ZERO(cec->adap);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_unprepare_hdmi_cec_clk;
|
||||
|
||||
ret = cec_register_adapter(cec->adap, &pdev->dev);
|
||||
if (ret) {
|
||||
cec_delete_adapter(cec->adap);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_delete_adapter;
|
||||
|
||||
cec_hw_init(cec);
|
||||
|
||||
platform_set_drvdata(pdev, cec);
|
||||
|
||||
return 0;
|
||||
|
||||
err_delete_adapter:
|
||||
cec_delete_adapter(cec->adap);
|
||||
|
||||
err_unprepare_hdmi_cec_clk:
|
||||
clk_unprepare(cec->clk_hdmi_cec);
|
||||
|
||||
err_unprepare_cec_clk:
|
||||
clk_unprepare(cec->clk_cec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_cec_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -366,7 +366,11 @@ static int tegra_cec_probe(struct platform_device *pdev)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
clk_prepare_enable(cec->clk);
|
||||
ret = clk_prepare_enable(cec->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to prepare clock for CEC\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set context info. */
|
||||
cec->dev = &pdev->dev;
|
||||
|
@ -446,9 +450,7 @@ static int tegra_cec_resume(struct platform_device *pdev)
|
|||
|
||||
dev_notice(&pdev->dev, "Resuming\n");
|
||||
|
||||
clk_prepare_enable(cec->clk);
|
||||
|
||||
return 0;
|
||||
return clk_prepare_enable(cec->clk);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1172,7 +1172,6 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config,
|
|||
"%s: Error attaching frontend %d\n",
|
||||
KBUILD_MODNAME, demod);
|
||||
goto error1;
|
||||
break;
|
||||
case 1:
|
||||
/* new priv instance */
|
||||
priv->i2c = i2c;
|
||||
|
|
|
@ -2107,32 +2107,55 @@ static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *an
|
|||
dib8000_write_word(state, 117 + mode, ana_fe[mode]);
|
||||
}
|
||||
|
||||
static const u16 lut_prbs_2k[14] = {
|
||||
0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
|
||||
static const u16 lut_prbs_2k[13] = {
|
||||
0x423, 0x009, 0x5C7,
|
||||
0x7A6, 0x3D8, 0x527,
|
||||
0x7FF, 0x79B, 0x3D6,
|
||||
0x3A2, 0x53B, 0x2F4,
|
||||
0x213
|
||||
};
|
||||
static const u16 lut_prbs_4k[14] = {
|
||||
0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
|
||||
|
||||
static const u16 lut_prbs_4k[13] = {
|
||||
0x208, 0x0C3, 0x7B9,
|
||||
0x423, 0x5C7, 0x3D8,
|
||||
0x7FF, 0x3D6, 0x53B,
|
||||
0x213, 0x029, 0x0D0,
|
||||
0x48E
|
||||
};
|
||||
static const u16 lut_prbs_8k[14] = {
|
||||
0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
|
||||
|
||||
static const u16 lut_prbs_8k[13] = {
|
||||
0x740, 0x069, 0x7DD,
|
||||
0x208, 0x7B9, 0x5C7,
|
||||
0x7FF, 0x53B, 0x029,
|
||||
0x48E, 0x4C4, 0x367,
|
||||
0x684
|
||||
};
|
||||
|
||||
static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
|
||||
{
|
||||
int sub_channel_prbs_group = 0;
|
||||
int prbs_group;
|
||||
|
||||
sub_channel_prbs_group = (subchannel / 3) + 1;
|
||||
dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
|
||||
sub_channel_prbs_group = subchannel / 3;
|
||||
if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k))
|
||||
return 0;
|
||||
|
||||
switch (state->fe[0]->dtv_property_cache.transmission_mode) {
|
||||
case TRANSMISSION_MODE_2K:
|
||||
return lut_prbs_2k[sub_channel_prbs_group];
|
||||
prbs_group = lut_prbs_2k[sub_channel_prbs_group];
|
||||
break;
|
||||
case TRANSMISSION_MODE_4K:
|
||||
return lut_prbs_4k[sub_channel_prbs_group];
|
||||
prbs_group = lut_prbs_4k[sub_channel_prbs_group];
|
||||
break;
|
||||
default:
|
||||
case TRANSMISSION_MODE_8K:
|
||||
return lut_prbs_8k[sub_channel_prbs_group];
|
||||
prbs_group = lut_prbs_8k[sub_channel_prbs_group];
|
||||
}
|
||||
|
||||
dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n",
|
||||
sub_channel_prbs_group, subchannel, prbs_group);
|
||||
|
||||
return prbs_group;
|
||||
}
|
||||
|
||||
static void dib8000_set_13seg_channel(struct dib8000_state *state)
|
||||
|
@ -2409,10 +2432,8 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq
|
|||
/* TSB or ISDBT ? apply it now */
|
||||
if (c->isdbt_sb_mode) {
|
||||
dib8000_set_sb_channel(state);
|
||||
if (c->isdbt_sb_subchannel < 14)
|
||||
init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
|
||||
else
|
||||
init_prbs = 0;
|
||||
init_prbs = dib8000_get_init_prbs(state,
|
||||
c->isdbt_sb_subchannel);
|
||||
} else {
|
||||
dib8000_set_13seg_channel(state);
|
||||
init_prbs = 0xfff;
|
||||
|
@ -3004,6 +3025,7 @@ static int dib8000_tune(struct dvb_frontend *fe)
|
|||
|
||||
unsigned long *timeout = &state->timeout;
|
||||
unsigned long now = jiffies;
|
||||
u16 init_prbs;
|
||||
#ifdef DIB8000_AGC_FREEZE
|
||||
u16 agc1, agc2;
|
||||
#endif
|
||||
|
@ -3302,8 +3324,10 @@ static int dib8000_tune(struct dvb_frontend *fe)
|
|||
break;
|
||||
|
||||
case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
|
||||
if (state->subchannel <= 41) {
|
||||
dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
|
||||
init_prbs = dib8000_get_init_prbs(state, state->subchannel);
|
||||
|
||||
if (init_prbs) {
|
||||
dib8000_set_subchannel_prbs(state, init_prbs);
|
||||
*tune_state = CT_DEMOD_STEP_9;
|
||||
} else {
|
||||
*tune_state = CT_DEMOD_STOP;
|
||||
|
|
|
@ -842,6 +842,20 @@ config VIDEO_IMX334
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx334.
|
||||
|
||||
config VIDEO_IMX335
|
||||
tristate "Sony IMX335 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_V4L2
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX335 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx335.
|
||||
|
||||
config VIDEO_IMX355
|
||||
tristate "Sony IMX355 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
|
@ -854,6 +868,20 @@ config VIDEO_IMX355
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx355.
|
||||
|
||||
config VIDEO_IMX412
|
||||
tristate "Sony IMX412 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_V4L2
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX412 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx412.
|
||||
|
||||
config VIDEO_OV02A10
|
||||
tristate "OmniVision OV02A10 sensor support"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
@ -1103,6 +1131,20 @@ config VIDEO_OV8865
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov8865.
|
||||
|
||||
config VIDEO_OV9282
|
||||
tristate "OmniVision OV9282 sensor support"
|
||||
depends on OF_GPIO
|
||||
depends on I2C && VIDEO_V4L2
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the OmniVision
|
||||
OV9282 camera sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov9282.
|
||||
|
||||
config VIDEO_OV9640
|
||||
tristate "OmniVision OV9640 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
|
|
|
@ -84,6 +84,7 @@ obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
|
|||
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
|
||||
obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
|
||||
obj-$(CONFIG_VIDEO_OV8865) += ov8865.o
|
||||
obj-$(CONFIG_VIDEO_OV9282) += ov9282.o
|
||||
obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
|
||||
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
|
||||
obj-$(CONFIG_VIDEO_OV9734) += ov9734.o
|
||||
|
@ -124,11 +125,12 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o
|
|||
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
|
||||
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
|
||||
obj-$(CONFIG_VIDEO_IMX334) += imx334.o
|
||||
obj-$(CONFIG_VIDEO_IMX335) += imx335.o
|
||||
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
|
||||
obj-$(CONFIG_VIDEO_IMX412) += imx412.o
|
||||
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
|
||||
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
|
||||
obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o
|
||||
obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o
|
||||
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
|
||||
|
||||
obj-$(CONFIG_SDR_MAX2175) += max2175.o
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
#define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017
|
||||
#define ADV7180_REG_CTRL_2 0x001d
|
||||
#define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031
|
||||
#define ADV7180_VSYNC_FIELD_CTL_1_NEWAV 0x12
|
||||
#define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d
|
||||
#define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e
|
||||
#define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f
|
||||
|
@ -205,6 +206,7 @@ struct adv7180_state {
|
|||
struct mutex mutex; /* mutual excl. when accessing chip */
|
||||
int irq;
|
||||
struct gpio_desc *pwdn_gpio;
|
||||
struct gpio_desc *rst_gpio;
|
||||
v4l2_std_id curr_norm;
|
||||
bool powered;
|
||||
bool streaming;
|
||||
|
@ -216,6 +218,7 @@ struct adv7180_state {
|
|||
struct i2c_client *vpp_client;
|
||||
const struct adv7180_chip_info *chip_info;
|
||||
enum v4l2_field field;
|
||||
bool force_bt656_4;
|
||||
};
|
||||
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
|
||||
struct adv7180_state, \
|
||||
|
@ -484,6 +487,19 @@ static void adv7180_set_power_pin(struct adv7180_state *state, bool on)
|
|||
}
|
||||
}
|
||||
|
||||
static void adv7180_set_reset_pin(struct adv7180_state *state, bool on)
|
||||
{
|
||||
if (!state->rst_gpio)
|
||||
return;
|
||||
|
||||
if (on) {
|
||||
gpiod_set_value_cansleep(state->rst_gpio, 1);
|
||||
} else {
|
||||
gpiod_set_value_cansleep(state->rst_gpio, 0);
|
||||
usleep_range(5000, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
static int adv7180_set_power(struct adv7180_state *state, bool on)
|
||||
{
|
||||
u8 val;
|
||||
|
@ -963,10 +979,26 @@ static int adv7182_init(struct adv7180_state *state)
|
|||
adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57);
|
||||
adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0);
|
||||
} else {
|
||||
if (state->chip_info->flags & ADV7180_FLAG_V2)
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
|
||||
0x17);
|
||||
if (state->chip_info->flags & ADV7180_FLAG_V2) {
|
||||
if (state->force_bt656_4) {
|
||||
/* ITU-R BT.656-4 compatible */
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
|
||||
ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
|
||||
/* Manually set NEWAVMODE */
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_VSYNC_FIELD_CTL_1,
|
||||
ADV7180_VSYNC_FIELD_CTL_1_NEWAV);
|
||||
/* Manually set V bit end position in NTSC mode */
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_NTSC_V_BIT_END,
|
||||
ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
|
||||
} else {
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
|
||||
0x17);
|
||||
}
|
||||
}
|
||||
else
|
||||
adv7180_write(state,
|
||||
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
|
||||
|
@ -1263,6 +1295,7 @@ static int init_device(struct adv7180_state *state)
|
|||
mutex_lock(&state->mutex);
|
||||
|
||||
adv7180_set_power_pin(state, true);
|
||||
adv7180_set_reset_pin(state, false);
|
||||
|
||||
adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
|
||||
usleep_range(5000, 10000);
|
||||
|
@ -1314,6 +1347,7 @@ static int init_device(struct adv7180_state *state)
|
|||
static int adv7180_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct adv7180_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
@ -1338,6 +1372,17 @@ static int adv7180_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(state->rst_gpio)) {
|
||||
ret = PTR_ERR(state->rst_gpio);
|
||||
v4l_err(client, "request for reset pin failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "adv,force-bt656-4"))
|
||||
state->force_bt656_4 = true;
|
||||
|
||||
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
|
||||
state->csi_client = i2c_new_dummy_device(client->adapter,
|
||||
ADV7180_DEFAULT_CSI_I2C_ADDR);
|
||||
|
@ -1392,11 +1437,19 @@ static int adv7180_probe(struct i2c_client *client,
|
|||
if (ret)
|
||||
goto err_free_irq;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr, client->adapter->name);
|
||||
mutex_lock(&state->mutex);
|
||||
ret = adv7180_read(state, ADV7180_REG_IDENT);
|
||||
mutex_unlock(&state->mutex);
|
||||
if (ret < 0)
|
||||
goto err_v4l2_async_unregister;
|
||||
|
||||
v4l_info(client, "chip id 0x%x found @ 0x%02x (%s)\n",
|
||||
ret, client->addr, client->adapter->name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_v4l2_async_unregister:
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
err_free_irq:
|
||||
if (state->irq > 0)
|
||||
free_irq(client->irq, state);
|
||||
|
@ -1428,6 +1481,7 @@ static int adv7180_remove(struct i2c_client *client)
|
|||
i2c_unregister_device(state->vpp_client);
|
||||
i2c_unregister_device(state->csi_client);
|
||||
|
||||
adv7180_set_reset_pin(state, true);
|
||||
adv7180_set_power_pin(state, false);
|
||||
|
||||
mutex_destroy(&state->mutex);
|
||||
|
|
|
@ -1943,6 +1943,51 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable)
|
|||
return rval;
|
||||
}
|
||||
|
||||
static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags)
|
||||
{
|
||||
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
|
||||
int rval;
|
||||
|
||||
if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) {
|
||||
switch (sensor->hwcfg.csi_signalling_mode) {
|
||||
case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY:
|
||||
if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) &
|
||||
CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY))
|
||||
return -EACCES;
|
||||
break;
|
||||
case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY:
|
||||
if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) &
|
||||
CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY))
|
||||
return -EACCES;
|
||||
break;
|
||||
default:
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
rval = ccs_pm_get_init(sensor);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) {
|
||||
rval = ccs_write(sensor, MANUAL_LP_CTRL,
|
||||
CCS_MANUAL_LP_CTRL_ENABLE);
|
||||
if (rval)
|
||||
pm_runtime_put(&client->dev);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int ccs_post_streamoff(struct v4l2_subdev *subdev)
|
||||
{
|
||||
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
|
||||
|
||||
return pm_runtime_put(&client->dev);
|
||||
}
|
||||
|
||||
static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
|
@ -2673,8 +2718,7 @@ static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines)
|
|||
*/
|
||||
|
||||
static ssize_t
|
||||
ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
nvm_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
||||
|
@ -2704,11 +2748,10 @@ ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
|
|||
*/
|
||||
return rval;
|
||||
}
|
||||
static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL);
|
||||
static DEVICE_ATTR_RO(nvm);
|
||||
|
||||
static ssize_t
|
||||
ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
ident_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
|
||||
|
@ -2723,8 +2766,7 @@ ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr,
|
|||
minfo->smia_manufacturer_id, minfo->model_id,
|
||||
minfo->revision_number) + 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL);
|
||||
static DEVICE_ATTR_RO(ident);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 subdev core operations
|
||||
|
@ -3058,6 +3100,8 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||
|
||||
static const struct v4l2_subdev_video_ops ccs_video_ops = {
|
||||
.s_stream = ccs_set_stream,
|
||||
.pre_streamon = ccs_pre_streamon,
|
||||
.post_streamoff = ccs_post_streamoff,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops ccs_pad_ops = {
|
||||
|
|
|
@ -1237,8 +1237,7 @@ static int et8ek8_dev_init(struct v4l2_subdev *subdev)
|
|||
* sysfs attributes
|
||||
*/
|
||||
static ssize_t
|
||||
et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
priv_mem_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct v4l2_subdev *subdev = dev_get_drvdata(dev);
|
||||
struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
|
||||
|
@ -1251,7 +1250,7 @@ et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
return ET8EK8_PRIV_MEM_SIZE;
|
||||
}
|
||||
static DEVICE_ATTR(priv_mem, 0444, et8ek8_priv_mem_read, NULL);
|
||||
static DEVICE_ATTR_RO(priv_mem);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* V4L2 subdev core operations
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define IMX258_CHIP_ID 0x0258
|
||||
|
||||
/* V_TIMING internal */
|
||||
#define IMX258_VTS_30FPS 0x0c98
|
||||
#define IMX258_VTS_30FPS 0x0c50
|
||||
#define IMX258_VTS_30FPS_2K 0x0638
|
||||
#define IMX258_VTS_30FPS_VGA 0x034c
|
||||
#define IMX258_VTS_MAX 0xffff
|
||||
|
@ -47,7 +47,7 @@
|
|||
/* Analog gain control */
|
||||
#define IMX258_REG_ANALOG_GAIN 0x0204
|
||||
#define IMX258_ANA_GAIN_MIN 0
|
||||
#define IMX258_ANA_GAIN_MAX 0x1fff
|
||||
#define IMX258_ANA_GAIN_MAX 480
|
||||
#define IMX258_ANA_GAIN_STEP 1
|
||||
#define IMX258_ANA_GAIN_DEFAULT 0x0
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -51,7 +51,7 @@
|
|||
#define OV2740_REG_MWB_R_GAIN 0x500a
|
||||
#define OV2740_REG_MWB_G_GAIN 0x500c
|
||||
#define OV2740_REG_MWB_B_GAIN 0x500e
|
||||
#define OV2740_DGTL_GAIN_MIN 0
|
||||
#define OV2740_DGTL_GAIN_MIN 1024
|
||||
#define OV2740_DGTL_GAIN_MAX 4095
|
||||
#define OV2740_DGTL_GAIN_STEP 1
|
||||
#define OV2740_DGTL_GAIN_DEFAULT 1024
|
||||
|
@ -61,6 +61,12 @@
|
|||
#define OV2740_TEST_PATTERN_ENABLE BIT(7)
|
||||
#define OV2740_TEST_PATTERN_BAR_SHIFT 2
|
||||
|
||||
/* Group Access */
|
||||
#define OV2740_REG_GROUP_ACCESS 0x3208
|
||||
#define OV2740_GROUP_HOLD_START 0x0
|
||||
#define OV2740_GROUP_HOLD_END 0x10
|
||||
#define OV2740_GROUP_HOLD_LAUNCH 0xa0
|
||||
|
||||
/* ISP CTRL00 */
|
||||
#define OV2740_REG_ISP_CTRL00 0x5000
|
||||
/* ISP CTRL01 */
|
||||
|
@ -438,6 +444,11 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain)
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1,
|
||||
OV2740_GROUP_HOLD_START);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_R_GAIN, 2, d_gain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -446,7 +457,18 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain);
|
||||
ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1,
|
||||
OV2740_GROUP_HOLD_END);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1,
|
||||
OV2740_GROUP_HOLD_LAUNCH);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov2740_test_pattern(struct ov2740 *ov2740, u32 pattern)
|
||||
|
|
|
@ -135,7 +135,9 @@ struct ov5640_pixfmt {
|
|||
static const struct ov5640_pixfmt ov5640_formats[] = {
|
||||
{ MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, },
|
||||
{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, },
|
||||
{ MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, },
|
||||
|
@ -2338,11 +2340,13 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
|
|||
u8 fmt, mux;
|
||||
|
||||
switch (format->code) {
|
||||
case MEDIA_BUS_FMT_UYVY8_1X16:
|
||||
case MEDIA_BUS_FMT_UYVY8_2X8:
|
||||
/* YUV422, UYVY */
|
||||
fmt = 0x3f;
|
||||
mux = OV5640_FMT_MUX_YUV422;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_YUYV8_1X16:
|
||||
case MEDIA_BUS_FMT_YUYV8_2X8:
|
||||
/* YUV422, YUYV */
|
||||
fmt = 0x30;
|
||||
|
|
|
@ -2304,25 +2304,26 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev)
|
|||
|
||||
clk_set_rate(ov8856->xvclk, xvclk_rate);
|
||||
xvclk_rate = clk_get_rate(ov8856->xvclk);
|
||||
|
||||
ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ov8856->reset_gpio))
|
||||
return PTR_ERR(ov8856->reset_gpio);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++)
|
||||
ov8856->supplies[i].supply = ov8856_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev,
|
||||
ARRAY_SIZE(ov8856_supply_names),
|
||||
ov8856->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (xvclk_rate != OV8856_XVCLK_19_2)
|
||||
dev_warn(dev, "external clock rate %u is unsupported",
|
||||
xvclk_rate);
|
||||
|
||||
ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ov8856->reset_gpio))
|
||||
return PTR_ERR(ov8856->reset_gpio);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++)
|
||||
ov8856->supplies[i].supply = ov8856_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov8856_supply_names),
|
||||
ov8856->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||
if (!ep)
|
||||
return -ENXIO;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,6 +60,12 @@
|
|||
#define OV9734_TEST_PATTERN_ENABLE BIT(7)
|
||||
#define OV9734_TEST_PATTERN_BAR_SHIFT 2
|
||||
|
||||
/* Group Access */
|
||||
#define OV9734_REG_GROUP_ACCESS 0x3208
|
||||
#define OV9734_GROUP_HOLD_START 0x0
|
||||
#define OV9734_GROUP_HOLD_END 0x10
|
||||
#define OV9734_GROUP_HOLD_LAUNCH 0xa0
|
||||
|
||||
enum {
|
||||
OV9734_LINK_FREQ_180MHZ_INDEX,
|
||||
};
|
||||
|
@ -433,6 +439,11 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1,
|
||||
OV9734_GROUP_HOLD_START);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_R_GAIN, 2, d_gain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -441,7 +452,18 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain);
|
||||
ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1,
|
||||
OV9734_GROUP_HOLD_END);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1,
|
||||
OV9734_GROUP_HOLD_LAUNCH);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov9734_test_pattern(struct ov9734 *ov9734, u32 pattern)
|
||||
|
|
|
@ -563,7 +563,7 @@ static void tda1997x_delayed_work_enable_hpd(struct work_struct *work)
|
|||
delayed_work_enable_hpd);
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
|
||||
v4l2_dbg(2, debug, sd, "%s:\n", __func__);
|
||||
v4l2_dbg(2, debug, sd, "%s\n", __func__);
|
||||
|
||||
/* Set HPD high */
|
||||
tda1997x_manual_hpd(sd, HPD_HIGH_OTHER);
|
||||
|
@ -1107,7 +1107,8 @@ tda1997x_detect_std(struct tda1997x_state *state,
|
|||
hper = io_read16(sd, REG_H_PER) & MASK_HPER;
|
||||
hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
|
||||
v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper);
|
||||
if (!vper || !hper || !hsper)
|
||||
|
||||
if (!state->input_detect[0] && !state->input_detect[1])
|
||||
return -ENOLINK;
|
||||
|
||||
for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
|
||||
|
@ -1695,14 +1696,15 @@ static int tda1997x_query_dv_timings(struct v4l2_subdev *sd,
|
|||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct tda1997x_state *state = to_state(sd);
|
||||
int ret;
|
||||
|
||||
v4l_dbg(1, debug, state->client, "%s\n", __func__);
|
||||
memset(timings, 0, sizeof(struct v4l2_dv_timings));
|
||||
mutex_lock(&state->lock);
|
||||
tda1997x_detect_std(state, timings);
|
||||
ret = tda1997x_detect_std(state, timings);
|
||||
mutex_unlock(&state->lock);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
|
||||
|
@ -2233,6 +2235,7 @@ static int tda1997x_core_init(struct v4l2_subdev *sd)
|
|||
/* get initial HDMI status */
|
||||
state->hdmi_status = io_read(sd, REG_HDMI_FLAGS);
|
||||
|
||||
io_write(sd, REG_EDID_ENABLE, EDID_ENABLE_A_EN | EDID_ENABLE_B_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -964,7 +964,7 @@ static int tvp5150_enable(struct v4l2_subdev *sd)
|
|||
|
||||
/*
|
||||
* Enable the YCbCr and clock outputs. In discrete sync mode
|
||||
* (non-BT.656) additionally enable the the sync outputs.
|
||||
* (non-BT.656) additionally enable the sync outputs.
|
||||
*/
|
||||
switch (decoder->mbus_type) {
|
||||
case V4L2_MBUS_PARALLEL:
|
||||
|
|
|
@ -556,7 +556,7 @@ static const struct media_file_operations media_device_fops = {
|
|||
* sysfs
|
||||
*/
|
||||
|
||||
static ssize_t show_model(struct device *cd,
|
||||
static ssize_t model_show(struct device *cd,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct media_devnode *devnode = to_media_devnode(cd);
|
||||
|
@ -565,7 +565,7 @@ static ssize_t show_model(struct device *cd,
|
|||
return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
|
||||
static DEVICE_ATTR_RO(model);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Registration/unregistration
|
||||
|
|
|
@ -78,27 +78,53 @@
|
|||
#define IVTV_PCI_ID_SONY 0x104d
|
||||
|
||||
/* hardware flags, no gaps allowed */
|
||||
#define IVTV_HW_CX25840 (1 << 0)
|
||||
#define IVTV_HW_SAA7115 (1 << 1)
|
||||
#define IVTV_HW_SAA7127 (1 << 2)
|
||||
#define IVTV_HW_MSP34XX (1 << 3)
|
||||
#define IVTV_HW_TUNER (1 << 4)
|
||||
#define IVTV_HW_WM8775 (1 << 5)
|
||||
#define IVTV_HW_CS53L32A (1 << 6)
|
||||
#define IVTV_HW_TVEEPROM (1 << 7)
|
||||
#define IVTV_HW_SAA7114 (1 << 8)
|
||||
#define IVTV_HW_UPD64031A (1 << 9)
|
||||
#define IVTV_HW_UPD6408X (1 << 10)
|
||||
#define IVTV_HW_SAA717X (1 << 11)
|
||||
#define IVTV_HW_WM8739 (1 << 12)
|
||||
#define IVTV_HW_VP27SMPX (1 << 13)
|
||||
#define IVTV_HW_M52790 (1 << 14)
|
||||
#define IVTV_HW_GPIO (1 << 15)
|
||||
#define IVTV_HW_I2C_IR_RX_AVER (1 << 16)
|
||||
#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17) /* External before internal */
|
||||
#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18)
|
||||
#define IVTV_HW_Z8F0811_IR_HAUP (1 << 19)
|
||||
#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 20)
|
||||
enum ivtv_hw_bits {
|
||||
IVTV_HW_BIT_CX25840,
|
||||
IVTV_HW_BIT_SAA7115,
|
||||
IVTV_HW_BIT_SAA7127,
|
||||
IVTV_HW_BIT_MSP34XX,
|
||||
IVTV_HW_BIT_TUNER,
|
||||
IVTV_HW_BIT_WM8775,
|
||||
IVTV_HW_BIT_CS53L32A,
|
||||
IVTV_HW_BIT_TVEEPROM,
|
||||
IVTV_HW_BIT_SAA7114,
|
||||
IVTV_HW_BIT_UPD64031A,
|
||||
IVTV_HW_BIT_UPD6408X,
|
||||
IVTV_HW_BIT_SAA717X,
|
||||
IVTV_HW_BIT_WM8739,
|
||||
IVTV_HW_BIT_VP27SMPX,
|
||||
IVTV_HW_BIT_M52790,
|
||||
IVTV_HW_BIT_GPIO,
|
||||
IVTV_HW_BIT_I2C_IR_RX_AVER,
|
||||
IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT, /* External before internal */
|
||||
IVTV_HW_BIT_I2C_IR_RX_HAUP_INT,
|
||||
IVTV_HW_BIT_Z8F0811_IR_HAUP,
|
||||
IVTV_HW_BIT_I2C_IR_RX_ADAPTEC,
|
||||
|
||||
IVTV_HW_MAX_BITS /* Should be the last one */
|
||||
};
|
||||
|
||||
#define IVTV_HW_CX25840 BIT(IVTV_HW_BIT_CX25840)
|
||||
#define IVTV_HW_SAA7115 BIT(IVTV_HW_BIT_SAA7115)
|
||||
#define IVTV_HW_SAA7127 BIT(IVTV_HW_BIT_SAA7127)
|
||||
#define IVTV_HW_MSP34XX BIT(IVTV_HW_BIT_MSP34XX)
|
||||
#define IVTV_HW_TUNER BIT(IVTV_HW_BIT_TUNER)
|
||||
#define IVTV_HW_WM8775 BIT(IVTV_HW_BIT_WM8775)
|
||||
#define IVTV_HW_CS53L32A BIT(IVTV_HW_BIT_CS53L32A)
|
||||
#define IVTV_HW_TVEEPROM BIT(IVTV_HW_BIT_TVEEPROM)
|
||||
#define IVTV_HW_SAA7114 BIT(IVTV_HW_BIT_SAA7114)
|
||||
#define IVTV_HW_UPD64031A BIT(IVTV_HW_BIT_UPD64031A)
|
||||
#define IVTV_HW_UPD6408X BIT(IVTV_HW_BIT_UPD6408X)
|
||||
#define IVTV_HW_SAA717X BIT(IVTV_HW_BIT_SAA717X)
|
||||
#define IVTV_HW_WM8739 BIT(IVTV_HW_BIT_WM8739)
|
||||
#define IVTV_HW_VP27SMPX BIT(IVTV_HW_BIT_VP27SMPX)
|
||||
#define IVTV_HW_M52790 BIT(IVTV_HW_BIT_M52790)
|
||||
#define IVTV_HW_GPIO BIT(IVTV_HW_BIT_GPIO)
|
||||
#define IVTV_HW_I2C_IR_RX_AVER BIT(IVTV_HW_BIT_I2C_IR_RX_AVER)
|
||||
#define IVTV_HW_I2C_IR_RX_HAUP_EXT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT)
|
||||
#define IVTV_HW_I2C_IR_RX_HAUP_INT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_INT)
|
||||
#define IVTV_HW_Z8F0811_IR_HAUP BIT(IVTV_HW_BIT_Z8F0811_IR_HAUP)
|
||||
#define IVTV_HW_I2C_IR_RX_ADAPTEC BIT(IVTV_HW_BIT_I2C_IR_RX_ADAPTEC)
|
||||
|
||||
#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
#define IVTV_ADAPTEC_IR_ADDR 0x6b
|
||||
|
||||
/* This array should match the IVTV_HW_ defines */
|
||||
static const u8 hw_addrs[] = {
|
||||
static const u8 hw_addrs[IVTV_HW_MAX_BITS] = {
|
||||
IVTV_CX25840_I2C_ADDR,
|
||||
IVTV_SAA7115_I2C_ADDR,
|
||||
IVTV_SAA7127_I2C_ADDR,
|
||||
|
@ -110,7 +110,7 @@ static const u8 hw_addrs[] = {
|
|||
};
|
||||
|
||||
/* This array should match the IVTV_HW_ defines */
|
||||
static const char * const hw_devicenames[] = {
|
||||
static const char * const hw_devicenames[IVTV_HW_MAX_BITS] = {
|
||||
"cx25840",
|
||||
"saa7115",
|
||||
"saa7127_auto", /* saa7127 or saa7129 */
|
||||
|
@ -240,10 +240,16 @@ void ivtv_i2c_new_ir_legacy(struct ivtv *itv)
|
|||
|
||||
int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
|
||||
{
|
||||
struct v4l2_subdev *sd;
|
||||
struct i2c_adapter *adap = &itv->i2c_adap;
|
||||
const char *type = hw_devicenames[idx];
|
||||
u32 hw = 1 << idx;
|
||||
struct v4l2_subdev *sd;
|
||||
const char *type;
|
||||
u32 hw;
|
||||
|
||||
if (idx >= IVTV_HW_MAX_BITS)
|
||||
return -ENODEV;
|
||||
|
||||
type = hw_devicenames[idx];
|
||||
hw = 1 << idx;
|
||||
|
||||
if (hw == IVTV_HW_TUNER) {
|
||||
/* special tuner handling */
|
||||
|
|
|
@ -1215,15 +1215,13 @@ static int alsa_device_exit(struct saa7134_dev *dev)
|
|||
static int saa7134_alsa_init(void)
|
||||
{
|
||||
struct saa7134_dev *dev = NULL;
|
||||
struct list_head *list;
|
||||
|
||||
saa7134_dmasound_init = alsa_device_init;
|
||||
saa7134_dmasound_exit = alsa_device_exit;
|
||||
|
||||
pr_info("saa7134 ALSA driver for DMA sound loaded\n");
|
||||
|
||||
list_for_each(list,&saa7134_devlist) {
|
||||
dev = list_entry(list, struct saa7134_dev, devlist);
|
||||
list_for_each_entry(dev, &saa7134_devlist, devlist) {
|
||||
if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
|
||||
pr_info("%s/alsa: %s doesn't support digital audio\n",
|
||||
dev->name, saa7134_boards[dev->board].name);
|
||||
|
|
|
@ -223,7 +223,8 @@ int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
|
|||
__le32 *cpu;
|
||||
dma_addr_t dma_addr = 0;
|
||||
|
||||
cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
|
||||
cpu = dma_alloc_coherent(&pci->dev, SAA7134_PGTABLE_SIZE, &dma_addr,
|
||||
GFP_KERNEL);
|
||||
if (NULL == cpu)
|
||||
return -ENOMEM;
|
||||
pt->size = SAA7134_PGTABLE_SIZE;
|
||||
|
@ -254,7 +255,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
|
|||
{
|
||||
if (NULL == pt->cpu)
|
||||
return;
|
||||
pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
|
||||
dma_free_coherent(&pci->dev, pt->size, pt->cpu, pt->dma);
|
||||
pt->cpu = NULL;
|
||||
}
|
||||
|
||||
|
@ -1092,7 +1093,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
|
|||
dev->pci_lat,
|
||||
(unsigned long long)pci_resource_start(pci_dev, 0));
|
||||
pci_set_master(pci_dev);
|
||||
err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
|
||||
err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
|
||||
if (err) {
|
||||
pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
|
||||
goto err_v4l2_unregister;
|
||||
|
|
|
@ -549,9 +549,6 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
|
|||
/* See of other commands are on the bus */
|
||||
if (saa7164_cmd_dequeue(dev) != SAA_OK)
|
||||
printk(KERN_ERR "dequeue(3) failed\n");
|
||||
|
||||
continue;
|
||||
|
||||
} /* (loop) */
|
||||
|
||||
/* Release the sequence number allocation */
|
||||
|
|
|
@ -663,7 +663,7 @@
|
|||
#define TW5864_SYNC 0x8008
|
||||
/* Define controls in register TW5864_SYNC */
|
||||
/*
|
||||
* 0 vlc stream to syncrous port
|
||||
* 0 vlc stream to synchronous port
|
||||
* 1 vlc stream to ddr buffers
|
||||
*/
|
||||
#define TW5864_SYNC_CFG BIT(7)
|
||||
|
|
|
@ -255,6 +255,23 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc)
|
|||
struct regmap *regmap = isc->regmap;
|
||||
u32 rlp_mode = isc->config.rlp_cfg_mode;
|
||||
|
||||
/*
|
||||
* In sama5d2, the YUV planar modes and the YUYV modes are treated
|
||||
* in the same way in RLP register.
|
||||
* Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
|
||||
* and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
|
||||
* but in sama5d2, the YCYC mode does not exist, and YYCC must be
|
||||
* selected for both planar and interleaved modes, as in fact
|
||||
* both modes are supported.
|
||||
*
|
||||
* Thus, if the YCYC mode is selected, replace it with the
|
||||
* sama5d2-compliant mode which is YYCC .
|
||||
*/
|
||||
if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) {
|
||||
rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
|
||||
rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
|
||||
}
|
||||
|
||||
regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
|
||||
ISC_RLP_CFG_MODE_MASK, rlp_mode);
|
||||
}
|
||||
|
|
|
@ -2053,17 +2053,25 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
|
|||
u32 src_fourcc, dst_fourcc;
|
||||
int ret;
|
||||
|
||||
if (!ctx->initialized) {
|
||||
ret = __coda_decoder_seq_init(ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
||||
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
||||
src_fourcc = q_data_src->fourcc;
|
||||
dst_fourcc = q_data_dst->fourcc;
|
||||
|
||||
if (!ctx->initialized) {
|
||||
ret = __coda_decoder_seq_init(ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
|
||||
CODA9_FRAME_TILED2LINEAR);
|
||||
if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
|
||||
ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
|
||||
if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
|
||||
ctx->frame_mem_ctrl |= (0x3 << 9) |
|
||||
((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
|
||||
}
|
||||
|
||||
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
|
||||
|
||||
ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
|
||||
|
|
|
@ -189,7 +189,7 @@ int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev)
|
|||
if (!ccdc_cfg) {
|
||||
/*
|
||||
* TODO. Will this ever happen? if so, we need to fix it.
|
||||
* Proabably we need to add the request to a linked list and
|
||||
* Probably we need to add the request to a linked list and
|
||||
* walk through it during vpfe probe
|
||||
*/
|
||||
printk(KERN_ERR "vpfe capture not initialized\n");
|
||||
|
|
|
@ -1238,8 +1238,8 @@ static const struct media_device_ops fimc_md_ops = {
|
|||
.link_notify = fimc_md_link_notify,
|
||||
};
|
||||
|
||||
static ssize_t fimc_md_sysfs_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t subdev_conf_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fimc_md *fmd = dev_get_drvdata(dev);
|
||||
|
||||
|
@ -1249,9 +1249,9 @@ static ssize_t fimc_md_sysfs_show(struct device *dev,
|
|||
return strscpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
|
||||
}
|
||||
|
||||
static ssize_t fimc_md_sysfs_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t subdev_conf_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fimc_md *fmd = dev_get_drvdata(dev);
|
||||
bool subdev_api;
|
||||
|
@ -1278,8 +1278,7 @@ static ssize_t fimc_md_sysfs_store(struct device *dev,
|
|||
* sub-dev - for media controller API, subdevs must be configured in user
|
||||
* space before starting streaming.
|
||||
*/
|
||||
static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
|
||||
fimc_md_sysfs_show, fimc_md_sysfs_store);
|
||||
static DEVICE_ATTR_RW(subdev_conf_mode);
|
||||
|
||||
static int cam_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
|
|
|
@ -692,7 +692,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
|
|||
* Scatter/gather mode requires stopping the controller between
|
||||
* frames so we can put in a new DMA descriptor array. If no new
|
||||
* buffer exists at frame completion, the controller is left stopped;
|
||||
* this function is charged with gettig things going again.
|
||||
* this function is charged with getting things going again.
|
||||
*/
|
||||
static void mcam_sg_restart(struct mcam_camera *cam)
|
||||
{
|
||||
|
|
|
@ -2037,8 +2037,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
|
|||
mutex_lock(&isp->media_dev.graph_mutex);
|
||||
|
||||
ret = media_entity_enum_init(&isp->crashed, &isp->media_dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
mutex_unlock(&isp->media_dev.graph_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
|
||||
if (sd->notifier != &isp->notifier)
|
||||
|
|
|
@ -234,6 +234,7 @@ struct venc_controls {
|
|||
u32 h264_loop_filter_mode;
|
||||
s32 h264_loop_filter_alpha;
|
||||
s32 h264_loop_filter_beta;
|
||||
u32 h264_8x8_transform;
|
||||
|
||||
u32 hevc_i_qp;
|
||||
u32 hevc_p_qp;
|
||||
|
@ -256,6 +257,7 @@ struct venc_controls {
|
|||
|
||||
u32 header_mode;
|
||||
bool aud_enable;
|
||||
u32 intra_refresh_period;
|
||||
|
||||
struct {
|
||||
u32 h264;
|
||||
|
|
|
@ -1137,6 +1137,9 @@ int venus_helper_set_format_constraints(struct venus_inst *inst)
|
|||
if (!IS_V6(inst->core))
|
||||
return 0;
|
||||
|
||||
if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC)
|
||||
return 0;
|
||||
|
||||
pconstraint.buffer_type = HFI_BUFFER_OUTPUT2;
|
||||
pconstraint.num_planes = 2;
|
||||
pconstraint.plane_format[0].stride_multiples = 128;
|
||||
|
|
|
@ -1239,6 +1239,14 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
|
|||
break;
|
||||
}
|
||||
|
||||
case HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8: {
|
||||
struct hfi_h264_8x8_transform *in = pdata, *tm = prop_data;
|
||||
|
||||
tm->enable_type = in->enable_type;
|
||||
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*tm);
|
||||
break;
|
||||
}
|
||||
|
||||
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
|
||||
case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
|
||||
case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE:
|
||||
|
|
|
@ -507,6 +507,7 @@
|
|||
#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020
|
||||
#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC 0x2005021
|
||||
#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY 0x2005023
|
||||
#define HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8 0x2005025
|
||||
#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026
|
||||
#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP 0x2005027
|
||||
#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP 0x2005028
|
||||
|
@ -562,6 +563,10 @@ struct hfi_bitrate {
|
|||
u32 layer_id;
|
||||
};
|
||||
|
||||
struct hfi_h264_8x8_transform {
|
||||
u32 enable_type;
|
||||
};
|
||||
|
||||
#define HFI_CAPABILITY_FRAME_WIDTH 0x01
|
||||
#define HFI_CAPABILITY_FRAME_HEIGHT 0x02
|
||||
#define HFI_CAPABILITY_MBS_PER_FRAME 0x03
|
||||
|
|
|
@ -261,7 +261,7 @@ sys_get_prop_image_version(struct device *dev,
|
|||
|
||||
smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY,
|
||||
SMEM_IMG_VER_TBL, &smem_blk_sz);
|
||||
if (smem_tbl_ptr && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ)
|
||||
if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ)
|
||||
memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS,
|
||||
img_ver, VER_STR_SZ);
|
||||
}
|
||||
|
|
|
@ -183,6 +183,8 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
|
|||
else
|
||||
return NULL;
|
||||
fmt = find_format(inst, pixmp->pixelformat, f->type);
|
||||
if (!fmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pixmp->width = clamp(pixmp->width, frame_width_min(inst),
|
||||
|
@ -547,6 +549,7 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
struct hfi_quantization_range quant_range;
|
||||
struct hfi_enable en;
|
||||
struct hfi_ltr_mode ltr_mode;
|
||||
struct hfi_intra_refresh intra_refresh = {};
|
||||
u32 ptype, rate_control, bitrate;
|
||||
u32 profile, level;
|
||||
int ret;
|
||||
|
@ -567,6 +570,7 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
struct hfi_h264_vui_timing_info info;
|
||||
struct hfi_h264_entropy_control entropy;
|
||||
struct hfi_h264_db_control deblock;
|
||||
struct hfi_h264_8x8_transform h264_transform;
|
||||
|
||||
ptype = HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
|
||||
info.enable = 1;
|
||||
|
@ -597,6 +601,17 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
ret = hfi_session_set_property(inst, ptype, &deblock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ptype = HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8;
|
||||
h264_transform.enable_type = 0;
|
||||
if (ctr->profile.h264 == HFI_H264_PROFILE_HIGH ||
|
||||
ctr->profile.h264 == HFI_H264_PROFILE_CONSTRAINED_HIGH)
|
||||
h264_transform.enable_type = ctr->h264_8x8_transform;
|
||||
|
||||
ret = hfi_session_set_property(inst, ptype, &h264_transform);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 ||
|
||||
|
@ -802,6 +817,31 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
en.enable = 1;
|
||||
|
||||
ret = hfi_session_set_property(inst, ptype, &en);
|
||||
}
|
||||
|
||||
if ((inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 ||
|
||||
inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) &&
|
||||
(rate_control == HFI_RATE_CONTROL_CBR_VFR ||
|
||||
rate_control == HFI_RATE_CONTROL_CBR_CFR)) {
|
||||
intra_refresh.mode = HFI_INTRA_REFRESH_NONE;
|
||||
intra_refresh.cir_mbs = 0;
|
||||
|
||||
if (ctr->intra_refresh_period) {
|
||||
u32 mbs;
|
||||
|
||||
mbs = ALIGN(inst->width, 16) * ALIGN(inst->height, 16);
|
||||
mbs /= 16 * 16;
|
||||
if (mbs % ctr->intra_refresh_period)
|
||||
mbs++;
|
||||
mbs /= ctr->intra_refresh_period;
|
||||
|
||||
intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM;
|
||||
intra_refresh.cir_mbs = mbs;
|
||||
}
|
||||
|
||||
ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
|
||||
|
||||
ret = hfi_session_set_property(inst, ptype, &intra_refresh);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#define SLICE_BYTE_SIZE_MAX 1024
|
||||
#define SLICE_BYTE_SIZE_MIN 1024
|
||||
#define SLICE_MB_SIZE_MAX 300
|
||||
#define INTRA_REFRESH_MBS_MAX 300
|
||||
#define AT_SLICE_BOUNDARY \
|
||||
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
|
||||
#define MAX_LTR_FRAME_COUNT 4
|
||||
|
@ -227,8 +226,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
}
|
||||
mutex_unlock(&inst->lock);
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
|
||||
ret = venc_calc_bpframes(ctrl->val, ctr->num_b_frames, &bframes,
|
||||
&ctr->num_p_frames);
|
||||
|
@ -319,6 +316,28 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
|
||||
ctr->mastering = *ctrl->p_new.p_hdr10_mastering;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
|
||||
ctr->intra_refresh_period = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
|
||||
if (ctr->profile.h264 != HFI_H264_PROFILE_HIGH &&
|
||||
ctr->profile.h264 != HFI_H264_PROFILE_CONSTRAINED_HIGH)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* In video firmware, 8x8 transform is supported only for
|
||||
* high profile(HP) and constrained high profile(CHP).
|
||||
* If client wants to disable 8x8 transform for HP/CHP,
|
||||
* it is better to set profile as main profile(MP).
|
||||
* Because there is no difference between HP and MP
|
||||
* if we disable 8x8 transform for HP.
|
||||
*/
|
||||
|
||||
if (ctrl->val == 0)
|
||||
return -EINVAL;
|
||||
|
||||
ctr->h264_8x8_transform = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -334,7 +353,7 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 57);
|
||||
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -437,6 +456,9 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP, 1, 51, 1, 1);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP, 1, 51, 1, 1);
|
||||
|
||||
|
@ -502,10 +524,6 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
|
||||
0, INTRA_REFRESH_MBS_MAX, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30);
|
||||
|
||||
|
@ -564,6 +582,10 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY,
|
||||
v4l2_ctrl_ptr_create(NULL));
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0,
|
||||
((4096 * 2304) >> 8), 1, 0);
|
||||
|
||||
ret = inst->ctrl_handler.error;
|
||||
if (ret)
|
||||
goto err;
|
||||
|
|
|
@ -253,8 +253,8 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
|
|||
int ret;
|
||||
|
||||
sd_state = v4l2_subdev_alloc_state(sd);
|
||||
if (sd_state == NULL)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(sd_state))
|
||||
return PTR_ERR(sd_state);
|
||||
|
||||
if (!rvin_format_from_pixel(vin, pix->pixelformat))
|
||||
pix->pixelformat = RVIN_DEFAULT_FORMAT;
|
||||
|
|
|
@ -863,12 +863,12 @@ static int rga_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(rga->m2m_dev)) {
|
||||
v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
|
||||
ret = PTR_ERR(rga->m2m_dev);
|
||||
goto unreg_video_dev;
|
||||
goto rel_vdev;
|
||||
}
|
||||
|
||||
ret = pm_runtime_resume_and_get(rga->dev);
|
||||
if (ret < 0)
|
||||
goto unreg_video_dev;
|
||||
goto rel_vdev;
|
||||
|
||||
rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
|
||||
rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
|
||||
|
@ -882,11 +882,23 @@ static int rga_probe(struct platform_device *pdev)
|
|||
rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
|
||||
&rga->cmdbuf_phy, GFP_KERNEL,
|
||||
DMA_ATTR_WRITE_COMBINE);
|
||||
if (!rga->cmdbuf_virt) {
|
||||
ret = -ENOMEM;
|
||||
goto rel_vdev;
|
||||
}
|
||||
|
||||
rga->src_mmu_pages =
|
||||
(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
|
||||
if (!rga->src_mmu_pages) {
|
||||
ret = -ENOMEM;
|
||||
goto free_dma;
|
||||
}
|
||||
rga->dst_mmu_pages =
|
||||
(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
|
||||
if (rga->dst_mmu_pages) {
|
||||
ret = -ENOMEM;
|
||||
goto free_src_pages;
|
||||
}
|
||||
|
||||
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
|
||||
def_frame.size = def_frame.stride * def_frame.height;
|
||||
|
@ -894,7 +906,7 @@ static int rga_probe(struct platform_device *pdev)
|
|||
ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
|
||||
if (ret) {
|
||||
v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
|
||||
goto rel_vdev;
|
||||
goto free_dst_pages;
|
||||
}
|
||||
|
||||
v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
|
||||
|
@ -902,10 +914,15 @@ static int rga_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
free_dst_pages:
|
||||
free_pages((unsigned long)rga->dst_mmu_pages, 3);
|
||||
free_src_pages:
|
||||
free_pages((unsigned long)rga->src_mmu_pages, 3);
|
||||
free_dma:
|
||||
dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
|
||||
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
|
||||
rel_vdev:
|
||||
video_device_release(vfd);
|
||||
unreg_video_dev:
|
||||
video_unregister_device(rga->vfd);
|
||||
unreg_v4l2_dev:
|
||||
v4l2_device_unregister(&rga->v4l2_dev);
|
||||
err_put_clk:
|
||||
|
|
|
@ -750,7 +750,7 @@ static int rkisp1_vb2_queue_setup(struct vb2_queue *queue,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb)
|
||||
static int rkisp1_vb2_buf_init(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct rkisp1_buffer *ispbuf =
|
||||
|
@ -780,6 +780,15 @@ static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb)
|
|||
if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap)
|
||||
swap(ispbuf->buff_addr[RKISP1_PLANE_CR],
|
||||
ispbuf->buff_addr[RKISP1_PLANE_CB]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct rkisp1_buffer *ispbuf =
|
||||
container_of(vbuf, struct rkisp1_buffer, vb);
|
||||
struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
|
||||
|
||||
spin_lock_irq(&cap->buf.lock);
|
||||
list_add_tail(&ispbuf->queue, &cap->buf.queue);
|
||||
|
@ -1039,6 +1048,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
|
|||
|
||||
static const struct vb2_ops rkisp1_vb2_ops = {
|
||||
.queue_setup = rkisp1_vb2_queue_setup,
|
||||
.buf_init = rkisp1_vb2_buf_init,
|
||||
.buf_queue = rkisp1_vb2_buf_queue,
|
||||
.buf_prepare = rkisp1_vb2_buf_prepare,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
|
|
|
@ -156,15 +156,11 @@ struct rkisp1_vdev_node {
|
|||
* @vb: vb2 buffer
|
||||
* @queue: entry of the buffer in the queue
|
||||
* @buff_addr: dma addresses of each plane, used only by the capture devices: selfpath, mainpath
|
||||
* @vaddr: virtual address for buffers used by params and stats devices
|
||||
*/
|
||||
struct rkisp1_buffer {
|
||||
struct vb2_v4l2_buffer vb;
|
||||
struct list_head queue;
|
||||
union {
|
||||
u32 buff_addr[VIDEO_MAX_PLANES];
|
||||
void *vaddr;
|
||||
};
|
||||
u32 buff_addr[VIDEO_MAX_PLANES];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1143,7 +1143,7 @@ static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params,
|
|||
cur_buf = list_first_entry(¶ms->params,
|
||||
struct rkisp1_buffer, queue);
|
||||
|
||||
new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr);
|
||||
new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
|
||||
|
||||
rkisp1_isp_isr_other_config(params, new_params);
|
||||
rkisp1_isp_isr_meas_config(params, new_params);
|
||||
|
@ -1382,7 +1382,6 @@ static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb)
|
|||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct rkisp1_params *params = vq->drv_priv;
|
||||
|
||||
params_buf->vaddr = vb2_plane_vaddr(vb, 0);
|
||||
spin_lock_irq(¶ms->config_lock);
|
||||
list_add_tail(¶ms_buf->queue, ¶ms->params);
|
||||
spin_unlock_irq(¶ms->config_lock);
|
||||
|
|
|
@ -112,7 +112,6 @@ static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb)
|
|||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct rkisp1_stats *stats_dev = vq->drv_priv;
|
||||
|
||||
stats_buf->vaddr = vb2_plane_vaddr(vb, 0);
|
||||
|
||||
spin_lock_irq(&stats_dev->lock);
|
||||
list_add_tail(&stats_buf->queue, &stats_dev->stat);
|
||||
|
@ -305,9 +304,8 @@ rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris)
|
|||
if (!cur_buf)
|
||||
return;
|
||||
|
||||
cur_stat_buf =
|
||||
(struct rkisp1_stat_buffer *)(cur_buf->vaddr);
|
||||
|
||||
cur_stat_buf = (struct rkisp1_stat_buffer *)
|
||||
vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
|
||||
if (isp_ris & RKISP1_CIF_ISP_AWB_DONE)
|
||||
rkisp1_stats_get_awb_meas(stats, cur_stat_buf);
|
||||
|
||||
|
|
|
@ -1418,7 +1418,7 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
|
|||
if (test_and_clear_bit(0, &dev->hw_lock) == 0)
|
||||
mfc_err("Failed to unlock hardware\n");
|
||||
|
||||
/* This is in deed imporant, as no operation has been
|
||||
/* This is indeed important, as no operation has been
|
||||
* scheduled, reduce the clock count as no one will
|
||||
* ever do this, because no interrupt related to this try_run
|
||||
* will ever come from hardware. */
|
||||
|
|
|
@ -175,8 +175,7 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name,
|
|||
msg.ipc_buf_size = ipc_buf_size;
|
||||
msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
|
||||
|
||||
memcpy(msg.name, name, sizeof(msg.name));
|
||||
msg.name[sizeof(msg.name) - 1] = 0;
|
||||
strscpy(msg.name, name, sizeof(msg.name));
|
||||
|
||||
msg.param_size = param->size;
|
||||
memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
|
||||
|
|
|
@ -45,22 +45,30 @@ static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val)
|
|||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static s64 cal_camerarx_get_external_rate(struct cal_camerarx *phy)
|
||||
static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy)
|
||||
{
|
||||
struct v4l2_ctrl *ctrl;
|
||||
s64 rate;
|
||||
struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2;
|
||||
u32 num_lanes = mipi_csi2->num_data_lanes;
|
||||
const struct cal_format_info *fmtinfo;
|
||||
u32 bpp;
|
||||
s64 freq;
|
||||
|
||||
ctrl = v4l2_ctrl_find(phy->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE);
|
||||
if (!ctrl) {
|
||||
phy_err(phy, "no pixel rate control in subdev: %s\n",
|
||||
phy->sensor->name);
|
||||
return -EPIPE;
|
||||
fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code);
|
||||
if (!fmtinfo)
|
||||
return -EINVAL;
|
||||
|
||||
bpp = fmtinfo->bpp;
|
||||
|
||||
freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes);
|
||||
if (freq < 0) {
|
||||
phy_err(phy, "failed to get link freq for subdev '%s'\n",
|
||||
phy->source->name);
|
||||
return freq;
|
||||
}
|
||||
|
||||
rate = v4l2_ctrl_g_ctrl_int64(ctrl);
|
||||
phy_dbg(3, phy, "sensor Pixel Rate: %llu\n", rate);
|
||||
phy_dbg(3, phy, "Source Link Freq: %llu\n", freq);
|
||||
|
||||
return rate;
|
||||
return freq;
|
||||
}
|
||||
|
||||
static void cal_camerarx_lane_config(struct cal_camerarx *phy)
|
||||
|
@ -116,34 +124,19 @@ void cal_camerarx_disable(struct cal_camerarx *phy)
|
|||
#define TCLK_MISS 1
|
||||
#define TCLK_SETTLE 14
|
||||
|
||||
static void cal_camerarx_config(struct cal_camerarx *phy, s64 external_rate)
|
||||
static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq)
|
||||
{
|
||||
unsigned int reg0, reg1;
|
||||
unsigned int ths_term, ths_settle;
|
||||
unsigned int csi2_ddrclk_khz;
|
||||
struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 =
|
||||
&phy->endpoint.bus.mipi_csi2;
|
||||
u32 num_lanes = mipi_csi2->num_data_lanes;
|
||||
|
||||
/* DPHY timing configuration */
|
||||
|
||||
/*
|
||||
* CSI-2 is DDR and we only count used lanes.
|
||||
*
|
||||
* csi2_ddrclk_khz = external_rate / 1000
|
||||
* / (2 * num_lanes) * phy->fmtinfo->bpp;
|
||||
*/
|
||||
csi2_ddrclk_khz = div_s64(external_rate * phy->fmtinfo->bpp,
|
||||
2 * num_lanes * 1000);
|
||||
|
||||
phy_dbg(1, phy, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz);
|
||||
|
||||
/* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */
|
||||
ths_term = 20 * csi2_ddrclk_khz / 1000000;
|
||||
ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000);
|
||||
phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term);
|
||||
|
||||
/* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */
|
||||
ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4;
|
||||
ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4;
|
||||
phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle);
|
||||
|
||||
reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0);
|
||||
|
@ -240,24 +233,41 @@ static void cal_camerarx_enable_irqs(struct cal_camerarx *phy)
|
|||
CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK |
|
||||
CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK |
|
||||
CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK;
|
||||
const u32 vc_err_mask =
|
||||
CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) |
|
||||
CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) |
|
||||
CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) |
|
||||
CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) |
|
||||
CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) |
|
||||
CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) |
|
||||
CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) |
|
||||
CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3);
|
||||
|
||||
/* Enable CIO error IRQs. */
|
||||
/* Enable CIO & VC error IRQs. */
|
||||
cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0),
|
||||
CAL_HL_IRQ_CIO_MASK(phy->instance));
|
||||
CAL_HL_IRQ_CIO_MASK(phy->instance) |
|
||||
CAL_HL_IRQ_VC_MASK(phy->instance));
|
||||
cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance),
|
||||
cio_err_mask);
|
||||
cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance),
|
||||
vc_err_mask);
|
||||
}
|
||||
|
||||
static void cal_camerarx_disable_irqs(struct cal_camerarx *phy)
|
||||
{
|
||||
/* Disable CIO error irqs */
|
||||
cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0),
|
||||
CAL_HL_IRQ_CIO_MASK(phy->instance));
|
||||
CAL_HL_IRQ_CIO_MASK(phy->instance) |
|
||||
CAL_HL_IRQ_VC_MASK(phy->instance));
|
||||
cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0);
|
||||
cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0);
|
||||
}
|
||||
|
||||
static void cal_camerarx_ppi_enable(struct cal_camerarx *phy)
|
||||
{
|
||||
cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance),
|
||||
1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK);
|
||||
|
||||
cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance),
|
||||
1, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
|
||||
}
|
||||
|
@ -270,16 +280,21 @@ static void cal_camerarx_ppi_disable(struct cal_camerarx *phy)
|
|||
|
||||
static int cal_camerarx_start(struct cal_camerarx *phy)
|
||||
{
|
||||
s64 external_rate;
|
||||
s64 link_freq;
|
||||
u32 sscounter;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
external_rate = cal_camerarx_get_external_rate(phy);
|
||||
if (external_rate < 0)
|
||||
return external_rate;
|
||||
if (phy->enable_count > 0) {
|
||||
phy->enable_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = v4l2_subdev_call(phy->sensor, core, s_power, 1);
|
||||
link_freq = cal_camerarx_get_ext_link_freq(phy);
|
||||
if (link_freq < 0)
|
||||
return link_freq;
|
||||
|
||||
ret = v4l2_subdev_call(phy->source, core, s_power, 1);
|
||||
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
|
||||
phy_err(phy, "power on failed in subdev\n");
|
||||
return ret;
|
||||
|
@ -311,7 +326,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
|
|||
* 2. CSI PHY and link initialization sequence.
|
||||
*
|
||||
* a. Deassert the CSI-2 PHY reset. Do not wait for reset completion
|
||||
* at this point, as it requires the external sensor to send the
|
||||
* at this point, as it requires the external source to send the
|
||||
* CSI-2 HS clock.
|
||||
*/
|
||||
cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance),
|
||||
|
@ -325,7 +340,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
|
|||
camerarx_read(phy, CAL_CSI2_PHY_REG0);
|
||||
|
||||
/* Program the PHY timing parameters. */
|
||||
cal_camerarx_config(phy, external_rate);
|
||||
cal_camerarx_config(phy, link_freq);
|
||||
|
||||
/*
|
||||
* b. Assert the FORCERXMODE signal.
|
||||
|
@ -370,12 +385,12 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
|
|||
cal_camerarx_power(phy, true);
|
||||
|
||||
/*
|
||||
* Start the sensor to enable the CSI-2 HS clock. We can now wait for
|
||||
* Start the source to enable the CSI-2 HS clock. We can now wait for
|
||||
* CSI-2 PHY reset to complete.
|
||||
*/
|
||||
ret = v4l2_subdev_call(phy->sensor, video, s_stream, 1);
|
||||
ret = v4l2_subdev_call(phy->source, video, s_stream, 1);
|
||||
if (ret) {
|
||||
v4l2_subdev_call(phy->sensor, core, s_power, 0);
|
||||
v4l2_subdev_call(phy->source, core, s_power, 0);
|
||||
cal_camerarx_disable_irqs(phy);
|
||||
phy_err(phy, "stream on failed in subdev\n");
|
||||
return ret;
|
||||
|
@ -399,14 +414,18 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
|
|||
/* Finally, enable the PHY Protocol Interface (PPI). */
|
||||
cal_camerarx_ppi_enable(phy);
|
||||
|
||||
phy->enable_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cal_camerarx_stop(struct cal_camerarx *phy)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (--phy->enable_count > 0)
|
||||
return;
|
||||
|
||||
cal_camerarx_ppi_disable(phy);
|
||||
|
||||
cal_camerarx_disable_irqs(phy);
|
||||
|
@ -418,27 +437,17 @@ static void cal_camerarx_stop(struct cal_camerarx *phy)
|
|||
CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL,
|
||||
CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
|
||||
|
||||
/* Wait for power down completion */
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (cal_read_field(phy->cal,
|
||||
CAL_CSI2_COMPLEXIO_CFG(phy->instance),
|
||||
CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) ==
|
||||
CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING)
|
||||
break;
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n",
|
||||
phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n",
|
||||
phy->instance,
|
||||
cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)), i,
|
||||
(i >= 10) ? "(timeout)" : "");
|
||||
cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)));
|
||||
|
||||
/* Disable the phy */
|
||||
cal_camerarx_disable(phy);
|
||||
|
||||
if (v4l2_subdev_call(phy->sensor, video, s_stream, 0))
|
||||
if (v4l2_subdev_call(phy->source, video, s_stream, 0))
|
||||
phy_err(phy, "stream off failed in subdev\n");
|
||||
|
||||
ret = v4l2_subdev_call(phy->sensor, core, s_power, 0);
|
||||
ret = v4l2_subdev_call(phy->source, core, s_power, 0);
|
||||
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
|
||||
phy_err(phy, "power off failed in subdev\n");
|
||||
}
|
||||
|
@ -558,16 +567,16 @@ static int cal_camerarx_parse_dt(struct cal_camerarx *phy)
|
|||
endpoint->bus.mipi_csi2.flags);
|
||||
|
||||
/* Retrieve the connected device and store it for later use. */
|
||||
phy->sensor_ep_node = of_graph_get_remote_endpoint(ep_node);
|
||||
phy->sensor_node = of_graph_get_port_parent(phy->sensor_ep_node);
|
||||
if (!phy->sensor_node) {
|
||||
phy->source_ep_node = of_graph_get_remote_endpoint(ep_node);
|
||||
phy->source_node = of_graph_get_port_parent(phy->source_ep_node);
|
||||
if (!phy->source_node) {
|
||||
phy_dbg(3, phy, "Can't get remote parent\n");
|
||||
of_node_put(phy->sensor_ep_node);
|
||||
of_node_put(phy->source_ep_node);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
phy_dbg(1, phy, "Found connected device %pOFn\n", phy->sensor_node);
|
||||
phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node);
|
||||
|
||||
done:
|
||||
of_node_put(ep_node);
|
||||
|
@ -602,12 +611,18 @@ cal_camerarx_get_pad_format(struct cal_camerarx *phy,
|
|||
static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct cal_camerarx *phy = to_cal_camerarx(sd);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
|
||||
if (enable)
|
||||
return cal_camerarx_start(phy);
|
||||
ret = cal_camerarx_start(phy);
|
||||
else
|
||||
cal_camerarx_stop(phy);
|
||||
|
||||
cal_camerarx_stop(phy);
|
||||
return 0;
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
|
@ -615,27 +630,36 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
|
|||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct cal_camerarx *phy = to_cal_camerarx(sd);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
|
||||
/* No transcoding, source and sink codes must match. */
|
||||
if (code->pad == CAL_CAMERARX_PAD_SOURCE) {
|
||||
if (cal_rx_pad_is_source(code->pad)) {
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
if (code->index > 0)
|
||||
return -EINVAL;
|
||||
if (code->index > 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fmt = cal_camerarx_get_pad_format(phy, sd_state,
|
||||
CAL_CAMERARX_PAD_SINK,
|
||||
code->which);
|
||||
code->code = fmt->code;
|
||||
return 0;
|
||||
} else {
|
||||
if (code->index >= cal_num_formats) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
code->code = cal_formats[code->index].code;
|
||||
}
|
||||
|
||||
if (code->index >= cal_num_formats)
|
||||
return -EINVAL;
|
||||
out:
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
code->code = cal_formats[code->index].code;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
|
||||
|
@ -644,38 +668,46 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
|
|||
{
|
||||
struct cal_camerarx *phy = to_cal_camerarx(sd);
|
||||
const struct cal_format_info *fmtinfo;
|
||||
int ret = 0;
|
||||
|
||||
if (fse->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
|
||||
/* No transcoding, source and sink formats must match. */
|
||||
if (fse->pad == CAL_CAMERARX_PAD_SOURCE) {
|
||||
if (cal_rx_pad_is_source(fse->pad)) {
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
fmt = cal_camerarx_get_pad_format(phy, sd_state,
|
||||
CAL_CAMERARX_PAD_SINK,
|
||||
fse->which);
|
||||
if (fse->code != fmt->code)
|
||||
return -EINVAL;
|
||||
if (fse->code != fmt->code) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fse->min_width = fmt->width;
|
||||
fse->max_width = fmt->width;
|
||||
fse->min_height = fmt->height;
|
||||
fse->max_height = fmt->height;
|
||||
} else {
|
||||
fmtinfo = cal_format_by_code(fse->code);
|
||||
if (!fmtinfo) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
|
||||
fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
|
||||
fse->min_height = CAL_MIN_HEIGHT_LINES;
|
||||
fse->max_height = CAL_MAX_HEIGHT_LINES;
|
||||
}
|
||||
|
||||
fmtinfo = cal_format_by_code(fse->code);
|
||||
if (!fmtinfo)
|
||||
return -EINVAL;
|
||||
out:
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
|
||||
fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
|
||||
fse->min_height = CAL_MIN_HEIGHT_LINES;
|
||||
fse->max_height = CAL_MAX_HEIGHT_LINES;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
|
||||
|
@ -685,10 +717,14 @@ static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
|
|||
struct cal_camerarx *phy = to_cal_camerarx(sd);
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
|
||||
fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad,
|
||||
format->which);
|
||||
format->format = *fmt;
|
||||
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -702,21 +738,18 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
|
|||
unsigned int bpp;
|
||||
|
||||
/* No transcoding, source and sink formats must match. */
|
||||
if (format->pad == CAL_CAMERARX_PAD_SOURCE)
|
||||
if (cal_rx_pad_is_source(format->pad))
|
||||
return cal_camerarx_sd_get_fmt(sd, sd_state, format);
|
||||
|
||||
/*
|
||||
* Default to the first format is the requested media bus code isn't
|
||||
* Default to the first format if the requested media bus code isn't
|
||||
* supported.
|
||||
*/
|
||||
fmtinfo = cal_format_by_code(format->format.code);
|
||||
if (!fmtinfo)
|
||||
fmtinfo = &cal_formats[0];
|
||||
|
||||
/*
|
||||
* Clamp the size, update the code. The field and colorspace are
|
||||
* accepted as-is.
|
||||
*/
|
||||
/* Clamp the size, update the code. The colorspace is accepted as-is. */
|
||||
bpp = ALIGN(fmtinfo->bpp, 8);
|
||||
|
||||
format->format.width = clamp_t(unsigned int, format->format.width,
|
||||
|
@ -726,20 +759,23 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
|
|||
CAL_MIN_HEIGHT_LINES,
|
||||
CAL_MAX_HEIGHT_LINES);
|
||||
format->format.code = fmtinfo->code;
|
||||
format->format.field = V4L2_FIELD_NONE;
|
||||
|
||||
/* Store the format and propagate it to the source pad. */
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
|
||||
fmt = cal_camerarx_get_pad_format(phy, sd_state,
|
||||
CAL_CAMERARX_PAD_SINK,
|
||||
format->which);
|
||||
*fmt = format->format;
|
||||
|
||||
fmt = cal_camerarx_get_pad_format(phy, sd_state,
|
||||
CAL_CAMERARX_PAD_SOURCE,
|
||||
CAL_CAMERARX_PAD_FIRST_SOURCE,
|
||||
format->which);
|
||||
*fmt = format->format;
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
phy->fmtinfo = fmtinfo;
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -798,6 +834,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
|
|||
struct platform_device *pdev = to_platform_device(cal->dev);
|
||||
struct cal_camerarx *phy;
|
||||
struct v4l2_subdev *sd;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
|
||||
|
@ -807,6 +844,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
|
|||
phy->cal = cal;
|
||||
phy->instance = instance;
|
||||
|
||||
mutex_init(&phy->mutex);
|
||||
|
||||
phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
(instance == 0) ?
|
||||
"cal_rx_core0" :
|
||||
|
@ -838,14 +877,17 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
|
|||
sd->dev = cal->dev;
|
||||
|
||||
phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
phy->pads[CAL_CAMERARX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i)
|
||||
phy->pads[i].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.ops = &cal_camerarx_media_ops;
|
||||
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads),
|
||||
phy->pads);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
cal_camerarx_sd_init_cfg(sd, NULL);
|
||||
ret = cal_camerarx_sd_init_cfg(sd, NULL);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd);
|
||||
if (ret)
|
||||
|
@ -866,7 +908,8 @@ void cal_camerarx_destroy(struct cal_camerarx *phy)
|
|||
|
||||
v4l2_device_unregister_subdev(&phy->subdev);
|
||||
media_entity_cleanup(&phy->subdev.entity);
|
||||
of_node_put(phy->sensor_ep_node);
|
||||
of_node_put(phy->sensor_node);
|
||||
of_node_put(phy->source_ep_node);
|
||||
of_node_put(phy->source_node);
|
||||
mutex_destroy(&phy->mutex);
|
||||
kfree(phy);
|
||||
}
|
||||
|
|
|
@ -102,8 +102,8 @@ static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int cal_enum_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
const struct cal_format_info *fmtinfo;
|
||||
|
@ -128,7 +128,7 @@ static int __subdev_get_format(struct cal_ctx *ctx,
|
|||
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
sd_fmt.pad = 0;
|
||||
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt);
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -151,7 +151,7 @@ static int __subdev_set_format(struct cal_ctx *ctx,
|
|||
sd_fmt.pad = 0;
|
||||
*mbus_fmt = *fmt;
|
||||
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt);
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -189,8 +189,8 @@ static void cal_calc_format_size(struct cal_ctx *ctx,
|
|||
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
|
||||
}
|
||||
|
||||
static int cal_try_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
const struct cal_format_info *fmtinfo;
|
||||
|
@ -216,7 +216,7 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv,
|
|||
fse.code = fmtinfo->code;
|
||||
fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
for (fse.index = 0; ; fse.index++) {
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size,
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size,
|
||||
NULL, &fse);
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -249,8 +249,8 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cal_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
struct vb2_queue *q = &ctx->vb_vidq;
|
||||
|
@ -266,7 +266,7 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = cal_try_fmt_vid_cap(file, priv, f);
|
||||
ret = cal_legacy_try_fmt_vid_cap(file, priv, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -300,8 +300,8 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cal_enum_framesizes(struct file *file, void *fh,
|
||||
struct v4l2_frmsizeenum *fsize)
|
||||
static int cal_legacy_enum_framesizes(struct file *file, void *fh,
|
||||
struct v4l2_frmsizeenum *fsize)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
const struct cal_format_info *fmtinfo;
|
||||
|
@ -321,7 +321,7 @@ static int cal_enum_framesizes(struct file *file, void *fh,
|
|||
fse.code = fmtinfo->code;
|
||||
fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL,
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL,
|
||||
&fse);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -337,8 +337,8 @@ static int cal_enum_framesizes(struct file *file, void *fh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cal_enum_input(struct file *file, void *priv,
|
||||
struct v4l2_input *inp)
|
||||
static int cal_legacy_enum_input(struct file *file, void *priv,
|
||||
struct v4l2_input *inp)
|
||||
{
|
||||
if (inp->index > 0)
|
||||
return -EINVAL;
|
||||
|
@ -348,20 +348,20 @@ static int cal_enum_input(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cal_g_input(struct file *file, void *priv, unsigned int *i)
|
||||
static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cal_s_input(struct file *file, void *priv, unsigned int i)
|
||||
static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
return i > 0 ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/* timeperframe is arbitrary and continuous */
|
||||
static int cal_enum_frameintervals(struct file *file, void *priv,
|
||||
struct v4l2_frmivalenum *fival)
|
||||
static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
|
||||
struct v4l2_frmivalenum *fival)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
const struct cal_format_info *fmtinfo;
|
||||
|
@ -378,7 +378,7 @@ static int cal_enum_frameintervals(struct file *file, void *priv,
|
|||
return -EINVAL;
|
||||
|
||||
fie.code = fmtinfo->code;
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval,
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval,
|
||||
NULL, &fie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -388,13 +388,27 @@ static int cal_enum_frameintervals(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops cal_ioctl_video_ops = {
|
||||
static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
|
||||
return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a);
|
||||
}
|
||||
|
||||
static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
|
||||
{
|
||||
struct cal_ctx *ctx = video_drvdata(file);
|
||||
|
||||
return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a);
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = {
|
||||
.vidioc_querycap = cal_querycap,
|
||||
.vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap,
|
||||
.vidioc_enum_fmt_vid_cap = cal_legacy_enum_fmt_vid_cap,
|
||||
.vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap,
|
||||
.vidioc_enum_framesizes = cal_enum_framesizes,
|
||||
.vidioc_try_fmt_vid_cap = cal_legacy_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = cal_legacy_s_fmt_vid_cap,
|
||||
.vidioc_enum_framesizes = cal_legacy_enum_framesizes,
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
||||
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
|
||||
|
@ -402,15 +416,17 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = {
|
|||
.vidioc_qbuf = vb2_ioctl_qbuf,
|
||||
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
||||
.vidioc_expbuf = vb2_ioctl_expbuf,
|
||||
.vidioc_enum_input = cal_enum_input,
|
||||
.vidioc_g_input = cal_g_input,
|
||||
.vidioc_s_input = cal_s_input,
|
||||
.vidioc_enum_frameintervals = cal_enum_frameintervals,
|
||||
.vidioc_enum_input = cal_legacy_enum_input,
|
||||
.vidioc_g_input = cal_legacy_g_input,
|
||||
.vidioc_s_input = cal_legacy_s_input,
|
||||
.vidioc_enum_frameintervals = cal_legacy_enum_frameintervals,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_log_status = v4l2_ctrl_log_status,
|
||||
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
||||
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
||||
.vidioc_g_parm = cal_legacy_g_parm,
|
||||
.vidioc_s_parm = cal_legacy_s_parm,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
|
@ -421,13 +437,28 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = {
|
|||
static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int idx;
|
||||
|
||||
if (f->index >= cal_num_formats)
|
||||
return -EINVAL;
|
||||
|
||||
f->pixelformat = cal_formats[f->index].fourcc;
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
idx = 0;
|
||||
|
||||
return 0;
|
||||
for (i = 0; i < cal_num_formats; ++i) {
|
||||
if (f->mbus_code && cal_formats[i].code != f->mbus_code)
|
||||
continue;
|
||||
|
||||
if (idx == f->index) {
|
||||
f->pixelformat = cal_formats[i].fourcc;
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f,
|
||||
|
@ -656,8 +687,13 @@ static void cal_release_buffers(struct cal_ctx *ctx,
|
|||
static int cal_video_check_format(struct cal_ctx *ctx)
|
||||
{
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
struct media_pad *remote_pad;
|
||||
|
||||
format = &ctx->phy->formats[CAL_CAMERARX_PAD_SOURCE];
|
||||
remote_pad = media_entity_remote_pad(&ctx->pad);
|
||||
if (!remote_pad)
|
||||
return -ENODEV;
|
||||
|
||||
format = &ctx->phy->formats[remote_pad->index];
|
||||
|
||||
if (ctx->fmtinfo->code != format->code ||
|
||||
ctx->v_fmt.fmt.pix.height != format->height ||
|
||||
|
@ -692,9 +728,15 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
goto error_pipeline;
|
||||
}
|
||||
|
||||
ret = cal_ctx_prepare(ctx);
|
||||
if (ret) {
|
||||
ctx_err(ctx, "Failed to prepare context: %d\n", ret);
|
||||
goto error_pipeline;
|
||||
}
|
||||
|
||||
spin_lock_irq(&ctx->dma.lock);
|
||||
buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list);
|
||||
ctx->dma.pending = buf;
|
||||
ctx->dma.active = buf;
|
||||
list_del(&buf->list);
|
||||
spin_unlock_irq(&ctx->dma.lock);
|
||||
|
||||
|
@ -719,6 +761,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
error_stop:
|
||||
cal_ctx_stop(ctx);
|
||||
pm_runtime_put_sync(ctx->cal->dev);
|
||||
cal_ctx_unprepare(ctx);
|
||||
|
||||
error_pipeline:
|
||||
media_pipeline_stop(&ctx->vdev.entity);
|
||||
|
@ -738,6 +781,8 @@ static void cal_stop_streaming(struct vb2_queue *vq)
|
|||
|
||||
pm_runtime_put_sync(ctx->cal->dev);
|
||||
|
||||
cal_ctx_unprepare(ctx);
|
||||
|
||||
cal_release_buffers(ctx, VB2_BUF_STATE_ERROR);
|
||||
|
||||
media_pipeline_stop(&ctx->vdev.entity);
|
||||
|
@ -785,20 +830,20 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
|
|||
memset(&mbus_code, 0, sizeof(mbus_code));
|
||||
mbus_code.index = j;
|
||||
mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code,
|
||||
ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
|
||||
NULL, &mbus_code);
|
||||
if (ret == -EINVAL)
|
||||
break;
|
||||
|
||||
if (ret) {
|
||||
ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
|
||||
ctx->phy->sensor->name, ret);
|
||||
ctx->phy->source->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx_dbg(2, ctx,
|
||||
"subdev %s: code: %04x idx: %u\n",
|
||||
ctx->phy->sensor->name, mbus_code.code, j);
|
||||
ctx->phy->source->name, mbus_code.code, j);
|
||||
|
||||
for (k = 0; k < cal_num_formats; k++) {
|
||||
fmtinfo = &cal_formats[k];
|
||||
|
@ -816,7 +861,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
|
|||
|
||||
if (i == 0) {
|
||||
ctx_err(ctx, "No suitable format reported by subdev %s\n",
|
||||
ctx->phy->sensor->name);
|
||||
ctx->phy->source->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -841,22 +886,57 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx)
|
||||
{
|
||||
const struct cal_format_info *fmtinfo;
|
||||
struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix;
|
||||
|
||||
fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8);
|
||||
if (!fmtinfo)
|
||||
return -EINVAL;
|
||||
|
||||
pix_fmt->width = 640;
|
||||
pix_fmt->height = 480;
|
||||
pix_fmt->field = V4L2_FIELD_NONE;
|
||||
pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
|
||||
pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
|
||||
pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
|
||||
pix_fmt->pixelformat = fmtinfo->fourcc;
|
||||
|
||||
ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
/* Save current format */
|
||||
cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
|
||||
ctx->fmtinfo = fmtinfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cal_ctx_v4l2_register(struct cal_ctx *ctx)
|
||||
{
|
||||
struct video_device *vfd = &ctx->vdev;
|
||||
int ret;
|
||||
|
||||
ret = cal_ctx_v4l2_init_formats(ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!cal_mc_api) {
|
||||
struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
|
||||
|
||||
ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler,
|
||||
ret = cal_ctx_v4l2_init_formats(ctx);
|
||||
if (ret) {
|
||||
ctx_err(ctx, "Failed to init formats: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler,
|
||||
NULL, true);
|
||||
if (ret < 0) {
|
||||
ctx_err(ctx, "Failed to add sensor ctrl handler\n");
|
||||
ctx_err(ctx, "Failed to add source ctrl handler\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = cal_ctx_v4l2_init_mc_format(ctx);
|
||||
if (ret) {
|
||||
ctx_err(ctx, "Failed to init format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -868,13 +948,13 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx)
|
|||
}
|
||||
|
||||
ret = media_create_pad_link(&ctx->phy->subdev.entity,
|
||||
CAL_CAMERARX_PAD_SOURCE,
|
||||
CAL_CAMERARX_PAD_FIRST_SOURCE,
|
||||
&vfd->entity, 0,
|
||||
MEDIA_LNK_FL_IMMUTABLE |
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (ret) {
|
||||
ctx_err(ctx, "Failed to create media link for context %u\n",
|
||||
ctx->index);
|
||||
ctx->dma_ctx);
|
||||
video_unregister_device(vfd);
|
||||
return ret;
|
||||
}
|
||||
|
@ -926,9 +1006,9 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx)
|
|||
| (cal_mc_api ? V4L2_CAP_IO_MC : 0);
|
||||
vfd->v4l2_dev = &ctx->cal->v4l2_dev;
|
||||
vfd->queue = q;
|
||||
snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index);
|
||||
snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx);
|
||||
vfd->release = video_device_release_empty;
|
||||
vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops;
|
||||
vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops;
|
||||
vfd->lock = &ctx->mutex;
|
||||
video_set_drvdata(vfd, ctx);
|
||||
|
||||
|
|
|
@ -290,11 +290,42 @@ void cal_quickdump_regs(struct cal_dev *cal)
|
|||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define CAL_MAX_PIX_PROC 4
|
||||
|
||||
static int cal_reserve_pix_proc(struct cal_dev *cal)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
spin_lock(&cal->v4l2_dev.lock);
|
||||
|
||||
ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC);
|
||||
|
||||
if (ret == CAL_MAX_PIX_PROC) {
|
||||
spin_unlock(&cal->v4l2_dev.lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
cal->reserved_pix_proc_mask |= BIT(ret);
|
||||
|
||||
spin_unlock(&cal->v4l2_dev.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num)
|
||||
{
|
||||
spin_lock(&cal->v4l2_dev.lock);
|
||||
|
||||
cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num);
|
||||
|
||||
spin_unlock(&cal->v4l2_dev.lock);
|
||||
}
|
||||
|
||||
static void cal_ctx_csi2_config(struct cal_ctx *ctx)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index));
|
||||
val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx));
|
||||
cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK);
|
||||
/*
|
||||
* DT type: MIPI CSI-2 Specs
|
||||
|
@ -304,15 +335,16 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx)
|
|||
* 0x2A: RAW8 1 pixel = 1 byte
|
||||
* 0x1E: YUV422 2 pixels = 4 bytes
|
||||
*/
|
||||
cal_set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK);
|
||||
cal_set_field(&val, 0, CAL_CSI2_CTX_VC_MASK);
|
||||
cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK);
|
||||
cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK);
|
||||
cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK);
|
||||
cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK);
|
||||
cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE,
|
||||
CAL_CSI2_CTX_PACK_MODE_MASK);
|
||||
cal_write(ctx->cal, CAL_CSI2_CTX0(ctx->index), val);
|
||||
ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->index,
|
||||
cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)));
|
||||
cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val);
|
||||
ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n",
|
||||
ctx->phy->instance, ctx->csi2_ctx,
|
||||
cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)));
|
||||
}
|
||||
|
||||
static void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
|
||||
|
@ -354,16 +386,16 @@ static void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
|
|||
break;
|
||||
}
|
||||
|
||||
val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->index));
|
||||
val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc));
|
||||
cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK);
|
||||
cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK);
|
||||
cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK);
|
||||
cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK);
|
||||
cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK);
|
||||
cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK);
|
||||
cal_write(ctx->cal, CAL_PIX_PROC(ctx->index), val);
|
||||
ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->index,
|
||||
cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)));
|
||||
cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val);
|
||||
ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc,
|
||||
cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)));
|
||||
}
|
||||
|
||||
static void cal_ctx_wr_dma_config(struct cal_ctx *ctx)
|
||||
|
@ -371,27 +403,25 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx)
|
|||
unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline;
|
||||
u32 val;
|
||||
|
||||
val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index));
|
||||
val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx));
|
||||
cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK);
|
||||
cal_set_field(&val, ctx->v_fmt.fmt.pix.height,
|
||||
CAL_WR_DMA_CTRL_YSIZE_MASK);
|
||||
cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT,
|
||||
CAL_WR_DMA_CTRL_DTAG_MASK);
|
||||
cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
|
||||
CAL_WR_DMA_CTRL_MODE_MASK);
|
||||
cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR,
|
||||
CAL_WR_DMA_CTRL_PATTERN_MASK);
|
||||
cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val);
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)));
|
||||
cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val);
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)));
|
||||
|
||||
cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->index),
|
||||
cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx),
|
||||
stride / 16, CAL_WR_DMA_OFST_MASK);
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index)));
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx)));
|
||||
|
||||
val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index));
|
||||
val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx));
|
||||
/* 64 bit word means no skipping */
|
||||
cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK);
|
||||
/*
|
||||
|
@ -400,34 +430,32 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx)
|
|||
* written per line.
|
||||
*/
|
||||
cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val);
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)));
|
||||
|
||||
val = cal_read(ctx->cal, CAL_CTRL);
|
||||
cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128,
|
||||
CAL_CTRL_BURSTSIZE_MASK);
|
||||
cal_set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK);
|
||||
cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED,
|
||||
CAL_CTRL_POSTED_WRITES_MASK);
|
||||
cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK);
|
||||
cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK);
|
||||
cal_write(ctx->cal, CAL_CTRL, val);
|
||||
ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL));
|
||||
cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val);
|
||||
ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx,
|
||||
cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)));
|
||||
}
|
||||
|
||||
void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr)
|
||||
{
|
||||
cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), addr);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr);
|
||||
}
|
||||
|
||||
static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx)
|
||||
{
|
||||
u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx));
|
||||
|
||||
cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
|
||||
CAL_WR_DMA_CTRL_MODE_MASK);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val);
|
||||
}
|
||||
|
||||
static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx)
|
||||
{
|
||||
u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index));
|
||||
u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx));
|
||||
|
||||
cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS,
|
||||
CAL_WR_DMA_CTRL_MODE_MASK);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val);
|
||||
cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val);
|
||||
}
|
||||
|
||||
static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx)
|
||||
|
@ -441,6 +469,31 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx)
|
|||
return stopped;
|
||||
}
|
||||
|
||||
int cal_ctx_prepare(struct cal_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ctx->use_pix_proc = !ctx->fmtinfo->meta;
|
||||
|
||||
if (ctx->use_pix_proc) {
|
||||
ret = cal_reserve_pix_proc(ctx->cal);
|
||||
if (ret < 0) {
|
||||
ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->pix_proc = ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cal_ctx_unprepare(struct cal_ctx *ctx)
|
||||
{
|
||||
if (ctx->use_pix_proc)
|
||||
cal_release_pix_proc(ctx->cal, ctx->pix_proc);
|
||||
}
|
||||
|
||||
void cal_ctx_start(struct cal_ctx *ctx)
|
||||
{
|
||||
ctx->sequence = 0;
|
||||
|
@ -448,14 +501,17 @@ void cal_ctx_start(struct cal_ctx *ctx)
|
|||
|
||||
/* Configure the CSI-2, pixel processing and write DMA contexts. */
|
||||
cal_ctx_csi2_config(ctx);
|
||||
cal_ctx_pix_proc_config(ctx);
|
||||
if (ctx->use_pix_proc)
|
||||
cal_ctx_pix_proc_config(ctx);
|
||||
cal_ctx_wr_dma_config(ctx);
|
||||
|
||||
/* Enable IRQ_WDMA_END and IRQ_WDMA_START. */
|
||||
cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1),
|
||||
CAL_HL_IRQ_MASK(ctx->index));
|
||||
CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx));
|
||||
cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2),
|
||||
CAL_HL_IRQ_MASK(ctx->index));
|
||||
CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx));
|
||||
|
||||
cal_ctx_wr_dma_enable(ctx);
|
||||
}
|
||||
|
||||
void cal_ctx_stop(struct cal_ctx *ctx)
|
||||
|
@ -479,11 +535,18 @@ void cal_ctx_stop(struct cal_ctx *ctx)
|
|||
|
||||
/* Disable IRQ_WDMA_END and IRQ_WDMA_START. */
|
||||
cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1),
|
||||
CAL_HL_IRQ_MASK(ctx->index));
|
||||
CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx));
|
||||
cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2),
|
||||
CAL_HL_IRQ_MASK(ctx->index));
|
||||
CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx));
|
||||
|
||||
ctx->dma.state = CAL_DMA_STOPPED;
|
||||
|
||||
/* Disable CSI2 context */
|
||||
cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0);
|
||||
|
||||
/* Disable pix proc */
|
||||
if (ctx->use_pix_proc)
|
||||
cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
|
@ -577,6 +640,16 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
|
|||
cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i),
|
||||
cio_stat);
|
||||
}
|
||||
|
||||
if (status & CAL_HL_IRQ_VC_MASK(i)) {
|
||||
u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i));
|
||||
|
||||
dev_err_ratelimited(cal->dev,
|
||||
"CIO%u VC error: %#08x\n",
|
||||
i, vc_stat);
|
||||
|
||||
cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,8 +661,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
|
|||
/* Clear Interrupt status */
|
||||
cal_write(cal, CAL_HL_IRQSTATUS(1), status);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
|
||||
if (status & CAL_HL_IRQ_MASK(i))
|
||||
for (i = 0; i < cal->num_contexts; ++i) {
|
||||
if (status & CAL_HL_IRQ_WDMA_END_MASK(i))
|
||||
cal_irq_wdma_end(cal->ctx[i]);
|
||||
}
|
||||
}
|
||||
|
@ -602,8 +675,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
|
|||
/* Clear Interrupt status */
|
||||
cal_write(cal, CAL_HL_IRQSTATUS(2), status);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
|
||||
if (status & CAL_HL_IRQ_MASK(i))
|
||||
for (i = 0; i < cal->num_contexts; ++i) {
|
||||
if (status & CAL_HL_IRQ_WDMA_START_MASK(i))
|
||||
cal_irq_wdma_start(cal->ctx[i]);
|
||||
}
|
||||
}
|
||||
|
@ -635,20 +708,20 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
|
|||
int pad;
|
||||
int ret;
|
||||
|
||||
if (phy->sensor) {
|
||||
if (phy->source) {
|
||||
phy_info(phy, "Rejecting subdev %s (Already set!!)",
|
||||
subdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
phy->sensor = subdev;
|
||||
phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name);
|
||||
phy->source = subdev;
|
||||
phy_dbg(1, phy, "Using source %s for capture\n", subdev->name);
|
||||
|
||||
pad = media_entity_get_fwnode_pad(&subdev->entity,
|
||||
of_fwnode_handle(phy->sensor_ep_node),
|
||||
of_fwnode_handle(phy->source_ep_node),
|
||||
MEDIA_PAD_FL_SOURCE);
|
||||
if (pad < 0) {
|
||||
phy_err(phy, "Sensor %s has no connected source pad\n",
|
||||
phy_err(phy, "Source %s has no connected source pad\n",
|
||||
subdev->name);
|
||||
return pad;
|
||||
}
|
||||
|
@ -658,7 +731,7 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
|
|||
MEDIA_LNK_FL_IMMUTABLE |
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
if (ret) {
|
||||
phy_err(phy, "Failed to create media link for sensor %s\n",
|
||||
phy_err(phy, "Failed to create media link for source %s\n",
|
||||
subdev->name);
|
||||
return ret;
|
||||
}
|
||||
|
@ -670,15 +743,30 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier)
|
|||
{
|
||||
struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier);
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
|
||||
if (cal->ctx[i])
|
||||
cal_ctx_v4l2_register(cal->ctx[i]);
|
||||
for (i = 0; i < cal->num_contexts; ++i) {
|
||||
ret = cal_ctx_v4l2_register(cal->ctx[i]);
|
||||
if (ret)
|
||||
goto err_ctx_unreg;
|
||||
}
|
||||
|
||||
if (cal_mc_api)
|
||||
ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev);
|
||||
if (!cal_mc_api)
|
||||
return 0;
|
||||
|
||||
ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev);
|
||||
if (ret)
|
||||
goto err_ctx_unreg;
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx_unreg:
|
||||
for (; i > 0; --i) {
|
||||
if (!cal->ctx[i - 1])
|
||||
continue;
|
||||
|
||||
cal_ctx_v4l2_unregister(cal->ctx[i - 1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -701,10 +789,10 @@ static int cal_async_notifier_register(struct cal_dev *cal)
|
|||
struct cal_v4l2_async_subdev *casd;
|
||||
struct fwnode_handle *fwnode;
|
||||
|
||||
if (!phy->sensor_node)
|
||||
if (!phy->source_node)
|
||||
continue;
|
||||
|
||||
fwnode = of_fwnode_handle(phy->sensor_node);
|
||||
fwnode = of_fwnode_handle(phy->source_node);
|
||||
casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier,
|
||||
fwnode,
|
||||
struct cal_v4l2_async_subdev);
|
||||
|
@ -777,10 +865,8 @@ static void cal_media_unregister(struct cal_dev *cal)
|
|||
unsigned int i;
|
||||
|
||||
/* Unregister all the V4L2 video devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) {
|
||||
if (cal->ctx[i])
|
||||
cal_ctx_v4l2_unregister(cal->ctx[i]);
|
||||
}
|
||||
for (i = 0; i < cal->num_contexts; i++)
|
||||
cal_ctx_v4l2_unregister(cal->ctx[i]);
|
||||
|
||||
cal_async_notifier_unregister(cal);
|
||||
media_device_unregister(&cal->mdev);
|
||||
|
@ -825,13 +911,6 @@ static int cal_media_init(struct cal_dev *cal)
|
|||
*/
|
||||
static void cal_media_cleanup(struct cal_dev *cal)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) {
|
||||
if (cal->ctx[i])
|
||||
cal_ctx_v4l2_cleanup(cal->ctx[i]);
|
||||
}
|
||||
|
||||
v4l2_device_unregister(&cal->v4l2_dev);
|
||||
media_device_cleanup(&cal->mdev);
|
||||
|
||||
|
@ -848,14 +927,17 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst)
|
|||
struct cal_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(cal->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->cal = cal;
|
||||
ctx->phy = cal->phy[inst];
|
||||
ctx->index = inst;
|
||||
ctx->dma_ctx = inst;
|
||||
ctx->csi2_ctx = inst;
|
||||
ctx->cport = inst;
|
||||
ctx->vc = 0;
|
||||
ctx->datatype = CAL_CSI2_CTX_DT_ANY;
|
||||
|
||||
ret = cal_ctx_v4l2_init(ctx);
|
||||
if (ret)
|
||||
|
@ -864,6 +946,13 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst)
|
|||
return ctx;
|
||||
}
|
||||
|
||||
static void cal_ctx_destroy(struct cal_ctx *ctx)
|
||||
{
|
||||
cal_ctx_v4l2_cleanup(ctx);
|
||||
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
static const struct of_device_id cal_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,dra72-cal",
|
||||
|
@ -976,7 +1065,6 @@ static int cal_init_camerarx_regmap(struct cal_dev *cal)
|
|||
static int cal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cal_dev *cal;
|
||||
struct cal_ctx *ctx;
|
||||
bool connected = false;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
@ -1045,7 +1133,7 @@ static int cal_probe(struct platform_device *pdev)
|
|||
goto error_camerarx;
|
||||
}
|
||||
|
||||
if (cal->phy[i]->sensor_node)
|
||||
if (cal->phy[i]->source_node)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
|
@ -1057,15 +1145,17 @@ static int cal_probe(struct platform_device *pdev)
|
|||
|
||||
/* Create contexts. */
|
||||
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
|
||||
if (!cal->phy[i]->sensor_node)
|
||||
if (!cal->phy[i]->source_node)
|
||||
continue;
|
||||
|
||||
cal->ctx[i] = cal_ctx_create(cal, i);
|
||||
if (!cal->ctx[i]) {
|
||||
cal_err(cal, "Failed to create context %u\n", i);
|
||||
cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i);
|
||||
if (!cal->ctx[cal->num_contexts]) {
|
||||
cal_err(cal, "Failed to create context %u\n", cal->num_contexts);
|
||||
ret = -ENODEV;
|
||||
goto error_context;
|
||||
}
|
||||
|
||||
cal->num_contexts++;
|
||||
}
|
||||
|
||||
/* Register the media device. */
|
||||
|
@ -1076,11 +1166,8 @@ static int cal_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
error_context:
|
||||
for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) {
|
||||
ctx = cal->ctx[i];
|
||||
if (ctx)
|
||||
cal_ctx_v4l2_cleanup(ctx);
|
||||
}
|
||||
for (i = 0; i < cal->num_contexts; i++)
|
||||
cal_ctx_destroy(cal->ctx[i]);
|
||||
|
||||
error_camerarx:
|
||||
for (i = 0; i < cal->data->num_csi2_phy; i++)
|
||||
|
@ -1106,16 +1193,17 @@ static int cal_remove(struct platform_device *pdev)
|
|||
|
||||
cal_media_unregister(cal);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cal->phy); i++) {
|
||||
if (cal->phy[i])
|
||||
cal_camerarx_disable(cal->phy[i]);
|
||||
}
|
||||
for (i = 0; i < cal->data->num_csi2_phy; i++)
|
||||
cal_camerarx_disable(cal->phy[i]);
|
||||
|
||||
cal_media_cleanup(cal);
|
||||
for (i = 0; i < cal->num_contexts; i++)
|
||||
cal_ctx_destroy(cal->ctx[i]);
|
||||
|
||||
for (i = 0; i < cal->data->num_csi2_phy; i++)
|
||||
cal_camerarx_destroy(cal->phy[i]);
|
||||
|
||||
cal_media_cleanup(cal);
|
||||
|
||||
if (ret >= 0)
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
@ -1127,6 +1215,7 @@ static int cal_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct cal_dev *cal = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
u32 val;
|
||||
|
||||
if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) {
|
||||
/*
|
||||
|
@ -1143,6 +1232,17 @@ static int cal_runtime_resume(struct device *dev)
|
|||
*/
|
||||
cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK);
|
||||
|
||||
val = cal_read(cal, CAL_CTRL);
|
||||
cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128,
|
||||
CAL_CTRL_BURSTSIZE_MASK);
|
||||
cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK);
|
||||
cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED,
|
||||
CAL_CTRL_POSTED_WRITES_MASK);
|
||||
cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK);
|
||||
cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK);
|
||||
cal_write(cal, CAL_CTRL, val);
|
||||
cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <media/videobuf2-v4l2.h>
|
||||
|
||||
#define CAL_MODULE_NAME "cal"
|
||||
#define CAL_NUM_CONTEXT 2
|
||||
#define CAL_MAX_NUM_CONTEXT 8
|
||||
#define CAL_NUM_CSI2_PORTS 2
|
||||
|
||||
/*
|
||||
|
@ -44,7 +44,22 @@
|
|||
#define CAL_MAX_HEIGHT_LINES 16383
|
||||
|
||||
#define CAL_CAMERARX_PAD_SINK 0
|
||||
#define CAL_CAMERARX_PAD_SOURCE 1
|
||||
#define CAL_CAMERARX_PAD_FIRST_SOURCE 1
|
||||
#define CAL_CAMERARX_NUM_SOURCE_PADS 1
|
||||
#define CAL_CAMERARX_NUM_PADS (1 + CAL_CAMERARX_NUM_SOURCE_PADS)
|
||||
|
||||
static inline bool cal_rx_pad_is_sink(u32 pad)
|
||||
{
|
||||
/* Camera RX has 1 sink pad, and N source pads */
|
||||
return pad == 0;
|
||||
}
|
||||
|
||||
static inline bool cal_rx_pad_is_source(u32 pad)
|
||||
{
|
||||
/* Camera RX has 1 sink pad, and N source pads */
|
||||
return pad >= CAL_CAMERARX_PAD_FIRST_SOURCE &&
|
||||
pad <= CAL_CAMERARX_NUM_SOURCE_PADS;
|
||||
}
|
||||
|
||||
struct device;
|
||||
struct device_node;
|
||||
|
@ -73,6 +88,7 @@ struct cal_format_info {
|
|||
u32 code;
|
||||
/* Bits per pixel */
|
||||
u8 bpp;
|
||||
bool meta;
|
||||
};
|
||||
|
||||
/* buffer for one video frame */
|
||||
|
@ -149,22 +165,29 @@ struct cal_data {
|
|||
struct cal_camerarx {
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
struct device *dev;
|
||||
struct regmap_field *fields[F_MAX_FIELDS];
|
||||
|
||||
struct cal_dev *cal;
|
||||
unsigned int instance;
|
||||
|
||||
struct v4l2_fwnode_endpoint endpoint;
|
||||
struct device_node *sensor_ep_node;
|
||||
struct device_node *sensor_node;
|
||||
struct v4l2_subdev *sensor;
|
||||
struct device_node *source_ep_node;
|
||||
struct device_node *source_node;
|
||||
struct v4l2_subdev *source;
|
||||
struct media_pipeline pipe;
|
||||
|
||||
struct v4l2_subdev subdev;
|
||||
struct media_pad pads[2];
|
||||
struct v4l2_mbus_framefmt formats[2];
|
||||
const struct cal_format_info *fmtinfo;
|
||||
struct media_pad pads[CAL_CAMERARX_NUM_PADS];
|
||||
struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS];
|
||||
|
||||
/*
|
||||
* Lock for camerarx ops. Protects:
|
||||
* - formats
|
||||
* - enable_count
|
||||
*/
|
||||
struct mutex mutex;
|
||||
|
||||
unsigned int enable_count;
|
||||
};
|
||||
|
||||
struct cal_dev {
|
||||
|
@ -184,11 +207,14 @@ struct cal_dev {
|
|||
/* Camera Core Module handle */
|
||||
struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS];
|
||||
|
||||
struct cal_ctx *ctx[CAL_NUM_CONTEXT];
|
||||
u32 num_contexts;
|
||||
struct cal_ctx *ctx[CAL_MAX_NUM_CONTEXT];
|
||||
|
||||
struct media_device mdev;
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct v4l2_async_notifier notifier;
|
||||
|
||||
unsigned long reserved_pix_proc_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -212,14 +238,20 @@ struct cal_ctx {
|
|||
/* Used to store current pixel format */
|
||||
struct v4l2_format v_fmt;
|
||||
|
||||
/* Current subdev enumerated format */
|
||||
/* Current subdev enumerated format (legacy) */
|
||||
const struct cal_format_info **active_fmt;
|
||||
unsigned int num_active_fmt;
|
||||
|
||||
unsigned int sequence;
|
||||
struct vb2_queue vb_vidq;
|
||||
unsigned int index;
|
||||
unsigned int cport;
|
||||
u8 dma_ctx;
|
||||
u8 cport;
|
||||
u8 csi2_ctx;
|
||||
u8 pix_proc;
|
||||
u8 vc;
|
||||
u8 datatype;
|
||||
|
||||
bool use_pix_proc;
|
||||
};
|
||||
|
||||
extern unsigned int cal_debug;
|
||||
|
@ -237,11 +269,11 @@ extern bool cal_mc_api;
|
|||
dev_err((cal)->dev, fmt, ##arg)
|
||||
|
||||
#define ctx_dbg(level, ctx, fmt, arg...) \
|
||||
cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg)
|
||||
cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg)
|
||||
#define ctx_info(ctx, fmt, arg...) \
|
||||
cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg)
|
||||
cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg)
|
||||
#define ctx_err(ctx, fmt, arg...) \
|
||||
cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg)
|
||||
cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg)
|
||||
|
||||
#define phy_dbg(level, phy, fmt, arg...) \
|
||||
cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg)
|
||||
|
@ -297,6 +329,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
|
|||
unsigned int instance);
|
||||
void cal_camerarx_destroy(struct cal_camerarx *phy);
|
||||
|
||||
int cal_ctx_prepare(struct cal_ctx *ctx);
|
||||
void cal_ctx_unprepare(struct cal_ctx *ctx);
|
||||
void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr);
|
||||
void cal_ctx_start(struct cal_ctx *ctx);
|
||||
void cal_ctx_stop(struct cal_ctx *ctx);
|
||||
|
|
|
@ -72,22 +72,8 @@
|
|||
#define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U)
|
||||
#define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U)
|
||||
#define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX0(m) (0x330U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX1(m) (0x334U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX2(m) (0x338U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX3(m) (0x33cU + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX4(m) (0x340U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX5(m) (0x344U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX6(m) (0x348U + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX7(m) (0x34cU + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS0(m) (0x350U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS1(m) (0x354U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS2(m) (0x358U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS3(m) (0x35cU + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS4(m) (0x360U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS5(m) (0x364U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS6(m) (0x368U + (m) * 0x80U)
|
||||
#define CAL_CSI2_STATUS7(m) (0x36cU + (m) * 0x80U)
|
||||
#define CAL_CSI2_CTX(phy, csi2_ctx) (0x330U + (phy) * 0x80U + (csi2_ctx) * 4)
|
||||
#define CAL_CSI2_STATUS(phy, csi2_ctx) (0x350U + (phy) * 0x80U + (csi2_ctx) * 4)
|
||||
|
||||
/* CAL CSI2 PHY register offsets */
|
||||
#define CAL_CSI2_PHY_REG0 0x000
|
||||
|
@ -139,7 +125,8 @@
|
|||
#define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0
|
||||
#define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0
|
||||
|
||||
#define CAL_HL_IRQ_MASK(m) BIT(m)
|
||||
#define CAL_HL_IRQ_WDMA_END_MASK(m) BIT(m)
|
||||
#define CAL_HL_IRQ_WDMA_START_MASK(m) BIT(m)
|
||||
|
||||
#define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6)
|
||||
|
||||
|
@ -419,32 +406,16 @@
|
|||
#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14)
|
||||
#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15)
|
||||
|
||||
#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT(0)
|
||||
#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT(1)
|
||||
#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT(2)
|
||||
#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT(3)
|
||||
#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT(4)
|
||||
#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT(5)
|
||||
#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT(8)
|
||||
#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT(9)
|
||||
#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT(10)
|
||||
#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT(11)
|
||||
#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT(12)
|
||||
#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT(13)
|
||||
#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT(16)
|
||||
#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT(17)
|
||||
#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT(18)
|
||||
#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT(19)
|
||||
#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT(20)
|
||||
#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT(21)
|
||||
#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT(24)
|
||||
#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT(25)
|
||||
#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT(26)
|
||||
#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT(27)
|
||||
#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT(28)
|
||||
#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT(29)
|
||||
#define CAL_CSI2_VC_IRQ_FS_IRQ_MASK(n) BIT(0 + ((n) * 8))
|
||||
#define CAL_CSI2_VC_IRQ_FE_IRQ_MASK(n) BIT(1 + ((n) * 8))
|
||||
#define CAL_CSI2_VC_IRQ_LS_IRQ_MASK(n) BIT(2 + ((n) * 8))
|
||||
#define CAL_CSI2_VC_IRQ_LE_IRQ_MASK(n) BIT(3 + ((n) * 8))
|
||||
#define CAL_CSI2_VC_IRQ_CS_IRQ_MASK(n) BIT(4 + ((n) * 8))
|
||||
#define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8))
|
||||
|
||||
#define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0)
|
||||
#define CAL_CSI2_CTX_DT_DISABLED 0
|
||||
#define CAL_CSI2_CTX_DT_ANY 1
|
||||
#define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6)
|
||||
#define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8)
|
||||
#define CAL_CSI2_CTX_ATT_MASK BIT(13)
|
||||
|
|
|
@ -676,9 +676,9 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
|
|||
* rectangles.
|
||||
*/
|
||||
entity->config = v4l2_subdev_alloc_state(&entity->subdev);
|
||||
if (entity->config == NULL) {
|
||||
if (IS_ERR(entity->config)) {
|
||||
media_entity_cleanup(&entity->subdev.entity);
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(entity->config);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -246,6 +246,16 @@ config IR_MESON
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called meson-ir.
|
||||
|
||||
config IR_MESON_TX
|
||||
tristate "Amlogic Meson IR TX"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
help
|
||||
Say Y if you want to use the IR transmitter available on
|
||||
Amlogic Meson SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called meson-ir-tx.
|
||||
|
||||
config IR_MTK
|
||||
tristate "Mediatek IR remote receiver"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
|
|||
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
|
||||
obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
|
||||
obj-$(CONFIG_IR_MESON) += meson-ir.o
|
||||
obj-$(CONFIG_IR_MESON_TX) += meson-ir-tx.o
|
||||
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
|
||||
obj-$(CONFIG_IR_ENE) += ene_ir.o
|
||||
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
|
||||
|
|
|
@ -1052,7 +1052,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
|
|||
rdev->device_name = "ENE eHome Infrared Remote Receiver";
|
||||
|
||||
if (dev->hw_learning_and_tx_capable) {
|
||||
rdev->s_learning_mode = ene_set_learning_mode;
|
||||
rdev->s_wideband_receiver = ene_set_learning_mode;
|
||||
init_completion(&dev->tx_complete);
|
||||
rdev->tx_ir = ene_transmit;
|
||||
rdev->s_tx_mask = ene_set_tx_mask;
|
||||
|
|
|
@ -412,7 +412,7 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
val |= LIRC_CAN_SET_REC_CARRIER |
|
||||
LIRC_CAN_SET_REC_CARRIER_RANGE;
|
||||
|
||||
if (dev->s_learning_mode)
|
||||
if (dev->s_wideband_receiver)
|
||||
val |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
|
||||
|
||||
if (dev->s_carrier_report)
|
||||
|
@ -519,10 +519,10 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
|
||||
case LIRC_SET_WIDEBAND_RECEIVER:
|
||||
if (!dev->s_learning_mode)
|
||||
if (!dev->s_wideband_receiver)
|
||||
ret = -ENOTTY;
|
||||
else
|
||||
ret = dev->s_learning_mode(dev, !!val);
|
||||
ret = dev->s_wideband_receiver(dev, !!val);
|
||||
break;
|
||||
|
||||
case LIRC_SET_MEASURE_CARRIER_MODE:
|
||||
|
|
|
@ -1630,7 +1630,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
|
|||
rc->tx_ir = mceusb_tx_ir;
|
||||
}
|
||||
if (ir->flags.rx2 > 0) {
|
||||
rc->s_learning_mode = mceusb_set_rx_wideband;
|
||||
rc->s_wideband_receiver = mceusb_set_rx_wideband;
|
||||
rc->s_carrier_report = mceusb_set_rx_carrier_report;
|
||||
}
|
||||
rc->driver_name = DRIVER_NAME;
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* meson-ir-tx.c - Amlogic Meson IR TX driver
|
||||
*
|
||||
* Copyright (c) 2021, SberDevices. All Rights Reserved.
|
||||
*
|
||||
* Author: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#define DEVICE_NAME "Meson IR TX"
|
||||
#define DRIVER_NAME "meson-ir-tx"
|
||||
|
||||
#define MIRTX_DEFAULT_CARRIER 38000
|
||||
#define MIRTX_DEFAULT_DUTY_CYCLE 50
|
||||
#define MIRTX_FIFO_THD 32
|
||||
|
||||
#define IRB_MOD_1US_CLK_RATE 1000000
|
||||
|
||||
#define IRB_FIFO_LEN 128
|
||||
|
||||
#define IRB_ADDR0 0x0
|
||||
#define IRB_ADDR1 0x4
|
||||
#define IRB_ADDR2 0x8
|
||||
#define IRB_ADDR3 0xc
|
||||
|
||||
#define IRB_MAX_DELAY (1 << 10)
|
||||
#define IRB_DELAY_MASK (IRB_MAX_DELAY - 1)
|
||||
|
||||
/* IRCTRL_IR_BLASTER_ADDR0 */
|
||||
#define IRB_MOD_CLK(x) ((x) << 12)
|
||||
#define IRB_MOD_SYS_CLK 0
|
||||
#define IRB_MOD_XTAL3_CLK 1
|
||||
#define IRB_MOD_1US_CLK 2
|
||||
#define IRB_MOD_10US_CLK 3
|
||||
#define IRB_INIT_HIGH BIT(2)
|
||||
#define IRB_ENABLE BIT(0)
|
||||
|
||||
/* IRCTRL_IR_BLASTER_ADDR2 */
|
||||
#define IRB_MOD_COUNT(lo, hi) ((((lo) - 1) << 16) | ((hi) - 1))
|
||||
|
||||
/* IRCTRL_IR_BLASTER_ADDR2 */
|
||||
#define IRB_WRITE_FIFO BIT(16)
|
||||
#define IRB_MOD_ENABLE BIT(12)
|
||||
#define IRB_TB_1US (0x0 << 10)
|
||||
#define IRB_TB_10US (0x1 << 10)
|
||||
#define IRB_TB_100US (0x2 << 10)
|
||||
#define IRB_TB_MOD_CLK (0x3 << 10)
|
||||
|
||||
/* IRCTRL_IR_BLASTER_ADDR3 */
|
||||
#define IRB_FIFO_THD_PENDING BIT(16)
|
||||
#define IRB_FIFO_IRQ_ENABLE BIT(8)
|
||||
|
||||
struct meson_irtx {
|
||||
struct device *dev;
|
||||
void __iomem *reg_base;
|
||||
u32 *buf;
|
||||
unsigned int buf_len;
|
||||
unsigned int buf_head;
|
||||
unsigned int carrier;
|
||||
unsigned int duty_cycle;
|
||||
/* Locks buf */
|
||||
spinlock_t lock;
|
||||
struct completion completion;
|
||||
unsigned long clk_rate;
|
||||
};
|
||||
|
||||
static void meson_irtx_set_mod(struct meson_irtx *ir)
|
||||
{
|
||||
unsigned int cnt = DIV_ROUND_CLOSEST(ir->clk_rate, ir->carrier);
|
||||
unsigned int pulse_cnt = DIV_ROUND_CLOSEST(cnt * ir->duty_cycle, 100);
|
||||
unsigned int space_cnt = cnt - pulse_cnt;
|
||||
|
||||
dev_dbg(ir->dev, "F_mod = %uHz, T_mod = %luns, duty_cycle = %u%%\n",
|
||||
ir->carrier, NSEC_PER_SEC / ir->clk_rate * cnt,
|
||||
100 * pulse_cnt / cnt);
|
||||
|
||||
writel(IRB_MOD_COUNT(pulse_cnt, space_cnt),
|
||||
ir->reg_base + IRB_ADDR1);
|
||||
}
|
||||
|
||||
static void meson_irtx_setup(struct meson_irtx *ir, unsigned int clk_nr)
|
||||
{
|
||||
/*
|
||||
* Disable the TX, set modulator clock tick and set initialize
|
||||
* output to be high. Set up carrier frequency and duty cycle. Then
|
||||
* unset initialize output. Enable FIFO interrupt, set FIFO interrupt
|
||||
* threshold. Finally, enable the transmitter back.
|
||||
*/
|
||||
writel(~IRB_ENABLE & (IRB_MOD_CLK(clk_nr) | IRB_INIT_HIGH),
|
||||
ir->reg_base + IRB_ADDR0);
|
||||
meson_irtx_set_mod(ir);
|
||||
writel(readl(ir->reg_base + IRB_ADDR0) & ~IRB_INIT_HIGH,
|
||||
ir->reg_base + IRB_ADDR0);
|
||||
writel(IRB_FIFO_IRQ_ENABLE | MIRTX_FIFO_THD,
|
||||
ir->reg_base + IRB_ADDR3);
|
||||
writel(readl(ir->reg_base + IRB_ADDR0) | IRB_ENABLE,
|
||||
ir->reg_base + IRB_ADDR0);
|
||||
}
|
||||
|
||||
static u32 meson_irtx_prepare_pulse(struct meson_irtx *ir, unsigned int time)
|
||||
{
|
||||
unsigned int delay;
|
||||
unsigned int tb = IRB_TB_MOD_CLK;
|
||||
unsigned int tb_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, ir->carrier);
|
||||
|
||||
delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;
|
||||
|
||||
return ((IRB_WRITE_FIFO | IRB_MOD_ENABLE) | tb | delay);
|
||||
}
|
||||
|
||||
static u32 meson_irtx_prepare_space(struct meson_irtx *ir, unsigned int time)
|
||||
{
|
||||
unsigned int delay;
|
||||
unsigned int tb = IRB_TB_100US;
|
||||
unsigned int tb_us = 100;
|
||||
|
||||
if (time <= IRB_MAX_DELAY) {
|
||||
tb = IRB_TB_1US;
|
||||
tb_us = 1;
|
||||
} else if (time <= 10 * IRB_MAX_DELAY) {
|
||||
tb = IRB_TB_10US;
|
||||
tb_us = 10;
|
||||
} else if (time <= 100 * IRB_MAX_DELAY) {
|
||||
tb = IRB_TB_100US;
|
||||
tb_us = 100;
|
||||
}
|
||||
|
||||
delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;
|
||||
|
||||
return ((IRB_WRITE_FIFO & ~IRB_MOD_ENABLE) | tb | delay);
|
||||
}
|
||||
|
||||
static void meson_irtx_send_buffer(struct meson_irtx *ir)
|
||||
{
|
||||
unsigned int nr = 0;
|
||||
unsigned int max_fifo_level = IRB_FIFO_LEN - MIRTX_FIFO_THD;
|
||||
|
||||
while (ir->buf_head < ir->buf_len && nr < max_fifo_level) {
|
||||
writel(ir->buf[ir->buf_head], ir->reg_base + IRB_ADDR2);
|
||||
|
||||
ir->buf_head++;
|
||||
nr++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool meson_irtx_check_buf(struct meson_irtx *ir,
|
||||
unsigned int *buf, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
unsigned int max_tb_us;
|
||||
/*
|
||||
* Max space timebase is 100 us.
|
||||
* Pulse timebase equals to carrier period.
|
||||
*/
|
||||
if (i % 2 == 0)
|
||||
max_tb_us = USEC_PER_SEC / ir->carrier;
|
||||
else
|
||||
max_tb_us = 100;
|
||||
|
||||
if (buf[i] >= max_tb_us * IRB_MAX_DELAY)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void meson_irtx_fill_buf(struct meson_irtx *ir, u32 *dst_buf,
|
||||
unsigned int *src_buf, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i % 2 == 0)
|
||||
dst_buf[i] = meson_irtx_prepare_pulse(ir, src_buf[i]);
|
||||
else
|
||||
dst_buf[i] = meson_irtx_prepare_space(ir, src_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t meson_irtx_irqhandler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct meson_irtx *ir = data;
|
||||
|
||||
writel(readl(ir->reg_base + IRB_ADDR3) & ~IRB_FIFO_THD_PENDING,
|
||||
ir->reg_base + IRB_ADDR3);
|
||||
|
||||
if (completion_done(&ir->completion))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
spin_lock_irqsave(&ir->lock, flags);
|
||||
if (ir->buf_head < ir->buf_len)
|
||||
meson_irtx_send_buffer(ir);
|
||||
else
|
||||
complete(&ir->completion);
|
||||
spin_unlock_irqrestore(&ir->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int meson_irtx_set_carrier(struct rc_dev *rc, u32 carrier)
|
||||
{
|
||||
struct meson_irtx *ir = rc->priv;
|
||||
|
||||
if (carrier == 0)
|
||||
return -EINVAL;
|
||||
|
||||
ir->carrier = carrier;
|
||||
meson_irtx_set_mod(ir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_irtx_set_duty_cycle(struct rc_dev *rc, u32 duty_cycle)
|
||||
{
|
||||
struct meson_irtx *ir = rc->priv;
|
||||
|
||||
ir->duty_cycle = duty_cycle;
|
||||
meson_irtx_set_mod(ir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_irtx_update_buf(struct meson_irtx *ir, u32 *buf,
|
||||
unsigned int len, unsigned int head)
|
||||
{
|
||||
ir->buf = buf;
|
||||
ir->buf_len = len;
|
||||
ir->buf_head = head;
|
||||
}
|
||||
|
||||
static int meson_irtx_transmit(struct rc_dev *rc, unsigned int *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct meson_irtx *ir = rc->priv;
|
||||
u32 *tx_buf;
|
||||
int ret = len;
|
||||
|
||||
if (!meson_irtx_check_buf(ir, buf, len))
|
||||
return -EINVAL;
|
||||
|
||||
tx_buf = kmalloc_array(len, sizeof(u32), GFP_KERNEL);
|
||||
if (!tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
meson_irtx_fill_buf(ir, tx_buf, buf, len);
|
||||
dev_dbg(ir->dev, "TX buffer filled, length = %u\n", len);
|
||||
|
||||
spin_lock_irqsave(&ir->lock, flags);
|
||||
meson_irtx_update_buf(ir, tx_buf, len, 0);
|
||||
reinit_completion(&ir->completion);
|
||||
meson_irtx_send_buffer(ir);
|
||||
spin_unlock_irqrestore(&ir->lock, flags);
|
||||
|
||||
if (!wait_for_completion_timeout(&ir->completion,
|
||||
usecs_to_jiffies(IR_MAX_DURATION)))
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
spin_lock_irqsave(&ir->lock, flags);
|
||||
kfree(ir->buf);
|
||||
meson_irtx_update_buf(ir, NULL, 0, 0);
|
||||
spin_unlock_irqrestore(&ir->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int meson_irtx_mod_clock_probe(struct meson_irtx *ir,
|
||||
unsigned int *clk_nr)
|
||||
{
|
||||
struct device_node *np = ir->dev->of_node;
|
||||
struct clk *clock;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
clock = devm_clk_get(ir->dev, "xtal");
|
||||
if (IS_ERR(clock) || clk_prepare_enable(clock))
|
||||
return -ENODEV;
|
||||
|
||||
*clk_nr = IRB_MOD_XTAL3_CLK;
|
||||
ir->clk_rate = clk_get_rate(clock) / 3;
|
||||
|
||||
if (ir->clk_rate < IRB_MOD_1US_CLK_RATE) {
|
||||
*clk_nr = IRB_MOD_1US_CLK;
|
||||
ir->clk_rate = IRB_MOD_1US_CLK_RATE;
|
||||
}
|
||||
|
||||
dev_info(ir->dev, "F_clk = %luHz\n", ir->clk_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init meson_irtx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct meson_irtx *ir;
|
||||
struct rc_dev *rc;
|
||||
int irq;
|
||||
unsigned int clk_nr;
|
||||
int ret;
|
||||
|
||||
ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL);
|
||||
if (!ir)
|
||||
return -ENOMEM;
|
||||
|
||||
ir->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ir->reg_base))
|
||||
return PTR_ERR(ir->reg_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no irq resource found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ir->dev = dev;
|
||||
ir->carrier = MIRTX_DEFAULT_CARRIER;
|
||||
ir->duty_cycle = MIRTX_DEFAULT_DUTY_CYCLE;
|
||||
init_completion(&ir->completion);
|
||||
spin_lock_init(&ir->lock);
|
||||
|
||||
ret = meson_irtx_mod_clock_probe(ir, &clk_nr);
|
||||
if (ret) {
|
||||
dev_err(dev, "modulator clock setup failed\n");
|
||||
return ret;
|
||||
}
|
||||
meson_irtx_setup(ir, clk_nr);
|
||||
|
||||
ret = devm_request_irq(dev, irq,
|
||||
meson_irtx_irqhandler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
DRIVER_NAME, ir);
|
||||
if (ret) {
|
||||
dev_err(dev, "irq request failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX);
|
||||
if (!rc)
|
||||
return -ENOMEM;
|
||||
|
||||
rc->driver_name = DRIVER_NAME;
|
||||
rc->device_name = DEVICE_NAME;
|
||||
rc->priv = ir;
|
||||
|
||||
rc->tx_ir = meson_irtx_transmit;
|
||||
rc->s_tx_carrier = meson_irtx_set_carrier;
|
||||
rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle;
|
||||
|
||||
ret = rc_register_device(rc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "rc_dev registration failed\n");
|
||||
rc_free_device(rc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_irtx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rc_dev *rc = platform_get_drvdata(pdev);
|
||||
|
||||
rc_unregister_device(rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id meson_irtx_dt_match[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson-g12a-ir-tx",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_irtx_dt_match);
|
||||
|
||||
static struct platform_driver meson_irtx_pd = {
|
||||
.remove = meson_irtx_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = meson_irtx_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(meson_irtx_pd, meson_irtx_probe);
|
||||
|
||||
MODULE_DESCRIPTION("Meson IR TX driver");
|
||||
MODULE_AUTHOR("Viktor Prutyanov <viktor.prutyanov@phystech.edu>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -15,12 +15,9 @@
|
|||
#include <linux/slab.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#define DRIVER_NAME "rc-loopback"
|
||||
#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
|
||||
#define RXMASK_REGULAR 0x1
|
||||
#define RXMASK_LEARNING 0x2
|
||||
|
||||
static bool debug;
|
||||
#define DRIVER_NAME "rc-loopback"
|
||||
#define RXMASK_NARROWBAND 0x1
|
||||
#define RXMASK_WIDEBAND 0x2
|
||||
|
||||
struct loopback_dev {
|
||||
struct rc_dev *dev;
|
||||
|
@ -28,7 +25,7 @@ struct loopback_dev {
|
|||
u32 txcarrier;
|
||||
u32 txduty;
|
||||
bool idle;
|
||||
bool learning;
|
||||
bool wideband;
|
||||
bool carrierreport;
|
||||
u32 rxcarriermin;
|
||||
u32 rxcarriermax;
|
||||
|
@ -40,12 +37,12 @@ static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
|
|||
{
|
||||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
|
||||
dprintk("invalid tx mask: %u\n", mask);
|
||||
return -EINVAL;
|
||||
if ((mask & (RXMASK_NARROWBAND | RXMASK_WIDEBAND)) != mask) {
|
||||
dev_dbg(&dev->dev, "invalid tx mask: %u\n", mask);
|
||||
return 2;
|
||||
}
|
||||
|
||||
dprintk("setting tx mask: %u\n", mask);
|
||||
dev_dbg(&dev->dev, "setting tx mask: %u\n", mask);
|
||||
lodev->txmask = mask;
|
||||
return 0;
|
||||
}
|
||||
|
@ -54,7 +51,7 @@ static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
|
|||
{
|
||||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
dprintk("setting tx carrier: %u\n", carrier);
|
||||
dev_dbg(&dev->dev, "setting tx carrier: %u\n", carrier);
|
||||
lodev->txcarrier = carrier;
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,11 +61,11 @@ static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
|
|||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if (duty_cycle < 1 || duty_cycle > 99) {
|
||||
dprintk("invalid duty cycle: %u\n", duty_cycle);
|
||||
dev_dbg(&dev->dev, "invalid duty cycle: %u\n", duty_cycle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dprintk("setting duty cycle: %u\n", duty_cycle);
|
||||
dev_dbg(&dev->dev, "setting duty cycle: %u\n", duty_cycle);
|
||||
lodev->txduty = duty_cycle;
|
||||
return 0;
|
||||
}
|
||||
|
@ -78,11 +75,11 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
|
|||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if (min < 1 || min > max) {
|
||||
dprintk("invalid rx carrier range %u to %u\n", min, max);
|
||||
dev_dbg(&dev->dev, "invalid rx carrier range %u to %u\n", min, max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dprintk("setting rx carrier range %u to %u\n", min, max);
|
||||
dev_dbg(&dev->dev, "setting rx carrier range %u to %u\n", min, max);
|
||||
lodev->rxcarriermin = min;
|
||||
lodev->rxcarriermax = max;
|
||||
return 0;
|
||||
|
@ -97,25 +94,33 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
|
|||
|
||||
if (lodev->txcarrier < lodev->rxcarriermin ||
|
||||
lodev->txcarrier > lodev->rxcarriermax) {
|
||||
dprintk("ignoring tx, carrier out of range\n");
|
||||
dev_dbg(&dev->dev, "ignoring tx, carrier out of range\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lodev->learning)
|
||||
rxmask = RXMASK_LEARNING;
|
||||
if (lodev->wideband)
|
||||
rxmask = RXMASK_WIDEBAND;
|
||||
else
|
||||
rxmask = RXMASK_REGULAR;
|
||||
rxmask = RXMASK_NARROWBAND;
|
||||
|
||||
if (!(rxmask & lodev->txmask)) {
|
||||
dprintk("ignoring tx, rx mask mismatch\n");
|
||||
dev_dbg(&dev->dev, "ignoring tx, rx mask mismatch\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
rawir.pulse = i % 2 ? false : true;
|
||||
rawir.duration = txbuf[i];
|
||||
if (rawir.duration)
|
||||
ir_raw_event_store_with_filter(dev, &rawir);
|
||||
|
||||
ir_raw_event_store_with_filter(dev, &rawir);
|
||||
}
|
||||
|
||||
if (lodev->carrierreport) {
|
||||
rawir.pulse = false;
|
||||
rawir.carrier_report = true;
|
||||
rawir.carrier = lodev->txcarrier;
|
||||
|
||||
ir_raw_event_store(dev, &rawir);
|
||||
}
|
||||
|
||||
/* Fake a silence long enough to cause us to go idle */
|
||||
|
@ -134,18 +139,18 @@ static void loop_set_idle(struct rc_dev *dev, bool enable)
|
|||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if (lodev->idle != enable) {
|
||||
dprintk("%sing idle mode\n", enable ? "enter" : "exit");
|
||||
dev_dbg(&dev->dev, "%sing idle mode\n", enable ? "enter" : "exit");
|
||||
lodev->idle = enable;
|
||||
}
|
||||
}
|
||||
|
||||
static int loop_set_learning_mode(struct rc_dev *dev, int enable)
|
||||
static int loop_set_wideband_receiver(struct rc_dev *dev, int enable)
|
||||
{
|
||||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if (lodev->learning != enable) {
|
||||
dprintk("%sing learning mode\n", enable ? "enter" : "exit");
|
||||
lodev->learning = !!enable;
|
||||
if (lodev->wideband != enable) {
|
||||
dev_dbg(&dev->dev, "using %sband receiver\n", enable ? "wide" : "narrow");
|
||||
lodev->wideband = !!enable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -156,7 +161,7 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
|
|||
struct loopback_dev *lodev = dev->priv;
|
||||
|
||||
if (lodev->carrierreport != enable) {
|
||||
dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
|
||||
dev_dbg(&dev->dev, "%sabling carrier reports\n", enable ? "en" : "dis");
|
||||
lodev->carrierreport = !!enable;
|
||||
}
|
||||
|
||||
|
@ -204,10 +209,8 @@ static int __init loop_init(void)
|
|||
int ret;
|
||||
|
||||
rc = rc_allocate_device(RC_DRIVER_IR_RAW);
|
||||
if (!rc) {
|
||||
printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
|
||||
if (!rc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc->device_name = "rc-core loopback device";
|
||||
rc->input_phys = "rc-core/virtual";
|
||||
|
@ -219,9 +222,9 @@ static int __init loop_init(void)
|
|||
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
|
||||
rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER;
|
||||
rc->encode_wakeup = true;
|
||||
rc->timeout = MS_TO_US(100); /* 100 ms */
|
||||
rc->timeout = IR_DEFAULT_TIMEOUT;
|
||||
rc->min_timeout = 1;
|
||||
rc->max_timeout = UINT_MAX;
|
||||
rc->max_timeout = IR_MAX_TIMEOUT;
|
||||
rc->rx_resolution = 1;
|
||||
rc->tx_resolution = 1;
|
||||
rc->s_tx_mask = loop_set_tx_mask;
|
||||
|
@ -230,22 +233,22 @@ static int __init loop_init(void)
|
|||
rc->s_rx_carrier_range = loop_set_rx_carrier_range;
|
||||
rc->tx_ir = loop_tx_ir;
|
||||
rc->s_idle = loop_set_idle;
|
||||
rc->s_learning_mode = loop_set_learning_mode;
|
||||
rc->s_wideband_receiver = loop_set_wideband_receiver;
|
||||
rc->s_carrier_report = loop_set_carrier_report;
|
||||
rc->s_wakeup_filter = loop_set_wakeup_filter;
|
||||
|
||||
loopdev.txmask = RXMASK_REGULAR;
|
||||
loopdev.txmask = RXMASK_NARROWBAND;
|
||||
loopdev.txcarrier = 36000;
|
||||
loopdev.txduty = 50;
|
||||
loopdev.rxcarriermin = 1;
|
||||
loopdev.rxcarriermax = ~0;
|
||||
loopdev.idle = true;
|
||||
loopdev.learning = false;
|
||||
loopdev.wideband = false;
|
||||
loopdev.carrierreport = false;
|
||||
|
||||
ret = rc_register_device(rc);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
|
||||
dev_err(&rc->dev, "rc_dev registration failed\n");
|
||||
rc_free_device(rc);
|
||||
return ret;
|
||||
}
|
||||
|
@ -262,9 +265,6 @@ static void __exit loop_exit(void)
|
|||
module_init(loop_init);
|
||||
module_exit(loop_exit);
|
||||
|
||||
module_param(debug, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Enable debug messages");
|
||||
|
||||
MODULE_DESCRIPTION("Loopback device for rc-core debugging");
|
||||
MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1940,7 +1940,7 @@ int rc_register_device(struct rc_dev *dev)
|
|||
kfree(path);
|
||||
|
||||
/*
|
||||
* once the the input device is registered in rc_setup_rx_device,
|
||||
* once the input device is registered in rc_setup_rx_device,
|
||||
* userspace can open the input device and rc_open() will be called
|
||||
* as a result. This results in driver code being allowed to submit
|
||||
* keycodes with rc_keydown, so lirc must be registered first.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* based heavily on the work of Stephen Cox, with additional
|
||||
* help from RedRat Ltd.
|
||||
*
|
||||
* This driver began life based an an old version of the first-generation
|
||||
* This driver began life based on an old version of the first-generation
|
||||
* lirc_mceusb driver from the lirc 0.7.2 distribution. It was then
|
||||
* significantly rewritten by Stephen Cox with the aid of RedRat Ltd's
|
||||
* Chris Dodge.
|
||||
|
|
|
@ -265,8 +265,6 @@ static void streamzap_callback(struct urb *urb)
|
|||
|
||||
ir_raw_event_handle(sz->rdev);
|
||||
usb_submit_urb(urb, GFP_ATOMIC);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
|
||||
|
|
|
@ -524,13 +524,13 @@ cxd2880_spi_probe(struct spi_device *spi)
|
|||
if (IS_ERR(dvb_spi->vcc_supply)) {
|
||||
if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto fail_adapter;
|
||||
goto fail_regulator;
|
||||
}
|
||||
dvb_spi->vcc_supply = NULL;
|
||||
} else {
|
||||
ret = regulator_enable(dvb_spi->vcc_supply);
|
||||
if (ret)
|
||||
goto fail_adapter;
|
||||
goto fail_regulator;
|
||||
}
|
||||
|
||||
dvb_spi->spi = spi;
|
||||
|
@ -618,6 +618,9 @@ cxd2880_spi_probe(struct spi_device *spi)
|
|||
fail_attach:
|
||||
dvb_unregister_adapter(&dvb_spi->adapter);
|
||||
fail_adapter:
|
||||
if (!dvb_spi->vcc_supply)
|
||||
regulator_disable(dvb_spi->vcc_supply);
|
||||
fail_regulator:
|
||||
kfree(dvb_spi);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -282,5 +282,5 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
|
|||
snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d",
|
||||
dev->inst, is_source ? "out" : "cap", idx);
|
||||
return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
|
||||
name, caps, 1);
|
||||
name, caps, CEC_MAX_LOG_ADDRS);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ config DVB_USB_AF9035
|
|||
tristate "Afatech AF9035 DVB-T USB2.0 support"
|
||||
depends on DVB_USB_V2
|
||||
select DVB_AF9033
|
||||
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
|
|
@ -210,6 +210,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type,
|
|||
/* register I2C device */
|
||||
client = i2c_new_client_device(adapter, &board_info);
|
||||
if (!i2c_client_has_driver(client)) {
|
||||
dev_err(&intf->dev, "failed to bind i2c device to %s driver\n", type);
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -541,7 +541,9 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
|
|||
si2168_config.i2c_adapter = &i2c_adapter;
|
||||
si2168_config.fe = &adap->fe[0];
|
||||
si2168_config.ts_mode = SI2168_TS_PARALLEL;
|
||||
if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2)
|
||||
if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2 ||
|
||||
le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2_LITE ||
|
||||
le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A)
|
||||
si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL;
|
||||
si2168_config.ts_clock_inv = 1;
|
||||
|
||||
|
@ -577,15 +579,24 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
|
|||
|
||||
static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
|
||||
{
|
||||
dvbsky_gpio_ctrl(d, 0x04, 1);
|
||||
msleep(20);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 0);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 1);
|
||||
msleep(100);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 1);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 0);
|
||||
msleep(50);
|
||||
|
||||
if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) {
|
||||
dvbsky_gpio_ctrl(d, 0x87, 0);
|
||||
msleep(20);
|
||||
dvbsky_gpio_ctrl(d, 0x86, 1);
|
||||
dvbsky_gpio_ctrl(d, 0x80, 0);
|
||||
msleep(100);
|
||||
dvbsky_gpio_ctrl(d, 0x80, 1);
|
||||
msleep(50);
|
||||
} else {
|
||||
dvbsky_gpio_ctrl(d, 0x04, 1);
|
||||
msleep(20);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 0);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 1);
|
||||
msleep(100);
|
||||
dvbsky_gpio_ctrl(d, 0x83, 1);
|
||||
dvbsky_gpio_ctrl(d, 0xc0, 0);
|
||||
msleep(50);
|
||||
}
|
||||
return WARM;
|
||||
}
|
||||
|
||||
|
@ -789,6 +800,12 @@ static const struct usb_device_id dvbsky_id_table[] = {
|
|||
{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2,
|
||||
&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2",
|
||||
RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
|
||||
{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2_LITE,
|
||||
&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2 Lite",
|
||||
NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230A,
|
||||
&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230A",
|
||||
NULL) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
|
||||
|
|
|
@ -17,7 +17,8 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
|
|||
|
||||
if (d->props.i2c_algo == NULL) {
|
||||
err("no i2c algorithm specified");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
|
||||
|
@ -27,11 +28,15 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
|
|||
|
||||
i2c_set_adapdata(&d->i2c_adap, d);
|
||||
|
||||
if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
|
||||
ret = i2c_add_adapter(&d->i2c_adap);
|
||||
if (ret < 0) {
|
||||
err("could not add i2c adapter");
|
||||
goto err;
|
||||
}
|
||||
|
||||
d->state |= DVB_USB_STATE_I2C;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue