From da0ac2bb7f9ce7ab8657ccd20d704a16a9cc61c0 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 24 Nov 2022 18:09:07 +0000 Subject: [PATCH] media: i2c: imx290: Reset to upstream. For backporting a load of upstream commits, reset to upstream first. Downstream patches then need to be regenerated and applied. Signed-off-by: Dave Stevenson --- drivers/media/i2c/imx290.c | 621 ++++++++----------------------------- 1 file changed, 133 insertions(+), 488 deletions(-) --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1,16 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Sony IMX462 / IMX290 / IMX327 CMOS Image Sensor Driver - * - * The IMX462, IMX290,and IMX327 are very similar 1920x1080 1/2.8 CMOS image - * sensors. - * IMX327 can support up to 60fps with 10 or 12bit readout. - * IMX290 adds support for 120fps, but only 10bit and when connected over 4 - * CSI-2 lanes. - * IMX462 adds support for 120fps in both 10 and 12bit readout modes. - * - * The modules don't appear to have a mechanism to identify whether the mono or - * colour variant is connected, therefore it is done via compatible string. + * Sony IMX290 CMOS Image Sensor Driver * * Copyright (C) 2019 FRAMOS GmbH. * @@ -23,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -33,28 +22,15 @@ #include #include -enum imx290_clk_index { - CLK_37_125, - CLK_74_25, -}; - #define IMX290_STANDBY 0x3000 #define IMX290_REGHOLD 0x3001 #define IMX290_XMSTA 0x3002 -#define IMX290_FLIP_WINMODE 0x3007 #define IMX290_FR_FDG_SEL 0x3009 #define IMX290_BLKLEVEL_LOW 0x300a #define IMX290_BLKLEVEL_HIGH 0x300b #define IMX290_GAIN 0x3014 -#define IMX290_VMAX_LOW 0x3018 -#define IMX290_VMAX_MAX 0x3fff #define IMX290_HMAX_LOW 0x301c #define IMX290_HMAX_HIGH 0x301d -#define IMX290_HMAX_MAX 0xffff - -#define IMX290_EXPOSURE_MIN 1 -#define IMX290_EXPOSURE_STEP 1 -#define IMX290_EXPOSURE_LOW 0x3020 #define IMX290_PGCTRL 0x308c #define IMX290_PHY_LANE_NUM 0x3407 #define IMX290_CSI_LANE_MODE 0x3443 @@ -63,13 +39,6 @@ enum imx290_clk_index { #define IMX290_PGCTRL_THRU BIT(1) #define IMX290_PGCTRL_MODE(n) ((n) << 4) -#define IMX290_NATIVE_WIDTH 1945U -#define IMX290_NATIVE_HEIGHT 1109U -#define IMX290_PIXEL_ARRAY_LEFT 4U -#define IMX290_PIXEL_ARRAY_TOP 12U -#define IMX290_PIXEL_ARRAY_WIDTH 1937U -#define IMX290_PIXEL_ARRAY_HEIGHT 1097U - static const char * const imx290_supply_name[] = { "vdda", "vddd", @@ -87,31 +56,19 @@ struct imx290_mode { u32 width; u32 height; u32 hmax; - u32 vmax; u8 link_freq_index; - struct v4l2_rect crop; - - const struct imx290_regval *mode_data; - u32 mode_data_size; - const struct imx290_regval *lane_data; - u32 lane_data_size; - - /* Clock setup can vary. Index as enum imx290_clk_index */ - const struct imx290_regval *clk_data[2]; - u32 clk_size; + const struct imx290_regval *data; + u32 data_size; }; struct imx290 { struct device *dev; struct clk *xclk; - u32 xclk_freq; struct regmap *regmap; u8 nlanes; u8 bpp; - const struct imx290_pixfmt *formats; - struct v4l2_subdev sd; struct media_pad pad; struct v4l2_mbus_framefmt current_format; @@ -123,11 +80,6 @@ struct imx290 { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *vblank; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *exposure; struct mutex lock; }; @@ -137,18 +89,11 @@ struct imx290_pixfmt { u8 bpp; }; -#define IMX290_NUM_FORMATS 2 - -static const struct imx290_pixfmt imx290_colour_formats[IMX290_NUM_FORMATS] = { +static const struct imx290_pixfmt imx290_formats[] = { { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, }; -static const struct imx290_pixfmt imx290_mono_formats[IMX290_NUM_FORMATS] = { - { MEDIA_BUS_FMT_Y10_1X10, 10 }, - { MEDIA_BUS_FMT_Y12_1X12, 12 }, -}; - static const struct regmap_config imx290_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -168,7 +113,11 @@ static const char * const imx290_test_pa static const struct imx290_regval imx290_global_init_settings[] = { { 0x3007, 0x00 }, + { 0x3018, 0x65 }, + { 0x3019, 0x04 }, { 0x301a, 0x00 }, + { 0x3444, 0x20 }, + { 0x3445, 0x25 }, { 0x303a, 0x0c }, { 0x3040, 0x00 }, { 0x3041, 0x00 }, @@ -222,33 +171,8 @@ static const struct imx290_regval imx290 { 0x33b3, 0x04 }, }; -static const struct imx290_regval imx290_37_125mhz_clock_1080p[] = { - { 0x305c, 0x18 }, - { 0x305d, 0x03 }, - { 0x305e, 0x20 }, - { 0x305f, 0x01 }, - { 0x315e, 0x1a }, - { 0x3164, 0x1a }, - { 0x3444, 0x20 }, - { 0x3445, 0x25 }, - { 0x3480, 0x49 }, -}; - -static const struct imx290_regval imx290_74_250mhz_clock_1080p[] = { - { 0x305c, 0x0c }, - { 0x305d, 0x03 }, - { 0x305e, 0x10 }, - { 0x305f, 0x01 }, - { 0x315e, 0x1b }, - { 0x3164, 0x1b }, - { 0x3444, 0x40 }, - { 0x3445, 0x4a }, - { 0x3480, 0x92 }, -}; - -static const struct imx290_regval imx290_1080p_common_settings[] = { +static const struct imx290_regval imx290_1080p_settings[] = { /* mode settings */ - { IMX290_FR_FDG_SEL, 0x01 }, { 0x3007, 0x00 }, { 0x303a, 0x0c }, { 0x3414, 0x0a }, @@ -258,36 +182,15 @@ static const struct imx290_regval imx290 { 0x3419, 0x04 }, { 0x3012, 0x64 }, { 0x3013, 0x00 }, -}; - -static const struct imx290_regval imx290_1080p_2lane_settings[] = { - { 0x3405, 0x00 }, + { 0x305c, 0x18 }, + { 0x305d, 0x03 }, + { 0x305e, 0x20 }, + { 0x305f, 0x01 }, + { 0x315e, 0x1a }, + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, /* data rate settings */ - { IMX290_PHY_LANE_NUM, 0x01 }, - { IMX290_CSI_LANE_MODE, 0x01 }, - { 0x3446, 0x77 }, - { 0x3447, 0x00 }, - { 0x3448, 0x67 }, - { 0x3449, 0x00 }, - { 0x344a, 0x47 }, - { 0x344b, 0x00 }, - { 0x344c, 0x37 }, - { 0x344d, 0x00 }, - { 0x344e, 0x3f }, - { 0x344f, 0x00 }, - { 0x3450, 0xff }, - { 0x3451, 0x00 }, - { 0x3452, 0x3f }, - { 0x3453, 0x00 }, - { 0x3454, 0x37 }, - { 0x3455, 0x00 }, -}; - -static const struct imx290_regval imx290_1080p_4lane_settings[] = { { 0x3405, 0x10 }, - /* data rate settings */ - { IMX290_PHY_LANE_NUM, 0x03 }, - { IMX290_CSI_LANE_MODE, 0x03 }, { 0x3446, 0x57 }, { 0x3447, 0x00 }, { 0x3448, 0x37 }, @@ -306,33 +209,8 @@ static const struct imx290_regval imx290 { 0x3455, 0x00 }, }; -static const struct imx290_regval imx290_37_125mhz_clock_720p[] = { - { 0x305c, 0x20 }, - { 0x305d, 0x00 }, - { 0x305e, 0x20 }, - { 0x305f, 0x01 }, - { 0x315e, 0x1a }, - { 0x3164, 0x1a }, - { 0x3444, 0x20 }, - { 0x3445, 0x25 }, - { 0x3480, 0x49 }, -}; - -static const struct imx290_regval imx290_74_250mhz_clock_720p[] = { - { 0x305c, 0x10 }, - { 0x305d, 0x00 }, - { 0x305e, 0x10 }, - { 0x305f, 0x01 }, - { 0x315e, 0x1b }, - { 0x3164, 0x1b }, - { 0x3444, 0x40 }, - { 0x3445, 0x4a }, - { 0x3480, 0x92 }, -}; - -static const struct imx290_regval imx290_720p_common_settings[] = { +static const struct imx290_regval imx290_720p_settings[] = { /* mode settings */ - { IMX290_FR_FDG_SEL, 0x01 }, { 0x3007, 0x10 }, { 0x303a, 0x06 }, { 0x3414, 0x04 }, @@ -342,36 +220,15 @@ static const struct imx290_regval imx290 { 0x3419, 0x02 }, { 0x3012, 0x64 }, { 0x3013, 0x00 }, -}; - -static const struct imx290_regval imx290_720p_2lane_settings[] = { - { 0x3405, 0x00 }, - { IMX290_PHY_LANE_NUM, 0x01 }, - { IMX290_CSI_LANE_MODE, 0x01 }, + { 0x305c, 0x20 }, + { 0x305d, 0x00 }, + { 0x305e, 0x20 }, + { 0x305f, 0x01 }, + { 0x315e, 0x1a }, + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, /* data rate settings */ - { 0x3446, 0x67 }, - { 0x3447, 0x00 }, - { 0x3448, 0x57 }, - { 0x3449, 0x00 }, - { 0x344a, 0x2f }, - { 0x344b, 0x00 }, - { 0x344c, 0x27 }, - { 0x344d, 0x00 }, - { 0x344e, 0x2f }, - { 0x344f, 0x00 }, - { 0x3450, 0xbf }, - { 0x3451, 0x00 }, - { 0x3452, 0x2f }, - { 0x3453, 0x00 }, - { 0x3454, 0x27 }, - { 0x3455, 0x00 }, -}; - -static const struct imx290_regval imx290_720p_4lane_settings[] = { { 0x3405, 0x10 }, - { IMX290_PHY_LANE_NUM, 0x03 }, - { IMX290_CSI_LANE_MODE, 0x03 }, - /* data rate settings */ { 0x3446, 0x4f }, { 0x3447, 0x00 }, { 0x3448, 0x2f }, @@ -451,46 +308,18 @@ static const struct imx290_mode imx290_m { .width = 1920, .height = 1080, - .hmax = 0x0898, - .vmax = 0x0465, + .hmax = 0x1130, .link_freq_index = FREQ_INDEX_1080P, - .crop = { - .left = 4 + 8, - .top = 12 + 8, - .width = 1920, - .height = 1080, - }, - .mode_data = imx290_1080p_common_settings, - .mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings), - .lane_data = imx290_1080p_2lane_settings, - .lane_data_size = ARRAY_SIZE(imx290_1080p_2lane_settings), - .clk_data = { - [CLK_37_125] = imx290_37_125mhz_clock_1080p, - [CLK_74_25] = imx290_74_250mhz_clock_1080p, - }, - .clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p), + .data = imx290_1080p_settings, + .data_size = ARRAY_SIZE(imx290_1080p_settings), }, { .width = 1280, .height = 720, - .hmax = 0x0ce4, - .vmax = 0x02ee, + .hmax = 0x19c8, .link_freq_index = FREQ_INDEX_720P, - .crop = { - .left = 4 + 8 + 320, - .top = 12 + 8 + 180, - .width = 1280, - .height = 720, - }, - .mode_data = imx290_720p_common_settings, - .mode_data_size = ARRAY_SIZE(imx290_720p_common_settings), - .lane_data = imx290_720p_2lane_settings, - .lane_data_size = ARRAY_SIZE(imx290_720p_2lane_settings), - .clk_data = { - [CLK_37_125] = imx290_37_125mhz_clock_720p, - [CLK_74_25] = imx290_74_250mhz_clock_720p, - }, - .clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p), + .data = imx290_720p_settings, + .data_size = ARRAY_SIZE(imx290_720p_settings), }, }; @@ -499,45 +328,17 @@ static const struct imx290_mode imx290_m .width = 1920, .height = 1080, .hmax = 0x0898, - .vmax = 0x0465, .link_freq_index = FREQ_INDEX_1080P, - .crop = { - .left = 4 + 8, - .top = 12 + 8, - .width = 1920, - .height = 1080, - }, - .mode_data = imx290_1080p_common_settings, - .mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings), - .lane_data = imx290_1080p_4lane_settings, - .lane_data_size = ARRAY_SIZE(imx290_1080p_4lane_settings), - .clk_data = { - [CLK_37_125] = imx290_37_125mhz_clock_1080p, - [CLK_74_25] = imx290_74_250mhz_clock_1080p, - }, - .clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p), + .data = imx290_1080p_settings, + .data_size = ARRAY_SIZE(imx290_1080p_settings), }, { .width = 1280, .height = 720, .hmax = 0x0ce4, - .vmax = 0x02ee, .link_freq_index = FREQ_INDEX_720P, - .crop = { - .left = 4 + 8 + 320, - .top = 12 + 8 + 180, - .width = 1280, - .height = 720, - }, - .mode_data = imx290_720p_common_settings, - .mode_data_size = ARRAY_SIZE(imx290_720p_common_settings), - .lane_data = imx290_720p_4lane_settings, - .lane_data_size = ARRAY_SIZE(imx290_720p_4lane_settings), - .clk_data = { - [CLK_37_125] = imx290_37_125mhz_clock_720p, - [CLK_74_25] = imx290_74_250mhz_clock_720p, - }, - .clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p), + .data = imx290_720p_settings, + .data_size = ARRAY_SIZE(imx290_720p_settings), }, }; @@ -651,53 +452,6 @@ static int imx290_set_gain(struct imx290 return ret; } -static int imx290_set_exposure(struct imx290 *imx290, u32 value) -{ - u32 exposure = (imx290->current_mode->height + imx290->vblank->val) - - value - 1; - int ret; - - ret = imx290_write_buffered_reg(imx290, IMX290_EXPOSURE_LOW, 3, - exposure); - if (ret) - dev_err(imx290->dev, "Unable to write exposure\n"); - - return ret; -} - -static int imx290_set_hmax(struct imx290 *imx290, u32 val) -{ - u32 hmax = val + imx290->current_mode->width; - int ret; - - ret = imx290_write_buffered_reg(imx290, IMX290_HMAX_LOW, 2, - hmax); - if (ret) - dev_err(imx290->dev, "Error setting HMAX register\n"); - - return ret; -} - -static int imx290_set_vmax(struct imx290 *imx290, u32 val) -{ - u32 vmax = val + imx290->current_mode->height; - int ret; - - ret = imx290_write_buffered_reg(imx290, IMX290_VMAX_LOW, 3, - vmax); - if (ret) - dev_err(imx290->dev, "Unable to write vmax\n"); - - /* - * Becuse of the way exposure works for this sensor, updating - * vblank causes the effective exposure to change, so we must - * set it back to the "new" correct value. - */ - imx290_set_exposure(imx290, imx290->exposure->val); - - return ret; -} - /* Stop streaming */ static int imx290_stop_streaming(struct imx290 *imx290) { @@ -717,50 +471,15 @@ static int imx290_set_ctrl(struct v4l2_c struct imx290 *imx290 = container_of(ctrl->handler, struct imx290, ctrls); int ret = 0; - u8 val; - - if (ctrl->id == V4L2_CID_VBLANK) { - u32 vmax = ctrl->val + imx290->current_mode->height; - - /* - * Changing vblank changes the allowed range for exposure. - * We don't supply the current exposure as default here as it - * may lie outside the new range. We will reset it just below. - */ - __v4l2_ctrl_modify_range(imx290->exposure, - IMX290_EXPOSURE_MIN, - vmax - 2, - IMX290_EXPOSURE_STEP, - vmax - 2); - } /* V4L2 controls values will be applied only when power is already up */ if (!pm_runtime_get_if_in_use(imx290->dev)) return 0; switch (ctrl->id) { - case V4L2_CID_ANALOGUE_GAIN: + case V4L2_CID_GAIN: ret = imx290_set_gain(imx290, ctrl->val); break; - case V4L2_CID_EXPOSURE: - ret = imx290_set_exposure(imx290, ctrl->val); - break; - case V4L2_CID_HBLANK: - ret = imx290_set_hmax(imx290, ctrl->val); - break; - case V4L2_CID_VBLANK: - ret = imx290_set_vmax(imx290, ctrl->val); - break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* WINMODE is in bits [6:4], so need to read-modify-write */ - ret = imx290_read_reg(imx290, IMX290_FLIP_WINMODE, &val); - if (ret) - break; - val &= ~0x03; - val |= imx290->vflip->val | (imx290->hflip->val << 1); - ret = imx290_write_reg(imx290, IMX290_FLIP_WINMODE, val); - break; case V4L2_CID_TEST_PATTERN: if (ctrl->val) { imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00); @@ -800,12 +519,10 @@ static int imx290_enum_mbus_code(struct struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - const struct imx290 *imx290 = to_imx290(sd); - - if (code->index >= IMX290_NUM_FORMATS) + if (code->index >= ARRAY_SIZE(imx290_formats)) return -EINVAL; - code->code = imx290->formats[code->index].code; + code->code = imx290_formats[code->index].code; return 0; } @@ -817,8 +534,8 @@ static int imx290_enum_frame_size(struct const struct imx290 *imx290 = to_imx290(sd); const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); - if (fse->code != imx290->formats[0].code && - fse->code != imx290->formats[1].code) + if ((fse->code != imx290_formats[0].code) && + (fse->code != imx290_formats[1].code)) return -EINVAL; if (fse->index >= imx290_modes_num(imx290)) @@ -859,9 +576,23 @@ static inline u8 imx290_get_link_freq_in return imx290->current_mode->link_freq_index; } +static s64 imx290_get_link_freq(struct imx290 *imx290) +{ + u8 index = imx290_get_link_freq_index(imx290); + + return *(imx290_link_freqs_ptr(imx290) + index); +} + static u64 imx290_calc_pixel_rate(struct imx290 *imx290) { - return 148500000; + s64 link_freq = imx290_get_link_freq(imx290); + u8 nlanes = imx290->nlanes; + u64 pixel_rate; + + /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = link_freq * 2 * nlanes; + do_div(pixel_rate, imx290->bpp); + return pixel_rate; } static int imx290_set_fmt(struct v4l2_subdev *sd, @@ -882,30 +613,22 @@ static int imx290_set_fmt(struct v4l2_su fmt->format.width = mode->width; fmt->format.height = mode->height; - for (i = 0; i < IMX290_NUM_FORMATS; i++) - if (imx290->formats[i].code == fmt->format.code) + for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) + if (imx290_formats[i].code == fmt->format.code) break; - if (i >= IMX290_NUM_FORMATS) + if (i >= ARRAY_SIZE(imx290_formats)) i = 0; - fmt->format.code = imx290->formats[i].code; + fmt->format.code = imx290_formats[i].code; fmt->format.field = V4L2_FIELD_NONE; - fmt->format.colorspace = V4L2_COLORSPACE_RAW; - fmt->format.ycbcr_enc = - V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); - fmt->format.quantization = - V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->format.colorspace, - fmt->format.ycbcr_enc); - fmt->format.xfer_func = - V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { format = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); } else { format = &imx290->current_format; imx290->current_mode = mode; - imx290->bpp = imx290->formats[i].bpp; + imx290->bpp = imx290_formats[i].bpp; if (imx290->link_freq) __v4l2_ctrl_s_ctrl(imx290->link_freq, @@ -913,18 +636,6 @@ static int imx290_set_fmt(struct v4l2_su if (imx290->pixel_rate) __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, imx290_calc_pixel_rate(imx290)); - - if (imx290->hblank) - __v4l2_ctrl_modify_range(imx290->hblank, - mode->hmax - mode->width, - IMX290_HMAX_MAX - mode->width, - 1, mode->hmax - mode->width); - if (imx290->vblank) - __v4l2_ctrl_modify_range(imx290->vblank, - mode->vmax - mode->height, - IMX290_VMAX_MAX - mode->height, - 1, - mode->vmax - mode->height); } *format = fmt->format; @@ -954,7 +665,6 @@ static int imx290_write_current_format(s switch (imx290->current_format.code) { case MEDIA_BUS_FMT_SRGGB10_1X10: - case MEDIA_BUS_FMT_Y10_1X10: ret = imx290_set_register_array(imx290, imx290_10bit_settings, ARRAY_SIZE( imx290_10bit_settings)); @@ -964,7 +674,6 @@ static int imx290_write_current_format(s } break; case MEDIA_BUS_FMT_SRGGB12_1X12: - case MEDIA_BUS_FMT_Y12_1X12: ret = imx290_set_register_array(imx290, imx290_12bit_settings, ARRAY_SIZE( imx290_12bit_settings)); @@ -981,63 +690,28 @@ static int imx290_write_current_format(s return 0; } -static const struct v4l2_rect * -__imx290_get_pad_crop(struct imx290 *imx290, - struct v4l2_subdev_state *sd_state, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&imx290->sd, sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &imx290->current_mode->crop; - } - - return NULL; -} - -static int imx290_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) +static int imx290_set_hmax(struct imx290 *imx290, u32 val) { - switch (sel->target) { - case V4L2_SEL_TGT_CROP: { - struct imx290 *imx290 = to_imx290(sd); - - mutex_lock(&imx290->lock); - sel->r = *__imx290_get_pad_crop(imx290, sd_state, sel->pad, - sel->which); - mutex_unlock(&imx290->lock); + int ret; - return 0; + ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff)); + if (ret) { + dev_err(imx290->dev, "Error setting HMAX register\n"); + return ret; } - case V4L2_SEL_TGT_NATIVE_SIZE: - sel->r.top = 0; - sel->r.left = 0; - sel->r.width = IMX290_NATIVE_WIDTH; - sel->r.height = IMX290_NATIVE_HEIGHT; - - return 0; - - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = IMX290_PIXEL_ARRAY_TOP; - sel->r.left = IMX290_PIXEL_ARRAY_LEFT; - sel->r.width = IMX290_PIXEL_ARRAY_WIDTH; - sel->r.height = IMX290_PIXEL_ARRAY_HEIGHT; - - return 0; + ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff)); + if (ret) { + dev_err(imx290->dev, "Error setting HMAX register\n"); + return ret; } - return -EINVAL; + return 0; } /* Start streaming */ static int imx290_start_streaming(struct imx290 *imx290) { - enum imx290_clk_index clk_idx = imx290->xclk_freq == 37125000 ? - CLK_37_125 : CLK_74_25; int ret; /* Set init register settings */ @@ -1049,14 +723,6 @@ static int imx290_start_streaming(struct return ret; } - ret = imx290_set_register_array(imx290, - imx290->current_mode->clk_data[clk_idx], - imx290->current_mode->clk_size); - if (ret < 0) { - dev_err(imx290->dev, "Could not set clock registers\n"); - return ret; - } - /* Apply the register values related to current frame format */ ret = imx290_write_current_format(imx290); if (ret < 0) { @@ -1065,22 +731,15 @@ static int imx290_start_streaming(struct } /* Apply default values of current mode */ - ret = imx290_set_register_array(imx290, - imx290->current_mode->mode_data, - imx290->current_mode->mode_data_size); + ret = imx290_set_register_array(imx290, imx290->current_mode->data, + imx290->current_mode->data_size); if (ret < 0) { dev_err(imx290->dev, "Could not set current mode\n"); return ret; } - - /* Apply lane config registers of current mode */ - ret = imx290_set_register_array(imx290, - imx290->current_mode->lane_data, - imx290->current_mode->lane_data_size); - if (ret < 0) { - dev_err(imx290->dev, "Could not set current mode\n"); + ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); + if (ret < 0) return ret; - } /* Apply customized values from user */ ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); @@ -1119,9 +778,6 @@ static int imx290_set_stream(struct v4l2 imx290_stop_streaming(imx290); pm_runtime_put(imx290->dev); } - /* vflip and hflip cannot change during streaming */ - __v4l2_ctrl_grab(imx290->vflip, enable); - __v4l2_ctrl_grab(imx290->hflip, enable); unlock_and_return: @@ -1139,6 +795,49 @@ static int imx290_get_regulators(struct imx290->supplies); } +static int imx290_set_data_lanes(struct imx290 *imx290) +{ + int ret = 0, laneval, frsel; + + switch (imx290->nlanes) { + case 2: + laneval = 0x01; + frsel = 0x02; + break; + case 4: + laneval = 0x03; + frsel = 0x01; + break; + default: + /* + * We should never hit this since the data lane count is + * validated in probe itself + */ + dev_err(imx290->dev, "Lane configuration not supported\n"); + ret = -EINVAL; + goto exit; + } + + ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval); + if (ret) { + dev_err(imx290->dev, "Error setting Physical Lane number register\n"); + goto exit; + } + + ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval); + if (ret) { + dev_err(imx290->dev, "Error setting CSI Lane mode register\n"); + goto exit; + } + + ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel); + if (ret) + dev_err(imx290->dev, "Error setting FR/FDG SEL register\n"); + +exit: + return ret; +} + static int imx290_power_on(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); @@ -1162,6 +861,9 @@ static int imx290_power_on(struct device gpiod_set_value_cansleep(imx290->rst_gpio, 0); usleep_range(30000, 31000); + /* Set data lane count */ + imx290_set_data_lanes(imx290); + return 0; } @@ -1191,7 +893,6 @@ static const struct v4l2_subdev_pad_ops .enum_frame_size = imx290_enum_frame_size, .get_fmt = imx290_get_fmt, .set_fmt = imx290_set_fmt, - .get_selection = imx290_get_selection, }; static const struct v4l2_subdev_ops imx290_subdev_ops = { @@ -1225,35 +926,16 @@ static s64 imx290_check_link_freqs(const return 0; } -static const struct of_device_id imx290_of_match[] = { - /* - * imx327 supports 1080p60 at 10 and 12bit. - * imx290 adds 10bit 1080p120. - * imx462 adds 10 and 12bit 1080p120. - * This driver currently maxes out at 1080p60, which is supported by all - * of them, but add the compatible strings for future implementation. - */ - { .compatible = "sony,imx327", .data = imx290_colour_formats }, - { .compatible = "sony,imx327-mono", .data = imx290_mono_formats }, - { .compatible = "sony,imx290", .data = imx290_colour_formats }, - { .compatible = "sony,imx290-mono", .data = imx290_mono_formats }, - { .compatible = "sony,imx462", .data = imx290_colour_formats }, - { .compatible = "sony,imx462-mono", .data = imx290_mono_formats }, - { /* sentinel */ } -}; - static int imx290_probe(struct i2c_client *client) { - struct v4l2_fwnode_device_properties props; struct device *dev = &client->dev; struct fwnode_handle *endpoint; /* Only CSI2 is supported for now: */ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - const struct of_device_id *match; - const struct imx290_mode *mode; struct imx290 *imx290; + u32 xclk_freq; s64 fq; int ret; @@ -1268,11 +950,6 @@ static int imx290_probe(struct i2c_clien return -ENODEV; } - match = of_match_device(imx290_of_match, dev); - if (!match) - return -ENODEV; - imx290->formats = (const struct imx290_pixfmt *)match->data; - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); if (!endpoint) { dev_err(dev, "Endpoint node not found\n"); @@ -1322,21 +999,21 @@ static int imx290_probe(struct i2c_clien } ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &imx290->xclk_freq); + &xclk_freq); if (ret) { dev_err(dev, "Could not get xclk frequency\n"); goto free_err; } /* external clock must be 37.125 MHz */ - if (imx290->xclk_freq != 37125000 && imx290->xclk_freq != 74250000) { + if (xclk_freq != 37125000) { dev_err(dev, "External clock frequency %u is not supported\n", - imx290->xclk_freq); + xclk_freq); ret = -EINVAL; goto free_err; } - ret = clk_set_rate(imx290->xclk, imx290->xclk_freq); + ret = clk_set_rate(imx290->xclk, xclk_freq); if (ret) { dev_err(dev, "Could not set xclk frequency\n"); goto free_err; @@ -1360,39 +1037,15 @@ static int imx290_probe(struct i2c_clien /* * Initialize the frame format. In particular, imx290->current_mode - * and imx290->bpp are set to defaults. + * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call + * below relies on these fields. */ imx290_entity_init_cfg(&imx290->sd, NULL); - v4l2_ctrl_handler_init(&imx290->ctrls, 11); + v4l2_ctrl_handler_init(&imx290->ctrls, 4); v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); - - mode = imx290->current_mode; - imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_HBLANK, - mode->hmax - mode->width, - IMX290_HMAX_MAX - mode->width, 1, - mode->hmax - mode->width); - - imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_VBLANK, - mode->vmax - mode->height, - IMX290_VMAX_MAX - mode->height, 1, - mode->vmax - mode->height); - - imx290->exposure = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_EXPOSURE, - IMX290_EXPOSURE_MIN, - mode->vmax - 2, - IMX290_EXPOSURE_STEP, - mode->vmax - 2); - - imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); + V4L2_CID_GAIN, 0, 72, 1, 0); imx290->link_freq = v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, @@ -1412,15 +1065,6 @@ static int imx290_probe(struct i2c_clien ARRAY_SIZE(imx290_test_pattern_menu) - 1, 0, 0, imx290_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); - if (ret) - goto free_ctrl; - - ret = v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, - &props); - if (ret) - goto free_ctrl; - imx290->sd.ctrl_handler = &imx290->ctrls; if (imx290->ctrls.error) { @@ -1443,9 +1087,6 @@ static int imx290_probe(struct i2c_clien goto free_ctrl; } - /* Initialize the frame format (this also sets imx290->current_mode) */ - imx290_entity_init_cfg(&imx290->sd, NULL); - ret = v4l2_async_register_subdev(&imx290->sd); if (ret < 0) { dev_err(dev, "Could not register v4l2 device\n"); @@ -1495,6 +1136,10 @@ static void imx290_remove(struct i2c_cli pm_runtime_set_suspended(imx290->dev); } +static const struct of_device_id imx290_of_match[] = { + { .compatible = "sony,imx290" }, + { /* sentinel */ } +}; MODULE_DEVICE_TABLE(of, imx290_of_match); static struct i2c_driver imx290_i2c_driver = {