From abade3bf45fd09cecec2af9833aeef7fca8e35ba Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Thu, 6 Apr 2023 10:14:05 +0200 Subject: [PATCH] media: i2c: ov5640: put back driver as of linux v5.15-stm32mp-r2 This is straight copy of the ov5640.c file found within linux v5.15-stm32mp-r2-rc6-1 with the unique modification below in order to make the remove function returning void (and remove the return 0) -static int ov5640_remove(struct i2c_client *client) +static void ov5640_remove(struct i2c_client *client) Signed-off-by: Alain Volmat Change-Id: I496dcbe3f926102ed838dbca63036393b68352e6 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/linux-stm32/+/299307 Tested-by: Eric FOURMONT Reviewed-by: Eric FOURMONT Domain-Review: Eric FOURMONT --- drivers/media/i2c/ov5640.c | 1969 +++++++++++++----------------------- 1 file changed, 712 insertions(+), 1257 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 267f514023e7..311fd9a10055 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -30,27 +29,13 @@ #define OV5640_XCLK_MIN 6000000 #define OV5640_XCLK_MAX 54000000 -#define OV5640_NATIVE_WIDTH 2624 -#define OV5640_NATIVE_HEIGHT 1964 -#define OV5640_PIXEL_ARRAY_TOP 14 -#define OV5640_PIXEL_ARRAY_LEFT 16 -#define OV5640_PIXEL_ARRAY_WIDTH 2592 -#define OV5640_PIXEL_ARRAY_HEIGHT 1944 - -/* FIXME: not documented. */ -#define OV5640_MIN_VBLANK 24 -#define OV5640_MAX_VTS 3375 - #define OV5640_DEFAULT_SLAVE_ID 0x3c -#define OV5640_LINK_RATE_MAX 490000000U - #define OV5640_REG_SYS_RESET02 0x3002 #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 #define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 -#define OV5640_REG_SYS_CTRL0_SW_RST 0x82 #define OV5640_REG_CHIP_ID 0x300a #define OV5640_REG_IO_MIPI_CTRL00 0x300e #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 @@ -74,18 +59,13 @@ #define OV5640_REG_AEC_PK_MANUAL 0x3503 #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a #define OV5640_REG_AEC_PK_VTS 0x350c -#define OV5640_REG_TIMING_HS 0x3800 -#define OV5640_REG_TIMING_VS 0x3802 -#define OV5640_REG_TIMING_HW 0x3804 -#define OV5640_REG_TIMING_VH 0x3806 #define OV5640_REG_TIMING_DVPHO 0x3808 #define OV5640_REG_TIMING_DVPVO 0x380a #define OV5640_REG_TIMING_HTS 0x380c #define OV5640_REG_TIMING_VTS 0x380e -#define OV5640_REG_TIMING_HOFFS 0x3810 -#define OV5640_REG_TIMING_VOFFS 0x3812 #define OV5640_REG_TIMING_TC_REG20 0x3820 #define OV5640_REG_TIMING_TC_REG21 0x3821 +#define OV5640_REG_DVP_PCLK_DIVIDER 0x3824 #define OV5640_REG_AEC_CTRL00 0x3a00 #define OV5640_REG_AEC_B50_STEP 0x3a08 #define OV5640_REG_AEC_B60_STEP 0x3a0a @@ -133,54 +113,14 @@ enum ov5640_mode_id { OV5640_NUM_MODES, }; +#define OV5640_DEFAULT_MODE OV5640_MODE_VGA_640_480 + enum ov5640_frame_rate { OV5640_15_FPS = 0, OV5640_30_FPS, - OV5640_60_FPS, OV5640_NUM_FRAMERATES, }; -enum ov5640_pixel_rate_id { - OV5640_PIXEL_RATE_168M, - OV5640_PIXEL_RATE_148M, - OV5640_PIXEL_RATE_124M, - OV5640_PIXEL_RATE_96M, - OV5640_PIXEL_RATE_48M, - OV5640_NUM_PIXEL_RATES, -}; - -/* - * The chip manual suggests 24/48/96/192 MHz pixel clocks. - * - * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for - * full resolution mode @15 FPS. - */ -static const u32 ov5640_pixel_rates[] = { - [OV5640_PIXEL_RATE_168M] = 168000000, - [OV5640_PIXEL_RATE_148M] = 148000000, - [OV5640_PIXEL_RATE_124M] = 124000000, - [OV5640_PIXEL_RATE_96M] = 96000000, - [OV5640_PIXEL_RATE_48M] = 48000000, -}; - -/* - * MIPI CSI-2 link frequencies. - * - * Derived from the above defined pixel rate for bpp = (8, 16, 24) and - * data_lanes = (1, 2) - * - * link_freq = (pixel_rate * bpp) / (2 * data_lanes) - */ -static const s64 ov5640_csi2_link_freqs[] = { - 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, - 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, - 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, - 248000000, 192000000, 192000000, 192000000, 96000000, -}; - -/* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ -#define OV5640_DEFAULT_LINK_FREQ 13 - enum ov5640_format_mux { OV5640_FMT_MUX_YUV422 = 0, OV5640_FMT_MUX_RGB, @@ -193,146 +133,34 @@ enum ov5640_format_mux { struct ov5640_pixfmt { u32 code; u32 colorspace; - u8 bpp; - u8 ctrl00; - enum ov5640_format_mux mux; }; -static const struct ov5640_pixfmt ov5640_dvp_formats[] = { - { - /* YUV422, YUYV */ - .code = MEDIA_BUS_FMT_JPEG_1X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .bpp = 16, - .ctrl00 = 0x30, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* YUV422, UYVY */ - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x3f, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* YUV422, YUYV */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x30, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x6f, - .mux = OV5640_FMT_MUX_RGB, - }, { - /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ - .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x61, - .mux = OV5640_FMT_MUX_RGB, - }, { - /* Raw, BGBG... / GRGR... */ - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x00, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, GBGB... / RGRG... */ - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x01, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, GRGR... / BGBG... */ - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x02, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, RGRG... / GBGB... */ - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x03, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, - { /* sentinel */ } +static const struct ov5640_pixfmt ov5640_formats[] = { + { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, }; -static const struct ov5640_pixfmt ov5640_csi2_formats[] = { - { - /* YUV422, YUYV */ - .code = MEDIA_BUS_FMT_JPEG_1X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .bpp = 16, - .ctrl00 = 0x30, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* YUV422, UYVY */ - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x3f, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* YUV422, YUYV */ - .code = MEDIA_BUS_FMT_YUYV8_1X16, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x30, - .mux = OV5640_FMT_MUX_YUV422, - }, { - /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ - .code = MEDIA_BUS_FMT_RGB565_1X16, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 16, - .ctrl00 = 0x6f, - .mux = OV5640_FMT_MUX_RGB, - }, { - /* BGR888: RGB */ - .code = MEDIA_BUS_FMT_BGR888_1X24, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 24, - .ctrl00 = 0x23, - .mux = OV5640_FMT_MUX_RGB, - }, { - /* Raw, BGBG... / GRGR... */ - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x00, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, GBGB... / RGRG... */ - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x01, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, GRGR... / BGBG... */ - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x02, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, { - /* Raw bayer, RGRG... / GBGB... */ - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .bpp = 8, - .ctrl00 = 0x03, - .mux = OV5640_FMT_MUX_RAW_DPC, - }, - { /* sentinel */ } +static const s64 ov5640_link_freqs[] = { + 63136800, /* 1280x720@15 */ + 83954880, /* 176x144@15, 320x240@15, 720x480@15 */ + 92145600, /* 640x480@15, 1024x768@15 */ + 126273600, /* 1280x720@30 */ + 167909760, /* 176x144@30, 320x240@30, 720x480@30 */ + 184291200, /* 640x480@30, 1024x768@30 */ + 191116800, /* 1920x1080@15 */ + 335819520, /* 2592x1944@15 */ + 382233600, /* 1920x1080@30 */ }; +#define OV5640_LINK_FREQS_NUM ARRAY_SIZE(ov5640_link_freqs) /* * FIXME: remove this when a subdev API becomes available @@ -346,7 +174,6 @@ MODULE_PARM_DESC(virtual_channel, static const int ov5640_framerates[] = { [OV5640_15_FPS] = 15, [OV5640_30_FPS] = 30, - [OV5640_60_FPS] = 60, }; /* regulator supplies */ @@ -374,42 +201,21 @@ struct reg_value { u32 delay_ms; }; -struct ov5640_timings { - /* Analog crop rectangle. */ - struct v4l2_rect analog_crop; - /* Visibile crop: from analog crop top-left corner. */ - struct v4l2_rect crop; - /* Total pixels per line: width + fixed hblank. */ - u32 htot; - /* Default vertical blanking: frame height = height + vblank. */ - u32 vblank_def; -}; - struct ov5640_mode_info { enum ov5640_mode_id id; enum ov5640_downsize_mode dn_mode; - enum ov5640_pixel_rate_id pixel_rate; - - unsigned int width; - unsigned int height; - - struct ov5640_timings dvp_timings; - struct ov5640_timings csi2_timings; - + u32 hact; + u32 htot; + u32 vact; + u32 vtot; const struct reg_value *reg_data; u32 reg_data_size; - - /* Used by s_frame_interval only. */ u32 max_fps; - u32 def_fps; }; struct ov5640_ctrls { struct v4l2_ctrl_handler handler; struct v4l2_ctrl *pixel_rate; - struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *vblank; struct { struct v4l2_ctrl *auto_exp; struct v4l2_ctrl *exposure; @@ -431,6 +237,7 @@ struct ov5640_ctrls { struct v4l2_ctrl *test_pattern; struct v4l2_ctrl *hflip; struct v4l2_ctrl *vflip; + struct v4l2_ctrl *link_freq; }; struct ov5640_dev { @@ -449,6 +256,8 @@ struct ov5640_dev { /* lock to protect all members below */ struct mutex lock; + int power_count; + struct v4l2_mbus_framefmt fmt; bool pending_fmt_change; @@ -456,7 +265,6 @@ struct ov5640_dev { const struct ov5640_mode_info *last_mode; enum ov5640_frame_rate current_fr; struct v4l2_fract frame_interval; - s64 current_link_freq; struct ov5640_ctrls ctrls; @@ -478,40 +286,6 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) ctrls.handler)->sd; } -static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) -{ - return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; -} - -static inline const struct ov5640_pixfmt * -ov5640_formats(struct ov5640_dev *sensor) -{ - return ov5640_is_csi2(sensor) ? ov5640_csi2_formats - : ov5640_dvp_formats; -} - -static const struct ov5640_pixfmt * -ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code) -{ - const struct ov5640_pixfmt *formats = ov5640_formats(sensor); - unsigned int i; - - for (i = 0; formats[i].code; ++i) { - if (formats[i].code == code) - return &formats[i]; - } - - return &formats[0]; -} - -static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) -{ - const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor, - code); - - return format->bpp; -} - /* * FIXME: all of these register tables are likely filled with * entries that set the register to their power-on default values, @@ -520,20 +294,8 @@ static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) * over i2c. */ /* YUV422 UYVY VGA@30fps */ - -static const struct v4l2_mbus_framefmt ov5640_default_fmt = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .width = 640, - .height = 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), - .quantization = V4L2_QUANTIZATION_FULL_RANGE, - .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), - .field = V4L2_FIELD_NONE, -}; - -static const struct reg_value ov5640_init_setting[] = { - {0x3103, 0x11, 0, 0}, +static const struct reg_value ov5640_init_setting_30fps_VGA[] = { + {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, @@ -548,7 +310,11 @@ static const struct reg_value ov5640_init_setting[] = { {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -612,11 +378,124 @@ static const struct reg_value ov5640_init_setting[] = { {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, }; -static const struct reg_value ov5640_setting_low_res[] = { +static const struct reg_value ov5640_setting_VGA_640_480[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, + {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_QQVGA_160_120[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static const struct reg_value ov5640_setting_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -630,38 +509,47 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = { {0x3c07, 0x07, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, - {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, }; static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x4407, 0x04, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, - {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, {0x4005, 0x1a, 0, 0}, }; @@ -669,473 +557,152 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, + {0x4407, 0x04, 0, 0}, + {0x5001, 0x83, 0, 70}, }; -static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { - { - /* 160x120 */ - .id = OV5640_MODE_QQVGA_160_120, - .dn_mode = SUBSAMPLING, - .pixel_rate = OV5640_PIXEL_RATE_48M, - .width = 160, - .height = 120, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 16, - .top = 6, - .width = 160, - .height = 120, - }, - .htot = 1896, - .vblank_def = 864, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - /* Maintain a minimum processing margin. */ - .crop = { - .left = 2, - .top = 4, - .width = 160, - .height = 120, - }, - .htot = 1600, - .vblank_def = 878, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 176x144 */ - .id = OV5640_MODE_QCIF_176_144, - .dn_mode = SUBSAMPLING, - .pixel_rate = OV5640_PIXEL_RATE_48M, - .width = 176, - .height = 144, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 16, - .top = 6, - .width = 176, - .height = 144, - }, - .htot = 1896, - .vblank_def = 840, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - /* Maintain a minimum processing margin. */ - .crop = { - .left = 2, - .top = 4, - .width = 176, - .height = 144, - }, - .htot = 1600, - .vblank_def = 854, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 320x240 */ - .id = OV5640_MODE_QVGA_320_240, - .dn_mode = SUBSAMPLING, - .width = 320, - .height = 240, - .pixel_rate = OV5640_PIXEL_RATE_48M, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 16, - .top = 6, - .width = 320, - .height = 240, - }, - .htot = 1896, - .vblank_def = 744, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - /* Maintain a minimum processing margin. */ - .crop = { - .left = 2, - .top = 4, - .width = 320, - .height = 240, - }, - .htot = 1600, - .vblank_def = 760, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 640x480 */ - .id = OV5640_MODE_VGA_640_480, - .dn_mode = SUBSAMPLING, - .pixel_rate = OV5640_PIXEL_RATE_48M, - .width = 640, - .height = 480, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 16, - .top = 6, - .width = 640, - .height = 480, - }, - .htot = 1896, - .vblank_def = 600, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - /* Maintain a minimum processing margin. */ - .crop = { - .left = 2, - .top = 4, - .width = 640, - .height = 480, - }, - .htot = 1600, - .vblank_def = 520, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_60_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 720x480 */ - .id = OV5640_MODE_NTSC_720_480, - .dn_mode = SUBSAMPLING, - .width = 720, - .height = 480, - .pixel_rate = OV5640_PIXEL_RATE_96M, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 56, - .top = 60, - .width = 720, - .height = 480, - }, - .htot = 1896, - .vblank_def = 504, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - .crop = { - .left = 56, - .top = 60, - .width = 720, - .height = 480, - }, - .htot = 1896, - .vblank_def = 1206, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 720x576 */ - .id = OV5640_MODE_PAL_720_576, - .dn_mode = SUBSAMPLING, - .width = 720, - .height = 576, - .pixel_rate = OV5640_PIXEL_RATE_96M, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 56, - .top = 6, - .width = 720, - .height = 576, - }, - .htot = 1896, - .vblank_def = 408, - }, - .csi2_timings = { - /* Feed the full valid pixel array to the ISP. */ - .analog_crop = { - .left = OV5640_PIXEL_ARRAY_LEFT, - .top = OV5640_PIXEL_ARRAY_TOP, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - .crop = { - .left = 56, - .top = 6, - .width = 720, - .height = 576, - }, - .htot = 1896, - .vblank_def = 1110, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 1024x768 */ - .id = OV5640_MODE_XGA_1024_768, - .dn_mode = SUBSAMPLING, - .pixel_rate = OV5640_PIXEL_RATE_96M, - .width = 1024, - .height = 768, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = 2624, - .height = 1944, - }, - .crop = { - .left = 16, - .top = 6, - .width = 1024, - .height = 768, - }, - .htot = 1896, - .vblank_def = 312, - }, - .csi2_timings = { - .analog_crop = { - .left = 0, - .top = 4, - .width = OV5640_NATIVE_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - }, - .crop = { - .left = 16, - .top = 6, - .width = 1024, - .height = 768, - }, - .htot = 1896, - .vblank_def = 918, - }, - .reg_data = ov5640_setting_low_res, - .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 1280x720 */ - .id = OV5640_MODE_720P_1280_720, - .dn_mode = SUBSAMPLING, - .pixel_rate = OV5640_PIXEL_RATE_124M, - .width = 1280, - .height = 720, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 250, - .width = 2624, - .height = 1456, - }, - .crop = { - .left = 16, - .top = 4, - .width = 1280, - .height = 720, - }, - .htot = 1892, - .vblank_def = 20, - }, - .csi2_timings = { - .analog_crop = { - .left = 0, - .top = 250, - .width = 2624, - .height = 1456, - }, - .crop = { - .left = 16, - .top = 4, - .width = 1280, - .height = 720, - }, - .htot = 1600, - .vblank_def = 560, - }, - .reg_data = ov5640_setting_720P_1280_720, - .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 1920x1080 */ - .id = OV5640_MODE_1080P_1920_1080, - .dn_mode = SCALING, - .pixel_rate = OV5640_PIXEL_RATE_148M, - .width = 1920, - .height = 1080, - .dvp_timings = { - .analog_crop = { - .left = 336, - .top = 434, - .width = 1952, - .height = 1088, - }, - .crop = { - .left = 16, - .top = 4, - .width = 1920, - .height = 1080, - }, - .htot = 2500, - .vblank_def = 40, - }, - .csi2_timings = { - /* Crop the full valid pixel array in the center. */ - .analog_crop = { - .left = 336, - .top = 434, - .width = 1952, - .height = 1088, - }, - /* Maintain a larger processing margins. */ - .crop = { - .left = 16, - .top = 4, - .width = 1920, - .height = 1080, - }, - .htot = 2234, - .vblank_def = 24, - }, - .reg_data = ov5640_setting_1080P_1920_1080, - .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), - .max_fps = OV5640_30_FPS, - .def_fps = OV5640_30_FPS - }, { - /* 2592x1944 */ - .id = OV5640_MODE_QSXGA_2592_1944, - .dn_mode = SCALING, - .pixel_rate = OV5640_PIXEL_RATE_168M, - .width = OV5640_PIXEL_ARRAY_WIDTH, - .height = OV5640_PIXEL_ARRAY_HEIGHT, - .dvp_timings = { - .analog_crop = { - .left = 0, - .top = 0, - .width = 2624, - .height = 1952, - }, - .crop = { - .left = 16, - .top = 4, - .width = 2592, - .height = 1944, - }, - .htot = 2844, - .vblank_def = 24, - }, - .csi2_timings = { - /* Give more processing margin to full resolution. */ - .analog_crop = { - .left = 0, - .top = 0, - .width = OV5640_NATIVE_WIDTH, - .height = 1952, - }, - .crop = { - .left = 16, - .top = 4, - .width = 2592, - .height = 1944, - }, - .htot = 2844, - .vblank_def = 24, - }, - .reg_data = ov5640_setting_QSXGA_2592_1944, - .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), - .max_fps = OV5640_15_FPS, - .def_fps = OV5640_15_FPS - }, +/* power-on sensor init reg table */ +static const struct ov5640_mode_info *ov5640_mode_init_data; + +static const struct ov5640_mode_info ov5640_mode_init_data_dvp = { + 0, SUBSAMPLING, 640, 1896, 480, 984, + ov5640_init_setting_30fps_VGA, + ARRAY_SIZE(ov5640_init_setting_30fps_VGA), + OV5640_30_FPS, }; -static const struct ov5640_timings * -ov5640_timings(const struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) -{ - if (ov5640_is_csi2(sensor)) - return &mode->csi2_timings; +static const struct ov5640_mode_info ov5640_mode_init_data_csi2 = { + 0, SUBSAMPLING, 640, 2844, 480, 984, + ov5640_init_setting_30fps_VGA, + ARRAY_SIZE(ov5640_init_setting_30fps_VGA), + OV5640_30_FPS, +}; - return &mode->dvp_timings; -} +static const struct ov5640_mode_info *ov5640_mode_data; + +static const struct ov5640_mode_info +ov5640_mode_data_dvp[OV5640_NUM_MODES] = { + {OV5640_MODE_QQVGA_160_120, SUBSAMPLING, + 160, 1896, 120, 984, + ov5640_setting_QQVGA_160_120, + ARRAY_SIZE(ov5640_setting_QQVGA_160_120), + OV5640_30_FPS}, + {OV5640_MODE_QCIF_176_144, SUBSAMPLING, + 176, 1896, 144, 984, + ov5640_setting_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_QCIF_176_144), + OV5640_30_FPS}, + {OV5640_MODE_QVGA_320_240, SUBSAMPLING, + 320, 1896, 240, 984, + ov5640_setting_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_QVGA_320_240), + OV5640_30_FPS}, + {OV5640_MODE_VGA_640_480, SUBSAMPLING, + 640, 1896, 480, 1080, + ov5640_setting_VGA_640_480, + ARRAY_SIZE(ov5640_setting_VGA_640_480), + OV5640_30_FPS}, + {OV5640_MODE_NTSC_720_480, SUBSAMPLING, + 720, 1896, 480, 984, + ov5640_setting_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_NTSC_720_480), + OV5640_30_FPS}, + {OV5640_MODE_PAL_720_576, SUBSAMPLING, + 720, 1896, 576, 984, + ov5640_setting_PAL_720_576, + ARRAY_SIZE(ov5640_setting_PAL_720_576), + OV5640_30_FPS}, + {OV5640_MODE_XGA_1024_768, SUBSAMPLING, + 1024, 1896, 768, 1080, + ov5640_setting_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_XGA_1024_768), + OV5640_30_FPS}, + {OV5640_MODE_720P_1280_720, SUBSAMPLING, + 1280, 1892, 720, 740, + ov5640_setting_720P_1280_720, + ARRAY_SIZE(ov5640_setting_720P_1280_720), + OV5640_30_FPS}, + {OV5640_MODE_1080P_1920_1080, SCALING, + 1920, 2500, 1080, 1120, + ov5640_setting_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_1080P_1920_1080), + OV5640_30_FPS}, + {OV5640_MODE_QSXGA_2592_1944, SCALING, + 2592, 2844, 1944, 1968, + ov5640_setting_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), + OV5640_15_FPS}, +}; + +/* + * When using CSI-2 interface, adjusting htot to 2844 + * gives better result in term of framerate, 720p support + * and overall stability with CSI-2 receiver + */ +static const struct ov5640_mode_info +ov5640_mode_data_csi2[OV5640_NUM_MODES] = { + {OV5640_MODE_QQVGA_160_120, SUBSAMPLING, + 160, 2844, 120, 984, + ov5640_setting_QQVGA_160_120, + ARRAY_SIZE(ov5640_setting_QQVGA_160_120), + OV5640_30_FPS}, + {OV5640_MODE_QCIF_176_144, SUBSAMPLING, + 176, 2844, 144, 984, + ov5640_setting_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_QCIF_176_144), + OV5640_30_FPS}, + {OV5640_MODE_QVGA_320_240, SUBSAMPLING, + 320, 2844, 240, 984, + ov5640_setting_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_QVGA_320_240), + OV5640_30_FPS}, + {OV5640_MODE_VGA_640_480, SUBSAMPLING, + 640, 2844, 480, 1080, + ov5640_setting_VGA_640_480, + ARRAY_SIZE(ov5640_setting_VGA_640_480), + OV5640_30_FPS}, + {OV5640_MODE_NTSC_720_480, SUBSAMPLING, + 720, 2844, 480, 984, + ov5640_setting_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_NTSC_720_480), + OV5640_30_FPS}, + {OV5640_MODE_PAL_720_576, SUBSAMPLING, + 720, 2844, 576, 984, + ov5640_setting_PAL_720_576, + ARRAY_SIZE(ov5640_setting_PAL_720_576), + OV5640_30_FPS}, + {OV5640_MODE_XGA_1024_768, SUBSAMPLING, + 1024, 2844, 768, 1080, + ov5640_setting_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_XGA_1024_768), + OV5640_30_FPS}, + {OV5640_MODE_720P_1280_720, SUBSAMPLING, + 1280, 2844, 720, 740, + ov5640_setting_720P_1280_720, + ARRAY_SIZE(ov5640_setting_720P_1280_720), + OV5640_30_FPS}, + {OV5640_MODE_1080P_1920_1080, SCALING, + 1920, 2844, 1080, 1120, + ov5640_setting_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_1080P_1920_1080), + OV5640_30_FPS}, + {OV5640_MODE_QSXGA_2592_1944, SCALING, + 2592, 2844, 1944, 1968, + ov5640_setting_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), + OV5640_15_FPS}, +}; static int ov5640_init_slave_id(struct ov5640_dev *sensor) { @@ -1309,10 +876,20 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, * +-----+-----+ * +------------> PCLK * - * There seems to be also constraints: + * This is deviating from the datasheet at least for the register + * 0x3108, since it's said here that the PCLK would be clocked from + * the PLL. + * + * There seems to be also (unverified) constraints: * - the PLL pre-divider output rate should be in the 4-27MHz range * - the PLL multiplier output rate should be in the 500-1000MHz range * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG + * + * In the two latter cases, these constraints are met since our + * factors are hardcoded. If we were to change that, we would need to + * take this into account. The only varying parts are the PLL + * multiplier and the system clock divider, which are shared between + * all these clocks so won't cause any issue. */ /* @@ -1331,6 +908,13 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, #define OV5640_SYSDIV_MIN 1 #define OV5640_SYSDIV_MAX 16 +/* + * Hardcode these values for scaler and non-scaler modes. + * FIXME: to be re-calcualted for 1 data lanes setups + */ +#define OV5640_MIPI_DIV_PCLK 2 +#define OV5640_MIPI_DIV_SCLK 1 + /* * This is supposed to be ranging from 1 to 2, but the value is always * set to 2 in the vendor kernels. @@ -1440,6 +1024,9 @@ out: /* * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values * for the MIPI CSI-2 output. + * + * FIXME: this have been tested with 16bpp and 2 lanes setup only. + * above formula for setups with 1 lane or image formats with different bpp. */ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) { @@ -1448,75 +1035,74 @@ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) unsigned long link_freq; unsigned long sysclk; u8 pclk_period; - u32 sample_rate; - u32 num_lanes; int ret; - /* Use the link freq computed at ov5640_update_pixel_rate() time. */ - link_freq = sensor->current_link_freq; + /* Get current link frequency */ + link_freq = ov5640_link_freqs[sensor->ctrls.link_freq->val]; /* - * - mipi_div - Additional divider for the MIPI lane clock. + * - mipi_div - Assumptions not supported by documentation * - * Higher link frequencies would make sysclk > 1GHz. - * Keep the sysclk low and do not divide in the MIPI domain. + * The MIPI clock generation differs for modes that use the scaler and + * modes that do not. */ - if (link_freq > OV5640_LINK_RATE_MAX) + if (sensor->current_mode->dn_mode == SCALING) mipi_div = 1; else mipi_div = 2; - sysclk = link_freq * mipi_div; + sysclk = link_freq * 2 * mipi_div; ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); /* - * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. + * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio; * * - root_div = 2 (fixed) - * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 + * - bit_div : MIPI 8-bit = 2 + * MIPI 10-bit = 2,5 * - pclk_div = 1 (fixed) - * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) + * - pll_div = (2 lanes ? mipi_div : 2 * mipi_div) + * 2 lanes: MIPI_SCLK = (4 or 5) * PCLK + * 1 lanes: MIPI_SCLK = (8 or 10) * PCLK * - * This results in the following MIPI_SCLK depending on the number - * of lanes: - * - * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK - * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK + * TODO: support 10-bit formats + * TODO: support 1 lane */ root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; - pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); + pclk_div = OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS; /* * Scaler clock: * - YUV: PCLK >= 2 * SCLK * - RAW or JPEG: PCLK >= SCLK * - sclk2x_div = sclk_div / 2 + * + * TODO: add support for RAW and JPEG modes. To maintain the + * SCLK to PCLK ratio, the sclk_div should probably be + * adjusted. */ sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); /* - * Set the pixel clock period expressed in ns with 1-bit decimal - * (0x01=0.5ns). + * This is called pclk period, but it actually represents the + * sample period expressed in ns with 1-bit decimal (0x01=0.5ns). * - * The register is very briefly documented. In the OV5645 datasheet it - * is described as (2 * pclk period), and from testing it seems the - * actual definition is 2 * 8-bit sample period. + * - pclk = link_freq * 2 * lanes / bpp * - * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 + * TODO: support 1 data lane; support modes with bpp != 16. */ - num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; - sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; - pclk_period = 2000000000UL / sample_rate; + pclk_period = 2000000000UL / (link_freq / 2); /* Program the clock tree registers. */ - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, + 0x0f, bit_div); if (ret) return ret; - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, - (sysdiv << 4) | mipi_div); + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, + 0xff, sysdiv << 4 | mipi_div); if (ret) return ret; @@ -1524,31 +1110,19 @@ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) if (ret) return ret; - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, - root_div | prediv); + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, + 0x1f, root_div | prediv); if (ret) return ret; ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, - (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); + (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); if (ret) return ret; return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); } -static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) -{ - const struct ov5640_mode_info *mode = sensor->current_mode; - const struct ov5640_timings *timings = &mode->dvp_timings; - u32 rate; - - rate = timings->htot * (timings->crop.height + timings->vblank_def); - rate *= ov5640_framerates[sensor->current_fr]; - - return rate; -} - static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, unsigned long rate, u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, @@ -1566,15 +1140,67 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, return _rate / *pll_rdiv / *bit_div / *pclk_div; } +static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) +{ + u64 rate; + + rate = sensor->current_mode->vtot * sensor->current_mode->htot; + rate *= ov5640_framerates[sensor->current_fr]; + + return rate; +} + static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) { + const struct ov5640_mode_info *mode = sensor->current_mode; u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; - u32 rate; + struct i2c_client *client = sensor->i2c_client; + unsigned int pclk_freq, max_pclk_freq; + u8 dvp_pclk_divider; + unsigned long rate; int ret; + /* Get pixel rate */ rate = ov5640_calc_pixel_rate(sensor); - rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code); - rate /= sensor->ep.bus.parallel.bus_width; + + dev_dbg(&client->dev, "pixel_rate=%lu selected (%dx%d@%d)(%dx%d)\n", + rate, + sensor->current_mode->hact, + sensor->current_mode->vact, + ov5640_framerates[sensor->current_fr], + sensor->current_mode->htot, + sensor->current_mode->vtot); + + /* + * All the formats we support have 16 bits per pixel, seems to require + * the same rate than YUV, so we can just use 16 bpp all the time. + */ + rate = rate * 16 / sensor->ep.bus.parallel.bus_width; + + /* + * 1280x720 and 1024x768 are reported to use 'SUBSAMPLING' only, + * but they seems to go through the scaler before subsampling. + */ + if (mode->dn_mode == SCALING || + (mode->id == OV5640_MODE_720P_1280_720) || + (mode->id == OV5640_MODE_XGA_1024_768)) + dvp_pclk_divider = 1; + else + dvp_pclk_divider = 2; + + ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER, + dvp_pclk_divider); + if (ret) + return ret; + pclk_freq = rate / dvp_pclk_divider; + max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency; + + /* clip rate according to optional maximum pixel clock limit */ + if (max_pclk_freq && (pclk_freq > max_pclk_freq)) { + rate = max_pclk_freq * dvp_pclk_divider; + dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n", + pclk_freq, max_pclk_freq); + } ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, &bit_div, &pclk_div); @@ -1610,6 +1236,7 @@ static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) (ilog2(pclk_div) << 4)); } +#if 0 /* set JPEG framing sizes */ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) @@ -1627,90 +1254,52 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width); + ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact); if (ret < 0) return ret; - return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height); + return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); } +#endif /* download ov5640 settings to sensor through i2c */ static int ov5640_set_timings(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) { - const struct ov5640_timings *timings; - const struct v4l2_rect *analog_crop; - const struct v4l2_rect *crop; int ret; - +#if 0 if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { ret = ov5640_set_jpeg_timings(sensor, mode); if (ret < 0) return ret; } - - timings = ov5640_timings(sensor, mode); - analog_crop = &timings->analog_crop; - crop = &timings->crop; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, - analog_crop->left); +#endif + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, - analog_crop->top); + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, - analog_crop->left + analog_crop->width - 1); + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, - analog_crop->top + analog_crop->height - 1); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot); - if (ret < 0) - return ret; - - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, - mode->height + timings->vblank_def); - if (ret < 0) - return ret; - - return 0; + return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); } -static void ov5640_load_regs(struct ov5640_dev *sensor, - const struct reg_value *regs, unsigned int regnum) +static int ov5640_load_regs(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) { + const struct reg_value *regs = mode->reg_data; unsigned int i; u32 delay_ms; u16 reg_addr; u8 mask, val; int ret = 0; - for (i = 0; i < regnum; ++i, ++regs) { + for (i = 0; i < mode->reg_data_size; ++i, ++regs) { delay_ms = regs->delay_ms; reg_addr = regs->reg_addr; val = regs->val; @@ -1719,7 +1308,7 @@ static void ov5640_load_regs(struct ov5640_dev *sensor, /* remain in power down mode for DVP */ if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && val == OV5640_REG_SYS_CTRL0_SW_PWUP && - !ov5640_is_csi2(sensor)) + sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) continue; if (mask) @@ -1732,6 +1321,8 @@ static void ov5640_load_regs(struct ov5640_dev *sensor, if (delay_ms) usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } + + return ov5640_set_timings(sensor, mode); } static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) @@ -2116,17 +1707,22 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) } static const struct ov5640_mode_info * -ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest) +ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, + int width, int height, bool nearest) { const struct ov5640_mode_info *mode; mode = v4l2_find_nearest_size(ov5640_mode_data, - ARRAY_SIZE(ov5640_mode_data), - width, height, width, height); + OV5640_NUM_MODES, + hact, vact, + width, height); if (!mode || - (!nearest && - (mode->width != width || mode->height != height))) + (!nearest && (mode->hact != width || mode->vact != height))) + return NULL; + + /* Check to see if the current mode exceeds the max frame rate */ + if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) return NULL; return mode; @@ -2179,8 +1775,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, return ret; /* Write capture setting */ - ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); - ret = ov5640_set_timings(sensor, mode); + ret = ov5640_load_regs(sensor, mode); if (ret < 0) return ret; @@ -2304,8 +1899,7 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, return -EINVAL; /* Write capture setting */ - ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); - return ov5640_set_timings(sensor, mode); + return ov5640_load_regs(sensor, mode); } static int ov5640_set_mode(struct ov5640_dev *sensor) @@ -2333,10 +1927,12 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) goto restore_auto_gain; } - if (ov5640_is_csi2(sensor)) + if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { ret = ov5640_set_mipi_pclk(sensor); - else + } else { ret = ov5640_set_dvp_pclk(sensor); + } + if (ret < 0) return 0; @@ -2403,8 +1999,10 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) int ret; /* first load the initial register values */ - ov5640_load_regs(sensor, ov5640_init_setting, - ARRAY_SIZE(ov5640_init_setting)); + ret = ov5640_load_regs(sensor, ov5640_mode_init_data); + if (ret < 0) + return ret; + sensor->last_mode = ov5640_mode_init_data; ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | @@ -2425,48 +2023,24 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable) gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); } -/* - * From section 2.7 power up sequence: - * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down - * t3 >= 1ms Delay from PWDN pull down to RESETB pull up - * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable - * - * Some modules don't expose RESETB/PWDN pins directly, instead providing a - * "PWUP" GPIO which is wired through appropriate delays and inverters to the - * pins. - * - * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we - * should still toggle the pwdn_gpio below with the appropriate delays, while - * the calls to reset_gpio will be ignored. - */ -static void ov5640_powerup_sequence(struct ov5640_dev *sensor) +static void ov5640_reset(struct ov5640_dev *sensor) { - if (sensor->pwdn_gpio) { - gpiod_set_value_cansleep(sensor->reset_gpio, 0); + if (!sensor->reset_gpio) + return; - /* camera power cycle */ - ov5640_power(sensor, false); - usleep_range(5000, 10000); - ov5640_power(sensor, true); - usleep_range(5000, 10000); + gpiod_set_value_cansleep(sensor->reset_gpio, 0); - gpiod_set_value_cansleep(sensor->reset_gpio, 1); - usleep_range(1000, 2000); + /* camera power cycle */ + ov5640_power(sensor, false); + usleep_range(5000, 10000); + ov5640_power(sensor, true); + usleep_range(5000, 10000); - gpiod_set_value_cansleep(sensor->reset_gpio, 0); - } else { - /* software reset */ - ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, - OV5640_REG_SYS_CTRL0_SW_RST); - } + gpiod_set_value_cansleep(sensor->reset_gpio, 1); + usleep_range(1000, 2000); + + gpiod_set_value_cansleep(sensor->reset_gpio, 0); usleep_range(20000, 25000); - - /* - * software standby: allows registers programming; - * exit at restore_mode() for CSI, s_stream(1) for DVP - */ - ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, - OV5640_REG_SYS_CTRL0_SW_PWDN); } static int ov5640_set_power_on(struct ov5640_dev *sensor) @@ -2489,7 +2063,8 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor) goto xclk_off; } - ov5640_powerup_sequence(sensor); + ov5640_reset(sensor); + ov5640_power(sensor, true); ret = ov5640_init_slave_id(sensor); if (ret) @@ -2719,24 +2294,39 @@ power_off: return ret; } -static int ov5640_sensor_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5640_dev *ov5640 = to_ov5640_dev(sd); - - return ov5640_set_power(ov5640, false); -} - -static int ov5640_sensor_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5640_dev *ov5640 = to_ov5640_dev(sd); - - return ov5640_set_power(ov5640, true); -} - /* --------------- Subdev Operations --------------- */ +static int ov5640_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov5640_dev *sensor = to_ov5640_dev(sd); + int ret = 0; + + mutex_lock(&sensor->lock); + + /* + * If the power count is modified from 0 to != 0 or from != 0 to 0, + * update the power state. + */ + if (sensor->power_count == !on) { + ret = ov5640_set_power(sensor, !!on); + if (ret) + goto out; + } + + /* Update the power count. */ + sensor->power_count += on ? 1 : -1; + WARN_ON(sensor->power_count < 0); +out: + mutex_unlock(&sensor->lock); + + if (on && !ret && sensor->power_count == 1) { + /* restore controls */ + ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + } + + return ret; +} + static int ov5640_try_frame_interval(struct ov5640_dev *sensor, struct v4l2_fract *fi, u32 width, u32 height) @@ -2747,12 +2337,12 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, int i; minfps = ov5640_framerates[OV5640_15_FPS]; - maxfps = ov5640_framerates[OV5640_60_FPS]; + maxfps = ov5640_framerates[OV5640_30_FPS]; if (fi->numerator == 0) { fi->denominator = maxfps; fi->numerator = 1; - rate = OV5640_60_FPS; + rate = OV5640_30_FPS; goto find_mode; } @@ -2773,7 +2363,7 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, fi->denominator = best_fps; find_mode: - mode = ov5640_find_mode(sensor, width, height, false); + mode = ov5640_find_mode(sensor, rate, width, height, false); return mode ? rate : -EINVAL; } @@ -2809,34 +2399,25 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, { struct ov5640_dev *sensor = to_ov5640_dev(sd); const struct ov5640_mode_info *mode; - const struct ov5640_pixfmt *pixfmt; - unsigned int bpp; + int i; - mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true); + mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); if (!mode) return -EINVAL; - - pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code); - bpp = pixfmt->bpp; - - /* - * Adjust mode according to bpp: - * - 8bpp modes work for resolution >= 1280x720 - * - 24bpp modes work resolution < 1280x720 - */ - if (bpp == 8 && mode->width < 1280) - mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720]; - else if (bpp == 24 && mode->width > 1024) - mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768]; - - fmt->width = mode->width; - fmt->height = mode->height; + fmt->width = mode->hact; + fmt->height = mode->vact; if (new_mode) *new_mode = mode; - fmt->code = pixfmt->code; - fmt->colorspace = pixfmt->colorspace; + for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) + if (ov5640_formats[i].code == fmt->code) + break; + if (i >= ARRAY_SIZE(ov5640_formats)) + i = 0; + + fmt->code = ov5640_formats[i].code; + fmt->colorspace = ov5640_formats[i].colorspace; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); @@ -2844,105 +2425,68 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, return 0; } -static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) +static int ov5640_set_link_freq_ctrl(struct ov5640_dev *sensor, + unsigned long rate) { - const struct ov5640_mode_info *mode = sensor->current_mode; - enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; - struct v4l2_mbus_framefmt *fmt = &sensor->fmt; - const struct ov5640_timings *timings; - s32 exposure_val, exposure_max; - unsigned int hblank; - unsigned int i = 0; - u32 pixel_rate; - s64 link_freq; - u32 num_lanes; - u32 vblank; - u32 bpp; - - /* - * Update the pixel rate control value. - * - * For DVP mode, maintain the pixel rate calculation using fixed FPS. - */ - if (!ov5640_is_csi2(sensor)) { - __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, - ov5640_calc_pixel_rate(sensor)); + u8 mipi_div; + unsigned int i; + unsigned int ret; + unsigned long link_freq; + unsigned int freq_index; + struct i2c_client *client = sensor->i2c_client; + if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) return 0; - } /* - * The MIPI CSI-2 link frequency should comply with the CSI-2 - * specification and be lower than 1GHz. + * - mipi_div - Assumptions not supported by documentation * - * Start from the suggested pixel_rate for the current mode and - * progressively slow it down if it exceeds 1GHz. + * The MIPI clock generation differs for modes that use the scaler and + * modes that do not. */ - num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; - bpp = ov5640_code_to_bpp(sensor, fmt->code); - do { - pixel_rate = ov5640_pixel_rates[pixel_rate_id]; - link_freq = pixel_rate * bpp / (2 * num_lanes); - } while (link_freq >= 1000000000U && - ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); - - sensor->current_link_freq = link_freq; + if (sensor->current_mode->dn_mode == SCALING) + mipi_div = 1; + else + mipi_div = 2; /* - * Higher link rates require the clock tree to be programmed with - * 'mipi_div' = 1; this has the effect of halving the actual output - * pixel rate in the MIPI domain. - * - * Adjust the pixel rate and link frequency control value to report it - * correctly to userspace. + * All the formats we support have 16 bits per pixel, seems to require + * the same rate than YUV, so we can just use 16 bpp all the time. */ - if (link_freq > OV5640_LINK_RATE_MAX) { - pixel_rate /= 2; - link_freq /= 2; - } + rate = rate * 16; - for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { - if (ov5640_csi2_link_freqs[i] == link_freq) + /* + * The 'rate' parameter is the bitrate = VTOT * HTOT * FPS * BPP + * + * Adjust it to represent the CSI-2 link frequency and use it to + * update the associated control. + */ + link_freq = rate / sensor->ep.bus.mipi_csi2.num_data_lanes / + 2 / mipi_div; + + freq_index = OV5640_LINK_FREQS_NUM - 1; + for (i = 0; i < OV5640_LINK_FREQS_NUM; ++i) { + if (ov5640_link_freqs[i] == link_freq) { + freq_index = i; break; + } } - WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); + WARN_ONCE(i == OV5640_LINK_FREQS_NUM, + "Link frequency %ld not supported", link_freq); - __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); - __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); + ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, freq_index); + if (ret < 0) + return ret; - timings = ov5640_timings(sensor, mode); - hblank = timings->htot - mode->width; - __v4l2_ctrl_modify_range(sensor->ctrls.hblank, - hblank, hblank, 1, hblank); + dev_dbg(&client->dev, "link_freq[%d]=%lld selected (%dx%d@%d)(%dx%d)\n", + freq_index, ov5640_link_freqs[freq_index], + sensor->current_mode->hact, + sensor->current_mode->vact, + ov5640_framerates[sensor->current_fr], + sensor->current_mode->htot, + sensor->current_mode->vtot); - vblank = timings->vblank_def; - - if (sensor->current_fr != mode->def_fps) { - /* - * Compute the vertical blanking according to the framerate - * configured with s_frame_interval. - */ - int fie_num = sensor->frame_interval.numerator; - int fie_denom = sensor->frame_interval.denominator; - - vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) - - mode->height; - } - - __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, - OV5640_MAX_VTS - mode->height, 1, vblank); - __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank); - - exposure_max = timings->crop.height + vblank - 4; - exposure_val = clamp_t(s32, sensor->ctrls.exposure->val, - sensor->ctrls.exposure->minimum, - exposure_max); - - __v4l2_ctrl_modify_range(sensor->ctrls.exposure, - sensor->ctrls.exposure->minimum, - exposure_max, 1, exposure_val); - - return 0; + return ret; } static int ov5640_set_fmt(struct v4l2_subdev *sd, @@ -2975,7 +2519,6 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, } if (new_mode != sensor->current_mode) { - sensor->current_fr = new_mode->def_fps; sensor->current_mode = new_mode; sensor->pending_mode_change = true; } @@ -2985,70 +2528,86 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, /* update format even if code is unchanged, resolution might change */ sensor->fmt = *mbus_fmt; - ov5640_update_pixel_rate(sensor); + if (sensor->pending_mode_change || sensor->pending_fmt_change) { + unsigned long rate = ov5640_calc_pixel_rate(sensor); + + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, rate); + + ret = ov5640_set_link_freq_ctrl(sensor, rate); + } out: mutex_unlock(&sensor->lock); return ret; } -static int ov5640_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct ov5640_dev *sensor = to_ov5640_dev(sd); - const struct ov5640_mode_info *mode = sensor->current_mode; - const struct ov5640_timings *timings; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: { - mutex_lock(&sensor->lock); - timings = ov5640_timings(sensor, mode); - sel->r = timings->analog_crop; - mutex_unlock(&sensor->lock); - - return 0; - } - - case V4L2_SEL_TGT_NATIVE_SIZE: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = 0; - sel->r.left = 0; - sel->r.width = OV5640_NATIVE_WIDTH; - sel->r.height = OV5640_NATIVE_HEIGHT; - - return 0; - - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.top = OV5640_PIXEL_ARRAY_TOP; - sel->r.left = OV5640_PIXEL_ARRAY_LEFT; - sel->r.width = OV5640_PIXEL_ARRAY_WIDTH; - sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT; - - return 0; - } - - return -EINVAL; -} - static int ov5640_set_framefmt(struct ov5640_dev *sensor, struct v4l2_mbus_framefmt *format) { - bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8; - const struct ov5640_pixfmt *pixfmt; int ret = 0; + bool is_jpeg = false; + u8 fmt, mux; - pixfmt = ov5640_code_to_pixfmt(sensor, format->code); + switch (format->code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY8_2X8: + /* YUV422, UYVY */ + fmt = 0x3f; + mux = OV5640_FMT_MUX_YUV422; + break; + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + /* YUV422, YUYV */ + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; + break; + case MEDIA_BUS_FMT_RGB565_2X8_LE: + /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ + fmt = 0x6F; + mux = OV5640_FMT_MUX_RGB; + break; + case MEDIA_BUS_FMT_RGB565_2X8_BE: + /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ + fmt = 0x61; + mux = OV5640_FMT_MUX_RGB; + break; + case MEDIA_BUS_FMT_JPEG_1X8: + /* YUV422, YUYV */ + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; + is_jpeg = true; + break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + /* Raw, BGBG... / GRGR... */ + fmt = 0x00; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + /* Raw bayer, GBGB... / RGRG... */ + fmt = 0x01; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + /* Raw bayer, GRGR... / BGBG... */ + fmt = 0x02; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + /* Raw bayer, RGRG... / GBGB... */ + fmt = 0x03; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + default: + return -EINVAL; + } /* FORMAT CONTROL00: YUV and RGB formatting */ - ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, - pixfmt->ctrl00); + ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); if (ret) return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, - pixfmt->mux); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); if (ret) return ret; @@ -3305,15 +2864,6 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) (BIT(2) | BIT(1)) : 0); } -static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value) -{ - const struct ov5640_mode_info *mode = sensor->current_mode; - - /* Update the VTOT timing register value. */ - return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, - mode->height + value); -} - static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -3322,9 +2872,6 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) /* v4l2_ctrl_lock() locks our own mutex */ - if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) - return 0; - switch (ctrl->id) { case V4L2_CID_AUTOGAIN: val = ov5640_get_gain(sensor); @@ -3340,8 +2887,6 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put_autosuspend(&sensor->i2c_client->dev); - return 0; } @@ -3349,31 +2894,16 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); struct ov5640_dev *sensor = to_ov5640_dev(sd); - const struct ov5640_mode_info *mode = sensor->current_mode; - const struct ov5640_timings *timings; - unsigned int exp_max; int ret; /* v4l2_ctrl_lock() locks our own mutex */ - switch (ctrl->id) { - case V4L2_CID_VBLANK: - /* Update the exposure range to the newly programmed vblank. */ - timings = ov5640_timings(sensor, mode); - exp_max = mode->height + ctrl->val - 4; - __v4l2_ctrl_modify_range(sensor->ctrls.exposure, - sensor->ctrls.exposure->minimum, - exp_max, sensor->ctrls.exposure->step, - timings->vblank_def); - break; - } - /* * If the device is not powered up by the host driver do * not apply any controls to H/W at this time. Instead - * the controls will be restored at start streaming time. + * the controls will be restored right after power-up. */ - if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) + if (sensor->power_count == 0) return 0; switch (ctrl->id) { @@ -3407,16 +2937,11 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VFLIP: ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); break; - case V4L2_CID_VBLANK: - ret = ov5640_set_ctrl_vblank(sensor, ctrl->val); - break; default: ret = -EINVAL; break; } - pm_runtime_put_autosuspend(&sensor->i2c_client->dev); - return ret; } @@ -3427,14 +2952,10 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { static int ov5640_init_controls(struct ov5640_dev *sensor) { - const struct ov5640_mode_info *mode = sensor->current_mode; const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; struct ov5640_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; - struct v4l2_fwnode_device_properties props; - const struct ov5640_timings *timings; - unsigned int max_vblank; - unsigned int hblank; + unsigned long rate; int ret; v4l2_ctrl_handler_init(hdl, 32); @@ -3443,26 +2964,22 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) hdl->lock = &sensor->lock; /* Clock related controls */ + rate = ov5640_calc_pixel_rate(sensor); ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, - ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], - ov5640_pixel_rates[0], 1, - ov5640_pixel_rates[mode->pixel_rate]); + 0, INT_MAX, 1, + rate); - ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, - V4L2_CID_LINK_FREQ, - ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, - OV5640_DEFAULT_LINK_FREQ, - ov5640_csi2_link_freqs); + ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, + OV5640_LINK_FREQS_NUM - 1, + 0, ov5640_link_freqs); + if (ctrls->link_freq) + ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - timings = ov5640_timings(sensor, mode); - hblank = timings->htot - mode->width; - ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank, - hblank, 1, hblank); - - max_vblank = OV5640_MAX_VTS - mode->height; - ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, - OV5640_MIN_VBLANK, max_vblank, - 1, timings->vblank_def); + mutex_lock(&sensor->lock); + ret = ov5640_set_link_freq_ctrl(sensor, rate); + mutex_unlock(&sensor->lock); + if (ret) + goto free_ctrls; /* Auto/manual white balance */ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, @@ -3482,7 +2999,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) /* Auto/manual gain */ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 0); ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, @@ -3511,20 +3028,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) goto free_ctrls; } - ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props); - if (ret) - goto free_ctrls; - - if (props.rotation == 180) - sensor->upside_down = true; - - ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); - if (ret) - goto free_ctrls; - ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; - ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; @@ -3544,29 +3048,16 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - struct ov5640_dev *sensor = to_ov5640_dev(sd); - u32 bpp = ov5640_code_to_bpp(sensor, fse->code); - unsigned int index = fse->index; - if (fse->pad != 0) return -EINVAL; - if (!bpp) + if (fse->index >= OV5640_NUM_MODES) return -EINVAL; - /* Only low-resolution modes are supported for 24bpp formats. */ - if (bpp == 24 && index >= OV5640_MODE_720P_1280_720) - return -EINVAL; - - /* FIXME: Low resolution modes don't work in 8bpp formats. */ - if (bpp == 8) - index += OV5640_MODE_720P_1280_720; - - if (index >= OV5640_NUM_MODES) - return -EINVAL; - - fse->min_width = ov5640_mode_data[index].width; + fse->min_width = + ov5640_mode_data[fse->index].hact; fse->max_width = fse->min_width; - fse->min_height = ov5640_mode_data[index].height; + fse->min_height = + ov5640_mode_data[fse->index].vact; fse->max_height = fse->min_height; return 0; @@ -3630,33 +3121,32 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, mode = sensor->current_mode; frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, - mode->width, - mode->height); + mode->hact, mode->vact); if (frame_rate < 0) { /* Always return a valid frame interval value */ fi->interval = sensor->frame_interval; goto out; } - mode = ov5640_find_mode(sensor, mode->width, mode->height, true); + mode = ov5640_find_mode(sensor, frame_rate, mode->hact, + mode->vact, true); if (!mode) { ret = -EINVAL; goto out; } - if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) { - ret = -EINVAL; - goto out; - } - if (mode != sensor->current_mode || frame_rate != sensor->current_fr) { + unsigned long rate; + sensor->current_fr = frame_rate; sensor->frame_interval = fi->interval; sensor->current_mode = mode; sensor->pending_mode_change = true; - ov5640_update_pixel_rate(sensor); + rate = ov5640_calc_pixel_rate(sensor); + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, rate); + ret = ov5640_set_link_freq_ctrl(sensor, rate); } out: mutex_unlock(&sensor->lock); @@ -3667,23 +3157,12 @@ static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct ov5640_dev *sensor = to_ov5640_dev(sd); - const struct ov5640_pixfmt *formats; - unsigned int num_formats; - - if (ov5640_is_csi2(sensor)) { - formats = ov5640_csi2_formats; - num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1; - } else { - formats = ov5640_dvp_formats; - num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1; - } - - if (code->index >= num_formats) + if (code->pad != 0) + return -EINVAL; + if (code->index >= ARRAY_SIZE(ov5640_formats)) return -EINVAL; - code->code = formats[code->index].code; - + code->code = ov5640_formats[code->index].code; return 0; } @@ -3692,18 +3171,6 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) struct ov5640_dev *sensor = to_ov5640_dev(sd); int ret = 0; - if (enable) { - ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); - if (ret < 0) - return ret; - - ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); - if (ret) { - pm_runtime_put(&sensor->i2c_client->dev); - return ret; - } - } - mutex_lock(&sensor->lock); if (sensor->streaming == !enable) { @@ -3720,7 +3187,7 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) sensor->pending_fmt_change = false; } - if (ov5640_is_csi2(sensor)) + if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) ret = ov5640_set_stream_mipi(sensor, enable); else ret = ov5640_set_stream_dvp(sensor, enable); @@ -3728,34 +3195,13 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) if (!ret) sensor->streaming = enable; } - out: mutex_unlock(&sensor->lock); - - if (!enable || ret) - pm_runtime_put_autosuspend(&sensor->i2c_client->dev); - return ret; } -static int ov5640_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) -{ - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(sd, state, 0); - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); - - *fmt = ov5640_default_fmt; - - crop->left = OV5640_PIXEL_ARRAY_LEFT; - crop->top = OV5640_PIXEL_ARRAY_TOP; - crop->width = OV5640_PIXEL_ARRAY_WIDTH; - crop->height = OV5640_PIXEL_ARRAY_HEIGHT; - - return 0; -} - static const struct v4l2_subdev_core_ops ov5640_core_ops = { + .s_power = ov5640_s_power, .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -3768,11 +3214,9 @@ static const struct v4l2_subdev_video_ops ov5640_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { - .init_cfg = ov5640_init_cfg, .enum_mbus_code = ov5640_enum_mbus_code, .get_fmt = ov5640_get_fmt, .set_fmt = ov5640_set_fmt, - .get_selection = ov5640_get_selection, .enum_frame_size = ov5640_enum_frame_size, .enum_frame_interval = ov5640_enum_frame_interval, }; @@ -3801,20 +3245,26 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor) int ret = 0; u16 chip_id; + ret = ov5640_set_power_on(sensor); + if (ret) + return ret; + ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); if (ret) { dev_err(&client->dev, "%s: failed to read chip identifier\n", __func__); - return ret; + goto power_off; } if (chip_id != 0x5640) { dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", __func__, chip_id); - return -ENXIO; + ret = -ENXIO; } - return 0; +power_off: + ov5640_set_power_off(sensor); + return ret; } static int ov5640_probe(struct i2c_client *client) @@ -3822,6 +3272,8 @@ static int ov5640_probe(struct i2c_client *client) struct device *dev = &client->dev; struct fwnode_handle *endpoint; struct ov5640_dev *sensor; + struct v4l2_mbus_framefmt *fmt; + u32 rotation; int ret; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); @@ -3834,18 +3286,35 @@ static int ov5640_probe(struct i2c_client *client) * default init sequence initialize sensor to * YUV422 UYVY VGA@30fps */ - sensor->fmt = ov5640_default_fmt; + fmt = &sensor->fmt; + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + fmt->field = V4L2_FIELD_NONE; sensor->frame_interval.numerator = 1; sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; sensor->current_fr = OV5640_30_FPS; - sensor->current_mode = - &ov5640_mode_data[OV5640_MODE_VGA_640_480]; - sensor->last_mode = sensor->current_mode; - sensor->current_link_freq = - ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ]; sensor->ae_target = 52; + /* optional indication of physical rotation of sensor */ + ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", + &rotation); + if (!ret) { + switch (rotation) { + case 180: + sensor->upside_down = true; + fallthrough; + case 0: + break; + default: + dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", + rotation); + } + } + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); if (!endpoint) { @@ -3867,6 +3336,20 @@ static int ov5640_probe(struct i2c_client *client) return -EINVAL; } + if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { + ov5640_mode_data = ov5640_mode_data_csi2; + ov5640_mode_init_data = &ov5640_mode_init_data_csi2; + } else { + ov5640_mode_data = ov5640_mode_data_dvp; + ov5640_mode_init_data = &ov5640_mode_init_data_dvp; + } + + fmt->width = ov5640_mode_data[OV5640_DEFAULT_MODE].hact; + fmt->height = ov5640_mode_data[OV5640_DEFAULT_MODE].vact; + sensor->current_mode = + &ov5640_mode_data[OV5640_DEFAULT_MODE]; + sensor->last_mode = sensor->current_mode; + /* get system clock (xclk) */ sensor->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(sensor->xclk)) { @@ -3906,43 +3389,26 @@ static int ov5640_probe(struct i2c_client *client) ret = ov5640_get_regulators(sensor); if (ret) - goto entity_cleanup; + return ret; mutex_init(&sensor->lock); + ret = ov5640_check_chip_id(sensor); + if (ret) + goto entity_cleanup; + ret = ov5640_init_controls(sensor); if (ret) goto entity_cleanup; - ret = ov5640_sensor_resume(dev); - if (ret) { - dev_err(dev, "failed to power on\n"); - goto entity_cleanup; - } - - pm_runtime_set_active(dev); - pm_runtime_get_noresume(dev); - pm_runtime_enable(dev); - - ret = ov5640_check_chip_id(sensor); - if (ret) - goto err_pm_runtime; - ret = v4l2_async_register_subdev_sensor(&sensor->sd); if (ret) - goto err_pm_runtime; - - pm_runtime_set_autosuspend_delay(dev, 1000); - pm_runtime_use_autosuspend(dev); - pm_runtime_put_autosuspend(dev); + goto free_ctrls; return 0; -err_pm_runtime: - pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); +free_ctrls: v4l2_ctrl_handler_free(&sensor->ctrls.handler); - ov5640_sensor_suspend(dev); entity_cleanup: media_entity_cleanup(&sensor->sd.entity); mutex_destroy(&sensor->lock); @@ -3953,12 +3419,6 @@ static void ov5640_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov5640_dev *sensor = to_ov5640_dev(sd); - struct device *dev = &client->dev; - - pm_runtime_disable(dev); - if (!pm_runtime_status_suspended(dev)) - ov5640_sensor_suspend(dev); - pm_runtime_set_suspended(dev); v4l2_async_unregister_subdev(&sensor->sd); media_entity_cleanup(&sensor->sd.entity); @@ -3966,10 +3426,6 @@ static void ov5640_remove(struct i2c_client *client) mutex_destroy(&sensor->lock); } -static const struct dev_pm_ops ov5640_pm_ops = { - SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL) -}; - static const struct i2c_device_id ov5640_id[] = { {"ov5640", 0}, {}, @@ -3986,7 +3442,6 @@ static struct i2c_driver ov5640_i2c_driver = { .driver = { .name = "ov5640", .of_match_table = ov5640_dt_ids, - .pm = &ov5640_pm_ops, }, .id_table = ov5640_id, .probe_new = ov5640_probe,