* [PATCH 0/2] media: Add bindings and driver for Sony IMX708
@ 2026-07-15 17:31 Jai Luthra
2026-07-15 17:31 ` [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor Jai Luthra
2026-07-15 17:31 ` [PATCH 2/2] media: i2c: Add a driver for Sony IMX708 Jai Luthra
0 siblings, 2 replies; 6+ messages in thread
From: Jai Luthra @ 2026-07-15 17:31 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: Dave Stevenson, Naushir Patuck, David Plowman, Kieran Bingham,
Laurent Pinchart, linux-media, devicetree,
Raspberry Pi Kernel Maintenance, Jai Luthra, Nick Hollinghurst
Hi,
This series adds dt-bindings and a basic V4L2 driver for Sony IMX708
camera sensor, used in Raspberry Pi Camera Module 3 [1].
This basic driver is an adaptation of the one present in the downstream
rpi-6.18.y tree (written by Nick Hollinghurst). Many features from the
downstream driver (like HDR, binned and 720p crop modes, etc.) are not
present here, and will be added on top using common raw sensor model in
a later series.
This has been tested on a Raspberry Pi 5 with libcamera.
[1]: https://www.raspberrypi.com/products/camera-module-3/
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
---
Jai Luthra (2):
dt-bindings: media: i2c: Add imx708 image sensor
media: i2c: Add a driver for Sony IMX708
.../devicetree/bindings/media/i2c/sony,imx708.yaml | 120 ++
MAINTAINERS | 8 +
drivers/media/i2c/Kconfig | 11 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/imx708.c | 1255 ++++++++++++++++++++
5 files changed, 1395 insertions(+)
---
base-commit: 6c3a86e563b5c79e4429d8aa4cde39b2485bf969
change-id: 20260715-imx708-967d68ca6ca8
Best regards,
--
Jai Luthra <jai.luthra@ideasonboard.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor
2026-07-15 17:31 [PATCH 0/2] media: Add bindings and driver for Sony IMX708 Jai Luthra
@ 2026-07-15 17:31 ` Jai Luthra
2026-07-15 17:39 ` sashiko-bot
2026-07-15 18:00 ` Jai Luthra
2026-07-15 17:31 ` [PATCH 2/2] media: i2c: Add a driver for Sony IMX708 Jai Luthra
1 sibling, 2 replies; 6+ messages in thread
From: Jai Luthra @ 2026-07-15 17:31 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: Dave Stevenson, Naushir Patuck, David Plowman, Kieran Bingham,
Laurent Pinchart, linux-media, devicetree,
Raspberry Pi Kernel Maintenance, Jai Luthra
Sony IMX708 is an 11.9 Megapixel CMOS sensor, that can output pixels
over MIPI CSI-2 bus. Add bindings for it.
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
---
.../devicetree/bindings/media/i2c/sony,imx708.yaml | 120 +++++++++++++++++++++
MAINTAINERS | 7 ++
2 files changed, 127 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
new file mode 100644
index 000000000000..bc346730e1f3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx708.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX708 Sensor
+
+maintainers:
+ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+ - Jai Luthra <jai.luthra@ideasonboard.com>
+
+description: |-
+ The Sony IMX708 is a 1/2.3-inch CMOS active pixel digital image sensor
+ with an active array size of 4608H x 2592V. It is programmable through
+ I2C interface. The I2C address is fixed to 0x1A as per sensor data sheet.
+ Image data is sent through MIPI CSI-2, which is configured as either 2 or
+ 4 data lanes.
+
+properties:
+ compatible:
+ const: sony,imx708
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ vdig-supply:
+ description:
+ Digital I/O voltage supply, 1.1 volts
+
+ vana1-supply:
+ description:
+ Analog1 voltage supply, 2.8 volts
+
+ vana2-supply:
+ description:
+ Analog2 voltage supply, 1.8 volts
+
+ vddl-supply:
+ description:
+ Digital core voltage supply, 1.8 volts
+
+ 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
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - vdig-supply
+ - vana1-supply
+ - vana2-supply
+ - vddl-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@1a {
+ compatible = "sony,imx708";
+ reg = <0x1a>;
+
+ clocks = <&clk 90>;
+
+ vdig-supply = <&camera_vdig>;
+ vana1-supply = <&camera_vana1>;
+ vana2-supply = <&camera_vana2>;
+ vddl-supply = <&camera_vddl>;
+
+ reset-gpios = <&gpio 35 GPIO_ACTIVE_LOW>;
+
+ port {
+ imx708_ep: endpoint {
+ data-lanes = <1 2>;
+ link-frequencies = /bits/ 64 <450000000>;
+ remote-endpoint = <&csi_ep>;
+ };
+ };
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index febe918d6316..b0e3abfd88a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25269,6 +25269,13 @@ S: Maintained
F: Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
F: drivers/media/i2c/imx678.c
+SONY IMX708 SENSOR DRIVER
+M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+M: Jai Luthra <jai.luthra@ideasonboard.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
+
SONY MEMORYSTICK SUBSYSTEM
M: Maxim Levitsky <maximlevitsky@gmail.com>
M: Alex Dubov <oakad@yahoo.com>
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] media: i2c: Add a driver for Sony IMX708
2026-07-15 17:31 [PATCH 0/2] media: Add bindings and driver for Sony IMX708 Jai Luthra
2026-07-15 17:31 ` [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor Jai Luthra
@ 2026-07-15 17:31 ` Jai Luthra
2026-07-15 17:43 ` sashiko-bot
1 sibling, 1 reply; 6+ messages in thread
From: Jai Luthra @ 2026-07-15 17:31 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: Dave Stevenson, Naushir Patuck, David Plowman, Kieran Bingham,
Laurent Pinchart, linux-media, devicetree,
Raspberry Pi Kernel Maintenance, Jai Luthra, Nick Hollinghurst
Sony IMX708 is an 11.9 Megapixel CMOS sensor with a 16:9 aspect ratio.
It is a quad-bayer sensor with support for remosaicing the output to
a normal 2x2 bayer pattern.
This basic driver adds supports for capturing the full active-area of
4608x2592, up to 14.35fps. The following features are supported by the
driver:
- MIPI RAW10 output
- Fixed quad-bayer correction
- Multiple link frequencies (different IOP_PLL_MPY)
- VBLANK control for flexible frame-rate
- Analogue gain and exposure control
- Extremely long exposure time with LONG_EXP_SHIFT
- Test pattern support
The following features are currently not supported and may be added
later. Some of them depend on the new common raw sensor model:
- Embedded data stream
- Freely configurable crop (analog and digital)
- 2x2 binning
- Quad-bayer multi-exposure HDR support
- HBLANK control
- 4-lane support
- Configurable clock-tree
- Flexible quad-bayer correction
Co-developed-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
---
MAINTAINERS | 1 +
drivers/media/i2c/Kconfig | 11 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/imx708.c | 1255 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1268 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index b0e3abfd88a9..448a7a801e94 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25275,6 +25275,7 @@ M: Jai Luthra <jai.luthra@ideasonboard.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
+F: drivers/media/i2c/imx708.c
SONY MEMORYSTICK SUBSYSTEM
M: Maxim Levitsky <maximlevitsky@gmail.com>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 7ffccba897ae..08ccadaef467 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -308,6 +308,17 @@ config VIDEO_IMX678
To compile this driver as a module, choose M here: the
module will be called imx678.
+config VIDEO_IMX708
+ tristate "Sony IMX708 sensor support"
+ depends on GPIOLIB
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX708 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx708.
+
config VIDEO_MAX9271_LIB
tristate
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index d04bd5724552..15dc9755e321 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -62,6 +62,7 @@ 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_IMX708) += imx708.o
obj-$(CONFIG_VIDEO_IMX471) += imx471.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
diff --git a/drivers/media/i2c/imx708.c b/drivers/media/i2c/imx708.c
new file mode 100644
index 000000000000..052474befc5e
--- /dev/null
+++ b/drivers/media/i2c/imx708.c
@@ -0,0 +1,1255 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Sony IMX708
+ *
+ * Copyright (C) 2026 Ideas on Board Oy
+ * Copyright (C) 2022 Raspberry Pi Ltd
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+/* Chip ID */
+#define IMX708_REG_CHIP_ID CCI_REG16(0x0016)
+#define IMX708_CHIP_ID 0x0708
+
+#define IMX708_REG_MODE_SELECT CCI_REG8(0x0100)
+#define IMX708_MODE_STANDBY 0x00
+#define IMX708_MODE_STREAMING 0x01
+
+#define IMX708_REG_ORIENTATION CCI_REG8(0x0101)
+
+#define IMX708_INCLK_FREQ 24000000
+
+/* Pixel rate */
+#define IMX708_PIXEL_RATE 595200000
+
+/* PLL */
+#define IMX708_REG_IVT_PXCK_DIV CCI_REG8(0x0301)
+#define IMX708_REG_IVT_SYCK_DIV CCI_REG8(0x0303)
+#define IMX708_REG_IVT_PREPLLCK_DIV CCI_REG8(0x0305)
+#define IMX708_REG_IVT_PLL_MPY CCI_REG16(0x0306)
+#define IMX708_REG_IOP_SYCK_DIV CCI_REG8(0x030b)
+#define IMX708_REG_IOP_PREPLLCK_DIV CCI_REG8(0x030d)
+#define IMX708_REG_IOP_PLL_MPY CCI_REG16(0x030e)
+#define IMX708_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
+
+/* V_TIMING internal */
+#define IMX708_REG_FRAME_LENGTH CCI_REG16(0x0340)
+#define IMX708_FRAME_LENGTH_MAX 0xffff
+#define IMX708_REG_LINE_LENGTH CCI_REG16(0x0342)
+#define IMX708_LINE_LENGTH 15648
+#define IMX708_VBLANK_MIN 58
+
+/* Imaging area */
+#define IMX708_REG_X_ADD_STA CCI_REG16(0x0344)
+#define IMX708_REG_X_ADD_END CCI_REG16(0x0348)
+#define IMX708_REG_Y_ADD_STA CCI_REG16(0x0346)
+#define IMX708_REG_Y_ADD_END CCI_REG16(0x034a)
+#define IMX708_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
+#define IMX708_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define IMX708_REG_DIG_CROP_WIDTH CCI_REG16(0x040c)
+#define IMX708_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e)
+#define IMX708_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
+#define IMX708_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
+
+#define IMX708_REG_ACROPLP_EN CCI_REG8(0x32df)
+#define IMX708_REG_BINNING_MODE CCI_REG8(0x0900)
+#define IMX708_REG_BINNING_TYPE CCI_REG8(0x0901)
+#define IMX708_REG_BINNING_WEIGHT CCI_REG8(0x0902)
+#define IMX708_REG_BINNING_PRIORITY_H CCI_REG8(0x3200)
+#define IMX708_REG_BINNING_PRIORITY_V CCI_REG8(0x3201)
+
+/* Long exposure multiplier */
+#define IMX708_LONG_EXP_SHIFT_MAX 7
+#define IMX708_LONG_EXP_SHIFT_REG CCI_REG8(0x3100)
+
+/* Exposure control */
+#define IMX708_REG_EXPOSURE CCI_REG16(0x0202)
+#define IMX708_EXPOSURE_OFFSET 48
+#define IMX708_EXPOSURE_DEFAULT 0x640
+#define IMX708_EXPOSURE_STEP 1
+#define IMX708_EXPOSURE_MIN 8
+
+/* Analog gain control */
+#define IMX708_REG_ANALOG_GAIN CCI_REG16(0x0204)
+#define IMX708_ANA_GAIN_MIN 0
+#define IMX708_ANA_GAIN_MAX 960
+#define IMX708_ANA_GAIN_STEP 1
+#define IMX708_ANA_GAIN_DEFAULT IMX708_ANA_GAIN_MIN
+
+/* Digital gain control */
+#define IMX708_REG_DIGITAL_GAIN CCI_REG16(0x020e)
+#define IMX708_DGTL_GAIN_MIN 0x0100
+#define IMX708_DGTL_GAIN_MAX 0xffff
+#define IMX708_DGTL_GAIN_DEFAULT 0x0100
+#define IMX708_DGTL_GAIN_STEP 1
+
+/* Colour balance controls */
+#define IMX708_REG_COLOUR_BALANCE_RED CCI_REG16(0x0b90)
+#define IMX708_REG_COLOUR_BALANCE_BLUE CCI_REG16(0x0b92)
+#define IMX708_COLOUR_BALANCE_MIN 0x01
+#define IMX708_COLOUR_BALANCE_MAX 0xffff
+#define IMX708_COLOUR_BALANCE_STEP 0x01
+#define IMX708_COLOUR_BALANCE_DEFAULT 0x100
+
+/* Test Pattern Control */
+#define IMX708_REG_TEST_PATTERN CCI_REG16(0x0600)
+#define IMX708_TEST_PATTERN_DISABLE 0
+#define IMX708_TEST_PATTERN_SOLID_COLOR 1
+#define IMX708_TEST_PATTERN_COLOR_BARS 2
+#define IMX708_TEST_PATTERN_GREY_COLOR 3
+#define IMX708_TEST_PATTERN_PN9 4
+
+/* Test pattern colour components */
+#define IMX708_REG_TEST_PATTERN_R CCI_REG16(0x0602)
+#define IMX708_REG_TEST_PATTERN_GR CCI_REG16(0x0604)
+#define IMX708_REG_TEST_PATTERN_B CCI_REG16(0x0606)
+#define IMX708_REG_TEST_PATTERN_GB CCI_REG16(0x0608)
+#define IMX708_TEST_PATTERN_COLOUR_MIN 0
+#define IMX708_TEST_PATTERN_COLOUR_MAX 0x0fff
+#define IMX708_TEST_PATTERN_COLOUR_STEP 1
+
+#define IMX708_REG_BASE_SPC_GAINS_L CCI_REG8(0x7b10)
+#define IMX708_REG_BASE_SPC_GAINS_R CCI_REG8(0x7c00)
+
+/* Middle and short exposure */
+#define IMX708_REG_MID_EXPOSURE CCI_REG16(0x3116)
+#define IMX708_REG_SHT_EXPOSURE CCI_REG16(0x0224)
+#define IMX708_REG_MID_ANALOG_GAIN CCI_REG16(0x3118)
+#define IMX708_REG_MID_DIGITAL_GAIN CCI_REG16(0x311a)
+#define IMX708_REG_SHT_ANALOG_GAIN CCI_REG16(0x0216)
+#define IMX708_REG_SHT_DIGITAL_GAIN CCI_REG16(0x0218)
+
+#define IMX708_REG_CLKLANE_BLANK CCI_REG8(0x3220)
+#define IMX708_CLKLANE_BLANK_NONCONT BIT(0)
+
+/* QBC Re-mosaic broken line correction registers */
+#define IMX708_REG_QBC_RMSC_EN CCI_REG8(0x32d5)
+#define IMX708_REG_LPF_INTENSITY_EN CCI_REG8(0xc428)
+#define IMX708_LPF_INTENSITY_ENABLED 0x00
+#define IMX708_LPF_INTENSITY_DISABLED 0x01
+#define IMX708_REG_LPF_INTENSITY CCI_REG8(0xc429)
+#define IMX708_LPF_INTENSITY_DEFAULT 2
+
+/* AE HIST */
+#define IMX708_REG_AEHIST_AUTO_THRESH CCI_REG16(0x3360)
+#define IMX708_REG_AEHIST1_AREA_WIDTH CCI_REG16(0x3366)
+#define IMX708_REG_AEHIST1_AREA_HEIGHT CCI_REG16(0x3368)
+
+enum pad_types {
+ IMX708_SOURCE_PAD,
+ IMX708_NUM_PADS
+};
+
+/* IMX708 native and active pixel array size. */
+static const struct v4l2_rect imx708_native_area = {
+ .top = 0,
+ .left = 0,
+ .width = 4640,
+ .height = 2658,
+};
+
+static const struct v4l2_rect imx708_active_area = {
+ .top = 24,
+ .left = 16,
+ .width = 4608,
+ .height = 2592,
+};
+
+struct imx708_reg_list {
+ unsigned int num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
+
+/* Default PDAF pixel correction gains */
+static const u8 pdaf_gains[2][9] = {
+ { 0x4c, 0x4c, 0x4c, 0x46, 0x3e, 0x39, 0x36, 0x36, 0x36 },
+ { 0x36, 0x36, 0x36, 0x39, 0x3e, 0x46, 0x4c, 0x4c, 0x4c }
+};
+
+/* Link frequency setup */
+enum {
+ IMX708_LINK_FREQ_450MHZ,
+ IMX708_LINK_FREQ_447MHZ,
+ IMX708_LINK_FREQ_453MHZ,
+};
+
+static const s64 link_freqs[] = {
+ [IMX708_LINK_FREQ_450MHZ] = 450000000,
+ [IMX708_LINK_FREQ_447MHZ] = 447000000,
+ [IMX708_LINK_FREQ_453MHZ] = 453000000,
+};
+
+/* 450MHz is the nominal "default" link frequency */
+static const struct cci_reg_sequence link_450Mhz_regs[] = {
+ { IMX708_REG_IOP_PLL_MPY, 0x012c },
+};
+
+static const struct cci_reg_sequence link_447Mhz_regs[] = {
+ { IMX708_REG_IOP_PLL_MPY, 0x012a },
+};
+
+static const struct cci_reg_sequence link_453Mhz_regs[] = {
+ { IMX708_REG_IOP_PLL_MPY, 0x012e },
+};
+
+static const struct imx708_reg_list link_freq_regs[] = {
+ [IMX708_LINK_FREQ_450MHZ] = {
+ .regs = link_450Mhz_regs,
+ .num_of_regs = ARRAY_SIZE(link_450Mhz_regs)
+ },
+ [IMX708_LINK_FREQ_447MHZ] = {
+ .regs = link_447Mhz_regs,
+ .num_of_regs = ARRAY_SIZE(link_447Mhz_regs)
+ },
+ [IMX708_LINK_FREQ_453MHZ] = {
+ .regs = link_453Mhz_regs,
+ .num_of_regs = ARRAY_SIZE(link_453Mhz_regs)
+ },
+};
+
+static const struct cci_reg_sequence imx708_common_regs[] = {
+ /* Common */
+ { CCI_REG8(0x0100), 0x00 },
+ { CCI_REG8(0x0136), 0x18 },
+ { CCI_REG8(0x0137), 0x00 },
+ { CCI_REG8(0x33f0), 0x02 },
+ { CCI_REG8(0x33f1), 0x05 },
+ { CCI_REG8(0x3062), 0x00 },
+ { CCI_REG8(0x3063), 0x12 },
+ { CCI_REG8(0x3068), 0x00 },
+ { CCI_REG8(0x3069), 0x12 },
+ { CCI_REG8(0x306a), 0x00 },
+ { CCI_REG8(0x306b), 0x30 },
+ { CCI_REG8(0x3076), 0x00 },
+ { CCI_REG8(0x3077), 0x30 },
+ { CCI_REG8(0x3078), 0x00 },
+ { CCI_REG8(0x3079), 0x30 },
+ { CCI_REG8(0x5e54), 0x0c },
+ { CCI_REG8(0x6e44), 0x00 },
+ { CCI_REG8(0xb0b6), 0x01 },
+ { CCI_REG8(0xe829), 0x00 },
+ { CCI_REG8(0xf001), 0x08 },
+ { CCI_REG8(0xf003), 0x08 },
+ { CCI_REG8(0xf00d), 0x10 },
+ { CCI_REG8(0xf00f), 0x10 },
+ { CCI_REG8(0xf031), 0x08 },
+ { CCI_REG8(0xf033), 0x08 },
+ { CCI_REG8(0xf03d), 0x10 },
+ { CCI_REG8(0xf03f), 0x10 },
+ { CCI_REG8(0x0112), 0x0a },
+ { CCI_REG8(0x0113), 0x0a },
+ { CCI_REG8(0x0114), 0x01 },
+ { CCI_REG8(0x0b8e), 0x01 },
+ { CCI_REG8(0x0b8f), 0x00 },
+ { CCI_REG8(0x0b94), 0x01 },
+ { CCI_REG8(0x0b95), 0x00 },
+ { CCI_REG8(0x3400), 0x01 },
+ { CCI_REG8(0x3478), 0x01 },
+ { CCI_REG8(0x3479), 0x1c },
+ { CCI_REG8(0x3091), 0x01 },
+ { CCI_REG8(0x3092), 0x00 },
+ { CCI_REG8(0x3419), 0x00 },
+ { CCI_REG8(0xbcf1), 0x02 },
+ { CCI_REG8(0x3094), 0x01 },
+ { CCI_REG8(0x3095), 0x01 },
+ { CCI_REG8(0x3362), 0x00 },
+ { CCI_REG8(0x3363), 0x00 },
+ { CCI_REG8(0x3364), 0x00 },
+ { CCI_REG8(0x3365), 0x00 },
+ { CCI_REG8(0x0138), 0x01 },
+ /* PLL config */
+ { IMX708_REG_IVT_PXCK_DIV, 0x05 },
+ { IMX708_REG_IVT_SYCK_DIV, 0x02 },
+ { IMX708_REG_IVT_PREPLLCK_DIV, 0x02 },
+ { IMX708_REG_IVT_PLL_MPY, 0x007c },
+ { IMX708_REG_IOP_SYCK_DIV, 0x02 },
+ { IMX708_REG_IOP_PREPLLCK_DIV, 0x04 },
+ { IMX708_REG_PLL_MULT_DRIV, 0x01 },
+ /* non-HDR defaults */
+ { CCI_REG8(0x0220), 0x62 },
+ { CCI_REG8(0x0222), 0x01 },
+ { CCI_REG8(0x350c), 0x00 },
+ { CCI_REG8(0x350d), 0x00 },
+ { IMX708_REG_SHT_EXPOSURE, 0x01f4 },
+ { IMX708_REG_MID_EXPOSURE, 0x01f4 },
+ { IMX708_REG_SHT_ANALOG_GAIN, 0x0000 },
+ { IMX708_REG_SHT_DIGITAL_GAIN, 0x0100 },
+ { IMX708_REG_MID_ANALOG_GAIN, 0x0000 },
+ { IMX708_REG_MID_DIGITAL_GAIN, 0x0100 },
+ { IMX708_REG_AEHIST1_AREA_WIDTH, 0x0000 },
+ { IMX708_REG_AEHIST1_AREA_HEIGHT, 0x0000 },
+ /* Quad-Bayer Compensation */
+ { IMX708_REG_QBC_RMSC_EN, 0x01 },
+ { IMX708_REG_LPF_INTENSITY, IMX708_LPF_INTENSITY_DEFAULT },
+ { IMX708_REG_LPF_INTENSITY_EN, IMX708_LPF_INTENSITY_ENABLED },
+ { CCI_REG8(0x32d6), 0x00 },
+ { CCI_REG8(0x32db), 0x01 },
+ /* Analogue crop disabled */
+ { IMX708_REG_ACROPLP_EN, 0x00 },
+ /* Unknown registers */
+ { CCI_REG8(0x3ca0), 0x00 },
+ { CCI_REG8(0x3ca1), 0x64 },
+ { CCI_REG8(0x3ca4), 0x00 },
+ { CCI_REG8(0x3ca5), 0x00 },
+ { CCI_REG8(0x3ca6), 0x00 },
+ { CCI_REG8(0x3ca7), 0x00 },
+ { CCI_REG8(0x3caa), 0x00 },
+ { CCI_REG8(0x3cab), 0x00 },
+ { CCI_REG8(0x3cb8), 0x00 },
+ { CCI_REG8(0x3cb9), 0x08 },
+ { CCI_REG8(0x3cba), 0x00 },
+ { CCI_REG8(0x3cbb), 0x00 },
+ { CCI_REG8(0x3cbc), 0x00 },
+ { CCI_REG8(0x3cbd), 0x3c },
+ { CCI_REG8(0x3cbe), 0x00 },
+ { CCI_REG8(0x3cbf), 0x00 },
+ { CCI_REG8(0x341a), 0x00 },
+ { CCI_REG8(0x341b), 0x00 },
+ { CCI_REG8(0x341c), 0x00 },
+ { CCI_REG8(0x341d), 0x00 },
+ { CCI_REG8(0x341e), 0x01 },
+ { CCI_REG8(0x341f), 0x20 },
+ { CCI_REG8(0x3420), 0x00 },
+ { CCI_REG8(0x3421), 0xd8 },
+};
+
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+ /* 10-bit modes. */
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+};
+
+static const char * const imx708_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Solid Color",
+ "Grey Color Bars",
+ "PN9"
+};
+
+static const int imx708_test_pattern_val[] = {
+ IMX708_TEST_PATTERN_DISABLE,
+ IMX708_TEST_PATTERN_COLOR_BARS,
+ IMX708_TEST_PATTERN_SOLID_COLOR,
+ IMX708_TEST_PATTERN_GREY_COLOR,
+ IMX708_TEST_PATTERN_PN9,
+};
+
+/* regulator supplies */
+static const char * const imx708_supply_name[] = {
+ /* Supplies can be enabled in any order */
+ "vana1", /* Analog1 (2.8V) supply */
+ "vana2", /* Analog2 (1.8V) supply */
+ "vdig", /* Digital Core (1.1V) supply */
+ "vddl", /* IF (1.8V) supply */
+};
+
+/*
+ * Initialisation delay between XCLR low->high and the moment when the sensor
+ * can start capture (i.e. can leave software standby), given by T7 in the
+ * datasheet is 8ms. This does include I2C setup time as well.
+ *
+ * Note, that delay between XCLR low->high and reading the CCI ID register (T6
+ * in the datasheet) is much smaller - 600us.
+ */
+#define IMX708_XCLR_MIN_DELAY_US 8000
+#define IMX708_XCLR_DELAY_RANGE_US 1000
+
+struct imx708 {
+ struct v4l2_subdev sd;
+ struct media_pad pad[IMX708_NUM_PADS];
+ struct regmap *cci;
+
+ struct clk *inclk;
+ u32 inclk_freq;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx708_supply_name)];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* V4L2 Controls */
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct {
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+
+ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
+ unsigned int long_exp_shift;
+
+ unsigned long link_freq_bitmap;
+
+ unsigned int csi_flags;
+};
+
+static inline struct imx708 *to_imx708(struct v4l2_subdev *_sd)
+{
+ return container_of_const(_sd, struct imx708, sd);
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx708_get_format_code(struct imx708 *imx708)
+{
+ unsigned int i;
+
+ i = (imx708->vflip->val ? 2 : 0) |
+ (imx708->hflip->val ? 1 : 0);
+
+ return codes[i];
+}
+
+static void imx708_adjust_exposure_range(struct imx708 *imx708)
+{
+ int exposure_max, exposure_def;
+
+ /* Honour the VBLANK limits when setting exposure. */
+ exposure_max = imx708_active_area.height + imx708->vblank->val -
+ IMX708_EXPOSURE_OFFSET;
+ exposure_def = min(exposure_max, imx708->exposure->val);
+ __v4l2_ctrl_modify_range(imx708->exposure, imx708->exposure->minimum,
+ exposure_max, imx708->exposure->step,
+ exposure_def);
+}
+
+static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val)
+{
+ int ret = 0;
+
+ imx708->long_exp_shift = 0;
+
+ while (val > IMX708_FRAME_LENGTH_MAX) {
+ imx708->long_exp_shift++;
+ val >>= 1;
+ }
+
+ cci_write(imx708->cci, IMX708_REG_FRAME_LENGTH, val, &ret);
+ cci_write(imx708->cci, IMX708_LONG_EXP_SHIFT_REG,
+ imx708->long_exp_shift, &ret);
+
+ return ret;
+}
+
+static int imx708_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx708 *imx708 =
+ container_of_const(ctrl->handler, struct imx708, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /*
+ * The VBLANK control may change the limits of usable exposure,
+ * so check and adjust if necessary.
+ */
+ imx708_adjust_exposure_range(imx708);
+ break;
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP: {
+ struct v4l2_subdev_state *state =
+ v4l2_subdev_get_locked_active_state(&imx708->sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_state_get_format(state, IMX708_SOURCE_PAD);
+ format->code = imx708_get_format_code(imx708);
+ break;
+ }
+ }
+
+ /*
+ * Only apply control values when device is powered on (RPM ACTIVE)
+ * and streaming (usage count != 0)
+ */
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ cci_write(imx708->cci, IMX708_REG_ANALOG_GAIN, ctrl->val, &ret);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = imx708_set_frame_length(imx708,
+ imx708_active_area.height +
+ ctrl->val);
+ fallthrough; /* update exposure with new long_exp_shift */
+ case V4L2_CID_EXPOSURE:
+ cci_write(imx708->cci, IMX708_REG_EXPOSURE,
+ imx708->exposure->val >> imx708->long_exp_shift,
+ &ret);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ cci_write(imx708->cci, IMX708_REG_DIGITAL_GAIN, ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ cci_write(imx708->cci, IMX708_REG_TEST_PATTERN,
+ imx708_test_pattern_val[ctrl->val], &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_RED:
+ cci_write(imx708->cci, IMX708_REG_TEST_PATTERN_R,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENR:
+ cci_write(imx708->cci, IMX708_REG_TEST_PATTERN_GR,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_BLUE:
+ cci_write(imx708->cci, IMX708_REG_TEST_PATTERN_B,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENB:
+ cci_write(imx708->cci, IMX708_REG_TEST_PATTERN_GB,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ cci_write(imx708->cci, IMX708_REG_ORIENTATION,
+ imx708->hflip->val | imx708->vflip->val << 1, &ret);
+ break;
+ case V4L2_CID_NOTIFY_GAINS:
+ cci_write(imx708->cci, IMX708_REG_COLOUR_BALANCE_BLUE,
+ ctrl->p_new.p_u32[0], &ret);
+ if (ret)
+ break;
+ cci_write(imx708->cci, IMX708_REG_COLOUR_BALANCE_RED,
+ ctrl->p_new.p_u32[3], &ret);
+ break;
+ default:
+ dev_warn(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx708_ctrl_ops = {
+ .s_ctrl = imx708_set_ctrl,
+};
+
+static int imx708_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx708 *imx708 = to_imx708(sd);
+
+ if (code->pad >= IMX708_NUM_PADS)
+ return -EINVAL;
+
+ if (code->index >= (ARRAY_SIZE(codes) / 4))
+ return -EINVAL;
+
+ code->code = imx708_get_format_code(imx708);
+
+ return 0;
+}
+
+static int imx708_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx708 *imx708 = to_imx708(sd);
+ u32 code;
+
+ if (fse->pad >= IMX708_NUM_PADS)
+ return -EINVAL;
+
+ code = imx708_get_format_code(imx708);
+
+ if (fse->code != code)
+ return -EINVAL;
+
+ if (fse->index > 0)
+ return -EINVAL;
+
+ fse->min_width = imx708_active_area.width;
+ fse->max_width = fse->min_width;
+ fse->min_height = imx708_active_area.height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int imx708_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct imx708 *imx708 = to_imx708(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ /* Initialize the image pad format. */
+ format = v4l2_subdev_state_get_format(state, IMX708_SOURCE_PAD);
+ format->code = imx708_get_format_code(imx708);
+ format->width = imx708_active_area.width;
+ format->height = imx708_active_area.height;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ /* Initialize the image pad crop. */
+ crop = v4l2_subdev_state_get_crop(state, IMX708_SOURCE_PAD);
+ *crop = imx708_active_area;
+
+ return 0;
+}
+
+static int imx708_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_state_get_crop(sd_state, sel->pad);
+ sel->r = *crop;
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r = imx708_native_area;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r = imx708_active_area;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx708_program_window(struct imx708 *imx708,
+ struct v4l2_subdev_state *state)
+{
+ const struct v4l2_rect *crop;
+ const struct v4l2_mbus_framefmt *format;
+ int ret = 0;
+ s32 x_start, y_start;
+
+ crop = v4l2_subdev_state_get_crop(state, IMX708_SOURCE_PAD);
+ format = v4l2_subdev_state_get_format(state, IMX708_SOURCE_PAD);
+
+ /* Line length */
+ cci_write(imx708->cci, IMX708_REG_LINE_LENGTH, IMX708_LINE_LENGTH,
+ &ret);
+
+ /* Imaging area */
+ x_start = crop->left - imx708_active_area.left;
+ y_start = crop->top - imx708_active_area.top;
+ cci_write(imx708->cci, IMX708_REG_X_ADD_STA, x_start, &ret);
+ cci_write(imx708->cci, IMX708_REG_Y_ADD_STA, y_start, &ret);
+ cci_write(imx708->cci, IMX708_REG_X_ADD_END, x_start + crop->width - 1,
+ &ret);
+ cci_write(imx708->cci, IMX708_REG_Y_ADD_END, y_start + crop->height - 1,
+ &ret);
+
+ /* Binning (fixed: no binning) */
+ cci_write(imx708->cci, IMX708_REG_BINNING_MODE, 0x00, &ret);
+ cci_write(imx708->cci, IMX708_REG_BINNING_TYPE, 0x11, &ret);
+ cci_write(imx708->cci, IMX708_REG_BINNING_WEIGHT, 0x0a, &ret);
+ cci_write(imx708->cci, IMX708_REG_BINNING_PRIORITY_H, 0x01, &ret);
+ cci_write(imx708->cci, IMX708_REG_BINNING_PRIORITY_V, 0x01, &ret);
+
+ /* Digital crop (fixed: no crop) */
+ cci_write(imx708->cci, IMX708_REG_DIG_CROP_X_OFFSET, 0, &ret);
+ cci_write(imx708->cci, IMX708_REG_DIG_CROP_Y_OFFSET, 0, &ret);
+ cci_write(imx708->cci, IMX708_REG_DIG_CROP_WIDTH, format->width, &ret);
+ cci_write(imx708->cci, IMX708_REG_DIG_CROP_HEIGHT, format->height, &ret);
+
+ /* Output size */
+ cci_write(imx708->cci, IMX708_REG_X_OUTPUT_SIZE, format->width, &ret);
+ cci_write(imx708->cci, IMX708_REG_Y_OUTPUT_SIZE, format->height, &ret);
+
+ return ret;
+}
+
+static int imx708_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx708 *imx708 = to_imx708(sd);
+ const struct imx708_reg_list *freq_regs;
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
+
+ /* Program windowing registers from V4L2 state */
+ ret = imx708_program_window(imx708, state);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ goto err_rpm_put;
+ }
+
+ /* Update the link frequency registers */
+ freq_regs = &link_freq_regs[__ffs(imx708->link_freq_bitmap)];
+ cci_multi_reg_write(imx708->cci, freq_regs->regs,
+ freq_regs->num_of_regs, &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set link frequency registers\n",
+ __func__);
+ goto err_rpm_put;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx708->sd.ctrl_handler);
+ if (ret)
+ goto err_rpm_put;
+
+ /* set stream on register */
+ cci_write(imx708->cci, IMX708_REG_MODE_SELECT,
+ IMX708_MODE_STREAMING, &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to start streaming\n",
+ __func__);
+ goto err_rpm_put;
+ }
+
+ /* vflip/hflip cannot change during streaming */
+ __v4l2_ctrl_grab(imx708->vflip, true);
+ __v4l2_ctrl_grab(imx708->hflip, true);
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put_sync(&client->dev);
+
+ return ret;
+}
+
+static int imx708_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx708 *imx708 = to_imx708(sd);
+ int ret = 0;
+
+ /* set stream off register */
+ cci_write(imx708->cci, IMX708_REG_MODE_SELECT,
+ IMX708_MODE_STANDBY, &ret);
+ if (ret)
+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
+
+ __v4l2_ctrl_grab(imx708->vflip, false);
+ __v4l2_ctrl_grab(imx708->hflip, false);
+
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return ret;
+}
+
+static int imx708_write_common(struct imx708 *imx708)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
+ int i, ret = 0;
+ u64 val;
+
+ cci_multi_reg_write(imx708->cci, imx708_common_regs,
+ ARRAY_SIZE(imx708_common_regs), &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set common settings\n",
+ __func__);
+ return ret;
+ }
+
+ cci_write(imx708->cci, IMX708_REG_CLKLANE_BLANK,
+ imx708->csi_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
+ IMX708_CLKLANE_BLANK_NONCONT : 0, &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set clock lane mode\n",
+ __func__);
+ return ret;
+ }
+
+ cci_read(imx708->cci, IMX708_REG_BASE_SPC_GAINS_L, &val, &ret);
+ if (ret == 0 && val == 0x40) {
+ for (i = 0; i < 54 && ret == 0; i++) {
+ cci_write(imx708->cci,
+ CCI_REG8(CCI_REG_ADDR(IMX708_REG_BASE_SPC_GAINS_L) + i),
+ pdaf_gains[0][i % 9], &ret);
+ }
+ for (i = 0; i < 54 && ret == 0; i++) {
+ cci_write(imx708->cci,
+ CCI_REG8(CCI_REG_ADDR(IMX708_REG_BASE_SPC_GAINS_R) + i),
+ pdaf_gains[1][i % 9], &ret);
+ }
+ }
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set PDAF gains\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Power/clock management functions */
+static int imx708_power_on(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx708 *imx708 = to_imx708(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx708_supply_name),
+ imx708->supplies);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(imx708->inclk);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable clock\n",
+ __func__);
+ goto reg_off;
+ }
+
+ gpiod_set_value_cansleep(imx708->reset_gpio, 0);
+ usleep_range(IMX708_XCLR_MIN_DELAY_US,
+ IMX708_XCLR_MIN_DELAY_US + IMX708_XCLR_DELAY_RANGE_US);
+
+ ret = imx708_write_common(imx708);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to write registers\n",
+ __func__);
+ goto clk_off;
+ }
+
+ return 0;
+
+clk_off:
+ gpiod_set_value_cansleep(imx708->reset_gpio, 1);
+ clk_disable_unprepare(imx708->inclk);
+
+reg_off:
+ regulator_bulk_disable(ARRAY_SIZE(imx708_supply_name),
+ imx708->supplies);
+ return ret;
+}
+
+static int imx708_power_off(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx708 *imx708 = to_imx708(sd);
+
+ gpiod_set_value_cansleep(imx708->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(imx708_supply_name),
+ imx708->supplies);
+ clk_disable_unprepare(imx708->inclk);
+
+ return 0;
+}
+
+/* Verify chip ID */
+static int imx708_identify_module(struct imx708 *imx708)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
+ int ret = 0;
+ u64 val;
+
+ cci_read(imx708->cci, IMX708_REG_CHIP_ID, &val, &ret);
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
+ IMX708_CHIP_ID, ret);
+ return ret;
+ }
+
+ if (val != IMX708_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
+ IMX708_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx708_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx708_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx708_pad_ops = {
+ .enum_mbus_code = imx708_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = v4l2_subdev_get_fmt,
+ .get_selection = imx708_get_selection,
+ .enum_frame_size = imx708_enum_frame_size,
+ .enable_streams = imx708_enable_streams,
+ .disable_streams = imx708_disable_streams,
+};
+
+static const struct v4l2_subdev_ops imx708_subdev_ops = {
+ .core = &imx708_core_ops,
+ .video = &imx708_video_ops,
+ .pad = &imx708_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx708_internal_ops = {
+ .init_state = imx708_init_state,
+};
+
+static const struct v4l2_ctrl_config imx708_notify_gains_ctrl = {
+ .ops = &imx708_ctrl_ops,
+ .id = V4L2_CID_NOTIFY_GAINS,
+ .type = V4L2_CTRL_TYPE_U32,
+ .min = IMX708_COLOUR_BALANCE_MIN,
+ .max = IMX708_COLOUR_BALANCE_MAX,
+ .step = IMX708_COLOUR_BALANCE_STEP,
+ .def = IMX708_COLOUR_BALANCE_DEFAULT,
+ .dims = { 4 },
+ .elem_size = sizeof(u32),
+};
+
+/* Initialize control handlers */
+static int imx708_init_controls(struct imx708 *imx708)
+{
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *link_freq;
+ unsigned int i;
+ s32 hblank, vblank_max, exposure_max;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ ctrl_hdlr = &imx708->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 17);
+ if (ret)
+ return ret;
+
+ /* By default, PIXEL_RATE is read only */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ IMX708_PIXEL_RATE, IMX708_PIXEL_RATE, 1,
+ IMX708_PIXEL_RATE);
+
+ link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freqs) - 1,
+ __ffs(imx708->link_freq_bitmap),
+ link_freqs);
+
+ /* Frame Time = 2^LONG_EXP_SHIFT * REG_FRAME_LENGTH */
+ vblank_max = ((1 << IMX708_LONG_EXP_SHIFT_MAX) *
+ IMX708_FRAME_LENGTH_MAX) - imx708_active_area.height;
+ imx708->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_VBLANK, IMX708_VBLANK_MIN,
+ vblank_max, 1, IMX708_VBLANK_MIN);
+
+ hblank = IMX708_LINE_LENGTH - imx708_active_area.width;
+ imx708->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1,
+ hblank);
+
+ /* Max Exposure = FRAME_LENGTH - OFFSET */
+ exposure_max = (imx708_active_area.height + IMX708_VBLANK_MIN) -
+ IMX708_EXPOSURE_OFFSET;
+ imx708->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX708_EXPOSURE_MIN,
+ exposure_max,
+ IMX708_EXPOSURE_STEP,
+ IMX708_EXPOSURE_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX708_ANA_GAIN_MIN, IMX708_ANA_GAIN_MAX,
+ IMX708_ANA_GAIN_STEP, IMX708_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX708_DGTL_GAIN_MIN, IMX708_DGTL_GAIN_MAX,
+ IMX708_DGTL_GAIN_STEP, IMX708_DGTL_GAIN_DEFAULT);
+
+ imx708->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ imx708->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &imx708->hflip);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx708_test_pattern_menu) - 1,
+ 0, 0, imx708_test_pattern_menu);
+ for (i = 0; i < 4; i++) {
+ /*
+ * The assumption is that
+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+ */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
+ V4L2_CID_TEST_PATTERN_RED + i,
+ IMX708_TEST_PATTERN_COLOUR_MIN,
+ IMX708_TEST_PATTERN_COLOUR_MAX,
+ IMX708_TEST_PATTERN_COLOUR_STEP,
+ IMX708_TEST_PATTERN_COLOUR_MAX);
+ /* The "Solid color" pattern is white by default */
+ }
+
+ v4l2_ctrl_new_custom(ctrl_hdlr, &imx708_notify_gains_ctrl, NULL);
+
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx708_ctrl_ops, &props);
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+ }
+
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ imx708->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ imx708->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ imx708->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx708->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+}
+
+static int imx708_check_hwcfg(struct device *dev, struct imx708 *imx708)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint ep_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ int ret = -EINVAL;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto error_out;
+ }
+
+ /* Check the number of MIPI CSI2 data lanes */
+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+ dev_err(dev, "only 2 data lanes are currently supported\n");
+ goto error_out;
+ }
+
+ imx708->csi_flags = ep_cfg.bus.mipi_csi2.flags;
+
+ /* Check the link frequency set in device tree */
+ ret = v4l2_link_freq_to_bitmap(dev, ep_cfg.link_frequencies,
+ ep_cfg.nr_of_link_frequencies,
+ link_freqs, ARRAY_SIZE(link_freqs),
+ &imx708->link_freq_bitmap);
+
+error_out:
+ v4l2_fwnode_endpoint_free(&ep_cfg);
+ fwnode_handle_put(endpoint);
+
+ return ret;
+}
+
+static int imx708_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx708 *imx708;
+ int ret;
+
+ imx708 = devm_kzalloc(&client->dev, sizeof(*imx708), GFP_KERNEL);
+ if (!imx708)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&imx708->sd, client, &imx708_subdev_ops);
+
+ imx708->cci = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(imx708->cci))
+ return dev_err_probe(dev, PTR_ERR(imx708->cci),
+ "failed to init CCI\n");
+
+ if (imx708_check_hwcfg(dev, imx708))
+ return -EINVAL;
+
+ imx708->inclk = devm_v4l2_sensor_clk_get(dev, NULL);
+ if (IS_ERR(imx708->inclk))
+ return dev_err_probe(dev, PTR_ERR(imx708->inclk),
+ "failed to get inclk\n");
+
+ imx708->inclk_freq = clk_get_rate(imx708->inclk);
+ if (imx708->inclk_freq != IMX708_INCLK_FREQ)
+ return dev_err_probe(dev, -EINVAL,
+ "inclk frequency not supported: %d Hz\n",
+ imx708->inclk_freq);
+
+ for (int i = 0; i < ARRAY_SIZE(imx708_supply_name); i++)
+ imx708->supplies[i].supply = imx708_supply_name[i];
+
+ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(imx708_supply_name),
+ imx708->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
+
+ imx708->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(imx708->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx708->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ ret = imx708_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = imx708_identify_module(imx708);
+ if (ret)
+ goto error_power_off;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = imx708_init_controls(imx708);
+ if (ret)
+ goto error_pm_runtime;
+
+ imx708->sd.internal_ops = &imx708_internal_ops;
+ imx708->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx708->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ imx708->pad[IMX708_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&imx708->sd.entity, IMX708_NUM_PADS,
+ imx708->pad);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to init entity pads\n");
+ goto error_handler_free;
+ }
+
+ imx708->sd.state_lock = imx708->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&imx708->sd);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to finalize subdev\n");
+ goto error_media_entity;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&imx708->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "failed to register sensor sub-device\n");
+ goto error_subdev_cleanup;
+ }
+
+ pm_runtime_idle(dev);
+ pm_runtime_set_autosuspend_delay(dev, 5000);
+ pm_runtime_use_autosuspend(dev);
+
+ return 0;
+
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&imx708->sd);
+
+error_media_entity:
+ media_entity_cleanup(&imx708->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(imx708->sd.ctrl_handler);
+
+error_pm_runtime:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+error_power_off:
+ imx708_power_off(&client->dev);
+
+ return ret;
+}
+
+static void imx708_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx708 *imx708 = to_imx708(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(imx708->sd.ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ imx708_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id imx708_dt_ids[] = {
+ { .compatible = "sony,imx708" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx708_dt_ids);
+
+static const struct dev_pm_ops imx708_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx708_power_off, imx708_power_on, NULL)
+};
+
+static struct i2c_driver imx708_i2c_driver = {
+ .driver = {
+ .name = "imx708",
+ .of_match_table = imx708_dt_ids,
+ .pm = pm_ptr(&imx708_pm_ops),
+ },
+ .probe = imx708_probe,
+ .remove = imx708_remove,
+};
+
+module_i2c_driver(imx708_i2c_driver);
+
+MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>");
+MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>");
+MODULE_DESCRIPTION("Sony IMX708 sensor driver");
+MODULE_LICENSE("GPL");
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor
2026-07-15 17:31 ` [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor Jai Luthra
@ 2026-07-15 17:39 ` sashiko-bot
2026-07-15 18:00 ` Jai Luthra
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-07-15 17:39 UTC (permalink / raw)
To: Jai Luthra; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The IMX708 device tree binding strictly prohibits standard camera properties like `rotation`, `orientation`, and `lens-focus` by omitting the common video-interface-devices schema reference.
--
--- Patch [1]: [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor ---
commit 6db06a28573083737d3c74ac1c5d01840d0d4fc3
Author: Jai Luthra <jai.luthra@ideasonboard.com>
dt-bindings: media: i2c: Add imx708 image sensor
This commit adds the device tree binding schema for the Sony IMX708 CMOS
sensor. It defines the I2C configuration, required power supplies, and
MIPI CSI-2 interface properties.
> diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
[ ... ]
> +required:
> + - compatible
> + - reg
> + - clocks
> + - vdig-supply
> + - vana1-supply
> + - vana2-supply
> + - vddl-supply
> + - port
> +
> +additionalProperties: false
[Severity: Medium]
Will this strict additionalProperties constraint incorrectly reject standard
camera properties like rotation or orientation?
Because this binding in Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
does not reference the common video-interface-devices schema, standard device
tree properties describing the physical mounting of the sensor will fail
validation during dt_binding_check.
Should this binding include an allOf reference to the common schema and use
unevaluatedProperties instead of additionalProperties at the top level?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715-imx708-v1-0-1f36f54e14d4@ideasonboard.com?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] media: i2c: Add a driver for Sony IMX708
2026-07-15 17:31 ` [PATCH 2/2] media: i2c: Add a driver for Sony IMX708 Jai Luthra
@ 2026-07-15 17:43 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-07-15 17:43 UTC (permalink / raw)
To: Jai Luthra; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Incorrect check of `pm_runtime_get_if_in_use()` return value in `imx708_set_ctrl()` leads to unbalanced runtime PM puts and hardware access while powered off.
- [Medium] Incorrect power-off sequence in `imx708_power_off()`: regulators are disabled before the input clock.
- [Medium] Software state (`imx708->long_exp_shift`) is updated before hardware confirms the write, leading to state mismatch on I2C failure.
--
--- Patch [2]: [PATCH 2/2] media: i2c: Add a driver for Sony IMX708 ---
commit 34adccd1a70befee0909b84ab4c6054b6de7c8c3
Author: Jai Luthra <jai.luthra@ideasonboard.com>
media: i2c: Add a driver for Sony IMX708
This commit introduces a new V4L2 I2C driver for the Sony IMX708 11.9
Megapixel CMOS sensor. It adds basic support for capturing the full active
area and includes controls for exposure, analogue gain, test patterns, and
variable frame rates using VBLANK.
> diff --git a/drivers/media/i2c/imx708.c b/drivers/media/i2c/imx708.c
> new file mode 100644
> index 0000000000000..052474befc5e4
> --- /dev/null
> +++ b/drivers/media/i2c/imx708.c
[ ... ]
> +static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val)
> +{
> + int ret = 0;
> +
> + imx708->long_exp_shift = 0;
> +
> + while (val > IMX708_FRAME_LENGTH_MAX) {
> + imx708->long_exp_shift++;
> + val >>= 1;
> + }
> +
> + cci_write(imx708->cci, IMX708_REG_FRAME_LENGTH, val, &ret);
[Severity: Medium]
Does this leave the software state out of sync if the I2C transaction fails?
The driver mutates imx708->long_exp_shift before issuing the cci_write()
commands. If cci_write() returns an error, the V4L2 framework rolls back
the VBLANK control to its previous value, but the driver retains the
mutated long_exp_shift. Subsequent exposure calculations would then use
this corrupted shift value.
> + cci_write(imx708->cci, IMX708_LONG_EXP_SHIFT_REG,
> + imx708->long_exp_shift, &ret);
> +
> + return ret;
> +}
> +
> +static int imx708_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
[ ... ]
> + /*
> + * Only apply control values when device is powered on (RPM ACTIVE)
> + * and streaming (usage count != 0)
> + */
> + if (!pm_runtime_get_if_in_use(&client->dev))
> + return 0;
[Severity: High]
Can this cause unbalanced runtime PM puts and hardware access while powered
off?
The pm_runtime_get_if_in_use() function returns -EINVAL if runtime PM is
disabled. In C, !(-EINVAL) evaluates to false, which causes the function to
bypass the early return. It then proceeds to access hardware registers and
calls pm_runtime_put_autosuspend(), decrementing a usage count that was
never incremented.
> +
> + switch (ctrl->id) {
> + case V4L2_CID_ANALOGUE_GAIN:
> + cci_write(imx708->cci, IMX708_REG_ANALOG_GAIN, ctrl->val, &ret);
[ ... ]
> +static int imx708_power_off(struct device *dev)
> +{
> + struct i2c_client *client = to_i2c_client(dev);
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct imx708 *imx708 = to_imx708(sd);
> +
> + gpiod_set_value_cansleep(imx708->reset_gpio, 1);
> + regulator_bulk_disable(ARRAY_SIZE(imx708_supply_name),
> + imx708->supplies);
> + clk_disable_unprepare(imx708->inclk);
[Severity: Medium]
Should the clock be disabled before the regulators are turned off?
During device power down, regulators vana and vdig are turned off while the
input clock inclk is still running.
> +
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715-imx708-v1-0-1f36f54e14d4@ideasonboard.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor
2026-07-15 17:31 ` [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor Jai Luthra
2026-07-15 17:39 ` sashiko-bot
@ 2026-07-15 18:00 ` Jai Luthra
1 sibling, 0 replies; 6+ messages in thread
From: Jai Luthra @ 2026-07-15 18:00 UTC (permalink / raw)
To: Dave Stevenson
Cc: Naushir Patuck, David Plowman, Kieran Bingham, Laurent Pinchart,
linux-media, devicetree, Raspberry Pi Kernel Maintenance,
Conor Dooley, Krzysztof Kozlowski, Mauro Carvalho Chehab,
Rob Herring, Sakari Ailus
Hi Dave,
Quoting Jai Luthra (2026-07-15 23:01:28)
> Sony IMX708 is an 11.9 Megapixel CMOS sensor, that can output pixels
> over MIPI CSI-2 bus. Add bindings for it.
>
> Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
> ---
> .../devicetree/bindings/media/i2c/sony,imx708.yaml | 120 +++++++++++++++++++++
> MAINTAINERS | 7 ++
> 2 files changed, 127 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
> new file mode 100644
> index 000000000000..bc346730e1f3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
> @@ -0,0 +1,120 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/sony,imx708.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sony IMX708 Sensor
> +
> +maintainers:
> + - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
> + - Jai Luthra <jai.luthra@ideasonboard.com>
> +
[...]
> diff --git a/MAINTAINERS b/MAINTAINERS
> index febe918d6316..b0e3abfd88a9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25269,6 +25269,13 @@ S: Maintained
> F: Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
> F: drivers/media/i2c/imx678.c
>
> +SONY IMX708 SENSOR DRIVER
> +M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
I've kept "kernel-list@raspberry.com" here from the downstream tree.
Given you maintain other sensors used by Raspberry Pi modules, let me know
in case you prefer I drop this or replace it with your email in v2.
Thanks,
Jai
> +M: Jai Luthra <jai.luthra@ideasonboard.com>
> +L: linux-media@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml
> +
> SONY MEMORYSTICK SUBSYSTEM
> M: Maxim Levitsky <maximlevitsky@gmail.com>
> M: Alex Dubov <oakad@yahoo.com>
>
> --
> 2.54.0
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-15 18:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-15 17:31 [PATCH 0/2] media: Add bindings and driver for Sony IMX708 Jai Luthra
2026-07-15 17:31 ` [PATCH 1/2] dt-bindings: media: i2c: Add imx708 image sensor Jai Luthra
2026-07-15 17:39 ` sashiko-bot
2026-07-15 18:00 ` Jai Luthra
2026-07-15 17:31 ` [PATCH 2/2] media: i2c: Add a driver for Sony IMX708 Jai Luthra
2026-07-15 17:43 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox