diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index 10f2efe916f2e9..f1cb7735e8bba4 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -137,6 +137,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ imx290.dtbo \ imx296.dtbo \ imx327.dtbo \ + imx335.dtbo \ imx378.dtbo \ imx415.dtbo \ imx462.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index d7c8782ea5927e..a5c233141d440a 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -2754,7 +2754,7 @@ Params: rotation Mounting rotation of the camera sensor (0 or Compute Module (CSI0, i2c_vc, and cam0_reg). vcm Configure a VCM focus drive on the sensor. 4lane Enable 4 CSI2 lanes. This requires a Compute - Module (1, 3, or 4). + Module (1, 3, 4, or 5) or Pi 5. Name: imx290 @@ -2763,7 +2763,7 @@ Info: Sony IMX290 camera module. variants. Load: dtoverlay=imx290, Params: 4lane Enable 4 CSI2 lanes. This requires a Compute - Module (1, 3, or 4). + Module (1, 3, 4, or 5) or Pi 5. clock-frequency Sets the clock frequency to match that used on the board. Modules from Vision Components use 37.125MHz @@ -2806,7 +2806,7 @@ Info: Sony IMX327 camera module. variants. Load: dtoverlay=imx327, Params: 4lane Enable 4 CSI2 lanes. This requires a Compute - Module (1, 3, or 4). + Module (1, 3, 4, or 5) or Pi 5. clock-frequency Sets the clock frequency to match that used on the board. Modules from Vision Components use 37.125MHz @@ -2823,6 +2823,25 @@ Params: 4lane Enable 4 CSI2 lanes. This requires a Compute Compute Module (CSI0, i2c_vc, and cam0_reg). +Name: imx335 +Info: Sony IMX335 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi + variants. +Load: dtoverlay=imx335, +Params: orientation Sensor orientation (0 = front, 1 = rear, + 2 = external, default external) + rotation Mounting rotation of the camera sensor (0 or + 180, default 0) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) + link-frequency Allowable link frequency values to use in Hz: + 594000000 (default), 445500000. + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). + 4lane Enable 4 CSI2 lanes. This requires a Compute + Module (1, 3, 4, or 5) or Pi 5. + + Name: imx378 Info: Sony IMX378 camera module. Uses Unicam 1, which is the standard camera connector on most Pi diff --git a/arch/arm/boot/dts/overlays/imx335-overlay.dts b/arch/arm/boot/dts/overlays/imx335-overlay.dts new file mode 100644 index 00000000000000..dfe207faecbeaa --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx335-overlay.dts @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Definitions for IMX335 camera module on VC I2C bus +/dts-v1/; +/plugin/; + +#include + +/{ + compatible = "brcm,bcm2835"; + + fragment@0 { + target = <&i2c0if>; + __overlay__ { + status = "okay"; + }; + }; + + clk_frag: fragment@1 { + target = <&cam1_clk>; + __overlay__ { + status = "okay"; + clock-frequency = <24000000>; + }; + }; + + fragment@2 { + target = <&i2c0mux>; + __overlay__ { + status = "okay"; + }; + }; + + reg_frag: fragment@3 { + target = <&cam1_reg>; + cam_reg: __overlay__ { + startup-delay-us = <200000>; + off-on-delay-us = <30000>; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + }; + + i2c_frag: fragment@100 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + #include "imx335.dtsi" + }; + }; + + csi_frag: fragment@101 { + target = <&csi1>; + csi: __overlay__ { + status = "okay"; + + port { + csi_ep: endpoint { + remote-endpoint = <&cam_endpoint>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + + fragment@102 { + target = <&csi1>; + __dormant__ { + compatible = "brcm,bcm2835-unicam-legacy"; + }; + }; + + fragment@201 { + target = <&csi_ep>; + __dormant__ { + data-lanes = <1 2 3 4>; + }; + }; + + fragment@202 { + target = <&cam_endpoint>; + __dormant__ { + data-lanes = <1 2 3 4>; + }; + }; + + __overrides__ { + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <0>,"!102"; + + cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, + <&cam_node>, "clocks:0=",<&cam0_clk>, + <&cam_node>, "avdd-supply:0=",<&cam0_reg>; + link-frequency = <&cam_endpoint>,"link-frequencies#0"; + 4lane = <0>, "+201+202"; + }; +}; + +&cam_node { + status = "okay"; +}; + +&cam_endpoint { + remote-endpoint = <&csi_ep>; +}; diff --git a/arch/arm/boot/dts/overlays/imx335.dtsi b/arch/arm/boot/dts/overlays/imx335.dtsi new file mode 100644 index 00000000000000..1d4b07da3b1438 --- /dev/null +++ b/arch/arm/boot/dts/overlays/imx335.dtsi @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Fragment that configures a Sony IMX335 + +cam_node: imx335@1a { + compatible = "sony,imx335"; + reg = <0x1a>; + status = "disabled"; + + clocks = <&cam1_clk>; + clock-names = "xclk"; + + avdd-supply = <&cam1_reg>; /* Analog 2.9v */ + iovdd-supply = <&cam_dummy_reg>; /* Digital I/O 1.8v */ + dvdd-supply = <&cam_dummy_reg>; /* Digital Core 1.2v */ + + rotation = <180>; + orientation = <2>; + + port { + cam_endpoint: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <594000000 445500000>; + }; + }; +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 0c2f60e19a539f..45f9948fc8f9d8 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -938,6 +938,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index 449d10b1bbd77c..8d913a6a1ee2bb 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -967,6 +967,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index fa234a7e0744c4..4ac383e5d821a7 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -931,6 +931,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 1b344d46806477..a40e957d6d710d 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -1016,6 +1016,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/arch/arm64/configs/bcm2711_rt_defconfig b/arch/arm64/configs/bcm2711_rt_defconfig index cd0ebd4cc48780..9aa8084d23d7c5 100644 --- a/arch/arm64/configs/bcm2711_rt_defconfig +++ b/arch/arm64/configs/bcm2711_rt_defconfig @@ -1016,6 +1016,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig index 9b4e554978beef..aa28b46a6aa275 100644 --- a/arch/arm64/configs/bcm2712_defconfig +++ b/arch/arm64/configs/bcm2712_defconfig @@ -1018,6 +1018,7 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX335=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_IMX477=m CONFIG_VIDEO_IMX500=m diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index fcfd1d851bd4aa..237dd39d5daea3 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -31,7 +31,7 @@ #define IMX335_REG_CPWAIT_TIME CCI_REG8(0x300d) #define IMX335_REG_WINMODE CCI_REG8(0x3018) #define IMX335_REG_HTRIMMING_START CCI_REG16_LE(0x302c) -#define IMX335_REG_HNUM CCI_REG8(0x302e) +#define IMX335_REG_HNUM CCI_REG16_LE(0x302e) /* Lines per frame */ #define IMX335_REG_VMAX CCI_REG24_LE(0x3030) @@ -56,6 +56,9 @@ #define IMX335_AGAIN_STEP 1 #define IMX335_AGAIN_DEFAULT 0 +/* Vertical flip */ +#define IMX335_REG_VREVERSE CCI_REG8(0x304f) + #define IMX335_REG_TPG_TESTCLKEN CCI_REG8(0x3148) #define IMX335_REG_INCLKSEL1 CCI_REG16_LE(0x314c) @@ -155,6 +158,8 @@ static const char * const imx335_supply_name[] = { * @vblank_max: Maximum vertical blanking in lines * @pclk: Sensor pixel clock * @reg_list: Register list for sensor mode + * @vflip_normal: Register list vflip (normal readout) + * @vflip_inverted: Register list vflip (inverted readout) */ struct imx335_mode { u32 width; @@ -166,6 +171,8 @@ struct imx335_mode { u32 vblank_max; u64 pclk; struct imx335_reg_list reg_list; + struct imx335_reg_list vflip_normal; + struct imx335_reg_list vflip_inverted; }; /** @@ -183,6 +190,7 @@ struct imx335_mode { * @pclk_ctrl: Pointer to pixel clock control * @hblank_ctrl: Pointer to horizontal blanking control * @vblank_ctrl: Pointer to vertical blanking control + * @vflip: Pointer to vertical flip control * @exp_ctrl: Pointer to exposure control * @again_ctrl: Pointer to analog gain control * @vblank: Vertical blanking in lines @@ -207,6 +215,7 @@ struct imx335 { struct v4l2_ctrl *pclk_ctrl; struct v4l2_ctrl *hblank_ctrl; struct v4l2_ctrl *vblank_ctrl; + struct v4l2_ctrl *vflip; struct { struct v4l2_ctrl *exp_ctrl; struct v4l2_ctrl *again_ctrl; @@ -252,14 +261,13 @@ static const int imx335_tpg_val[] = { }; /* Sensor mode registers */ -static const struct cci_reg_sequence mode_2592x1940_regs[] = { +static const struct cci_reg_sequence mode_2592x1944_regs[] = { { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, { IMX335_REG_MASTER_MODE, 0x00 }, { IMX335_REG_WINMODE, 0x04 }, { IMX335_REG_HTRIMMING_START, 48 }, { IMX335_REG_HNUM, 2592 }, { IMX335_REG_Y_OUT_SIZE, 1944 }, - { IMX335_REG_AREA3_ST_ADR_1, 176 }, { IMX335_REG_AREA3_WIDTH_1, 3928 }, { IMX335_REG_OPB_SIZE_V, 0 }, { IMX335_REG_XVS_XHS_DRV, 0x00 }, @@ -333,6 +341,26 @@ static const struct cci_reg_sequence mode_2592x1940_regs[] = { { CCI_REG8(0x3a00), 0x00 }, }; +static const struct cci_reg_sequence mode_2592x1944_vflip_normal[] = { + { IMX335_REG_AREA3_ST_ADR_1, 176 }, + + /* Undocumented V-Flip related registers on Page 55 of datasheet. */ + { CCI_REG8(0x3081), 0x02, }, + { CCI_REG8(0x3083), 0x02, }, + { CCI_REG16_LE(0x30b6), 0x00 }, + { CCI_REG16_LE(0x3116), 0x08 }, +}; + +static const struct cci_reg_sequence mode_2592x1944_vflip_inverted[] = { + { IMX335_REG_AREA3_ST_ADR_1, 4112 }, + + /* Undocumented V-Flip related registers on Page 55 of datasheet. */ + { CCI_REG8(0x3081), 0xfe, }, + { CCI_REG8(0x3083), 0xfe, }, + { CCI_REG16_LE(0x30b6), 0x1fa }, + { CCI_REG16_LE(0x3116), 0x002 }, +}; + static const struct cci_reg_sequence raw10_framefmt_regs[] = { { IMX335_REG_ADBIT, 0x00 }, { IMX335_REG_MDBIT, 0x00 }, @@ -416,8 +444,16 @@ static const struct imx335_mode supported_mode = { .vblank_max = 133060, .pclk = 396000000, .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), - .regs = mode_2592x1940_regs, + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .vflip_normal = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_normal), + .regs = mode_2592x1944_vflip_normal, + }, + .vflip_inverted = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_inverted), + .regs = mode_2592x1944_vflip_inverted, }, }; @@ -492,6 +528,26 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) return ret; } +static int imx335_update_vertical_flip(struct imx335 *imx335, u32 vflip) +{ + int ret = 0; + + if (vflip) + cci_multi_reg_write(imx335->cci, + imx335->cur_mode->vflip_inverted.regs, + imx335->cur_mode->vflip_inverted.num_of_regs, + &ret); + else + cci_multi_reg_write(imx335->cci, + imx335->cur_mode->vflip_normal.regs, + imx335->cur_mode->vflip_normal.num_of_regs, + &ret); + if (ret) + return ret; + + return cci_write(imx335->cci, IMX335_REG_VREVERSE, vflip, NULL); +} + static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index) { int ret = 0; @@ -559,12 +615,12 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) imx335->vblank, imx335->vblank + imx335->cur_mode->height); - return __v4l2_ctrl_modify_range(imx335->exp_ctrl, - IMX335_EXPOSURE_MIN, - imx335->vblank + - imx335->cur_mode->height - - IMX335_EXPOSURE_OFFSET, - 1, IMX335_EXPOSURE_DEFAULT); + __v4l2_ctrl_modify_range(imx335->exp_ctrl, + IMX335_EXPOSURE_MIN, + imx335->vblank + + imx335->cur_mode->height - + IMX335_EXPOSURE_OFFSET, + 1, IMX335_EXPOSURE_DEFAULT); } /* @@ -575,6 +631,13 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) return 0; switch (ctrl->id) { + case V4L2_CID_VBLANK: + exposure = imx335->exp_ctrl->val; + analog_gain = imx335->again_ctrl->val; + + ret = imx335_update_exp_gain(imx335, exposure, analog_gain); + + break; case V4L2_CID_EXPOSURE: exposure = ctrl->val; analog_gain = imx335->again_ctrl->val; @@ -584,6 +647,10 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) ret = imx335_update_exp_gain(imx335, exposure, analog_gain); + break; + case V4L2_CID_VFLIP: + ret = imx335_update_vertical_flip(imx335, ctrl->val); + break; case V4L2_CID_TEST_PATTERN: ret = imx335_update_test_pattern(imx335, ctrl->val); @@ -1166,7 +1233,7 @@ static int imx335_init_controls(struct imx335 *imx335) return ret; /* v4l2_fwnode_device_properties can add two more controls */ - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); if (ret) return ret; @@ -1201,6 +1268,13 @@ static int imx335_init_controls(struct imx335 *imx335) v4l2_ctrl_cluster(2, &imx335->exp_ctrl); + imx335->vflip = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + if (imx335->vflip) + imx335->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + imx335->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_VBLANK,