* [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver
@ 2026-09-25 13:29 Rishikesh Donadkar
2026-09-25 13:29 ` [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 Rishikesh Donadkar
` (7 more replies)
0 siblings, 8 replies; 15+ messages in thread
From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw)
To: linux-media, linux-kernel, devicetree, linux-arm-kernel
Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr,
kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht,
y-abhilashchandra, mirela.rabulea, laurent.pinchart
The OmniVision OV2312 is an RGB-IR camera sensor with a 1600x1300 active
array. It uses a 4x4 Bayer pattern that interleaves near-infrared (Ir)
pixels alongside R, G, and B pixels, enabling both RGB and IR capture
from a single sensor.
Every frame the sensor alternates its exposure and IR flash strobe
settings to produce two complementary images, streamed simultaneously with
two MIPI CSI-2 virtual channels:
- VC0: IR-dominant frame
- VC1: RGB-dominant frame
Because the OV2312 uses a 4x4 Bayer pattern with Ir pixels (RGBIr), the
existing 2x2 Bayer pixel formats are insufficient. This series adds eight
new 10-bit RGBIr media-bus and V4L2 pixel formats (one per valid phase of
the 4x4 pattern) and propagates them through the relevant drivers along
the capture path : DS90UB960 deserializer, Cadence CSI-2 RX
and TI J721E CSI-2 RX as seen in the `media-ctl --print-dot` output[1]
Two alternating frames are captured under different lighting
conditions - one optimised for RGB and one for IR - they require
independent exposure and gain settings. The standard V4L2 exposure and
gain controls (V4L2_CID_EXPOSURE, V4L2_CID_AGAIN, V4L2_CID_DGAIN) are
single-valued per subdevice, which makes it impossible to express
per-stream settings for a sensor like the OV2312 that produces two
distinct streams from a single I2C-controlled device. The new
V4L2_CID_EXPOSURE_MULTI, V4L2_CID_AGAIN_MULTI, and V4L2_CID_DGAIN_MULTI
controls introduced by Mirela Rabulea [2] solve this by defining each
control as a U32 array, one element per capture type. The OV2312 driver
uses a two-element array where index 0 carries the value for the
RGB-dominant frame and index 1 carries the value for the IR-dominant
frame, giving userspace independent control over both streams through a
single subdevice handle. The driver treats a zero value as a sentinel
meaning "no update for this capture type": the register patch for a given
stream is applied only when all three controls (exposure, analog gain, and
digital gain) carry a non-zero value for that index. This allows userspace
to update RGB settings alone by setting index 0 to the desired values and
leaving index 1 at zero, and vice versa.
Both streams run at 1600x1301 resolution, 30 fps each, where the image
data is 1600x1300 and one extra row carries embedded data. The driver
exposes these as separate v4l2 streams which a downstream CSI-RX DMA
driver can route to independent /dev/videoX nodes. Because the two virtual
channels are driven by alternating register groups with different exposure
and IR strobe settings, a pipeline misrouting (e.g., an RGB frame landing
on the IR channel) may not be obvious from the pixel data alone.
Userspace can use the embedded line, which encodes per-frame sensor state
including strobe and exposure register values, to verify that each received
frame matches the expected capture type for that virtual channel.
[1] https://gist.github.com/RISHI27-dot/1876791cba10798412050e1142fa7899
[2] https://lore.kernel.org/all/20250818155809.469479-1-mirela.rabulea@nxp.com/
Testing Details:
===============
This series is tested on the Texas Instruments AM62A7-SK EVM with the
LI-OV2312-FPDLinkIII-110H camera module connected via the
V3Link FPDLink-III daughter card using GStreamer
Testing branch (device-tree overlays and any patches
not yet upstream):
https://github.com/RISHI27-dot/linux/commits/lpc/ov2312/
GStreamer pipeline:
https://gist.github.com/RISHI27-dot/87dc7dec1fdec5f20ead02ca7defb4a8
source code for tiovxisp gst plugin that does the ioctl to set array
controls and does the embedded data filtering:
https://github.com/RISHI27-dot/edgeai-gst-plugins/blob/lpc/ov2312/ext/tiovx/gsttiovxisp.c
Dependencies:
============
This series depends on the following patch series:
https://lore.kernel.org/all/20250818155809.469479-1-mirela.rabulea@nxp.com/
Jai Luthra (7):
dt-bindings: media: Add bindings for Omnivision OV2312
media: v4l: Add 10-bit RGBIr formats
media: i2c: ds90ub960: Add 10-bit RGBIr formats
media: cadence: csi2rx: Add RAW10 RGBIr formats
media: ti: j721e-csi2rx: Add RAW10 RGBIr formats
media: i2c: ov2312: add Omnivison OV2312 driver
arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312
Rishikesh Donadkar (1):
arm64: defconfig: Enable OV2312
.../bindings/media/i2c/ovti,ov2312.yaml | 79 ++
arch/arm64/boot/dts/ti/Makefile | 6 +
.../boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso | 89 ++
.../boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso | 89 ++
.../boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso | 89 ++
.../boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso | 89 ++
arch/arm64/configs/defconfig | 1 +
drivers/media/i2c/Kconfig | 12 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/ds90ub960.c | 18 +
drivers/media/i2c/ov2312.c | 939 ++++++++++++++++++
drivers/media/i2c/ov2312.h | 285 ++++++
drivers/media/platform/cadence/cdns-csi2rx.c | 8 +
.../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 48 +
drivers/media/v4l2-core/v4l2-ioctl.c | 8 +
include/uapi/linux/media-bus-format.h | 10 +-
include/uapi/linux/videodev2.h | 9 +
17 files changed, 1779 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml
create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso
create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso
create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso
create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso
create mode 100644 drivers/media/i2c/ov2312.c
create mode 100644 drivers/media/i2c/ov2312.h
--
2.34.1
^ permalink raw reply [flat|nested] 15+ messages in thread* [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-26 14:51 ` Laurent Pinchart 2026-09-25 13:29 ` [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats Rishikesh Donadkar ` (6 subsequent siblings) 7 siblings, 1 reply; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Add DT bindings for Omnivision OV2312 camera sensor. Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- .../bindings/media/i2c/ovti,ov2312.yaml | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml new file mode 100644 index 000000000000..76929fcc6550 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov2312.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV2312 Camera Sensor + +maintainers: + - Jai Luthra <j-luthra@ti.com> + +description: |- + Omnvision OV2312 is a camera sensor with an active array size of 1600x1300. + It supports capture of frames with a 4x4 RGB-IR bayer pattern. This provides + both human (RGB) and machine vision (IR) capabilities in low-light scenarios. + +properties: + compatible: + enum: + - ovti,ov2312 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: xvclk + + reset-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the RESET pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: ../video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&fixed_clock>; + clock-names = "xvclk"; + + reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; + + port { + camera1: endpoint { + remote-endpoint = <&vin1a_ep>; + }; + }; + }; + }; + +... -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 2026-09-25 13:29 ` [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 Rishikesh Donadkar @ 2026-09-26 14:51 ` Laurent Pinchart 0 siblings, 0 replies; 15+ messages in thread From: Laurent Pinchart @ 2026-09-26 14:51 UTC (permalink / raw) To: Rishikesh Donadkar Cc: linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea On Fri, Sep 25, 2026 at 06:59:54PM +0530, Rishikesh Donadkar wrote: > From: Jai Luthra <j-luthra@ti.com> > > Add DT bindings for Omnivision OV2312 camera sensor. > > Signed-off-by: Jai Luthra <j-luthra@ti.com> > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> > --- > .../bindings/media/i2c/ovti,ov2312.yaml | 79 +++++++++++++++++++ > 1 file changed, 79 insertions(+) > create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml > > diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml > new file mode 100644 > index 000000000000..76929fcc6550 > --- /dev/null > +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2312.yaml > @@ -0,0 +1,79 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/media/i2c/ovti,ov2312.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: OmniVision OV2312 Camera Sensor > + > +maintainers: > + - Jai Luthra <j-luthra@ti.com> > + > +description: |- > + Omnvision OV2312 is a camera sensor with an active array size of 1600x1300. s/Omnvision/OmniVision/ (although they now seem to style the company name as OMNIVISION) > + It supports capture of frames with a 4x4 RGB-IR bayer pattern. This provides > + both human (RGB) and machine vision (IR) capabilities in low-light scenarios. > + > +properties: > + compatible: > + enum: > + - ovti,ov2312 > + > + reg: > + maxItems: 1 > + > + clocks: > + maxItems: 1 > + > + clock-names: > + const: xvclk If there's a single clock, drop the name. > + > + reset-gpios: > + maxItems: 1 > + description: > + Specifier for the GPIO connected to the RESET pin. You also need regulators. > + > + port: > + $ref: /schemas/graph.yaml#/properties/port > + additionalProperties: false > + > + properties: > + endpoint: > + $ref: ../video-interfaces.yaml# > + unevaluatedProperties: false The sensor supports both CSI-2 and parallel output. You need to be more precise here regarding the supported properties. The bus type, in particular, needs to be defined. > + > +required: > + - compatible > + - reg > + - clocks > + - clock-names > + - port > + > +additionalProperties: false > + > +examples: > + - | > + #include <dt-bindings/gpio/gpio.h> > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + camera@60 { > + compatible = "ovti,ov2312"; > + reg = <0x60>; > + > + clocks = <&fixed_clock>; > + clock-names = "xvclk"; > + > + reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; > + > + port { > + camera1: endpoint { > + remote-endpoint = <&vin1a_ep>; > + }; > + }; > + }; > + }; > + > +... -- Regards, Laurent Pinchart ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-26 14:30 ` Sakari Ailus 2026-09-25 13:29 ` [RFC PATCH 3/8] media: i2c: ds90ub960: " Rishikesh Donadkar ` (5 subsequent siblings) 7 siblings, 1 reply; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Some camera sensors now use an expanded CFA pattern to capture near-IR light along with the visible spectrum (R,G,B). This allows capturing light in both low-light and day-light scenarios using the same sensor. Instead of having a 2x2 repetition of B,G,R like in older bayer formats, here we have a 4x4 repetition of B,G,R,Ir where the number of G pixels are the same, but half the B and R pixels are replaced with Ir. Thus instead of having 4 total phases, we now have 8 total phases or re-arrangements of this pattern. Co-developed-by: Rahul T R <r-ravikumar@ti.com> Signed-off-by: Rahul T R <r-ravikumar@ti.com> Signed-off-by: Jai Luthra <j-luthra@ti.com> Co-developed-by: Rishikesh Donadkar <r-donadkar@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++++++ include/uapi/linux/media-bus-format.h | 10 +++++++++- include/uapi/linux/videodev2.h | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 17ba1ae70735..97ce6e1a6781 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1435,6 +1435,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break; case V4L2_PIX_FMT_RAW_CRU20: descr = "14-bit Raw CRU Packed"; break; + case V4L2_PIX_FMT_SRGGI10: descr = "10-bit Bayer RGBG/GIrGIr"; break; + case V4L2_PIX_FMT_SGRIG10: descr = "10-bit Bayer GRGB/IrGIrG"; break; + case V4L2_PIX_FMT_SBGGI10: descr = "10-bit Bayer BGRG/GIrGIr"; break; + case V4L2_PIX_FMT_SGBIG10: descr = "10-bit Bayer GBGR/IrGIrG"; break; + case V4L2_PIX_FMT_SGIRG10: descr = "10-bit Bayer GIrGIr/RGBG"; break; + case V4L2_PIX_FMT_SIGGR10: descr = "10-bit Bayer IrGIrG/GRGB"; break; + case V4L2_PIX_FMT_SGIBG10: descr = "10-bit Bayer GIrGIr/BGRG"; break; + case V4L2_PIX_FMT_SIGGB10: descr = "10-bit Bayer IrGIrG/GBGR"; break; case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 6005f033e62c..c50042300a98 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -124,7 +124,7 @@ #define MEDIA_BUS_FMT_YUV16_1X48 0x202a #define MEDIA_BUS_FMT_UYYVYY16_0_5X48 0x202b -/* Bayer - next is 0x3025 */ +/* Bayer - next is 0x3029 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 #define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 #define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 @@ -161,6 +161,14 @@ #define MEDIA_BUS_FMT_SGBRG20_1X20 0x3022 #define MEDIA_BUS_FMT_SGRBG20_1X20 0x3023 #define MEDIA_BUS_FMT_SRGGB20_1X20 0x3024 +#define MEDIA_BUS_FMT_SRGGI10_1X10 0x3021 +#define MEDIA_BUS_FMT_SGRIG10_1X10 0x3022 +#define MEDIA_BUS_FMT_SBGGI10_1X10 0x3023 +#define MEDIA_BUS_FMT_SGBIG10_1X10 0x3024 +#define MEDIA_BUS_FMT_SGIRG10_1X10 0x3025 +#define MEDIA_BUS_FMT_SIGGR10_1X10 0x3026 +#define MEDIA_BUS_FMT_SGIBG10_1X10 0x3027 +#define MEDIA_BUS_FMT_SIGGB10_1X10 0x3028 /* JPEG compressed formats - next is 0x4002 */ #define MEDIA_BUS_FMT_JPEG_1X8 0x4001 diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 5373dba640fa..c56af0826f59 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -744,6 +744,15 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16 RGRG.. GBGB.. */ + /* 10bit raw bayer with IR (4x4) */ +#define V4L2_PIX_FMT_SRGGI10 v4l2_fourcc('R', 'G', 'I', '0') /* 10 RGBG.. GIrGIr.. */ +#define V4L2_PIX_FMT_SGRIG10 v4l2_fourcc('G', 'R', 'I', '0') /* 10 GRGB.. IrGIrG.. */ +#define V4L2_PIX_FMT_SBGGI10 v4l2_fourcc('B', 'G', 'I', '0') /* 10 BGRG.. GIrGIr.. */ +#define V4L2_PIX_FMT_SGBIG10 v4l2_fourcc('G', 'B', 'I', '0') /* 10 GBGR.. IrGIrG.. */ +#define V4L2_PIX_FMT_SGIRG10 v4l2_fourcc('G', 'I', 'R', '0') /* 10 GIrGIr.. RGBG.. */ +#define V4L2_PIX_FMT_SIGGR10 v4l2_fourcc('I', 'G', 'R', '0') /* 10 IrGIrG.. GRGB.. */ +#define V4L2_PIX_FMT_SGIBG10 v4l2_fourcc('G', 'I', 'B', '0') /* 10 GIrGIr.. BGRG.. */ +#define V4L2_PIX_FMT_SIGGB10 v4l2_fourcc('I', 'G', 'B', '0') /* 10 IrGIrG.. GBGR.. */ /* HSV formats */ #define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3') -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats 2026-09-25 13:29 ` [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats Rishikesh Donadkar @ 2026-09-26 14:30 ` Sakari Ailus 2026-09-26 14:40 ` Laurent Pinchart 0 siblings, 1 reply; 15+ messages in thread From: Sakari Ailus @ 2026-09-26 14:30 UTC (permalink / raw) To: Rishikesh Donadkar Cc: linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart Hi Rishikesh, On Fri, Sep 25, 2026 at 06:59:55PM +0530, Rishikesh Donadkar wrote: > From: Jai Luthra <j-luthra@ti.com> > > Some camera sensors now use an expanded CFA pattern to capture near-IR > light along with the visible spectrum (R,G,B). This allows capturing > light in both low-light and day-light scenarios using the same sensor. > > Instead of having a 2x2 repetition of B,G,R like in older bayer formats, > here we have a 4x4 repetition of B,G,R,Ir where the number of G pixels > are the same, but half the B and R pixels are replaced with Ir. Thus > instead of having 4 total phases, we now have 8 total phases or > re-arrangements of this pattern. > > Co-developed-by: Rahul T R <r-ravikumar@ti.com> > Signed-off-by: Rahul T R <r-ravikumar@ti.com> > Signed-off-by: Jai Luthra <j-luthra@ti.com> > Co-developed-by: Rishikesh Donadkar <r-donadkar@ti.com> > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> I think we need to use the common raw mbus and pixel formats for the patterns that have IR pixels. See <URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=metadata>. That's mostly pending on userspace support now. Can the sensor output Bayer pattern as well? -- Regards, Sakari Ailus ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats 2026-09-26 14:30 ` Sakari Ailus @ 2026-09-26 14:40 ` Laurent Pinchart 0 siblings, 0 replies; 15+ messages in thread From: Laurent Pinchart @ 2026-09-26 14:40 UTC (permalink / raw) To: Sakari Ailus Cc: Rishikesh Donadkar, linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea On Sat, Sep 26, 2026 at 05:30:22PM +0300, Sakari Ailus wrote: > Hi Rishikesh, > > On Fri, Sep 25, 2026 at 06:59:55PM +0530, Rishikesh Donadkar wrote: > > From: Jai Luthra <j-luthra@ti.com> > > > > Some camera sensors now use an expanded CFA pattern to capture near-IR > > light along with the visible spectrum (R,G,B). This allows capturing > > light in both low-light and day-light scenarios using the same sensor. > > > > Instead of having a 2x2 repetition of B,G,R like in older bayer formats, > > here we have a 4x4 repetition of B,G,R,Ir where the number of G pixels > > are the same, but half the B and R pixels are replaced with Ir. Thus > > instead of having 4 total phases, we now have 8 total phases or > > re-arrangements of this pattern. > > > > Co-developed-by: Rahul T R <r-ravikumar@ti.com> > > Signed-off-by: Rahul T R <r-ravikumar@ti.com> > > Signed-off-by: Jai Luthra <j-luthra@ti.com> > > Co-developed-by: Rishikesh Donadkar <r-donadkar@ti.com> > > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> > > I think we need to use the common raw mbus and pixel formats for the > patterns that have IR pixels. See > <URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=metadata>. That's right, we shouldn't add new CFA-specific media bus codes. They just don't scale. > That's mostly pending on userspace support now. > > Can the sensor output Bayer pattern as well? -- Regards, Laurent Pinchart ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 3/8] media: i2c: ds90ub960: Add 10-bit RGBIr formats 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 " Rishikesh Donadkar ` (4 subsequent siblings) 7 siblings, 0 replies; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Add new 4x4 RGBIr bayer formats Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- drivers/media/i2c/ds90ub960.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 7d7ba6d349fc..c86b18e0b4b3 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -664,6 +664,24 @@ static const struct ub960_format_info ub960_formats[] = { { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, + + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + + { .code = MEDIA_BUS_FMT_SRGGI10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGRIG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SBGGI10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGBIG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGIRG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SIGGR10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SGIBG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, + { .code = MEDIA_BUS_FMT_SIGGB10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, }, }; static const struct ub960_format_info *ub960_find_format(u32 code) -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 RGBIr formats 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar ` (2 preceding siblings ...) 2026-09-25 13:29 ` [RFC PATCH 3/8] media: i2c: ds90ub960: " Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-26 14:52 ` Laurent Pinchart 2026-09-25 13:29 ` [RFC PATCH 5/8] media: ti: j721e-csi2rx: " Rishikesh Donadkar ` (3 subsequent siblings) 7 siblings, 1 reply; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Add 10-bit RGBIr formats to the table to allow capturing them. Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- drivers/media/platform/cadence/cdns-csi2rx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index de7cce76397a..8ed730452d3c 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -173,6 +173,14 @@ static const struct csi2rx_fmt formats[] = { { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, .max_pixels = 1, }, { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, .max_pixels = 1, }, { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, .max_pixels = 1, }, + { .code = MEDIA_BUS_FMT_SRGGI10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SGRIG10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SBGGI10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SGBIG10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SGIRG10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SIGGR10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SGIBG10_1X10, .bpp = 10, .max_pixels = 2 }, + { .code = MEDIA_BUS_FMT_SIGGB10_1X10, .bpp = 10, .max_pixels = 2 }, }; static void csi2rx_configure_error_irq_mask(void __iomem *base, -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 RGBIr formats 2026-09-25 13:29 ` [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 " Rishikesh Donadkar @ 2026-09-26 14:52 ` Laurent Pinchart 0 siblings, 0 replies; 15+ messages in thread From: Laurent Pinchart @ 2026-09-26 14:52 UTC (permalink / raw) To: Rishikesh Donadkar Cc: linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea On Fri, Sep 25, 2026 at 06:59:57PM +0530, Rishikesh Donadkar wrote: > From: Jai Luthra <j-luthra@ti.com> > > Add 10-bit RGBIr formats to the table to allow capturing them. > > Signed-off-by: Jai Luthra <j-luthra@ti.com> > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> > --- > drivers/media/platform/cadence/cdns-csi2rx.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c > index de7cce76397a..8ed730452d3c 100644 > --- a/drivers/media/platform/cadence/cdns-csi2rx.c > +++ b/drivers/media/platform/cadence/cdns-csi2rx.c > @@ -173,6 +173,14 @@ static const struct csi2rx_fmt formats[] = { > { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, .max_pixels = 1, }, > { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, .max_pixels = 1, }, > { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, .max_pixels = 1, }, > + { .code = MEDIA_BUS_FMT_SRGGI10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SGRIG10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SBGGI10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SGBIG10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SGIRG10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SIGGR10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SGIBG10_1X10, .bpp = 10, .max_pixels = 2 }, > + { .code = MEDIA_BUS_FMT_SIGGB10_1X10, .bpp = 10, .max_pixels = 2 }, Raw formats will allow supporting all possible CFA patterns without having to extend each driver every time a new pattern is added. > }; > > static void csi2rx_configure_error_irq_mask(void __iomem *base, -- Regards, Laurent Pinchart ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 5/8] media: ti: j721e-csi2rx: Add RAW10 RGBIr formats 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar ` (3 preceding siblings ...) 2026-09-25 13:29 ` [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 " Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 6/8] media: i2c: ov2312: add Omnivison OV2312 driver Rishikesh Donadkar ` (2 subsequent siblings) 7 siblings, 0 replies; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Add 10-bit RGBIr formats to the table to allow capturing them. Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 022ea3d616c9..9f97f019368e 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -249,6 +249,54 @@ static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { .csi_dt = MIPI_CSI2_DT_RAW12, .bpp = 16, .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGI10, + .code = MEDIA_BUS_FMT_SRGGI10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRIG10, + .code = MEDIA_BUS_FMT_SGRIG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SBGGI10, + .code = MEDIA_BUS_FMT_SBGGI10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBIG10, + .code = MEDIA_BUS_FMT_SGBIG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGIRG10, + .code = MEDIA_BUS_FMT_SGIRG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SIGGR10, + .code = MEDIA_BUS_FMT_SIGGR10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGIBG10, + .code = MEDIA_BUS_FMT_SGIBG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SIGGB10, + .code = MEDIA_BUS_FMT_SIGGB10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, }, { .fourcc = V4L2_PIX_FMT_RGB565X, .code = MEDIA_BUS_FMT_RGB565_1X16, -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 6/8] media: i2c: ov2312: add Omnivison OV2312 driver 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar ` (4 preceding siblings ...) 2026-09-25 13:29 ` [RFC PATCH 5/8] media: ti: j721e-csi2rx: " Rishikesh Donadkar @ 2026-09-25 13:29 ` Rishikesh Donadkar 2026-09-25 13:30 ` [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 Rishikesh Donadkar 2026-09-25 13:30 ` [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 Rishikesh Donadkar 7 siblings, 0 replies; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:29 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> Omnivision OV2312 is an RGB-IR sensor, i.e. it uses a 4x4 R,G,B,Ir bayer pattern to capture both visible and near-infrared light. Every alternate frame, the sensor changes the exposure and IR flash strobe registers to stream an - A. IR-dominant frame on CSI-2 virtual channel 0 B. RGB-dominant frame on CSI-2 virtual channel 1 These A/B frames are routed as separate v4l2 streams, which may be mapped to two separate /dev/videoX nodes by the CSI-RX DMA driver. Both of these streams are captured at a resolution of 1600x1301, 30 fps each (60fps total). The extra row (1301 vs 1300) is an embedded line prepended to each frame by the sensor, containing the following register values: 0x4813 - VC (Virtual Channel) 0x321A - Group ID 0x3920 - Strobe 0x3501 - Exposure HI 0x3502 - Exposure LO 0x3508 - Gain HI 0x3509 - Gain LO 0x350e - Current Exposure HI 0x350f - Current Exposure LO This driver also supports a few v4l2 controls like horizontal/vertical flip, multi exposure and multi gain controls. Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- drivers/media/i2c/Kconfig | 12 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov2312.c | 939 +++++++++++++++++++++++++++++++++++++ drivers/media/i2c/ov2312.h | 285 +++++++++++ 4 files changed, 1237 insertions(+) create mode 100644 drivers/media/i2c/ov2312.c create mode 100644 drivers/media/i2c/ov2312.h diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4d9946479160..8d9d8d491b2e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -496,6 +496,18 @@ config VIDEO_OV13B10 This is a Video4Linux2 sensor driver for the OmniVision OV13B10 camera. +config VIDEO_OV2312 + tristate "OmniVision OV2312 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the OmniVision + OV2312 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2312. + config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" help diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index fd1cb25718c0..e019f174c5c0 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o obj-$(CONFIG_VIDEO_OV08X40) += ov08x40.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o +obj-$(CONFIG_VIDEO_OV2312) += ov2312.o obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o diff --git a/drivers/media/i2c/ov2312.c b/drivers/media/i2c/ov2312.c new file mode 100644 index 000000000000..1561e1b3602d --- /dev/null +++ b/drivers/media/i2c/ov2312.c @@ -0,0 +1,939 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Omnivision OV2312 RGB-IR Image Sensor driver + * + * Copyright (c) 2022 Jai Luthra <j-luthra@ti.com> + */ + +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ctrls.h> + +#include "ov2312.h" + +struct ov2312 { + struct device *dev; + + struct clk *clk; + unsigned long clk_rate; + + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *exposure_multi; + struct v4l2_ctrl *again_multi; + struct v4l2_ctrl *dgain_multi; + struct v4l2_ctrl *h_flip; + struct v4l2_ctrl *v_flip; + + u32 fps; + + struct mutex lock; /* For streaming status */ + unsigned int enable_count; +}; + +static inline struct ov2312 *to_ov2312(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov2312, sd); +} + +static int ov2312_read(struct ov2312 *ov2312, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(ov2312->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ov2312->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int ov2312_write(struct ov2312 *ov2312, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(ov2312->regmap, addr, &val_le, nbytes); + if (ret < 0) + dev_err(ov2312->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; +} + +static int ov2312_write_table(struct ov2312 *ov2312, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret, i; + + for (i = 0; i < nr_regs; i++) { + ret = regmap_write(ov2312->regmap, regs[i].reg, regs[i].def); + if (ret < 0) { + dev_err(ov2312->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, regs[i].reg, regs[i].def, ret); + return ret; + } + } + return 0; +} + +static void ov2312_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + int i; + + for (i = 0; i < 2; ++i) { + format = v4l2_subdev_state_get_format(state, 0, i); + format->code = ov2312_mbus_formats[0]; + format->width = ov2312_framesizes[0].width; + format->height = ov2312_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_DEFAULT; + } +} + +static int ov2312_set_fmt(struct v4l2_subdev *sd, + const struct v4l2_subdev_client_info *ci, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* Sensor only supports a single format. */ + code = ov2312_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(ov2312_framesizes, + ARRAY_SIZE(ov2312_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + v4l2_subdev_lock_state(state); + + /* Update the stored format and return it. */ + format = v4l2_subdev_state_get_format(state, fmt->pad, fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ov2312->enable_count) { + ret = -EBUSY; + goto done; + } + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int _ov2312_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + ov2312_init_formats(state); + + return 0; +} + +static int ov2312_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + unsigned int i; + + if (pad != 0) + return -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + fmt = v4l2_subdev_state_get_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream - 2 virtual channels */ + + bpp = 10; + + for (i = 0; i < 2; ++i) { + fd->entry[fd->num_entries].stream = i; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = i; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */ + + fd->num_entries++; + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ov2312_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 2) + return -EINVAL; + + v4l2_subdev_lock_state(state); + + ret = _ov2312_set_routing(sd, state); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ov2312_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _ov2312_set_routing(sd, state); + + return ret; +} + +static int ov2312_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(ov2312_mbus_formats)) + return -EINVAL; + + code->code = ov2312_mbus_formats[code->index]; + + return 0; +} + +static int ov2312_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov2312_mbus_formats); ++i) { + if (ov2312_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(ov2312_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(ov2312_framesizes)) + return -EINVAL; + + fse->min_width = ov2312_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ov2312_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ov2312_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval *fi) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = ov2312->fps / 2; + + return 0; +} + +static int ov2312_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval *fi) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + + if (!fi->interval.numerator) + return -EINVAL; + + dev_dbg(ov2312->dev, "%s: Set framerate %dfps\n", __func__, + fi->interval.denominator / fi->interval.numerator); + + if ((fi->interval.denominator / fi->interval.numerator) != ov2312->fps / 2) { + dev_err(ov2312->dev, "%s: Framerate can only be %dfps\n", + __func__, ov2312->fps / 2); + return -EINVAL; + } + + return 0; +} + +static int ov2312_detect(struct ov2312 *ov2312) +{ + int ret; + u32 id; + + ret = ov2312_read(ov2312, OV2312_SC_CHIP_ID_HI, &id, 2); + if (ret < 0) + return ret; + + id = cpu_to_be16(id); + + if (id != OV2312_CHIP_ID) { + dev_err(ov2312->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_dbg(ov2312->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +/* + */ +static int ov2312_set_group_a(struct ov2312 *ov2312) +{ + u32 ir_exposure = ov2312->exposure_multi->p_new.p_u32[1]; + u32 ir_again = ov2312->again_multi->p_new.p_u32[1]; + u32 ir_dgain = ov2312->dgain_multi->p_new.p_u32[1]; + u32 ir_strobe_start = OV2312_VTS - ir_exposure - 7; + int ret; + + struct reg_sequence ov2312_groupA[] = { + {0x3208, 0x00},/* Group A (IR Dominant VC0) */ + {OV2312_AEC_PK_EXPO_HI, (ir_exposure >> 8) & 0xff}, + {OV2312_AEC_PK_EXPO_LO, ir_exposure & 0xff}, + {OV2312_AEC_PK_AGAIN_HI, (ir_again >> 4) & 0xff}, + {OV2312_AEC_PK_AGAIN_LO, (ir_again & 0x0f) << 4}, + {OV2312_AEC_PK_DGAIN_HI, (ir_dgain >> 8) & 0xff}, + {OV2312_AEC_PK_DGAIN_LO, ir_dgain & 0xff}, + {0x3920, 0xff},/* IR Strobe duty cycle */ + {0x3927, (ir_exposure >> 8) & 0xff}, + {0x3928, ir_exposure & 0xff}, + {0x3929, (ir_strobe_start >> 8) & 0xff}, + {0x392a, ir_strobe_start & 0xff}, + {0x4813, 0x01},/* VC=1. This register takes effect from next frame */ + {0x3208, 0x10}, + {0x320D, 0x00},/* Auto mode switch between group0 and group1 ;setting to switch */ + {0x320D, 0x31}, + {0x3208, 0xA0}, + }; + + ret = regmap_register_patch(ov2312->regmap, ov2312_groupA, + ARRAY_SIZE(ov2312_groupA)); + if (ret < 0) + dev_err(ov2312->dev, + "%s: failed to apply Group A register patch (%d)!\n", + __func__, ret); + return ret; +} + +static int ov2312_set_group_b(struct ov2312 *ov2312) +{ + u32 rgb_exposure = ov2312->exposure_multi->p_new.p_u32[0]; + u32 rgb_again = ov2312->again_multi->p_new.p_u32[0]; + u32 rgb_dgain = ov2312->dgain_multi->p_new.p_u32[0]; + int ret; + + struct reg_sequence ov2312_groupB[] = { + {0x3208, 0x01},/* Group B (RGB Dominant VC1) */ + {OV2312_AEC_PK_EXPO_HI, (rgb_exposure >> 8) & 0xff}, + {OV2312_AEC_PK_EXPO_LO, rgb_exposure & 0xff}, + {OV2312_AEC_PK_AGAIN_HI, (rgb_again >> 4) & 0xff}, + {OV2312_AEC_PK_AGAIN_LO, (rgb_again & 0x0f) << 4}, + {OV2312_AEC_PK_DGAIN_HI, (rgb_dgain >> 8) & 0xff}, + {OV2312_AEC_PK_DGAIN_LO, rgb_dgain & 0xff}, + {0x3920, 0x00}, + {0x4813, 0x00},/* VC=0. This register takes effect from next frame */ + {0x3208, 0x11}, + {0x320D, 0x00},/* Auto mode switch between group0 and group1 ;setting to switch */ + {0x320D, 0x30}, + {0x3208, 0xA0}, + }; + + ret = regmap_register_patch(ov2312->regmap, ov2312_groupB, + ARRAY_SIZE(ov2312_groupB)); + if (ret < 0) + dev_err(ov2312->dev, + "%s: failed to apply Group B register patch (%d)!\n", + __func__, ret); + return ret; +} + +static int ov2312_set_AB_mode(struct ov2312 *ov2312) +{ + bool ir_ready = ov2312->exposure_multi->p_new.p_u32[1] && + ov2312->again_multi->p_new.p_u32[1] && + ov2312->dgain_multi->p_new.p_u32[1]; + bool rgb_ready = ov2312->exposure_multi->p_new.p_u32[0] && + ov2312->again_multi->p_new.p_u32[0] && + ov2312->dgain_multi->p_new.p_u32[0]; + int ret; + + if (ir_ready) { + ret = ov2312_set_group_a(ov2312); + if (ret < 0) + return ret; + } + + if (rgb_ready) { + ret = ov2312_set_group_b(ov2312); + if (ret < 0) + return ret; + } + + /* Wait for 1 frame duration after setting AB mode registers */ + if (ir_ready || rgb_ready) + msleep(33); + + return 0; +} + +static int ov2312_set_orientation(struct ov2312 *ov2312) +{ + bool v_flip = ov2312->v_flip->val; + bool h_flip = ov2312->h_flip->val; + u32 reg = (v_flip ? 0x4400 : 0) | (h_flip ? 0x0004 : 0); + + return ov2312_write(ov2312, OV2312_TIMING_VFLIP, be16_to_cpu(reg), 2); +} + +static int ov2312_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2312 *ov2312 = container_of(ctrl->handler, + struct ov2312, ctrls); + int ret; + + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (pm_runtime_suspended(ov2312->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_MULTI: + case V4L2_CID_AGAIN_MULTI: + case V4L2_CID_DGAIN_MULTI: + dev_dbg(ov2312->dev, "debug: %s: %s = [%u, %u]\n", __func__, + ctrl->name, ctrl->p_new.p_u32[0], ctrl->p_new.p_u32[1]); + + ret = ov2312_set_AB_mode(ov2312); + break; + + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = ov2312_set_orientation(ov2312); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static int ov2312_power_on(struct ov2312 *ov2312) +{ + int ret; + + ret = clk_prepare_enable(ov2312->clk); + if (ret < 0) + return ret; + + if (ov2312->reset_gpio) { + gpiod_set_value_cansleep(ov2312->reset_gpio, 0); + usleep_range(100, 1000); + gpiod_set_value_cansleep(ov2312->reset_gpio, 1); + msleep(30); + } + return 0; +} + +static int ov2312_power_off(struct ov2312 *ov2312) +{ + if (ov2312->reset_gpio) { + gpiod_set_value_cansleep(ov2312->reset_gpio, 0); + usleep_range(1, 10); + } + + clk_disable_unprepare(ov2312->clk); + + return 0; +} + +static int ov2312_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + return ov2312_power_on(ov2312); +} + +static int ov2312_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + return ov2312_power_off(ov2312); +} + +static int ov2312_start_stream(struct ov2312 *ov2312) +{ + int ret; + + ret = ov2312_write_table(ov2312, ov2312_1600x1300_60fps_AB, + ARRAY_SIZE(ov2312_1600x1300_60fps_AB)); + if (ret < 0) + return ret; + + /* Update controls on wake up */ + ret = ov2312_set_orientation(ov2312); + if (ret < 0) + return ret; + + ret = ov2312_set_AB_mode(ov2312); + if (ret < 0) + return ret; + + msleep(100); + + /* Set active */ + ret = ov2312_write(ov2312, OV2312_SYS_MODE_SEL, 1, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby */ + msleep(20); + return 0; +} + +static int ov2312_stop_stream(struct ov2312 *ov2312) +{ + int ret; + + /* Set standby */ + ret = ov2312_write(ov2312, OV2312_SYS_MODE_SEL, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int ov2312_sd_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + int ret; + + guard(mutex)(&ov2312->lock); + + if (!ov2312->enable_count) { + ret = pm_runtime_resume_and_get(ov2312->dev); + if (ret < 0) + goto err; + + ret = ov2312_start_stream(ov2312); + if (ret < 0) { + pm_runtime_put(ov2312->dev); + goto err; + } + } + + ov2312->enable_count++; + + return 0; + +err: + dev_err(ov2312->dev, + "%s: failed to enable streams %d\n", __func__, ret); + return ret; +} + +static int ov2312_sd_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ov2312 *ov2312 = to_ov2312(sd); + int ret; + + mutex_lock(&ov2312->lock); + + if (ov2312->enable_count == 1) { + ret = ov2312_stop_stream(ov2312); + if (ret < 0) + goto err_runtime_put; + } + + ov2312->enable_count--; + mutex_unlock(&ov2312->lock); + + if (!ov2312->enable_count) + pm_runtime_put(ov2312->dev); + + return 0; + +err_runtime_put: + mutex_unlock(&ov2312->lock); + pm_runtime_put(ov2312->dev); + return ret; +} + +static const struct v4l2_subdev_pad_ops ov2312_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov2312_set_fmt, + .enum_mbus_code = ov2312_enum_mbus_code, + .enum_frame_size = ov2312_enum_frame_sizes, + .set_routing = ov2312_set_routing, + .get_frame_desc = ov2312_get_frame_desc, + .get_frame_interval = ov2312_get_frame_interval, + .set_frame_interval = ov2312_set_frame_interval, + .enable_streams = ov2312_sd_enable_streams, + .disable_streams = ov2312_sd_disable_streams, +}; + +static const struct v4l2_subdev_internal_ops ov2312_internal_ops = { + .init_state = ov2312_init_state, +}; + +static const struct v4l2_subdev_ops ov2312_subdev_ops = { + .pad = &ov2312_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops ov2312_ctrl_ops = { + .s_ctrl = ov2312_set_ctrl, +}; + +static const struct dev_pm_ops ov2312_pm_ops = { + SET_RUNTIME_PM_OPS(ov2312_suspend, ov2312_resume, NULL) +}; + +static int ov2312_probe(struct i2c_client *client) +{ + struct ov2312 *ov2312; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + + /* Allocate internal struct */ + ov2312 = devm_kzalloc(&client->dev, sizeof(*ov2312), GFP_KERNEL); + if (!ov2312) + return -ENOMEM; + + ov2312->dev = &client->dev; + ov2312->client = client; + + /* Initialize I2C Regmap */ + ov2312->regmap = devm_regmap_init_i2c(client, &ov2312_regmap_config); + if (IS_ERR(ov2312->regmap)) + return PTR_ERR(ov2312->regmap); + + /* Initialize Shutdown GPIO */ + ov2312->reset_gpio = devm_gpiod_get_optional(ov2312->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov2312->reset_gpio)) + return PTR_ERR(ov2312->reset_gpio); + + ov2312->clk = devm_clk_get(ov2312->dev, "xvclk"); + if (IS_ERR(ov2312->clk)) + return PTR_ERR(ov2312->clk); + + ov2312->clk_rate = clk_get_rate(ov2312->clk); + dev_info(ov2312->dev, "xvclk rate: %lu Hz\n", ov2312->clk_rate); + + if (ov2312->clk_rate < 6000000 || ov2312->clk_rate > 27000000) + return -EINVAL; + + /* Power on */ + ret = ov2312_power_on(ov2312); + if (ret < 0) + return ret; + + /* Detect sensor */ + ret = ov2312_detect(ov2312); + if (ret < 0) + goto err_power_off; + + /* Initialize the subdev and its controls. */ + sd = &ov2312->sd; + v4l2_i2c_subdev_init(sd, client, &ov2312_subdev_ops); + sd->internal_ops = &ov2312_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + ov2312->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov2312->pad); + if (ret < 0) { + dev_err_probe(ov2312->dev, ret, "media entity init failed\n"); + goto err_power_off; + } + + ov2312->fps = OV2312_FRAMERATE_DEFAULT; + ret = devm_mutex_init(ov2312->dev, &ov2312->lock); + if (ret) { + dev_err_probe(ov2312->dev, ret, "mutex init failed\n"); + goto err_media_cleanup; + } + + /* Initialize controls */ + ctrl_hdr = &ov2312->ctrls; + /* 3 multi-capture + 2 flip + 3 single backward-compat */ + ret = v4l2_ctrl_handler_init(ctrl_hdr, 8); + if (ret < 0) { + ret = dev_err_probe(ov2312->dev, ret, + "ctrl handler init failed\n"); + goto err_media_cleanup; + } + + ov2312->ctrls.lock = &ov2312->lock; + + /* Multi-capture controls: index 0 = RGB (longest), index 1 = IR */ + { + const struct v4l2_ctrl_config exposure_multi_cfg = { + .ops = &ov2312_ctrl_ops, + .id = V4L2_CID_EXPOSURE_MULTI, + .type = V4L2_CTRL_TYPE_U32, + .min = 0, + .max = OV2312_EXPOSURE_MAX, + .step = 1, + .def = OV2312_EXPOSURE_DEFAULT, + .dims = { 2 }, + }; + const struct v4l2_ctrl_config again_multi_cfg = { + .ops = &ov2312_ctrl_ops, + .id = V4L2_CID_AGAIN_MULTI, + .type = V4L2_CTRL_TYPE_U32, + .min = 0, + .max = OV2312_AGAIN_MAX, + .step = 1, + .def = OV2312_AGAIN_DEFAULT, + .dims = { 2 }, + }; + const struct v4l2_ctrl_config dgain_multi_cfg = { + .ops = &ov2312_ctrl_ops, + .id = V4L2_CID_DGAIN_MULTI, + .type = V4L2_CTRL_TYPE_U32, + .min = 0, + .max = OV2312_DGAIN_MAX, + .step = 1, + .def = OV2312_DGAIN_DEFAULT, + .dims = { 2 }, + }; + + ov2312->exposure_multi = v4l2_ctrl_new_custom(ctrl_hdr, + &exposure_multi_cfg, + NULL); + ov2312->again_multi = v4l2_ctrl_new_custom(ctrl_hdr, + &again_multi_cfg, + NULL); + ov2312->dgain_multi = v4l2_ctrl_new_custom(ctrl_hdr, + &dgain_multi_cfg, + NULL); + } + + if (ov2312->exposure_multi && ov2312->again_multi && ov2312->dgain_multi) { + /* Set per-element initial values: [0]=RGB default, [1]=IR default */ + ov2312->exposure_multi->p_cur.p_u32[0] = OV2312_EXPOSURE_DEFAULT; + ov2312->exposure_multi->p_cur.p_u32[1] = OV2312_IR_EXPOSURE; + ov2312->exposure_multi->p_new.p_u32[0] = OV2312_EXPOSURE_DEFAULT; + ov2312->exposure_multi->p_new.p_u32[1] = OV2312_IR_EXPOSURE; + + ov2312->again_multi->p_cur.p_u32[0] = OV2312_AGAIN_DEFAULT; + ov2312->again_multi->p_cur.p_u32[1] = OV2312_AGAIN_DEFAULT; + ov2312->again_multi->p_new.p_u32[0] = OV2312_AGAIN_DEFAULT; + ov2312->again_multi->p_new.p_u32[1] = OV2312_AGAIN_DEFAULT; + + ov2312->dgain_multi->p_cur.p_u32[0] = OV2312_DGAIN_DEFAULT; + ov2312->dgain_multi->p_cur.p_u32[1] = OV2312_DGAIN_DEFAULT; + ov2312->dgain_multi->p_new.p_u32[0] = OV2312_DGAIN_DEFAULT; + ov2312->dgain_multi->p_new.p_u32[1] = OV2312_DGAIN_DEFAULT; + } + + ov2312->h_flip = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + ov2312->v_flip = v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + /* + * Register single-capture controls with proper ranges for backward + * compatibility with older userspace. The v4l2 core redirects s_ctrl + * for these to the corresponding multi-capture control. + */ + v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_EXPOSURE, 1, OV2312_EXPOSURE_MAX, + 1, OV2312_EXPOSURE_DEFAULT); + v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, OV2312_AGAIN_MAX, + 1, OV2312_AGAIN_DEFAULT); + v4l2_ctrl_new_std(ctrl_hdr, &ov2312_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, OV2312_DGAIN_MAX, + 1, OV2312_DGAIN_DEFAULT); + + ov2312->sd.ctrl_handler = ctrl_hdr; + if (ov2312->ctrls.error) { + ret = ov2312->ctrls.error; + ret = dev_err_probe(ov2312->dev, ret, + "failed to add the ctrls\n"); + goto err_ctrl_free; + } + + /* PM Runtime */ + pm_runtime_enable(ov2312->dev); + pm_runtime_set_suspended(ov2312->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) + goto err_pm_disable; + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + ret = dev_err_probe(ov2312->dev, ret, + "v4l2 subdev register failed\n"); + goto err_subdev_cleanup; + } + + dev_info(ov2312->dev, "ov2312 probed\n"); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&ov2312->sd); + +err_pm_disable: + pm_runtime_disable(ov2312->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + +err_media_cleanup: + media_entity_cleanup(&ov2312->sd.entity); + +err_power_off: + ov2312_power_off(ov2312); + + return ret; +} + +static void ov2312_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2312 *ov2312 = to_ov2312(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&ov2312->ctrls); + v4l2_subdev_cleanup(&ov2312->sd); + media_entity_cleanup(&sd->entity); + + pm_runtime_disable(ov2312->dev); +} + +static const struct i2c_device_id ov2312_id[] = { + { "ov2312", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, ov2312_id); + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2312_of_match[] = { + { .compatible = "ovti,ov2312", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov2312_of_match); +#endif + +static struct i2c_driver ov2312_i2c_driver = { + .driver = { + .name = "ov2312", + .pm = &ov2312_pm_ops, + .of_match_table = of_match_ptr(ov2312_of_match), + }, + .probe = ov2312_probe, + .remove = ov2312_remove, + .id_table = ov2312_id, +}; + +module_i2c_driver(ov2312_i2c_driver); + +MODULE_AUTHOR("Jai Luthra <j-luthra@ti.com>"); +MODULE_DESCRIPTION("OV2312 RGB-IR Image Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov2312.h b/drivers/media/i2c/ov2312.h new file mode 100644 index 000000000000..8ed435878638 --- /dev/null +++ b/drivers/media/i2c/ov2312.h @@ -0,0 +1,285 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Omnivision OV2312 RGB-IR Image Sensor driver + * + * Copyright (c) 2022 Jai Luthra <j-luthra@ti.com> + */ + +#include <linux/types.h> +#include <linux/media-bus-format.h> + +#define OV2312_CHIP_ID 0x2311 +#define OV2312_FRAMERATE_DEFAULT 60 + +#define OV2312_ED_LINES 1 +#define OV2312_OUT_WIDTH 1600 +#define OV2312_OUT_HEIGHT (1300 + OV2312_ED_LINES) +#define OV2312_VTS 0x0588 + +#define OV2312_SYS_MODE_SEL 0x0100 +#define OV2312_SC_CHIP_ID_HI 0x300a +#define OV2312_SC_CHIP_ID_LO 0x300b +#define OV2312_AEC_PK_EXPO_HI 0x3501 +#define OV2312_AEC_PK_EXPO_LO 0x3502 +#define OV2312_AEC_PK_AGAIN_HI 0x3508 +#define OV2312_AEC_PK_AGAIN_LO 0x3509 +#define OV2312_AEC_PK_DGAIN_HI 0x350a +#define OV2312_AEC_PK_DGAIN_LO 0x350b +#define OV2312_TIMING_VFLIP 0x3820 +#define OV2312_TIMING_HFLIP 0x3821 + +/* Exposure control */ +#define OV2312_EXPOSURE_MAX (OV2312_VTS - 12) +#define OV2312_EXPOSURE_DEFAULT 0x057c +#define OV2312_IR_EXPOSURE 0x0090 +#define OV2312_IR_STROBE OV2312_IR_EXPOSURE +#define OV2312_IR_STROBE_START (OV2312_VTS - OV2312_IR_EXPOSURE - 7) + +/* Analog gain control */ +#define OV2312_AGAIN_MAX 0x1FF +#define OV2312_AGAIN_DEFAULT 0x010 + +/* Digital gain control */ +#define OV2312_DGAIN_MAX 0x0FFF +#define OV2312_DGAIN_DEFAULT 0x0100 + +static const struct v4l2_area ov2312_framesizes[] = { + { + .width = OV2312_OUT_WIDTH, + .height = OV2312_OUT_HEIGHT, + }, +}; + +static const u32 ov2312_mbus_formats[] = { + MEDIA_BUS_FMT_SBGGI10_1X10, +}; + +static const struct regmap_config ov2312_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const struct reg_sequence ov2312_1600x1300_60fps_AB[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x010c, 0x02}, + {0x010b, 0x01}, + {0x0300, 0x01}, + {0x0302, 0x32}, + {0x0303, 0x00}, + {0x0304, 0x03}, + {0x0305, 0x02}, + {0x0306, 0x01}, + {0x030d, 0x5a}, + {0x030e, 0x04}, + {0x3001, 0x02}, + {0x3004, 0x00}, + {0x3005, 0x00}, + {0x3006, 0x0a}, + {0x3011, 0x0d}, + {0x3014, 0x04}, + {0x301c, 0xf0}, + {0x3020, 0x20}, + {0x302c, 0x00}, + {0x302d, 0x00}, + {0x302e, 0x00}, + {0x302f, 0x03}, + {0x3030, 0x10}, + {0x303f, 0x03}, + {0x3103, 0x00}, + {0x3106, 0x08}, + {0x31ff, 0x01}, + {0x3501, 0x05}, + {0x3502, 0x7c}, + {0x3506, 0x00}, + {0x3507, 0x00}, + {0x3620, 0x67}, + {0x3633, 0x78}, + {0x3662, 0x65}, + {0x3664, 0xb0}, + {0x3666, 0x70}, + {0x3670, 0x68}, + {0x3674, 0x10}, + {0x3675, 0x00}, + {0x367e, 0x90}, + {0x3680, 0x84}, + {0x36a2, 0x04}, + {0x36a3, 0x80}, + {0x36b0, 0x00}, + {0x3700, 0x35}, + {0x3704, 0x39}, + {0x370a, 0x50}, + {0x3712, 0x00}, + {0x3713, 0x02}, + {0x3778, 0x00}, + {0x379b, 0x01}, + {0x379c, 0x10}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x06}, + {0x3805, 0x4f}, + {0x3806, 0x05}, + {0x3807, 0x23}, + {0x3808, 0x06}, + {0x3809, 0x40}, + {0x380a, 0x05}, + {0x380b, 0x14}, + {0x380c, 0x03}, + {0x380d, 0xa8}, + {0x380e, (OV2312_VTS >> 8) & 0xff}, + {0x380f, OV2312_VTS & 0xff}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3816, 0x00}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x05}, + {0x382b, 0x5a}, + {0x382c, 0x0a}, + {0x382d, 0xf8}, + {0x3881, 0x44}, + {0x3882, 0x02}, + {0x3883, 0x8c}, + {0x3885, 0x07}, + {0x389d, 0x03}, + {0x38a6, 0x00}, + {0x38a7, 0x01}, + {0x38b3, 0x07}, + {0x38b1, 0x00}, + {0x38e5, 0x02}, + {0x38e7, 0x00}, + {0x38e8, 0x00}, + {0x3910, 0xff}, + {0x3911, 0xff}, + {0x3912, 0x08}, + {0x3913, 0x00}, + {0x3914, 0x00}, + {0x3915, 0x00}, + {0x391c, 0x00}, + {0x3920, 0xff}, + {0x3921, 0x80}, + {0x3922, 0x00}, + {0x3923, 0x00}, + {0x3924, 0x05}, + {0x3925, 0x00}, + {0x3926, 0x00}, + {0x3927, 0x00}, + {0x3928, 0x1a}, + {0x392d, 0x03}, + {0x392e, 0xa8}, + {0x392f, 0x08}, + {0x4001, 0x00}, + {0x4003, 0x40}, + {0x4008, 0x04}, + {0x4009, 0x1b}, + {0x400c, 0x04}, + {0x400d, 0x1b}, + {0x4010, 0xf4}, + {0x4011, 0x00}, + {0x4016, 0x00}, + {0x4017, 0x04}, + {0x4042, 0x11}, + {0x4043, 0x70}, + {0x4045, 0x00}, + {0x4409, 0x5f}, + {0x4509, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x80}, + {0x4708, 0x09}, + {0x470c, 0x81}, + {0x4710, 0x06}, + {0x4711, 0x00}, + {0x4800, 0x00}, + {0x481f, 0x30}, + {0x4837, 0x14}, + {0x4f00, 0x00}, + {0x4f07, 0x00}, + {0x4f08, 0x03}, + {0x4f09, 0x08}, + {0x4f0c, 0x05}, + {0x4f0d, 0xb4}, + {0x4f10, 0x00}, + {0x4f11, 0x00}, + {0x4f12, 0x07}, + {0x4f13, 0xe2}, + {0x5000, 0x9f}, + {0x5001, 0x20}, + {0x5026, 0x00}, + {0x5c00, 0x00}, + {0x5c01, 0x2c}, + {0x5c02, 0x00}, + {0x5c03, 0x7f}, + {0x5e00, 0x00}, + {0x5e01, 0x41}, + {0x38b1, 0x02}, + {0x0100, 0x01}, + {0x3006, 0x08},/* Strobe control */ + {0x3004, 0x02}, + {0x3007, 0x02}, + {0x301c, 0x20}, + {0x3020, 0x20}, + {0x3025, 0x02}, + {0x382c, 0x0a}, + {0x382d, 0xf8}, + {0x3920, 0xff}, + {0x3921, 0x00}, + {0x3923, 0x00}, + {0x3924, 0x00}, + {0x3925, 0x00}, + {0x3926, 0x00}, + {0x3927, 0x00}, + {0x3928, 0x80}, + {0x392b, 0x00}, + {0x392c, 0x00}, + {0x392d, 0x03}, + {0x392e, 0xa8}, + {0x392f, 0x0b}, + {0x38b3, 0x07}, + {0x3885, 0x07}, + {0x382b, 0x3a}, + {0x3670, 0x68}, + {0x3016, 0xF1}, + {0x0100, 0x01}, + {0x4814, 0x6B}, + {0x3218, 0x32}, + {0x3216, 0x01}, + {0x3208, 0x04}, + {0x4813, 0x01}, + {0x321a, 0x01}, + {0x3920, 0x01}, + {0x3501, 0x02}, + {0x3508, 0x02}, + {0x350e, 0x02}, + {0x3208, 0x14}, + {0x3662, 0x65}, + {0x366F, 0x1A}, + {0x3674, 0x11}, + {0x3016, 0xF0}, + {0x301C, 0xF0},/* AB mode - Group auto switch example setting */ + {0x3209, 0x01},/* Stay in Group A for 1 Frame */ + {0x320A, 0x01},/* Stay in Group B for 1 Frame */ + {0x320B, 0x00}, + {0x320C, 0x00}, + {0x3208, 0x00},/* Group A (IR Dominant VC0) default values */ + {OV2312_AEC_PK_EXPO_HI, (OV2312_IR_EXPOSURE >> 8) & 0xff}, + {OV2312_AEC_PK_EXPO_LO, OV2312_IR_EXPOSURE & 0xff}, + {OV2312_AEC_PK_AGAIN_HI, 0x01}, + {OV2312_AEC_PK_AGAIN_LO, 0x00}, + {OV2312_AEC_PK_DGAIN_HI, 0x01}, + {OV2312_AEC_PK_DGAIN_LO, 0x00}, + {0x3920, 0xff},/* IR Strobe duty cycle */ + {0x3927, (OV2312_IR_STROBE >> 8) & 0xff}, + {0x3928, OV2312_IR_STROBE & 0xff}, + {0x3929, (OV2312_IR_STROBE_START >> 8) & 0xff}, + {0x392a, OV2312_IR_STROBE_START & 0xff}, + {0x4813, 0x01},/* VC=1. This register takes effect from next frame */ + {0x3208, 0x10}, + +}; -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar ` (5 preceding siblings ...) 2026-09-25 13:29 ` [RFC PATCH 6/8] media: i2c: ov2312: add Omnivison OV2312 driver Rishikesh Donadkar @ 2026-09-25 13:30 ` Rishikesh Donadkar 2026-09-26 14:57 ` Laurent Pinchart 2026-09-25 13:30 ` [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 Rishikesh Donadkar 7 siblings, 1 reply; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:30 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart From: Jai Luthra <j-luthra@ti.com> OV2312 is a raw (4x4 RGB-IR bayer) sensor, the LI-OV2312-FPDLinkIII-110H module [1] packages it with an FPDLink-III serializer (DS90UB953) for use with sensor fusion setups using FPDLink-III deserializer boards. Link: https://www.leopardimaging.com/product/autonomous-camera/ti-fpdlinkiii-cameras/li-ov2312-fpdlinkiii/li-ov2312-fpdlinkiii-110h/ [1] Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- arch/arm64/boot/dts/ti/Makefile | 6 ++ .../boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso | 89 +++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso | 89 +++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso | 89 +++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso | 89 +++++++++++++++++++ 5 files changed, 362 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 795978e962ee..8d608e244087 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -508,5 +508,11 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ k3-j784s4-evm-usb0-type-a.dtb \ k3-j784s4-evm-usxgmii-exp1-exp2.dtb +# FPDLink Sensors +dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \ + k3-fpdlink-ov2312-0-1.dtbo \ + k3-fpdlink-ov2312-0-2.dtbo \ + k3-fpdlink-ov2312-0-3.dtbo + # Enable support for device-tree overlays DTC_FLAGS := -@ diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso new file mode 100644 index 000000000000..0829f01a0f90 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&deserializer_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&deserializer_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x44>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso new file mode 100644 index 000000000000..06cba8c7397f --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&deserializer_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&deserializer_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x45>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso new file mode 100644 index 000000000000..7d377dbe5bbf --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&deserializer_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&deserializer_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x46>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso new file mode 100644 index 000000000000..f74bff5f12b0 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&deserializer_0_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&deserializer_0_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x47>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2>; + /*clock-noncontinuous;*/ + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@60 { + compatible = "ovti,ov2312"; + reg = <0x60>; + + clocks = <&serializer>; + clock-names = "xvclk"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <24000000>; + + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 2026-09-25 13:30 ` [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 Rishikesh Donadkar @ 2026-09-26 14:57 ` Laurent Pinchart 0 siblings, 0 replies; 15+ messages in thread From: Laurent Pinchart @ 2026-09-26 14:57 UTC (permalink / raw) To: Rishikesh Donadkar Cc: linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea On Fri, Sep 25, 2026 at 07:00:00PM +0530, Rishikesh Donadkar wrote: > From: Jai Luthra <j-luthra@ti.com> > > OV2312 is a raw (4x4 RGB-IR bayer) sensor, the LI-OV2312-FPDLinkIII-110H > module [1] packages it with an FPDLink-III serializer (DS90UB953) for > use with sensor fusion setups using FPDLink-III deserializer boards. > > Link: https://www.leopardimaging.com/product/autonomous-camera/ti-fpdlinkiii-cameras/li-ov2312-fpdlinkiii/li-ov2312-fpdlinkiii-110h/ [1] > Signed-off-by: Jai Luthra <j-luthra@ti.com> > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> > --- > arch/arm64/boot/dts/ti/Makefile | 6 ++ > .../boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso | 89 +++++++++++++++++++ > .../boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso | 89 +++++++++++++++++++ > .../boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso | 89 +++++++++++++++++++ > .../boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso | 89 +++++++++++++++++++ This seems to be a very strong candidate for the new DT addons (https://bootlin.com/blog/device-tree-addons-describing-non-discoverable-addon-boards-and-connectors/). It would help getting this feature merged if you could give it a try. > 5 files changed, 362 insertions(+) > create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso > create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso > create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso > create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso > > diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile > index 795978e962ee..8d608e244087 100644 > --- a/arch/arm64/boot/dts/ti/Makefile > +++ b/arch/arm64/boot/dts/ti/Makefile > @@ -508,5 +508,11 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ > k3-j784s4-evm-usb0-type-a.dtb \ > k3-j784s4-evm-usxgmii-exp1-exp2.dtb > > +# FPDLink Sensors > +dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \ > + k3-fpdlink-ov2312-0-1.dtbo \ > + k3-fpdlink-ov2312-0-2.dtbo \ > + k3-fpdlink-ov2312-0-3.dtbo > + > # Enable support for device-tree overlays > DTC_FLAGS := -@ > diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso > new file mode 100644 > index 000000000000..0829f01a0f90 > --- /dev/null > +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-0.dtso > @@ -0,0 +1,89 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * IMX390 FPD-Link 3 Camera Module > + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ > + */ > + > +/dts-v1/; > +/plugin/; > + > +#include <dt-bindings/gpio/gpio.h> > + > +&deserializer_0_ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + /* FPDLink RX 0 */ > + port@0 { > + reg = <0>; > + > + ub960_fpd3_1_in: endpoint { > + remote-endpoint = <&ub953_1_out>; > + }; > + }; > +}; > + > +&deserializer_0_links { > + #address-cells = <1>; > + #size-cells = <0>; > + > + link@0 { > + reg = <0>; > + i2c-alias = <0x44>; > + > + ti,rx-mode = <3>; > + > + serializer: serializer { > + compatible = "ti,ds90ub953-q1"; > + gpio-controller; > + #gpio-cells = <2>; > + > + #clock-cells = <0>; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port@0 { > + reg = <0>; > + ub953_1_in: endpoint { > + data-lanes = <1 2>; > + /*clock-noncontinuous;*/ > + remote-endpoint = <&sensor_1_out>; > + }; > + }; > + > + port@1 { > + reg = <1>; > + > + ub953_1_out: endpoint { > + remote-endpoint = <&ub960_fpd3_1_in>; > + }; > + }; > + }; > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + sensor@60 { > + compatible = "ovti,ov2312"; > + reg = <0x60>; > + > + clocks = <&serializer>; > + clock-names = "xvclk"; > + assigned-clocks = <&serializer>; > + assigned-clock-rates = <24000000>; > + > + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; > + > + port { > + sensor_1_out: endpoint { > + remote-endpoint = <&ub953_1_in>; > + }; > + }; > + }; > + }; > + }; > + }; > +}; > diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso > new file mode 100644 > index 000000000000..06cba8c7397f > --- /dev/null > +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-1.dtso > @@ -0,0 +1,89 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * IMX390 FPD-Link 3 Camera Module > + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ > + */ > + > +/dts-v1/; > +/plugin/; > + > +#include <dt-bindings/gpio/gpio.h> > + > +&deserializer_0_ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + /* FPDLink RX 1 */ > + port@1 { > + reg = <1>; > + > + ub960_fpd3_1_in: endpoint { > + remote-endpoint = <&ub953_1_out>; > + }; > + }; > +}; > + > +&deserializer_0_links { > + #address-cells = <1>; > + #size-cells = <0>; > + > + link@1 { > + reg = <1>; > + i2c-alias = <0x45>; > + > + ti,rx-mode = <3>; > + > + serializer: serializer { > + compatible = "ti,ds90ub953-q1"; > + gpio-controller; > + #gpio-cells = <2>; > + > + #clock-cells = <0>; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port@0 { > + reg = <0>; > + ub953_1_in: endpoint { > + data-lanes = <1 2>; > + /*clock-noncontinuous;*/ > + remote-endpoint = <&sensor_1_out>; > + }; > + }; > + > + port@1 { > + reg = <1>; > + > + ub953_1_out: endpoint { > + remote-endpoint = <&ub960_fpd3_1_in>; > + }; > + }; > + }; > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + sensor@60 { > + compatible = "ovti,ov2312"; > + reg = <0x60>; > + > + clocks = <&serializer>; > + clock-names = "xvclk"; > + assigned-clocks = <&serializer>; > + assigned-clock-rates = <24000000>; > + > + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; > + > + port { > + sensor_1_out: endpoint { > + remote-endpoint = <&ub953_1_in>; > + }; > + }; > + }; > + }; > + }; > + }; > +}; > diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso > new file mode 100644 > index 000000000000..7d377dbe5bbf > --- /dev/null > +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-2.dtso > @@ -0,0 +1,89 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * IMX390 FPD-Link 3 Camera Module > + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ > + */ > + > +/dts-v1/; > +/plugin/; > + > +#include <dt-bindings/gpio/gpio.h> > + > +&deserializer_0_ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + /* FPDLink RX 2 */ > + port@2 { > + reg = <2>; > + > + ub960_fpd3_1_in: endpoint { > + remote-endpoint = <&ub953_1_out>; > + }; > + }; > +}; > + > +&deserializer_0_links { > + #address-cells = <1>; > + #size-cells = <0>; > + > + link@2 { > + reg = <2>; > + i2c-alias = <0x46>; > + > + ti,rx-mode = <3>; > + > + serializer: serializer { > + compatible = "ti,ds90ub953-q1"; > + gpio-controller; > + #gpio-cells = <2>; > + > + #clock-cells = <0>; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port@0 { > + reg = <0>; > + ub953_1_in: endpoint { > + data-lanes = <1 2>; > + /*clock-noncontinuous;*/ > + remote-endpoint = <&sensor_1_out>; > + }; > + }; > + > + port@1 { > + reg = <1>; > + > + ub953_1_out: endpoint { > + remote-endpoint = <&ub960_fpd3_1_in>; > + }; > + }; > + }; > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + sensor@60 { > + compatible = "ovti,ov2312"; > + reg = <0x60>; > + > + clocks = <&serializer>; > + clock-names = "xvclk"; > + assigned-clocks = <&serializer>; > + assigned-clock-rates = <24000000>; > + > + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; > + > + port { > + sensor_1_out: endpoint { > + remote-endpoint = <&ub953_1_in>; > + }; > + }; > + }; > + }; > + }; > + }; > +}; > diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso > new file mode 100644 > index 000000000000..f74bff5f12b0 > --- /dev/null > +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-ov2312-0-3.dtso > @@ -0,0 +1,89 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * IMX390 FPD-Link 3 Camera Module > + * Copyright (c) 2023 Texas Instruments Incorporated - http://www.ti.com/ > + */ > + > +/dts-v1/; > +/plugin/; > + > +#include <dt-bindings/gpio/gpio.h> > + > +&deserializer_0_ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + /* FPDLink RX 3 */ > + port@3 { > + reg = <3>; > + > + ub960_fpd3_1_in: endpoint { > + remote-endpoint = <&ub953_1_out>; > + }; > + }; > +}; > + > +&deserializer_0_links { > + #address-cells = <1>; > + #size-cells = <0>; > + > + link@3 { > + reg = <3>; > + i2c-alias = <0x47>; > + > + ti,rx-mode = <3>; > + > + serializer: serializer { > + compatible = "ti,ds90ub953-q1"; > + gpio-controller; > + #gpio-cells = <2>; > + > + #clock-cells = <0>; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port@0 { > + reg = <0>; > + ub953_1_in: endpoint { > + data-lanes = <1 2>; > + /*clock-noncontinuous;*/ > + remote-endpoint = <&sensor_1_out>; > + }; > + }; > + > + port@1 { > + reg = <1>; > + > + ub953_1_out: endpoint { > + remote-endpoint = <&ub960_fpd3_1_in>; > + }; > + }; > + }; > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + sensor@60 { > + compatible = "ovti,ov2312"; > + reg = <0x60>; > + > + clocks = <&serializer>; > + clock-names = "xvclk"; > + assigned-clocks = <&serializer>; > + assigned-clock-rates = <24000000>; > + > + reset-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; > + > + port { > + sensor_1_out: endpoint { > + remote-endpoint = <&ub953_1_in>; > + }; > + }; > + }; > + }; > + }; > + }; > +}; -- Regards, Laurent Pinchart ^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar ` (6 preceding siblings ...) 2026-09-25 13:30 ` [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 Rishikesh Donadkar @ 2026-09-25 13:30 ` Rishikesh Donadkar 2026-09-26 14:55 ` Laurent Pinchart 7 siblings, 1 reply; 15+ messages in thread From: Rishikesh Donadkar @ 2026-09-25 13:30 UTC (permalink / raw) To: linux-media, linux-kernel, devicetree, linux-arm-kernel Cc: tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea, laurent.pinchart Enable Omnivison OV2312 RGB+Ir based sensor Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 6ec8d3a69c98..f00b8eee15f3 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -954,6 +954,7 @@ CONFIG_VIDEO_TI_J721E_CSI2RX=m CONFIG_VIDEO_HANTRO=m CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX412=m +CONFIG_VIDEO_OV2312=m CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m CONFIG_VIDEO_S5KJN1=m -- 2.34.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 2026-09-25 13:30 ` [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 Rishikesh Donadkar @ 2026-09-26 14:55 ` Laurent Pinchart 0 siblings, 0 replies; 15+ messages in thread From: Laurent Pinchart @ 2026-09-26 14:55 UTC (permalink / raw) To: Rishikesh Donadkar Cc: linux-media, linux-kernel, devicetree, linux-arm-kernel, tomi.valkeinen, mchehab, robh, krzk+dt, conor+dt, nm, vigneshr, kristo, sakari.ailus, mripard, jai.luthra, jai.luthra, devarsht, y-abhilashchandra, mirela.rabulea On Fri, Sep 25, 2026 at 07:00:01PM +0530, Rishikesh Donadkar wrote: > Enable Omnivison OV2312 RGB+Ir based sensor Why is this needed in the defconfig ? > Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com> > --- > arch/arm64/configs/defconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig > index 6ec8d3a69c98..f00b8eee15f3 100644 > --- a/arch/arm64/configs/defconfig > +++ b/arch/arm64/configs/defconfig > @@ -954,6 +954,7 @@ CONFIG_VIDEO_TI_J721E_CSI2RX=m > CONFIG_VIDEO_HANTRO=m > CONFIG_VIDEO_IMX219=m > CONFIG_VIDEO_IMX412=m > +CONFIG_VIDEO_OV2312=m > CONFIG_VIDEO_OV5640=m > CONFIG_VIDEO_OV5645=m > CONFIG_VIDEO_S5KJN1=m -- Regards, Laurent Pinchart ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-09-26 14:57 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-25 13:29 [RFC PATCH 0/8] Add OmniVision OV2312 RGB-IR sensor driver Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 1/8] dt-bindings: media: Add bindings for Omnivision OV2312 Rishikesh Donadkar 2026-09-26 14:51 ` Laurent Pinchart 2026-09-25 13:29 ` [RFC PATCH 2/8] media: v4l: Add 10-bit RGBIr formats Rishikesh Donadkar 2026-09-26 14:30 ` Sakari Ailus 2026-09-26 14:40 ` Laurent Pinchart 2026-09-25 13:29 ` [RFC PATCH 3/8] media: i2c: ds90ub960: " Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 4/8] media: cadence: csi2rx: Add RAW10 " Rishikesh Donadkar 2026-09-26 14:52 ` Laurent Pinchart 2026-09-25 13:29 ` [RFC PATCH 5/8] media: ti: j721e-csi2rx: " Rishikesh Donadkar 2026-09-25 13:29 ` [RFC PATCH 6/8] media: i2c: ov2312: add Omnivison OV2312 driver Rishikesh Donadkar 2026-09-25 13:30 ` [RFC PATCH 7/8] arm64: dts: ti: k3-am62a7: FPDLink overlays for LI OV2312 Rishikesh Donadkar 2026-09-26 14:57 ` Laurent Pinchart 2026-09-25 13:30 ` [RFC PATCH 8/8] arm64: defconfig: Enable OV2312 Rishikesh Donadkar 2026-09-26 14:55 ` Laurent Pinchart
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®