diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 12e4a974937dfb..ff3abbbd121035 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -2972,6 +2972,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or Compute Module (CSI0, i2c_vc, and cam0_reg). link-frequency Allowable link frequency values to use in Hz: 450000000 (default), 447000000, 453000000. + 4lane Enable 4 CSI2 lanes. This requires a Compute + Module (1, 3, 4, or 5) or Pi 5. Name: interludeaudio-analog diff --git a/arch/arm/boot/dts/overlays/imx708-overlay.dts b/arch/arm/boot/dts/overlays/imx708-overlay.dts index 3cbec474ce3e96..07598de058e544 100644 --- a/arch/arm/boot/dts/overlays/imx708-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx708-overlay.dts @@ -81,6 +81,22 @@ }; }; + fragment@201 { + target = <&csi_ep>; + __dormant__ { + data-lanes = <1 2 3 4>; + }; + }; + + fragment@202 { + target = <&cam_endpoint>; + __dormant__ { + data-lanes = <1 2 3 4>; + link-frequencies = + /bits/ 64 <547000000>; + }; + }; + __overrides__ { rotation = <&cam_node>,"rotation:0"; orientation = <&cam_node>,"orientation:0"; @@ -95,6 +111,7 @@ vcm = <&vcm_node>, "status", <0>, "=4"; link-frequency = <&cam_endpoint>,"link-frequencies#0"; + 4lane = <0>, "+201+202"; }; }; diff --git a/drivers/media/i2c/imx708.c b/drivers/media/i2c/imx708.c index a56478e31bb133..9fb4bd7713c02f 100644 --- a/drivers/media/i2c/imx708.c +++ b/drivers/media/i2c/imx708.c @@ -39,6 +39,10 @@ MODULE_PARM_DESC(qbc_adjust, "Quad Bayer broken line correction strength [0,2-5] #define IMX708_MODE_STANDBY 0x00 #define IMX708_MODE_STREAMING 0x01 +#define IMX708_REG_CSI_LANE_MODE 0x0114 +#define IMX708_CSI_2_LANE_MODE 0x01 +#define IMX708_CSI_4_LANE_MODE 0x03 + #define IMX708_REG_ORIENTATION 0x101 #define IMX708_INCLK_FREQ 24000000 @@ -50,6 +54,9 @@ MODULE_PARM_DESC(qbc_adjust, "Quad Bayer broken line correction strength [0,2-5] #define IMX708_REG_FRAME_LENGTH 0x0340 #define IMX708_FRAME_LENGTH_MAX 0xffff +/* H_TIMING internal */ +#define IMX708_REG_LINE_LENGTH 0x0342 + /* Long exposure multiplier */ #define IMX708_LONG_EXP_SHIFT_MAX 7 #define IMX708_LONG_EXP_SHIFT_REG 0x3100 @@ -160,7 +167,7 @@ struct imx708_mode { unsigned int height; /* H-timing in pixels */ - unsigned int line_length_pix; + unsigned int line_length_pix[2]; /* Analog crop rectangle. */ struct v4l2_rect crop; @@ -175,7 +182,7 @@ struct imx708_mode { struct imx708_reg_list reg_list; /* Not all modes have the same pixel rate. */ - u64 pixel_rate; + u64 pixel_rate[2]; /* Not all modes have the same minimum exposure. */ u32 exposure_lines_min; @@ -201,12 +208,16 @@ enum { IMX708_LINK_FREQ_450MHZ, IMX708_LINK_FREQ_447MHZ, IMX708_LINK_FREQ_453MHZ, + IMX708_LINK_FREQ_524MHZ, + IMX708_LINK_FREQ_547MHZ, }; static const s64 link_freqs[] = { [IMX708_LINK_FREQ_450MHZ] = 450000000, [IMX708_LINK_FREQ_447MHZ] = 447000000, [IMX708_LINK_FREQ_453MHZ] = 453000000, + [IMX708_LINK_FREQ_524MHZ] = 524000000, + [IMX708_LINK_FREQ_547MHZ] = 547000000, }; /* 450MHz is the nominal "default" link frequency */ @@ -225,6 +236,16 @@ static const struct imx708_reg link_453Mhz_regs[] = { {0x030F, 0x2e}, }; +static const struct imx708_reg link_524Mhz_regs[] = { + {0x030E, 0x01}, + {0x030F, 0x5D}, +}; + +static const struct imx708_reg link_547Mhz_regs[] = { + {0x030E, 0x01}, + {0x030F, 0x6D}, +}; + static const struct imx708_reg_list link_freq_regs[] = { [IMX708_LINK_FREQ_450MHZ] = { .regs = link_450Mhz_regs, @@ -238,16 +259,24 @@ static const struct imx708_reg_list link_freq_regs[] = { .regs = link_453Mhz_regs, .num_of_regs = ARRAY_SIZE(link_453Mhz_regs) }, + [IMX708_LINK_FREQ_524MHZ] = { + .regs = link_524Mhz_regs, + .num_of_regs = ARRAY_SIZE(link_524Mhz_regs) + }, + [IMX708_LINK_FREQ_547MHZ] = { + .regs = link_547Mhz_regs, + .num_of_regs = ARRAY_SIZE(link_547Mhz_regs) + }, }; static const struct imx708_reg mode_common_regs[] = { - {0x0100, 0x00}, - {0x0136, 0x18}, - {0x0137, 0x00}, - {0x33F0, 0x02}, - {0x33F1, 0x05}, + {0x0100, 0x00}, + {0x0136, 0x18}, //REG_EXCK_FREQ_MSB + {0x0137, 0x00}, //REG_EXCK_FREQ_LSB + {0x33F0, 0x02}, //REG_IOPSYCK_DIV 0x01, 0x02 + {0x33F1, 0x05}, //REG_IOPPXCK_DIV 0x01, 0x05 {0x3062, 0x00}, - {0x3063, 0x12}, + {0x3063, 0x12}, //0x30, 0x12 {0x3068, 0x00}, {0x3069, 0x12}, {0x306A, 0x00}, @@ -268,9 +297,8 @@ static const struct imx708_reg mode_common_regs[] = { {0xF033, 0x08}, {0xF03D, 0x10}, {0xF03F, 0x10}, - {0x0112, 0x0A}, - {0x0113, 0x0A}, - {0x0114, 0x01}, + {0x0112, 0x0A}, //REG_CSI_FORMAT_C + {0x0113, 0x0A}, //REG_CSI_FORMAT_D {0x0B8E, 0x01}, {0x0B8F, 0x00}, {0x0B94, 0x01}, @@ -288,28 +316,115 @@ static const struct imx708_reg mode_common_regs[] = { {0x3363, 0x00}, {0x3364, 0x00}, {0x3365, 0x00}, - {0x0138, 0x01}, + {0x0138, 0x01}, //REG_TEMP_SENS_CTL +}; + +/* Pixel rate setup */ +enum { + IMX708_PIX_RATE_566Mhz, + IMX708_PIX_RATE_585Mhz, + IMX708_PIX_RATE_595Mhz, + IMX708_PIX_RATE_777Mhz, + IMX708_PIX_RATE_854Mhz, +}; + +static const s64 pixel_rates[] = { + [IMX708_PIX_RATE_566Mhz] = 566400000, + [IMX708_PIX_RATE_585Mhz] = 585600000, + [IMX708_PIX_RATE_595Mhz] = 595200000, + [IMX708_PIX_RATE_777Mhz] = 777600000, + [IMX708_PIX_RATE_854Mhz] = 854400000, +}; + +static const struct imx708_reg pixel_rate_566Mhz_regs[] = { + {0x0305, 0x02}, + {0x0306, 0x00}, + {0x0307, 0x76}, +}; + +static const struct imx708_reg pixel_rate_585Mhz_regs[] = { + {0x0305, 0x02}, + {0x0306, 0x00}, + {0x0307, 0x7A}, +}; + +static const struct imx708_reg pixel_rate_595Mhz_regs[] = { + {0x0305, 0x02}, + {0x0306, 0x00}, + {0x0307, 0x7C}, +}; + +static const struct imx708_reg pixel_rate_777Mhz_regs[] = { + {0x0305, 0x02}, + {0x0306, 0x00}, + {0x0307, 0xA2}, +}; + +static const struct imx708_reg pixel_rate_854Mhz_regs[] = { + {0x0305, 0x03}, + {0x0306, 0x01}, + {0x0307, 0x0B}, +}; + +static const struct imx708_reg_list pixel_rate_regs[] = { + [IMX708_PIX_RATE_566Mhz] = { + .regs = pixel_rate_566Mhz_regs, + .num_of_regs = ARRAY_SIZE(pixel_rate_566Mhz_regs) + }, + [IMX708_PIX_RATE_585Mhz] = { + .regs = pixel_rate_585Mhz_regs, + .num_of_regs = ARRAY_SIZE(pixel_rate_585Mhz_regs) + }, + [IMX708_PIX_RATE_595Mhz] = { + .regs = pixel_rate_595Mhz_regs, + .num_of_regs = ARRAY_SIZE(pixel_rate_595Mhz_regs) + }, + [IMX708_PIX_RATE_777Mhz] = { + .regs = pixel_rate_777Mhz_regs, + .num_of_regs = ARRAY_SIZE(pixel_rate_777Mhz_regs) + }, + [IMX708_PIX_RATE_854Mhz] = { + .regs = pixel_rate_854Mhz_regs, + .num_of_regs = ARRAY_SIZE(pixel_rate_854Mhz_regs) + }, +}; + +/* Line Length setup */ +enum { + IMX708_LINE_LENGTH_2608, + IMX708_LINE_LENGTH_5216, + IMX708_LINE_LENGTH_7824, + IMX708_LINE_LENGTH_10432, + IMX708_LINE_LENGTH_15648, + IMX708_LINE_LENGTH_20864, +}; + +static const s64 line_lengths[] = { + [IMX708_LINE_LENGTH_2608] = 2608, + [IMX708_LINE_LENGTH_5216] = 5216, + [IMX708_LINE_LENGTH_7824] = 7824, + [IMX708_LINE_LENGTH_10432] = 10432, + [IMX708_LINE_LENGTH_15648] = 15648, + [IMX708_LINE_LENGTH_20864] = 20864, }; /* 10-bit. */ static const struct imx708_reg mode_4608x2592_regs[] = { - {0x0342, 0x3D}, - {0x0343, 0x20}, - {0x0340, 0x0A}, - {0x0341, 0x59}, - {0x0344, 0x00}, - {0x0345, 0x00}, - {0x0346, 0x00}, - {0x0347, 0x00}, - {0x0348, 0x11}, - {0x0349, 0xFF}, - {0x034A, 0X0A}, - {0x034B, 0x1F}, + {0x0340, 0x0A}, //REG_FRAME_LEN_MSB + {0x0341, 0x59}, //REG_FRAME_LEN_LSB (0xC4, 0x5A, 0x59) + {0x0344, 0x00}, //REG_X_ADD_STA_MSB + {0x0345, 0x00}, //REG_X_ADD_STA_LSB + {0x0346, 0x00}, //REG_Y_ADD_STA_MSB + {0x0347, 0x00}, //REG_Y_ADD_STA_LSB + {0x0348, 0x11}, //REG_X_ADD_END_MSB + {0x0349, 0xFF}, //REG_X_ADD_END_LSB + {0x034A, 0X0A}, //REG_Y_ADD_END_MSB + {0x034B, 0x1F}, //REG_Y_ADD_END_LSB {0x0220, 0x62}, {0x0222, 0x01}, - {0x0900, 0x00}, - {0x0901, 0x11}, - {0x0902, 0x0A}, + {0x0900, 0x00}, //REG_BINNING_MODE + {0x0901, 0x11}, //REG_BINNING_HV + {0x0902, 0x0A}, //REG_BINNING_WEIGHTING {0x3200, 0x01}, {0x3201, 0x01}, {0x32D5, 0x01}, @@ -318,28 +433,25 @@ static const struct imx708_reg mode_4608x2592_regs[] = { {0x32DF, 0x00}, {0x350C, 0x00}, {0x350D, 0x00}, - {0x0408, 0x00}, - {0x0409, 0x00}, - {0x040A, 0x00}, - {0x040B, 0x00}, - {0x040C, 0x12}, - {0x040D, 0x00}, - {0x040E, 0x0A}, - {0x040F, 0x20}, - {0x034C, 0x12}, - {0x034D, 0x00}, - {0x034E, 0x0A}, - {0x034F, 0x20}, - {0x0301, 0x05}, - {0x0303, 0x02}, - {0x0305, 0x02}, - {0x0306, 0x00}, - {0x0307, 0x7C}, + {0x0408, 0x00}, //REG_DIG_CROP_X_OFFSET_MSB + {0x0409, 0x00}, //REG_DIG_CROP_X_OFFSET_LSB + {0x040A, 0x00}, //REG_DIG_CROP_Y_OFFSET_MSB + {0x040B, 0x00}, //REG_DIG_CROP_Y_OFFSET_LSB + {0x040C, 0x12}, //REG_DIG_CROP_WIDTH_MSB + {0x040D, 0x00}, //REG_DIG_CROP_WIDTH_LSB + {0x040E, 0x0A}, //REG_DIG_CROP_HEIGHT_MSB + {0x040F, 0x20}, //REG_DIG_CROP_HEIGHT_LSB + {0x034C, 0x12}, //REG_X_OUT_SIZE_MSB + {0x034D, 0x00}, //REG_X_OUT_SIZE_LSB + {0x034E, 0x0A}, //REG_Y_OUT_SIZE_MSB + {0x034F, 0x20}, //REG_Y_OUT_SIZE_LSB + {0x0301, 0x05}, //REG_IVTPXCK_DIV + {0x0303, 0x02}, //REG_IVTSYCK_DIV {0x030B, 0x02}, - {0x030D, 0x04}, - {0x0310, 0x01}, + {0x030D, 0x04}, //REG_IOP_PREPLLCK_DIV + {0x0310, 0x01}, //REG_PLL_MULTI_DRV {0x3CA0, 0x00}, - {0x3CA1, 0x64}, + {0x3CA1, 0x64}, //0x32, 0x64 {0x3CA4, 0x00}, {0x3CA5, 0x00}, {0x3CA6, 0x00}, @@ -347,27 +459,27 @@ static const struct imx708_reg mode_4608x2592_regs[] = { {0x3CAA, 0x00}, {0x3CAB, 0x00}, {0x3CB8, 0x00}, - {0x3CB9, 0x08}, + {0x3CB9, 0x08}, //0x04, 0x08 {0x3CBA, 0x00}, {0x3CBB, 0x00}, {0x3CBC, 0x00}, - {0x3CBD, 0x3C}, + {0x3CBD, 0x3C}, //0x1E, 0x3C {0x3CBE, 0x00}, {0x3CBF, 0x00}, - {0x0202, 0x0A}, - {0x0203, 0x29}, + {0x0202, 0x0A}, //REG_COARSE_INTEGRATION_TIME_MSB + {0x0203, 0x29}, //REG_COARSE_INTEGRATION_TIME_LSB {0x0224, 0x01}, {0x0225, 0xF4}, {0x3116, 0x01}, {0x3117, 0xF4}, - {0x0204, 0x00}, - {0x0205, 0x00}, + {0x0204, 0x00}, //REG_ANA_GLOBAL_GAIN_U + {0x0205, 0x00}, //REG_ANA_GLOBAL_GAIN_L {0x0216, 0x00}, {0x0217, 0x00}, {0x0218, 0x01}, {0x0219, 0x00}, - {0x020E, 0x01}, - {0x020F, 0x00}, + {0x020E, 0x01}, //REG_DIG_GAIN_GR_U + {0x020F, 0x00}, //REG_DIG_GAIN_GR_L {0x3118, 0x00}, {0x3119, 0x00}, {0x311A, 0x01}, @@ -426,9 +538,6 @@ static const struct imx708_reg mode_2x2binned_regs[] = { {0x034F, 0x10}, {0x0301, 0x05}, {0x0303, 0x02}, - {0x0305, 0x02}, - {0x0306, 0x00}, - {0x0307, 0x7A}, {0x030B, 0x02}, {0x030D, 0x04}, {0x0310, 0x01}, @@ -520,9 +629,6 @@ static const struct imx708_reg mode_2x2binned_720p_regs[] = { {0x034F, 0x60}, {0x0301, 0x05}, {0x0303, 0x02}, - {0x0305, 0x02}, - {0x0306, 0x00}, - {0x0307, 0x76}, {0x030B, 0x02}, {0x030D, 0x04}, {0x0310, 0x01}, @@ -614,9 +720,6 @@ static const struct imx708_reg mode_hdr_regs[] = { {0x034F, 0x10}, {0x0301, 0x05}, {0x0303, 0x02}, - {0x0305, 0x02}, - {0x0306, 0x00}, - {0x0307, 0xA2}, {0x030B, 0x02}, {0x030D, 0x04}, {0x0310, 0x01}, @@ -676,7 +779,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { /* Full resolution. */ .width = 4608, .height = 2592, - .line_length_pix = 0x3d20, + .line_length_pix = {15648, 10432}, .crop = { .left = IMX708_PIXEL_ARRAY_LEFT, .top = IMX708_PIXEL_ARRAY_TOP, @@ -689,7 +792,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { .num_of_regs = ARRAY_SIZE(mode_4608x2592_regs), .regs = mode_4608x2592_regs, }, - .pixel_rate = 595200000, + .pixel_rate = {595200000, 854400000}, .exposure_lines_min = 8, .exposure_lines_step = 1, .hdr = false, @@ -699,7 +802,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { /* regular 2x2 binned. */ .width = 2304, .height = 1296, - .line_length_pix = 0x1e90, + .line_length_pix = {7824, 5216}, .crop = { .left = IMX708_PIXEL_ARRAY_LEFT, .top = IMX708_PIXEL_ARRAY_TOP, @@ -712,7 +815,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { .num_of_regs = ARRAY_SIZE(mode_2x2binned_regs), .regs = mode_2x2binned_regs, }, - .pixel_rate = 585600000, + .pixel_rate = {585600000, 585600000}, .exposure_lines_min = 4, .exposure_lines_step = 2, .hdr = false, @@ -722,7 +825,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { /* 2x2 binned and cropped for 720p. */ .width = 1536, .height = 864, - .line_length_pix = 0x1460, + .line_length_pix = {5216, 5216}, .crop = { .left = IMX708_PIXEL_ARRAY_LEFT + 768, .top = IMX708_PIXEL_ARRAY_TOP + 432, @@ -735,7 +838,7 @@ static const struct imx708_mode supported_modes_10bit_no_hdr[] = { .num_of_regs = ARRAY_SIZE(mode_2x2binned_720p_regs), .regs = mode_2x2binned_720p_regs, }, - .pixel_rate = 566400000, + .pixel_rate = {566400000, 566400000}, .exposure_lines_min = 4, .exposure_lines_step = 2, .hdr = false, @@ -748,7 +851,7 @@ static const struct imx708_mode supported_modes_10bit_hdr[] = { /* There's only one HDR mode, which is 2x2 downscaled */ .width = 2304, .height = 1296, - .line_length_pix = 0x1460, + .line_length_pix = {5216, 5216}, .crop = { .left = IMX708_PIXEL_ARRAY_LEFT, .top = IMX708_PIXEL_ARRAY_TOP, @@ -761,7 +864,7 @@ static const struct imx708_mode supported_modes_10bit_hdr[] = { .num_of_regs = ARRAY_SIZE(mode_hdr_regs), .regs = mode_hdr_regs, }, - .pixel_rate = 777600000, + .pixel_rate = {777600000, 777600000}, .exposure_lines_min = 8 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, .exposure_lines_step = 2 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, .hdr = true, @@ -866,6 +969,9 @@ struct imx708 { unsigned int long_exp_shift; unsigned int link_freq_idx; + + /* Two or Four lanes */ + u8 lanes; }; static inline struct imx708 *to_imx708(struct v4l2_subdev *_sd) @@ -1108,25 +1214,20 @@ static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val) static void imx708_set_framing_limits(struct imx708 *imx708) { const struct imx708_mode *mode = imx708->mode; - unsigned int hblank; + unsigned int hblank, pix_rate; - __v4l2_ctrl_modify_range(imx708->pixel_rate, - mode->pixel_rate, mode->pixel_rate, - 1, mode->pixel_rate); + pix_rate = mode->pixel_rate[imx708->lanes == 2 ? 0 : 1]; + __v4l2_ctrl_modify_range(imx708->pixel_rate, pix_rate, pix_rate, 1, pix_rate); /* Update limits and set FPS to default */ __v4l2_ctrl_modify_range(imx708->vblank, mode->vblank_min, - ((1 << IMX708_LONG_EXP_SHIFT_MAX) * - IMX708_FRAME_LENGTH_MAX) - mode->height, - 1, mode->vblank_default); + ((1 << IMX708_LONG_EXP_SHIFT_MAX) * + IMX708_FRAME_LENGTH_MAX) - mode->height, + 1, mode->vblank_default); - /* - * Currently PPL is fixed to the mode specified value, so hblank - * depends on mode->width only, and is not changeable in any - * way other than changing the mode. - */ - hblank = mode->line_length_pix - mode->width; + hblank = mode->line_length_pix[imx708->lanes == 2 ? 0 : 1] - mode->width; __v4l2_ctrl_modify_range(imx708->hblank, hblank, hblank, 1, hblank); + } static int imx708_set_ctrl(struct v4l2_ctrl *ctrl) @@ -1215,6 +1316,10 @@ static int imx708_set_ctrl(struct v4l2_ctrl *ctrl) ret = imx708_set_frame_length(imx708, imx708->mode->height + ctrl->val); break; + case V4L2_CID_HBLANK: + ret = imx708_write_reg(imx708, IMX708_REG_LINE_LENGTH, 2, + imx708->mode->width + ctrl->val); + break; case V4L2_CID_NOTIFY_GAINS: ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_BLUE, IMX708_REG_VALUE_16BIT, @@ -1474,11 +1579,18 @@ static int imx708_get_selection(struct v4l2_subdev *sd, return -EINVAL; } +static int imx708_configure_lanes(struct imx708 *imx708) +{ + return imx708_write_reg(imx708, IMX708_REG_CSI_LANE_MODE, IMX708_REG_VALUE_08BIT, + imx708->lanes == 2 ? IMX708_CSI_2_LANE_MODE : + IMX708_CSI_4_LANE_MODE); +}; + /* Start streaming */ static int imx708_start_streaming(struct imx708 *imx708) { struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd); - const struct imx708_reg_list *reg_list, *freq_regs; + const struct imx708_reg_list *reg_list, *freq_regs, *pix_rate_regs; int i, ret; u32 val; @@ -1516,6 +1628,16 @@ static int imx708_start_streaming(struct imx708 *imx708) imx708->common_regs_written = true; } + /* Configure two or four Lane mode */ + ret = imx708_configure_lanes(imx708); + if (ret) { + dev_err(&client->dev, "%s failed to configure lanes\n", __func__); + return ret; + } + ret = imx708_read_reg(imx708, IMX708_REG_CSI_LANE_MODE, + IMX708_REG_VALUE_08BIT, &val); + dev_info(&client->dev, "configured %d lanes\n", val+1); + /* Apply default values of current mode */ reg_list = &imx708->mode->reg_list; ret = imx708_write_regs(imx708, reg_list->regs, reg_list->num_of_regs); @@ -1524,6 +1646,22 @@ static int imx708_start_streaming(struct imx708 *imx708) return ret; } + /* Set the pixel rate */ + for (i = 0; i < ARRAY_SIZE(pixel_rates); i++) { + if (pixel_rates[i] == (imx708->lanes == 2 ? + imx708->mode->pixel_rate[0] : + imx708->mode->pixel_rate[1])) { + break; + } + } + pix_rate_regs = &pixel_rate_regs[i]; + ret = imx708_write_regs(imx708, pix_rate_regs->regs, + pix_rate_regs->num_of_regs); + if (ret) { + dev_err(&client->dev, "%s failed to set pixel rate\n", __func__); + return ret; + } + /* Update the link frequency registers */ freq_regs = &link_freq_regs[imx708->link_freq_idx]; ret = imx708_write_regs(imx708, freq_regs->regs, @@ -1892,7 +2030,6 @@ static int imx708_init_controls(struct imx708 *imx708) goto error; } - 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->hdr_mode->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; @@ -1938,10 +2075,13 @@ static int imx708_check_hwcfg(struct device *dev, struct imx708 *imx708) } /* 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"); + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 && + ep_cfg.bus.mipi_csi2.num_data_lanes != 4) { + dev_err_probe(dev, -EINVAL, + "only 2 or 4 data lanes are currently supported\n"); goto error_out; } + imx708->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; /* Check the link frequency set in device tree */ if (!ep_cfg.nr_of_link_frequencies) {