mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
[GIT PULL for v7.3] media updates
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmqFXqYACgkQCF8+vY7k 4RWNtw//T8GAlfl1BDlqxcWQHPFLkGqogsZQUx8aITayUBXpOzWHK4neGM7QF2Za 9kmBi3OzWgW3hIfbW4/vQCBSdDmTLSjoYHjYsc2Y3Cr0RvxIoEFw0GILYzygE3gp y9sUFHs2S43Xh1n3LuTcu0woL8YcY/3SaMrvEA6uoSGmOETiIUIuNkLpUAOEWhrl hkpRHt160yFiADSr8Ve9435xnkf5GvC0rmf/jF/KSUuNXrQuEx+5LIWzmadQRhph 2o+LuOJClKenglguU+yMA/DNEJuxxT1LOUgEiw05U2I03N8DqpiCO8Mpp2/l0iXH fgYFpObz6LdkusUSePamR2XaA3+ViNM48ddg1xmo+1gYQ/ggipsVVWifZpGFs2hq lbHEPV2Va/hlVj5EZJh4E6PHzH3UkGii2zgiHw0W3XWtTXS/qVlRjQwlo4aZTKok KPlOCNY69XADqOCmSB+kEmuCULfqoiJChk0qeRJX+kETc7gT+Qx4Ej0WT9LdF+NV 7+gxMOgUJFuTr1HkhO5ZXWezikBsJUvLUFud8mV+4iAJldby23I4UEXUEPK7od+W 8RXyWvf9/0owE2E3dOqkoM2sz2WW17nWZe8bPV+NTX39qw5WBOpaPpZGxVzOWinS KUTHJkp/O/1ymWtMz4+B+8QTO7n6KUnVDdL4qkO8cOrJGZizxoU= =8fcn -----END PGP SIGNATURE----- Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media updates from Mauro Carvalho Chehab: - v4l2-core: added ISP statistics support and per-block validation - v4l2-core: Allow unknown HDR10 white point and luminance - New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor - New codec: Milos: VPU v2.0 codec support - isp driver: gained support for Dreamchip RPPX1 ISP framework - vsp1 driver: gained support for RZ/T2H and RZ/N2H - Novalake driver: gained CVS support for new NVL hardware - dvb-core: fix feed leak on failed DMX_ADD_PID - several driver fixes, cleanups and minor improvements * tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits) media: ipu-bridge: check all DMI entries when overriding sensor rotation media: v4l2-async: avoid deleting unlinked ASC entry on link error media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement media: intel/ipu6: fix async notifier cleanup leak on parse error media: staging/ipu7: fix async notifier UAF on probe error path media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem() media: rcar-isp: Fix VSPX reference leaks media: rcar-isp: Release ISPCORE resources media: i2c: imx415: Release runtime PM reference on VBLANK error media: i2c: imx415: Return test pattern write errors media: renesas: vsp1: Declare index variables in for loop statement media: renesas: vsp1: Make reset control optional to support platforms without a reset line media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs media: nxp: imx8-isi: Add additional 32-bit RGB format support media: nxp: imx8-isi: Add 16-bit raw Bayer format support media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks media: nxp: imx8-isi: Correct color map between V4L2 and ISI ...
This commit is contained in:
commit
f4cdf7ca9a
7
CREDITS
7
CREDITS
|
|
@ -640,6 +640,10 @@ S: 25-29 St Giles
|
|||
S: Oxford
|
||||
S: United Kingdom
|
||||
|
||||
N: Bingbu Cao
|
||||
E: bingbu.cao@amd.com
|
||||
D: Ipu6, ipu7 and camera sensor drivers
|
||||
|
||||
N: Luiz Fernando N. Capitulino
|
||||
E: lcapitulino@mandriva.com.br
|
||||
E: lcapitulino@gmail.com
|
||||
|
|
@ -3334,6 +3338,9 @@ E: rpurdie@rpsys.net
|
|||
D: Backlight subsystem maintainer
|
||||
S: United Kingdom
|
||||
|
||||
N: Tian Shu Qiu
|
||||
D: Ipu6, ipu7 and camera sensor drivers
|
||||
|
||||
N: Daniel Quinlan
|
||||
E: quinlan@pathname.com
|
||||
W: https://www.pathname.com/~quinlan/
|
||||
|
|
|
|||
|
|
@ -446,3 +446,7 @@ EM28xx cards list
|
|||
- MyGica UTV3 Analog USB2.0 TV Box
|
||||
- em2860
|
||||
- eb1a:2860
|
||||
* - 113
|
||||
- StarTech SVID2USB232
|
||||
- em28281
|
||||
- eb1a:8286
|
||||
|
|
|
|||
|
|
@ -50,8 +50,15 @@ properties:
|
|||
|
||||
properties:
|
||||
data-lanes:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
|
||||
required:
|
||||
- link-frequencies
|
||||
|
|
|
|||
130
Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
Normal file
130
Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2026 Ideas on Board Oy
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/i2c/sony,imx678.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony IMX678 Sensor
|
||||
|
||||
maintainers:
|
||||
- Jai Luthra <jai.luthra@ideasonboard.com>
|
||||
|
||||
description:
|
||||
Sony IMX678 diagonal 8.86 mm (Type 1/1.8) CMOS active pixel type solid-state
|
||||
image sensor with a square pixel array and 8.40M (3856x2180) effective pixels.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/media/video-interface-devices.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- sony,imx678-aamr
|
||||
- sony,imx678-aaqr
|
||||
- const: sony,imx678
|
||||
description:
|
||||
The IMX678 sensor exists in a colour variant (IMX678-AAQR) and a mono
|
||||
variant (IMX678-AAMR). The variant-specific compatible describes the
|
||||
exact sensor variant, with the generic IMX678 compatible as a fallback.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
Input clock (INCK). Only the rates listed in the datasheet are supported:
|
||||
13.5, 18, 24, 27, 36, 37.125, 72, and 74.25 MHz.
|
||||
maxItems: 1
|
||||
|
||||
avdd-supply:
|
||||
description: Analog power supply (3.3V)
|
||||
|
||||
ovdd-supply:
|
||||
description: Interface power supply (1.8V)
|
||||
|
||||
dvdd-supply:
|
||||
description: Digital power supply (1.1V)
|
||||
|
||||
reset-gpios:
|
||||
description: Sensor RESETN (XCLR) GPIO
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
- items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
- const: 5
|
||||
- const: 6
|
||||
- const: 7
|
||||
- const: 8
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
- link-frequencies
|
||||
|
||||
required:
|
||||
- endpoint
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- avdd-supply
|
||||
- ovdd-supply
|
||||
- dvdd-supply
|
||||
- port
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
camera@1a {
|
||||
compatible = "sony,imx678-aaqr", "sony,imx678";
|
||||
reg = <0x1a>;
|
||||
clocks = <&imx678_clk>;
|
||||
|
||||
avdd-supply = <&camera_avdd_3v3>;
|
||||
ovdd-supply = <&camera_ovdd_1v8>;
|
||||
dvdd-supply = <&camera_dvdd_1v1>;
|
||||
|
||||
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
imx678: endpoint {
|
||||
remote-endpoint = <&cam>;
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <720000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -27,9 +27,10 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- st,vd55g1
|
||||
- st,vd55g4
|
||||
- st,vd65g4
|
||||
description:
|
||||
VD55G1 is the monochrome variant, while VD65G4 is the color one.
|
||||
VD55G1 and VD55G4 are monochrome variants, while VD65G4 is a color one.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -117,7 +117,9 @@ allOf:
|
|||
compatible:
|
||||
not:
|
||||
contains:
|
||||
const: fsl,imx91-isi
|
||||
enum:
|
||||
- fsl,imx8ulp-isi
|
||||
- fsl,imx91-isi
|
||||
then:
|
||||
required:
|
||||
- fsl,blk-ctrl
|
||||
|
|
|
|||
166
Documentation/devicetree/bindings/media/qcom,milos-iris.yaml
Normal file
166
Documentation/devicetree/bindings/media/qcom,milos-iris.yaml
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/qcom,milos-iris.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Milos SoC Iris video encoder and decoder
|
||||
|
||||
maintainers:
|
||||
- Alexander Koskovich <akoskovich@pm.me>
|
||||
|
||||
description:
|
||||
The Iris video processing unit on Qualcomm Milos SoC is a video encode and
|
||||
decode accelerator.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,milos-iris
|
||||
|
||||
clocks:
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface
|
||||
- const: core
|
||||
- const: vcodec0_core
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
interconnects:
|
||||
maxItems: 2
|
||||
|
||||
interconnect-names:
|
||||
items:
|
||||
- const: cpu-cfg
|
||||
- const: video-mem
|
||||
|
||||
iommus:
|
||||
maxItems: 2
|
||||
|
||||
operating-points-v2: true
|
||||
opp-table:
|
||||
type: object
|
||||
|
||||
power-domains:
|
||||
maxItems: 4
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: venus
|
||||
- const: vcodec0
|
||||
- const: cx
|
||||
- const: mx
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: core
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- dma-coherent
|
||||
- interconnects
|
||||
- interconnect-names
|
||||
- iommus
|
||||
- power-domain-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,venus-common.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/clock/qcom,milos-gcc.h>
|
||||
#include <dt-bindings/clock/qcom,milos-videocc.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interconnect/qcom,icc.h>
|
||||
#include <dt-bindings/interconnect/qcom,milos-rpmh.h>
|
||||
#include <dt-bindings/power/qcom-rpmpd.h>
|
||||
#include <dt-bindings/power/qcom,rpmhpd.h>
|
||||
|
||||
video-codec@aa00000 {
|
||||
compatible = "qcom,milos-iris";
|
||||
reg = <0x0aa00000 0xf0000>;
|
||||
|
||||
clocks = <&gcc GCC_VIDEO_AXI0_CLK>,
|
||||
<&videocc VIDEO_CC_MVS0C_CLK>,
|
||||
<&videocc VIDEO_CC_MVS0_CLK>;
|
||||
clock-names = "iface",
|
||||
"core",
|
||||
"vcodec0_core";
|
||||
|
||||
dma-coherent;
|
||||
iommus = <&apps_smmu 0x1960 0>,
|
||||
<&apps_smmu 0x1967 0>;
|
||||
|
||||
interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
|
||||
&cnoc_cfg SLAVE_VENUS_CFG QCOM_ICC_TAG_ACTIVE_ONLY>,
|
||||
<&mmss_noc MASTER_VIDEO QCOM_ICC_TAG_ALWAYS
|
||||
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
|
||||
interconnect-names = "cpu-cfg",
|
||||
"video-mem";
|
||||
|
||||
interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
operating-points-v2 = <&iris_opp_table>;
|
||||
|
||||
memory-region = <&video_mem>;
|
||||
|
||||
power-domains = <&videocc VIDEO_CC_MVS0C_GDSC>,
|
||||
<&videocc VIDEO_CC_MVS0_GDSC>,
|
||||
<&rpmhpd RPMHPD_CX>,
|
||||
<&rpmhpd RPMHPD_MX>;
|
||||
power-domain-names = "venus",
|
||||
"vcodec0",
|
||||
"cx",
|
||||
"mx";
|
||||
|
||||
resets = <&gcc GCC_VIDEO_AXI0_CLK_ARES>,
|
||||
<&videocc VIDEO_CC_MVS0C_CLK_ARES>;
|
||||
reset-names = "bus",
|
||||
"core";
|
||||
|
||||
iris_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp-240000000 {
|
||||
opp-hz = /bits/ 64 <240000000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>,
|
||||
<&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-338000000 {
|
||||
opp-hz = /bits/ 64 <338000000>;
|
||||
required-opps = <&rpmhpd_opp_svs>,
|
||||
<&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-366000000 {
|
||||
opp-hz = /bits/ 64 <366000000>;
|
||||
required-opps = <&rpmhpd_opp_svs_l1>,
|
||||
<&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-444000000 {
|
||||
opp-hz = /bits/ 64 <444000000>;
|
||||
required-opps = <&rpmhpd_opp_nom>,
|
||||
<&rpmhpd_opp_svs_l1>;
|
||||
};
|
||||
|
||||
opp-552000000 {
|
||||
opp-hz = /bits/ 64 <552000000>;
|
||||
required-opps = <&rpmhpd_opp_turbo>,
|
||||
<&rpmhpd_opp_nom>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -14,7 +14,11 @@ description:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcm2290-camss
|
||||
oneOf:
|
||||
- items:
|
||||
- const: qcom,shikra-camss
|
||||
- const: qcom,qcm2290-camss
|
||||
- const: qcom,qcm2290-camss
|
||||
|
||||
reg:
|
||||
maxItems: 9
|
||||
|
|
@ -76,7 +80,14 @@ properties:
|
|||
- const: sf_mnoc
|
||||
|
||||
iommus:
|
||||
maxItems: 4
|
||||
oneOf:
|
||||
- items:
|
||||
- description: S1 HLOS VFE non-protected (VFE only)
|
||||
- items:
|
||||
- description: S1 HLOS VFE non-protected
|
||||
- description: S1 HLOS CDM non-protected
|
||||
- description: S1 HLOS OPE read non-protected
|
||||
- description: S1 HLOS OPE write non-protected
|
||||
|
||||
power-domains:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -122,10 +122,10 @@ properties:
|
|||
- rc-proteus-2309
|
||||
- rc-purpletv
|
||||
- rc-pv951
|
||||
- rc-rc5-tv
|
||||
- rc-rc6-mce
|
||||
- rc-real-audio-220-32-keys
|
||||
- rc-reddo
|
||||
- rc-siemens-gigaset-rc20
|
||||
- rc-snapstream-firefly
|
||||
- rc-streamzap
|
||||
- rc-su3000
|
||||
|
|
@ -147,11 +147,11 @@ properties:
|
|||
- rc-tt-1500
|
||||
- rc-twinhan-dtv-cab-ci
|
||||
- rc-twinhan1027
|
||||
- rc-vega-s9x
|
||||
- rc-videomate-k100
|
||||
- rc-videomate-s350
|
||||
- rc-videomate-tv-pvr
|
||||
- rc-videostrong-kii-pro
|
||||
- rc-vega-s9x
|
||||
- rc-wetek-hub
|
||||
- rc-wetek-play2
|
||||
- rc-winfast
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ properties:
|
|||
- renesas,r9a09g047-fcpvd # RZ/G3E
|
||||
- renesas,r9a09g056-fcpvd # RZ/V2N
|
||||
- renesas,r9a09g057-fcpvd # RZ/V2H(P)
|
||||
- renesas,r9a09g077-fcpvd # RZ/T2H
|
||||
- renesas,r9a09g087-fcpvd # RZ/N2H
|
||||
- const: renesas,fcpv # Generic FCP for VSP fallback
|
||||
|
||||
reg:
|
||||
|
|
@ -66,7 +68,6 @@ required:
|
|||
- reg
|
||||
- clocks
|
||||
- power-domains
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
@ -83,6 +84,8 @@ allOf:
|
|||
- renesas,r9a09g047-fcpvd
|
||||
- renesas,r9a09g056-fcpvd
|
||||
- renesas,r9a09g057-fcpvd
|
||||
- renesas,r9a09g077-fcpvd
|
||||
- renesas,r9a09g087-fcpvd
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
|
@ -94,6 +97,19 @@ allOf:
|
|||
clocks:
|
||||
maxItems: 1
|
||||
clock-names: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a09g077-fcpvd
|
||||
- renesas,r9a09g087-fcpvd
|
||||
then:
|
||||
properties:
|
||||
resets: false
|
||||
else:
|
||||
required:
|
||||
- resets
|
||||
|
||||
examples:
|
||||
# R8A7795 (R-Car H3) FCP for VSP-D1
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ properties:
|
|||
- renesas,r9a09g047-vsp2 # RZ/G3E
|
||||
- renesas,r9a09g056-vsp2 # RZ/V2N
|
||||
- renesas,r9a09g057-vsp2 # RZ/V2H(P)
|
||||
- renesas,r9a09g077-vsp2 # RZ/T2H
|
||||
- renesas,r9a09g087-vsp2 # RZ/N2H
|
||||
- const: renesas,r9a07g044-vsp2 # RZ/G2L fallback
|
||||
|
||||
reg:
|
||||
|
|
@ -67,7 +69,6 @@ required:
|
|||
- interrupts
|
||||
- clocks
|
||||
- power-domains
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
@ -101,6 +102,20 @@ allOf:
|
|||
maxItems: 1
|
||||
clock-names: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a09g077-vsp2
|
||||
- renesas,r9a09g087-vsp2
|
||||
then:
|
||||
properties:
|
||||
resets: false
|
||||
else:
|
||||
required:
|
||||
- resets
|
||||
|
||||
examples:
|
||||
# R8A7790 (R-Car H2) VSP1-S
|
||||
- |
|
||||
|
|
|
|||
93
Documentation/devicetree/bindings/media/ti,am437x-vpfe.yaml
Normal file
93
Documentation/devicetree/bindings/media/ti,am437x-vpfe.yaml
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/ti,am437x-vpfe.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments AM437x CAMERA Video Processing Front End (VPFE)
|
||||
|
||||
maintainers:
|
||||
- Benoit Parrot <bparrot@ti.com>
|
||||
- Bhargav Joshi <j.bhargav.u@gmail.com>
|
||||
|
||||
description:
|
||||
The Video Processing Front End (VPFE) is a key component for image capture
|
||||
applications. The capture module provides the system interface and the
|
||||
processing capability to connect RAW image-sensor modules and video decoders
|
||||
to the AM437x device.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,am437x-vpfe
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
A single parallel input port connecting to an external image sensor or
|
||||
video decoder. The VPFE supports only one input port per instance.
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
ti,am437x-vpfe-interface:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3, 4]
|
||||
description:
|
||||
Selects the VPFE input interface type can be one of following
|
||||
0 - Raw Bayer (VPFE_RAW_BAYER)
|
||||
1 - BT.656 8-bit (VPFE_BT656)
|
||||
2 - BT.656 10-bit (VPFE_BT656_10BIT)
|
||||
3 - YCbCr 8-bit sync (VPFE_YCBCR_SYNC_8)
|
||||
4 - YCbCr 16-bit sync (VPFE_YCBCR_SYNC_16)
|
||||
|
||||
bus-width:
|
||||
minimum: 8
|
||||
maximum: 16
|
||||
|
||||
required:
|
||||
- remote-endpoint
|
||||
- ti,am437x-vpfe-interface
|
||||
- bus-width
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
vpfe@48328000{
|
||||
compatible = "ti,am437x-vpfe";
|
||||
reg = <0x48328000 0x2000>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&vpfe_pins_default>;
|
||||
pinctrl-1 = <&vpfe_pins_sleep>;
|
||||
|
||||
port {
|
||||
vpfe0_ep: endpoint {
|
||||
remote-endpoint = <&ov2659_1>;
|
||||
ti,am437x-vpfe-interface = <0>;
|
||||
bus-width = <8>;
|
||||
hsync-active = <0>;
|
||||
vsync-active = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
Texas Instruments AM437x CAMERA (VPFE)
|
||||
--------------------------------------
|
||||
|
||||
The Video Processing Front End (VPFE) is a key component for image capture
|
||||
applications. The capture module provides the system interface and the
|
||||
processing capability to connect RAW image-sensor modules and video decoders
|
||||
to the AM437x device.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "ti,am437x-vpfe"
|
||||
- reg: physical base address and length of the registers set for the device;
|
||||
- interrupts: should contain IRQ line for the VPFE;
|
||||
- ti,am437x-vpfe-interface: can be one of the following,
|
||||
0 - Raw Bayer Interface.
|
||||
1 - 8 Bit BT656 Interface.
|
||||
2 - 10 Bit BT656 Interface.
|
||||
3 - YCbCr 8 Bit Interface.
|
||||
4 - YCbCr 16 Bit Interface.
|
||||
|
||||
VPFE supports a single port node with parallel bus. It should contain one
|
||||
'port' child node with child 'endpoint' node. Please refer to the bindings
|
||||
defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
Example:
|
||||
vpfe: vpfe@f0034000 {
|
||||
compatible = "ti,am437x-vpfe";
|
||||
reg = <0x48328000 0x2000>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&vpfe_pins_default>;
|
||||
pinctrl-1 = <&vpfe_pins_sleep>;
|
||||
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
vpfe0_ep: endpoint {
|
||||
remote-endpoint = <&ov2659_1>;
|
||||
ti,am437x-vpfe-interface = <0>;
|
||||
bus-width = <8>;
|
||||
hsync-active = <0>;
|
||||
vsync-active = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c1: i2c@4802a000 {
|
||||
|
||||
ov2659@30 {
|
||||
compatible = "ti,ov2659";
|
||||
reg = <0x30>;
|
||||
|
||||
port {
|
||||
ov2659_1: endpoint {
|
||||
remote-endpoint = <&vpfe0_ep>;
|
||||
bus-width = <8>;
|
||||
mclk-frequency = <12000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -432,6 +432,10 @@ The Media Driver Maintainers responsible for specific areas are:
|
|||
|
||||
- Qualcomm drivers
|
||||
|
||||
- Ricardo Ribalda <ribalda@chromium.org>
|
||||
|
||||
- Media-CI
|
||||
|
||||
Submit Checklist Addendum
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
are CEC devices that can only handle CDC messages.
|
||||
|
||||
All other messages are ignored.
|
||||
* .. _`CEC-LOG-ADDRS-FL-CONFIG-FAILED`:
|
||||
|
||||
- ``CEC_LOG_ADDRS_FL_CONFIG_FAILED``
|
||||
- 8
|
||||
- If this flag is set, then the CEC device failed to claim a free logical
|
||||
address and is in the unconfigured state. This can never happen if
|
||||
``CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK`` was set as well.
|
||||
|
||||
.. tabularcolumns:: |p{7.8cm}|p{1.0cm}|p{8.5cm}|
|
||||
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ Variables
|
|||
|
||||
- ..
|
||||
|
||||
- :rspan:`5` ``stuct play``
|
||||
- :rspan:`5` ``struct play``
|
||||
|
||||
- :rspan:`4` ``__s32 speed``
|
||||
|
||||
|
|
|
|||
|
|
@ -80,15 +80,25 @@ Colorimetry Control IDs
|
|||
- ``white_point_x``
|
||||
- Specifies the normalized x chromaticity coordinate of the white
|
||||
point of the mastering display in increments of 0.00002.
|
||||
When both ``white_point_x`` and ``white_point_y`` are zero,
|
||||
the white point chromaticity is unknown. If either coordinate is
|
||||
non-zero, both coordinates shall be within their valid ranges.
|
||||
* - __u16
|
||||
- ``white_point_y``
|
||||
- Specifies the normalized y chromaticity coordinate of the white
|
||||
point of the mastering display in increments of 0.00002.
|
||||
When both ``white_point_x`` and ``white_point_y`` are zero,
|
||||
the white point chromaticity is unknown. If either coordinate is
|
||||
non-zero, both coordinates shall be within their valid ranges.
|
||||
* - __u32
|
||||
- ``max_luminance``
|
||||
- Specifies the nominal maximum display luminance of the mastering
|
||||
display in units of 0.0001 cd/m\ :sup:`2`.
|
||||
A value of zero indicates that the nominal maximum display
|
||||
luminance is unknown.
|
||||
* - __u32
|
||||
- ``min_luminance``
|
||||
- specifies the nominal minimum display luminance of the mastering
|
||||
- Specifies the nominal minimum display luminance of the mastering
|
||||
display in units of 0.0001 cd/m\ :sup:`2`.
|
||||
A value of zero indicates that the nominal minimum display
|
||||
luminance is unknown.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ These formats are used for the :ref:`metadata` interface only.
|
|||
metafmt-pisp-be
|
||||
metafmt-pisp-fe
|
||||
metafmt-rkisp1
|
||||
metafmt-rppx1
|
||||
metafmt-uvc
|
||||
metafmt-uvc-msxu-1-5
|
||||
metafmt-vivid
|
||||
|
|
|
|||
99
Documentation/userspace-api/media/v4l/metafmt-rppx1.rst
Normal file
99
Documentation/userspace-api/media/v4l/metafmt-rppx1.rst
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _v4l2-meta-fmt-rppx1-params:
|
||||
.. _v4l2-meta-fmt-rppx1-stats:
|
||||
|
||||
*************************************************************************
|
||||
V4L2_META_FMT_RPPX1_PARAMS ('DR1P'), V4L2_META_FMT_RPPX1_STATS ('DR1S')
|
||||
*************************************************************************
|
||||
|
||||
Configuration Parameters
|
||||
========================
|
||||
|
||||
The configuration parameters are passed to the metadata output video node, using
|
||||
the :c:type:`v4l2_meta_format` interface. Rather than a single struct containing
|
||||
sub-structs for each configurable area of the ISP, parameters for the Dreamchip
|
||||
RPPX1 use the v4l2-isp parameters system, through which groups of parameters are
|
||||
defined as distinct structs or "blocks" which may be added to the data member of
|
||||
:c:type:`v4l2_isp_buffer`. Userspace is responsible for populating the data
|
||||
member with the blocks that need to be configured by the driver. Each
|
||||
block-specific struct embeds :c:type:`v4l2_isp_block_header` as its first member
|
||||
and userspace must populate the type member with a value from
|
||||
:c:type:`rppx1_params_block_type`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct v4l2_isp_params_buffer *params =
|
||||
(struct v4l2_isp_params_buffer *)buffer;
|
||||
|
||||
params->version = V4L2_ISP_PARAMS_VERSION_V1;
|
||||
params->data_size = 0;
|
||||
|
||||
void *data = (void *)params->data;
|
||||
|
||||
struct rppx1_ccor_params *ccor =
|
||||
(struct rppx1_ccor_params *)data;
|
||||
|
||||
ccor->header.type = RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST;
|
||||
ccor->header.flags |= V4L2_ISP_PARAMS_FL_BLOCK_ENABLE;
|
||||
ccor->header.size = sizeof(struct rppx1_ccor_params);
|
||||
|
||||
ccor->coeff[0][0] = 0x1000;
|
||||
ccor->coeff[0][1] = 0x0000;
|
||||
ccor->coeff[0][2] = 0x0000;
|
||||
ccor->coeff[1][0] = 0x0000;
|
||||
ccor->coeff[1][1] = 0x1000;
|
||||
ccor->coeff[1][2] = 0x0000;
|
||||
ccor->coeff[2][0] = 0x0000;
|
||||
ccor->coeff[2][1] = 0x0000;
|
||||
ccor->coeff[2][2] = 0x1000;
|
||||
|
||||
ccor->offset[0] = 0x200000;
|
||||
ccor->offset[1] = 0x200000;
|
||||
ccor->offset[2] = 0x200000;
|
||||
|
||||
data += sizeof(struct rppx1_ccor_params);
|
||||
params->data_size += sizeof(struct rppx1_ccor_params);
|
||||
|
||||
3A Statistics
|
||||
=============
|
||||
|
||||
The ISP device collects different statistics over an input bayer frame. Those
|
||||
statistics can be obtained by userspace from the metadata capture video node,
|
||||
using the :c:type:`v4l2_meta_format` interface. Rather than a single struct
|
||||
containing sub-structs for each statistics area of the ISP, statistics for the
|
||||
Dreamchip RPPX1 use the v4l2-isp statistics system, through which groups of
|
||||
statistics are defined as distinct structs or "blocks" which may be added to the
|
||||
data member of :c:type:`v4l2_isp_buffer`. Userspace is responsible for parsing
|
||||
the buffer and extracting the blocks of statistics. Each block-specific struct
|
||||
embeds :c:type:`v4l2_isp_block_header` as its first member and userspace must
|
||||
interpret the type member with a value from :c:type:`rppx1_stats_block_type`.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
const struct v4l2_isp_buffer *stats =
|
||||
(struct v4l2_isp_buffer *)buf;
|
||||
size_t block_offset = 0;
|
||||
|
||||
while (block_offset < stats->data_size) {
|
||||
const struct v4l2_isp_stats_block_header *block =
|
||||
(void*)(stats->data + block_offset);
|
||||
|
||||
block_offset += block->size;
|
||||
|
||||
switch (block->type) {
|
||||
case RPPX1_STATS_BLOCK_TYPE_HIST_POST:
|
||||
for (unsigned int i = 0; i < RPPX1_HIST_NUM_BINS; i++)
|
||||
printf("hist.hist_bins[%u] = 0x%08x\n",
|
||||
i, hist.hist_bins[%i]);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown block type 0x%04x", block->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Dreamchip RPPX1 uAPI data types
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/media/dreamchip/rppx1-config.h
|
||||
|
|
@ -18,22 +18,22 @@ single C structure that contains a header, followed by a binary buffer where
|
|||
userspace programs a variable number of ISP configuration data block, one for
|
||||
each supported ISP feature.
|
||||
|
||||
The :c:type:`v4l2_isp_params_buffer` structure defines the buffer header which
|
||||
is followed by a binary buffer of ISP configuration data. Userspace shall
|
||||
correctly populate the buffer header with the generic parameters format version
|
||||
and with the size (in bytes) of the binary data buffer where it will store the
|
||||
ISP blocks configuration.
|
||||
The :c:type:`v4l2_isp_buffer` structure defines the buffer header which is
|
||||
followed by a binary buffer of ISP configuration data. Userspace shall correctly
|
||||
populate the buffer header with the serialization format version and with the
|
||||
size (in bytes) of the binary data buffer where it will store the ISP blocks
|
||||
configuration.
|
||||
|
||||
Each *ISP configuration block* is preceded by an header implemented by the
|
||||
:c:type:`v4l2_isp_params_block_header` structure, followed by the configuration
|
||||
Each *ISP configuration block* is preceded by a header implemented by the
|
||||
:c:type:`v4l2_isp_block_header` structure, followed by the configuration
|
||||
parameters for that specific block, defined by the ISP driver specific data
|
||||
types.
|
||||
|
||||
Userspace applications are responsible for correctly populating each block's
|
||||
header fields (type, flags and size) and the block-specific parameters.
|
||||
|
||||
ISP block enabling, disabling and configuration
|
||||
-----------------------------------------------
|
||||
ISP parameters block enabling, disabling and configuration
|
||||
----------------------------------------------------------
|
||||
|
||||
When userspace wants to configure and enable an ISP block it shall fully
|
||||
populate the block configuration and set the V4L2_ISP_PARAMS_FL_BLOCK_ENABLE
|
||||
|
|
@ -59,7 +59,30 @@ definition without invalidating the existing ones.
|
|||
ISP statistics
|
||||
==============
|
||||
|
||||
Support for generic statistics format is not yet implemented in Video4Linux2.
|
||||
The generic ISP statistics format is identical to the generic ISP configuration
|
||||
parameters format. It is realized by defining a C structure that contains a
|
||||
header, followed by binary buffer where the ISP driver copies a variable number
|
||||
of ISP statistics blocks.
|
||||
|
||||
Extensible statistics buffers have :c:type:`v4l2_isp_buffer` header followed by
|
||||
a binary buffer of ISP statistics data. ISP drivers populate the buffer header
|
||||
with the serialization format version and with the size (in bytes) of the binary
|
||||
data buffer where ISP statistics data are serialized. Applications shall
|
||||
validate that the serialization format version matches the expected one and that
|
||||
the buffer size doesn't exceed the maximum size for a statistics buffer as
|
||||
declared by the driver's uAPI header.
|
||||
|
||||
Each *ISP statistics block* is preceded by a header implemented by the
|
||||
:c:type:`v4l2_isp_block_header` structure, followed by the statistics data for
|
||||
that specific block. The driver might optionally report platform-specific flags
|
||||
associated with each statistics block.
|
||||
|
||||
Applications inspect the statistics block type as reported in the header and
|
||||
validates the reported size matches the block's expected size before accessing
|
||||
the ISP statistics data.
|
||||
|
||||
Extension to the statistics format can be implemented by adding new blocks
|
||||
definition without invalidating the existing ones.
|
||||
|
||||
V4L2 ISP uAPI data types
|
||||
========================
|
||||
|
|
|
|||
|
|
@ -72,12 +72,6 @@ partial array, all elements have to be set or retrieved. The total size
|
|||
is calculated as ``elems`` * ``elem_size``. These values can be obtained
|
||||
by calling :ref:`VIDIOC_QUERY_EXT_CTRL <VIDIOC_QUERYCTRL>`.
|
||||
|
||||
To change the value of a set of controls applications initialize the
|
||||
``id``, ``size``, ``reserved2`` and ``value/value64/string/ptr`` fields
|
||||
of each struct :c:type:`v4l2_ext_control` and call
|
||||
the :ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` ioctl. The controls will only be set if *all*
|
||||
control values are valid.
|
||||
|
||||
To check if a set of controls have correct values applications
|
||||
initialize the ``id``, ``size``, ``reserved2`` and
|
||||
``value/value64/string/ptr`` fields of each struct
|
||||
|
|
@ -86,6 +80,15 @@ initialize the ``id``, ``size``, ``reserved2`` and
|
|||
values are automatically adjusted to a valid value or if an error is
|
||||
returned.
|
||||
|
||||
To change the value of a set of controls applications initialize the
|
||||
``id``, ``size``, ``reserved2`` and ``value/value64/string/ptr`` fields
|
||||
of each struct :c:type:`v4l2_ext_control` and call
|
||||
the :ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` ioctl.
|
||||
:ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` will implicitly call
|
||||
:ref:`VIDIOC_TRY_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` first and return an
|
||||
error if that fails. So the controls will only be set if *all*
|
||||
control values are valid.
|
||||
|
||||
When the ``id`` or ``which`` is invalid drivers return an ``EINVAL`` error
|
||||
code. When the value is out of bounds drivers can choose to take the
|
||||
closest valid value or return an ``ERANGE`` error code, whatever seems more
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ subdevice routing table. This may be smaller or larger than the value of
|
|||
drivers may adjust the requested routing table.
|
||||
|
||||
The kernel can return a ``num_routes`` value larger than ``len_routes`` from
|
||||
both ioctls. This indicates thare are more routes in the routing table than fits
|
||||
both ioctls. This indicates there are more routes in the routing table than fits
|
||||
the ``routes`` array. In this case, the ``routes`` array is filled by the kernel
|
||||
with the first ``len_routes`` entries of the subdevice routing table. This is
|
||||
not considered to be an error, and the ioctl call succeeds. If the applications
|
||||
|
|
|
|||
55
MAINTAINERS
55
MAINTAINERS
|
|
@ -3936,7 +3936,7 @@ F: Documentation/devicetree/bindings/leds/ams,as3668.yaml
|
|||
F: drivers/leds/leds-as3668.c
|
||||
|
||||
ASAHI KASEI AK7375 LENS VOICE COIL DRIVER
|
||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -7868,6 +7868,16 @@ F: drivers/block/drbd/
|
|||
F: include/linux/drbd*
|
||||
F: lib/lru_cache.c
|
||||
|
||||
DREAMCHIP RPPX1 ISP
|
||||
M: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
|
||||
M: Jai Luthra <jai.luthra+renesas@ideasonboard.com>
|
||||
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/userspace-api/media/v4l/metafmt-rppx1.rst
|
||||
F: drivers/media/platform/dreamchip/rppx1/
|
||||
F: include/uapi/linux/media/dreamchip/rppx1-config.h
|
||||
|
||||
DRIVER COMPONENT FRAMEWORK
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
F: drivers/base/component.c
|
||||
|
|
@ -13133,9 +13143,7 @@ F: drivers/iommu/intel/
|
|||
INTEL IPU3 CSI-2 CIO2 DRIVER
|
||||
M: Yong Zhi <yong.zhi@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
M: Bingbu Cao <bingbu.cao@intel.com>
|
||||
M: Dan Scally <dan.scally@ideasonboard.com>
|
||||
R: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -13144,8 +13152,6 @@ F: drivers/media/pci/intel/ipu3/
|
|||
|
||||
INTEL IPU3 CSI-2 IMGU DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
R: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/admin-guide/media/ipu3.rst
|
||||
|
|
@ -13155,8 +13161,6 @@ F: drivers/staging/media/ipu3/
|
|||
|
||||
INTEL IPU6 INPUT SYSTEM DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
M: Bingbu Cao <bingbu.cao@intel.com>
|
||||
R: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -13165,7 +13169,6 @@ F: drivers/media/pci/intel/ipu6/
|
|||
|
||||
INTEL IPU7 INPUT SYSTEM DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -13377,6 +13380,7 @@ INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
|
|||
M: Daniel Scally <dan.scally@ideasonboard.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
F: drivers/platform/x86/intel/int3472/
|
||||
F: include/linux/platform_data/x86/int3472.h
|
||||
|
||||
|
|
@ -13467,7 +13471,6 @@ F: drivers/net/wireless/intel/iwlwifi/
|
|||
|
||||
INTEL VISION SENSING CONTROLLER DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
R: Lixu Zhang <lixu.zhang@intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
|
|
@ -19501,7 +19504,9 @@ F: drivers/iio/adc/vf610_adc.c
|
|||
|
||||
NXP i.MX 8M ISI DRIVER
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
R: Frank Li <Frank.Li@nxp.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
L: imx@lists.linux.dev
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/fsl,imx8*-isi.yaml
|
||||
F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml
|
||||
|
|
@ -19934,7 +19939,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,os05b10.yaml
|
|||
F: drivers/media/i2c/os05b10.c
|
||||
|
||||
OMNIVISION OV01A10 SENSOR DRIVER
|
||||
M: Bingbu Cao <bingbu.cao@intel.com>
|
||||
M: Bingbu Cao <bingbu.cao@amd.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -20027,9 +20033,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov2735.yaml
|
|||
F: drivers/media/i2c/ov2735.c
|
||||
|
||||
OMNIVISION OV2740 SENSOR DRIVER
|
||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
R: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@amd.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -20171,8 +20176,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov9650.txt
|
|||
F: drivers/media/i2c/ov9650.c
|
||||
|
||||
OMNIVISION OV9734 SENSOR DRIVER
|
||||
M: Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@amd.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -25253,7 +25258,8 @@ F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml
|
|||
F: drivers/media/i2c/imx296.c
|
||||
|
||||
SONY IMX319 SENSOR DRIVER
|
||||
M: Bingbu Cao <bingbu.cao@intel.com>
|
||||
M: Bingbu Cao <bingbu.cao@amd.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -25275,7 +25281,9 @@ 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>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
M: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
R: David Heidelberg <david@ixit.cz>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
|
|
@ -25296,6 +25304,19 @@ T: git git://linuxtv.org/media.git
|
|||
F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
|
||||
F: drivers/media/i2c/imx415.c
|
||||
|
||||
SONY IMX471 SENSOR DRIVER
|
||||
M: Kate Hsuan <hpa@redhat.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/i2c/imx471.c
|
||||
|
||||
SONY IMX678 SENSOR DRIVER
|
||||
M: Jai Luthra <jai.luthra@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
|
||||
F: drivers/media/i2c/imx678.c
|
||||
|
||||
SONY MEMORYSTICK SUBSYSTEM
|
||||
M: Maxim Levitsky <maximlevitsky@gmail.com>
|
||||
M: Alex Dubov <oakad@yahoo.com>
|
||||
|
|
|
|||
|
|
@ -859,6 +859,7 @@ static const char * const acpi_honor_dep_ids[] = {
|
|||
"INTC10DE", /* CVS (LNL) driver must be loaded to allow camera streaming */
|
||||
"INTC10E0", /* CVS (ARL) driver must be loaded to allow camera streaming */
|
||||
"INTC10E1", /* CVS (PTL) driver must be loaded to allow camera streaming */
|
||||
"INTC10FA", /* CVS (NVL) driver must be loaded to allow camera streaming */
|
||||
"RSCV0001", /* RISC-V PLIC */
|
||||
"RSCV0002", /* RISC-V APLIC */
|
||||
"RSCV0005", /* RISC-V SBI MPXY MBOX */
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ void cec_queue_event_fh(struct cec_fh *fh,
|
|||
const struct cec_event *new_ev, u64 ts)
|
||||
{
|
||||
static const u16 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 800, 800, 8, 8, 8, 8
|
||||
3, 1, 800, 800, 8, 8, 8, 8
|
||||
};
|
||||
struct cec_event_entry *entry;
|
||||
struct cec_event_entry *new_entry, *entry;
|
||||
unsigned int ev_idx = new_ev->event - 1;
|
||||
|
||||
if (WARN_ON(ev_idx >= ARRAY_SIZE(fh->events)))
|
||||
|
|
@ -92,36 +92,57 @@ void cec_queue_event_fh(struct cec_fh *fh,
|
|||
ts = ktime_get_ns();
|
||||
|
||||
mutex_lock(&fh->lock);
|
||||
if (ev_idx < CEC_NUM_CORE_EVENTS)
|
||||
entry = &fh->core_events[ev_idx];
|
||||
else
|
||||
entry = kmalloc_obj(*entry);
|
||||
if (entry) {
|
||||
new_entry = kmalloc_obj(*new_entry);
|
||||
if (new_entry) {
|
||||
if (new_ev->event == CEC_EVENT_LOST_MSGS &&
|
||||
fh->queued_events[ev_idx]) {
|
||||
entry = list_first_entry(&fh->events[ev_idx],
|
||||
struct cec_event_entry, list);
|
||||
entry->ev.lost_msgs.lost_msgs +=
|
||||
new_ev->lost_msgs.lost_msgs;
|
||||
kfree(new_entry);
|
||||
goto unlock;
|
||||
}
|
||||
entry->ev = *new_ev;
|
||||
entry->ev.ts = ts;
|
||||
|
||||
new_entry->ev = *new_ev;
|
||||
new_entry->ev.ts = ts;
|
||||
|
||||
/*
|
||||
* If the physical address becomes invalid (HPD went low),
|
||||
* then just flush all pending STATE_CHANGE events since
|
||||
* those are all obsoleted.
|
||||
*
|
||||
* This ensures you will not see stale STATE_CHANGE events.
|
||||
*/
|
||||
if (new_ev->event == CEC_EVENT_STATE_CHANGE &&
|
||||
new_ev->state_change.phys_addr == CEC_PHYS_ADDR_INVALID &&
|
||||
fh->queued_events[ev_idx]) {
|
||||
/* drop all events */
|
||||
while (!list_empty(&fh->events[ev_idx])) {
|
||||
entry = list_first_entry(&fh->events[ev_idx],
|
||||
struct cec_event_entry, list);
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
fh->total_queued_events--;
|
||||
fh->queued_events[ev_idx]--;
|
||||
}
|
||||
new_entry->ev.flags |= CEC_EVENT_FL_DROPPED_EVENTS;
|
||||
}
|
||||
|
||||
if (fh->queued_events[ev_idx] < max_events[ev_idx]) {
|
||||
/* Add new msg at the end of the queue */
|
||||
list_add_tail(&entry->list, &fh->events[ev_idx]);
|
||||
list_add_tail(&new_entry->list, &fh->events[ev_idx]);
|
||||
fh->queued_events[ev_idx]++;
|
||||
fh->total_queued_events++;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (ev_idx >= CEC_NUM_CORE_EVENTS) {
|
||||
list_add_tail(&entry->list, &fh->events[ev_idx]);
|
||||
/* drop the oldest event */
|
||||
entry = list_first_entry(&fh->events[ev_idx],
|
||||
struct cec_event_entry, list);
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
list_add_tail(&new_entry->list, &fh->events[ev_idx]);
|
||||
/* drop the oldest event */
|
||||
entry = list_first_entry(&fh->events[ev_idx],
|
||||
struct cec_event_entry, list);
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
/* Mark that events were lost */
|
||||
entry = list_first_entry_or_null(&fh->events[ev_idx],
|
||||
|
|
@ -608,6 +629,13 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|||
attempts_made = 1;
|
||||
|
||||
mutex_lock(&adap->lock);
|
||||
if (adap->error_inj_tx_timeouts) {
|
||||
dprintk(2, "%s: error_inj_tx_timeouts %u\n",
|
||||
__func__, adap->error_inj_tx_timeouts);
|
||||
adap->error_inj_tx_timeouts--;
|
||||
mutex_unlock(&adap->lock);
|
||||
return;
|
||||
}
|
||||
data = adap->transmitting;
|
||||
if (!data) {
|
||||
/*
|
||||
|
|
@ -965,7 +993,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
|
|||
*/
|
||||
mutex_unlock(&adap->lock);
|
||||
err = wait_for_completion_killable(&data->c);
|
||||
cancel_delayed_work_sync(&data->work);
|
||||
disable_delayed_work_sync(&data->work);
|
||||
mutex_lock(&adap->lock);
|
||||
|
||||
if (err)
|
||||
|
|
@ -1317,7 +1345,7 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||
{
|
||||
struct cec_log_addrs *las = &adap->log_addrs;
|
||||
struct cec_msg msg = { };
|
||||
const unsigned int max_retries = 2;
|
||||
const unsigned int max_attempts = 3;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
|
|
@ -1328,7 +1356,7 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||
msg.len = 1;
|
||||
msg.msg[0] = (log_addr << 4) | log_addr;
|
||||
|
||||
for (i = 0; i < max_retries; i++) {
|
||||
for (i = 0; i < max_attempts; i++) {
|
||||
err = cec_transmit_msg_fh(adap, &msg, NULL, true);
|
||||
|
||||
/*
|
||||
|
|
@ -1345,31 +1373,24 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The message was aborted or timed out due to a disconnect or
|
||||
* unconfigure, just bail out.
|
||||
*/
|
||||
if (msg.tx_status &
|
||||
(CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT))
|
||||
return -EINTR;
|
||||
if (msg.tx_status & CEC_TX_STATUS_OK)
|
||||
return 0;
|
||||
if (msg.tx_status & CEC_TX_STATUS_NACK)
|
||||
break;
|
||||
/*
|
||||
* Retry up to max_retries times if the message was neither
|
||||
* Do up to max_attempts if the message was neither
|
||||
* OKed or NACKed. This can happen due to e.g. a Lost
|
||||
* Arbitration condition.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are unable to get an OK or a NACK after max_retries attempts
|
||||
* If we are unable to get an OK or a NACK after max_attempts
|
||||
* (and note that each attempt already consists of four polls), then
|
||||
* we assume that something is really weird and that it is not a
|
||||
* good idea to try and claim this logical address.
|
||||
*/
|
||||
if (i == max_retries) {
|
||||
if (i == max_attempts) {
|
||||
dprintk(0, "polling for LA %u failed with tx_status=0x%04x\n",
|
||||
log_addr, msg.tx_status);
|
||||
return 0;
|
||||
|
|
@ -1468,6 +1489,7 @@ static int cec_config_thread_func(void *arg)
|
|||
dprintk(1, "physical address: %x.%x.%x.%x, claim %d logical addresses\n",
|
||||
cec_phys_addr_exp(adap->phys_addr), las->num_log_addrs);
|
||||
las->log_addr_mask = 0;
|
||||
las->flags &= ~CEC_LOG_ADDRS_FL_CONFIG_FAILED;
|
||||
|
||||
if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED)
|
||||
goto configured;
|
||||
|
|
@ -1600,6 +1622,8 @@ static int cec_config_thread_func(void *arg)
|
|||
unconfigure:
|
||||
for (i = 0; i < las->num_log_addrs; i++)
|
||||
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
|
||||
if (adap->phys_addr != CEC_PHYS_ADDR_INVALID)
|
||||
las->flags |= CEC_LOG_ADDRS_FL_CONFIG_FAILED;
|
||||
cec_adap_unconfigure(adap);
|
||||
adap->is_configuring = false;
|
||||
adap->must_reconfigure = false;
|
||||
|
|
@ -1717,7 +1741,6 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|||
cec_phys_addr_exp(phys_addr));
|
||||
if (becomes_invalid || !is_invalid) {
|
||||
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
|
||||
cec_post_state_event(adap);
|
||||
cec_adap_unconfigure(adap);
|
||||
if (becomes_invalid) {
|
||||
cec_adap_enable(adap);
|
||||
|
|
@ -2219,9 +2242,13 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
|
|||
* Unprocessed messages are aborted if userspace isn't doing
|
||||
* any processing either.
|
||||
*/
|
||||
mutex_lock(&adap->lock);
|
||||
if (!is_broadcast && !is_reply && !adap->follower_cnt &&
|
||||
!adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT)
|
||||
!adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) {
|
||||
mutex_unlock(&adap->lock);
|
||||
return cec_feature_abort(adap, msg);
|
||||
}
|
||||
mutex_unlock(&adap->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2234,10 +2261,12 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
|
|||
* Send to the exclusive follower if there is one, otherwise send
|
||||
* to all followers.
|
||||
*/
|
||||
mutex_lock(&adap->lock);
|
||||
if (adap->cec_follower)
|
||||
cec_queue_msg_fh(adap->cec_follower, msg);
|
||||
else
|
||||
cec_queue_msg_followers(adap, msg);
|
||||
mutex_unlock(&adap->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,8 +345,7 @@ static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh,
|
|||
|
||||
if (copy_to_user(parg, &ev->ev, sizeof(ev->ev)))
|
||||
err = -EFAULT;
|
||||
if (ev_idx >= CEC_NUM_CORE_EVENTS)
|
||||
kfree(ev);
|
||||
kfree(ev);
|
||||
fh->queued_events[ev_idx]--;
|
||||
fh->total_queued_events--;
|
||||
|
||||
|
|
@ -673,7 +672,7 @@ static int cec_release(struct inode *inode, struct file *filp)
|
|||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
for (i = CEC_NUM_CORE_EVENTS; i < CEC_NUM_EVENTS; i++) {
|
||||
for (i = 0; i < CEC_NUM_EVENTS; i++) {
|
||||
while (!list_empty(&fh->events[i])) {
|
||||
struct cec_event_entry *entry =
|
||||
list_first_entry(&fh->events[i],
|
||||
|
|
|
|||
|
|
@ -5,16 +5,33 @@
|
|||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "cec-priv.h"
|
||||
|
||||
|
|
@ -93,7 +110,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
|||
minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES);
|
||||
if (minor == CEC_NUM_DEVICES) {
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
pr_err("could not get a free minor\n");
|
||||
pr_err("Could not get a free minor\n");
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
|
|
@ -104,19 +121,19 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
|||
devnode->dev.bus = &cec_bus_type;
|
||||
devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor);
|
||||
devnode->dev.release = cec_devnode_release;
|
||||
dev_set_name(&devnode->dev, "cec%d", devnode->minor);
|
||||
dev_set_name(&devnode->dev, "%s%d", CEC_NAME, devnode->minor);
|
||||
device_initialize(&devnode->dev);
|
||||
|
||||
/* Part 2: Initialize and register the character device */
|
||||
cdev_init(&devnode->cdev, &cec_devnode_fops);
|
||||
devnode->cdev.owner = owner;
|
||||
kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor);
|
||||
kobject_set_name(&devnode->cdev.kobj, "%s%d", CEC_NAME, devnode->minor);
|
||||
|
||||
devnode->registered = true;
|
||||
ret = cdev_device_add(&devnode->cdev, &devnode->dev);
|
||||
if (ret) {
|
||||
devnode->registered = false;
|
||||
pr_err("%s: cdev_device_add failed\n", __func__);
|
||||
pr_err("cdev_device_add() failed\n");
|
||||
goto clr_bit;
|
||||
}
|
||||
|
||||
|
|
@ -205,19 +222,35 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused)
|
|||
|
||||
return call_op(adap, error_inj_show, sf);
|
||||
}
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj);
|
||||
|
||||
static int cec_error_inj_open(struct inode *inode, struct file *file)
|
||||
static ssize_t cec_error_inj_tx_timeouts_write(struct file *file,
|
||||
const char __user *ubuf, size_t count, loff_t *ppos)
|
||||
{
|
||||
return single_open(file, cec_error_inj_show, inode->i_private);
|
||||
struct seq_file *sf = file->private_data;
|
||||
struct cec_adapter *adap = sf->private;
|
||||
int ret;
|
||||
|
||||
if (count > 5)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&adap->lock);
|
||||
ret = kstrtou32_from_user(ubuf, count, 0, &adap->error_inj_tx_timeouts);
|
||||
if (ret)
|
||||
adap->error_inj_tx_timeouts = 0;
|
||||
mutex_unlock(&adap->lock);
|
||||
return ret ? : count;
|
||||
}
|
||||
|
||||
static const struct file_operations cec_error_inj_fops = {
|
||||
.open = cec_error_inj_open,
|
||||
.write = cec_error_inj_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
static int cec_error_inj_tx_timeouts_show(struct seq_file *sf, void *unused)
|
||||
{
|
||||
struct cec_adapter *adap = sf->private;
|
||||
|
||||
seq_printf(sf, "%u", adap->error_inj_tx_timeouts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj_tx_timeouts);
|
||||
#endif
|
||||
|
||||
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
|
|
@ -263,12 +296,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
mutex_init(&adap->devnode.lock_fhs);
|
||||
mutex_init(&adap->devnode.lock);
|
||||
|
||||
adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name);
|
||||
adap->kthread = kthread_run(cec_thread_func, adap, "%s-%s", CEC_NAME, name);
|
||||
if (IS_ERR(adap->kthread)) {
|
||||
pr_err("cec-%s: kernel_thread() failed\n", name);
|
||||
pr_err("%s: kthread_run() failed\n", name);
|
||||
res = PTR_ERR(adap->kthread);
|
||||
kfree(adap);
|
||||
return ERR_PTR(res);
|
||||
goto err_free_adap;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MEDIA_CEC_RC
|
||||
|
|
@ -278,11 +310,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
/* Prepare the RC input device */
|
||||
adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE);
|
||||
if (!adap->rc) {
|
||||
pr_err("cec-%s: failed to allocate memory for rc_dev\n",
|
||||
name);
|
||||
pr_err("%s: failed to allocate memory for rc_dev\n", name);
|
||||
kthread_stop(adap->kthread);
|
||||
kfree(adap);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
res = -ENOMEM;
|
||||
goto err_free_adap;
|
||||
}
|
||||
|
||||
snprintf(adap->input_phys, sizeof(adap->input_phys),
|
||||
|
|
@ -298,9 +329,18 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
adap->rc->allowed_protocols = RC_PROTO_BIT_CEC;
|
||||
adap->rc->priv = adap;
|
||||
adap->rc->map_name = RC_MAP_CEC;
|
||||
adap->rc->timeout = MS_TO_US(550);
|
||||
adap->rc->timeout = 550 * USEC_PER_MSEC;
|
||||
#endif
|
||||
return adap;
|
||||
|
||||
err_free_adap:
|
||||
mutex_destroy(&adap->devnode.lock);
|
||||
mutex_destroy(&adap->devnode.lock_fhs);
|
||||
|
||||
mutex_destroy(&adap->lock);
|
||||
|
||||
kfree(adap);
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_allocate_adapter);
|
||||
|
||||
|
|
@ -326,8 +366,7 @@ int cec_register_adapter(struct cec_adapter *adap,
|
|||
res = rc_register_device(adap->rc);
|
||||
|
||||
if (res) {
|
||||
pr_err("cec-%s: failed to prepare input device\n",
|
||||
adap->name);
|
||||
pr_err("%s: failed to prepare input device\n", adap->name);
|
||||
rc_free_device(adap->rc);
|
||||
adap->rc = NULL;
|
||||
return res;
|
||||
|
|
@ -356,6 +395,9 @@ int cec_register_adapter(struct cec_adapter *adap,
|
|||
debugfs_create_devm_seqfile(&adap->devnode.dev, "status", adap->cec_dir,
|
||||
cec_adap_status);
|
||||
|
||||
debugfs_create_file("error-inj-tx-timeouts", 0644, adap->cec_dir, adap,
|
||||
&cec_error_inj_tx_timeouts_fops);
|
||||
|
||||
if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line)
|
||||
return 0;
|
||||
debugfs_create_file("error-inj", 0644, adap->cec_dir, adap,
|
||||
|
|
@ -371,9 +413,7 @@ void cec_unregister_adapter(struct cec_adapter *adap)
|
|||
return;
|
||||
|
||||
#ifdef CONFIG_MEDIA_CEC_RC
|
||||
/* Note: rc_unregister also calls rc_free */
|
||||
rc_unregister_device(adap->rc);
|
||||
adap->rc = NULL;
|
||||
#endif
|
||||
debugfs_remove_recursive(adap->cec_dir);
|
||||
#ifdef CONFIG_CEC_NOTIFIER
|
||||
|
|
@ -387,14 +427,23 @@ void cec_delete_adapter(struct cec_adapter *adap)
|
|||
{
|
||||
if (IS_ERR_OR_NULL(adap))
|
||||
return;
|
||||
|
||||
if (adap->kthread_config)
|
||||
kthread_stop(adap->kthread_config);
|
||||
kthread_stop(adap->kthread);
|
||||
|
||||
if (adap->ops->adap_free)
|
||||
adap->ops->adap_free(adap);
|
||||
|
||||
#ifdef CONFIG_MEDIA_CEC_RC
|
||||
rc_free_device(adap->rc);
|
||||
#endif
|
||||
|
||||
mutex_destroy(&adap->devnode.lock);
|
||||
mutex_destroy(&adap->devnode.lock_fhs);
|
||||
|
||||
mutex_destroy(&adap->lock);
|
||||
|
||||
kfree(adap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_delete_adapter);
|
||||
|
|
@ -407,14 +456,14 @@ static int __init cec_devnode_init(void)
|
|||
int ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, CEC_NAME);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_warn("cec: unable to allocate major\n");
|
||||
pr_warn("Unable to allocate major\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
top_cec_dir = debugfs_create_dir("cec", NULL);
|
||||
top_cec_dir = debugfs_create_dir(CEC_NAME, NULL);
|
||||
if (IS_ERR_OR_NULL(top_cec_dir)) {
|
||||
pr_warn("cec: Failed to create debugfs cec dir\n");
|
||||
pr_warn("Failed to create debugfs " CEC_NAME " dir\n");
|
||||
top_cec_dir = NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -423,7 +472,7 @@ static int __init cec_devnode_init(void)
|
|||
if (ret < 0) {
|
||||
debugfs_remove_recursive(top_cec_dir);
|
||||
unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES);
|
||||
pr_warn("cec: bus_register failed\n");
|
||||
pr_warn("bus_register() failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)
|
|||
return;
|
||||
|
||||
pin->adap->cec_pin_is_high = v;
|
||||
if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) {
|
||||
if (atomic_read_acquire(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) {
|
||||
u8 ev = v;
|
||||
|
||||
if (pin->work_pin_events_dropped) {
|
||||
|
|
@ -126,7 +126,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)
|
|||
pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get();
|
||||
pin->work_pin_events_wr =
|
||||
(pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS;
|
||||
atomic_inc(&pin->work_pin_num_events);
|
||||
atomic_inc_return_release(&pin->work_pin_num_events);
|
||||
} else {
|
||||
pin->work_pin_events_dropped = true;
|
||||
pin->work_pin_events_dropped_cnt++;
|
||||
|
|
@ -692,7 +692,6 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
|
|||
v = cec_pin_read(pin);
|
||||
if (!v)
|
||||
break;
|
||||
pin->state = CEC_ST_RX_START_BIT_HIGH;
|
||||
delta = ktime_us_delta(ts, pin->ts);
|
||||
/* Start bit low is too short, go back to idle */
|
||||
if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) {
|
||||
|
|
@ -703,7 +702,16 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
|
|||
cec_pin_to_idle(pin);
|
||||
break;
|
||||
}
|
||||
pin->state = CEC_ST_RX_START_BIT_HIGH;
|
||||
if (rx_arb_lost(pin, &poll)) {
|
||||
/*
|
||||
* Normally rx_toggle is toggled in cec_pin_to_idle()
|
||||
* when we're in an RX state, but here we switch to TX
|
||||
* mode, so cec_pin_to_idle() sees a TX mode and never
|
||||
* toggles rx_toggle. So toggle it here as a special
|
||||
* corner case.
|
||||
*/
|
||||
pin->rx_toggle ^= 1;
|
||||
cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf);
|
||||
pin->tx_generated_poll = true;
|
||||
pin->tx_extra_bytes = 0;
|
||||
|
|
@ -1101,7 +1109,7 @@ static int cec_pin_thread_func(void *_adap)
|
|||
pin->work_tx_ts);
|
||||
}
|
||||
|
||||
while (atomic_read(&pin->work_pin_num_events)) {
|
||||
while (atomic_read_acquire(&pin->work_pin_num_events)) {
|
||||
unsigned int idx = pin->work_pin_events_rd;
|
||||
u8 v = pin->work_pin_events[idx];
|
||||
|
||||
|
|
@ -1110,7 +1118,7 @@ static int cec_pin_thread_func(void *_adap)
|
|||
v & CEC_PIN_EVENT_FL_DROPPED,
|
||||
pin->work_pin_ts[idx]);
|
||||
pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS;
|
||||
atomic_dec(&pin->work_pin_num_events);
|
||||
atomic_dec_return_release(&pin->work_pin_num_events);
|
||||
}
|
||||
|
||||
switch (atomic_xchg(&pin->work_irq_change,
|
||||
|
|
|
|||
|
|
@ -405,6 +405,7 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
|
|||
}
|
||||
|
||||
static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
|
||||
.name = "core",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.reg_read = meson_ao_cec_g12a_read,
|
||||
|
|
@ -688,10 +689,8 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
|
|||
meson_ao_cec_g12a_irq,
|
||||
meson_ao_cec_g12a_irq_thread,
|
||||
0, NULL, ao_cec);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "irq request failed\n");
|
||||
if (ret)
|
||||
goto out_probe_adapter;
|
||||
}
|
||||
|
||||
ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
|
||||
if (IS_ERR(ao_cec->oscin)) {
|
||||
|
|
|
|||
|
|
@ -636,10 +636,8 @@ static int meson_ao_cec_probe(struct platform_device *pdev)
|
|||
meson_ao_cec_irq,
|
||||
meson_ao_cec_irq_thread,
|
||||
0, NULL, ao_cec);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "irq request failed\n");
|
||||
if (ret)
|
||||
goto out_probe_adapter;
|
||||
}
|
||||
|
||||
ao_cec->core = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(ao_cec->core)) {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,15 @@
|
|||
* Copyright (C) 2018, Aidilab Srl.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
/* CEC Framework */
|
||||
#include <media/cec-notifier.h>
|
||||
|
|
@ -356,7 +357,7 @@ static int secocec_ir_probe(void *priv)
|
|||
cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
|
||||
cec->ir->priv = cec;
|
||||
cec->ir->map_name = RC_MAP_HAUPPAUGE;
|
||||
cec->ir->timeout = MS_TO_US(100);
|
||||
cec->ir->timeout = 100 * USEC_PER_MSEC;
|
||||
|
||||
/* Clear the status register */
|
||||
status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
|
||||
|
|
@ -618,7 +619,6 @@ static int secocec_probe(struct platform_device *pdev)
|
|||
dev_name(&pdev->dev), secocec);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot request IRQ %d\n", secocec->irq);
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ static void stm32_rx_done(struct stm32_cec *cec, u32 status)
|
|||
u32 val;
|
||||
|
||||
regmap_read(cec->regmap, CEC_RXDR, &val);
|
||||
cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
|
||||
if (cec->rx_msg.len < CEC_MAX_MSG_SIZE)
|
||||
cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
|
||||
}
|
||||
|
||||
if (cec->irq_status & RXEND) {
|
||||
|
|
@ -193,18 +194,24 @@ static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||
static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
|
||||
{
|
||||
struct stm32_cec *cec = adap->priv;
|
||||
u32 oar = (1 << logical_addr) << 16;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Poll every 100µs the register CEC_CR to wait end of transmission */
|
||||
regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM),
|
||||
100, CEC_XFER_TIMEOUT_MS * 1000);
|
||||
ret = regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM),
|
||||
100, CEC_XFER_TIMEOUT_MS * 1000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
|
||||
|
||||
if (logical_addr == CEC_LOG_ADDR_INVALID)
|
||||
if (logical_addr == CEC_LOG_ADDR_INVALID) {
|
||||
regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
|
||||
else
|
||||
} else {
|
||||
u32 oar = BIT(logical_addr) << 16;
|
||||
|
||||
regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar);
|
||||
}
|
||||
|
||||
regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <media/cec-notifier.h>
|
||||
|
|
@ -47,6 +48,7 @@ struct tegra_cec {
|
|||
u32 tx_buf[CEC_MAX_MSG_SIZE];
|
||||
u8 tx_buf_cur;
|
||||
u8 tx_buf_cnt;
|
||||
u32 rx_total_low_drives;
|
||||
};
|
||||
|
||||
static inline u32 cec_read(struct tegra_cec *cec, u32 reg)
|
||||
|
|
@ -116,6 +118,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
|
|||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
if (status & TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED) {
|
||||
dev_warn_ratelimited(dev, "RX bus error detected, generated low drive\n");
|
||||
cec->rx_total_low_drives++;
|
||||
cec_write(cec, TEGRA_CEC_INT_STAT,
|
||||
TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED);
|
||||
}
|
||||
|
||||
if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) ||
|
||||
(status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) {
|
||||
tegra_cec_error_recovery(cec);
|
||||
|
|
@ -241,9 +250,21 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||
TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
|
||||
TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED |
|
||||
TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
|
||||
TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED |
|
||||
TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED);
|
||||
|
||||
cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE);
|
||||
/*
|
||||
* TX_NAK_MODE ensures that the whole message is transmitted even
|
||||
* if each byte is NACKed. Without this flag the retransmit of the
|
||||
* messages after a NACK can be corrupt. This is a bug in the hardware.
|
||||
*
|
||||
* While less efficient, in practice you rarely transmit messages
|
||||
* that can be NACKed, with the exception of POLL messages which
|
||||
* are just one byte anyway.
|
||||
*/
|
||||
cec_write(cec, TEGRA_CEC_HW_CONTROL,
|
||||
TEGRA_CEC_HWCTRL_TX_RX_MODE |
|
||||
TEGRA_CEC_HWCTRL_TX_NAK_MODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -307,11 +328,20 @@ static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_cec_adap_status(struct cec_adapter *adap, struct seq_file *file)
|
||||
{
|
||||
struct tegra_cec *cec = adap->priv;
|
||||
|
||||
seq_printf(file, "receive low drive count: %u\n",
|
||||
cec->rx_total_low_drives);
|
||||
}
|
||||
|
||||
static const struct cec_adap_ops tegra_cec_ops = {
|
||||
.adap_enable = tegra_cec_adap_enable,
|
||||
.adap_log_addr = tegra_cec_adap_log_addr,
|
||||
.adap_transmit = tegra_cec_adap_transmit,
|
||||
.adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable,
|
||||
.adap_status = tegra_cec_adap_status,
|
||||
};
|
||||
|
||||
static int tegra_cec_probe(struct platform_device *pdev)
|
||||
|
|
@ -381,11 +411,8 @@ static int tegra_cec_probe(struct platform_device *pdev)
|
|||
tegra_cec_irq_handler, tegra_cec_irq_thread_handler,
|
||||
0, "cec_irq", &pdev->dev);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to request interrupt for device\n");
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME,
|
||||
CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL |
|
||||
|
|
@ -458,6 +485,7 @@ static const struct of_device_id tegra_cec_of_match[] = {
|
|||
{ .compatible = "nvidia,tegra210-cec", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_cec_of_match);
|
||||
|
||||
static struct platform_driver tegra_cec_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -657,7 +657,8 @@ static void extron_process_received(struct extron_port *port, const char *data)
|
|||
if (!port || port->disconnected)
|
||||
return;
|
||||
|
||||
if (len < 5 || (len - 2) % 3 || data[len - 2] != '*')
|
||||
if (len < 5 || ((len - 2) / 3 > sizeof(msg.msg)) ||
|
||||
(len - 2) % 3 || data[len - 2] != '*')
|
||||
goto malformed;
|
||||
|
||||
while (*data != '*') {
|
||||
|
|
|
|||
|
|
@ -2346,9 +2346,11 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg,
|
|||
(params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
|
||||
}
|
||||
|
||||
static void tpg_fill_plane_extras(const struct tpg_data *tpg,
|
||||
const struct tpg_draw_params *params,
|
||||
unsigned p, unsigned h, u8 *vbuf)
|
||||
/* noinline to work around clang KASAN issues */
|
||||
static noinline_for_stack void
|
||||
tpg_fill_plane_extras(const struct tpg_data *tpg,
|
||||
const struct tpg_draw_params *params,
|
||||
unsigned p, unsigned h, u8 *vbuf)
|
||||
{
|
||||
unsigned twopixsize = params->twopixsize;
|
||||
unsigned img_width = params->img_width;
|
||||
|
|
@ -2483,9 +2485,9 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg,
|
|||
}
|
||||
}
|
||||
|
||||
static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
|
||||
const struct tpg_draw_params *params,
|
||||
unsigned p, unsigned h, u8 *vbuf)
|
||||
static noinline_for_stack void
|
||||
tpg_fill_plane_pattern(const struct tpg_data *tpg, const struct tpg_draw_params *params,
|
||||
unsigned p, unsigned h, u8 *vbuf)
|
||||
{
|
||||
unsigned twopixsize = params->twopixsize;
|
||||
unsigned img_width = params->img_width;
|
||||
|
|
|
|||
|
|
@ -635,19 +635,6 @@ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(vb2_find_buffer);
|
||||
|
||||
/*
|
||||
* vb2_querybuf() - query video buffer information
|
||||
* @q: vb2 queue
|
||||
* @b: buffer struct passed from userspace to vidioc_querybuf handler
|
||||
* in driver
|
||||
*
|
||||
* Should be called from vidioc_querybuf ioctl handler in driver.
|
||||
* This function will verify the passed v4l2_buffer structure and fill the
|
||||
* relevant information for the userspace.
|
||||
*
|
||||
* The return values from this function are intended to be directly returned
|
||||
* from vidioc_querybuf handler in driver.
|
||||
*/
|
||||
int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
|
||||
{
|
||||
struct vb2_buffer *vb;
|
||||
|
|
|
|||
|
|
@ -884,6 +884,7 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
|
|||
struct dmxdev_filter *filter, u16 pid)
|
||||
{
|
||||
struct dmxdev_feed *feed;
|
||||
int ret;
|
||||
|
||||
if ((filter->type != DMXDEV_TYPE_PES) ||
|
||||
(filter->state < DMXDEV_STATE_SET))
|
||||
|
|
@ -901,8 +902,14 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
|
|||
feed->pid = pid;
|
||||
list_add(&feed->next, &filter->feed.ts);
|
||||
|
||||
if (filter->state >= DMXDEV_STATE_GO)
|
||||
return dvb_dmxdev_start_feed(dmxdev, filter, feed);
|
||||
if (filter->state >= DMXDEV_STATE_GO) {
|
||||
ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
|
||||
if (ret < 0) {
|
||||
list_del(&feed->next);
|
||||
kfree(feed);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/kthread.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
|
@ -2760,77 +2761,25 @@ static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *w
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
static int __dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dvb_adapter *adapter = fe->dvb;
|
||||
int ret;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
if (fe->exit == DVB_FE_DEVICE_REMOVED)
|
||||
return -ENODEV;
|
||||
|
||||
if (adapter->mfe_shared == 2) {
|
||||
mutex_lock(&adapter->mfe_lock);
|
||||
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
|
||||
if (adapter->mfe_dvbdev &&
|
||||
!adapter->mfe_dvbdev->writers) {
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
} else if (adapter->mfe_shared) {
|
||||
mutex_lock(&adapter->mfe_lock);
|
||||
|
||||
if (!adapter->mfe_dvbdev)
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
|
||||
else if (adapter->mfe_dvbdev != dvbdev) {
|
||||
struct dvb_device
|
||||
*mfedev = adapter->mfe_dvbdev;
|
||||
struct dvb_frontend
|
||||
*mfe = mfedev->priv;
|
||||
struct dvb_frontend_private
|
||||
*mfepriv = mfe->frontend_priv;
|
||||
int mferetry = (dvb_mfe_wait_time << 1);
|
||||
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
while (mferetry-- && (mfedev->users != -1 ||
|
||||
mfepriv->thread)) {
|
||||
if (msleep_interruptible(500)) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&adapter->mfe_lock);
|
||||
if (adapter->mfe_dvbdev != dvbdev) {
|
||||
mfedev = adapter->mfe_dvbdev;
|
||||
mfe = mfedev->priv;
|
||||
mfepriv = mfe->frontend_priv;
|
||||
if (mfedev->users != -1 ||
|
||||
mfepriv->thread) {
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
|
||||
if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
|
||||
goto err0;
|
||||
return ret;
|
||||
|
||||
/* If we took control of the bus, we need to force
|
||||
reinitialization. This is because many ts_bus_ctrl()
|
||||
functions strobe the RESET pin on the demod, and if the
|
||||
frontend thread already exists then the dvb_init() routine
|
||||
won't get called (which is what usually does initial
|
||||
register configuration). */
|
||||
/*
|
||||
* If we took control of the bus, we need to force
|
||||
* reinitialization. This is because many ts_bus_ctrl()
|
||||
* functions strobe the RESET pin on the demod, and if the
|
||||
* frontend thread already exists then the dvb_init() routine
|
||||
* won't get called (which is what usually does initial
|
||||
* register configuration).
|
||||
*/
|
||||
fepriv->reinitialise = 1;
|
||||
}
|
||||
|
||||
|
|
@ -2871,8 +2820,6 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
|||
|
||||
dvb_frontend_get(fe);
|
||||
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
return ret;
|
||||
|
||||
err3:
|
||||
|
|
@ -2891,12 +2838,88 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
|||
err1:
|
||||
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
|
||||
fe->ops.ts_bus_ctrl(fe, 0);
|
||||
err0:
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wait_dvb_frontend(struct dvb_adapter *adapter,
|
||||
struct dvb_device *mfedev)
|
||||
{
|
||||
struct dvb_frontend *mfe = mfedev->priv;
|
||||
struct dvb_frontend_private *mfepriv = mfe->frontend_priv;
|
||||
int mferetry = (dvb_mfe_wait_time << 1);
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&adapter->mfe_lock);
|
||||
|
||||
if (mfedev->users == -1 && !mfepriv->thread)
|
||||
return 0;
|
||||
|
||||
mutex_unlock(&adapter->mfe_lock);
|
||||
|
||||
while (mferetry-- && (mfedev->users != -1 || mfepriv->thread)) {
|
||||
if (msleep_interruptible(500))
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&adapter->mfe_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_adapter *adapter = fe->dvb;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
if (fe->exit == DVB_FE_DEVICE_REMOVED)
|
||||
return -ENODEV;
|
||||
|
||||
if (!adapter->mfe_shared)
|
||||
return __dvb_frontend_open(inode, file);
|
||||
|
||||
guard(mutex)(&adapter->mfe_lock);
|
||||
|
||||
if (adapter->mfe_shared == 2) {
|
||||
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
|
||||
if (adapter->mfe_dvbdev &&
|
||||
!adapter->mfe_dvbdev->writers)
|
||||
return -EBUSY;
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
return __dvb_frontend_open(inode, file);
|
||||
}
|
||||
|
||||
if (!adapter->mfe_dvbdev) {
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
} else if (adapter->mfe_dvbdev != dvbdev) {
|
||||
struct dvb_device *mfedev = adapter->mfe_dvbdev;
|
||||
struct dvb_frontend *mfe = mfedev->priv;
|
||||
struct dvb_frontend_private *mfepriv = mfe->frontend_priv;
|
||||
int ret;
|
||||
|
||||
ret = wait_dvb_frontend(adapter, mfedev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adapter->mfe_dvbdev != dvbdev) {
|
||||
mfedev = adapter->mfe_dvbdev;
|
||||
mfe = mfedev->priv;
|
||||
mfepriv = mfe->frontend_priv;
|
||||
if (mfedev->users != -1 || mfepriv->thread)
|
||||
return -EBUSY;
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
}
|
||||
|
||||
return __dvb_frontend_open(inode, file);
|
||||
}
|
||||
|
||||
static int dvb_frontend_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
|
|
|
|||
|
|
@ -995,22 +995,22 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe,
|
|||
const struct helene_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct helene_priv *priv = NULL;
|
||||
struct helene_priv *pr = NULL;
|
||||
|
||||
priv = kzalloc_obj(struct helene_priv);
|
||||
if (priv == NULL)
|
||||
pr = kzalloc_obj(struct helene_priv);
|
||||
if (!pr)
|
||||
return NULL;
|
||||
priv->i2c_address = (config->i2c_address >> 1);
|
||||
priv->i2c = i2c;
|
||||
priv->set_tuner_data = config->set_tuner_priv;
|
||||
priv->set_tuner = config->set_tuner_callback;
|
||||
priv->xtal = config->xtal;
|
||||
pr->i2c_address = (config->i2c_address >> 1);
|
||||
pr->i2c = i2c;
|
||||
pr->set_tuner_data = config->set_tuner_priv;
|
||||
pr->set_tuner = config->set_tuner_callback;
|
||||
pr->xtal = config->xtal;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
if (helene_x_pon(priv) != 0) {
|
||||
kfree(priv);
|
||||
if (helene_x_pon(pr) != 0) {
|
||||
kfree(pr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1019,10 +1019,10 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe,
|
|||
|
||||
memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_s,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
fe->tuner_priv = priv;
|
||||
dev_info(&priv->i2c->dev,
|
||||
"Sony HELENE Sat attached on addr=%x at I2C adapter %p\n",
|
||||
priv->i2c_address, priv->i2c);
|
||||
fe->tuner_priv = pr;
|
||||
dev_info(&pr->i2c->dev,
|
||||
"Sony HELENE Sat attached on addr=%x at I2C adapter %p\n",
|
||||
pr->i2c_address, pr->i2c);
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(helene_attach_s);
|
||||
|
|
@ -1031,22 +1031,22 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe,
|
|||
const struct helene_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct helene_priv *priv = NULL;
|
||||
struct helene_priv *pr = NULL;
|
||||
|
||||
priv = kzalloc_obj(struct helene_priv);
|
||||
if (priv == NULL)
|
||||
pr = kzalloc_obj(struct helene_priv);
|
||||
if (!pr)
|
||||
return NULL;
|
||||
priv->i2c_address = (config->i2c_address >> 1);
|
||||
priv->i2c = i2c;
|
||||
priv->set_tuner_data = config->set_tuner_priv;
|
||||
priv->set_tuner = config->set_tuner_callback;
|
||||
priv->xtal = config->xtal;
|
||||
pr->i2c_address = (config->i2c_address >> 1);
|
||||
pr->i2c = i2c;
|
||||
pr->set_tuner_data = config->set_tuner_priv;
|
||||
pr->set_tuner = config->set_tuner_callback;
|
||||
pr->xtal = config->xtal;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
if (helene_x_pon(priv) != 0) {
|
||||
kfree(priv);
|
||||
if (helene_x_pon(pr) != 0) {
|
||||
kfree(pr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1055,10 +1055,10 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe,
|
|||
|
||||
memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_t,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
fe->tuner_priv = priv;
|
||||
dev_info(&priv->i2c->dev,
|
||||
"Sony HELENE Ter attached on addr=%x at I2C adapter %p\n",
|
||||
priv->i2c_address, priv->i2c);
|
||||
fe->tuner_priv = pr;
|
||||
dev_info(&pr->i2c->dev,
|
||||
"Sony HELENE Ter attached on addr=%x at I2C adapter %p\n",
|
||||
pr->i2c_address, pr->i2c);
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(helene_attach);
|
||||
|
|
|
|||
|
|
@ -906,9 +906,12 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
goto err;
|
||||
|
||||
mutex_unlock(&dev->v4l2_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
rtl2832_sdr_free_urbs(dev);
|
||||
rtl2832_sdr_free_stream_bufs(dev);
|
||||
rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
|
||||
mutex_unlock(&dev->v4l2_lock);
|
||||
|
||||
|
|
@ -1477,14 +1480,22 @@ static void rtl2832_sdr_remove(struct platform_device *pdev)
|
|||
|
||||
dev_dbg(&pdev->dev, "\n");
|
||||
|
||||
mutex_lock(&dev->vb_queue_lock);
|
||||
mutex_lock(&dev->v4l2_lock);
|
||||
/* No need to keep the urbs around after disconnection */
|
||||
dev->udev = NULL;
|
||||
/*
|
||||
* vb2_video_unregister_device() releases the vb2 queue, which
|
||||
* triggers rtl2832_sdr_stop_streaming() if streaming is active.
|
||||
* stop_streaming() uses dev->udev to free URBs and coherent DMA
|
||||
* stream buffers via usb_free_coherent(), so it must run before
|
||||
* dev->udev is cleared. vb2_video_unregister_device() locks
|
||||
* vb_queue_lock internally and stop_streaming() locks v4l2_lock,
|
||||
* so neither may be held by the caller.
|
||||
*/
|
||||
v4l2_device_disconnect(&dev->v4l2_dev);
|
||||
video_unregister_device(&dev->vdev);
|
||||
vb2_video_unregister_device(&dev->vdev);
|
||||
|
||||
mutex_lock(&dev->v4l2_lock);
|
||||
dev->udev = NULL;
|
||||
mutex_unlock(&dev->v4l2_lock);
|
||||
mutex_unlock(&dev->vb_queue_lock);
|
||||
|
||||
v4l2_device_put(&dev->v4l2_dev);
|
||||
module_put(pdev->dev.parent->driver->owner);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ config VIDEO_IMX335
|
|||
|
||||
config VIDEO_IMX355
|
||||
tristate "Sony IMX355 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX355 camera.
|
||||
|
|
@ -269,6 +270,7 @@ config VIDEO_IMX355
|
|||
config VIDEO_IMX412
|
||||
tristate "Sony IMX412 sensor support"
|
||||
depends on OF
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX412 camera.
|
||||
|
|
@ -287,6 +289,27 @@ config VIDEO_IMX415
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx415.
|
||||
|
||||
config VIDEO_IMX471
|
||||
tristate "Sony IMX471 sensor support"
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX471 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx471.
|
||||
|
||||
config VIDEO_IMX678
|
||||
tristate "Sony IMX678 sensor support"
|
||||
depends on GPIOLIB
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX678 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx678.
|
||||
|
||||
config VIDEO_MAX9271_LIB
|
||||
tristate
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o
|
|||
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
|
||||
obj-$(CONFIG_VIDEO_IMX412) += imx412.o
|
||||
obj-$(CONFIG_VIDEO_IMX415) += imx415.o
|
||||
obj-$(CONFIG_VIDEO_IMX678) += imx678.o
|
||||
obj-$(CONFIG_VIDEO_IMX471) += imx471.o
|
||||
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
|
||||
obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
|
||||
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
|
||||
|
|
|
|||
|
|
@ -1290,7 +1290,7 @@ static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on)
|
|||
struct device *dev = &alvium->i2c_client->dev;
|
||||
int ret;
|
||||
|
||||
ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,
|
||||
ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_AUTO_RW,
|
||||
on ? 0x02 : 0x00);
|
||||
if (ret) {
|
||||
dev_err(dev, "Fail to set autoexposure reg\n");
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#define PCI_DEVICE_ID_INTEL_IPU7 0x645d /* MTL / LNL */
|
||||
#define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d /* ARL / PTL */
|
||||
#define PCI_DEVICE_ID_INTEL_IPU8 0xd719 /* NVL */
|
||||
|
||||
/*
|
||||
* IPU7 PCI device IDs not covered by ipu6_pci_tbl in ipu6-pci-table.h.
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
static const struct pci_device_id icvs_ipu7_tbl[] = {
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) },
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) },
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU8) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -962,6 +964,7 @@ static const struct acpi_device_id intel_cvs_acpi_match[] = {
|
|||
{ "INTC10DE" }, /* LNL */
|
||||
{ "INTC10E0" }, /* ARL */
|
||||
{ "INTC10E1" }, /* PTL */
|
||||
{ "INTC10FA" }, /* NVL */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, intel_cvs_acpi_match);
|
||||
|
|
|
|||
|
|
@ -432,7 +432,6 @@ enum icvs_state {
|
|||
* @freq_ctrl: (future) frequency control pointer
|
||||
* @pads: Local media pads (sink/source)
|
||||
* @nr_of_lanes: Active CSI-2 lane count
|
||||
* @link_freq: Current link frequency (Hz)
|
||||
* @ipu_link: PM runtime device link (IPU consumer, CVS supplier)
|
||||
* @res: Resource capability (light/full)
|
||||
* @caps: Reported device protocol capabilities
|
||||
|
|
@ -458,7 +457,6 @@ struct icvs {
|
|||
struct v4l2_ctrl *freq_ctrl;
|
||||
struct media_pad pads[ICVS_CSI_NUM_PADS];
|
||||
u32 nr_of_lanes;
|
||||
u64 link_freq;
|
||||
struct device_link *ipu_link;
|
||||
enum icvs_resources res;
|
||||
struct icvs_dev_capabilities caps;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = {
|
|||
/**
|
||||
* csi_set_link_cfg - Program default CSI-2 link parameters
|
||||
* @ctx: CVS device context
|
||||
* @link_freq: Link frequency (Hz)
|
||||
*
|
||||
* Populates a HOST_SET_MIPI_CONFIG command using current lane count and
|
||||
* link frequency, then submits it to the device.
|
||||
|
|
@ -53,12 +54,12 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = {
|
|||
*
|
||||
* Return: 0 on success or negative errno.
|
||||
*/
|
||||
static int csi_set_link_cfg(struct icvs *ctx)
|
||||
static int csi_set_link_cfg(struct icvs *ctx, u64 link_freq)
|
||||
{
|
||||
struct icvs_cmd cmd = {
|
||||
.cmd_id = cpu_to_be16(ICVS_HOST_SET_MIPI_CONFIG),
|
||||
.param.conf.nr_of_lanes = ctx->nr_of_lanes,
|
||||
.param.conf.link_freq = ctx->link_freq,
|
||||
.param.conf.link_freq = link_freq,
|
||||
};
|
||||
size_t cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf);
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd,
|
|||
struct v4l2_subdev *remote_sd =
|
||||
media_entity_to_v4l2_subdev(ctx->remote->entity);
|
||||
struct device *dev = cvs_dev(ctx);
|
||||
s64 freq;
|
||||
s64 link_freq;
|
||||
int ret;
|
||||
|
||||
/* cvs_set_link_owner(ICVS_CSI_LINK_HOST) */
|
||||
|
|
@ -99,15 +100,14 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
freq = v4l2_get_link_freq(ctx->remote, 0, 0);
|
||||
if (freq < 0) {
|
||||
ret = freq;
|
||||
link_freq = v4l2_get_link_freq(ctx->remote, 0, 0);
|
||||
if (link_freq < 0) {
|
||||
ret = link_freq;
|
||||
goto err_rpm_put;
|
||||
}
|
||||
ctx->link_freq = freq;
|
||||
|
||||
if (ctx->i2c_client) {
|
||||
ret = csi_set_link_cfg(ctx);
|
||||
ret = csi_set_link_cfg(ctx, link_freq);
|
||||
if (ret < 0)
|
||||
goto err_rpm_put_sync;
|
||||
}
|
||||
|
|
@ -345,7 +345,6 @@ static int cvs_csi_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
|
|||
if (freq < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->link_freq = freq;
|
||||
cfg->link_freq = freq;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -3962,6 +3962,7 @@ static int cx25840_probe(struct i2c_client *client)
|
|||
int err = state->hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return err;
|
||||
}
|
||||
if (!is_cx2583x(state))
|
||||
|
|
@ -3986,6 +3987,7 @@ static void cx25840_remove(struct i2c_client *client)
|
|||
cx25840_ir_remove(sd);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cx25840_id[] = {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
|
@ -84,6 +85,8 @@
|
|||
#define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd)
|
||||
|
||||
struct gc0310_device {
|
||||
struct clk *clk;
|
||||
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
||||
|
|
@ -635,7 +638,6 @@ static int gc0310_check_hwcfg(struct device *dev)
|
|||
};
|
||||
struct fwnode_handle *ep_fwnode;
|
||||
unsigned long link_freq_bitmap;
|
||||
u32 mclk;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
|
@ -647,21 +649,6 @@ static int gc0310_check_hwcfg(struct device *dev)
|
|||
return dev_err_probe(dev, -EPROBE_DEFER,
|
||||
"waiting for fwnode graph endpoint\n");
|
||||
|
||||
ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
||||
&mclk);
|
||||
if (ret) {
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
return dev_err_probe(dev, ret,
|
||||
"reading clock-frequency property\n");
|
||||
}
|
||||
|
||||
if (mclk != GC0310_MCLK_FREQ) {
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"external clock %u is not supported\n",
|
||||
mclk);
|
||||
}
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg);
|
||||
fwnode_handle_put(ep_fwnode);
|
||||
if (ret)
|
||||
|
|
@ -685,6 +672,7 @@ static int gc0310_check_hwcfg(struct device *dev)
|
|||
static int gc0310_probe(struct i2c_client *client)
|
||||
{
|
||||
struct gc0310_device *sensor;
|
||||
unsigned long freq;
|
||||
int ret;
|
||||
|
||||
ret = gc0310_check_hwcfg(&client->dev);
|
||||
|
|
@ -695,6 +683,16 @@ static int gc0310_probe(struct i2c_client *client)
|
|||
if (!sensor)
|
||||
return -ENOMEM;
|
||||
|
||||
sensor->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL);
|
||||
if (IS_ERR(sensor->clk))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(sensor->clk),
|
||||
"failed to get clock\n");
|
||||
|
||||
freq = clk_get_rate(sensor->clk);
|
||||
if (freq != GC0310_MCLK_FREQ)
|
||||
return dev_err_probe(&client->dev, -EINVAL,
|
||||
"external clock %lu is not supported\n", freq);
|
||||
|
||||
sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(sensor->reset)) {
|
||||
return dev_err_probe(&client->dev, PTR_ERR(sensor->reset),
|
||||
|
|
|
|||
|
|
@ -110,11 +110,16 @@
|
|||
|
||||
/* Test Pattern Control */
|
||||
#define IMX219_REG_TEST_PATTERN CCI_REG16(0x0600)
|
||||
#define IMX219_TEST_PATTERN_DISABLE 0
|
||||
#define IMX219_TEST_PATTERN_SOLID_COLOR 1
|
||||
#define IMX219_TEST_PATTERN_COLOR_BARS 2
|
||||
#define IMX219_TEST_PATTERN_GREY_COLOR 3
|
||||
#define IMX219_TEST_PATTERN_PN9 4
|
||||
#define IMX219_TEST_PATTERN_DISABLE 0
|
||||
#define IMX219_TEST_PATTERN_SOLID_COLOR 1
|
||||
#define IMX219_TEST_PATTERN_COLOR_BARS 2
|
||||
#define IMX219_TEST_PATTERN_GREY_COLOR 3
|
||||
#define IMX219_TEST_PATTERN_PN9 4
|
||||
#define IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS 5
|
||||
#define IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS 6
|
||||
#define IMX219_TEST_PATTERN_COLUMN_COUNTER 7
|
||||
#define IMX219_TEST_PATTERN_INV_COLUMN_COUNTER 8
|
||||
#define IMX219_TEST_PATTERN_PN31 9
|
||||
|
||||
/* Test pattern colour components */
|
||||
#define IMX219_REG_TESTP_RED CCI_REG16(0x0602)
|
||||
|
|
@ -238,7 +243,12 @@ static const char * const imx219_test_pattern_menu[] = {
|
|||
"Color Bars",
|
||||
"Solid Color",
|
||||
"Grey Color Bars",
|
||||
"PN9"
|
||||
"PN9",
|
||||
"16 Split Color Bars",
|
||||
"16 Split Inverted Color Bars",
|
||||
"Column Counter",
|
||||
"Inverted Column Counter",
|
||||
"PN31"
|
||||
};
|
||||
|
||||
static const int imx219_test_pattern_val[] = {
|
||||
|
|
@ -247,6 +257,11 @@ static const int imx219_test_pattern_val[] = {
|
|||
IMX219_TEST_PATTERN_SOLID_COLOR,
|
||||
IMX219_TEST_PATTERN_GREY_COLOR,
|
||||
IMX219_TEST_PATTERN_PN9,
|
||||
IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS,
|
||||
IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS,
|
||||
IMX219_TEST_PATTERN_COLUMN_COUNTER,
|
||||
IMX219_TEST_PATTERN_INV_COLUMN_COUNTER,
|
||||
IMX219_TEST_PATTERN_PN31
|
||||
};
|
||||
|
||||
/* regulator supplies */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -13,38 +13,39 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
/* Streaming Mode */
|
||||
#define IMX412_REG_MODE_SELECT 0x0100
|
||||
#define IMX412_REG_MODE_SELECT CCI_REG8(0x0100)
|
||||
#define IMX412_MODE_STANDBY 0x00
|
||||
#define IMX412_MODE_STREAMING 0x01
|
||||
|
||||
/* Lines per frame */
|
||||
#define IMX412_REG_LPFR 0x0340
|
||||
#define IMX412_REG_LPFR CCI_REG16(0x0340)
|
||||
|
||||
/* Chip ID */
|
||||
#define IMX412_REG_ID 0x0016
|
||||
#define IMX412_REG_ID CCI_REG16(0x0016)
|
||||
#define IMX412_ID 0x577
|
||||
|
||||
/* Exposure control */
|
||||
#define IMX412_REG_EXPOSURE_CIT 0x0202
|
||||
#define IMX412_REG_EXPOSURE_CIT CCI_REG16(0x0202)
|
||||
#define IMX412_EXPOSURE_MIN 8
|
||||
#define IMX412_EXPOSURE_OFFSET 22
|
||||
#define IMX412_EXPOSURE_STEP 1
|
||||
#define IMX412_EXPOSURE_DEFAULT 0x0648
|
||||
|
||||
/* Analog gain control */
|
||||
#define IMX412_REG_AGAIN 0x0204
|
||||
#define IMX412_REG_AGAIN CCI_REG16(0x0204)
|
||||
#define IMX412_AGAIN_MIN 0
|
||||
#define IMX412_AGAIN_MAX 978
|
||||
#define IMX412_AGAIN_STEP 1
|
||||
#define IMX412_AGAIN_DEFAULT 0
|
||||
|
||||
/* Group hold register */
|
||||
#define IMX412_REG_HOLD 0x0104
|
||||
#define IMX412_REG_HOLD CCI_REG8(0x0104)
|
||||
|
||||
/* Input clock rate */
|
||||
#define IMX412_INCLK_RATE 24000000
|
||||
|
|
@ -56,16 +57,6 @@
|
|||
#define IMX412_REG_MIN 0x00
|
||||
#define IMX412_REG_MAX 0xffff
|
||||
|
||||
/**
|
||||
* struct imx412_reg - imx412 sensor register
|
||||
* @address: Register address
|
||||
* @val: Register value
|
||||
*/
|
||||
struct imx412_reg {
|
||||
u16 address;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct imx412_reg_list - imx412 sensor register list
|
||||
* @num_of_regs: Number of registers in the list
|
||||
|
|
@ -73,7 +64,7 @@ struct imx412_reg {
|
|||
*/
|
||||
struct imx412_reg_list {
|
||||
u32 num_of_regs;
|
||||
const struct imx412_reg *regs;
|
||||
const struct cci_reg_sequence *regs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -111,6 +102,7 @@ static const char * const imx412_supply_names[] = {
|
|||
/**
|
||||
* struct imx412 - imx412 sensor device structure
|
||||
* @dev: Pointer to generic device
|
||||
* @cci: CCI register map
|
||||
* @client: Pointer to i2c client
|
||||
* @sd: V4L2 sub-device
|
||||
* @pad: Media pad. Only one pad supported
|
||||
|
|
@ -126,10 +118,10 @@ static const char * const imx412_supply_names[] = {
|
|||
* @again_ctrl: Pointer to analog gain control
|
||||
* @vblank: Vertical blanking in lines
|
||||
* @cur_mode: Pointer to current selected sensor mode
|
||||
* @mutex: Mutex for serializing sensor controls
|
||||
*/
|
||||
struct imx412 {
|
||||
struct device *dev;
|
||||
struct regmap *cci;
|
||||
struct i2c_client *client;
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
|
@ -147,7 +139,6 @@ struct imx412 {
|
|||
};
|
||||
u32 vblank;
|
||||
const struct imx412_mode *cur_mode;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static const s64 link_freq[] = {
|
||||
|
|
@ -155,238 +146,238 @@ static const s64 link_freq[] = {
|
|||
};
|
||||
|
||||
/* Sensor mode registers */
|
||||
static const struct imx412_reg mode_4056x3040_regs[] = {
|
||||
{0x0136, 0x18},
|
||||
{0x0137, 0x00},
|
||||
{0x3c7e, 0x08},
|
||||
{0x3c7f, 0x02},
|
||||
{0x38a8, 0x1f},
|
||||
{0x38a9, 0xff},
|
||||
{0x38aa, 0x1f},
|
||||
{0x38ab, 0xff},
|
||||
{0x55d4, 0x00},
|
||||
{0x55d5, 0x00},
|
||||
{0x55d6, 0x07},
|
||||
{0x55d7, 0xff},
|
||||
{0x55e8, 0x07},
|
||||
{0x55e9, 0xff},
|
||||
{0x55ea, 0x00},
|
||||
{0x55eb, 0x00},
|
||||
{0x575c, 0x07},
|
||||
{0x575d, 0xff},
|
||||
{0x575e, 0x00},
|
||||
{0x575f, 0x00},
|
||||
{0x5764, 0x00},
|
||||
{0x5765, 0x00},
|
||||
{0x5766, 0x07},
|
||||
{0x5767, 0xff},
|
||||
{0x5974, 0x04},
|
||||
{0x5975, 0x01},
|
||||
{0x5f10, 0x09},
|
||||
{0x5f11, 0x92},
|
||||
{0x5f12, 0x32},
|
||||
{0x5f13, 0x72},
|
||||
{0x5f14, 0x16},
|
||||
{0x5f15, 0xba},
|
||||
{0x5f17, 0x13},
|
||||
{0x5f18, 0x24},
|
||||
{0x5f19, 0x60},
|
||||
{0x5f1a, 0xe3},
|
||||
{0x5f1b, 0xad},
|
||||
{0x5f1c, 0x74},
|
||||
{0x5f2d, 0x25},
|
||||
{0x5f5c, 0xd0},
|
||||
{0x6a22, 0x00},
|
||||
{0x6a23, 0x1d},
|
||||
{0x7ba8, 0x00},
|
||||
{0x7ba9, 0x00},
|
||||
{0x886b, 0x00},
|
||||
{0x9002, 0x0a},
|
||||
{0x9004, 0x1a},
|
||||
{0x9214, 0x93},
|
||||
{0x9215, 0x69},
|
||||
{0x9216, 0x93},
|
||||
{0x9217, 0x6b},
|
||||
{0x9218, 0x93},
|
||||
{0x9219, 0x6d},
|
||||
{0x921a, 0x57},
|
||||
{0x921b, 0x58},
|
||||
{0x921c, 0x57},
|
||||
{0x921d, 0x59},
|
||||
{0x921e, 0x57},
|
||||
{0x921f, 0x5a},
|
||||
{0x9220, 0x57},
|
||||
{0x9221, 0x5b},
|
||||
{0x9222, 0x93},
|
||||
{0x9223, 0x02},
|
||||
{0x9224, 0x93},
|
||||
{0x9225, 0x03},
|
||||
{0x9226, 0x93},
|
||||
{0x9227, 0x04},
|
||||
{0x9228, 0x93},
|
||||
{0x9229, 0x05},
|
||||
{0x922a, 0x98},
|
||||
{0x922b, 0x21},
|
||||
{0x922c, 0xb2},
|
||||
{0x922d, 0xdb},
|
||||
{0x922e, 0xb2},
|
||||
{0x922f, 0xdc},
|
||||
{0x9230, 0xb2},
|
||||
{0x9231, 0xdd},
|
||||
{0x9232, 0xe2},
|
||||
{0x9233, 0xe1},
|
||||
{0x9234, 0xb2},
|
||||
{0x9235, 0xe2},
|
||||
{0x9236, 0xb2},
|
||||
{0x9237, 0xe3},
|
||||
{0x9238, 0xb7},
|
||||
{0x9239, 0xb9},
|
||||
{0x923a, 0xb7},
|
||||
{0x923b, 0xbb},
|
||||
{0x923c, 0xb7},
|
||||
{0x923d, 0xbc},
|
||||
{0x923e, 0xb7},
|
||||
{0x923f, 0xc5},
|
||||
{0x9240, 0xb7},
|
||||
{0x9241, 0xc7},
|
||||
{0x9242, 0xb7},
|
||||
{0x9243, 0xc9},
|
||||
{0x9244, 0x98},
|
||||
{0x9245, 0x56},
|
||||
{0x9246, 0x98},
|
||||
{0x9247, 0x55},
|
||||
{0x9380, 0x00},
|
||||
{0x9381, 0x62},
|
||||
{0x9382, 0x00},
|
||||
{0x9383, 0x56},
|
||||
{0x9384, 0x00},
|
||||
{0x9385, 0x52},
|
||||
{0x9388, 0x00},
|
||||
{0x9389, 0x55},
|
||||
{0x938a, 0x00},
|
||||
{0x938b, 0x55},
|
||||
{0x938c, 0x00},
|
||||
{0x938d, 0x41},
|
||||
{0x5078, 0x01},
|
||||
{0x0112, 0x0a},
|
||||
{0x0113, 0x0a},
|
||||
{0x0114, 0x03},
|
||||
{0x0342, 0x11},
|
||||
{0x0343, 0xa0},
|
||||
{0x0340, 0x0d},
|
||||
{0x0341, 0xda},
|
||||
{0x3210, 0x00},
|
||||
{0x0344, 0x00},
|
||||
{0x0345, 0x00},
|
||||
{0x0346, 0x00},
|
||||
{0x0347, 0x00},
|
||||
{0x0348, 0x0f},
|
||||
{0x0349, 0xd7},
|
||||
{0x034a, 0x0b},
|
||||
{0x034b, 0xdf},
|
||||
{0x00e3, 0x00},
|
||||
{0x00e4, 0x00},
|
||||
{0x00e5, 0x01},
|
||||
{0x00fc, 0x0a},
|
||||
{0x00fd, 0x0a},
|
||||
{0x00fe, 0x0a},
|
||||
{0x00ff, 0x0a},
|
||||
{0xe013, 0x00},
|
||||
{0x0220, 0x00},
|
||||
{0x0221, 0x11},
|
||||
{0x0381, 0x01},
|
||||
{0x0383, 0x01},
|
||||
{0x0385, 0x01},
|
||||
{0x0387, 0x01},
|
||||
{0x0900, 0x00},
|
||||
{0x0901, 0x11},
|
||||
{0x0902, 0x00},
|
||||
{0x3140, 0x02},
|
||||
{0x3241, 0x11},
|
||||
{0x3250, 0x03},
|
||||
{0x3e10, 0x00},
|
||||
{0x3e11, 0x00},
|
||||
{0x3f0d, 0x00},
|
||||
{0x3f42, 0x00},
|
||||
{0x3f43, 0x00},
|
||||
{0x0401, 0x00},
|
||||
{0x0404, 0x00},
|
||||
{0x0405, 0x10},
|
||||
{0x0408, 0x00},
|
||||
{0x0409, 0x00},
|
||||
{0x040a, 0x00},
|
||||
{0x040b, 0x00},
|
||||
{0x040c, 0x0f},
|
||||
{0x040d, 0xd8},
|
||||
{0x040e, 0x0b},
|
||||
{0x040f, 0xe0},
|
||||
{0x034c, 0x0f},
|
||||
{0x034d, 0xd8},
|
||||
{0x034e, 0x0b},
|
||||
{0x034f, 0xe0},
|
||||
{0x0301, 0x05},
|
||||
{0x0303, 0x02},
|
||||
{0x0305, 0x04},
|
||||
{0x0306, 0x00},
|
||||
{0x0307, 0xc8},
|
||||
{0x0309, 0x0a},
|
||||
{0x030b, 0x01},
|
||||
{0x030d, 0x02},
|
||||
{0x030e, 0x01},
|
||||
{0x030f, 0x5e},
|
||||
{0x0310, 0x00},
|
||||
{0x0820, 0x12},
|
||||
{0x0821, 0xc0},
|
||||
{0x0822, 0x00},
|
||||
{0x0823, 0x00},
|
||||
{0x3e20, 0x01},
|
||||
{0x3e37, 0x00},
|
||||
{0x3f50, 0x00},
|
||||
{0x3f56, 0x00},
|
||||
{0x3f57, 0xe2},
|
||||
{0x3c0a, 0x5a},
|
||||
{0x3c0b, 0x55},
|
||||
{0x3c0c, 0x28},
|
||||
{0x3c0d, 0x07},
|
||||
{0x3c0e, 0xff},
|
||||
{0x3c0f, 0x00},
|
||||
{0x3c10, 0x00},
|
||||
{0x3c11, 0x02},
|
||||
{0x3c12, 0x00},
|
||||
{0x3c13, 0x03},
|
||||
{0x3c14, 0x00},
|
||||
{0x3c15, 0x00},
|
||||
{0x3c16, 0x0c},
|
||||
{0x3c17, 0x0c},
|
||||
{0x3c18, 0x0c},
|
||||
{0x3c19, 0x0a},
|
||||
{0x3c1a, 0x0a},
|
||||
{0x3c1b, 0x0a},
|
||||
{0x3c1c, 0x00},
|
||||
{0x3c1d, 0x00},
|
||||
{0x3c1e, 0x00},
|
||||
{0x3c1f, 0x00},
|
||||
{0x3c20, 0x00},
|
||||
{0x3c21, 0x00},
|
||||
{0x3c22, 0x3f},
|
||||
{0x3c23, 0x0a},
|
||||
{0x3e35, 0x01},
|
||||
{0x3f4a, 0x03},
|
||||
{0x3f4b, 0xbf},
|
||||
{0x3f26, 0x00},
|
||||
{0x0202, 0x0d},
|
||||
{0x0203, 0xc4},
|
||||
{0x0204, 0x00},
|
||||
{0x0205, 0x00},
|
||||
{0x020e, 0x01},
|
||||
{0x020f, 0x00},
|
||||
{0x0210, 0x01},
|
||||
{0x0211, 0x00},
|
||||
{0x0212, 0x01},
|
||||
{0x0213, 0x00},
|
||||
{0x0214, 0x01},
|
||||
{0x0215, 0x00},
|
||||
{0xbcf1, 0x00},
|
||||
static const struct cci_reg_sequence mode_4056x3040_regs[] = {
|
||||
{ CCI_REG8(0x0136), 0x18 },
|
||||
{ CCI_REG8(0x0137), 0x00 },
|
||||
{ CCI_REG8(0x3c7e), 0x08 },
|
||||
{ CCI_REG8(0x3c7f), 0x02 },
|
||||
{ CCI_REG8(0x38a8), 0x1f },
|
||||
{ CCI_REG8(0x38a9), 0xff },
|
||||
{ CCI_REG8(0x38aa), 0x1f },
|
||||
{ CCI_REG8(0x38ab), 0xff },
|
||||
{ CCI_REG8(0x55d4), 0x00 },
|
||||
{ CCI_REG8(0x55d5), 0x00 },
|
||||
{ CCI_REG8(0x55d6), 0x07 },
|
||||
{ CCI_REG8(0x55d7), 0xff },
|
||||
{ CCI_REG8(0x55e8), 0x07 },
|
||||
{ CCI_REG8(0x55e9), 0xff },
|
||||
{ CCI_REG8(0x55ea), 0x00 },
|
||||
{ CCI_REG8(0x55eb), 0x00 },
|
||||
{ CCI_REG8(0x575c), 0x07 },
|
||||
{ CCI_REG8(0x575d), 0xff },
|
||||
{ CCI_REG8(0x575e), 0x00 },
|
||||
{ CCI_REG8(0x575f), 0x00 },
|
||||
{ CCI_REG8(0x5764), 0x00 },
|
||||
{ CCI_REG8(0x5765), 0x00 },
|
||||
{ CCI_REG8(0x5766), 0x07 },
|
||||
{ CCI_REG8(0x5767), 0xff },
|
||||
{ CCI_REG8(0x5974), 0x04 },
|
||||
{ CCI_REG8(0x5975), 0x01 },
|
||||
{ CCI_REG8(0x5f10), 0x09 },
|
||||
{ CCI_REG8(0x5f11), 0x92 },
|
||||
{ CCI_REG8(0x5f12), 0x32 },
|
||||
{ CCI_REG8(0x5f13), 0x72 },
|
||||
{ CCI_REG8(0x5f14), 0x16 },
|
||||
{ CCI_REG8(0x5f15), 0xba },
|
||||
{ CCI_REG8(0x5f17), 0x13 },
|
||||
{ CCI_REG8(0x5f18), 0x24 },
|
||||
{ CCI_REG8(0x5f19), 0x60 },
|
||||
{ CCI_REG8(0x5f1a), 0xe3 },
|
||||
{ CCI_REG8(0x5f1b), 0xad },
|
||||
{ CCI_REG8(0x5f1c), 0x74 },
|
||||
{ CCI_REG8(0x5f2d), 0x25 },
|
||||
{ CCI_REG8(0x5f5c), 0xd0 },
|
||||
{ CCI_REG8(0x6a22), 0x00 },
|
||||
{ CCI_REG8(0x6a23), 0x1d },
|
||||
{ CCI_REG8(0x7ba8), 0x00 },
|
||||
{ CCI_REG8(0x7ba9), 0x00 },
|
||||
{ CCI_REG8(0x886b), 0x00 },
|
||||
{ CCI_REG8(0x9002), 0x0a },
|
||||
{ CCI_REG8(0x9004), 0x1a },
|
||||
{ CCI_REG8(0x9214), 0x93 },
|
||||
{ CCI_REG8(0x9215), 0x69 },
|
||||
{ CCI_REG8(0x9216), 0x93 },
|
||||
{ CCI_REG8(0x9217), 0x6b },
|
||||
{ CCI_REG8(0x9218), 0x93 },
|
||||
{ CCI_REG8(0x9219), 0x6d },
|
||||
{ CCI_REG8(0x921a), 0x57 },
|
||||
{ CCI_REG8(0x921b), 0x58 },
|
||||
{ CCI_REG8(0x921c), 0x57 },
|
||||
{ CCI_REG8(0x921d), 0x59 },
|
||||
{ CCI_REG8(0x921e), 0x57 },
|
||||
{ CCI_REG8(0x921f), 0x5a },
|
||||
{ CCI_REG8(0x9220), 0x57 },
|
||||
{ CCI_REG8(0x9221), 0x5b },
|
||||
{ CCI_REG8(0x9222), 0x93 },
|
||||
{ CCI_REG8(0x9223), 0x02 },
|
||||
{ CCI_REG8(0x9224), 0x93 },
|
||||
{ CCI_REG8(0x9225), 0x03 },
|
||||
{ CCI_REG8(0x9226), 0x93 },
|
||||
{ CCI_REG8(0x9227), 0x04 },
|
||||
{ CCI_REG8(0x9228), 0x93 },
|
||||
{ CCI_REG8(0x9229), 0x05 },
|
||||
{ CCI_REG8(0x922a), 0x98 },
|
||||
{ CCI_REG8(0x922b), 0x21 },
|
||||
{ CCI_REG8(0x922c), 0xb2 },
|
||||
{ CCI_REG8(0x922d), 0xdb },
|
||||
{ CCI_REG8(0x922e), 0xb2 },
|
||||
{ CCI_REG8(0x922f), 0xdc },
|
||||
{ CCI_REG8(0x9230), 0xb2 },
|
||||
{ CCI_REG8(0x9231), 0xdd },
|
||||
{ CCI_REG8(0x9232), 0xe2 },
|
||||
{ CCI_REG8(0x9233), 0xe1 },
|
||||
{ CCI_REG8(0x9234), 0xb2 },
|
||||
{ CCI_REG8(0x9235), 0xe2 },
|
||||
{ CCI_REG8(0x9236), 0xb2 },
|
||||
{ CCI_REG8(0x9237), 0xe3 },
|
||||
{ CCI_REG8(0x9238), 0xb7 },
|
||||
{ CCI_REG8(0x9239), 0xb9 },
|
||||
{ CCI_REG8(0x923a), 0xb7 },
|
||||
{ CCI_REG8(0x923b), 0xbb },
|
||||
{ CCI_REG8(0x923c), 0xb7 },
|
||||
{ CCI_REG8(0x923d), 0xbc },
|
||||
{ CCI_REG8(0x923e), 0xb7 },
|
||||
{ CCI_REG8(0x923f), 0xc5 },
|
||||
{ CCI_REG8(0x9240), 0xb7 },
|
||||
{ CCI_REG8(0x9241), 0xc7 },
|
||||
{ CCI_REG8(0x9242), 0xb7 },
|
||||
{ CCI_REG8(0x9243), 0xc9 },
|
||||
{ CCI_REG8(0x9244), 0x98 },
|
||||
{ CCI_REG8(0x9245), 0x56 },
|
||||
{ CCI_REG8(0x9246), 0x98 },
|
||||
{ CCI_REG8(0x9247), 0x55 },
|
||||
{ CCI_REG8(0x9380), 0x00 },
|
||||
{ CCI_REG8(0x9381), 0x62 },
|
||||
{ CCI_REG8(0x9382), 0x00 },
|
||||
{ CCI_REG8(0x9383), 0x56 },
|
||||
{ CCI_REG8(0x9384), 0x00 },
|
||||
{ CCI_REG8(0x9385), 0x52 },
|
||||
{ CCI_REG8(0x9388), 0x00 },
|
||||
{ CCI_REG8(0x9389), 0x55 },
|
||||
{ CCI_REG8(0x938a), 0x00 },
|
||||
{ CCI_REG8(0x938b), 0x55 },
|
||||
{ CCI_REG8(0x938c), 0x00 },
|
||||
{ CCI_REG8(0x938d), 0x41 },
|
||||
{ CCI_REG8(0x5078), 0x01 },
|
||||
{ CCI_REG8(0x0112), 0x0a },
|
||||
{ CCI_REG8(0x0113), 0x0a },
|
||||
{ CCI_REG8(0x0114), 0x03 },
|
||||
{ CCI_REG8(0x0342), 0x11 },
|
||||
{ CCI_REG8(0x0343), 0xa0 },
|
||||
{ CCI_REG8(0x0340), 0x0d },
|
||||
{ CCI_REG8(0x0341), 0xda },
|
||||
{ CCI_REG8(0x3210), 0x00 },
|
||||
{ CCI_REG8(0x0344), 0x00 },
|
||||
{ CCI_REG8(0x0345), 0x00 },
|
||||
{ CCI_REG8(0x0346), 0x00 },
|
||||
{ CCI_REG8(0x0347), 0x00 },
|
||||
{ CCI_REG8(0x0348), 0x0f },
|
||||
{ CCI_REG8(0x0349), 0xd7 },
|
||||
{ CCI_REG8(0x034a), 0x0b },
|
||||
{ CCI_REG8(0x034b), 0xdf },
|
||||
{ CCI_REG8(0x00e3), 0x00 },
|
||||
{ CCI_REG8(0x00e4), 0x00 },
|
||||
{ CCI_REG8(0x00e5), 0x01 },
|
||||
{ CCI_REG8(0x00fc), 0x0a },
|
||||
{ CCI_REG8(0x00fd), 0x0a },
|
||||
{ CCI_REG8(0x00fe), 0x0a },
|
||||
{ CCI_REG8(0x00ff), 0x0a },
|
||||
{ CCI_REG8(0xe013), 0x00 },
|
||||
{ CCI_REG8(0x0220), 0x00 },
|
||||
{ CCI_REG8(0x0221), 0x11 },
|
||||
{ CCI_REG8(0x0381), 0x01 },
|
||||
{ CCI_REG8(0x0383), 0x01 },
|
||||
{ CCI_REG8(0x0385), 0x01 },
|
||||
{ CCI_REG8(0x0387), 0x01 },
|
||||
{ CCI_REG8(0x0900), 0x00 },
|
||||
{ CCI_REG8(0x0901), 0x11 },
|
||||
{ CCI_REG8(0x0902), 0x00 },
|
||||
{ CCI_REG8(0x3140), 0x02 },
|
||||
{ CCI_REG8(0x3241), 0x11 },
|
||||
{ CCI_REG8(0x3250), 0x03 },
|
||||
{ CCI_REG8(0x3e10), 0x00 },
|
||||
{ CCI_REG8(0x3e11), 0x00 },
|
||||
{ CCI_REG8(0x3f0d), 0x00 },
|
||||
{ CCI_REG8(0x3f42), 0x00 },
|
||||
{ CCI_REG8(0x3f43), 0x00 },
|
||||
{ CCI_REG8(0x0401), 0x00 },
|
||||
{ CCI_REG8(0x0404), 0x00 },
|
||||
{ CCI_REG8(0x0405), 0x10 },
|
||||
{ CCI_REG8(0x0408), 0x00 },
|
||||
{ CCI_REG8(0x0409), 0x00 },
|
||||
{ CCI_REG8(0x040a), 0x00 },
|
||||
{ CCI_REG8(0x040b), 0x00 },
|
||||
{ CCI_REG8(0x040c), 0x0f },
|
||||
{ CCI_REG8(0x040d), 0xd8 },
|
||||
{ CCI_REG8(0x040e), 0x0b },
|
||||
{ CCI_REG8(0x040f), 0xe0 },
|
||||
{ CCI_REG8(0x034c), 0x0f },
|
||||
{ CCI_REG8(0x034d), 0xd8 },
|
||||
{ CCI_REG8(0x034e), 0x0b },
|
||||
{ CCI_REG8(0x034f), 0xe0 },
|
||||
{ CCI_REG8(0x0301), 0x05 },
|
||||
{ CCI_REG8(0x0303), 0x02 },
|
||||
{ CCI_REG8(0x0305), 0x04 },
|
||||
{ CCI_REG8(0x0306), 0x00 },
|
||||
{ CCI_REG8(0x0307), 0xc8 },
|
||||
{ CCI_REG8(0x0309), 0x0a },
|
||||
{ CCI_REG8(0x030b), 0x01 },
|
||||
{ CCI_REG8(0x030d), 0x02 },
|
||||
{ CCI_REG8(0x030e), 0x01 },
|
||||
{ CCI_REG8(0x030f), 0x5e },
|
||||
{ CCI_REG8(0x0310), 0x00 },
|
||||
{ CCI_REG8(0x0820), 0x12 },
|
||||
{ CCI_REG8(0x0821), 0xc0 },
|
||||
{ CCI_REG8(0x0822), 0x00 },
|
||||
{ CCI_REG8(0x0823), 0x00 },
|
||||
{ CCI_REG8(0x3e20), 0x01 },
|
||||
{ CCI_REG8(0x3e37), 0x00 },
|
||||
{ CCI_REG8(0x3f50), 0x00 },
|
||||
{ CCI_REG8(0x3f56), 0x00 },
|
||||
{ CCI_REG8(0x3f57), 0xe2 },
|
||||
{ CCI_REG8(0x3c0a), 0x5a },
|
||||
{ CCI_REG8(0x3c0b), 0x55 },
|
||||
{ CCI_REG8(0x3c0c), 0x28 },
|
||||
{ CCI_REG8(0x3c0d), 0x07 },
|
||||
{ CCI_REG8(0x3c0e), 0xff },
|
||||
{ CCI_REG8(0x3c0f), 0x00 },
|
||||
{ CCI_REG8(0x3c10), 0x00 },
|
||||
{ CCI_REG8(0x3c11), 0x02 },
|
||||
{ CCI_REG8(0x3c12), 0x00 },
|
||||
{ CCI_REG8(0x3c13), 0x03 },
|
||||
{ CCI_REG8(0x3c14), 0x00 },
|
||||
{ CCI_REG8(0x3c15), 0x00 },
|
||||
{ CCI_REG8(0x3c16), 0x0c },
|
||||
{ CCI_REG8(0x3c17), 0x0c },
|
||||
{ CCI_REG8(0x3c18), 0x0c },
|
||||
{ CCI_REG8(0x3c19), 0x0a },
|
||||
{ CCI_REG8(0x3c1a), 0x0a },
|
||||
{ CCI_REG8(0x3c1b), 0x0a },
|
||||
{ CCI_REG8(0x3c1c), 0x00 },
|
||||
{ CCI_REG8(0x3c1d), 0x00 },
|
||||
{ CCI_REG8(0x3c1e), 0x00 },
|
||||
{ CCI_REG8(0x3c1f), 0x00 },
|
||||
{ CCI_REG8(0x3c20), 0x00 },
|
||||
{ CCI_REG8(0x3c21), 0x00 },
|
||||
{ CCI_REG8(0x3c22), 0x3f },
|
||||
{ CCI_REG8(0x3c23), 0x0a },
|
||||
{ CCI_REG8(0x3e35), 0x01 },
|
||||
{ CCI_REG8(0x3f4a), 0x03 },
|
||||
{ CCI_REG8(0x3f4b), 0xbf },
|
||||
{ CCI_REG8(0x3f26), 0x00 },
|
||||
{ CCI_REG8(0x0202), 0x0d },
|
||||
{ CCI_REG8(0x0203), 0xc4 },
|
||||
{ CCI_REG8(0x0204), 0x00 },
|
||||
{ CCI_REG8(0x0205), 0x00 },
|
||||
{ CCI_REG8(0x020e), 0x01 },
|
||||
{ CCI_REG8(0x020f), 0x00 },
|
||||
{ CCI_REG8(0x0210), 0x01 },
|
||||
{ CCI_REG8(0x0211), 0x00 },
|
||||
{ CCI_REG8(0x0212), 0x01 },
|
||||
{ CCI_REG8(0x0213), 0x00 },
|
||||
{ CCI_REG8(0x0214), 0x01 },
|
||||
{ CCI_REG8(0x0215), 0x00 },
|
||||
{ CCI_REG8(0xbcf1), 0x00 },
|
||||
};
|
||||
|
||||
/* Supported sensor mode configurations */
|
||||
|
|
@ -417,97 +408,6 @@ static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev)
|
|||
return container_of(subdev, struct imx412, sd);
|
||||
}
|
||||
|
||||
/**
|
||||
* imx412_read_reg() - Read registers.
|
||||
* @imx412: pointer to imx412 device
|
||||
* @reg: register address
|
||||
* @len: length of bytes to read. Max supported bytes is 4
|
||||
* @val: pointer to register value to be filled.
|
||||
*
|
||||
* Return: 0 if successful, error code otherwise.
|
||||
*/
|
||||
static int imx412_read_reg(struct imx412 *imx412, u16 reg, u32 len, u32 *val)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd);
|
||||
struct i2c_msg msgs[2] = {0};
|
||||
u8 addr_buf[2] = {0};
|
||||
u8 data_buf[4] = {0};
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(len > 4))
|
||||
return -EINVAL;
|
||||
|
||||
put_unaligned_be16(reg, addr_buf);
|
||||
|
||||
/* Write register address */
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = ARRAY_SIZE(addr_buf);
|
||||
msgs[0].buf = addr_buf;
|
||||
|
||||
/* Read data from register */
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = &data_buf[4 - len];
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret != ARRAY_SIZE(msgs))
|
||||
return -EIO;
|
||||
|
||||
*val = get_unaligned_be32(data_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* imx412_write_reg() - Write register
|
||||
* @imx412: pointer to imx412 device
|
||||
* @reg: register address
|
||||
* @len: length of bytes. Max supported bytes is 4
|
||||
* @val: register value
|
||||
*
|
||||
* Return: 0 if successful, error code otherwise.
|
||||
*/
|
||||
static int imx412_write_reg(struct imx412 *imx412, u16 reg, u32 len, u32 val)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd);
|
||||
u8 buf[6] = {0};
|
||||
|
||||
if (WARN_ON(len > 4))
|
||||
return -EINVAL;
|
||||
|
||||
put_unaligned_be16(reg, buf);
|
||||
put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
|
||||
if (i2c_master_send(client, buf, len + 2) != len + 2)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* imx412_write_regs() - Write a list of registers
|
||||
* @imx412: pointer to imx412 device
|
||||
* @regs: list of registers to be written
|
||||
* @len: length of registers array
|
||||
*
|
||||
* Return: 0 if successful, error code otherwise.
|
||||
*/
|
||||
static int imx412_write_regs(struct imx412 *imx412,
|
||||
const struct imx412_reg *regs, u32 len)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
ret = imx412_write_reg(imx412, regs[i].address, 1, regs[i].val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* imx412_update_controls() - Update control ranges based on streaming mode
|
||||
* @imx412: pointer to imx412 device
|
||||
|
|
@ -543,29 +443,25 @@ static int imx412_update_controls(struct imx412 *imx412,
|
|||
static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
|
||||
{
|
||||
u32 lpfr;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int ret_hold;
|
||||
|
||||
lpfr = imx412->vblank + imx412->cur_mode->height;
|
||||
|
||||
dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u\n",
|
||||
exposure, gain, lpfr);
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
cci_write(imx412->cci, IMX412_REG_HOLD, 1, &ret);
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr);
|
||||
if (ret)
|
||||
goto error_release_group_hold;
|
||||
cci_write(imx412->cci, IMX412_REG_LPFR, lpfr, &ret);
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure);
|
||||
if (ret)
|
||||
goto error_release_group_hold;
|
||||
cci_write(imx412->cci, IMX412_REG_EXPOSURE_CIT, exposure, &ret);
|
||||
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain);
|
||||
cci_write(imx412->cci, IMX412_REG_AGAIN, gain, &ret);
|
||||
|
||||
error_release_group_hold:
|
||||
imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0);
|
||||
ret_hold = cci_write(imx412->cci, IMX412_REG_HOLD, 0, NULL);
|
||||
if (ret_hold)
|
||||
return ret_hold;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -679,8 +575,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd,
|
|||
{
|
||||
struct imx412 *imx412 = to_imx412(sd);
|
||||
|
||||
mutex_lock(&imx412->mutex);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
struct v4l2_mbus_framefmt *framefmt;
|
||||
|
||||
|
|
@ -690,8 +584,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd,
|
|||
imx412_fill_pad_format(imx412, imx412->cur_mode, fmt);
|
||||
}
|
||||
|
||||
mutex_unlock(&imx412->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -703,8 +595,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd,
|
|||
const struct imx412_mode *mode;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&imx412->mutex);
|
||||
|
||||
mode = &supported_mode;
|
||||
imx412_fill_pad_format(imx412, mode, fmt);
|
||||
|
||||
|
|
@ -719,8 +609,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd,
|
|||
imx412->cur_mode = mode;
|
||||
}
|
||||
|
||||
mutex_unlock(&imx412->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -737,88 +625,86 @@ static int imx412_init_state(struct v4l2_subdev *sd,
|
|||
}
|
||||
|
||||
/**
|
||||
* imx412_start_streaming() - Start sensor stream
|
||||
* @imx412: pointer to imx412 device
|
||||
* imx412_enable_streams() - Enable specified streams for the sensor
|
||||
* @sd: pointer to the V4L2 subdevice
|
||||
* @state: pointer to the subdevice state
|
||||
* @pad: pad number for which streams are enabled
|
||||
* @streams_mask: bitmask specifying the streams to enable
|
||||
*
|
||||
* Return: 0 if successful, error code otherwise.
|
||||
*/
|
||||
static int imx412_start_streaming(struct imx412 *imx412)
|
||||
static int imx412_enable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
const struct imx412_reg_list *reg_list;
|
||||
struct imx412 *imx412 = to_imx412(sd);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(imx412->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Write sensor mode registers */
|
||||
reg_list = &imx412->cur_mode->reg_list;
|
||||
ret = imx412_write_regs(imx412, reg_list->regs,
|
||||
reg_list->num_of_regs);
|
||||
ret = cci_multi_reg_write(imx412->cci, reg_list->regs,
|
||||
reg_list->num_of_regs, NULL);
|
||||
if (ret) {
|
||||
dev_err(imx412->dev, "fail to write initial registers\n");
|
||||
return ret;
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
/* Setup handler will write actual exposure and gain */
|
||||
ret = __v4l2_ctrl_handler_setup(imx412->sd.ctrl_handler);
|
||||
if (ret) {
|
||||
dev_err(imx412->dev, "fail to setup handler\n");
|
||||
return ret;
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
/* Delay is required before streaming*/
|
||||
usleep_range(7400, 8000);
|
||||
|
||||
/* Start streaming */
|
||||
ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT,
|
||||
1, IMX412_MODE_STREAMING);
|
||||
ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT,
|
||||
IMX412_MODE_STREAMING, NULL);
|
||||
if (ret) {
|
||||
dev_err(imx412->dev, "fail to start streaming\n");
|
||||
return ret;
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_rpm_put:
|
||||
pm_runtime_put(imx412->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* imx412_stop_streaming() - Stop sensor stream
|
||||
* @imx412: pointer to imx412 device
|
||||
* imx412_disable_streams() - Enable specified streams for the sensor
|
||||
* @sd: pointer to the V4L2 subdevice
|
||||
* @state: pointer to the subdevice state
|
||||
* @pad: pad number for which streams are disabled
|
||||
* @streams_mask: bitmask specifying the streams to disable
|
||||
*
|
||||
* Return: 0 if successful, error code otherwise.
|
||||
*/
|
||||
static int imx412_stop_streaming(struct imx412 *imx412)
|
||||
{
|
||||
return imx412_write_reg(imx412, IMX412_REG_MODE_SELECT,
|
||||
1, IMX412_MODE_STANDBY);
|
||||
}
|
||||
|
||||
static int imx412_set_stream(struct v4l2_subdev *sd, int enable)
|
||||
static int imx412_disable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct imx412 *imx412 = to_imx412(sd);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&imx412->mutex);
|
||||
ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT,
|
||||
IMX412_MODE_STANDBY, NULL);
|
||||
|
||||
if (enable) {
|
||||
ret = pm_runtime_resume_and_get(imx412->dev);
|
||||
if (ret)
|
||||
goto error_unlock;
|
||||
if (ret)
|
||||
dev_err(imx412->dev, "failed to set stream off\n");
|
||||
|
||||
ret = imx412_start_streaming(imx412);
|
||||
if (ret)
|
||||
goto error_power_off;
|
||||
} else {
|
||||
imx412_stop_streaming(imx412);
|
||||
pm_runtime_put(imx412->dev);
|
||||
}
|
||||
|
||||
mutex_unlock(&imx412->mutex);
|
||||
pm_runtime_put(imx412->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_power_off:
|
||||
pm_runtime_put(imx412->dev);
|
||||
error_unlock:
|
||||
mutex_unlock(&imx412->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -830,16 +716,18 @@ static int imx412_set_stream(struct v4l2_subdev *sd, int enable)
|
|||
static int imx412_detect(struct imx412 *imx412)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
u64 val;
|
||||
|
||||
ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val);
|
||||
ret = cci_read(imx412->cci, IMX412_REG_ID, &val, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(imx412->dev, ret,
|
||||
"failed to read chip id %x\n",
|
||||
IMX412_ID);
|
||||
|
||||
if (val != IMX412_ID) {
|
||||
dev_err(imx412->dev, "chip id mismatch: %x!=%x\n",
|
||||
IMX412_ID, val);
|
||||
return -ENXIO;
|
||||
return dev_err_probe(imx412->dev, -ENODEV,
|
||||
"chip id mismatch: %x!=%llx",
|
||||
IMX412_ID, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -933,7 +821,7 @@ static int imx412_parse_hw_config(struct imx412 *imx412)
|
|||
|
||||
/* V4l2 subdevice ops */
|
||||
static const struct v4l2_subdev_video_ops imx412_video_ops = {
|
||||
.s_stream = imx412_set_stream,
|
||||
.s_stream = v4l2_subdev_s_stream_helper,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops imx412_pad_ops = {
|
||||
|
|
@ -941,6 +829,8 @@ static const struct v4l2_subdev_pad_ops imx412_pad_ops = {
|
|||
.enum_frame_size = imx412_enum_frame_size,
|
||||
.get_fmt = imx412_get_pad_format,
|
||||
.set_fmt = imx412_set_pad_format,
|
||||
.enable_streams = imx412_enable_streams,
|
||||
.disable_streams = imx412_disable_streams,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops imx412_subdev_ops = {
|
||||
|
|
@ -1021,9 +911,6 @@ static int imx412_init_controls(struct imx412 *imx412)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Serialize controls with sensor device */
|
||||
ctrl_hdlr->lock = &imx412->mutex;
|
||||
|
||||
/* Initialize exposure and gain */
|
||||
lpfr = mode->vblank + mode->height;
|
||||
imx412->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
|
||||
|
|
@ -1104,6 +991,11 @@ static int imx412_probe(struct i2c_client *client)
|
|||
if (!name)
|
||||
return -ENODEV;
|
||||
|
||||
imx412->cci = devm_cci_regmap_init_i2c(client, 16);
|
||||
if (IS_ERR(imx412->cci))
|
||||
return dev_err_probe(imx412->dev, PTR_ERR(imx412->cci),
|
||||
"Failed to init CCI\n");
|
||||
|
||||
/* Initialize subdev */
|
||||
v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops);
|
||||
imx412->sd.internal_ops = &imx412_internal_ops;
|
||||
|
|
@ -1114,13 +1006,10 @@ static int imx412_probe(struct i2c_client *client)
|
|||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&imx412->mutex);
|
||||
|
||||
ret = imx412_power_on(imx412->dev);
|
||||
if (ret) {
|
||||
dev_err(imx412->dev, "failed to power-on the sensor\n");
|
||||
goto error_mutex_destroy;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(imx412->dev, ret,
|
||||
"failed to power-on the sensor\n");
|
||||
|
||||
/* Check module identity */
|
||||
ret = imx412_detect(imx412);
|
||||
|
|
@ -1153,27 +1042,37 @@ static int imx412_probe(struct i2c_client *client)
|
|||
goto error_handler_free;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev_sensor(&imx412->sd);
|
||||
imx412->sd.state_lock = imx412->ctrl_handler.lock;
|
||||
ret = v4l2_subdev_init_finalize(&imx412->sd);
|
||||
if (ret < 0) {
|
||||
dev_err(imx412->dev,
|
||||
"failed to register async subdev: %d\n", ret);
|
||||
dev_err_probe(imx412->dev, ret, "subdev init error\n");
|
||||
goto error_media_entity;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(imx412->dev);
|
||||
pm_runtime_enable(imx412->dev);
|
||||
|
||||
ret = v4l2_async_register_subdev_sensor(&imx412->sd);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(imx412->dev, ret,
|
||||
"failed to register sub-device\n");
|
||||
goto error_subdev_cleanup;
|
||||
}
|
||||
|
||||
pm_runtime_idle(imx412->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_subdev_cleanup:
|
||||
v4l2_subdev_cleanup(&imx412->sd);
|
||||
pm_runtime_disable(imx412->dev);
|
||||
pm_runtime_set_suspended(imx412->dev);
|
||||
error_media_entity:
|
||||
media_entity_cleanup(&imx412->sd.entity);
|
||||
error_handler_free:
|
||||
v4l2_ctrl_handler_free(imx412->sd.ctrl_handler);
|
||||
error_power_off:
|
||||
imx412_power_off(imx412->dev);
|
||||
error_mutex_destroy:
|
||||
mutex_destroy(&imx412->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1181,9 +1080,9 @@ static int imx412_probe(struct i2c_client *client)
|
|||
static void imx412_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct imx412 *imx412 = to_imx412(sd);
|
||||
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
v4l2_subdev_cleanup(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
||||
|
||||
|
|
@ -1191,8 +1090,6 @@ static void imx412_remove(struct i2c_client *client)
|
|||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
imx412_power_off(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
mutex_destroy(&imx412->mutex);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops imx412_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ static int imx415_set_testpattern(struct imx415 *sensor, int val)
|
|||
cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x01, &ret);
|
||||
cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x01, &ret);
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx415_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
|
|
@ -720,7 +720,7 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
ret = cci_write(sensor->regmap, IMX415_VMAX,
|
||||
format->height + ctrl->val, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
/*
|
||||
* Exposure is set based on VMAX which has just changed, so
|
||||
* program exposure register as well
|
||||
|
|
|
|||
957
drivers/media/i2c/imx471.c
Normal file
957
drivers/media/i2c/imx471.c
Normal file
|
|
@ -0,0 +1,957 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* imx471.c - imx471 sensor driver
|
||||
*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
* Copyright (C) 2026 Kate Hsuan <hpa@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <media/v4l2-cci.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
|
||||
#define IMX471_REG_MODE_SELECT CCI_REG8(0x0100)
|
||||
#define IMX471_MODE_STANDBY 0x00
|
||||
#define IMX471_MODE_STREAMING 0x01
|
||||
|
||||
/* Chip ID */
|
||||
#define IMX471_REG_CHIP_ID CCI_REG16(0x0016)
|
||||
#define IMX471_CHIP_ID 0x0471
|
||||
|
||||
/* V_TIMING internal */
|
||||
#define IMX471_REG_FLL CCI_REG16(0x0340)
|
||||
#define IMX471_FLL_MAX 0xffff
|
||||
|
||||
/* Exposure control */
|
||||
#define IMX471_REG_EXPOSURE CCI_REG16(0x0202)
|
||||
#define IMX471_EXPOSURE_MIN 1
|
||||
#define IMX471_EXPOSURE_STEP 1
|
||||
#define IMX471_EXPOSURE_DEFAULT 1270
|
||||
|
||||
/* Default exposure margin */
|
||||
#define IMX471_EXPOSURE_MARGIN 18
|
||||
|
||||
/* Analog gain control */
|
||||
#define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204)
|
||||
#define IMX471_ANA_GAIN_MIN 0
|
||||
#define IMX471_ANA_GAIN_MAX 800
|
||||
#define IMX471_ANA_GAIN_STEP 1
|
||||
#define IMX471_ANA_GAIN_DEFAULT 0
|
||||
|
||||
/* Digital gain control */
|
||||
#define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9)
|
||||
#define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e)
|
||||
#define IMX471_DGTL_GAIN_MIN 256
|
||||
#define IMX471_DGTL_GAIN_MAX 4095
|
||||
#define IMX471_DGTL_GAIN_STEP 1
|
||||
#define IMX471_DGTL_GAIN_DEFAULT 256
|
||||
|
||||
/* HFLIP and VFLIP control */
|
||||
#define IMX471_REG_ORIENTATION CCI_REG8(0x0101)
|
||||
|
||||
/* Test Pattern Control */
|
||||
#define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600)
|
||||
|
||||
/* default link frequency and external clock */
|
||||
#define IMX471_LINK_FREQ_DEFAULT 200000000LL
|
||||
#define IMX471_EXT_CLK 19200000
|
||||
|
||||
/* PLL */
|
||||
#define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301)
|
||||
#define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303)
|
||||
#define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
|
||||
#define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306)
|
||||
#define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309)
|
||||
#define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b)
|
||||
#define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
|
||||
#define IMX471_PLL_SINGLE 0
|
||||
#define IMX471_PLL_DUAL 1
|
||||
|
||||
/* IMX471 native and active pixel array size */
|
||||
#define IMX471_NATIVE_WIDTH 4672
|
||||
#define IMX471_NATIVE_HEIGHT 3512
|
||||
#define IMX471_PIXEL_ARRAY_LEFT 8
|
||||
#define IMX471_PIXEL_ARRAY_TOP 8
|
||||
#define IMX471_PIXEL_ARRAY_WIDTH 4656
|
||||
#define IMX471_PIXEL_ARRAY_HEIGHT 3496
|
||||
|
||||
#define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136)
|
||||
|
||||
#define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112)
|
||||
#define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a
|
||||
|
||||
#define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114)
|
||||
#define IMX471_CSI_2_LANE_MODE 1
|
||||
#define IMX471_CSI_4_LANE_MODE 3
|
||||
|
||||
#define IMX471_REG_X_ADD_STA CCI_REG16(0x0344)
|
||||
#define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346)
|
||||
#define IMX471_REG_X_ADD_END CCI_REG16(0x0348)
|
||||
#define IMX471_REG_Y_ADD_END CCI_REG16(0x034a)
|
||||
#define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
|
||||
#define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
|
||||
#define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381)
|
||||
#define IMX471_REG_X_ODD_INC CCI_REG8(0x0383)
|
||||
#define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385)
|
||||
#define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387)
|
||||
|
||||
#define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
|
||||
#define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
|
||||
#define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c)
|
||||
#define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e)
|
||||
|
||||
/* Binning mode */
|
||||
#define IMX471_REG_BINNING_MODE CCI_REG8(0x0900)
|
||||
#define IMX471_BINNING_NONE 0
|
||||
#define IMX471_BINNING_ENABLE 1
|
||||
#define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901)
|
||||
#define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
|
||||
|
||||
#define to_imx471(_sd) container_of_const(_sd, struct imx471, sd)
|
||||
|
||||
static const char * const imx471_supply_name[] = {
|
||||
"vana",
|
||||
};
|
||||
|
||||
struct imx471_mode {
|
||||
u32 width;
|
||||
u32 height;
|
||||
|
||||
/* V-timing */
|
||||
u32 fll_def;
|
||||
u32 fll_min;
|
||||
|
||||
/* H-timing */
|
||||
u32 llp;
|
||||
|
||||
const struct cci_reg_sequence *default_mode_regs;
|
||||
unsigned int default_mode_regs_length;
|
||||
};
|
||||
|
||||
struct imx471 {
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct v4l2_ctrl *vblank;
|
||||
struct v4l2_ctrl *hblank;
|
||||
struct v4l2_ctrl *vflip;
|
||||
struct v4l2_ctrl *hflip;
|
||||
struct v4l2_ctrl *exposure;
|
||||
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)];
|
||||
struct clk *img_clk;
|
||||
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct cci_reg_sequence imx471_global_regs[] = {
|
||||
{ IMX471_REG_EXCK_FREQ, 0x1333 },
|
||||
{ CCI_REG8(0x3c7e), 0x08 },
|
||||
{ CCI_REG8(0x3c7f), 0x05 },
|
||||
{ CCI_REG8(0x3e35), 0x00 },
|
||||
{ CCI_REG8(0x3e36), 0x00 },
|
||||
{ CCI_REG8(0x3e37), 0x00 },
|
||||
{ CCI_REG8(0x3f7f), 0x01 },
|
||||
{ CCI_REG8(0x4431), 0x04 },
|
||||
{ CCI_REG8(0x531c), 0x01 },
|
||||
{ CCI_REG8(0x531d), 0x02 },
|
||||
{ CCI_REG8(0x531e), 0x04 },
|
||||
{ CCI_REG8(0x5928), 0x00 },
|
||||
{ CCI_REG8(0x5929), 0x2f },
|
||||
{ CCI_REG8(0x592a), 0x00 },
|
||||
{ CCI_REG8(0x592b), 0x85 },
|
||||
{ CCI_REG8(0x592c), 0x00 },
|
||||
{ CCI_REG8(0x592d), 0x32 },
|
||||
{ CCI_REG8(0x592e), 0x00 },
|
||||
{ CCI_REG8(0x592f), 0x88 },
|
||||
{ CCI_REG8(0x5930), 0x00 },
|
||||
{ CCI_REG8(0x5931), 0x3d },
|
||||
{ CCI_REG8(0x5932), 0x00 },
|
||||
{ CCI_REG8(0x5933), 0x93 },
|
||||
{ CCI_REG8(0x5938), 0x00 },
|
||||
{ CCI_REG8(0x5939), 0x24 },
|
||||
{ CCI_REG8(0x593a), 0x00 },
|
||||
{ CCI_REG8(0x593b), 0x7a },
|
||||
{ CCI_REG8(0x593c), 0x00 },
|
||||
{ CCI_REG8(0x593d), 0x24 },
|
||||
{ CCI_REG8(0x593e), 0x00 },
|
||||
{ CCI_REG8(0x593f), 0x7a },
|
||||
{ CCI_REG8(0x5940), 0x00 },
|
||||
{ CCI_REG8(0x5941), 0x2f },
|
||||
{ CCI_REG8(0x5942), 0x00 },
|
||||
{ CCI_REG8(0x5943), 0x85 },
|
||||
{ CCI_REG8(0x5f0e), 0x6e },
|
||||
{ CCI_REG8(0x5f11), 0xc6 },
|
||||
{ CCI_REG8(0x5f17), 0x5e },
|
||||
{ CCI_REG8(0x7990), 0x01 },
|
||||
{ CCI_REG8(0x7993), 0x5d },
|
||||
{ CCI_REG8(0x7994), 0x5d },
|
||||
{ CCI_REG8(0x7995), 0xa1 },
|
||||
{ CCI_REG8(0x799a), 0x01 },
|
||||
{ CCI_REG8(0x799d), 0x00 },
|
||||
{ CCI_REG8(0x8169), 0x01 },
|
||||
{ CCI_REG8(0x8359), 0x01 },
|
||||
{ CCI_REG8(0x9302), 0x1e },
|
||||
{ CCI_REG8(0x9306), 0x1f },
|
||||
{ CCI_REG8(0x930a), 0x26 },
|
||||
{ CCI_REG8(0x930e), 0x23 },
|
||||
{ CCI_REG8(0x9312), 0x23 },
|
||||
{ CCI_REG8(0x9316), 0x2c },
|
||||
{ CCI_REG8(0x9317), 0x19 },
|
||||
{ CCI_REG8(0xb046), 0x01 },
|
||||
{ CCI_REG8(0xb048), 0x01 },
|
||||
};
|
||||
|
||||
static const struct cci_reg_sequence mode_1928x1088_regs[] = {
|
||||
{ IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 },
|
||||
{ IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE },
|
||||
{ IMX471_REG_X_ADD_STA, 8 },
|
||||
{ IMX471_REG_Y_ADD_STA, 408 },
|
||||
{ IMX471_REG_X_ADD_END, 4647 },
|
||||
{ IMX471_REG_Y_ADD_END, 3051 },
|
||||
{ IMX471_REG_X_EVEN_INC, 1 },
|
||||
{ IMX471_REG_X_ODD_INC, 1 },
|
||||
{ IMX471_REG_Y_EVEN_INC, 1 },
|
||||
{ IMX471_REG_Y_ODD_INC, 1 },
|
||||
{ IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE },
|
||||
{ IMX471_REG_BINNING_TYPE, 0x22 },
|
||||
{ IMX471_REG_BINNING_WEIGHTING, 0x08 },
|
||||
{ IMX471_REG_DIG_CROP_X_OFFSET, 208 },
|
||||
{ IMX471_REG_DIG_CROP_Y_OFFSET, 108 },
|
||||
{ IMX471_REG_DIG_CROP_WIDTH, 1928 },
|
||||
{ IMX471_REG_DIG_CROP_HEIGHT, 1088 },
|
||||
{ IMX471_REG_X_OUTPUT_SIZE, 1928 },
|
||||
{ IMX471_REG_Y_OUTPUT_SIZE, 1088 },
|
||||
{ IMX471_REG_VTPXCK_DIV, 0x06 },
|
||||
{ IMX471_REG_VTSYCK_DIV, 0x02 },
|
||||
{ IMX471_REG_PREPLLCK_VT_DIV, 0x02 },
|
||||
{ IMX471_REG_PLL_VT_MPY, 0x0079 },
|
||||
{ IMX471_REG_OPSYCK_DIV, 0x01 },
|
||||
{ CCI_REG8(0x030d), 0x02 },
|
||||
{ CCI_REG8(0x030e), 0x00 },
|
||||
{ CCI_REG8(0x030f), 0x53 },
|
||||
{ IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL },
|
||||
{ CCI_REG8(0x3f4c), 0x81 },
|
||||
{ CCI_REG8(0x3f4d), 0x81 },
|
||||
{ CCI_REG8(0x3f78), 0x01 },
|
||||
{ CCI_REG8(0x3f79), 0x31 },
|
||||
{ CCI_REG8(0x3ffe), 0x00 },
|
||||
{ CCI_REG8(0x3fff), 0x8a },
|
||||
{ CCI_REG8(0x5f0a), 0xb6 },
|
||||
};
|
||||
|
||||
static const char * const imx471_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"Solid Colour",
|
||||
"Eight Vertical Colour Bars",
|
||||
"Colour Bars With Fade to Grey",
|
||||
"Pseudorandom Sequence (PN9)",
|
||||
};
|
||||
|
||||
static const s64 link_freq_menu_items[] = {
|
||||
IMX471_LINK_FREQ_DEFAULT,
|
||||
};
|
||||
|
||||
/*
|
||||
* The Bayer formats for the flipping.
|
||||
* - no flip
|
||||
* - h flip
|
||||
* - v flip
|
||||
* - h and v flips
|
||||
*/
|
||||
static const u32 imx471_hv_flips_bayer_order[] = {
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
};
|
||||
|
||||
static const struct imx471_mode imx471_modes[] = {
|
||||
{
|
||||
.width = 1928,
|
||||
.height = 1088,
|
||||
.fll_def = 1308,
|
||||
.fll_min = 1308,
|
||||
.llp = 2328,
|
||||
.default_mode_regs = mode_1928x1088_regs,
|
||||
.default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs),
|
||||
},
|
||||
};
|
||||
|
||||
static int imx471_get_regulators(struct device *dev, struct imx471 *sensor)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++)
|
||||
sensor->supplies[i].supply = imx471_supply_name[i];
|
||||
|
||||
return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name),
|
||||
sensor->supplies);
|
||||
}
|
||||
|
||||
static int imx471_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct imx471 *sensor = container_of_const(ctrl->handler,
|
||||
struct imx471,
|
||||
ctrl_handler);
|
||||
struct v4l2_subdev_state *state =
|
||||
v4l2_subdev_get_locked_active_state(&sensor->sd);
|
||||
const struct v4l2_mbus_framefmt *format =
|
||||
v4l2_subdev_state_get_format(state, 0);
|
||||
int ret;
|
||||
|
||||
if (ctrl->id == V4L2_CID_VBLANK) {
|
||||
s64 exposure_max = format->height + ctrl->val -
|
||||
IMX471_EXPOSURE_MARGIN;
|
||||
ret = __v4l2_ctrl_modify_range(sensor->exposure,
|
||||
sensor->exposure->minimum,
|
||||
exposure_max,
|
||||
sensor->exposure->step,
|
||||
exposure_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!pm_runtime_get_if_in_use(sensor->dev))
|
||||
return 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN,
|
||||
ctrl->val, NULL);
|
||||
break;
|
||||
case V4L2_CID_DIGITAL_GAIN:
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL,
|
||||
ctrl->val, NULL);
|
||||
break;
|
||||
case V4L2_CID_EXPOSURE:
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE,
|
||||
ctrl->val, NULL);
|
||||
break;
|
||||
case V4L2_CID_VBLANK:
|
||||
/* Update FLL that meets expected vertical blanking */
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_FLL,
|
||||
format->height + ctrl->val, NULL);
|
||||
break;
|
||||
case V4L2_CID_TEST_PATTERN:
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN,
|
||||
ctrl->val, NULL);
|
||||
break;
|
||||
case V4L2_CID_HFLIP:
|
||||
case V4L2_CID_VFLIP:
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION,
|
||||
sensor->hflip->val | sensor->vflip->val << 1,
|
||||
NULL);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n",
|
||||
ctrl->id, ctrl->val);
|
||||
break;
|
||||
}
|
||||
|
||||
pm_runtime_put(sensor->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops imx471_ctrl_ops = {
|
||||
.s_ctrl = imx471_set_ctrl,
|
||||
};
|
||||
|
||||
static u32 imx471_get_format_code(struct imx471 *sensor)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0);
|
||||
|
||||
return imx471_hv_flips_bayer_order[i];
|
||||
}
|
||||
|
||||
static int imx471_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
|
||||
if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = imx471_get_format_code(sensor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx471_enum_frame_size(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
if (fse->index >= ARRAY_SIZE(imx471_modes))
|
||||
return -EINVAL;
|
||||
|
||||
fse->min_width = imx471_modes[fse->index].width;
|
||||
fse->max_width = fse->min_width;
|
||||
fse->min_height = imx471_modes[fse->index].height;
|
||||
fse->max_height = fse->min_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx471_update_pad_format(struct imx471 *sensor,
|
||||
const struct imx471_mode *mode,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
fmt->format.code = imx471_get_format_code(sensor);
|
||||
fmt->format.width = mode->width;
|
||||
fmt->format.height = mode->height;
|
||||
fmt->format.field = V4L2_FIELD_NONE;
|
||||
}
|
||||
|
||||
static int imx471_set_pad_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
const struct imx471_mode *mode;
|
||||
int h_blank, ret;
|
||||
|
||||
mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
|
||||
width, height, fmt->format.width,
|
||||
fmt->format.height);
|
||||
|
||||
imx471_update_pad_format(sensor, mode, fmt);
|
||||
|
||||
*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
return 0;
|
||||
|
||||
if (media_entity_is_streaming(&sensor->sd.entity))
|
||||
return -EBUSY;
|
||||
|
||||
ret = __v4l2_ctrl_modify_range(sensor->vblank,
|
||||
mode->fll_min - mode->height,
|
||||
IMX471_FLL_MAX - mode->height,
|
||||
1,
|
||||
mode->fll_def - mode->height);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
h_blank = mode->llp - mode->width;
|
||||
/*
|
||||
* Currently hblank is not changeable.
|
||||
* So FPS control is done only by vblank.
|
||||
*/
|
||||
return __v4l2_ctrl_modify_range(sensor->hblank, h_blank,
|
||||
h_blank, 1, h_blank);
|
||||
}
|
||||
|
||||
static int imx471_get_selection(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_selection *sel)
|
||||
{
|
||||
switch (sel->target) {
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
|
||||
break;
|
||||
|
||||
case V4L2_SEL_TGT_NATIVE_SIZE:
|
||||
sel->r.top = 0;
|
||||
sel->r.left = 0;
|
||||
sel->r.width = IMX471_NATIVE_WIDTH;
|
||||
sel->r.height = IMX471_NATIVE_HEIGHT;
|
||||
return 0;
|
||||
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
sel->r.top = IMX471_PIXEL_ARRAY_TOP;
|
||||
sel->r.left = IMX471_PIXEL_ARRAY_LEFT;
|
||||
sel->r.width = IMX471_PIXEL_ARRAY_WIDTH;
|
||||
sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int imx471_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state)
|
||||
{
|
||||
struct v4l2_subdev_format fmt = {
|
||||
.which = V4L2_SUBDEV_FORMAT_TRY,
|
||||
.format = {
|
||||
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
.width = imx471_modes[0].width,
|
||||
.height = imx471_modes[0].height,
|
||||
},
|
||||
};
|
||||
|
||||
return imx471_set_pad_format(sd, sd_state, &fmt);
|
||||
}
|
||||
|
||||
static int imx471_identify_module(struct imx471 *sensor)
|
||||
{
|
||||
int ret;
|
||||
u64 val;
|
||||
|
||||
ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(sensor->dev, ret,
|
||||
"failed to read chip id\n");
|
||||
|
||||
if (val != IMX471_CHIP_ID)
|
||||
return dev_err_probe(sensor->dev, -EIO,
|
||||
"chip id mismatch: %x!=%llx\n",
|
||||
IMX471_CHIP_ID, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx471_power_off(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
|
||||
clk_disable_unprepare(sensor->img_clk);
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 1);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
|
||||
sensor->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx471_power_on(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name),
|
||||
sensor->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable regulators: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sensor->img_clk);
|
||||
if (ret < 0) {
|
||||
regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
|
||||
sensor->supplies);
|
||||
dev_err(dev, "failed to enable imaging clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
|
||||
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx471_enable_stream(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
const struct imx471_mode *mode;
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(sensor->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = imx471_identify_module(sensor);
|
||||
if (ret)
|
||||
goto error_powerdown;
|
||||
|
||||
ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs,
|
||||
ARRAY_SIZE(imx471_global_regs), NULL);
|
||||
if (ret) {
|
||||
dev_err(sensor->dev, "failed to set global settings: %d\n",
|
||||
ret);
|
||||
goto error_powerdown;
|
||||
}
|
||||
|
||||
fmt = v4l2_subdev_state_get_format(state, 0);
|
||||
mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
|
||||
width, height, fmt->width, fmt->height);
|
||||
|
||||
ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs,
|
||||
mode->default_mode_regs_length, NULL);
|
||||
if (ret) {
|
||||
dev_err(sensor->dev, "failed to set mode: %d\n", ret);
|
||||
goto error_powerdown;
|
||||
}
|
||||
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto error_powerdown;
|
||||
|
||||
ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler);
|
||||
if (ret)
|
||||
goto error_powerdown;
|
||||
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
|
||||
IMX471_MODE_STREAMING, NULL);
|
||||
if (ret)
|
||||
goto error_powerdown;
|
||||
|
||||
__v4l2_ctrl_grab(sensor->vflip, true);
|
||||
__v4l2_ctrl_grab(sensor->hflip, true);
|
||||
|
||||
return ret;
|
||||
|
||||
error_powerdown:
|
||||
pm_runtime_put(sensor->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx471_disable_stream(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct imx471 *sensor = to_imx471(sd);
|
||||
int ret;
|
||||
|
||||
ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
|
||||
IMX471_MODE_STANDBY, NULL);
|
||||
pm_runtime_put(sensor->dev);
|
||||
|
||||
if (ret)
|
||||
dev_err(sensor->dev,
|
||||
"failed to disable stream with return value: %d\n",
|
||||
ret);
|
||||
|
||||
__v4l2_ctrl_grab(sensor->vflip, false);
|
||||
__v4l2_ctrl_grab(sensor->hflip, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops imx471_video_ops = {
|
||||
.s_stream = v4l2_subdev_s_stream_helper,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops imx471_pad_ops = {
|
||||
.enum_mbus_code = imx471_enum_mbus_code,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = imx471_set_pad_format,
|
||||
.get_selection = imx471_get_selection,
|
||||
.enum_frame_size = imx471_enum_frame_size,
|
||||
.enable_streams = imx471_enable_stream,
|
||||
.disable_streams = imx471_disable_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops imx471_subdev_ops = {
|
||||
.video = &imx471_video_ops,
|
||||
.pad = &imx471_pad_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx471_internal_ops = {
|
||||
.init_state = imx471_init_state,
|
||||
};
|
||||
|
||||
static int imx471_init_controls(struct imx471 *sensor)
|
||||
{
|
||||
const struct imx471_mode *mode = &imx471_modes[0];
|
||||
struct v4l2_fwnode_device_properties props;
|
||||
struct v4l2_ctrl_handler *ctrl_hdlr;
|
||||
struct v4l2_ctrl *link_freq;
|
||||
s64 exposure_max, hblank;
|
||||
u64 pixel_rate;
|
||||
int ret;
|
||||
|
||||
ret = v4l2_fwnode_device_parse(sensor->dev, &props);
|
||||
if (ret) {
|
||||
dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrl_hdlr = &sensor->ctrl_handler;
|
||||
v4l2_ctrl_handler_init(ctrl_hdlr, 12);
|
||||
|
||||
v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props);
|
||||
|
||||
link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
|
||||
&imx471_ctrl_ops,
|
||||
V4L2_CID_LINK_FREQ,
|
||||
ARRAY_SIZE(link_freq_menu_items) - 1,
|
||||
0,
|
||||
link_freq_menu_items);
|
||||
|
||||
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
|
||||
pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10);
|
||||
|
||||
v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE, pixel_rate,
|
||||
pixel_rate, 1, pixel_rate);
|
||||
|
||||
sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
|
||||
&imx471_ctrl_ops,
|
||||
V4L2_CID_VBLANK,
|
||||
mode->fll_min - mode->height,
|
||||
IMX471_FLL_MAX - mode->height,
|
||||
1,
|
||||
mode->fll_def - mode->height);
|
||||
|
||||
hblank = mode->llp - mode->width;
|
||||
sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_HBLANK, hblank, hblank,
|
||||
1, hblank);
|
||||
|
||||
/* fll >= exposure time + adjust parameter (default value is 18) */
|
||||
exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN;
|
||||
sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE,
|
||||
IMX471_EXPOSURE_MIN, exposure_max,
|
||||
IMX471_EXPOSURE_STEP,
|
||||
IMX471_EXPOSURE_DEFAULT);
|
||||
|
||||
v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
|
||||
IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX,
|
||||
IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT);
|
||||
|
||||
v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
|
||||
IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX,
|
||||
IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT);
|
||||
|
||||
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_TEST_PATTERN,
|
||||
ARRAY_SIZE(imx471_test_pattern_menu) - 1,
|
||||
0, 0, imx471_test_pattern_menu);
|
||||
|
||||
sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_HFLIP, 0, 1, 1, 0);
|
||||
|
||||
sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
|
||||
if (ctrl_hdlr->error) {
|
||||
dev_err(sensor->dev, "%s control init failed: %d\n",
|
||||
__func__, ctrl_hdlr->error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
|
||||
sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
|
||||
|
||||
sensor->sd.ctrl_handler = ctrl_hdlr;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
v4l2_ctrl_handler_free(ctrl_hdlr);
|
||||
|
||||
return ctrl_hdlr->error;
|
||||
}
|
||||
|
||||
static int imx471_check_hwcfg(struct imx471 *sensor)
|
||||
{
|
||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||
.bus_type = V4L2_MBUS_CSI2_DPHY,
|
||||
};
|
||||
struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev);
|
||||
unsigned long link_freq_bitmap;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(sensor->dev, PTR_ERR(clk),
|
||||
"can't get clock frequency\n");
|
||||
|
||||
if (clk_get_rate(clk) != IMX471_EXT_CLK)
|
||||
return dev_err_probe(sensor->dev, -EINVAL,
|
||||
"external clock %lu is not supported\n",
|
||||
clk_get_rate(clk));
|
||||
|
||||
ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
|
||||
fwnode_handle_put(ep);
|
||||
if (ret)
|
||||
return dev_err_probe(sensor->dev, ret,
|
||||
"parsing endpoint failed\n");
|
||||
|
||||
if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
|
||||
ret = dev_err_probe(sensor->dev, -EINVAL,
|
||||
"number of CSI2 data lanes %u is not supported\n",
|
||||
bus_cfg.bus.mipi_csi2.num_data_lanes);
|
||||
goto done_endpoint_free;
|
||||
}
|
||||
|
||||
ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies,
|
||||
bus_cfg.nr_of_link_frequencies,
|
||||
link_freq_menu_items,
|
||||
ARRAY_SIZE(link_freq_menu_items),
|
||||
&link_freq_bitmap);
|
||||
|
||||
done_endpoint_free:
|
||||
v4l2_fwnode_endpoint_free(&bus_cfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx471_probe(struct i2c_client *client)
|
||||
{
|
||||
struct imx471 *sensor;
|
||||
int ret;
|
||||
|
||||
sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
|
||||
if (!sensor)
|
||||
return dev_err_probe(&client->dev, -ENOMEM,
|
||||
"failed to allocate memory\n");
|
||||
|
||||
sensor->dev = &client->dev;
|
||||
|
||||
ret = imx471_check_hwcfg(sensor);
|
||||
if (ret)
|
||||
return dev_err_probe(sensor->dev, ret,
|
||||
"failed to check hwcfg: %d\n", ret);
|
||||
|
||||
ret = imx471_get_regulators(sensor->dev, sensor);
|
||||
if (ret)
|
||||
return dev_err_probe(sensor->dev, ret,
|
||||
"failed to get regulators\n");
|
||||
|
||||
sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(sensor->reset_gpio))
|
||||
return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio),
|
||||
"failed to get reset gpio\n");
|
||||
|
||||
sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
|
||||
if (IS_ERR(sensor->img_clk))
|
||||
return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk),
|
||||
"failed to get imaging clock\n");
|
||||
|
||||
v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops);
|
||||
|
||||
sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
|
||||
if (IS_ERR(sensor->regmap))
|
||||
return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap),
|
||||
"failed to initialize CCI\n");
|
||||
|
||||
ret = imx471_power_on(sensor->dev);
|
||||
if (ret)
|
||||
return dev_err_probe(sensor->dev, ret,
|
||||
"failed to power on\n");
|
||||
|
||||
ret = imx471_identify_module(sensor);
|
||||
if (ret) {
|
||||
dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n",
|
||||
ret);
|
||||
goto error_power_off;
|
||||
}
|
||||
|
||||
ret = imx471_init_controls(sensor);
|
||||
if (ret) {
|
||||
dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n",
|
||||
ret);
|
||||
goto error_power_off;
|
||||
}
|
||||
|
||||
sensor->sd.internal_ops = &imx471_internal_ops;
|
||||
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
|
||||
ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
|
||||
if (ret) {
|
||||
dev_err_probe(sensor->dev, ret,
|
||||
"failed to init entity pads: %d\n", ret);
|
||||
goto error_v4l2_ctrl_handler_free;
|
||||
}
|
||||
|
||||
sensor->sd.state_lock = sensor->ctrl_handler.lock;
|
||||
ret = v4l2_subdev_init_finalize(&sensor->sd);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n",
|
||||
ret);
|
||||
goto error_media_entity_pm;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(sensor->dev);
|
||||
pm_runtime_enable(sensor->dev);
|
||||
|
||||
ret = v4l2_async_register_subdev_sensor(&sensor->sd);
|
||||
if (ret < 0)
|
||||
goto error_v4l2_subdev_cleanup;
|
||||
|
||||
pm_runtime_idle(sensor->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_v4l2_subdev_cleanup:
|
||||
pm_runtime_disable(sensor->dev);
|
||||
pm_runtime_set_suspended(sensor->dev);
|
||||
v4l2_subdev_cleanup(&sensor->sd);
|
||||
|
||||
error_media_entity_pm:
|
||||
media_entity_cleanup(&sensor->sd.entity);
|
||||
|
||||
error_v4l2_ctrl_handler_free:
|
||||
v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
|
||||
|
||||
error_power_off:
|
||||
imx471_power_off(sensor->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx471_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
v4l2_subdev_cleanup(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
if (!pm_runtime_status_suspended(&client->dev)) {
|
||||
imx471_power_off(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off,
|
||||
imx471_power_on, NULL);
|
||||
|
||||
static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = {
|
||||
{ "SONY471A" },
|
||||
{ "TBE20A0" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids);
|
||||
|
||||
static struct i2c_driver imx471_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "imx471",
|
||||
.acpi_match_table = ACPI_PTR(imx471_acpi_ids),
|
||||
.pm = pm_sleep_ptr(&imx471_pm_ops),
|
||||
},
|
||||
.probe = imx471_probe,
|
||||
.remove = imx471_remove,
|
||||
};
|
||||
module_i2c_driver(imx471_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>");
|
||||
MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>");
|
||||
MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>");
|
||||
MODULE_DESCRIPTION("Sony imx471 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
1447
drivers/media/i2c/imx678.c
Normal file
1447
drivers/media/i2c/imx678.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -1062,7 +1062,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
|||
priv->sd.state_lock = priv->ctrls.lock;
|
||||
ret = v4l2_subdev_init_finalize(&priv->sd);
|
||||
if (ret)
|
||||
goto err_async;
|
||||
goto err_entity;
|
||||
|
||||
ret = v4l2_async_register_subdev(&priv->sd);
|
||||
if (ret < 0) {
|
||||
|
|
@ -1074,6 +1074,8 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
|||
|
||||
err_subdev:
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
err_entity:
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
err_async:
|
||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||
max9286_v4l2_notifier_unregister(priv);
|
||||
|
|
@ -1084,6 +1086,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
|||
static void max9286_v4l2_unregister(struct max9286_priv *priv)
|
||||
{
|
||||
v4l2_subdev_cleanup(&priv->sd);
|
||||
media_entity_cleanup(&priv->sd.entity);
|
||||
v4l2_ctrl_handler_free(&priv->ctrls);
|
||||
v4l2_async_unregister_subdev(&priv->sd);
|
||||
max9286_v4l2_notifier_unregister(priv);
|
||||
|
|
|
|||
|
|
@ -717,6 +717,7 @@ static int msp_probe(struct i2c_client *client)
|
|||
if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
|
||||
dev_dbg_lvl(&client->dev, 1, msp_debug,
|
||||
"not an msp3400 (cannot read chip version)\n");
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -812,6 +813,7 @@ static int msp_probe(struct i2c_client *client)
|
|||
int err = hdl->error;
|
||||
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -865,6 +867,7 @@ static void msp_remove(struct i2c_client *client)
|
|||
msp_reset(client);
|
||||
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
media_entity_cleanup(&state->sd.entity);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -452,11 +452,7 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031)
|
|||
ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1);
|
||||
}
|
||||
|
||||
static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
|
|
|
|||
|
|
@ -1079,11 +1079,12 @@ static int mt9t112_probe(struct i2c_client *client)
|
|||
v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
|
||||
|
||||
priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk");
|
||||
if (PTR_ERR(priv->clk) == -ENOENT)
|
||||
if (IS_ERR(priv->clk)) {
|
||||
if (PTR_ERR(priv->clk) != -ENOENT)
|
||||
return dev_err_probe(&client->dev, PTR_ERR(priv->clk),
|
||||
"Unable to get clock \"extclk\"\n");
|
||||
priv->clk = NULL;
|
||||
else if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(priv->clk),
|
||||
"Unable to get clock \"extclk\"\n");
|
||||
}
|
||||
|
||||
priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby",
|
||||
GPIOD_OUT_HIGH);
|
||||
|
|
|
|||
|
|
@ -520,6 +520,7 @@ static int mt9v011_probe(struct i2c_client *c)
|
|||
(version != MT9V011_REV_B_VERSION)) {
|
||||
v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
|
||||
version);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -542,6 +543,7 @@ static int mt9v011_probe(struct i2c_client *c)
|
|||
|
||||
v4l2_err(sd, "control initialization error %d\n", ret);
|
||||
v4l2_ctrl_handler_free(&core->ctrls);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return ret;
|
||||
}
|
||||
core->sd.ctrl_handler = &core->ctrls;
|
||||
|
|
@ -577,6 +579,7 @@ static void mt9v011_remove(struct i2c_client *c)
|
|||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&core->ctrls);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -820,18 +820,16 @@ static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10)
|
|||
if (!ep)
|
||||
return -ENXIO;
|
||||
|
||||
/* Optional indication of MIPI clock voltage unit */
|
||||
if (!fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage",
|
||||
&clk_volt))
|
||||
ov02a10->mipi_clock_voltage = clk_volt;
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
|
||||
fwnode_handle_put(ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Optional indication of MIPI clock voltage unit */
|
||||
ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage",
|
||||
&clk_volt);
|
||||
|
||||
if (!ret)
|
||||
ov02a10->mipi_clock_voltage = clk_volt;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
|
||||
for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
|
||||
if (link_freq_menu_items[i] ==
|
||||
|
|
|
|||
|
|
@ -1241,41 +1241,42 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.disable_locking = true,
|
||||
};
|
||||
|
||||
static int ov2740_register_nvmem(struct i2c_client *client,
|
||||
struct ov2740 *ov2740)
|
||||
{
|
||||
struct nvm_data *nvm;
|
||||
struct regmap_config regmap_config = { };
|
||||
struct nvmem_config nvmem_config = { };
|
||||
struct regmap *regmap;
|
||||
struct device *dev = ov2740->dev;
|
||||
struct nvmem_config nvmem_config = {
|
||||
.name = dev_name(dev),
|
||||
.dev = dev,
|
||||
.read_only = true,
|
||||
.root_only = true,
|
||||
.owner = THIS_MODULE,
|
||||
.compat = true,
|
||||
.base_dev = dev,
|
||||
.reg_read = ov2740_nvmem_read,
|
||||
.stride = 1,
|
||||
.word_size = 1,
|
||||
.size = CUSTOMER_USE_OTP_SIZE,
|
||||
};
|
||||
|
||||
nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL);
|
||||
if (!nvm)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap_config.val_bits = 8;
|
||||
regmap_config.reg_bits = 16;
|
||||
regmap_config.disable_locking = true;
|
||||
regmap = devm_regmap_init_i2c(client, ®map_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
nvm->regmap = regmap;
|
||||
|
||||
nvmem_config.name = dev_name(dev);
|
||||
nvmem_config.dev = dev;
|
||||
nvmem_config.read_only = true;
|
||||
nvmem_config.root_only = true;
|
||||
nvmem_config.owner = THIS_MODULE;
|
||||
nvmem_config.compat = true;
|
||||
nvmem_config.base_dev = dev;
|
||||
nvmem_config.reg_read = ov2740_nvmem_read;
|
||||
nvmem_config.reg_write = NULL;
|
||||
nvmem_config.priv = nvm;
|
||||
nvmem_config.stride = 1;
|
||||
nvmem_config.word_size = 1;
|
||||
nvmem_config.size = CUSTOMER_USE_OTP_SIZE;
|
||||
|
||||
nvm->nvmem = devm_nvmem_register(dev, &nvmem_config);
|
||||
if (IS_ERR(nvm->nvmem))
|
||||
|
|
|
|||
|
|
@ -1116,18 +1116,14 @@ static void ov7740_remove(struct i2c_client *client)
|
|||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
|
||||
|
||||
mutex_destroy(&ov7740->mutex);
|
||||
v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
|
||||
media_entity_cleanup(&ov7740->subdev.entity);
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
media_entity_cleanup(&ov7740->subdev.entity);
|
||||
ov7740_free_controls(ov7740);
|
||||
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
ov7740_set_power(ov7740, 0);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
ov7740_set_power(ov7740, 0);
|
||||
}
|
||||
|
||||
static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -2608,7 +2608,7 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
|
|||
{
|
||||
struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
|
||||
struct ov8865_state *state = &sensor->state;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (enable) {
|
||||
ret = pm_runtime_resume_and_get(sensor->dev);
|
||||
|
|
@ -2617,18 +2617,32 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
|
|||
}
|
||||
|
||||
mutex_lock(&sensor->mutex);
|
||||
ret = ov8865_sw_standby(sensor, !enable);
|
||||
|
||||
/*
|
||||
* The sensor may have been kept powered by something else (e.g. the
|
||||
* VCM's runtime PM device link on IPU3 platforms), in which case
|
||||
* runtime resume did not run and the hardware may still be
|
||||
* configured for a previous mode. Always program the negotiated
|
||||
* configuration on stream start.
|
||||
*/
|
||||
if (enable) {
|
||||
ret = ov8865_sensor_init(sensor);
|
||||
if (!ret)
|
||||
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = ov8865_sw_standby(sensor, !enable);
|
||||
|
||||
mutex_unlock(&sensor->mutex);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
state->streaming = !!enable;
|
||||
|
||||
if (!enable)
|
||||
if (ret || !enable)
|
||||
pm_runtime_put(sensor->dev);
|
||||
|
||||
return 0;
|
||||
if (!ret)
|
||||
state->streaming = enable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
|
||||
|
|
@ -2915,15 +2929,15 @@ static int ov8865_resume(struct device *dev)
|
|||
if (ret)
|
||||
goto complete;
|
||||
|
||||
ret = ov8865_sensor_init(sensor);
|
||||
if (ret)
|
||||
goto error_power;
|
||||
|
||||
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
|
||||
if (ret)
|
||||
goto error_power;
|
||||
|
||||
if (state->streaming) {
|
||||
ret = ov8865_sensor_init(sensor);
|
||||
if (ret)
|
||||
goto error_power;
|
||||
|
||||
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
|
||||
if (ret)
|
||||
goto error_power;
|
||||
|
||||
ret = ov8865_sw_standby(sensor, false);
|
||||
if (ret)
|
||||
goto error_power;
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ struct ov9282_mode {
|
|||
* @noncontinuous_clock: Selection of CSI2 noncontinuous clock mode
|
||||
* @cur_mode: Pointer to current selected sensor mode
|
||||
* @code: Mbus code currently selected
|
||||
* @mutex: Mutex for serializing sensor controls
|
||||
*/
|
||||
struct ov9282 {
|
||||
struct device *dev;
|
||||
|
|
@ -648,7 +647,8 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||
ctrl->val ? OV9282_OUTPUT_ENABLE6_STROBE : 0, NULL);
|
||||
break;
|
||||
case V4L2_CID_FLASH_DURATION:
|
||||
ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN, ctrl->val, NULL);
|
||||
ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN,
|
||||
ov9282_us_to_flash_duration(ov9282, ctrl->val), NULL);
|
||||
break;
|
||||
default:
|
||||
dev_err(ov9282->dev, "Invalid control %d", ctrl->id);
|
||||
|
|
|
|||
|
|
@ -588,10 +588,12 @@ static int rdacm21_probe(struct i2c_client *client)
|
|||
|
||||
ret = v4l2_async_register_subdev(&dev->sd);
|
||||
if (ret)
|
||||
goto error_free_ctrls;
|
||||
goto error_entity_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
error_entity_cleanup:
|
||||
media_entity_cleanup(&dev->sd.entity);
|
||||
error_free_ctrls:
|
||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||
error:
|
||||
|
|
@ -606,6 +608,7 @@ static void rdacm21_remove(struct i2c_client *client)
|
|||
|
||||
v4l2_async_unregister_subdev(&dev->sd);
|
||||
v4l2_ctrl_handler_free(&dev->ctrls);
|
||||
media_entity_cleanup(&dev->sd.entity);
|
||||
i2c_unregister_device(dev->isp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1867,6 +1867,7 @@ static int saa711x_probe(struct i2c_client *client)
|
|||
int err = hdl->error;
|
||||
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return err;
|
||||
}
|
||||
v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
|
||||
|
|
@ -1925,6 +1926,7 @@ static void saa711x_remove(struct i2c_client *client)
|
|||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id saa711x_id[] = {
|
||||
|
|
|
|||
|
|
@ -29,11 +29,7 @@
|
|||
|
||||
/* Register Map */
|
||||
#define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000)
|
||||
#define VD55G1_MODEL_ID_VD55G1 0x53354731 /* Mono */
|
||||
#define VD55G1_MODEL_ID_VD65G4 0x53354733 /* RGB */
|
||||
#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004)
|
||||
#define VD55G1_REVISION_CCB 0x2020
|
||||
#define VD55G1_REVISION_BAYER 0x3030
|
||||
#define VD55G1_REG_COLOR_VERSION CCI_REG32_LE(0x0670)
|
||||
#define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012)
|
||||
#define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000)
|
||||
#define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c)
|
||||
|
|
@ -60,7 +56,10 @@
|
|||
#define VD55G1_PATGEN_ENABLE BIT(0)
|
||||
#define VD55G1_REG_MANUAL_ANALOG_GAIN CCI_REG8(0x0501)
|
||||
#define VD55G1_REG_MANUAL_COARSE_EXPOSURE CCI_REG16_LE(0x0502)
|
||||
#define VD55G1_REG_MANUAL_DIGITAL_GAIN CCI_REG16_LE(0x0504)
|
||||
#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0 CCI_REG16_LE(0x0504)
|
||||
#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1 CCI_REG16_LE(0x0506)
|
||||
#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2 CCI_REG16_LE(0x0508)
|
||||
#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3 CCI_REG16_LE(0x050a)
|
||||
#define VD55G1_REG_APPLIED_COARSE_EXPOSURE CCI_REG16_LE(0x00e8)
|
||||
#define VD55G1_REG_APPLIED_ANALOG_GAIN CCI_REG16_LE(0x00ea)
|
||||
#define VD55G1_REG_APPLIED_DIGITAL_GAIN CCI_REG16_LE(0x00ec)
|
||||
|
|
@ -114,9 +113,8 @@
|
|||
|
||||
#define VD55G1_WIDTH 804
|
||||
#define VD55G1_HEIGHT 704
|
||||
#define VD55G1_MODE_DEF 0
|
||||
#define VD55G1_MODE_IDX_DEF 0
|
||||
#define VD55G1_NB_GPIOS 4
|
||||
#define VD55G1_MBUS_CODE_DEF 0
|
||||
#define VD55G1_DGAIN_DEF 256
|
||||
#define VD55G1_AGAIN_DEF 19
|
||||
#define VD55G1_EXPO_MAX_TERM 64
|
||||
|
|
@ -135,8 +133,39 @@
|
|||
#define VD55G1_MIPI_RATE_MIN (250 * MEGA)
|
||||
#define VD55G1_MIPI_RATE_MAX (1200 * MEGA)
|
||||
|
||||
#define VD55G1_MODEL_ID_NAME(id) \
|
||||
((id) == VD55G1_MODEL_ID_VD55G1 ? "vd55g1" : "vd65g4")
|
||||
enum vd55g1_model_id {
|
||||
VD55G1_MODEL_ID_2 = 0x53354731,
|
||||
VD55G1_MODEL_ID_3 = 0x53354733,
|
||||
};
|
||||
|
||||
enum vd55g1_color_version {
|
||||
VD55G1_COLOR_VERSION_MONO,
|
||||
VD55G1_COLOR_VERSION_BAYER,
|
||||
};
|
||||
|
||||
struct vd55g1_version {
|
||||
char *name;
|
||||
enum vd55g1_model_id id;
|
||||
enum vd55g1_color_version color;
|
||||
};
|
||||
|
||||
static const struct vd55g1_version vd55g1_versions[] = {
|
||||
{
|
||||
.name = "vd55g1",
|
||||
.id = VD55G1_MODEL_ID_2,
|
||||
.color = VD55G1_COLOR_VERSION_MONO,
|
||||
},
|
||||
{
|
||||
.name = "vd55g4",
|
||||
.id = VD55G1_MODEL_ID_3,
|
||||
.color = VD55G1_COLOR_VERSION_MONO,
|
||||
},
|
||||
{
|
||||
.name = "vd65g4",
|
||||
.id = VD55G1_MODEL_ID_3,
|
||||
.color = VD55G1_COLOR_VERSION_BAYER,
|
||||
},
|
||||
};
|
||||
|
||||
static const u8 vd55g1_patch_array[] = {
|
||||
0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00,
|
||||
|
|
@ -532,7 +561,7 @@ struct vd55g1_vblank_limits {
|
|||
|
||||
struct vd55g1 {
|
||||
struct device *dev;
|
||||
unsigned int id;
|
||||
const struct vd55g1_version *version;
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)];
|
||||
|
|
@ -623,20 +652,28 @@ static unsigned int vd55g1_get_fmt_data_type(u32 code)
|
|||
|
||||
static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code)
|
||||
{
|
||||
u32 fallback_code;
|
||||
unsigned int i, j;
|
||||
|
||||
if (sensor->id == VD55G1_MODEL_ID_VD55G1)
|
||||
return code;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) {
|
||||
for (j = 0; j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); j++) {
|
||||
if (vd55g1_mbus_formats_bayer[i][j] == code)
|
||||
goto adapt_bayer_pattern;
|
||||
if (sensor->version->color == VD55G1_COLOR_VERSION_MONO) {
|
||||
fallback_code = vd55g1_mbus_formats_mono[0];
|
||||
for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_mono); i++)
|
||||
if (vd55g1_mbus_formats_mono[i] == code)
|
||||
return code;
|
||||
} else {
|
||||
fallback_code = vd55g1_mbus_formats_bayer[0][0];
|
||||
for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) {
|
||||
for (j = 0;
|
||||
j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]);
|
||||
j++) {
|
||||
if (vd55g1_mbus_formats_bayer[i][j] == code)
|
||||
goto adapt_bayer_pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
dev_warn(sensor->dev, "Unsupported mbus format\n");
|
||||
dev_warn(sensor->dev, "Unsupported mbus format: 0x%x\n", code);
|
||||
|
||||
return code;
|
||||
return fallback_code;
|
||||
|
||||
adapt_bayer_pattern:
|
||||
j = 0;
|
||||
|
|
@ -649,12 +686,6 @@ static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code)
|
|||
return vd55g1_mbus_formats_bayer[i][j];
|
||||
}
|
||||
|
||||
static s32 vd55g1_get_pixel_rate(struct vd55g1 *sensor,
|
||||
struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
return sensor->mipi_rate / vd55g1_get_fmt_bpp(format->code);
|
||||
}
|
||||
|
||||
static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor,
|
||||
struct v4l2_mbus_framefmt *format,
|
||||
struct v4l2_rect *crop)
|
||||
|
|
@ -850,9 +881,16 @@ static int vd55g1_update_expo_cluster(struct vd55g1 *sensor, bool is_auto)
|
|||
vd55g1_write(sensor, VD55G1_REG_MANUAL_ANALOG_GAIN,
|
||||
sensor->again_ctrl->val, &ret);
|
||||
|
||||
if (!is_auto && sensor->dgain_ctrl->is_new)
|
||||
vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN,
|
||||
if (!is_auto && sensor->dgain_ctrl->is_new) {
|
||||
vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0,
|
||||
sensor->dgain_ctrl->val, &ret);
|
||||
vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1,
|
||||
sensor->dgain_ctrl->val, &ret);
|
||||
vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2,
|
||||
sensor->dgain_ctrl->val, &ret);
|
||||
vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3,
|
||||
sensor->dgain_ctrl->val, &ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1173,8 +1211,8 @@ static int vd55g1_patch(struct vd55g1 *sensor)
|
|||
u64 patch;
|
||||
int ret = 0;
|
||||
|
||||
/* vd55g1 needs a patch while vd65g4 does not */
|
||||
if (sensor->id == VD55G1_MODEL_ID_VD55G1) {
|
||||
/* Version 2 needs a patch while version 3 does not */
|
||||
if (sensor->version->id == VD55G1_MODEL_ID_2) {
|
||||
vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR,
|
||||
sizeof(vd55g1_patch_array),
|
||||
vd55g1_patch_array, &ret);
|
||||
|
|
@ -1246,7 +1284,7 @@ static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd,
|
|||
struct vd55g1 *sensor = to_vd55g1(sd);
|
||||
u32 base_code;
|
||||
|
||||
if (sensor->id == VD55G1_MODEL_ID_VD55G1) {
|
||||
if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER) {
|
||||
if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_mono))
|
||||
return -EINVAL;
|
||||
base_code = vd55g1_mbus_formats_mono[code->index];
|
||||
|
|
@ -1285,12 +1323,6 @@ static int vd55g1_new_format_change_controls(struct vd55g1 *sensor,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update pixel rate to reflect new bpp */
|
||||
ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl,
|
||||
vd55g1_get_pixel_rate(sensor, format));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update hblank according to new width */
|
||||
hblank = vd55g1_get_hblank_min(sensor, format, crop);
|
||||
ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1,
|
||||
|
|
@ -1347,6 +1379,7 @@ static int vd55g1_init_state(struct v4l2_subdev *sd,
|
|||
{
|
||||
struct vd55g1 *sensor = to_vd55g1(sd);
|
||||
struct v4l2_subdev_format fmt = { 0 };
|
||||
int code;
|
||||
struct v4l2_subdev_route routes[] = {
|
||||
{ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE }
|
||||
};
|
||||
|
|
@ -1361,9 +1394,13 @@ static int vd55g1_init_state(struct v4l2_subdev *sd,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF],
|
||||
vd55g1_get_fmt_code(sensor, VD55G1_MBUS_CODE_DEF),
|
||||
&fmt.format);
|
||||
if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER)
|
||||
code = vd55g1_mbus_formats_mono[0];
|
||||
else
|
||||
code = vd55g1_mbus_formats_bayer[0][0];
|
||||
fmt.format.code = vd55g1_get_fmt_code(sensor, code);
|
||||
fmt.format.width = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].width;
|
||||
fmt.format.height = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].height;
|
||||
|
||||
return vd55g1_set_pad_fmt(sd, sd_state, &fmt);
|
||||
}
|
||||
|
|
@ -1549,7 +1586,6 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor)
|
|||
v4l2_subdev_state_get_crop(state, 0);
|
||||
struct v4l2_mbus_framefmt *format =
|
||||
v4l2_subdev_state_get_format(state, 0);
|
||||
s32 pixel_rate = vd55g1_get_pixel_rate(sensor, format);
|
||||
int ret;
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 16);
|
||||
|
|
@ -1591,7 +1627,7 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor)
|
|||
sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops,
|
||||
V4L2_CID_PIXEL_RATE, 1,
|
||||
INT_MAX, 1,
|
||||
pixel_rate);
|
||||
sensor->pixel_clock);
|
||||
if (sensor->pixel_rate_ctrl)
|
||||
sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
sensor->ae_lock_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK,
|
||||
|
|
@ -1644,38 +1680,46 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct vd55g1_version *
|
||||
vd55g1_get_version(enum vd55g1_model_id id,
|
||||
enum vd55g1_color_version color)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(vd55g1_versions); i++) {
|
||||
if (vd55g1_versions[i].id == id &&
|
||||
vd55g1_versions[i].color == color)
|
||||
return &vd55g1_versions[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vd55g1_detect(struct vd55g1 *sensor)
|
||||
{
|
||||
unsigned int dt_id = (uintptr_t)device_get_match_data(sensor->dev);
|
||||
u64 rev, id;
|
||||
int ret;
|
||||
const struct vd55g1_version *dt_version =
|
||||
device_get_match_data(sensor->dev);
|
||||
const struct vd55g1_version *version;
|
||||
u64 color, id;
|
||||
int ret = 0;
|
||||
|
||||
ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL);
|
||||
vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, &ret);
|
||||
vd55g1_read(sensor, VD55G1_REG_COLOR_VERSION, &color, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id != VD55G1_MODEL_ID_VD55G1 && id != VD55G1_MODEL_ID_VD65G4) {
|
||||
dev_warn(sensor->dev, "Unsupported sensor id 0x%x\n",
|
||||
(u32)id);
|
||||
version = vd55g1_get_version(id, color);
|
||||
if (!version) {
|
||||
dev_warn(sensor->dev, "Unsupported sensor version, expected %s\n",
|
||||
dt_version->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (id != dt_id) {
|
||||
dev_err(sensor->dev, "Probed sensor %s and device tree definition (%s) mismatch",
|
||||
VD55G1_MODEL_ID_NAME(id), VD55G1_MODEL_ID_NAME(dt_id));
|
||||
if (version->id != dt_version->id ||
|
||||
version->color != dt_version->color) {
|
||||
dev_err(sensor->dev, "Probed sensor version %s and device tree definition %s mismatch",
|
||||
version->name, dt_version->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
sensor->id = id;
|
||||
|
||||
ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &rev, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((id == VD55G1_MODEL_ID_VD55G1 && rev != VD55G1_REVISION_CCB) &&
|
||||
(id == VD55G1_MODEL_ID_VD65G4 && rev != VD55G1_REVISION_BAYER)) {
|
||||
dev_err(sensor->dev, "Unsupported sensor revision 0x%x for sensor %s\n",
|
||||
(u16)rev, VD55G1_MODEL_ID_NAME(id));
|
||||
return -ENODEV;
|
||||
}
|
||||
sensor->version = version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2033,8 +2077,9 @@ static void vd55g1_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct of_device_id vd55g1_dt_ids[] = {
|
||||
{ .compatible = "st,vd55g1", .data = (void *)VD55G1_MODEL_ID_VD55G1 },
|
||||
{ .compatible = "st,vd65g4", .data = (void *)VD55G1_MODEL_ID_VD65G4 },
|
||||
{ .compatible = "st,vd55g1", .data = (void *)&vd55g1_versions[0] },
|
||||
{ .compatible = "st,vd55g4", .data = (void *)&vd55g1_versions[1] },
|
||||
{ .compatible = "st,vd65g4", .data = (void *)&vd55g1_versions[2] },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vd55g1_dt_ids);
|
||||
|
|
|
|||
|
|
@ -522,8 +522,12 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
|
|||
data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data,
|
||||
"%s-vid-cap", data->v4l2_dev.name);
|
||||
ret = PTR_ERR_OR_ZERO(data->kthread_vid_cap);
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (ret) {
|
||||
data->kthread_vid_cap = NULL;
|
||||
goto error_rpm_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_rpm_put:
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
|
|
|||
|
|
@ -3563,12 +3563,12 @@ static int __maybe_unused bttv_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct pci_device_id bttv_pci_tbl[] = {
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0},
|
||||
{0,}
|
||||
{ PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848) },
|
||||
{ PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849) },
|
||||
{ PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878) },
|
||||
{ PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879) },
|
||||
{ PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ int cobalt_alsa_init(struct cobalt_stream *s)
|
|||
err_exit_free:
|
||||
if (sc != NULL)
|
||||
snd_card_free(sc);
|
||||
kfree(cobsc);
|
||||
err_exit:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,8 @@
|
|||
|
||||
/* add your revision and whatnot here */
|
||||
static const struct pci_device_id cobalt_pci_tbl[] = {
|
||||
{PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0,}
|
||||
{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_COBALT) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -40,9 +40,8 @@ EXPORT_SYMBOL(cx18_ext_init);
|
|||
|
||||
/* add your revision and whatnot here */
|
||||
static const struct pci_device_id cx18_pci_tbl[] = {
|
||||
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0,}
|
||||
{ PCI_VDEVICE(CX, PCI_DEVICE_ID_CX23418) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
|
|||
: VBI_HBLANK_SAMPLES_50HZ;
|
||||
|
||||
/* find the first valid line */
|
||||
for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) {
|
||||
for (i = hdr_size, buf += hdr_size; i + 3 < size; i++, buf++) {
|
||||
if (buf[0] == 0xff && !buf[1] && !buf[2] &&
|
||||
(buf[3] == sliced_vbi_eav_rp[0] ||
|
||||
buf[3] == sliced_vbi_eav_rp[1]))
|
||||
|
|
|
|||
|
|
@ -528,6 +528,7 @@ void netup_ci_exit(struct cx23885_tsport *port)
|
|||
if (NULL == state->ca.data)
|
||||
return;
|
||||
|
||||
cancel_work_sync(&state->work);
|
||||
dvb_ca_en50221_release(&state->ca);
|
||||
kfree(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2279,16 +2279,10 @@ static int __maybe_unused cx23885_resume(struct device *dev_d)
|
|||
static const struct pci_device_id cx23885_pci_tbl[] = {
|
||||
{
|
||||
/* CX23885 */
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8852,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_DEVICE(0x14f1, 0x8852),
|
||||
}, {
|
||||
/* CX23887 Rev 2 */
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8880,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_DEVICE(0x14f1, 0x8880),
|
||||
}, {
|
||||
/* --- end of list --- */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -681,8 +681,8 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
|
|||
*/
|
||||
|
||||
static const struct pci_device_id __maybe_unused cx25821_audio_pci_tbl[] = {
|
||||
{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0,}
|
||||
{ PCI_DEVICE(0x14f1, 0x0920) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -1347,16 +1347,10 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
|
|||
static const struct pci_device_id cx25821_pci_tbl[] = {
|
||||
{
|
||||
/* CX25821 Athena */
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8210,
|
||||
.subvendor = 0x14f1,
|
||||
.subdevice = 0x0920,
|
||||
PCI_DEVICE_SUB(0x14f1, 0x8210, 0x14f1, 0x0920),
|
||||
}, {
|
||||
/* CX25821 No Brand */
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8210,
|
||||
.subvendor = 0x0000,
|
||||
.subdevice = 0x0000,
|
||||
PCI_DEVICE_SUB(0x14f1, 0x8210, 0x0000, 0x0000),
|
||||
}, {
|
||||
/* --- end of list --- */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -809,9 +809,9 @@ static const struct snd_kcontrol_new snd_cx88_alc_switch = {
|
|||
*/
|
||||
|
||||
static const struct pci_device_id cx88_audio_pci_tbl[] = {
|
||||
{0x14f1, 0x8801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0x14f1, 0x8811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0, }
|
||||
{ PCI_DEVICE(0x14f1, 0x8801) },
|
||||
{ PCI_DEVICE(0x14f1, 0x8811) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
|
||||
|
||||
|
|
|
|||
|
|
@ -640,6 +640,7 @@ int cx8802_register_driver(struct cx8802_driver *drv)
|
|||
list_add_tail(&driver->drvlist, &dev->drvlist);
|
||||
} else {
|
||||
pr_err("cx8802 probe failed, err = %d\n", err);
|
||||
kfree(driver);
|
||||
}
|
||||
mutex_unlock(&drv->core->lock);
|
||||
}
|
||||
|
|
@ -787,10 +788,7 @@ static void cx8802_remove(struct pci_dev *pci_dev)
|
|||
|
||||
static const struct pci_device_id cx8802_pci_tbl[] = {
|
||||
{
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8802,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_DEVICE(0x14f1, 0x8802),
|
||||
}, {
|
||||
/* --- end of list --- */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1610,10 +1610,7 @@ static int __maybe_unused cx8800_resume(struct device *dev_d)
|
|||
|
||||
static const struct pci_device_id cx8800_pci_tbl[] = {
|
||||
{
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8800,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_DEVICE(0x14f1, 0x8800),
|
||||
}, {
|
||||
/* --- end of list --- */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ static const struct pci_device_id ddb_id_table[] = {
|
|||
DDB_DEVICE_ANY(0x0323),
|
||||
DDB_DEVICE_ANY(0x0328),
|
||||
DDB_DEVICE_ANY(0x0329),
|
||||
{0}
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, ddb_id_table);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
|||
|
|
@ -1209,15 +1209,9 @@ static void dm1105_remove(struct pci_dev *pdev)
|
|||
|
||||
static const struct pci_device_id dm1105_id_table[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_TRIGEM,
|
||||
.device = PCI_DEVICE_ID_DM1105,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_VDEVICE(TRIGEM, PCI_DEVICE_ID_DM1105),
|
||||
}, {
|
||||
.vendor = PCI_VENDOR_ID_AXESS,
|
||||
.device = PCI_DEVICE_ID_DM05,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_VDEVICE(AXESS, PCI_DEVICE_ID_DM05),
|
||||
}, {
|
||||
/* empty */
|
||||
},
|
||||
|
|
|
|||
|
|
@ -577,8 +577,8 @@ static void dt3155_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
static const struct pci_device_id pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
|
||||
{ 0, /* zero marks the end */ },
|
||||
{ PCI_VDEVICE(INTEL, DT3155_DEVICE_ID) },
|
||||
{ /* zero marks the end */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,10 @@ int hws_vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *setfp
|
|||
int hws_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i);
|
||||
int hws_vidioc_g_input(struct file *file, void *priv, unsigned int *i);
|
||||
int hws_vidioc_s_input(struct file *file, void *priv, unsigned int i);
|
||||
int hws_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a);
|
||||
int hws_vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a);
|
||||
int hws_vidioc_dv_timings_cap(struct file *file, void *fh,
|
||||
struct v4l2_dv_timings_cap *cap);
|
||||
int hws_vidioc_s_dv_timings(struct file *file, void *fh,
|
||||
struct v4l2_dv_timings *timings);
|
||||
|
||||
int hws_vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
|
||||
int hws_vidioc_g_dv_timings(struct file *file, void *fh,
|
||||
struct v4l2_dv_timings *timings);
|
||||
int hws_vidioc_enum_dv_timings(struct file *file, void *fh,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
* Please keep the list sorted by ACPI HID.
|
||||
*/
|
||||
static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
||||
/* Himax HM1092 */
|
||||
IPU_SENSOR_CONFIG("HIMX1092", 2, 180000000, 180480000),
|
||||
/* Himax HM11B1 */
|
||||
IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000),
|
||||
/* Himax HM2170 */
|
||||
|
|
@ -97,6 +99,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
|||
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
|
||||
/* Sony IMX471 */
|
||||
IPU_SENSOR_CONFIG("SONY471A", 1, 200000000),
|
||||
/* Sony IMX471 (found on Lenovo X1 Carbon G14) */
|
||||
IPU_SENSOR_CONFIG("TBE20A0", 1, 200000000),
|
||||
/* Toshiba T4KA3 */
|
||||
IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000),
|
||||
};
|
||||
|
|
@ -134,6 +138,60 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
|
|||
},
|
||||
.driver_data = "OVTI02C1",
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 16 (Dell 16 Premium) DA16250"),
|
||||
},
|
||||
.driver_data = "OVTI02C1",
|
||||
},
|
||||
/*
|
||||
* The first four characters of DMI_BOARD_NAME identify the Lenovo
|
||||
* machine type/model. For example, a DMI_BOARD_NAME starting with
|
||||
* "21Q6" indicates a ThinkPad X9-15.
|
||||
*
|
||||
* Reference: https://psref.lenovo.com/
|
||||
*/
|
||||
{
|
||||
/* Lenovo X9-14 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "21QA"),
|
||||
},
|
||||
.driver_data = "SONY471A",
|
||||
},
|
||||
{
|
||||
/* Lenovo X9-14 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "21QB"),
|
||||
},
|
||||
.driver_data = "SONY471A",
|
||||
},
|
||||
{
|
||||
/* Lenovo X9-15 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "21Q6"),
|
||||
},
|
||||
.driver_data = "SONY471A",
|
||||
},
|
||||
{
|
||||
/* Lenovo X9-15 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "21Q7"),
|
||||
},
|
||||
.driver_data = "SONY471A",
|
||||
},
|
||||
{
|
||||
/* Samsung Galaxy Book5 Pro 360 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "960QHA"),
|
||||
},
|
||||
.driver_data = "OVTI02E1",
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
|
|
@ -171,6 +229,7 @@ static const struct acpi_device_id ivsc_acpi_ids[] = {
|
|||
{ "INTC10DE" }, /* LNL */
|
||||
{ "INTC10E0" }, /* ARL */
|
||||
{ "INTC10E1" }, /* PTL */
|
||||
{ "INTC10FA" }, /* NVL */
|
||||
};
|
||||
|
||||
static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev)
|
||||
|
|
@ -180,8 +239,8 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev
|
|||
for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) {
|
||||
const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i];
|
||||
struct acpi_device *consumer, *ivsc_adev;
|
||||
|
||||
acpi_handle handle = acpi_device_handle(ACPI_PTR(adev));
|
||||
|
||||
for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1)
|
||||
/* camera sensor depends on IVSC in DSDT if exist */
|
||||
for_each_acpi_consumer_dev(ivsc_adev, consumer)
|
||||
|
|
@ -298,9 +357,11 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
|
|||
{
|
||||
const struct dmi_system_id *dmi_id;
|
||||
|
||||
dmi_id = dmi_first_match(upside_down_sensor_dmi_ids);
|
||||
if (dmi_id && acpi_dev_hid_match(adev, dmi_id->driver_data))
|
||||
return 180;
|
||||
/* A machine may have one entry per sensor, so check all matches. */
|
||||
for (dmi_id = dmi_first_match(upside_down_sensor_dmi_ids); dmi_id;
|
||||
dmi_id = dmi_first_match(dmi_id + 1))
|
||||
if (acpi_dev_hid_match(adev, dmi_id->driver_data))
|
||||
return 180;
|
||||
|
||||
switch (ssdb->degree) {
|
||||
case IPU_SENSOR_ROTATION_NORMAL:
|
||||
|
|
|
|||
|
|
@ -1961,7 +1961,7 @@ static const struct dev_pm_ops cio2_pm_ops = {
|
|||
};
|
||||
|
||||
static const struct pci_device_id cio2_pci_id_table[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, CIO2_PCI_ID) },
|
||||
{ PCI_VDEVICE(INTEL, CIO2_PCI_ID) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -761,6 +761,7 @@ static int isys_notifier_init(struct ipu6_isys *isys)
|
|||
|
||||
err_parse:
|
||||
fwnode_handle_put(ep);
|
||||
v4l2_async_nf_cleanup(&isys->notifier);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -400,7 +400,6 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
|
|||
&ipdata->hw_variant);
|
||||
if (IS_ERR(isys_adev->mmu)) {
|
||||
put_device(&isys_adev->auxdev.dev);
|
||||
kfree(pdata);
|
||||
return dev_err_cast_probe(dev, isys_adev->mmu,
|
||||
"ipu6_mmu_init(isys_adev->mmu) failed\n");
|
||||
}
|
||||
|
|
@ -408,10 +407,8 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
|
|||
isys_adev->mmu->dev = &isys_adev->auxdev.dev;
|
||||
|
||||
ret = ipu6_bus_add_device(isys_adev);
|
||||
if (ret) {
|
||||
kfree(pdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return isys_adev;
|
||||
}
|
||||
|
|
@ -444,7 +441,6 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
|
|||
&ipdata->hw_variant);
|
||||
if (IS_ERR(psys_adev->mmu)) {
|
||||
put_device(&psys_adev->auxdev.dev);
|
||||
kfree(pdata);
|
||||
return dev_err_cast_probe(&pdev->dev, psys_adev->mmu,
|
||||
"ipu6_mmu_init(psys_adev->mmu) failed\n");
|
||||
}
|
||||
|
|
@ -452,10 +448,8 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
|
|||
psys_adev->mmu->dev = &psys_adev->auxdev.dev;
|
||||
|
||||
ret = ipu6_bus_add_device(psys_adev);
|
||||
if (ret) {
|
||||
kfree(pdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return psys_adev;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,11 +60,9 @@ EXPORT_SYMBOL(ivtv_ext_init);
|
|||
|
||||
/* add your revision and whatnot here */
|
||||
static const struct pci_device_id ivtv_pci_tbl[] = {
|
||||
{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0,}
|
||||
{ PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV15) },
|
||||
{ PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV16) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
|
|||
unsigned lines = 0;
|
||||
|
||||
/* find the first valid line */
|
||||
for (i = 0; i < size; i++, buf++) {
|
||||
for (i = 0; i + 3 < size; i++, buf++) {
|
||||
if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,9 @@
|
|||
#define TERRATEC 0x153b
|
||||
|
||||
#define MAKE_ENTRY(__subven, __subdev, __configptr, __rc) { \
|
||||
.vendor = TWINHAN_TECHNOLOGIES, \
|
||||
.device = MANTIS, \
|
||||
.subvendor = (__subven), \
|
||||
.subdevice = (__subdev), \
|
||||
.driver_data = (unsigned long) \
|
||||
PCI_DEVICE_SUB(TWINHAN_TECHNOLOGIES, MANTIS, \
|
||||
(__subven), (__subdev)), \
|
||||
.driver_data = (unsigned long) \
|
||||
&(struct mantis_pci_drvdata){__configptr, __rc} \
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -694,9 +694,9 @@ static void mgb4_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
static const struct pci_device_id mgb4_pci_ids[] = {
|
||||
{ PCI_DEVICE(DIGITEQ_VID, T100_DID), },
|
||||
{ PCI_DEVICE(DIGITEQ_VID, T200_DID), },
|
||||
{ 0, }
|
||||
{ PCI_DEVICE(DIGITEQ_VID, T100_DID) },
|
||||
{ PCI_DEVICE(DIGITEQ_VID, T200_DID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, mgb4_pci_ids);
|
||||
|
||||
|
|
|
|||
|
|
@ -1014,7 +1014,7 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev)
|
|||
static const struct pci_device_id netup_unidvb_pci_tbl[] = {
|
||||
{ PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */
|
||||
{ PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */
|
||||
{ 0, }
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl);
|
||||
|
||||
|
|
|
|||
|
|
@ -1155,8 +1155,7 @@ static const struct ngene_info ngene_info_terratec = {
|
|||
/****************************************************************************/
|
||||
|
||||
#define NGENE_ID(_subvend, _subdev, _driverdata) { \
|
||||
.vendor = NGENE_VID, .device = NGENE_PID, \
|
||||
.subvendor = _subvend, .subdevice = _subdev, \
|
||||
PCI_DEVICE_SUB(NGENE_VID, NGENE_PID, (_subvend), (_subdev)), \
|
||||
.driver_data = (unsigned long) &_driverdata }
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
@ -1173,7 +1172,7 @@ static const struct pci_device_id ngene_id_tbl[] = {
|
|||
NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
|
||||
NGENE_ID(0x1461, 0x062e, ngene_info_m780),
|
||||
NGENE_ID(0x153b, 0x1167, ngene_info_terratec),
|
||||
{0}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
|
||||
|
||||
|
|
|
|||
|
|
@ -762,10 +762,7 @@ static void pluto2_remove(struct pci_dev *pdev)
|
|||
|
||||
static const struct pci_device_id pluto2_id_table[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_SCM,
|
||||
.device = PCI_DEVICE_ID_PLUTO2,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
PCI_VDEVICE(SCM, PCI_DEVICE_ID_PLUTO2),
|
||||
}, {
|
||||
/* empty */
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -361,22 +361,14 @@ static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
|
|||
|
||||
static const struct pci_device_id pci_tbl[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x17c8,
|
||||
.subdevice = 0x2401,
|
||||
.driver_data = (unsigned long) &hexium_gemini_4bnc,
|
||||
},
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2401),
|
||||
.driver_data = (unsigned long)&hexium_gemini_4bnc,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x17c8,
|
||||
.subdevice = 0x2402,
|
||||
.driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
|
||||
},
|
||||
{
|
||||
.vendor = 0,
|
||||
}
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2402),
|
||||
.driver_data = (unsigned long)&hexium_gemini_dual_4bnc,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
|
|
|||
|
|
@ -425,29 +425,16 @@ static struct saa7146_pci_extension_data hexium_orion_4bnc = {
|
|||
|
||||
static const struct pci_device_id pci_tbl[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x0000,
|
||||
.subdevice = 0x0000,
|
||||
.driver_data = (unsigned long) &hexium_hv_pci6,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x17c8,
|
||||
.subdevice = 0x0101,
|
||||
.driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x17c8,
|
||||
.subdevice = 0x2101,
|
||||
.driver_data = (unsigned long) &hexium_orion_4bnc,
|
||||
},
|
||||
{
|
||||
.vendor = 0,
|
||||
}
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000),
|
||||
.driver_data = (unsigned long)&hexium_hv_pci6,
|
||||
}, {
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x0101),
|
||||
.driver_data = (unsigned long)&hexium_orion_1svhs_3bnc,
|
||||
}, {
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2101),
|
||||
.driver_data = (unsigned long)&hexium_orion_4bnc,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
|
|
|||
|
|
@ -821,14 +821,10 @@ static struct saa7146_pci_extension_data mxb = {
|
|||
|
||||
static const struct pci_device_id pci_tbl[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PHILIPS,
|
||||
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
|
||||
.subvendor = 0x0000,
|
||||
.subdevice = 0x0000,
|
||||
PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000),
|
||||
.driver_data = (unsigned long)&mxb,
|
||||
}, {
|
||||
.vendor = 0,
|
||||
}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user