12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 219a81c14SSteve Longerbeam /* 319a81c14SSteve Longerbeam * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 419a81c14SSteve Longerbeam * Copyright (C) 2014-2017 Mentor Graphics Inc. 519a81c14SSteve Longerbeam */ 619a81c14SSteve Longerbeam 719a81c14SSteve Longerbeam #include <linux/clk.h> 819a81c14SSteve Longerbeam #include <linux/clk-provider.h> 919a81c14SSteve Longerbeam #include <linux/clkdev.h> 1019a81c14SSteve Longerbeam #include <linux/ctype.h> 1119a81c14SSteve Longerbeam #include <linux/delay.h> 1219a81c14SSteve Longerbeam #include <linux/device.h> 1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h> 1419a81c14SSteve Longerbeam #include <linux/i2c.h> 1519a81c14SSteve Longerbeam #include <linux/init.h> 167c7e33b7SRob Herring #include <linux/mod_devicetable.h> 1719a81c14SSteve Longerbeam #include <linux/module.h> 1885644a9bSPaul Elder #include <linux/pm_runtime.h> 1941d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h> 2019a81c14SSteve Longerbeam #include <linux/slab.h> 2119a81c14SSteve Longerbeam #include <linux/types.h> 2219a81c14SSteve Longerbeam #include <media/v4l2-async.h> 2319a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h> 2419a81c14SSteve Longerbeam #include <media/v4l2-device.h> 252d18fbc5SAkinobu Mita #include <media/v4l2-event.h> 2619a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h> 2719a81c14SSteve Longerbeam #include <media/v4l2-subdev.h> 2819a81c14SSteve Longerbeam 2919a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */ 3019a81c14SSteve Longerbeam #define OV5640_XCLK_MIN 6000000 3141cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000 3219a81c14SSteve Longerbeam 335113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH 2624 345113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT 1964 355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP 14 365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT 16 375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH 2592 385113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT 1944 395113d5b3SJacopo Mondi 40bce93b82SJacopo Mondi /* FIXME: not documented. */ 41bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK 24 42bce93b82SJacopo Mondi #define OV5640_MAX_VTS 3375 43bce93b82SJacopo Mondi 4419a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c 4519a81c14SSteve Longerbeam 463c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX 490000000U 473c28588fSJacopo Mondi 48d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02 0x3002 49d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 50f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0 0x3008 513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 523b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 53decea0a9SJai Luthra #define OV5640_REG_SYS_CTRL0_SW_RST 0x82 5419a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID 0x300a 55f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00 0x300e 56f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 57f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 5819a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00 0x3019 59f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1 0x302e 6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0 0x3034 6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1 0x3035 6219a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2 0x3036 6319a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3 0x3037 6419a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID 0x3100 65f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1 0x3103 6619a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN 0x3400 6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN 0x3402 6919a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN 0x3404 7019a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL 0x3406 7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500 7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501 7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502 7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL 0x3503 7519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a 7619a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS 0x350c 773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS 0x3800 783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS 0x3802 793145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW 0x3804 803145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH 0x3806 8186633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO 0x3808 8286633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO 0x380a 8319a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS 0x380c 8419a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS 0x380e 853145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS 0x3810 863145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS 0x3812 87ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20 0x3820 8819a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21 0x3821 8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00 0x3a00 9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP 0x3a08 9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP 0x3a0a 9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D 0x3a0d 9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E 0x3a0e 9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F 0x3a0f 9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10 0x3a10 9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11 0x3a11 9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B 0x3a1b 9819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E 0x3a1e 9919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F 0x3a1f 10019a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00 0x3c00 10119a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01 0x3c01 10219a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c 10319a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01 0x4202 104e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00 0x4300 1057cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE 0x4602 1067cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE 0x4604 1072b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT 0x4713 1084039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00 0x4730 109f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00 0x4740 11019a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00 0x4800 11119a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE 0x4814 1126c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD 0x4837 113e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f 11419a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d 11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0 0x5580 11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1 0x5581 11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3 0x5583 11819a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4 0x5584 11919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5 0x5585 12019a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT 0x56a1 12119a81c14SSteve Longerbeam 12219a81c14SSteve Longerbeam enum ov5640_mode_id { 12332ea5e05SHugues Fruchet OV5640_MODE_QQVGA_160_120 = 0, 12432ea5e05SHugues Fruchet OV5640_MODE_QCIF_176_144, 12519a81c14SSteve Longerbeam OV5640_MODE_QVGA_320_240, 12619a81c14SSteve Longerbeam OV5640_MODE_VGA_640_480, 12719a81c14SSteve Longerbeam OV5640_MODE_NTSC_720_480, 12819a81c14SSteve Longerbeam OV5640_MODE_PAL_720_576, 12919a81c14SSteve Longerbeam OV5640_MODE_XGA_1024_768, 13019a81c14SSteve Longerbeam OV5640_MODE_720P_1280_720, 13119a81c14SSteve Longerbeam OV5640_MODE_1080P_1920_1080, 13219a81c14SSteve Longerbeam OV5640_MODE_QSXGA_2592_1944, 13319a81c14SSteve Longerbeam OV5640_NUM_MODES, 13419a81c14SSteve Longerbeam }; 13519a81c14SSteve Longerbeam 13619a81c14SSteve Longerbeam enum ov5640_frame_rate { 13719a81c14SSteve Longerbeam OV5640_15_FPS = 0, 13819a81c14SSteve Longerbeam OV5640_30_FPS, 139e823fb16SMaxime Ripard OV5640_60_FPS, 14019a81c14SSteve Longerbeam OV5640_NUM_FRAMERATES, 14119a81c14SSteve Longerbeam }; 14219a81c14SSteve Longerbeam 14322845bf2SJacopo Mondi enum ov5640_pixel_rate_id { 14422845bf2SJacopo Mondi OV5640_PIXEL_RATE_168M, 14522845bf2SJacopo Mondi OV5640_PIXEL_RATE_148M, 14622845bf2SJacopo Mondi OV5640_PIXEL_RATE_124M, 14722845bf2SJacopo Mondi OV5640_PIXEL_RATE_96M, 14822845bf2SJacopo Mondi OV5640_PIXEL_RATE_48M, 14922845bf2SJacopo Mondi OV5640_NUM_PIXEL_RATES, 15022845bf2SJacopo Mondi }; 15122845bf2SJacopo Mondi 15222845bf2SJacopo Mondi /* 15322845bf2SJacopo Mondi * The chip manual suggests 24/48/96/192 MHz pixel clocks. 15422845bf2SJacopo Mondi * 15522845bf2SJacopo Mondi * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for 15622845bf2SJacopo Mondi * full resolution mode @15 FPS. 15722845bf2SJacopo Mondi */ 15822845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = { 15922845bf2SJacopo Mondi [OV5640_PIXEL_RATE_168M] = 168000000, 16022845bf2SJacopo Mondi [OV5640_PIXEL_RATE_148M] = 148000000, 16122845bf2SJacopo Mondi [OV5640_PIXEL_RATE_124M] = 124000000, 16222845bf2SJacopo Mondi [OV5640_PIXEL_RATE_96M] = 96000000, 16322845bf2SJacopo Mondi [OV5640_PIXEL_RATE_48M] = 48000000, 16422845bf2SJacopo Mondi }; 16522845bf2SJacopo Mondi 1667a3b8d4bSJacopo Mondi /* 1677a3b8d4bSJacopo Mondi * MIPI CSI-2 link frequencies. 1687a3b8d4bSJacopo Mondi * 1697a3b8d4bSJacopo Mondi * Derived from the above defined pixel rate for bpp = (8, 16, 24) and 1707a3b8d4bSJacopo Mondi * data_lanes = (1, 2) 1717a3b8d4bSJacopo Mondi * 1727a3b8d4bSJacopo Mondi * link_freq = (pixel_rate * bpp) / (2 * data_lanes) 1737a3b8d4bSJacopo Mondi */ 1747a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = { 1757a3b8d4bSJacopo Mondi 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, 1767a3b8d4bSJacopo Mondi 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, 1777a3b8d4bSJacopo Mondi 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, 1787a3b8d4bSJacopo Mondi 248000000, 192000000, 192000000, 192000000, 96000000, 1797a3b8d4bSJacopo Mondi }; 1807a3b8d4bSJacopo Mondi 1817a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ 1827a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ 13 1837a3b8d4bSJacopo Mondi 184b7ed3abdSLoic Poulain enum ov5640_format_mux { 185b7ed3abdSLoic Poulain OV5640_FMT_MUX_YUV422 = 0, 186b7ed3abdSLoic Poulain OV5640_FMT_MUX_RGB, 187b7ed3abdSLoic Poulain OV5640_FMT_MUX_DITHER, 188b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_DPC, 189b7ed3abdSLoic Poulain OV5640_FMT_MUX_SNR_RAW, 190b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_CIP, 191b7ed3abdSLoic Poulain }; 192b7ed3abdSLoic Poulain 193a89f14bbSJacopo Mondi struct ov5640_pixfmt { 194e3ee691dSHugues Fruchet u32 code; 195e3ee691dSHugues Fruchet u32 colorspace; 1962d7671f6SJacopo Mondi u8 bpp; 197935fbc94SJacopo Mondi u8 ctrl00; 198935fbc94SJacopo Mondi enum ov5640_format_mux mux; 199a89f14bbSJacopo Mondi }; 200a89f14bbSJacopo Mondi 201a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_dvp_formats[] = { 2022d7671f6SJacopo Mondi { 203935fbc94SJacopo Mondi /* YUV422, YUYV */ 2042d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_JPEG_1X8, 2052d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_JPEG, 2062d7671f6SJacopo Mondi .bpp = 16, 207935fbc94SJacopo Mondi .ctrl00 = 0x30, 208935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 2092d7671f6SJacopo Mondi }, { 210935fbc94SJacopo Mondi /* YUV422, UYVY */ 2112d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_2X8, 2122d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2132d7671f6SJacopo Mondi .bpp = 16, 214935fbc94SJacopo Mondi .ctrl00 = 0x3f, 215935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 2162d7671f6SJacopo Mondi }, { 217935fbc94SJacopo Mondi /* YUV422, YUYV */ 2182d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_2X8, 2192d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2202d7671f6SJacopo Mondi .bpp = 16, 221935fbc94SJacopo Mondi .ctrl00 = 0x30, 222935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 2232d7671f6SJacopo Mondi }, { 224935fbc94SJacopo Mondi /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 2252d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 2262d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2272d7671f6SJacopo Mondi .bpp = 16, 228935fbc94SJacopo Mondi .ctrl00 = 0x6f, 229935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RGB, 2302d7671f6SJacopo Mondi }, { 231935fbc94SJacopo Mondi /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ 2322d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 2332d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2342d7671f6SJacopo Mondi .bpp = 16, 235935fbc94SJacopo Mondi .ctrl00 = 0x61, 236935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RGB, 2372d7671f6SJacopo Mondi }, { 238935fbc94SJacopo Mondi /* Raw, BGBG... / GRGR... */ 239a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR8_1X8, 240a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 241a89f14bbSJacopo Mondi .bpp = 8, 242935fbc94SJacopo Mondi .ctrl00 = 0x00, 243935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 244a89f14bbSJacopo Mondi }, { 245935fbc94SJacopo Mondi /* Raw bayer, GBGB... / RGRG... */ 246a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_SGBRG8_1X8, 247a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 248935fbc94SJacopo Mondi .bpp = 8, 249935fbc94SJacopo Mondi .ctrl00 = 0x01, 250935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 251a89f14bbSJacopo Mondi }, { 252935fbc94SJacopo Mondi /* Raw bayer, GRGR... / BGBG... */ 253a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_SGRBG8_1X8, 254a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 255a89f14bbSJacopo Mondi .bpp = 8, 256935fbc94SJacopo Mondi .ctrl00 = 0x02, 257935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 258a89f14bbSJacopo Mondi }, { 259935fbc94SJacopo Mondi /* Raw bayer, RGRG... / GBGB... */ 260a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_SRGGB8_1X8, 261a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 262a89f14bbSJacopo Mondi .bpp = 8, 263935fbc94SJacopo Mondi .ctrl00 = 0x03, 264935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 265a89f14bbSJacopo Mondi }, 266a89f14bbSJacopo Mondi { /* sentinel */ } 267a89f14bbSJacopo Mondi }; 268a89f14bbSJacopo Mondi 269a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_csi2_formats[] = { 270a89f14bbSJacopo Mondi { 271935fbc94SJacopo Mondi /* YUV422, YUYV */ 272a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_JPEG_1X8, 273a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_JPEG, 274a89f14bbSJacopo Mondi .bpp = 16, 275935fbc94SJacopo Mondi .ctrl00 = 0x30, 276935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 277a89f14bbSJacopo Mondi }, { 278935fbc94SJacopo Mondi /* YUV422, UYVY */ 279a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_1X16, 280a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 281a89f14bbSJacopo Mondi .bpp = 16, 282935fbc94SJacopo Mondi .ctrl00 = 0x3f, 283935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 284a89f14bbSJacopo Mondi }, { 285935fbc94SJacopo Mondi /* YUV422, YUYV */ 286a89f14bbSJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_1X16, 287a89f14bbSJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 288a89f14bbSJacopo Mondi .bpp = 16, 289935fbc94SJacopo Mondi .ctrl00 = 0x30, 290935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_YUV422, 291a89f14bbSJacopo Mondi }, { 292935fbc94SJacopo Mondi /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 2930a43fcd7SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_1X16, 2940a43fcd7SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2950a43fcd7SJacopo Mondi .bpp = 16, 296935fbc94SJacopo Mondi .ctrl00 = 0x6f, 297935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RGB, 2980a43fcd7SJacopo Mondi }, { 299935fbc94SJacopo Mondi /* BGR888: RGB */ 3006ac98b41SJacopo Mondi .code = MEDIA_BUS_FMT_BGR888_1X24, 3016ac98b41SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 3026ac98b41SJacopo Mondi .bpp = 24, 303935fbc94SJacopo Mondi .ctrl00 = 0x23, 304935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RGB, 3056ac98b41SJacopo Mondi }, { 306935fbc94SJacopo Mondi /* Raw, BGBG... / GRGR... */ 3072d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR8_1X8, 3082d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 3092d7671f6SJacopo Mondi .bpp = 8, 310935fbc94SJacopo Mondi .ctrl00 = 0x00, 311935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 3122d7671f6SJacopo Mondi }, { 313935fbc94SJacopo Mondi /* Raw bayer, GBGB... / RGRG... */ 3142d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGBRG8_1X8, 3152d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 316935fbc94SJacopo Mondi .bpp = 8, 317935fbc94SJacopo Mondi .ctrl00 = 0x01, 318935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 3192d7671f6SJacopo Mondi }, { 320935fbc94SJacopo Mondi /* Raw bayer, GRGR... / BGBG... */ 3212d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGRBG8_1X8, 3222d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 3232d7671f6SJacopo Mondi .bpp = 8, 324935fbc94SJacopo Mondi .ctrl00 = 0x02, 325935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 3262d7671f6SJacopo Mondi }, { 327935fbc94SJacopo Mondi /* Raw bayer, RGRG... / GBGB... */ 3282d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SRGGB8_1X8, 3292d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 3302d7671f6SJacopo Mondi .bpp = 8, 331935fbc94SJacopo Mondi .ctrl00 = 0x03, 332935fbc94SJacopo Mondi .mux = OV5640_FMT_MUX_RAW_DPC, 3332d7671f6SJacopo Mondi }, 334a89f14bbSJacopo Mondi { /* sentinel */ } 335e3ee691dSHugues Fruchet }; 336e3ee691dSHugues Fruchet 33719a81c14SSteve Longerbeam /* 33819a81c14SSteve Longerbeam * FIXME: remove this when a subdev API becomes available 33919a81c14SSteve Longerbeam * to set the MIPI CSI-2 virtual channel. 34019a81c14SSteve Longerbeam */ 34119a81c14SSteve Longerbeam static unsigned int virtual_channel; 3428670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444); 34319a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel, 34419a81c14SSteve Longerbeam "MIPI CSI-2 virtual channel (0..3), default 0"); 34519a81c14SSteve Longerbeam 34619a81c14SSteve Longerbeam static const int ov5640_framerates[] = { 34719a81c14SSteve Longerbeam [OV5640_15_FPS] = 15, 34819a81c14SSteve Longerbeam [OV5640_30_FPS] = 30, 349e823fb16SMaxime Ripard [OV5640_60_FPS] = 60, 35019a81c14SSteve Longerbeam }; 35119a81c14SSteve Longerbeam 35219a81c14SSteve Longerbeam /* regulator supplies */ 35319a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = { 35441d8d7f5SHugues Fruchet "DOVDD", /* Digital I/O (1.8V) supply */ 35519a81c14SSteve Longerbeam "AVDD", /* Analog (2.8V) supply */ 35624c8ac89SFabio Estevam "DVDD", /* Digital Core (1.5V) supply */ 35719a81c14SSteve Longerbeam }; 35819a81c14SSteve Longerbeam 35919a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) 36019a81c14SSteve Longerbeam 36119a81c14SSteve Longerbeam /* 36219a81c14SSteve Longerbeam * Image size under 1280 * 960 are SUBSAMPLING 36319a81c14SSteve Longerbeam * Image size upper 1280 * 960 are SCALING 36419a81c14SSteve Longerbeam */ 36519a81c14SSteve Longerbeam enum ov5640_downsize_mode { 36619a81c14SSteve Longerbeam SUBSAMPLING, 36719a81c14SSteve Longerbeam SCALING, 36819a81c14SSteve Longerbeam }; 36919a81c14SSteve Longerbeam 37019a81c14SSteve Longerbeam struct reg_value { 37119a81c14SSteve Longerbeam u16 reg_addr; 37219a81c14SSteve Longerbeam u8 val; 37319a81c14SSteve Longerbeam u8 mask; 37419a81c14SSteve Longerbeam u32 delay_ms; 37519a81c14SSteve Longerbeam }; 37619a81c14SSteve Longerbeam 3775113d5b3SJacopo Mondi struct ov5640_timings { 3783145efcdSJacopo Mondi /* Analog crop rectangle. */ 3793145efcdSJacopo Mondi struct v4l2_rect analog_crop; 3803145efcdSJacopo Mondi /* Visibile crop: from analog crop top-left corner. */ 3813145efcdSJacopo Mondi struct v4l2_rect crop; 3825113d5b3SJacopo Mondi /* Total pixels per line: width + fixed hblank. */ 383476dec01SMaxime Ripard u32 htot; 3845113d5b3SJacopo Mondi /* Default vertical blanking: frame height = height + vblank. */ 3853145efcdSJacopo Mondi u32 vblank_def; 3865113d5b3SJacopo Mondi }; 3875113d5b3SJacopo Mondi 3885113d5b3SJacopo Mondi struct ov5640_mode_info { 3895113d5b3SJacopo Mondi enum ov5640_mode_id id; 3905113d5b3SJacopo Mondi enum ov5640_downsize_mode dn_mode; 3915113d5b3SJacopo Mondi enum ov5640_pixel_rate_id pixel_rate; 3925113d5b3SJacopo Mondi 3935113d5b3SJacopo Mondi unsigned int width; 3945113d5b3SJacopo Mondi unsigned int height; 3955113d5b3SJacopo Mondi 3965113d5b3SJacopo Mondi struct ov5640_timings dvp_timings; 3975113d5b3SJacopo Mondi struct ov5640_timings csi2_timings; 3985113d5b3SJacopo Mondi 39919a81c14SSteve Longerbeam const struct reg_value *reg_data; 40019a81c14SSteve Longerbeam u32 reg_data_size; 4015113d5b3SJacopo Mondi 4025113d5b3SJacopo Mondi /* Used by s_frame_interval only. */ 4035554c80eSAdam Ford u32 max_fps; 40419f2e3e6SHugues Fruchet u32 def_fps; 40519a81c14SSteve Longerbeam }; 40619a81c14SSteve Longerbeam 40719a81c14SSteve Longerbeam struct ov5640_ctrls { 40819a81c14SSteve Longerbeam struct v4l2_ctrl_handler handler; 409cc196e48SBenoit Parrot struct v4l2_ctrl *pixel_rate; 4107a3b8d4bSJacopo Mondi struct v4l2_ctrl *link_freq; 41132979f67SJacopo Mondi struct v4l2_ctrl *hblank; 412bce93b82SJacopo Mondi struct v4l2_ctrl *vblank; 41319a81c14SSteve Longerbeam struct { 41419a81c14SSteve Longerbeam struct v4l2_ctrl *auto_exp; 41519a81c14SSteve Longerbeam struct v4l2_ctrl *exposure; 41619a81c14SSteve Longerbeam }; 41719a81c14SSteve Longerbeam struct { 41819a81c14SSteve Longerbeam struct v4l2_ctrl *auto_wb; 41919a81c14SSteve Longerbeam struct v4l2_ctrl *blue_balance; 42019a81c14SSteve Longerbeam struct v4l2_ctrl *red_balance; 42119a81c14SSteve Longerbeam }; 42219a81c14SSteve Longerbeam struct { 42319a81c14SSteve Longerbeam struct v4l2_ctrl *auto_gain; 42419a81c14SSteve Longerbeam struct v4l2_ctrl *gain; 42519a81c14SSteve Longerbeam }; 42619a81c14SSteve Longerbeam struct v4l2_ctrl *brightness; 4271068fecaSMylène Josserand struct v4l2_ctrl *light_freq; 42819a81c14SSteve Longerbeam struct v4l2_ctrl *saturation; 42919a81c14SSteve Longerbeam struct v4l2_ctrl *contrast; 43019a81c14SSteve Longerbeam struct v4l2_ctrl *hue; 43119a81c14SSteve Longerbeam struct v4l2_ctrl *test_pattern; 432ce85705aSHugues Fruchet struct v4l2_ctrl *hflip; 433ce85705aSHugues Fruchet struct v4l2_ctrl *vflip; 43419a81c14SSteve Longerbeam }; 43519a81c14SSteve Longerbeam 43619a81c14SSteve Longerbeam struct ov5640_dev { 43719a81c14SSteve Longerbeam struct i2c_client *i2c_client; 43819a81c14SSteve Longerbeam struct v4l2_subdev sd; 43919a81c14SSteve Longerbeam struct media_pad pad; 44019a81c14SSteve Longerbeam struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ 44119a81c14SSteve Longerbeam struct clk *xclk; /* system clock to OV5640 */ 44219a81c14SSteve Longerbeam u32 xclk_freq; 44319a81c14SSteve Longerbeam 44419a81c14SSteve Longerbeam struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES]; 44519a81c14SSteve Longerbeam struct gpio_desc *reset_gpio; 44619a81c14SSteve Longerbeam struct gpio_desc *pwdn_gpio; 447c3f3ba3eSHugues Fruchet bool upside_down; 44819a81c14SSteve Longerbeam 44919a81c14SSteve Longerbeam /* lock to protect all members below */ 45019a81c14SSteve Longerbeam struct mutex lock; 45119a81c14SSteve Longerbeam 45219a81c14SSteve Longerbeam struct v4l2_mbus_framefmt fmt; 453fb98e29fSHugues Fruchet bool pending_fmt_change; 45419a81c14SSteve Longerbeam 45519a81c14SSteve Longerbeam const struct ov5640_mode_info *current_mode; 456985cdcb0SHugues Fruchet const struct ov5640_mode_info *last_mode; 45719a81c14SSteve Longerbeam enum ov5640_frame_rate current_fr; 45819a81c14SSteve Longerbeam struct v4l2_fract frame_interval; 4593c28588fSJacopo Mondi s64 current_link_freq; 46019a81c14SSteve Longerbeam 46119a81c14SSteve Longerbeam struct ov5640_ctrls ctrls; 46219a81c14SSteve Longerbeam 46319a81c14SSteve Longerbeam u32 prev_sysclk, prev_hts; 46419a81c14SSteve Longerbeam u32 ae_low, ae_high, ae_target; 46519a81c14SSteve Longerbeam 46619a81c14SSteve Longerbeam bool pending_mode_change; 46719a81c14SSteve Longerbeam bool streaming; 46819a81c14SSteve Longerbeam }; 46919a81c14SSteve Longerbeam 47019a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) 47119a81c14SSteve Longerbeam { 47219a81c14SSteve Longerbeam return container_of(sd, struct ov5640_dev, sd); 47319a81c14SSteve Longerbeam } 47419a81c14SSteve Longerbeam 47519a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) 47619a81c14SSteve Longerbeam { 47719a81c14SSteve Longerbeam return &container_of(ctrl->handler, struct ov5640_dev, 47819a81c14SSteve Longerbeam ctrls.handler)->sd; 47919a81c14SSteve Longerbeam } 48019a81c14SSteve Longerbeam 4818e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) 4828e823f5cSJacopo Mondi { 4838e823f5cSJacopo Mondi return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; 4848e823f5cSJacopo Mondi } 4858e823f5cSJacopo Mondi 486a89f14bbSJacopo Mondi static inline const struct ov5640_pixfmt * 487a89f14bbSJacopo Mondi ov5640_formats(struct ov5640_dev *sensor) 488a89f14bbSJacopo Mondi { 489a89f14bbSJacopo Mondi return ov5640_is_csi2(sensor) ? ov5640_csi2_formats 490a89f14bbSJacopo Mondi : ov5640_dvp_formats; 491a89f14bbSJacopo Mondi } 492a89f14bbSJacopo Mondi 493a89f14bbSJacopo Mondi static const struct ov5640_pixfmt * 494a89f14bbSJacopo Mondi ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code) 495a89f14bbSJacopo Mondi { 496a89f14bbSJacopo Mondi const struct ov5640_pixfmt *formats = ov5640_formats(sensor); 497a89f14bbSJacopo Mondi unsigned int i; 498a89f14bbSJacopo Mondi 499a89f14bbSJacopo Mondi for (i = 0; formats[i].code; ++i) { 500a89f14bbSJacopo Mondi if (formats[i].code == code) 501a89f14bbSJacopo Mondi return &formats[i]; 502a89f14bbSJacopo Mondi } 503a89f14bbSJacopo Mondi 504a89f14bbSJacopo Mondi return &formats[0]; 505a89f14bbSJacopo Mondi } 506a89f14bbSJacopo Mondi 507a89f14bbSJacopo Mondi static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) 508a89f14bbSJacopo Mondi { 509a89f14bbSJacopo Mondi const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor, 510a89f14bbSJacopo Mondi code); 511a89f14bbSJacopo Mondi 512a89f14bbSJacopo Mondi return format->bpp; 513a89f14bbSJacopo Mondi } 514a89f14bbSJacopo Mondi 51519a81c14SSteve Longerbeam /* 51619a81c14SSteve Longerbeam * FIXME: all of these register tables are likely filled with 51719a81c14SSteve Longerbeam * entries that set the register to their power-on default values, 51819a81c14SSteve Longerbeam * and which are otherwise not touched by this driver. Those entries 51919a81c14SSteve Longerbeam * should be identified and removed to speed register load time 52019a81c14SSteve Longerbeam * over i2c. 52119a81c14SSteve Longerbeam */ 522fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */ 52390b0f355SJacopo Mondi 52468453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = { 52568453b02SGuoniu.zhou .code = MEDIA_BUS_FMT_UYVY8_1X16, 52668453b02SGuoniu.zhou .width = 640, 52768453b02SGuoniu.zhou .height = 480, 52868453b02SGuoniu.zhou .colorspace = V4L2_COLORSPACE_SRGB, 52968453b02SGuoniu.zhou .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), 53068453b02SGuoniu.zhou .quantization = V4L2_QUANTIZATION_FULL_RANGE, 53168453b02SGuoniu.zhou .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), 53268453b02SGuoniu.zhou .field = V4L2_FIELD_NONE, 53368453b02SGuoniu.zhou }; 53468453b02SGuoniu.zhou 53568453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = { 53690b0f355SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_2X8, 53790b0f355SJacopo Mondi .width = 640, 53890b0f355SJacopo Mondi .height = 480, 53990b0f355SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 54090b0f355SJacopo Mondi .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), 54190b0f355SJacopo Mondi .quantization = V4L2_QUANTIZATION_FULL_RANGE, 54290b0f355SJacopo Mondi .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), 54390b0f355SJacopo Mondi .field = V4L2_FIELD_NONE, 54490b0f355SJacopo Mondi }; 54590b0f355SJacopo Mondi 546e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = { 547decea0a9SJai Luthra {0x3103, 0x11, 0, 0}, 548576f5d4bSLad Prabhakar {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, 54919a81c14SSteve Longerbeam {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, 55019a81c14SSteve Longerbeam {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, 55119a81c14SSteve Longerbeam {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, 55219a81c14SSteve Longerbeam {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, 55319a81c14SSteve Longerbeam {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, 55419a81c14SSteve Longerbeam {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, 55519a81c14SSteve Longerbeam {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, 55619a81c14SSteve Longerbeam {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, 55719a81c14SSteve Longerbeam {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, 55819a81c14SSteve Longerbeam {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, 55919a81c14SSteve Longerbeam {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, 56019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 56119a81c14SSteve Longerbeam {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, 5623145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 56319a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 56419a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 56519a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 56619a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 56719a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 56819a81c14SSteve Longerbeam {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, 56919a81c14SSteve Longerbeam {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, 570aa4bb8b8SJacopo Mondi {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, 571a828002fSGuoniu.zhou {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x4837, 0x0a, 0, 0}, 57219a81c14SSteve Longerbeam {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, 57319a81c14SSteve Longerbeam {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, 57419a81c14SSteve Longerbeam {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, 57519a81c14SSteve Longerbeam {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, 57619a81c14SSteve Longerbeam {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, 57719a81c14SSteve Longerbeam {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, 57819a81c14SSteve Longerbeam {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, 57919a81c14SSteve Longerbeam {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, 58019a81c14SSteve Longerbeam {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, 58119a81c14SSteve Longerbeam {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, 58219a81c14SSteve Longerbeam {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, 58319a81c14SSteve Longerbeam {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, 58419a81c14SSteve Longerbeam {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, 58519a81c14SSteve Longerbeam {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, 58619a81c14SSteve Longerbeam {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, 58719a81c14SSteve Longerbeam {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, 58819a81c14SSteve Longerbeam {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, 58919a81c14SSteve Longerbeam {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, 59019a81c14SSteve Longerbeam {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, 59119a81c14SSteve Longerbeam {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, 59219a81c14SSteve Longerbeam {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, 59319a81c14SSteve Longerbeam {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, 59419a81c14SSteve Longerbeam {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, 59519a81c14SSteve Longerbeam {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, 59619a81c14SSteve Longerbeam {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, 59719a81c14SSteve Longerbeam {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, 59819a81c14SSteve Longerbeam {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, 59919a81c14SSteve Longerbeam {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, 60019a81c14SSteve Longerbeam {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, 60119a81c14SSteve Longerbeam {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, 60219a81c14SSteve Longerbeam {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, 60319a81c14SSteve Longerbeam {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, 60419a81c14SSteve Longerbeam {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, 60519a81c14SSteve Longerbeam {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, 60619a81c14SSteve Longerbeam {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, 60719a81c14SSteve Longerbeam {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, 60819a81c14SSteve Longerbeam {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, 60919a81c14SSteve Longerbeam {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, 61019a81c14SSteve Longerbeam {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, 61119a81c14SSteve Longerbeam {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, 61219a81c14SSteve Longerbeam {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, 61319a81c14SSteve Longerbeam {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, 61419a81c14SSteve Longerbeam {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, 61519a81c14SSteve Longerbeam {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, 61619a81c14SSteve Longerbeam {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, 61719a81c14SSteve Longerbeam {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, 61819a81c14SSteve Longerbeam {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, 61919a81c14SSteve Longerbeam {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, 62019a81c14SSteve Longerbeam {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, 62119a81c14SSteve Longerbeam {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, 62219a81c14SSteve Longerbeam }; 62319a81c14SSteve Longerbeam 624db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = { 625c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 62619a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 627ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 6283145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 62919a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 63019a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 63119a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 63219a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 63319a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6342b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 635a828002fSGuoniu.zhou {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 636a828002fSGuoniu.zhou {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 63719a81c14SSteve Longerbeam }; 63819a81c14SSteve Longerbeam 639086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = { 640c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, 64119a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 642ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 6433145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 64419a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 64519a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, 64619a81c14SSteve Longerbeam {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, 64719a81c14SSteve Longerbeam {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, 64819a81c14SSteve Longerbeam {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, 6492b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 65019a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, 65119a81c14SSteve Longerbeam {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, 65219a81c14SSteve Longerbeam }; 65319a81c14SSteve Longerbeam 654086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = { 655c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 65619a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 657ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 6583145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 65919a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 66019a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 66119a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 66219a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 66319a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6642b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 66519a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 666c14d107eSMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, 667c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, 66819a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 669476dec01SMaxime Ripard {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, 67019a81c14SSteve Longerbeam {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, 67119a81c14SSteve Longerbeam {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, 67219a81c14SSteve Longerbeam {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, 6732b5c18f9SChen-Yu Tsai {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, 67419a81c14SSteve Longerbeam {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, 67592b9096cSBenoit Parrot {0x4005, 0x1a, 0, 0}, 67619a81c14SSteve Longerbeam }; 67719a81c14SSteve Longerbeam 678086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { 679c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 68019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 681ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 6823145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 68319a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 68419a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 68519a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 68619a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 68719a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6882b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 68919a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 69019a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, 69119a81c14SSteve Longerbeam }; 69219a81c14SSteve Longerbeam 6935113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { 6948409d017SJacopo Mondi { 6958409d017SJacopo Mondi /* 160x120 */ 6963145efcdSJacopo Mondi .id = OV5640_MODE_QQVGA_160_120, 6973145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6983145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6995113d5b3SJacopo Mondi .width = 160, 7005113d5b3SJacopo Mondi .height = 120, 7015113d5b3SJacopo Mondi .dvp_timings = { 7023145efcdSJacopo Mondi .analog_crop = { 7033145efcdSJacopo Mondi .left = 0, 7043145efcdSJacopo Mondi .top = 4, 7053145efcdSJacopo Mondi .width = 2624, 7063145efcdSJacopo Mondi .height = 1944, 7073145efcdSJacopo Mondi }, 7083145efcdSJacopo Mondi .crop = { 7093145efcdSJacopo Mondi .left = 16, 7103145efcdSJacopo Mondi .top = 6, 7113145efcdSJacopo Mondi .width = 160, 7123145efcdSJacopo Mondi .height = 120, 7133145efcdSJacopo Mondi }, 7143145efcdSJacopo Mondi .htot = 1896, 7153145efcdSJacopo Mondi .vblank_def = 864, 7165113d5b3SJacopo Mondi }, 7175113d5b3SJacopo Mondi .csi2_timings = { 7185113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 7195113d5b3SJacopo Mondi .analog_crop = { 7205113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 7215113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 7225113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 7235113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 7245113d5b3SJacopo Mondi }, 7255113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 7265113d5b3SJacopo Mondi .crop = { 7275113d5b3SJacopo Mondi .left = 2, 7285113d5b3SJacopo Mondi .top = 4, 7295113d5b3SJacopo Mondi .width = 160, 7305113d5b3SJacopo Mondi .height = 120, 7315113d5b3SJacopo Mondi }, 732961bed9fSJacopo Mondi .htot = 1600, 733961bed9fSJacopo Mondi .vblank_def = 878, 7345113d5b3SJacopo Mondi }, 735db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 736db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 73719f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 73819f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 7398409d017SJacopo Mondi }, { 7408409d017SJacopo Mondi /* 176x144 */ 7413145efcdSJacopo Mondi .id = OV5640_MODE_QCIF_176_144, 7423145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7433145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 7445113d5b3SJacopo Mondi .width = 176, 7455113d5b3SJacopo Mondi .height = 144, 7465113d5b3SJacopo Mondi .dvp_timings = { 7473145efcdSJacopo Mondi .analog_crop = { 7483145efcdSJacopo Mondi .left = 0, 7493145efcdSJacopo Mondi .top = 4, 7503145efcdSJacopo Mondi .width = 2624, 7513145efcdSJacopo Mondi .height = 1944, 7523145efcdSJacopo Mondi }, 7533145efcdSJacopo Mondi .crop = { 7543145efcdSJacopo Mondi .left = 16, 7553145efcdSJacopo Mondi .top = 6, 7563145efcdSJacopo Mondi .width = 176, 7573145efcdSJacopo Mondi .height = 144, 7583145efcdSJacopo Mondi }, 7593145efcdSJacopo Mondi .htot = 1896, 7603145efcdSJacopo Mondi .vblank_def = 840, 7615113d5b3SJacopo Mondi }, 7625113d5b3SJacopo Mondi .csi2_timings = { 7635113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 7645113d5b3SJacopo Mondi .analog_crop = { 7655113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 7665113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 7675113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 7685113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 7695113d5b3SJacopo Mondi }, 7705113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 7715113d5b3SJacopo Mondi .crop = { 7725113d5b3SJacopo Mondi .left = 2, 7735113d5b3SJacopo Mondi .top = 4, 7745113d5b3SJacopo Mondi .width = 176, 7755113d5b3SJacopo Mondi .height = 144, 7765113d5b3SJacopo Mondi }, 777961bed9fSJacopo Mondi .htot = 1600, 778961bed9fSJacopo Mondi .vblank_def = 854, 7795113d5b3SJacopo Mondi }, 780db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 781db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 78219f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 78319f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 7848409d017SJacopo Mondi }, { 7858409d017SJacopo Mondi /* 320x240 */ 7863145efcdSJacopo Mondi .id = OV5640_MODE_QVGA_320_240, 7873145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7885113d5b3SJacopo Mondi .width = 320, 7895113d5b3SJacopo Mondi .height = 240, 7903145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 7915113d5b3SJacopo Mondi .dvp_timings = { 7923145efcdSJacopo Mondi .analog_crop = { 7933145efcdSJacopo Mondi .left = 0, 7943145efcdSJacopo Mondi .top = 4, 7953145efcdSJacopo Mondi .width = 2624, 7963145efcdSJacopo Mondi .height = 1944, 7973145efcdSJacopo Mondi }, 7983145efcdSJacopo Mondi .crop = { 7993145efcdSJacopo Mondi .left = 16, 8003145efcdSJacopo Mondi .top = 6, 8013145efcdSJacopo Mondi .width = 320, 8023145efcdSJacopo Mondi .height = 240, 8033145efcdSJacopo Mondi }, 8043145efcdSJacopo Mondi .htot = 1896, 8053145efcdSJacopo Mondi .vblank_def = 744, 8065113d5b3SJacopo Mondi }, 8075113d5b3SJacopo Mondi .csi2_timings = { 8085113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 8095113d5b3SJacopo Mondi .analog_crop = { 8105113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 8115113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 8125113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 8135113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 8145113d5b3SJacopo Mondi }, 8155113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 8165113d5b3SJacopo Mondi .crop = { 8175113d5b3SJacopo Mondi .left = 2, 8185113d5b3SJacopo Mondi .top = 4, 8195113d5b3SJacopo Mondi .width = 320, 8205113d5b3SJacopo Mondi .height = 240, 8215113d5b3SJacopo Mondi }, 822961bed9fSJacopo Mondi .htot = 1600, 823961bed9fSJacopo Mondi .vblank_def = 760, 8245113d5b3SJacopo Mondi }, 825db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 826db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 82719f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 82819f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 8298409d017SJacopo Mondi }, { 8308409d017SJacopo Mondi /* 640x480 */ 8313145efcdSJacopo Mondi .id = OV5640_MODE_VGA_640_480, 8323145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8333145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 8345113d5b3SJacopo Mondi .width = 640, 8355113d5b3SJacopo Mondi .height = 480, 8365113d5b3SJacopo Mondi .dvp_timings = { 8373145efcdSJacopo Mondi .analog_crop = { 8383145efcdSJacopo Mondi .left = 0, 8393145efcdSJacopo Mondi .top = 4, 8403145efcdSJacopo Mondi .width = 2624, 8413145efcdSJacopo Mondi .height = 1944, 8423145efcdSJacopo Mondi }, 8433145efcdSJacopo Mondi .crop = { 8443145efcdSJacopo Mondi .left = 16, 8453145efcdSJacopo Mondi .top = 6, 8463145efcdSJacopo Mondi .width = 640, 8473145efcdSJacopo Mondi .height = 480, 8483145efcdSJacopo Mondi }, 8493145efcdSJacopo Mondi .htot = 1896, 8503145efcdSJacopo Mondi .vblank_def = 600, 8515113d5b3SJacopo Mondi }, 8525113d5b3SJacopo Mondi .csi2_timings = { 8535113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 8545113d5b3SJacopo Mondi .analog_crop = { 8555113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 8565113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 8575113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 8585113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 8595113d5b3SJacopo Mondi }, 8605113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 8615113d5b3SJacopo Mondi .crop = { 8625113d5b3SJacopo Mondi .left = 2, 8635113d5b3SJacopo Mondi .top = 4, 8645113d5b3SJacopo Mondi .width = 640, 8655113d5b3SJacopo Mondi .height = 480, 8665113d5b3SJacopo Mondi }, 867961bed9fSJacopo Mondi .htot = 1600, 868961bed9fSJacopo Mondi .vblank_def = 520, 8695113d5b3SJacopo Mondi }, 870db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 871db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 87219f2e3e6SHugues Fruchet .max_fps = OV5640_60_FPS, 87319f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 8748409d017SJacopo Mondi }, { 8758409d017SJacopo Mondi /* 720x480 */ 8763145efcdSJacopo Mondi .id = OV5640_MODE_NTSC_720_480, 8773145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8785113d5b3SJacopo Mondi .width = 720, 8795113d5b3SJacopo Mondi .height = 480, 8803145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 8815113d5b3SJacopo Mondi .dvp_timings = { 8823145efcdSJacopo Mondi .analog_crop = { 8833145efcdSJacopo Mondi .left = 0, 8843145efcdSJacopo Mondi .top = 4, 8853145efcdSJacopo Mondi .width = 2624, 8863145efcdSJacopo Mondi .height = 1944, 8873145efcdSJacopo Mondi }, 8883145efcdSJacopo Mondi .crop = { 889e74ef55bSJacopo Mondi .left = 56, 8903145efcdSJacopo Mondi .top = 60, 8913145efcdSJacopo Mondi .width = 720, 8923145efcdSJacopo Mondi .height = 480, 8933145efcdSJacopo Mondi }, 8943145efcdSJacopo Mondi .htot = 1896, 8953145efcdSJacopo Mondi .vblank_def = 504, 8965113d5b3SJacopo Mondi }, 8975113d5b3SJacopo Mondi .csi2_timings = { 8985113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 8995113d5b3SJacopo Mondi .analog_crop = { 9005113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 9015113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 9025113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 9035113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 9045113d5b3SJacopo Mondi }, 9055113d5b3SJacopo Mondi .crop = { 9065113d5b3SJacopo Mondi .left = 56, 9075113d5b3SJacopo Mondi .top = 60, 9085113d5b3SJacopo Mondi .width = 720, 9095113d5b3SJacopo Mondi .height = 480, 9105113d5b3SJacopo Mondi }, 9115113d5b3SJacopo Mondi .htot = 1896, 912961bed9fSJacopo Mondi .vblank_def = 1206, 9135113d5b3SJacopo Mondi }, 914db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 915db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 91619f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 91719f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 9188409d017SJacopo Mondi }, { 9198409d017SJacopo Mondi /* 720x576 */ 9203145efcdSJacopo Mondi .id = OV5640_MODE_PAL_720_576, 9213145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 9225113d5b3SJacopo Mondi .width = 720, 9235113d5b3SJacopo Mondi .height = 576, 9243145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 9255113d5b3SJacopo Mondi .dvp_timings = { 9263145efcdSJacopo Mondi .analog_crop = { 9273145efcdSJacopo Mondi .left = 0, 9283145efcdSJacopo Mondi .top = 4, 9293145efcdSJacopo Mondi .width = 2624, 9303145efcdSJacopo Mondi .height = 1944, 9313145efcdSJacopo Mondi }, 9323145efcdSJacopo Mondi .crop = { 9333145efcdSJacopo Mondi .left = 56, 9343145efcdSJacopo Mondi .top = 6, 9353145efcdSJacopo Mondi .width = 720, 9363145efcdSJacopo Mondi .height = 576, 9373145efcdSJacopo Mondi }, 9383145efcdSJacopo Mondi .htot = 1896, 9393145efcdSJacopo Mondi .vblank_def = 408, 9405113d5b3SJacopo Mondi }, 9415113d5b3SJacopo Mondi .csi2_timings = { 9425113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 9435113d5b3SJacopo Mondi .analog_crop = { 9445113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 9455113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 9465113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 9475113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 9485113d5b3SJacopo Mondi }, 9495113d5b3SJacopo Mondi .crop = { 9505113d5b3SJacopo Mondi .left = 56, 9515113d5b3SJacopo Mondi .top = 6, 9525113d5b3SJacopo Mondi .width = 720, 9535113d5b3SJacopo Mondi .height = 576, 9545113d5b3SJacopo Mondi }, 9555113d5b3SJacopo Mondi .htot = 1896, 956961bed9fSJacopo Mondi .vblank_def = 1110, 9575113d5b3SJacopo Mondi }, 958db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 959db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 96019f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 96119f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 9628409d017SJacopo Mondi }, { 9638409d017SJacopo Mondi /* 1024x768 */ 9643145efcdSJacopo Mondi .id = OV5640_MODE_XGA_1024_768, 9653145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 9663145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 9675113d5b3SJacopo Mondi .width = 1024, 9685113d5b3SJacopo Mondi .height = 768, 9695113d5b3SJacopo Mondi .dvp_timings = { 9703145efcdSJacopo Mondi .analog_crop = { 9713145efcdSJacopo Mondi .left = 0, 9723145efcdSJacopo Mondi .top = 4, 9733145efcdSJacopo Mondi .width = 2624, 9743145efcdSJacopo Mondi .height = 1944, 9753145efcdSJacopo Mondi }, 9763145efcdSJacopo Mondi .crop = { 9773145efcdSJacopo Mondi .left = 16, 9783145efcdSJacopo Mondi .top = 6, 9793145efcdSJacopo Mondi .width = 1024, 9803145efcdSJacopo Mondi .height = 768, 9813145efcdSJacopo Mondi }, 9823145efcdSJacopo Mondi .htot = 1896, 9833145efcdSJacopo Mondi .vblank_def = 312, 9845113d5b3SJacopo Mondi }, 9855113d5b3SJacopo Mondi .csi2_timings = { 9865113d5b3SJacopo Mondi .analog_crop = { 9875113d5b3SJacopo Mondi .left = 0, 9885113d5b3SJacopo Mondi .top = 4, 9895113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 9905113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 9915113d5b3SJacopo Mondi }, 9925113d5b3SJacopo Mondi .crop = { 9935113d5b3SJacopo Mondi .left = 16, 9945113d5b3SJacopo Mondi .top = 6, 9955113d5b3SJacopo Mondi .width = 1024, 9965113d5b3SJacopo Mondi .height = 768, 9975113d5b3SJacopo Mondi }, 9985113d5b3SJacopo Mondi .htot = 1896, 999961bed9fSJacopo Mondi .vblank_def = 918, 10005113d5b3SJacopo Mondi }, 1001db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 1002db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 100319f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 100419f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 10058409d017SJacopo Mondi }, { 10068409d017SJacopo Mondi /* 1280x720 */ 10073145efcdSJacopo Mondi .id = OV5640_MODE_720P_1280_720, 10083145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 10093145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_124M, 10105113d5b3SJacopo Mondi .width = 1280, 10115113d5b3SJacopo Mondi .height = 720, 10125113d5b3SJacopo Mondi .dvp_timings = { 10133145efcdSJacopo Mondi .analog_crop = { 10143145efcdSJacopo Mondi .left = 0, 10153145efcdSJacopo Mondi .top = 250, 10163145efcdSJacopo Mondi .width = 2624, 10173145efcdSJacopo Mondi .height = 1456, 10183145efcdSJacopo Mondi }, 10193145efcdSJacopo Mondi .crop = { 10203145efcdSJacopo Mondi .left = 16, 10213145efcdSJacopo Mondi .top = 4, 10223145efcdSJacopo Mondi .width = 1280, 10233145efcdSJacopo Mondi .height = 720, 10243145efcdSJacopo Mondi }, 10253145efcdSJacopo Mondi .htot = 1892, 10263145efcdSJacopo Mondi .vblank_def = 20, 10275113d5b3SJacopo Mondi }, 10285113d5b3SJacopo Mondi .csi2_timings = { 10295113d5b3SJacopo Mondi .analog_crop = { 10305113d5b3SJacopo Mondi .left = 0, 10315113d5b3SJacopo Mondi .top = 250, 10325113d5b3SJacopo Mondi .width = 2624, 10335113d5b3SJacopo Mondi .height = 1456, 10345113d5b3SJacopo Mondi }, 10355113d5b3SJacopo Mondi .crop = { 10365113d5b3SJacopo Mondi .left = 16, 10375113d5b3SJacopo Mondi .top = 4, 10385113d5b3SJacopo Mondi .width = 1280, 10395113d5b3SJacopo Mondi .height = 720, 10405113d5b3SJacopo Mondi }, 1041961bed9fSJacopo Mondi .htot = 1600, 1042961bed9fSJacopo Mondi .vblank_def = 560, 10435113d5b3SJacopo Mondi }, 10443145efcdSJacopo Mondi .reg_data = ov5640_setting_720P_1280_720, 10453145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), 104619f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 104719f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 10488409d017SJacopo Mondi }, { 10498409d017SJacopo Mondi /* 1920x1080 */ 10503145efcdSJacopo Mondi .id = OV5640_MODE_1080P_1920_1080, 10513145efcdSJacopo Mondi .dn_mode = SCALING, 10523145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_148M, 10535113d5b3SJacopo Mondi .width = 1920, 10545113d5b3SJacopo Mondi .height = 1080, 10555113d5b3SJacopo Mondi .dvp_timings = { 10563145efcdSJacopo Mondi .analog_crop = { 10573145efcdSJacopo Mondi .left = 336, 10583145efcdSJacopo Mondi .top = 434, 10593145efcdSJacopo Mondi .width = 1952, 10603145efcdSJacopo Mondi .height = 1088, 10613145efcdSJacopo Mondi }, 10623145efcdSJacopo Mondi .crop = { 10633145efcdSJacopo Mondi .left = 16, 10643145efcdSJacopo Mondi .top = 4, 10653145efcdSJacopo Mondi .width = 1920, 10663145efcdSJacopo Mondi .height = 1080, 10673145efcdSJacopo Mondi }, 10683145efcdSJacopo Mondi .htot = 2500, 10693145efcdSJacopo Mondi .vblank_def = 40, 10705113d5b3SJacopo Mondi }, 10715113d5b3SJacopo Mondi .csi2_timings = { 10725113d5b3SJacopo Mondi /* Crop the full valid pixel array in the center. */ 10735113d5b3SJacopo Mondi .analog_crop = { 10745113d5b3SJacopo Mondi .left = 336, 10755113d5b3SJacopo Mondi .top = 434, 10765113d5b3SJacopo Mondi .width = 1952, 10775113d5b3SJacopo Mondi .height = 1088, 10785113d5b3SJacopo Mondi }, 10795113d5b3SJacopo Mondi /* Maintain a larger processing margins. */ 10805113d5b3SJacopo Mondi .crop = { 10815113d5b3SJacopo Mondi .left = 16, 10825113d5b3SJacopo Mondi .top = 4, 10835113d5b3SJacopo Mondi .width = 1920, 10845113d5b3SJacopo Mondi .height = 1080, 10855113d5b3SJacopo Mondi }, 1086961bed9fSJacopo Mondi .htot = 2234, 1087961bed9fSJacopo Mondi .vblank_def = 24, 10885113d5b3SJacopo Mondi }, 10893145efcdSJacopo Mondi .reg_data = ov5640_setting_1080P_1920_1080, 10903145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), 109119f2e3e6SHugues Fruchet .max_fps = OV5640_30_FPS, 109219f2e3e6SHugues Fruchet .def_fps = OV5640_30_FPS 10938409d017SJacopo Mondi }, { 10948409d017SJacopo Mondi /* 2592x1944 */ 10953145efcdSJacopo Mondi .id = OV5640_MODE_QSXGA_2592_1944, 10963145efcdSJacopo Mondi .dn_mode = SCALING, 10973145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_168M, 10985113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 10995113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 11005113d5b3SJacopo Mondi .dvp_timings = { 11013145efcdSJacopo Mondi .analog_crop = { 11023145efcdSJacopo Mondi .left = 0, 11033145efcdSJacopo Mondi .top = 0, 11043145efcdSJacopo Mondi .width = 2624, 11053145efcdSJacopo Mondi .height = 1952, 11063145efcdSJacopo Mondi }, 11073145efcdSJacopo Mondi .crop = { 11083145efcdSJacopo Mondi .left = 16, 11093145efcdSJacopo Mondi .top = 4, 11103145efcdSJacopo Mondi .width = 2592, 11113145efcdSJacopo Mondi .height = 1944, 11123145efcdSJacopo Mondi }, 11133145efcdSJacopo Mondi .htot = 2844, 11143145efcdSJacopo Mondi .vblank_def = 24, 11155113d5b3SJacopo Mondi }, 11165113d5b3SJacopo Mondi .csi2_timings = { 11175113d5b3SJacopo Mondi /* Give more processing margin to full resolution. */ 11185113d5b3SJacopo Mondi .analog_crop = { 11195113d5b3SJacopo Mondi .left = 0, 11205113d5b3SJacopo Mondi .top = 0, 11215113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 11225113d5b3SJacopo Mondi .height = 1952, 11235113d5b3SJacopo Mondi }, 11245113d5b3SJacopo Mondi .crop = { 11255113d5b3SJacopo Mondi .left = 16, 11265113d5b3SJacopo Mondi .top = 4, 11275113d5b3SJacopo Mondi .width = 2592, 11285113d5b3SJacopo Mondi .height = 1944, 11295113d5b3SJacopo Mondi }, 11305113d5b3SJacopo Mondi .htot = 2844, 11315113d5b3SJacopo Mondi .vblank_def = 24, 11325113d5b3SJacopo Mondi }, 11333145efcdSJacopo Mondi .reg_data = ov5640_setting_QSXGA_2592_1944, 11343145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), 113519f2e3e6SHugues Fruchet .max_fps = OV5640_15_FPS, 113619f2e3e6SHugues Fruchet .def_fps = OV5640_15_FPS 11378409d017SJacopo Mondi }, 113819a81c14SSteve Longerbeam }; 113919a81c14SSteve Longerbeam 11402de6bb97SJacopo Mondi static const struct ov5640_timings * 11412de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor, 11422de6bb97SJacopo Mondi const struct ov5640_mode_info *mode) 11432de6bb97SJacopo Mondi { 11442de6bb97SJacopo Mondi if (ov5640_is_csi2(sensor)) 11452de6bb97SJacopo Mondi return &mode->csi2_timings; 11462de6bb97SJacopo Mondi 11472de6bb97SJacopo Mondi return &mode->dvp_timings; 11482de6bb97SJacopo Mondi } 11492de6bb97SJacopo Mondi 115019a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor) 115119a81c14SSteve Longerbeam { 115219a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 115319a81c14SSteve Longerbeam struct i2c_msg msg; 115419a81c14SSteve Longerbeam u8 buf[3]; 115519a81c14SSteve Longerbeam int ret; 115619a81c14SSteve Longerbeam 115719a81c14SSteve Longerbeam if (client->addr == OV5640_DEFAULT_SLAVE_ID) 115819a81c14SSteve Longerbeam return 0; 115919a81c14SSteve Longerbeam 116019a81c14SSteve Longerbeam buf[0] = OV5640_REG_SLAVE_ID >> 8; 116119a81c14SSteve Longerbeam buf[1] = OV5640_REG_SLAVE_ID & 0xff; 116219a81c14SSteve Longerbeam buf[2] = client->addr << 1; 116319a81c14SSteve Longerbeam 116419a81c14SSteve Longerbeam msg.addr = OV5640_DEFAULT_SLAVE_ID; 116519a81c14SSteve Longerbeam msg.flags = 0; 116619a81c14SSteve Longerbeam msg.buf = buf; 116719a81c14SSteve Longerbeam msg.len = sizeof(buf); 116819a81c14SSteve Longerbeam 116919a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 117019a81c14SSteve Longerbeam if (ret < 0) { 117119a81c14SSteve Longerbeam dev_err(&client->dev, "%s: failed with %d\n", __func__, ret); 117219a81c14SSteve Longerbeam return ret; 117319a81c14SSteve Longerbeam } 117419a81c14SSteve Longerbeam 117519a81c14SSteve Longerbeam return 0; 117619a81c14SSteve Longerbeam } 117719a81c14SSteve Longerbeam 117819a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) 117919a81c14SSteve Longerbeam { 118019a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 118119a81c14SSteve Longerbeam struct i2c_msg msg; 118219a81c14SSteve Longerbeam u8 buf[3]; 118319a81c14SSteve Longerbeam int ret; 118419a81c14SSteve Longerbeam 118519a81c14SSteve Longerbeam buf[0] = reg >> 8; 118619a81c14SSteve Longerbeam buf[1] = reg & 0xff; 118719a81c14SSteve Longerbeam buf[2] = val; 118819a81c14SSteve Longerbeam 118919a81c14SSteve Longerbeam msg.addr = client->addr; 119019a81c14SSteve Longerbeam msg.flags = client->flags; 119119a81c14SSteve Longerbeam msg.buf = buf; 119219a81c14SSteve Longerbeam msg.len = sizeof(buf); 119319a81c14SSteve Longerbeam 119419a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 119519a81c14SSteve Longerbeam if (ret < 0) { 11963924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", 119719a81c14SSteve Longerbeam __func__, reg, val); 119819a81c14SSteve Longerbeam return ret; 119919a81c14SSteve Longerbeam } 120019a81c14SSteve Longerbeam 120119a81c14SSteve Longerbeam return 0; 120219a81c14SSteve Longerbeam } 120319a81c14SSteve Longerbeam 120419a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) 120519a81c14SSteve Longerbeam { 120619a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 120719a81c14SSteve Longerbeam struct i2c_msg msg[2]; 120819a81c14SSteve Longerbeam u8 buf[2]; 120919a81c14SSteve Longerbeam int ret; 121019a81c14SSteve Longerbeam 121119a81c14SSteve Longerbeam buf[0] = reg >> 8; 121219a81c14SSteve Longerbeam buf[1] = reg & 0xff; 121319a81c14SSteve Longerbeam 121419a81c14SSteve Longerbeam msg[0].addr = client->addr; 121519a81c14SSteve Longerbeam msg[0].flags = client->flags; 121619a81c14SSteve Longerbeam msg[0].buf = buf; 121719a81c14SSteve Longerbeam msg[0].len = sizeof(buf); 121819a81c14SSteve Longerbeam 121919a81c14SSteve Longerbeam msg[1].addr = client->addr; 122019a81c14SSteve Longerbeam msg[1].flags = client->flags | I2C_M_RD; 122119a81c14SSteve Longerbeam msg[1].buf = buf; 122219a81c14SSteve Longerbeam msg[1].len = 1; 122319a81c14SSteve Longerbeam 122419a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, msg, 2); 12253924c623SHugues Fruchet if (ret < 0) { 12263924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x\n", 12273924c623SHugues Fruchet __func__, reg); 122819a81c14SSteve Longerbeam return ret; 12293924c623SHugues Fruchet } 123019a81c14SSteve Longerbeam 123119a81c14SSteve Longerbeam *val = buf[0]; 123219a81c14SSteve Longerbeam return 0; 123319a81c14SSteve Longerbeam } 123419a81c14SSteve Longerbeam 123519a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) 123619a81c14SSteve Longerbeam { 123719a81c14SSteve Longerbeam u8 hi, lo; 123819a81c14SSteve Longerbeam int ret; 123919a81c14SSteve Longerbeam 124019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &hi); 124119a81c14SSteve Longerbeam if (ret) 124219a81c14SSteve Longerbeam return ret; 124319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg + 1, &lo); 124419a81c14SSteve Longerbeam if (ret) 124519a81c14SSteve Longerbeam return ret; 124619a81c14SSteve Longerbeam 124719a81c14SSteve Longerbeam *val = ((u16)hi << 8) | (u16)lo; 124819a81c14SSteve Longerbeam return 0; 124919a81c14SSteve Longerbeam } 125019a81c14SSteve Longerbeam 125119a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val) 125219a81c14SSteve Longerbeam { 125319a81c14SSteve Longerbeam int ret; 125419a81c14SSteve Longerbeam 125519a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg, val >> 8); 125619a81c14SSteve Longerbeam if (ret) 125719a81c14SSteve Longerbeam return ret; 125819a81c14SSteve Longerbeam 125919a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg + 1, val & 0xff); 126019a81c14SSteve Longerbeam } 126119a81c14SSteve Longerbeam 126219a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, 126319a81c14SSteve Longerbeam u8 mask, u8 val) 126419a81c14SSteve Longerbeam { 126519a81c14SSteve Longerbeam u8 readval; 126619a81c14SSteve Longerbeam int ret; 126719a81c14SSteve Longerbeam 126819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &readval); 126919a81c14SSteve Longerbeam if (ret) 127019a81c14SSteve Longerbeam return ret; 127119a81c14SSteve Longerbeam 127219a81c14SSteve Longerbeam readval &= ~mask; 127319a81c14SSteve Longerbeam val &= mask; 127419a81c14SSteve Longerbeam val |= readval; 127519a81c14SSteve Longerbeam 127619a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg, val); 127719a81c14SSteve Longerbeam } 127819a81c14SSteve Longerbeam 1279aa288248SMaxime Ripard /* 1280aa288248SMaxime Ripard * After trying the various combinations, reading various 1281f8a7647dSMauro Carvalho Chehab * documentations spread around the net, and from the various 1282aa288248SMaxime Ripard * feedback, the clock tree is probably as follows: 1283aa288248SMaxime Ripard * 1284aa288248SMaxime Ripard * +--------------+ 1285aa288248SMaxime Ripard * | Ext. Clock | 1286aa288248SMaxime Ripard * +-+------------+ 1287aa288248SMaxime Ripard * | +----------+ 1288aa288248SMaxime Ripard * +->| PLL1 | - reg 0x3036, for the multiplier 1289aa288248SMaxime Ripard * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider 1290aa288248SMaxime Ripard * | +--------------+ 1291aa288248SMaxime Ripard * +->| System Clock | - reg 0x3035, bits 4-7 1292aa288248SMaxime Ripard * +-+------------+ 1293aa288248SMaxime Ripard * | +--------------+ 1294aa288248SMaxime Ripard * +->| MIPI Divider | - reg 0x3035, bits 0-3 1295aa288248SMaxime Ripard * | +-+------------+ 1296aa288248SMaxime Ripard * | +----------------> MIPI SCLK 1297aa288248SMaxime Ripard * | + +-----+ 1298aa288248SMaxime Ripard * | +->| / 2 |-------> MIPI BIT CLK 1299aa288248SMaxime Ripard * | +-----+ 1300aa288248SMaxime Ripard * | +--------------+ 1301aa288248SMaxime Ripard * +->| PLL Root Div | - reg 0x3037, bit 4 1302aa288248SMaxime Ripard * +-+------------+ 1303aa288248SMaxime Ripard * | +---------+ 13044c85f628SPaul Kocialkowski * +->| Bit Div | - reg 0x3034, bits 0-3 1305aa288248SMaxime Ripard * +-+-------+ 1306aa288248SMaxime Ripard * | +-------------+ 1307aa288248SMaxime Ripard * +->| SCLK Div | - reg 0x3108, bits 0-1 1308aa288248SMaxime Ripard * | +-+-----------+ 1309aa288248SMaxime Ripard * | +---------------> SCLK 1310aa288248SMaxime Ripard * | +-------------+ 1311aa288248SMaxime Ripard * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 1312aa288248SMaxime Ripard * | +-+-----------+ 1313aa288248SMaxime Ripard * | +---------------> SCLK 2X 1314aa288248SMaxime Ripard * | +-------------+ 1315aa288248SMaxime Ripard * +->| PCLK Div | - reg 0x3108, bits 4-5 1316aa288248SMaxime Ripard * ++------------+ 1317aa288248SMaxime Ripard * + +-----------+ 1318aa288248SMaxime Ripard * +->| P_DIV | - reg 0x3035, bits 0-3 1319aa288248SMaxime Ripard * +-----+-----+ 1320aa288248SMaxime Ripard * +------------> PCLK 1321aa288248SMaxime Ripard * 13226c957ed7SJacopo Mondi * There seems to be also constraints: 1323aa288248SMaxime Ripard * - the PLL pre-divider output rate should be in the 4-27MHz range 1324aa288248SMaxime Ripard * - the PLL multiplier output rate should be in the 500-1000MHz range 1325aa288248SMaxime Ripard * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG 1326aa288248SMaxime Ripard */ 1327aa288248SMaxime Ripard 1328aa288248SMaxime Ripard /* 1329aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1330aa288248SMaxime Ripard * set to 3 in the vendor kernels. 1331aa288248SMaxime Ripard */ 1332aa288248SMaxime Ripard #define OV5640_PLL_PREDIV 3 1333aa288248SMaxime Ripard 1334aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN 4 1335aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX 252 1336aa288248SMaxime Ripard 1337aa288248SMaxime Ripard /* 1338aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 16, but the value is 1339aa288248SMaxime Ripard * always set to either 1 or 2 in the vendor kernels. 1340aa288248SMaxime Ripard */ 1341aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN 1 1342aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX 16 1343aa288248SMaxime Ripard 1344aa288248SMaxime Ripard /* 1345aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 2, but the value is always 1346aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1347aa288248SMaxime Ripard */ 1348aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV 2 1349aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) 1350aa288248SMaxime Ripard 1351aa288248SMaxime Ripard /* 1352aa288248SMaxime Ripard * We only supports 8-bit formats at the moment 1353aa288248SMaxime Ripard */ 1354aa288248SMaxime Ripard #define OV5640_BIT_DIV 2 1355aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 1356aa288248SMaxime Ripard 1357aa288248SMaxime Ripard /* 1358aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1359aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1360aa288248SMaxime Ripard */ 1361aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV 2 1362aa288248SMaxime Ripard 1363aa288248SMaxime Ripard /* 1364aa288248SMaxime Ripard * This is hardcoded so that the consistency is maintained between SCLK and 1365aa288248SMaxime Ripard * SCLK 2x. 1366aa288248SMaxime Ripard */ 1367aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) 1368aa288248SMaxime Ripard 1369aa288248SMaxime Ripard /* 1370aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1371aa288248SMaxime Ripard * set to 1 in the vendor kernels. 1372aa288248SMaxime Ripard */ 1373aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV 1 1374aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 1375aa288248SMaxime Ripard 1376aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, 1377aa288248SMaxime Ripard u8 pll_prediv, u8 pll_mult, 1378aa288248SMaxime Ripard u8 sysdiv) 1379aa288248SMaxime Ripard { 1380aa288248SMaxime Ripard unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; 1381aa288248SMaxime Ripard 1382aa288248SMaxime Ripard /* PLL1 output cannot exceed 1GHz. */ 1383aa288248SMaxime Ripard if (sysclk / 1000000 > 1000) 1384aa288248SMaxime Ripard return 0; 1385aa288248SMaxime Ripard 1386aa288248SMaxime Ripard return sysclk / sysdiv; 1387aa288248SMaxime Ripard } 1388aa288248SMaxime Ripard 1389aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, 1390aa288248SMaxime Ripard unsigned long rate, 1391aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, 1392aa288248SMaxime Ripard u8 *sysdiv) 1393aa288248SMaxime Ripard { 1394aa288248SMaxime Ripard unsigned long best = ~0; 1395aa288248SMaxime Ripard u8 best_sysdiv = 1, best_mult = 1; 1396aa288248SMaxime Ripard u8 _sysdiv, _pll_mult; 1397aa288248SMaxime Ripard 1398aa288248SMaxime Ripard for (_sysdiv = OV5640_SYSDIV_MIN; 1399aa288248SMaxime Ripard _sysdiv <= OV5640_SYSDIV_MAX; 1400aa288248SMaxime Ripard _sysdiv++) { 1401aa288248SMaxime Ripard for (_pll_mult = OV5640_PLL_MULT_MIN; 1402aa288248SMaxime Ripard _pll_mult <= OV5640_PLL_MULT_MAX; 1403aa288248SMaxime Ripard _pll_mult++) { 1404aa288248SMaxime Ripard unsigned long _rate; 1405aa288248SMaxime Ripard 1406aa288248SMaxime Ripard /* 1407aa288248SMaxime Ripard * The PLL multiplier cannot be odd if above 1408aa288248SMaxime Ripard * 127. 1409aa288248SMaxime Ripard */ 1410aa288248SMaxime Ripard if (_pll_mult > 127 && (_pll_mult % 2)) 1411aa288248SMaxime Ripard continue; 1412aa288248SMaxime Ripard 1413aa288248SMaxime Ripard _rate = ov5640_compute_sys_clk(sensor, 1414aa288248SMaxime Ripard OV5640_PLL_PREDIV, 1415aa288248SMaxime Ripard _pll_mult, _sysdiv); 1416aa288248SMaxime Ripard 1417aa288248SMaxime Ripard /* 1418aa288248SMaxime Ripard * We have reached the maximum allowed PLL1 output, 1419aa288248SMaxime Ripard * increase sysdiv. 1420aa288248SMaxime Ripard */ 14212e3df204SAdam Ford if (!_rate) 1422aa288248SMaxime Ripard break; 1423aa288248SMaxime Ripard 1424aa288248SMaxime Ripard /* 1425aa288248SMaxime Ripard * Prefer rates above the expected clock rate than 1426aa288248SMaxime Ripard * below, even if that means being less precise. 1427aa288248SMaxime Ripard */ 1428aa288248SMaxime Ripard if (_rate < rate) 1429aa288248SMaxime Ripard continue; 1430aa288248SMaxime Ripard 1431aa288248SMaxime Ripard if (abs(rate - _rate) < abs(rate - best)) { 1432aa288248SMaxime Ripard best = _rate; 1433aa288248SMaxime Ripard best_sysdiv = _sysdiv; 1434aa288248SMaxime Ripard best_mult = _pll_mult; 1435aa288248SMaxime Ripard } 1436aa288248SMaxime Ripard 1437aa288248SMaxime Ripard if (_rate == rate) 1438aa288248SMaxime Ripard goto out; 1439aa288248SMaxime Ripard } 1440aa288248SMaxime Ripard } 1441aa288248SMaxime Ripard 1442aa288248SMaxime Ripard out: 1443aa288248SMaxime Ripard *sysdiv = best_sysdiv; 1444aa288248SMaxime Ripard *pll_prediv = OV5640_PLL_PREDIV; 1445aa288248SMaxime Ripard *pll_mult = best_mult; 1446aa288248SMaxime Ripard 1447aa288248SMaxime Ripard return best; 1448aa288248SMaxime Ripard } 1449aa288248SMaxime Ripard 1450aa288248SMaxime Ripard /* 1451aa288248SMaxime Ripard * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values 1452aa288248SMaxime Ripard * for the MIPI CSI-2 output. 1453aa288248SMaxime Ripard */ 14546c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) 1455aa288248SMaxime Ripard { 14566c957ed7SJacopo Mondi u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div; 1457aa288248SMaxime Ripard u8 prediv, mult, sysdiv; 14586c957ed7SJacopo Mondi unsigned long link_freq; 14596c957ed7SJacopo Mondi unsigned long sysclk; 14606c957ed7SJacopo Mondi u8 pclk_period; 14616c957ed7SJacopo Mondi u32 sample_rate; 14626c957ed7SJacopo Mondi u32 num_lanes; 1463aa288248SMaxime Ripard int ret; 1464aa288248SMaxime Ripard 14656c957ed7SJacopo Mondi /* Use the link freq computed at ov5640_update_pixel_rate() time. */ 14666c957ed7SJacopo Mondi link_freq = sensor->current_link_freq; 14676c957ed7SJacopo Mondi 1468aa288248SMaxime Ripard /* 14696c957ed7SJacopo Mondi * - mipi_div - Additional divider for the MIPI lane clock. 14706c957ed7SJacopo Mondi * 14716c957ed7SJacopo Mondi * Higher link frequencies would make sysclk > 1GHz. 14726c957ed7SJacopo Mondi * Keep the sysclk low and do not divide in the MIPI domain. 1473aa288248SMaxime Ripard */ 14746c957ed7SJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) 14756c957ed7SJacopo Mondi mipi_div = 1; 1476aa288248SMaxime Ripard else 14776c957ed7SJacopo Mondi mipi_div = 2; 1478aa288248SMaxime Ripard 14796c957ed7SJacopo Mondi sysclk = link_freq * mipi_div; 14806c957ed7SJacopo Mondi ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); 1481aa288248SMaxime Ripard 14826c957ed7SJacopo Mondi /* 14836c957ed7SJacopo Mondi * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. 14846c957ed7SJacopo Mondi * 14856c957ed7SJacopo Mondi * - root_div = 2 (fixed) 14866c957ed7SJacopo Mondi * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 14876c957ed7SJacopo Mondi * - pclk_div = 1 (fixed) 14886c957ed7SJacopo Mondi * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) 14896c957ed7SJacopo Mondi * 14906c957ed7SJacopo Mondi * This results in the following MIPI_SCLK depending on the number 14916c957ed7SJacopo Mondi * of lanes: 14926c957ed7SJacopo Mondi * 14936c957ed7SJacopo Mondi * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK 14946c957ed7SJacopo Mondi * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK 14956c957ed7SJacopo Mondi */ 14966c957ed7SJacopo Mondi root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; 14976c957ed7SJacopo Mondi bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; 14986c957ed7SJacopo Mondi pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); 1499aa288248SMaxime Ripard 15006c957ed7SJacopo Mondi /* 15016c957ed7SJacopo Mondi * Scaler clock: 15026c957ed7SJacopo Mondi * - YUV: PCLK >= 2 * SCLK 15036c957ed7SJacopo Mondi * - RAW or JPEG: PCLK >= SCLK 15046c957ed7SJacopo Mondi * - sclk2x_div = sclk_div / 2 15056c957ed7SJacopo Mondi */ 15066c957ed7SJacopo Mondi sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); 15076c957ed7SJacopo Mondi sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); 15086c957ed7SJacopo Mondi 15096c957ed7SJacopo Mondi /* 15106c957ed7SJacopo Mondi * Set the pixel clock period expressed in ns with 1-bit decimal 15116c957ed7SJacopo Mondi * (0x01=0.5ns). 15126c957ed7SJacopo Mondi * 15136c957ed7SJacopo Mondi * The register is very briefly documented. In the OV5645 datasheet it 15146c957ed7SJacopo Mondi * is described as (2 * pclk period), and from testing it seems the 15156c957ed7SJacopo Mondi * actual definition is 2 * 8-bit sample period. 15166c957ed7SJacopo Mondi * 15176c957ed7SJacopo Mondi * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 15186c957ed7SJacopo Mondi */ 15196c957ed7SJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 15206c957ed7SJacopo Mondi sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; 15216c957ed7SJacopo Mondi pclk_period = 2000000000UL / sample_rate; 15226c957ed7SJacopo Mondi 15236c957ed7SJacopo Mondi /* Program the clock tree registers. */ 15246c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); 15256c957ed7SJacopo Mondi if (ret) 15266c957ed7SJacopo Mondi return ret; 15276c957ed7SJacopo Mondi 15286c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, 15296c957ed7SJacopo Mondi (sysdiv << 4) | mipi_div); 1530aa288248SMaxime Ripard if (ret) 1531aa288248SMaxime Ripard return ret; 1532aa288248SMaxime Ripard 1533aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); 1534aa288248SMaxime Ripard if (ret) 1535aa288248SMaxime Ripard return ret; 1536aa288248SMaxime Ripard 15376c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, 15386c957ed7SJacopo Mondi root_div | prediv); 1539aa288248SMaxime Ripard if (ret) 1540aa288248SMaxime Ripard return ret; 1541aa288248SMaxime Ripard 15426c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 15436c957ed7SJacopo Mondi (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); 15446c957ed7SJacopo Mondi if (ret) 15456c957ed7SJacopo Mondi return ret; 15466c957ed7SJacopo Mondi 15476c957ed7SJacopo Mondi return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); 15486c957ed7SJacopo Mondi } 15496c957ed7SJacopo Mondi 15506c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) 15516c957ed7SJacopo Mondi { 15523145efcdSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 15535113d5b3SJacopo Mondi const struct ov5640_timings *timings = &mode->dvp_timings; 15546c957ed7SJacopo Mondi u32 rate; 15556c957ed7SJacopo Mondi 15565113d5b3SJacopo Mondi rate = timings->htot * (timings->crop.height + timings->vblank_def); 15576c957ed7SJacopo Mondi rate *= ov5640_framerates[sensor->current_fr]; 15586c957ed7SJacopo Mondi 15596c957ed7SJacopo Mondi return rate; 1560aa288248SMaxime Ripard } 1561aa288248SMaxime Ripard 1562aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, 1563aa288248SMaxime Ripard unsigned long rate, 1564aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, 1565aa288248SMaxime Ripard u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) 1566aa288248SMaxime Ripard { 1567aa288248SMaxime Ripard unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * 1568aa288248SMaxime Ripard OV5640_PCLK_ROOT_DIV; 1569aa288248SMaxime Ripard 1570aa288248SMaxime Ripard _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, 1571aa288248SMaxime Ripard sysdiv); 1572aa288248SMaxime Ripard *pll_rdiv = OV5640_PLL_ROOT_DIV; 1573aa288248SMaxime Ripard *bit_div = OV5640_BIT_DIV; 1574aa288248SMaxime Ripard *pclk_div = OV5640_PCLK_ROOT_DIV; 1575aa288248SMaxime Ripard 1576aa288248SMaxime Ripard return _rate / *pll_rdiv / *bit_div / *pclk_div; 1577aa288248SMaxime Ripard } 1578aa288248SMaxime Ripard 15796c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) 1580aa288248SMaxime Ripard { 1581aa288248SMaxime Ripard u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; 15826c957ed7SJacopo Mondi u32 rate; 1583aa288248SMaxime Ripard int ret; 1584aa288248SMaxime Ripard 15856c957ed7SJacopo Mondi rate = ov5640_calc_pixel_rate(sensor); 1586a89f14bbSJacopo Mondi rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code); 15876c957ed7SJacopo Mondi rate /= sensor->ep.bus.parallel.bus_width; 15886c957ed7SJacopo Mondi 1589aa288248SMaxime Ripard ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, 1590aa288248SMaxime Ripard &bit_div, &pclk_div); 1591aa288248SMaxime Ripard 1592aa288248SMaxime Ripard if (bit_div == 2) 1593aa288248SMaxime Ripard bit_div = 8; 1594aa288248SMaxime Ripard 1595aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 1596aa288248SMaxime Ripard 0x0f, bit_div); 1597aa288248SMaxime Ripard if (ret) 1598aa288248SMaxime Ripard return ret; 1599aa288248SMaxime Ripard 1600aa288248SMaxime Ripard /* 1601aa288248SMaxime Ripard * We need to set sysdiv according to the clock, and to clear 1602aa288248SMaxime Ripard * the MIPI divider. 1603aa288248SMaxime Ripard */ 1604aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 1605aa288248SMaxime Ripard 0xff, sysdiv << 4); 1606aa288248SMaxime Ripard if (ret) 1607aa288248SMaxime Ripard return ret; 1608aa288248SMaxime Ripard 1609aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 1610aa288248SMaxime Ripard 0xff, mult); 1611aa288248SMaxime Ripard if (ret) 1612aa288248SMaxime Ripard return ret; 1613aa288248SMaxime Ripard 1614aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 1615aa288248SMaxime Ripard 0x1f, prediv | ((pll_rdiv - 1) << 4)); 1616aa288248SMaxime Ripard if (ret) 1617aa288248SMaxime Ripard return ret; 1618aa288248SMaxime Ripard 1619aa288248SMaxime Ripard return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, 1620aa288248SMaxime Ripard (ilog2(pclk_div) << 4)); 1621aa288248SMaxime Ripard } 1622aa288248SMaxime Ripard 16237cb013b1SChen-Yu Tsai /* set JPEG framing sizes */ 16247cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, 16257cb013b1SChen-Yu Tsai const struct ov5640_mode_info *mode) 16267cb013b1SChen-Yu Tsai { 16277cb013b1SChen-Yu Tsai int ret; 16287cb013b1SChen-Yu Tsai 16292b5c18f9SChen-Yu Tsai /* 16302b5c18f9SChen-Yu Tsai * compression mode 3 timing 16312b5c18f9SChen-Yu Tsai * 16322b5c18f9SChen-Yu Tsai * Data is transmitted with programmable width (VFIFO_HSIZE). 16332b5c18f9SChen-Yu Tsai * No padding done. Last line may have less data. Varying 16342b5c18f9SChen-Yu Tsai * number of lines per frame, depending on amount of data. 16352b5c18f9SChen-Yu Tsai */ 16362b5c18f9SChen-Yu Tsai ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); 16372b5c18f9SChen-Yu Tsai if (ret < 0) 16382b5c18f9SChen-Yu Tsai return ret; 16392b5c18f9SChen-Yu Tsai 16405113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width); 16417cb013b1SChen-Yu Tsai if (ret < 0) 16427cb013b1SChen-Yu Tsai return ret; 16437cb013b1SChen-Yu Tsai 16445113d5b3SJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height); 16457cb013b1SChen-Yu Tsai } 16467cb013b1SChen-Yu Tsai 164719a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */ 1648bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor, 1649bad1774eSJacopo Mondi const struct ov5640_mode_info *mode) 1650bad1774eSJacopo Mondi { 16515113d5b3SJacopo Mondi const struct ov5640_timings *timings; 16525113d5b3SJacopo Mondi const struct v4l2_rect *analog_crop; 16535113d5b3SJacopo Mondi const struct v4l2_rect *crop; 1654bad1774eSJacopo Mondi int ret; 1655bad1774eSJacopo Mondi 16567cb013b1SChen-Yu Tsai if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { 16577cb013b1SChen-Yu Tsai ret = ov5640_set_jpeg_timings(sensor, mode); 16587cb013b1SChen-Yu Tsai if (ret < 0) 16597cb013b1SChen-Yu Tsai return ret; 16607cb013b1SChen-Yu Tsai } 16617cb013b1SChen-Yu Tsai 16622de6bb97SJacopo Mondi timings = ov5640_timings(sensor, mode); 16635113d5b3SJacopo Mondi analog_crop = &timings->analog_crop; 16645113d5b3SJacopo Mondi crop = &timings->crop; 16655113d5b3SJacopo Mondi 16663145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, 16673145efcdSJacopo Mondi analog_crop->left); 1668bad1774eSJacopo Mondi if (ret < 0) 1669bad1774eSJacopo Mondi return ret; 1670bad1774eSJacopo Mondi 16713145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, 16723145efcdSJacopo Mondi analog_crop->top); 16733145efcdSJacopo Mondi if (ret < 0) 16743145efcdSJacopo Mondi return ret; 16753145efcdSJacopo Mondi 16763145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, 16773145efcdSJacopo Mondi analog_crop->left + analog_crop->width - 1); 16783145efcdSJacopo Mondi if (ret < 0) 16793145efcdSJacopo Mondi return ret; 16803145efcdSJacopo Mondi 16813145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, 16823145efcdSJacopo Mondi analog_crop->top + analog_crop->height - 1); 16833145efcdSJacopo Mondi if (ret < 0) 16843145efcdSJacopo Mondi return ret; 16853145efcdSJacopo Mondi 16863145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); 16873145efcdSJacopo Mondi if (ret < 0) 16883145efcdSJacopo Mondi return ret; 16893145efcdSJacopo Mondi 16903145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); 16913145efcdSJacopo Mondi if (ret < 0) 16923145efcdSJacopo Mondi return ret; 16933145efcdSJacopo Mondi 16945113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width); 16953145efcdSJacopo Mondi if (ret < 0) 16963145efcdSJacopo Mondi return ret; 16973145efcdSJacopo Mondi 16985113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height); 1699bad1774eSJacopo Mondi if (ret < 0) 1700bad1774eSJacopo Mondi return ret; 1701bad1774eSJacopo Mondi 17025113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot); 1703bad1774eSJacopo Mondi if (ret < 0) 1704bad1774eSJacopo Mondi return ret; 1705bad1774eSJacopo Mondi 17063145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 17075113d5b3SJacopo Mondi mode->height + timings->vblank_def); 17083145efcdSJacopo Mondi if (ret < 0) 17093145efcdSJacopo Mondi return ret; 17103145efcdSJacopo Mondi 17113145efcdSJacopo Mondi return 0; 1712bad1774eSJacopo Mondi } 1713bad1774eSJacopo Mondi 1714e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor, 1715e4359019SJacopo Mondi const struct reg_value *regs, unsigned int regnum) 171619a81c14SSteve Longerbeam { 171719a81c14SSteve Longerbeam unsigned int i; 171819a81c14SSteve Longerbeam u32 delay_ms; 171919a81c14SSteve Longerbeam u16 reg_addr; 172019a81c14SSteve Longerbeam u8 mask, val; 172119a81c14SSteve Longerbeam int ret = 0; 172219a81c14SSteve Longerbeam 1723e4359019SJacopo Mondi for (i = 0; i < regnum; ++i, ++regs) { 172419a81c14SSteve Longerbeam delay_ms = regs->delay_ms; 172519a81c14SSteve Longerbeam reg_addr = regs->reg_addr; 172619a81c14SSteve Longerbeam val = regs->val; 172719a81c14SSteve Longerbeam mask = regs->mask; 172819a81c14SSteve Longerbeam 17293b987d70SLad Prabhakar /* remain in power down mode for DVP */ 17303b987d70SLad Prabhakar if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && 17313b987d70SLad Prabhakar val == OV5640_REG_SYS_CTRL0_SW_PWUP && 17328e823f5cSJacopo Mondi !ov5640_is_csi2(sensor)) 17333b987d70SLad Prabhakar continue; 17343b987d70SLad Prabhakar 173519a81c14SSteve Longerbeam if (mask) 173619a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, reg_addr, mask, val); 173719a81c14SSteve Longerbeam else 173819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg_addr, val); 173919a81c14SSteve Longerbeam if (ret) 174019a81c14SSteve Longerbeam break; 174119a81c14SSteve Longerbeam 174219a81c14SSteve Longerbeam if (delay_ms) 174319a81c14SSteve Longerbeam usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); 174419a81c14SSteve Longerbeam } 174519a81c14SSteve Longerbeam } 174619a81c14SSteve Longerbeam 1747dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) 1748dc29a1c1SHugues Fruchet { 1749dc29a1c1SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 1750dc29a1c1SHugues Fruchet BIT(0), on ? 0 : BIT(0)); 1751dc29a1c1SHugues Fruchet } 1752dc29a1c1SHugues Fruchet 175319a81c14SSteve Longerbeam /* read exposure, in number of line periods */ 175419a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor) 175519a81c14SSteve Longerbeam { 175619a81c14SSteve Longerbeam int exp, ret; 175719a81c14SSteve Longerbeam u8 temp; 175819a81c14SSteve Longerbeam 175919a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp); 176019a81c14SSteve Longerbeam if (ret) 176119a81c14SSteve Longerbeam return ret; 176219a81c14SSteve Longerbeam exp = ((int)temp & 0x0f) << 16; 176319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp); 176419a81c14SSteve Longerbeam if (ret) 176519a81c14SSteve Longerbeam return ret; 176619a81c14SSteve Longerbeam exp |= ((int)temp << 8); 176719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp); 176819a81c14SSteve Longerbeam if (ret) 176919a81c14SSteve Longerbeam return ret; 177019a81c14SSteve Longerbeam exp |= (int)temp; 177119a81c14SSteve Longerbeam 177219a81c14SSteve Longerbeam return exp >> 4; 177319a81c14SSteve Longerbeam } 177419a81c14SSteve Longerbeam 177519a81c14SSteve Longerbeam /* write exposure, given number of line periods */ 177619a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure) 177719a81c14SSteve Longerbeam { 177819a81c14SSteve Longerbeam int ret; 177919a81c14SSteve Longerbeam 178019a81c14SSteve Longerbeam exposure <<= 4; 178119a81c14SSteve Longerbeam 178219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 178319a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_LO, 178419a81c14SSteve Longerbeam exposure & 0xff); 178519a81c14SSteve Longerbeam if (ret) 178619a81c14SSteve Longerbeam return ret; 178719a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 178819a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_MED, 178919a81c14SSteve Longerbeam (exposure >> 8) & 0xff); 179019a81c14SSteve Longerbeam if (ret) 179119a81c14SSteve Longerbeam return ret; 179219a81c14SSteve Longerbeam return ov5640_write_reg(sensor, 179319a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_HI, 179419a81c14SSteve Longerbeam (exposure >> 16) & 0x0f); 179519a81c14SSteve Longerbeam } 179619a81c14SSteve Longerbeam 179719a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor) 179819a81c14SSteve Longerbeam { 179919a81c14SSteve Longerbeam u16 gain; 180019a81c14SSteve Longerbeam int ret; 180119a81c14SSteve Longerbeam 180219a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain); 180319a81c14SSteve Longerbeam if (ret) 180419a81c14SSteve Longerbeam return ret; 180519a81c14SSteve Longerbeam 180619a81c14SSteve Longerbeam return gain & 0x3ff; 180719a81c14SSteve Longerbeam } 180819a81c14SSteve Longerbeam 18093cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain) 18103cca8ef5SHugues Fruchet { 18113cca8ef5SHugues Fruchet return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, 18123cca8ef5SHugues Fruchet (u16)gain & 0x3ff); 18133cca8ef5SHugues Fruchet } 18143cca8ef5SHugues Fruchet 18153cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) 18163cca8ef5SHugues Fruchet { 18173cca8ef5SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 18183cca8ef5SHugues Fruchet BIT(1), on ? 0 : BIT(1)); 18193cca8ef5SHugues Fruchet } 18203cca8ef5SHugues Fruchet 1821f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) 1822f22996dbSHugues Fruchet { 18233b987d70SLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? 18243b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWUP : 18253b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWDN); 1826f22996dbSHugues Fruchet } 1827f22996dbSHugues Fruchet 1828f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) 182919a81c14SSteve Longerbeam { 183019a81c14SSteve Longerbeam int ret; 183119a81c14SSteve Longerbeam 1832aa4bb8b8SJacopo Mondi /* 1833aa4bb8b8SJacopo Mondi * Enable/disable the MIPI interface 1834aa4bb8b8SJacopo Mondi * 1835aa4bb8b8SJacopo Mondi * 0x300e = on ? 0x45 : 0x40 1836aa4bb8b8SJacopo Mondi * 1837aa4bb8b8SJacopo Mondi * FIXME: the sensor manual (version 2.03) reports 1838aa4bb8b8SJacopo Mondi * [7:5] = 000 : 1 data lane mode 1839aa4bb8b8SJacopo Mondi * [7:5] = 001 : 2 data lanes mode 1840aa4bb8b8SJacopo Mondi * But this settings do not work, while the following ones 1841aa4bb8b8SJacopo Mondi * have been validated for 2 data lanes mode. 1842aa4bb8b8SJacopo Mondi * 1843aa4bb8b8SJacopo Mondi * [7:5] = 010 : 2 data lanes mode 1844aa4bb8b8SJacopo Mondi * [4] = 0 : Power up MIPI HS Tx 1845aa4bb8b8SJacopo Mondi * [3] = 0 : Power up MIPI LS Rx 1846aa4bb8b8SJacopo Mondi * [2] = 1/0 : MIPI interface enable/disable 1847aa4bb8b8SJacopo Mondi * [1:0] = 01/00: FIXME: 'debug' 1848aa4bb8b8SJacopo Mondi */ 1849aa4bb8b8SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 1850aa4bb8b8SJacopo Mondi on ? 0x45 : 0x40); 185119a81c14SSteve Longerbeam if (ret) 185219a81c14SSteve Longerbeam return ret; 185319a81c14SSteve Longerbeam 185419a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01, 185519a81c14SSteve Longerbeam on ? 0x00 : 0x0f); 185619a81c14SSteve Longerbeam } 185719a81c14SSteve Longerbeam 185819a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor) 185919a81c14SSteve Longerbeam { 186019a81c14SSteve Longerbeam /* calculate sysclk */ 186119a81c14SSteve Longerbeam u32 xvclk = sensor->xclk_freq / 10000; 186219a81c14SSteve Longerbeam u32 multiplier, prediv, VCO, sysdiv, pll_rdiv; 186319a81c14SSteve Longerbeam u32 sclk_rdiv_map[] = {1, 2, 4, 8}; 186419a81c14SSteve Longerbeam u32 bit_div2x = 1, sclk_rdiv, sysclk; 186519a81c14SSteve Longerbeam u8 temp1, temp2; 186619a81c14SSteve Longerbeam int ret; 186719a81c14SSteve Longerbeam 186819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1); 186919a81c14SSteve Longerbeam if (ret) 187019a81c14SSteve Longerbeam return ret; 187119a81c14SSteve Longerbeam temp2 = temp1 & 0x0f; 187219a81c14SSteve Longerbeam if (temp2 == 8 || temp2 == 10) 187319a81c14SSteve Longerbeam bit_div2x = temp2 / 2; 187419a81c14SSteve Longerbeam 187519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1); 187619a81c14SSteve Longerbeam if (ret) 187719a81c14SSteve Longerbeam return ret; 187819a81c14SSteve Longerbeam sysdiv = temp1 >> 4; 187919a81c14SSteve Longerbeam if (sysdiv == 0) 188019a81c14SSteve Longerbeam sysdiv = 16; 188119a81c14SSteve Longerbeam 188219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1); 188319a81c14SSteve Longerbeam if (ret) 188419a81c14SSteve Longerbeam return ret; 188519a81c14SSteve Longerbeam multiplier = temp1; 188619a81c14SSteve Longerbeam 188719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1); 188819a81c14SSteve Longerbeam if (ret) 188919a81c14SSteve Longerbeam return ret; 189019a81c14SSteve Longerbeam prediv = temp1 & 0x0f; 189119a81c14SSteve Longerbeam pll_rdiv = ((temp1 >> 4) & 0x01) + 1; 189219a81c14SSteve Longerbeam 189319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1); 189419a81c14SSteve Longerbeam if (ret) 189519a81c14SSteve Longerbeam return ret; 189619a81c14SSteve Longerbeam temp2 = temp1 & 0x03; 189719a81c14SSteve Longerbeam sclk_rdiv = sclk_rdiv_map[temp2]; 189819a81c14SSteve Longerbeam 189919a81c14SSteve Longerbeam if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x) 190019a81c14SSteve Longerbeam return -EINVAL; 190119a81c14SSteve Longerbeam 190219a81c14SSteve Longerbeam VCO = xvclk * multiplier / prediv; 190319a81c14SSteve Longerbeam 190419a81c14SSteve Longerbeam sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv; 190519a81c14SSteve Longerbeam 190619a81c14SSteve Longerbeam return sysclk; 190719a81c14SSteve Longerbeam } 190819a81c14SSteve Longerbeam 190919a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor) 191019a81c14SSteve Longerbeam { 191119a81c14SSteve Longerbeam /* read HTS from register settings */ 191219a81c14SSteve Longerbeam u8 mode; 191319a81c14SSteve Longerbeam int ret; 191419a81c14SSteve Longerbeam 191519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode); 191619a81c14SSteve Longerbeam if (ret) 191719a81c14SSteve Longerbeam return ret; 191819a81c14SSteve Longerbeam mode &= 0xfb; 191919a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode); 192019a81c14SSteve Longerbeam } 192119a81c14SSteve Longerbeam 192219a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor) 192319a81c14SSteve Longerbeam { 192419a81c14SSteve Longerbeam /* read HTS from register settings */ 192519a81c14SSteve Longerbeam u16 hts; 192619a81c14SSteve Longerbeam int ret; 192719a81c14SSteve Longerbeam 192819a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts); 192919a81c14SSteve Longerbeam if (ret) 193019a81c14SSteve Longerbeam return ret; 193119a81c14SSteve Longerbeam return hts; 193219a81c14SSteve Longerbeam } 193319a81c14SSteve Longerbeam 193419a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor) 193519a81c14SSteve Longerbeam { 193619a81c14SSteve Longerbeam u16 vts; 193719a81c14SSteve Longerbeam int ret; 193819a81c14SSteve Longerbeam 193919a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts); 194019a81c14SSteve Longerbeam if (ret) 194119a81c14SSteve Longerbeam return ret; 194219a81c14SSteve Longerbeam return vts; 194319a81c14SSteve Longerbeam } 194419a81c14SSteve Longerbeam 194519a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts) 194619a81c14SSteve Longerbeam { 194719a81c14SSteve Longerbeam return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts); 194819a81c14SSteve Longerbeam } 194919a81c14SSteve Longerbeam 195019a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor) 195119a81c14SSteve Longerbeam { 195219a81c14SSteve Longerbeam /* get banding filter value */ 195319a81c14SSteve Longerbeam int ret, light_freq = 0; 195419a81c14SSteve Longerbeam u8 temp, temp1; 195519a81c14SSteve Longerbeam 195619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp); 195719a81c14SSteve Longerbeam if (ret) 195819a81c14SSteve Longerbeam return ret; 195919a81c14SSteve Longerbeam 196019a81c14SSteve Longerbeam if (temp & 0x80) { 196119a81c14SSteve Longerbeam /* manual */ 196219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00, 196319a81c14SSteve Longerbeam &temp1); 196419a81c14SSteve Longerbeam if (ret) 196519a81c14SSteve Longerbeam return ret; 196619a81c14SSteve Longerbeam if (temp1 & 0x04) { 196719a81c14SSteve Longerbeam /* 50Hz */ 196819a81c14SSteve Longerbeam light_freq = 50; 196919a81c14SSteve Longerbeam } else { 197019a81c14SSteve Longerbeam /* 60Hz */ 197119a81c14SSteve Longerbeam light_freq = 60; 197219a81c14SSteve Longerbeam } 197319a81c14SSteve Longerbeam } else { 197419a81c14SSteve Longerbeam /* auto */ 197519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C, 197619a81c14SSteve Longerbeam &temp1); 197719a81c14SSteve Longerbeam if (ret) 197819a81c14SSteve Longerbeam return ret; 197919a81c14SSteve Longerbeam 198019a81c14SSteve Longerbeam if (temp1 & 0x01) { 198119a81c14SSteve Longerbeam /* 50Hz */ 198219a81c14SSteve Longerbeam light_freq = 50; 198319a81c14SSteve Longerbeam } else { 198419a81c14SSteve Longerbeam /* 60Hz */ 198519a81c14SSteve Longerbeam } 198619a81c14SSteve Longerbeam } 198719a81c14SSteve Longerbeam 198819a81c14SSteve Longerbeam return light_freq; 198919a81c14SSteve Longerbeam } 199019a81c14SSteve Longerbeam 199119a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) 199219a81c14SSteve Longerbeam { 199319a81c14SSteve Longerbeam u32 band_step60, max_band60, band_step50, max_band50, prev_vts; 199419a81c14SSteve Longerbeam int ret; 199519a81c14SSteve Longerbeam 199619a81c14SSteve Longerbeam /* read preview PCLK */ 199719a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 199819a81c14SSteve Longerbeam if (ret < 0) 199919a81c14SSteve Longerbeam return ret; 200019a81c14SSteve Longerbeam if (ret == 0) 200119a81c14SSteve Longerbeam return -EINVAL; 200219a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 200319a81c14SSteve Longerbeam /* read preview HTS */ 200419a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 200519a81c14SSteve Longerbeam if (ret < 0) 200619a81c14SSteve Longerbeam return ret; 200719a81c14SSteve Longerbeam if (ret == 0) 200819a81c14SSteve Longerbeam return -EINVAL; 200919a81c14SSteve Longerbeam sensor->prev_hts = ret; 201019a81c14SSteve Longerbeam 201119a81c14SSteve Longerbeam /* read preview VTS */ 201219a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 201319a81c14SSteve Longerbeam if (ret < 0) 201419a81c14SSteve Longerbeam return ret; 201519a81c14SSteve Longerbeam prev_vts = ret; 201619a81c14SSteve Longerbeam 201719a81c14SSteve Longerbeam /* calculate banding filter */ 201819a81c14SSteve Longerbeam /* 60Hz */ 201919a81c14SSteve Longerbeam band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; 202019a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60); 202119a81c14SSteve Longerbeam if (ret) 202219a81c14SSteve Longerbeam return ret; 202319a81c14SSteve Longerbeam if (!band_step60) 202419a81c14SSteve Longerbeam return -EINVAL; 202519a81c14SSteve Longerbeam max_band60 = (int)((prev_vts - 4) / band_step60); 202619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60); 202719a81c14SSteve Longerbeam if (ret) 202819a81c14SSteve Longerbeam return ret; 202919a81c14SSteve Longerbeam 203019a81c14SSteve Longerbeam /* 50Hz */ 203119a81c14SSteve Longerbeam band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts; 203219a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50); 203319a81c14SSteve Longerbeam if (ret) 203419a81c14SSteve Longerbeam return ret; 203519a81c14SSteve Longerbeam if (!band_step50) 203619a81c14SSteve Longerbeam return -EINVAL; 203719a81c14SSteve Longerbeam max_band50 = (int)((prev_vts - 4) / band_step50); 203819a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50); 203919a81c14SSteve Longerbeam } 204019a81c14SSteve Longerbeam 204119a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) 204219a81c14SSteve Longerbeam { 204319a81c14SSteve Longerbeam /* stable in high */ 204419a81c14SSteve Longerbeam u32 fast_high, fast_low; 204519a81c14SSteve Longerbeam int ret; 204619a81c14SSteve Longerbeam 204719a81c14SSteve Longerbeam sensor->ae_low = target * 23 / 25; /* 0.92 */ 204819a81c14SSteve Longerbeam sensor->ae_high = target * 27 / 25; /* 1.08 */ 204919a81c14SSteve Longerbeam 205019a81c14SSteve Longerbeam fast_high = sensor->ae_high << 1; 205119a81c14SSteve Longerbeam if (fast_high > 255) 205219a81c14SSteve Longerbeam fast_high = 255; 205319a81c14SSteve Longerbeam 205419a81c14SSteve Longerbeam fast_low = sensor->ae_low >> 1; 205519a81c14SSteve Longerbeam 205619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high); 205719a81c14SSteve Longerbeam if (ret) 205819a81c14SSteve Longerbeam return ret; 205919a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low); 206019a81c14SSteve Longerbeam if (ret) 206119a81c14SSteve Longerbeam return ret; 206219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high); 206319a81c14SSteve Longerbeam if (ret) 206419a81c14SSteve Longerbeam return ret; 206519a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low); 206619a81c14SSteve Longerbeam if (ret) 206719a81c14SSteve Longerbeam return ret; 206819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high); 206919a81c14SSteve Longerbeam if (ret) 207019a81c14SSteve Longerbeam return ret; 207119a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); 207219a81c14SSteve Longerbeam } 207319a81c14SSteve Longerbeam 2074c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor) 207519a81c14SSteve Longerbeam { 207619a81c14SSteve Longerbeam u8 temp; 207719a81c14SSteve Longerbeam int ret; 207819a81c14SSteve Longerbeam 207919a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); 208019a81c14SSteve Longerbeam if (ret) 208119a81c14SSteve Longerbeam return ret; 2082c2c3f42dSHugues Fruchet 2083c2c3f42dSHugues Fruchet return temp & BIT(0); 208419a81c14SSteve Longerbeam } 208519a81c14SSteve Longerbeam 2086ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) 2087ce85705aSHugues Fruchet { 2088ce85705aSHugues Fruchet int ret; 2089ce85705aSHugues Fruchet 2090ce85705aSHugues Fruchet /* 2091ce85705aSHugues Fruchet * TIMING TC REG21: 2092ce85705aSHugues Fruchet * - [0]: Horizontal binning enable 2093ce85705aSHugues Fruchet */ 2094ce85705aSHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 2095ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 2096ce85705aSHugues Fruchet if (ret) 2097ce85705aSHugues Fruchet return ret; 2098ce85705aSHugues Fruchet /* 2099ce85705aSHugues Fruchet * TIMING TC REG20: 2100ce85705aSHugues Fruchet * - [0]: Undocumented, but hardcoded init sequences 2101ce85705aSHugues Fruchet * are always setting REG21/REG20 bit 0 to same value... 2102ce85705aSHugues Fruchet */ 2103ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 2104ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 2105ce85705aSHugues Fruchet } 2106ce85705aSHugues Fruchet 210719a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) 210819a81c14SSteve Longerbeam { 21098670d70aSHugues Fruchet struct i2c_client *client = sensor->i2c_client; 211019a81c14SSteve Longerbeam u8 temp, channel = virtual_channel; 211119a81c14SSteve Longerbeam int ret; 211219a81c14SSteve Longerbeam 21138670d70aSHugues Fruchet if (channel > 3) { 21148670d70aSHugues Fruchet dev_err(&client->dev, 21158670d70aSHugues Fruchet "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", 21168670d70aSHugues Fruchet __func__, channel); 211719a81c14SSteve Longerbeam return -EINVAL; 21188670d70aSHugues Fruchet } 211919a81c14SSteve Longerbeam 212019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); 212119a81c14SSteve Longerbeam if (ret) 212219a81c14SSteve Longerbeam return ret; 212319a81c14SSteve Longerbeam temp &= ~(3 << 6); 212419a81c14SSteve Longerbeam temp |= (channel << 6); 212519a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); 212619a81c14SSteve Longerbeam } 212719a81c14SSteve Longerbeam 212819a81c14SSteve Longerbeam static const struct ov5640_mode_info * 2129b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest) 213019a81c14SSteve Longerbeam { 21313c4a7372SHugues Fruchet const struct ov5640_mode_info *mode; 213219a81c14SSteve Longerbeam 2133086c25f8SMaxime Ripard mode = v4l2_find_nearest_size(ov5640_mode_data, 2134086c25f8SMaxime Ripard ARRAY_SIZE(ov5640_mode_data), 21355113d5b3SJacopo Mondi width, height, width, height); 213619a81c14SSteve Longerbeam 21373c4a7372SHugues Fruchet if (!mode || 21383145efcdSJacopo Mondi (!nearest && 21395113d5b3SJacopo Mondi (mode->width != width || mode->height != height))) 21403c4a7372SHugues Fruchet return NULL; 214119a81c14SSteve Longerbeam 214219a81c14SSteve Longerbeam return mode; 214319a81c14SSteve Longerbeam } 214419a81c14SSteve Longerbeam 214519a81c14SSteve Longerbeam /* 214619a81c14SSteve Longerbeam * sensor changes between scaling and subsampling, go through 214719a81c14SSteve Longerbeam * exposure calculation 214819a81c14SSteve Longerbeam */ 214941d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, 215041d8d7f5SHugues Fruchet const struct ov5640_mode_info *mode) 215119a81c14SSteve Longerbeam { 215219a81c14SSteve Longerbeam u32 prev_shutter, prev_gain16; 215319a81c14SSteve Longerbeam u32 cap_shutter, cap_gain16; 215419a81c14SSteve Longerbeam u32 cap_sysclk, cap_hts, cap_vts; 215519a81c14SSteve Longerbeam u32 light_freq, cap_bandfilt, cap_maxband; 215619a81c14SSteve Longerbeam u32 cap_gain16_shutter; 215719a81c14SSteve Longerbeam u8 average; 215819a81c14SSteve Longerbeam int ret; 215919a81c14SSteve Longerbeam 216041d8d7f5SHugues Fruchet if (!mode->reg_data) 216119a81c14SSteve Longerbeam return -EINVAL; 216219a81c14SSteve Longerbeam 216319a81c14SSteve Longerbeam /* read preview shutter */ 216419a81c14SSteve Longerbeam ret = ov5640_get_exposure(sensor); 216519a81c14SSteve Longerbeam if (ret < 0) 216619a81c14SSteve Longerbeam return ret; 216719a81c14SSteve Longerbeam prev_shutter = ret; 2168c2c3f42dSHugues Fruchet ret = ov5640_get_binning(sensor); 216919a81c14SSteve Longerbeam if (ret < 0) 217019a81c14SSteve Longerbeam return ret; 217119a81c14SSteve Longerbeam if (ret && mode->id != OV5640_MODE_720P_1280_720 && 217219a81c14SSteve Longerbeam mode->id != OV5640_MODE_1080P_1920_1080) 217319a81c14SSteve Longerbeam prev_shutter *= 2; 217419a81c14SSteve Longerbeam 217519a81c14SSteve Longerbeam /* read preview gain */ 217619a81c14SSteve Longerbeam ret = ov5640_get_gain(sensor); 217719a81c14SSteve Longerbeam if (ret < 0) 217819a81c14SSteve Longerbeam return ret; 217919a81c14SSteve Longerbeam prev_gain16 = ret; 218019a81c14SSteve Longerbeam 218119a81c14SSteve Longerbeam /* get average */ 218219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average); 218319a81c14SSteve Longerbeam if (ret) 218419a81c14SSteve Longerbeam return ret; 218519a81c14SSteve Longerbeam 218619a81c14SSteve Longerbeam /* turn off night mode for capture */ 218719a81c14SSteve Longerbeam ret = ov5640_set_night_mode(sensor); 218819a81c14SSteve Longerbeam if (ret < 0) 218919a81c14SSteve Longerbeam return ret; 219019a81c14SSteve Longerbeam 219119a81c14SSteve Longerbeam /* Write capture setting */ 2192e4359019SJacopo Mondi ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); 2193e4359019SJacopo Mondi ret = ov5640_set_timings(sensor, mode); 219419a81c14SSteve Longerbeam if (ret < 0) 219519a81c14SSteve Longerbeam return ret; 219619a81c14SSteve Longerbeam 219719a81c14SSteve Longerbeam /* read capture VTS */ 219819a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 219919a81c14SSteve Longerbeam if (ret < 0) 220019a81c14SSteve Longerbeam return ret; 220119a81c14SSteve Longerbeam cap_vts = ret; 220219a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 220319a81c14SSteve Longerbeam if (ret < 0) 220419a81c14SSteve Longerbeam return ret; 220519a81c14SSteve Longerbeam if (ret == 0) 220619a81c14SSteve Longerbeam return -EINVAL; 220719a81c14SSteve Longerbeam cap_hts = ret; 220819a81c14SSteve Longerbeam 220919a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 221019a81c14SSteve Longerbeam if (ret < 0) 221119a81c14SSteve Longerbeam return ret; 221219a81c14SSteve Longerbeam if (ret == 0) 221319a81c14SSteve Longerbeam return -EINVAL; 221419a81c14SSteve Longerbeam cap_sysclk = ret; 221519a81c14SSteve Longerbeam 221619a81c14SSteve Longerbeam /* calculate capture banding filter */ 221719a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 221819a81c14SSteve Longerbeam if (ret < 0) 221919a81c14SSteve Longerbeam return ret; 222019a81c14SSteve Longerbeam light_freq = ret; 222119a81c14SSteve Longerbeam 222219a81c14SSteve Longerbeam if (light_freq == 60) { 222319a81c14SSteve Longerbeam /* 60Hz */ 222419a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120; 222519a81c14SSteve Longerbeam } else { 222619a81c14SSteve Longerbeam /* 50Hz */ 222719a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts; 222819a81c14SSteve Longerbeam } 222919a81c14SSteve Longerbeam 223019a81c14SSteve Longerbeam if (!sensor->prev_sysclk) { 223119a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 223219a81c14SSteve Longerbeam if (ret < 0) 223319a81c14SSteve Longerbeam return ret; 223419a81c14SSteve Longerbeam if (ret == 0) 223519a81c14SSteve Longerbeam return -EINVAL; 223619a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 223719a81c14SSteve Longerbeam } 223819a81c14SSteve Longerbeam 223919a81c14SSteve Longerbeam if (!cap_bandfilt) 224019a81c14SSteve Longerbeam return -EINVAL; 224119a81c14SSteve Longerbeam 224219a81c14SSteve Longerbeam cap_maxband = (int)((cap_vts - 4) / cap_bandfilt); 224319a81c14SSteve Longerbeam 224419a81c14SSteve Longerbeam /* calculate capture shutter/gain16 */ 224519a81c14SSteve Longerbeam if (average > sensor->ae_low && average < sensor->ae_high) { 224619a81c14SSteve Longerbeam /* in stable range */ 224719a81c14SSteve Longerbeam cap_gain16_shutter = 224819a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 224919a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 225019a81c14SSteve Longerbeam sensor->prev_hts / cap_hts * 225119a81c14SSteve Longerbeam sensor->ae_target / average; 225219a81c14SSteve Longerbeam } else { 225319a81c14SSteve Longerbeam cap_gain16_shutter = 225419a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 225519a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 225619a81c14SSteve Longerbeam sensor->prev_hts / cap_hts; 225719a81c14SSteve Longerbeam } 225819a81c14SSteve Longerbeam 225919a81c14SSteve Longerbeam /* gain to shutter */ 226019a81c14SSteve Longerbeam if (cap_gain16_shutter < (cap_bandfilt * 16)) { 226119a81c14SSteve Longerbeam /* shutter < 1/100 */ 226219a81c14SSteve Longerbeam cap_shutter = cap_gain16_shutter / 16; 226319a81c14SSteve Longerbeam if (cap_shutter < 1) 226419a81c14SSteve Longerbeam cap_shutter = 1; 226519a81c14SSteve Longerbeam 226619a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 226719a81c14SSteve Longerbeam if (cap_gain16 < 16) 226819a81c14SSteve Longerbeam cap_gain16 = 16; 226919a81c14SSteve Longerbeam } else { 227019a81c14SSteve Longerbeam if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) { 227119a81c14SSteve Longerbeam /* exposure reach max */ 227219a81c14SSteve Longerbeam cap_shutter = cap_bandfilt * cap_maxband; 227319a81c14SSteve Longerbeam if (!cap_shutter) 227419a81c14SSteve Longerbeam return -EINVAL; 227519a81c14SSteve Longerbeam 227619a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 227719a81c14SSteve Longerbeam } else { 227819a81c14SSteve Longerbeam /* 1/100 < (cap_shutter = n/100) =< max */ 227919a81c14SSteve Longerbeam cap_shutter = 228019a81c14SSteve Longerbeam ((int)(cap_gain16_shutter / 16 / cap_bandfilt)) 228119a81c14SSteve Longerbeam * cap_bandfilt; 228219a81c14SSteve Longerbeam if (!cap_shutter) 228319a81c14SSteve Longerbeam return -EINVAL; 228419a81c14SSteve Longerbeam 228519a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 228619a81c14SSteve Longerbeam } 228719a81c14SSteve Longerbeam } 228819a81c14SSteve Longerbeam 228919a81c14SSteve Longerbeam /* set capture gain */ 22903cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, cap_gain16); 229119a81c14SSteve Longerbeam if (ret) 229219a81c14SSteve Longerbeam return ret; 229319a81c14SSteve Longerbeam 229419a81c14SSteve Longerbeam /* write capture shutter */ 229519a81c14SSteve Longerbeam if (cap_shutter > (cap_vts - 4)) { 229619a81c14SSteve Longerbeam cap_vts = cap_shutter + 4; 229719a81c14SSteve Longerbeam ret = ov5640_set_vts(sensor, cap_vts); 229819a81c14SSteve Longerbeam if (ret < 0) 229919a81c14SSteve Longerbeam return ret; 230019a81c14SSteve Longerbeam } 230119a81c14SSteve Longerbeam 230219a81c14SSteve Longerbeam /* set exposure */ 23033cca8ef5SHugues Fruchet return ov5640_set_exposure(sensor, cap_shutter); 230419a81c14SSteve Longerbeam } 230519a81c14SSteve Longerbeam 230619a81c14SSteve Longerbeam /* 230719a81c14SSteve Longerbeam * if sensor changes inside scaling or subsampling 230819a81c14SSteve Longerbeam * change mode directly 230919a81c14SSteve Longerbeam */ 231019a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor, 23113cca8ef5SHugues Fruchet const struct ov5640_mode_info *mode) 231219a81c14SSteve Longerbeam { 231341d8d7f5SHugues Fruchet if (!mode->reg_data) 231419a81c14SSteve Longerbeam return -EINVAL; 231519a81c14SSteve Longerbeam 231619a81c14SSteve Longerbeam /* Write capture setting */ 2317e4359019SJacopo Mondi ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); 2318e4359019SJacopo Mondi return ov5640_set_timings(sensor, mode); 231919a81c14SSteve Longerbeam } 232019a81c14SSteve Longerbeam 2321985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor) 232219a81c14SSteve Longerbeam { 232319a81c14SSteve Longerbeam const struct ov5640_mode_info *mode = sensor->current_mode; 2324985cdcb0SHugues Fruchet const struct ov5640_mode_info *orig_mode = sensor->last_mode; 232519a81c14SSteve Longerbeam enum ov5640_downsize_mode dn_mode, orig_dn_mode; 23263cca8ef5SHugues Fruchet bool auto_gain = sensor->ctrls.auto_gain->val == 1; 2327dc29a1c1SHugues Fruchet bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; 232819a81c14SSteve Longerbeam int ret; 232919a81c14SSteve Longerbeam 233019a81c14SSteve Longerbeam dn_mode = mode->dn_mode; 233119a81c14SSteve Longerbeam orig_dn_mode = orig_mode->dn_mode; 233219a81c14SSteve Longerbeam 233319a81c14SSteve Longerbeam /* auto gain and exposure must be turned off when changing modes */ 23343cca8ef5SHugues Fruchet if (auto_gain) { 23353cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, false); 233619a81c14SSteve Longerbeam if (ret) 233719a81c14SSteve Longerbeam return ret; 23383cca8ef5SHugues Fruchet } 2339bf4a4b51SMaxime Ripard 23403cca8ef5SHugues Fruchet if (auto_exp) { 2341dc29a1c1SHugues Fruchet ret = ov5640_set_autoexposure(sensor, false); 234219a81c14SSteve Longerbeam if (ret) 23433cca8ef5SHugues Fruchet goto restore_auto_gain; 23443cca8ef5SHugues Fruchet } 234519a81c14SSteve Longerbeam 23466c957ed7SJacopo Mondi if (ov5640_is_csi2(sensor)) 23476c957ed7SJacopo Mondi ret = ov5640_set_mipi_pclk(sensor); 23486c957ed7SJacopo Mondi else 23496c957ed7SJacopo Mondi ret = ov5640_set_dvp_pclk(sensor); 2350aa288248SMaxime Ripard if (ret < 0) 2351aa288248SMaxime Ripard return 0; 2352aa288248SMaxime Ripard 235319a81c14SSteve Longerbeam if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || 235419a81c14SSteve Longerbeam (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { 235519a81c14SSteve Longerbeam /* 235619a81c14SSteve Longerbeam * change between subsampling and scaling 23573cca8ef5SHugues Fruchet * go through exposure calculation 235819a81c14SSteve Longerbeam */ 235919a81c14SSteve Longerbeam ret = ov5640_set_mode_exposure_calc(sensor, mode); 236019a81c14SSteve Longerbeam } else { 236119a81c14SSteve Longerbeam /* 236219a81c14SSteve Longerbeam * change inside subsampling or scaling 236319a81c14SSteve Longerbeam * download firmware directly 236419a81c14SSteve Longerbeam */ 23653cca8ef5SHugues Fruchet ret = ov5640_set_mode_direct(sensor, mode); 236619a81c14SSteve Longerbeam } 236719a81c14SSteve Longerbeam if (ret < 0) 23683cca8ef5SHugues Fruchet goto restore_auto_exp_gain; 23693cca8ef5SHugues Fruchet 23703cca8ef5SHugues Fruchet /* restore auto gain and exposure */ 23713cca8ef5SHugues Fruchet if (auto_gain) 23723cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 23733cca8ef5SHugues Fruchet if (auto_exp) 23743cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 237519a81c14SSteve Longerbeam 2376ce85705aSHugues Fruchet ret = ov5640_set_binning(sensor, dn_mode != SCALING); 2377ce85705aSHugues Fruchet if (ret < 0) 2378ce85705aSHugues Fruchet return ret; 237919a81c14SSteve Longerbeam ret = ov5640_set_ae_target(sensor, sensor->ae_target); 238019a81c14SSteve Longerbeam if (ret < 0) 238119a81c14SSteve Longerbeam return ret; 238219a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 238319a81c14SSteve Longerbeam if (ret < 0) 238419a81c14SSteve Longerbeam return ret; 238519a81c14SSteve Longerbeam ret = ov5640_set_bandingfilter(sensor); 238619a81c14SSteve Longerbeam if (ret < 0) 238719a81c14SSteve Longerbeam return ret; 238819a81c14SSteve Longerbeam ret = ov5640_set_virtual_channel(sensor); 238919a81c14SSteve Longerbeam if (ret < 0) 239019a81c14SSteve Longerbeam return ret; 239119a81c14SSteve Longerbeam 239219a81c14SSteve Longerbeam sensor->pending_mode_change = false; 2393985cdcb0SHugues Fruchet sensor->last_mode = mode; 239419a81c14SSteve Longerbeam 239519a81c14SSteve Longerbeam return 0; 23963cca8ef5SHugues Fruchet 23973cca8ef5SHugues Fruchet restore_auto_exp_gain: 23983cca8ef5SHugues Fruchet if (auto_exp) 23993cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 24003cca8ef5SHugues Fruchet restore_auto_gain: 24013cca8ef5SHugues Fruchet if (auto_gain) 24023cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 24033cca8ef5SHugues Fruchet 24043cca8ef5SHugues Fruchet return ret; 240519a81c14SSteve Longerbeam } 240619a81c14SSteve Longerbeam 240719ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor, 240819ad26f9SAkinobu Mita struct v4l2_mbus_framefmt *format); 240919ad26f9SAkinobu Mita 241019a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */ 241119a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor) 241219a81c14SSteve Longerbeam { 241319a81c14SSteve Longerbeam int ret; 241419a81c14SSteve Longerbeam 241519a81c14SSteve Longerbeam /* first load the initial register values */ 2416e4359019SJacopo Mondi ov5640_load_regs(sensor, ov5640_init_setting, 2417e4359019SJacopo Mondi ARRAY_SIZE(ov5640_init_setting)); 241819a81c14SSteve Longerbeam 24198f57c2f8SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 24207851fe7aSMaxime Ripard (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | 24217851fe7aSMaxime Ripard ilog2(OV5640_SCLK_ROOT_DIV)); 24228f57c2f8SMaxime Ripard if (ret) 24238f57c2f8SMaxime Ripard return ret; 24248f57c2f8SMaxime Ripard 242519a81c14SSteve Longerbeam /* now restore the last capture mode */ 2426985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 242719ad26f9SAkinobu Mita if (ret < 0) 242819ad26f9SAkinobu Mita return ret; 242919ad26f9SAkinobu Mita 243019ad26f9SAkinobu Mita return ov5640_set_framefmt(sensor, &sensor->fmt); 243119a81c14SSteve Longerbeam } 243219a81c14SSteve Longerbeam 243319a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable) 243419a81c14SSteve Longerbeam { 24351fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); 243619a81c14SSteve Longerbeam } 243719a81c14SSteve Longerbeam 2438d7ff6913SJai Luthra /* 2439d7ff6913SJai Luthra * From section 2.7 power up sequence: 2440d7ff6913SJai Luthra * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down 2441d7ff6913SJai Luthra * t3 >= 1ms Delay from PWDN pull down to RESETB pull up 2442d7ff6913SJai Luthra * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable 2443d7ff6913SJai Luthra * 2444d7ff6913SJai Luthra * Some modules don't expose RESETB/PWDN pins directly, instead providing a 2445d7ff6913SJai Luthra * "PWUP" GPIO which is wired through appropriate delays and inverters to the 2446d7ff6913SJai Luthra * pins. 2447d7ff6913SJai Luthra * 2448d7ff6913SJai Luthra * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we 2449d7ff6913SJai Luthra * should still toggle the pwdn_gpio below with the appropriate delays, while 2450d7ff6913SJai Luthra * the calls to reset_gpio will be ignored. 2451d7ff6913SJai Luthra */ 2452d7ff6913SJai Luthra static void ov5640_powerup_sequence(struct ov5640_dev *sensor) 245319a81c14SSteve Longerbeam { 2454decea0a9SJai Luthra if (sensor->pwdn_gpio) { 2455*a210df33SMarek Vasut gpiod_set_value_cansleep(sensor->reset_gpio, 1); 245619a81c14SSteve Longerbeam 245719a81c14SSteve Longerbeam /* camera power cycle */ 245819a81c14SSteve Longerbeam ov5640_power(sensor, false); 2459*a210df33SMarek Vasut usleep_range(5000, 10000); /* t2 */ 246019a81c14SSteve Longerbeam ov5640_power(sensor, true); 2461*a210df33SMarek Vasut usleep_range(1000, 2000); /* t3 */ 246219a81c14SSteve Longerbeam 24631fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 2464decea0a9SJai Luthra } else { 2465decea0a9SJai Luthra /* software reset */ 2466decea0a9SJai Luthra ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, 2467decea0a9SJai Luthra OV5640_REG_SYS_CTRL0_SW_RST); 2468decea0a9SJai Luthra } 2469*a210df33SMarek Vasut usleep_range(20000, 25000); /* t4 */ 2470decea0a9SJai Luthra 2471decea0a9SJai Luthra /* 2472decea0a9SJai Luthra * software standby: allows registers programming; 2473decea0a9SJai Luthra * exit at restore_mode() for CSI, s_stream(1) for DVP 2474decea0a9SJai Luthra */ 2475decea0a9SJai Luthra ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, 2476decea0a9SJai Luthra OV5640_REG_SYS_CTRL0_SW_PWDN); 247719a81c14SSteve Longerbeam } 247819a81c14SSteve Longerbeam 24790f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor) 248019a81c14SSteve Longerbeam { 24810f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 24820f7acb52SHugues Fruchet int ret; 248319a81c14SSteve Longerbeam 24840f7acb52SHugues Fruchet ret = clk_prepare_enable(sensor->xclk); 24850f7acb52SHugues Fruchet if (ret) { 24860f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable clock\n", 24870f7acb52SHugues Fruchet __func__); 24880f7acb52SHugues Fruchet return ret; 24890f7acb52SHugues Fruchet } 249019a81c14SSteve Longerbeam 249119a81c14SSteve Longerbeam ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, 249219a81c14SSteve Longerbeam sensor->supplies); 24930f7acb52SHugues Fruchet if (ret) { 24940f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable regulators\n", 24950f7acb52SHugues Fruchet __func__); 249619a81c14SSteve Longerbeam goto xclk_off; 24970f7acb52SHugues Fruchet } 249819a81c14SSteve Longerbeam 2499d7ff6913SJai Luthra ov5640_powerup_sequence(sensor); 250019a81c14SSteve Longerbeam 250119a81c14SSteve Longerbeam ret = ov5640_init_slave_id(sensor); 250219a81c14SSteve Longerbeam if (ret) 250319a81c14SSteve Longerbeam goto power_off; 250419a81c14SSteve Longerbeam 25050f7acb52SHugues Fruchet return 0; 25060f7acb52SHugues Fruchet 25070f7acb52SHugues Fruchet power_off: 25080f7acb52SHugues Fruchet ov5640_power(sensor, false); 25090f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 25100f7acb52SHugues Fruchet xclk_off: 25110f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 25120f7acb52SHugues Fruchet return ret; 25130f7acb52SHugues Fruchet } 25140f7acb52SHugues Fruchet 25150f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor) 25160f7acb52SHugues Fruchet { 25170f7acb52SHugues Fruchet ov5640_power(sensor, false); 25180f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 25190f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 25200f7acb52SHugues Fruchet } 25210f7acb52SHugues Fruchet 2522b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) 2523b1751ae6SLad Prabhakar { 2524b1751ae6SLad Prabhakar int ret; 2525b1751ae6SLad Prabhakar 2526b1751ae6SLad Prabhakar if (!on) { 2527b1751ae6SLad Prabhakar /* Reset MIPI bus settings to their default values. */ 2528b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2529b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04); 2530b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00); 2531b1751ae6SLad Prabhakar return 0; 2532b1751ae6SLad Prabhakar } 2533b1751ae6SLad Prabhakar 2534b1751ae6SLad Prabhakar /* 2535b1751ae6SLad Prabhakar * Power up MIPI HS Tx and LS Rx; 2 data lanes mode 2536b1751ae6SLad Prabhakar * 2537b1751ae6SLad Prabhakar * 0x300e = 0x40 2538b1751ae6SLad Prabhakar * [7:5] = 010 : 2 data lanes mode (see FIXME note in 2539b1751ae6SLad Prabhakar * "ov5640_set_stream_mipi()") 2540b1751ae6SLad Prabhakar * [4] = 0 : Power up MIPI HS Tx 2541b1751ae6SLad Prabhakar * [3] = 0 : Power up MIPI LS Rx 254298cb72d3SMarek Vasut * [2] = 1 : MIPI interface enabled 2543b1751ae6SLad Prabhakar */ 254498cb72d3SMarek Vasut ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x44); 2545b1751ae6SLad Prabhakar if (ret) 2546b1751ae6SLad Prabhakar return ret; 2547b1751ae6SLad Prabhakar 2548b1751ae6SLad Prabhakar /* 2549b1751ae6SLad Prabhakar * Gate clock and set LP11 in 'no packets mode' (idle) 2550b1751ae6SLad Prabhakar * 2551b1751ae6SLad Prabhakar * 0x4800 = 0x24 2552b1751ae6SLad Prabhakar * [5] = 1 : Gate clock when 'no packets' 2553b1751ae6SLad Prabhakar * [2] = 1 : MIPI bus in LP11 when 'no packets' 2554b1751ae6SLad Prabhakar */ 2555b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24); 2556b1751ae6SLad Prabhakar if (ret) 2557b1751ae6SLad Prabhakar return ret; 2558b1751ae6SLad Prabhakar 2559b1751ae6SLad Prabhakar /* 2560b1751ae6SLad Prabhakar * Set data lanes and clock in LP11 when 'sleeping' 2561b1751ae6SLad Prabhakar * 2562b1751ae6SLad Prabhakar * 0x3019 = 0x70 2563b1751ae6SLad Prabhakar * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' 2564b1751ae6SLad Prabhakar * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' 2565b1751ae6SLad Prabhakar * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' 2566b1751ae6SLad Prabhakar */ 2567b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70); 2568b1751ae6SLad Prabhakar if (ret) 2569b1751ae6SLad Prabhakar return ret; 2570b1751ae6SLad Prabhakar 2571b1751ae6SLad Prabhakar /* Give lanes some time to coax into LP11 state. */ 2572b1751ae6SLad Prabhakar usleep_range(500, 1000); 2573b1751ae6SLad Prabhakar 2574b1751ae6SLad Prabhakar return 0; 2575b1751ae6SLad Prabhakar } 2576b1751ae6SLad Prabhakar 2577576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) 2578576f5d4bSLad Prabhakar { 2579311a6408SLad Prabhakar unsigned int flags = sensor->ep.bus.parallel.flags; 258068579b32SHugues Fruchet bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; 258168579b32SHugues Fruchet u8 polarities = 0; 2582576f5d4bSLad Prabhakar int ret; 2583576f5d4bSLad Prabhakar 2584576f5d4bSLad Prabhakar if (!on) { 2585576f5d4bSLad Prabhakar /* Reset settings to their default values. */ 258668579b32SHugues Fruchet ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); 2587311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2588311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); 2589576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); 2590576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00); 2591576f5d4bSLad Prabhakar return 0; 2592576f5d4bSLad Prabhakar } 2593576f5d4bSLad Prabhakar 2594576f5d4bSLad Prabhakar /* 2595311a6408SLad Prabhakar * Note about parallel port configuration. 2596311a6408SLad Prabhakar * 2597311a6408SLad Prabhakar * When configured in parallel mode, the OV5640 will 2598311a6408SLad Prabhakar * output 10 bits data on DVP data lines [9:0]. 2599311a6408SLad Prabhakar * If only 8 bits data are wanted, the 8 bits data lines 2600311a6408SLad Prabhakar * of the camera interface must be physically connected 2601311a6408SLad Prabhakar * on the DVP data lines [9:2]. 2602311a6408SLad Prabhakar * 2603311a6408SLad Prabhakar * Control lines polarity can be configured through 2604311a6408SLad Prabhakar * devicetree endpoint control lines properties. 2605311a6408SLad Prabhakar * If no endpoint control lines properties are set, 2606311a6408SLad Prabhakar * polarity will be as below: 2607311a6408SLad Prabhakar * - VSYNC: active high 2608311a6408SLad Prabhakar * - HREF: active low 2609311a6408SLad Prabhakar * - PCLK: active low 261068579b32SHugues Fruchet * 261168579b32SHugues Fruchet * VSYNC & HREF are not configured if BT656 bus mode is selected 2612311a6408SLad Prabhakar */ 261368579b32SHugues Fruchet 261468579b32SHugues Fruchet /* 261568579b32SHugues Fruchet * BT656 embedded synchronization configuration 261668579b32SHugues Fruchet * 261768579b32SHugues Fruchet * CCIR656 CTRL00 261868579b32SHugues Fruchet * - [7]: SYNC code selection (0: auto generate sync code, 261968579b32SHugues Fruchet * 1: sync code from regs 0x4732-0x4735) 262068579b32SHugues Fruchet * - [6]: f value in CCIR656 SYNC code when fixed f value 262168579b32SHugues Fruchet * - [5]: Fixed f value 262268579b32SHugues Fruchet * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, 262368579b32SHugues Fruchet * 01: data from regs 0x4736-0x4738, 10: always keep 0) 262468579b32SHugues Fruchet * - [1]: Clip data disable 262568579b32SHugues Fruchet * - [0]: CCIR656 mode enable 262668579b32SHugues Fruchet * 262768579b32SHugues Fruchet * Default CCIR656 SAV/EAV mode with default codes 262868579b32SHugues Fruchet * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: 262968579b32SHugues Fruchet * - CCIR656 mode enable 263068579b32SHugues Fruchet * - auto generation of sync codes 263168579b32SHugues Fruchet * - blank toggle data 1'h040/1'h200 263268579b32SHugues Fruchet * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) 263368579b32SHugues Fruchet */ 263468579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 263568579b32SHugues Fruchet bt656 ? 0x01 : 0x00); 263668579b32SHugues Fruchet if (ret) 263768579b32SHugues Fruchet return ret; 263868579b32SHugues Fruchet 2639311a6408SLad Prabhakar /* 2640311a6408SLad Prabhakar * configure parallel port control lines polarity 2641311a6408SLad Prabhakar * 2642311a6408SLad Prabhakar * POLARITY CTRL0 2643311a6408SLad Prabhakar * - [5]: PCLK polarity (0: active low, 1: active high) 2644311a6408SLad Prabhakar * - [1]: HREF polarity (0: active low, 1: active high) 2645311a6408SLad Prabhakar * - [0]: VSYNC polarity (mismatch here between 2646311a6408SLad Prabhakar * datasheet and hardware, 0 is active high 2647311a6408SLad Prabhakar * and 1 is active low...) 2648311a6408SLad Prabhakar */ 264968579b32SHugues Fruchet if (!bt656) { 2650311a6408SLad Prabhakar if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 265168579b32SHugues Fruchet polarities |= BIT(1); 2652311a6408SLad Prabhakar if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 265368579b32SHugues Fruchet polarities |= BIT(0); 265468579b32SHugues Fruchet } 265568579b32SHugues Fruchet if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 265668579b32SHugues Fruchet polarities |= BIT(5); 2657311a6408SLad Prabhakar 265868579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); 2659311a6408SLad Prabhakar if (ret) 2660311a6408SLad Prabhakar return ret; 2661311a6408SLad Prabhakar 2662311a6408SLad Prabhakar /* 266368579b32SHugues Fruchet * powerdown MIPI TX/RX PHY & enable DVP 2664311a6408SLad Prabhakar * 2665311a6408SLad Prabhakar * MIPI CONTROL 00 266668579b32SHugues Fruchet * [4] = 1 : Power down MIPI HS Tx 266768579b32SHugues Fruchet * [3] = 1 : Power down MIPI LS Rx 266868579b32SHugues Fruchet * [2] = 0 : DVP enable (MIPI disable) 2669311a6408SLad Prabhakar */ 2670311a6408SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); 2671311a6408SLad Prabhakar if (ret) 2672311a6408SLad Prabhakar return ret; 2673311a6408SLad Prabhakar 2674311a6408SLad Prabhakar /* 2675576f5d4bSLad Prabhakar * enable VSYNC/HREF/PCLK DVP control lines 2676576f5d4bSLad Prabhakar * & D[9:6] DVP data lines 2677576f5d4bSLad Prabhakar * 2678576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 01 2679576f5d4bSLad Prabhakar * - 6: VSYNC output enable 2680576f5d4bSLad Prabhakar * - 5: HREF output enable 2681576f5d4bSLad Prabhakar * - 4: PCLK output enable 2682576f5d4bSLad Prabhakar * - [3:0]: D[9:6] output enable 2683576f5d4bSLad Prabhakar */ 26844039b037SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 268568579b32SHugues Fruchet bt656 ? 0x1f : 0x7f); 2686576f5d4bSLad Prabhakar if (ret) 2687576f5d4bSLad Prabhakar return ret; 2688576f5d4bSLad Prabhakar 2689576f5d4bSLad Prabhakar /* 2690576f5d4bSLad Prabhakar * enable D[5:0] DVP data lines 2691576f5d4bSLad Prabhakar * 2692576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 02 2693576f5d4bSLad Prabhakar * - [7:2]: D[5:0] output enable 2694576f5d4bSLad Prabhakar */ 2695576f5d4bSLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc); 2696576f5d4bSLad Prabhakar } 2697576f5d4bSLad Prabhakar 26980f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on) 26990f7acb52SHugues Fruchet { 27000f7acb52SHugues Fruchet int ret = 0; 27010f7acb52SHugues Fruchet 27020f7acb52SHugues Fruchet if (on) { 27030f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 27040f7acb52SHugues Fruchet if (ret) 27050f7acb52SHugues Fruchet return ret; 27060f7acb52SHugues Fruchet 270719a81c14SSteve Longerbeam ret = ov5640_restore_mode(sensor); 270819a81c14SSteve Longerbeam if (ret) 270919a81c14SSteve Longerbeam goto power_off; 2710b1751ae6SLad Prabhakar } 271119a81c14SSteve Longerbeam 2712576f5d4bSLad Prabhakar if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 2713b1751ae6SLad Prabhakar ret = ov5640_set_power_mipi(sensor, on); 2714576f5d4bSLad Prabhakar else 2715576f5d4bSLad Prabhakar ret = ov5640_set_power_dvp(sensor, on); 2716b1751ae6SLad Prabhakar if (ret) 2717b1751ae6SLad Prabhakar goto power_off; 2718aa4bb8b8SJacopo Mondi 2719b1751ae6SLad Prabhakar if (!on) 2720aa4bb8b8SJacopo Mondi ov5640_set_power_off(sensor); 272119a81c14SSteve Longerbeam 272219a81c14SSteve Longerbeam return 0; 272319a81c14SSteve Longerbeam 272419a81c14SSteve Longerbeam power_off: 27250f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 272619a81c14SSteve Longerbeam return ret; 272719a81c14SSteve Longerbeam } 272819a81c14SSteve Longerbeam 272985644a9bSPaul Elder static int ov5640_sensor_suspend(struct device *dev) 273019a81c14SSteve Longerbeam { 273185644a9bSPaul Elder struct v4l2_subdev *sd = dev_get_drvdata(dev); 273285644a9bSPaul Elder struct ov5640_dev *ov5640 = to_ov5640_dev(sd); 273319a81c14SSteve Longerbeam 273485644a9bSPaul Elder return ov5640_set_power(ov5640, false); 273519a81c14SSteve Longerbeam } 273619a81c14SSteve Longerbeam 273785644a9bSPaul Elder static int ov5640_sensor_resume(struct device *dev) 273885644a9bSPaul Elder { 273985644a9bSPaul Elder struct v4l2_subdev *sd = dev_get_drvdata(dev); 274085644a9bSPaul Elder struct ov5640_dev *ov5640 = to_ov5640_dev(sd); 274119a81c14SSteve Longerbeam 274285644a9bSPaul Elder return ov5640_set_power(ov5640, true); 274319a81c14SSteve Longerbeam } 274419a81c14SSteve Longerbeam 274585644a9bSPaul Elder /* --------------- Subdev Operations --------------- */ 274619a81c14SSteve Longerbeam 274719a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor, 274819a81c14SSteve Longerbeam struct v4l2_fract *fi, 2749f33b56d3SGuoniu.zhou const struct ov5640_mode_info *mode_info) 275019a81c14SSteve Longerbeam { 2751f33b56d3SGuoniu.zhou const struct ov5640_mode_info *mode = mode_info; 27526530a5ebSJagan Teki enum ov5640_frame_rate rate = OV5640_15_FPS; 2753f6cc192fSMaxime Ripard int minfps, maxfps, best_fps, fps; 2754f6cc192fSMaxime Ripard int i; 275519a81c14SSteve Longerbeam 275619a81c14SSteve Longerbeam minfps = ov5640_framerates[OV5640_15_FPS]; 2757f33b56d3SGuoniu.zhou maxfps = ov5640_framerates[mode->max_fps]; 275819a81c14SSteve Longerbeam 275919a81c14SSteve Longerbeam if (fi->numerator == 0) { 276019a81c14SSteve Longerbeam fi->denominator = maxfps; 276119a81c14SSteve Longerbeam fi->numerator = 1; 2762f33b56d3SGuoniu.zhou rate = mode->max_fps; 2763e823fb16SMaxime Ripard goto find_mode; 276419a81c14SSteve Longerbeam } 276519a81c14SSteve Longerbeam 2766f6cc192fSMaxime Ripard fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), 2767f6cc192fSMaxime Ripard minfps, maxfps); 2768f6cc192fSMaxime Ripard 2769f6cc192fSMaxime Ripard best_fps = minfps; 2770f6cc192fSMaxime Ripard for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { 2771f6cc192fSMaxime Ripard int curr_fps = ov5640_framerates[i]; 2772f6cc192fSMaxime Ripard 2773f6cc192fSMaxime Ripard if (abs(curr_fps - fps) < abs(best_fps - fps)) { 2774f6cc192fSMaxime Ripard best_fps = curr_fps; 2775f6cc192fSMaxime Ripard rate = i; 2776f6cc192fSMaxime Ripard } 2777f6cc192fSMaxime Ripard } 277819a81c14SSteve Longerbeam 277919a81c14SSteve Longerbeam fi->numerator = 1; 2780f6cc192fSMaxime Ripard fi->denominator = best_fps; 278119a81c14SSteve Longerbeam 2782e823fb16SMaxime Ripard find_mode: 2783f33b56d3SGuoniu.zhou mode = ov5640_find_mode(sensor, mode->width, mode->height, false); 27845a3ad937SMaxime Ripard return mode ? rate : -EINVAL; 278519a81c14SSteve Longerbeam } 278619a81c14SSteve Longerbeam 278719a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd, 27880d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 278919a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 279019a81c14SSteve Longerbeam { 279119a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 279219a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt; 279319a81c14SSteve Longerbeam 279419a81c14SSteve Longerbeam if (format->pad != 0) 279519a81c14SSteve Longerbeam return -EINVAL; 279619a81c14SSteve Longerbeam 279719a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 279819a81c14SSteve Longerbeam 279919a81c14SSteve Longerbeam if (format->which == V4L2_SUBDEV_FORMAT_TRY) 28000d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 280119a81c14SSteve Longerbeam format->pad); 280219a81c14SSteve Longerbeam else 280319a81c14SSteve Longerbeam fmt = &sensor->fmt; 280419a81c14SSteve Longerbeam 280519a81c14SSteve Longerbeam format->format = *fmt; 280619a81c14SSteve Longerbeam 280719a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 280819a81c14SSteve Longerbeam 280919a81c14SSteve Longerbeam return 0; 281019a81c14SSteve Longerbeam } 281119a81c14SSteve Longerbeam 281219a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, 281319a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt, 281419a81c14SSteve Longerbeam const struct ov5640_mode_info **new_mode) 281519a81c14SSteve Longerbeam { 281619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 281719a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 2818a89f14bbSJacopo Mondi const struct ov5640_pixfmt *pixfmt; 2819a89f14bbSJacopo Mondi unsigned int bpp; 282019a81c14SSteve Longerbeam 2821b6ae5022SJacopo Mondi mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true); 282219a81c14SSteve Longerbeam if (!mode) 282319a81c14SSteve Longerbeam return -EINVAL; 2824dd81b8ffSJacopo Mondi 2825a89f14bbSJacopo Mondi pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code); 2826a89f14bbSJacopo Mondi bpp = pixfmt->bpp; 2827a89f14bbSJacopo Mondi 2828dd81b8ffSJacopo Mondi /* 2829dd81b8ffSJacopo Mondi * Adjust mode according to bpp: 2830dd81b8ffSJacopo Mondi * - 8bpp modes work for resolution >= 1280x720 2831dd81b8ffSJacopo Mondi * - 24bpp modes work resolution < 1280x720 2832dd81b8ffSJacopo Mondi */ 2833dd81b8ffSJacopo Mondi if (bpp == 8 && mode->width < 1280) 2834dd81b8ffSJacopo Mondi mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720]; 2835dd81b8ffSJacopo Mondi else if (bpp == 24 && mode->width > 1024) 2836dd81b8ffSJacopo Mondi mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768]; 2837dd81b8ffSJacopo Mondi 28385113d5b3SJacopo Mondi fmt->width = mode->width; 28395113d5b3SJacopo Mondi fmt->height = mode->height; 284019a81c14SSteve Longerbeam 284119a81c14SSteve Longerbeam if (new_mode) 284219a81c14SSteve Longerbeam *new_mode = mode; 2843e3ee691dSHugues Fruchet 2844a89f14bbSJacopo Mondi fmt->code = pixfmt->code; 2845a89f14bbSJacopo Mondi fmt->colorspace = pixfmt->colorspace; 2846e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 2847e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 2848e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 2849e3ee691dSHugues Fruchet 285019a81c14SSteve Longerbeam return 0; 285119a81c14SSteve Longerbeam } 285219a81c14SSteve Longerbeam 28533c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) 28543c28588fSJacopo Mondi { 28553c28588fSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 28563c28588fSJacopo Mondi enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; 28573c28588fSJacopo Mondi struct v4l2_mbus_framefmt *fmt = &sensor->fmt; 285832979f67SJacopo Mondi const struct ov5640_timings *timings; 2859bce93b82SJacopo Mondi s32 exposure_val, exposure_max; 286032979f67SJacopo Mondi unsigned int hblank; 28613c28588fSJacopo Mondi unsigned int i = 0; 28623c28588fSJacopo Mondi u32 pixel_rate; 28633c28588fSJacopo Mondi s64 link_freq; 28643c28588fSJacopo Mondi u32 num_lanes; 286519f2e3e6SHugues Fruchet u32 vblank; 28663c28588fSJacopo Mondi u32 bpp; 28673c28588fSJacopo Mondi 28683c28588fSJacopo Mondi /* 28693c28588fSJacopo Mondi * Update the pixel rate control value. 28703c28588fSJacopo Mondi * 28713c28588fSJacopo Mondi * For DVP mode, maintain the pixel rate calculation using fixed FPS. 28723c28588fSJacopo Mondi */ 28733c28588fSJacopo Mondi if (!ov5640_is_csi2(sensor)) { 28743c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 28753c28588fSJacopo Mondi ov5640_calc_pixel_rate(sensor)); 28763c28588fSJacopo Mondi 28773c28588fSJacopo Mondi return 0; 28783c28588fSJacopo Mondi } 28793c28588fSJacopo Mondi 28803c28588fSJacopo Mondi /* 28813c28588fSJacopo Mondi * The MIPI CSI-2 link frequency should comply with the CSI-2 28823c28588fSJacopo Mondi * specification and be lower than 1GHz. 28833c28588fSJacopo Mondi * 28843c28588fSJacopo Mondi * Start from the suggested pixel_rate for the current mode and 28853c28588fSJacopo Mondi * progressively slow it down if it exceeds 1GHz. 28863c28588fSJacopo Mondi */ 28873c28588fSJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 2888a89f14bbSJacopo Mondi bpp = ov5640_code_to_bpp(sensor, fmt->code); 28893c28588fSJacopo Mondi do { 28903c28588fSJacopo Mondi pixel_rate = ov5640_pixel_rates[pixel_rate_id]; 28913c28588fSJacopo Mondi link_freq = pixel_rate * bpp / (2 * num_lanes); 28923c28588fSJacopo Mondi } while (link_freq >= 1000000000U && 28933c28588fSJacopo Mondi ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); 28943c28588fSJacopo Mondi 28953c28588fSJacopo Mondi sensor->current_link_freq = link_freq; 28963c28588fSJacopo Mondi 28973c28588fSJacopo Mondi /* 28983c28588fSJacopo Mondi * Higher link rates require the clock tree to be programmed with 28993c28588fSJacopo Mondi * 'mipi_div' = 1; this has the effect of halving the actual output 29003c28588fSJacopo Mondi * pixel rate in the MIPI domain. 29013c28588fSJacopo Mondi * 29023c28588fSJacopo Mondi * Adjust the pixel rate and link frequency control value to report it 29033c28588fSJacopo Mondi * correctly to userspace. 29043c28588fSJacopo Mondi */ 29053c28588fSJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) { 29063c28588fSJacopo Mondi pixel_rate /= 2; 29073c28588fSJacopo Mondi link_freq /= 2; 29083c28588fSJacopo Mondi } 29093c28588fSJacopo Mondi 29103c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { 29113c28588fSJacopo Mondi if (ov5640_csi2_link_freqs[i] == link_freq) 29123c28588fSJacopo Mondi break; 29133c28588fSJacopo Mondi } 29143c28588fSJacopo Mondi WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); 29153c28588fSJacopo Mondi 29163c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); 29173c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); 29183c28588fSJacopo Mondi 291932979f67SJacopo Mondi timings = ov5640_timings(sensor, mode); 292032979f67SJacopo Mondi hblank = timings->htot - mode->width; 292132979f67SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.hblank, 292232979f67SJacopo Mondi hblank, hblank, 1, hblank); 292332979f67SJacopo Mondi 292419f2e3e6SHugues Fruchet vblank = timings->vblank_def; 292519f2e3e6SHugues Fruchet __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, 292619f2e3e6SHugues Fruchet OV5640_MAX_VTS - mode->height, 1, vblank); 292719f2e3e6SHugues Fruchet __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank); 292819f2e3e6SHugues Fruchet 292919f2e3e6SHugues Fruchet exposure_max = timings->crop.height + vblank - 4; 2930bce93b82SJacopo Mondi exposure_val = clamp_t(s32, sensor->ctrls.exposure->val, 2931bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 2932bce93b82SJacopo Mondi exposure_max); 293319f2e3e6SHugues Fruchet 2934bce93b82SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 2935bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 2936bce93b82SJacopo Mondi exposure_max, 1, exposure_val); 2937bce93b82SJacopo Mondi 29383c28588fSJacopo Mondi return 0; 29393c28588fSJacopo Mondi } 29403c28588fSJacopo Mondi 294119a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd, 29420d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 294319a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 294419a81c14SSteve Longerbeam { 294519a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 294619a81c14SSteve Longerbeam const struct ov5640_mode_info *new_mode; 2947e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 294819a81c14SSteve Longerbeam int ret; 294919a81c14SSteve Longerbeam 295019a81c14SSteve Longerbeam if (format->pad != 0) 295119a81c14SSteve Longerbeam return -EINVAL; 295219a81c14SSteve Longerbeam 295319a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 295419a81c14SSteve Longerbeam 295519a81c14SSteve Longerbeam if (sensor->streaming) { 295619a81c14SSteve Longerbeam ret = -EBUSY; 295719a81c14SSteve Longerbeam goto out; 295819a81c14SSteve Longerbeam } 295919a81c14SSteve Longerbeam 296025affde3SJacopo Mondi ret = ov5640_try_fmt_internal(sd, mbus_fmt, &new_mode); 296119a81c14SSteve Longerbeam if (ret) 296219a81c14SSteve Longerbeam goto out; 296319a81c14SSteve Longerbeam 2964e738f5ddSMirela Rabulea if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2965e738f5ddSMirela Rabulea *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt; 2966e738f5ddSMirela Rabulea goto out; 2967e738f5ddSMirela Rabulea } 296819a81c14SSteve Longerbeam 29696949d864SHugues Fruchet if (new_mode != sensor->current_mode) { 297019f2e3e6SHugues Fruchet sensor->current_fr = new_mode->def_fps; 297119a81c14SSteve Longerbeam sensor->current_mode = new_mode; 297219a81c14SSteve Longerbeam sensor->pending_mode_change = true; 29736949d864SHugues Fruchet } 297407115449SJacopo Mondi if (mbus_fmt->code != sensor->fmt.code) 2975fb98e29fSHugues Fruchet sensor->pending_fmt_change = true; 297607115449SJacopo Mondi 2977e738f5ddSMirela Rabulea /* update format even if code is unchanged, resolution might change */ 2978e738f5ddSMirela Rabulea sensor->fmt = *mbus_fmt; 2979e738f5ddSMirela Rabulea 29803c28588fSJacopo Mondi ov5640_update_pixel_rate(sensor); 29813c28588fSJacopo Mondi 298219a81c14SSteve Longerbeam out: 298319a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 298419a81c14SSteve Longerbeam return ret; 298519a81c14SSteve Longerbeam } 298619a81c14SSteve Longerbeam 298766ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd, 298866ed85ebSJacopo Mondi struct v4l2_subdev_state *sd_state, 298966ed85ebSJacopo Mondi struct v4l2_subdev_selection *sel) 299066ed85ebSJacopo Mondi { 299166ed85ebSJacopo Mondi struct ov5640_dev *sensor = to_ov5640_dev(sd); 299266ed85ebSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 299366ed85ebSJacopo Mondi const struct ov5640_timings *timings; 299466ed85ebSJacopo Mondi 299566ed85ebSJacopo Mondi switch (sel->target) { 299666ed85ebSJacopo Mondi case V4L2_SEL_TGT_CROP: { 299766ed85ebSJacopo Mondi mutex_lock(&sensor->lock); 299866ed85ebSJacopo Mondi timings = ov5640_timings(sensor, mode); 299966ed85ebSJacopo Mondi sel->r = timings->analog_crop; 300066ed85ebSJacopo Mondi mutex_unlock(&sensor->lock); 300166ed85ebSJacopo Mondi 300266ed85ebSJacopo Mondi return 0; 300366ed85ebSJacopo Mondi } 300466ed85ebSJacopo Mondi 300566ed85ebSJacopo Mondi case V4L2_SEL_TGT_NATIVE_SIZE: 300666ed85ebSJacopo Mondi case V4L2_SEL_TGT_CROP_BOUNDS: 300766ed85ebSJacopo Mondi sel->r.top = 0; 300866ed85ebSJacopo Mondi sel->r.left = 0; 300966ed85ebSJacopo Mondi sel->r.width = OV5640_NATIVE_WIDTH; 301066ed85ebSJacopo Mondi sel->r.height = OV5640_NATIVE_HEIGHT; 301166ed85ebSJacopo Mondi 301266ed85ebSJacopo Mondi return 0; 301366ed85ebSJacopo Mondi 301466ed85ebSJacopo Mondi case V4L2_SEL_TGT_CROP_DEFAULT: 301566ed85ebSJacopo Mondi sel->r.top = OV5640_PIXEL_ARRAY_TOP; 301666ed85ebSJacopo Mondi sel->r.left = OV5640_PIXEL_ARRAY_LEFT; 301766ed85ebSJacopo Mondi sel->r.width = OV5640_PIXEL_ARRAY_WIDTH; 301866ed85ebSJacopo Mondi sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT; 301966ed85ebSJacopo Mondi 302066ed85ebSJacopo Mondi return 0; 302166ed85ebSJacopo Mondi } 302266ed85ebSJacopo Mondi 302366ed85ebSJacopo Mondi return -EINVAL; 302466ed85ebSJacopo Mondi } 302566ed85ebSJacopo Mondi 3026e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor, 3027e3ee691dSHugues Fruchet struct v4l2_mbus_framefmt *format) 3028e3ee691dSHugues Fruchet { 3029935fbc94SJacopo Mondi bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8; 3030935fbc94SJacopo Mondi const struct ov5640_pixfmt *pixfmt; 3031e3ee691dSHugues Fruchet int ret = 0; 3032e3ee691dSHugues Fruchet 3033935fbc94SJacopo Mondi pixfmt = ov5640_code_to_pixfmt(sensor, format->code); 3034e3ee691dSHugues Fruchet 3035e3ee691dSHugues Fruchet /* FORMAT CONTROL00: YUV and RGB formatting */ 3036935fbc94SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, 3037935fbc94SJacopo Mondi pixfmt->ctrl00); 3038e3ee691dSHugues Fruchet if (ret) 3039e3ee691dSHugues Fruchet return ret; 3040e3ee691dSHugues Fruchet 3041e3ee691dSHugues Fruchet /* FORMAT MUX CONTROL: ISP YUV or RGB */ 3042935fbc94SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, 3043935fbc94SJacopo Mondi pixfmt->mux); 3044d47c4126SHugues Fruchet if (ret) 3045d47c4126SHugues Fruchet return ret; 3046d47c4126SHugues Fruchet 3047d47c4126SHugues Fruchet /* 3048d47c4126SHugues Fruchet * TIMING TC REG21: 3049d47c4126SHugues Fruchet * - [5]: JPEG enable 3050d47c4126SHugues Fruchet */ 3051d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 3052d47c4126SHugues Fruchet BIT(5), is_jpeg ? BIT(5) : 0); 3053d47c4126SHugues Fruchet if (ret) 3054d47c4126SHugues Fruchet return ret; 3055d47c4126SHugues Fruchet 3056d47c4126SHugues Fruchet /* 3057d47c4126SHugues Fruchet * SYSTEM RESET02: 3058d47c4126SHugues Fruchet * - [4]: Reset JFIFO 3059d47c4126SHugues Fruchet * - [3]: Reset SFIFO 3060d47c4126SHugues Fruchet * - [2]: Reset JPEG 3061d47c4126SHugues Fruchet */ 3062d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, 3063d47c4126SHugues Fruchet BIT(4) | BIT(3) | BIT(2), 3064d47c4126SHugues Fruchet is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); 3065d47c4126SHugues Fruchet if (ret) 3066d47c4126SHugues Fruchet return ret; 3067d47c4126SHugues Fruchet 3068d47c4126SHugues Fruchet /* 3069d47c4126SHugues Fruchet * CLOCK ENABLE02: 3070d47c4126SHugues Fruchet * - [5]: Enable JPEG 2x clock 3071d47c4126SHugues Fruchet * - [3]: Enable JPEG clock 3072d47c4126SHugues Fruchet */ 3073d47c4126SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, 3074d47c4126SHugues Fruchet BIT(5) | BIT(3), 3075d47c4126SHugues Fruchet is_jpeg ? (BIT(5) | BIT(3)) : 0); 3076e3ee691dSHugues Fruchet } 307719a81c14SSteve Longerbeam 307819a81c14SSteve Longerbeam /* 307919a81c14SSteve Longerbeam * Sensor Controls. 308019a81c14SSteve Longerbeam */ 308119a81c14SSteve Longerbeam 308219a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value) 308319a81c14SSteve Longerbeam { 308419a81c14SSteve Longerbeam int ret; 308519a81c14SSteve Longerbeam 308619a81c14SSteve Longerbeam if (value) { 308719a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 308819a81c14SSteve Longerbeam BIT(0), BIT(0)); 308919a81c14SSteve Longerbeam if (ret) 309019a81c14SSteve Longerbeam return ret; 309119a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value); 309219a81c14SSteve Longerbeam } else { 309319a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0); 309419a81c14SSteve Longerbeam } 309519a81c14SSteve Longerbeam 309619a81c14SSteve Longerbeam return ret; 309719a81c14SSteve Longerbeam } 309819a81c14SSteve Longerbeam 309919a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value) 310019a81c14SSteve Longerbeam { 310119a81c14SSteve Longerbeam int ret; 310219a81c14SSteve Longerbeam 310319a81c14SSteve Longerbeam if (value) { 310419a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 310519a81c14SSteve Longerbeam BIT(2), BIT(2)); 310619a81c14SSteve Longerbeam if (ret) 310719a81c14SSteve Longerbeam return ret; 310819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5, 310919a81c14SSteve Longerbeam value & 0xff); 311019a81c14SSteve Longerbeam } else { 311119a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0); 311219a81c14SSteve Longerbeam } 311319a81c14SSteve Longerbeam 311419a81c14SSteve Longerbeam return ret; 311519a81c14SSteve Longerbeam } 311619a81c14SSteve Longerbeam 311719a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value) 311819a81c14SSteve Longerbeam { 311919a81c14SSteve Longerbeam int ret; 312019a81c14SSteve Longerbeam 312119a81c14SSteve Longerbeam if (value) { 312219a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 312319a81c14SSteve Longerbeam BIT(1), BIT(1)); 312419a81c14SSteve Longerbeam if (ret) 312519a81c14SSteve Longerbeam return ret; 312619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3, 312719a81c14SSteve Longerbeam value & 0xff); 312819a81c14SSteve Longerbeam if (ret) 312919a81c14SSteve Longerbeam return ret; 313019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4, 313119a81c14SSteve Longerbeam value & 0xff); 313219a81c14SSteve Longerbeam } else { 313319a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0); 313419a81c14SSteve Longerbeam } 313519a81c14SSteve Longerbeam 313619a81c14SSteve Longerbeam return ret; 313719a81c14SSteve Longerbeam } 313819a81c14SSteve Longerbeam 313919a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) 314019a81c14SSteve Longerbeam { 314119a81c14SSteve Longerbeam int ret; 314219a81c14SSteve Longerbeam 314319a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL, 314419a81c14SSteve Longerbeam BIT(0), awb ? 0 : 1); 314519a81c14SSteve Longerbeam if (ret) 314619a81c14SSteve Longerbeam return ret; 314719a81c14SSteve Longerbeam 314819a81c14SSteve Longerbeam if (!awb) { 314919a81c14SSteve Longerbeam u16 red = (u16)sensor->ctrls.red_balance->val; 315019a81c14SSteve Longerbeam u16 blue = (u16)sensor->ctrls.blue_balance->val; 315119a81c14SSteve Longerbeam 315219a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red); 315319a81c14SSteve Longerbeam if (ret) 315419a81c14SSteve Longerbeam return ret; 315519a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue); 315619a81c14SSteve Longerbeam } 315719a81c14SSteve Longerbeam 315819a81c14SSteve Longerbeam return ret; 315919a81c14SSteve Longerbeam } 316019a81c14SSteve Longerbeam 31613cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, 31623cca8ef5SHugues Fruchet enum v4l2_exposure_auto_type auto_exposure) 316319a81c14SSteve Longerbeam { 316419a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 31653cca8ef5SHugues Fruchet bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); 316619a81c14SSteve Longerbeam int ret = 0; 316719a81c14SSteve Longerbeam 316819a81c14SSteve Longerbeam if (ctrls->auto_exp->is_new) { 31693cca8ef5SHugues Fruchet ret = ov5640_set_autoexposure(sensor, auto_exp); 317019a81c14SSteve Longerbeam if (ret) 317119a81c14SSteve Longerbeam return ret; 317219a81c14SSteve Longerbeam } 317319a81c14SSteve Longerbeam 31743cca8ef5SHugues Fruchet if (!auto_exp && ctrls->exposure->is_new) { 317519a81c14SSteve Longerbeam u16 max_exp; 317619a81c14SSteve Longerbeam 317719a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, 317819a81c14SSteve Longerbeam &max_exp); 317919a81c14SSteve Longerbeam if (ret) 318019a81c14SSteve Longerbeam return ret; 318119a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 318219a81c14SSteve Longerbeam if (ret < 0) 318319a81c14SSteve Longerbeam return ret; 318419a81c14SSteve Longerbeam max_exp += ret; 31856146fde3SHugues Fruchet ret = 0; 318619a81c14SSteve Longerbeam 318719a81c14SSteve Longerbeam if (ctrls->exposure->val < max_exp) 318819a81c14SSteve Longerbeam ret = ov5640_set_exposure(sensor, ctrls->exposure->val); 318919a81c14SSteve Longerbeam } 319019a81c14SSteve Longerbeam 319119a81c14SSteve Longerbeam return ret; 319219a81c14SSteve Longerbeam } 319319a81c14SSteve Longerbeam 31943cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) 319519a81c14SSteve Longerbeam { 319619a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 319719a81c14SSteve Longerbeam int ret = 0; 319819a81c14SSteve Longerbeam 319919a81c14SSteve Longerbeam if (ctrls->auto_gain->is_new) { 32003cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, auto_gain); 320119a81c14SSteve Longerbeam if (ret) 320219a81c14SSteve Longerbeam return ret; 320319a81c14SSteve Longerbeam } 320419a81c14SSteve Longerbeam 32053cca8ef5SHugues Fruchet if (!auto_gain && ctrls->gain->is_new) 32063cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, ctrls->gain->val); 320719a81c14SSteve Longerbeam 320819a81c14SSteve Longerbeam return ret; 320919a81c14SSteve Longerbeam } 321019a81c14SSteve Longerbeam 32119f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = { 32129f6d7bacSChen-Yu Tsai "Disabled", 32139f6d7bacSChen-Yu Tsai "Color bars", 3214bddc5cdfSChen-Yu Tsai "Color bars w/ rolling bar", 3215bddc5cdfSChen-Yu Tsai "Color squares", 3216bddc5cdfSChen-Yu Tsai "Color squares w/ rolling bar", 32179f6d7bacSChen-Yu Tsai }; 32189f6d7bacSChen-Yu Tsai 3219a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE BIT(7) 3220a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ 3221a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT BIT(5) 3222a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ 3223a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD (0 << 2) 3224a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) 3225a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) 3226a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) 3227a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR (0 << 0) 3228a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM (1 << 0) 3229a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE (2 << 0) 3230a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK (3 << 0) 3231a0c29afbSChen-Yu Tsai 3232a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = { 3233a0c29afbSChen-Yu Tsai 0, 32342aff1fc3SChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | 3235a0c29afbSChen-Yu Tsai OV5640_TEST_BAR, 3236bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | 3237bddc5cdfSChen-Yu Tsai OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, 3238bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, 3239bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, 3240a0c29afbSChen-Yu Tsai }; 3241a0c29afbSChen-Yu Tsai 324219a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) 324319a81c14SSteve Longerbeam { 3244a0c29afbSChen-Yu Tsai return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, 3245a0c29afbSChen-Yu Tsai test_pattern_val[value]); 324619a81c14SSteve Longerbeam } 324719a81c14SSteve Longerbeam 32481068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) 32491068fecaSMylène Josserand { 32501068fecaSMylène Josserand int ret; 32511068fecaSMylène Josserand 32521068fecaSMylène Josserand ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), 32531068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? 32541068fecaSMylène Josserand 0 : BIT(7)); 32551068fecaSMylène Josserand if (ret) 32561068fecaSMylène Josserand return ret; 32571068fecaSMylène Josserand 32581068fecaSMylène Josserand return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), 32591068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? 32601068fecaSMylène Josserand BIT(2) : 0); 32611068fecaSMylène Josserand } 32621068fecaSMylène Josserand 3263ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value) 3264ce85705aSHugues Fruchet { 3265ce85705aSHugues Fruchet /* 3266c3f3ba3eSHugues Fruchet * If sensor is mounted upside down, mirror logic is inversed. 3267c3f3ba3eSHugues Fruchet * 3268ce85705aSHugues Fruchet * Sensor is a BSI (Back Side Illuminated) one, 3269ce85705aSHugues Fruchet * so image captured is physically mirrored. 3270ce85705aSHugues Fruchet * This is why mirror logic is inversed in 3271ce85705aSHugues Fruchet * order to cancel this mirror effect. 3272ce85705aSHugues Fruchet */ 3273ce85705aSHugues Fruchet 3274ce85705aSHugues Fruchet /* 3275ce85705aSHugues Fruchet * TIMING TC REG21: 3276ce85705aSHugues Fruchet * - [2]: ISP mirror 3277ce85705aSHugues Fruchet * - [1]: Sensor mirror 3278ce85705aSHugues Fruchet */ 3279ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 3280ce85705aSHugues Fruchet BIT(2) | BIT(1), 3281c3f3ba3eSHugues Fruchet (!(value ^ sensor->upside_down)) ? 3282c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3283ce85705aSHugues Fruchet } 3284ce85705aSHugues Fruchet 3285ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) 3286ce85705aSHugues Fruchet { 3287c3f3ba3eSHugues Fruchet /* If sensor is mounted upside down, flip logic is inversed */ 3288c3f3ba3eSHugues Fruchet 3289ce85705aSHugues Fruchet /* 3290ce85705aSHugues Fruchet * TIMING TC REG20: 3291ce85705aSHugues Fruchet * - [2]: ISP vflip 3292ce85705aSHugues Fruchet * - [1]: Sensor vflip 3293ce85705aSHugues Fruchet */ 3294ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 3295ce85705aSHugues Fruchet BIT(2) | BIT(1), 3296c3f3ba3eSHugues Fruchet (value ^ sensor->upside_down) ? 3297c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3298ce85705aSHugues Fruchet } 3299ce85705aSHugues Fruchet 3300bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value) 3301bce93b82SJacopo Mondi { 3302bce93b82SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 3303bce93b82SJacopo Mondi 3304bce93b82SJacopo Mondi /* Update the VTOT timing register value. */ 3305bce93b82SJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 3306bce93b82SJacopo Mondi mode->height + value); 3307bce93b82SJacopo Mondi } 3308bce93b82SJacopo Mondi 330919a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 331019a81c14SSteve Longerbeam { 331119a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 331219a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 331319a81c14SSteve Longerbeam int val; 331419a81c14SSteve Longerbeam 331519a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 331619a81c14SSteve Longerbeam 331785644a9bSPaul Elder if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) 331885644a9bSPaul Elder return 0; 331985644a9bSPaul Elder 332019a81c14SSteve Longerbeam switch (ctrl->id) { 332119a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 332219a81c14SSteve Longerbeam val = ov5640_get_gain(sensor); 332319a81c14SSteve Longerbeam if (val < 0) 332419a81c14SSteve Longerbeam return val; 332519a81c14SSteve Longerbeam sensor->ctrls.gain->val = val; 332619a81c14SSteve Longerbeam break; 332719a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 332819a81c14SSteve Longerbeam val = ov5640_get_exposure(sensor); 332919a81c14SSteve Longerbeam if (val < 0) 333019a81c14SSteve Longerbeam return val; 333119a81c14SSteve Longerbeam sensor->ctrls.exposure->val = val; 333219a81c14SSteve Longerbeam break; 333319a81c14SSteve Longerbeam } 333419a81c14SSteve Longerbeam 3335e13064a3SAndrey Skvortsov pm_runtime_mark_last_busy(&sensor->i2c_client->dev); 333685644a9bSPaul Elder pm_runtime_put_autosuspend(&sensor->i2c_client->dev); 333785644a9bSPaul Elder 333819a81c14SSteve Longerbeam return 0; 333919a81c14SSteve Longerbeam } 334019a81c14SSteve Longerbeam 334119a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) 334219a81c14SSteve Longerbeam { 334319a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 334419a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 3345bce93b82SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 3346bce93b82SJacopo Mondi const struct ov5640_timings *timings; 3347bce93b82SJacopo Mondi unsigned int exp_max; 334819a81c14SSteve Longerbeam int ret; 334919a81c14SSteve Longerbeam 335019a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 335119a81c14SSteve Longerbeam 3352bce93b82SJacopo Mondi switch (ctrl->id) { 3353bce93b82SJacopo Mondi case V4L2_CID_VBLANK: 3354bce93b82SJacopo Mondi /* Update the exposure range to the newly programmed vblank. */ 3355bce93b82SJacopo Mondi timings = ov5640_timings(sensor, mode); 3356bce93b82SJacopo Mondi exp_max = mode->height + ctrl->val - 4; 3357bce93b82SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 3358bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 3359bce93b82SJacopo Mondi exp_max, sensor->ctrls.exposure->step, 3360bce93b82SJacopo Mondi timings->vblank_def); 3361bce93b82SJacopo Mondi break; 3362bce93b82SJacopo Mondi } 3363bce93b82SJacopo Mondi 336419a81c14SSteve Longerbeam /* 336519a81c14SSteve Longerbeam * If the device is not powered up by the host driver do 336619a81c14SSteve Longerbeam * not apply any controls to H/W at this time. Instead 336785644a9bSPaul Elder * the controls will be restored at start streaming time. 336819a81c14SSteve Longerbeam */ 336985644a9bSPaul Elder if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) 337019a81c14SSteve Longerbeam return 0; 337119a81c14SSteve Longerbeam 337219a81c14SSteve Longerbeam switch (ctrl->id) { 337319a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 337419a81c14SSteve Longerbeam ret = ov5640_set_ctrl_gain(sensor, ctrl->val); 337519a81c14SSteve Longerbeam break; 337619a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 337719a81c14SSteve Longerbeam ret = ov5640_set_ctrl_exposure(sensor, ctrl->val); 337819a81c14SSteve Longerbeam break; 337919a81c14SSteve Longerbeam case V4L2_CID_AUTO_WHITE_BALANCE: 338019a81c14SSteve Longerbeam ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); 338119a81c14SSteve Longerbeam break; 338219a81c14SSteve Longerbeam case V4L2_CID_HUE: 338319a81c14SSteve Longerbeam ret = ov5640_set_ctrl_hue(sensor, ctrl->val); 338419a81c14SSteve Longerbeam break; 338519a81c14SSteve Longerbeam case V4L2_CID_CONTRAST: 338619a81c14SSteve Longerbeam ret = ov5640_set_ctrl_contrast(sensor, ctrl->val); 338719a81c14SSteve Longerbeam break; 338819a81c14SSteve Longerbeam case V4L2_CID_SATURATION: 338919a81c14SSteve Longerbeam ret = ov5640_set_ctrl_saturation(sensor, ctrl->val); 339019a81c14SSteve Longerbeam break; 339119a81c14SSteve Longerbeam case V4L2_CID_TEST_PATTERN: 339219a81c14SSteve Longerbeam ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); 339319a81c14SSteve Longerbeam break; 33941068fecaSMylène Josserand case V4L2_CID_POWER_LINE_FREQUENCY: 33951068fecaSMylène Josserand ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); 33961068fecaSMylène Josserand break; 3397ce85705aSHugues Fruchet case V4L2_CID_HFLIP: 3398ce85705aSHugues Fruchet ret = ov5640_set_ctrl_hflip(sensor, ctrl->val); 3399ce85705aSHugues Fruchet break; 3400ce85705aSHugues Fruchet case V4L2_CID_VFLIP: 3401ce85705aSHugues Fruchet ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); 3402ce85705aSHugues Fruchet break; 3403bce93b82SJacopo Mondi case V4L2_CID_VBLANK: 3404bce93b82SJacopo Mondi ret = ov5640_set_ctrl_vblank(sensor, ctrl->val); 3405bce93b82SJacopo Mondi break; 340619a81c14SSteve Longerbeam default: 340719a81c14SSteve Longerbeam ret = -EINVAL; 340819a81c14SSteve Longerbeam break; 340919a81c14SSteve Longerbeam } 341019a81c14SSteve Longerbeam 3411e13064a3SAndrey Skvortsov pm_runtime_mark_last_busy(&sensor->i2c_client->dev); 341285644a9bSPaul Elder pm_runtime_put_autosuspend(&sensor->i2c_client->dev); 341385644a9bSPaul Elder 341419a81c14SSteve Longerbeam return ret; 341519a81c14SSteve Longerbeam } 341619a81c14SSteve Longerbeam 341719a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { 341819a81c14SSteve Longerbeam .g_volatile_ctrl = ov5640_g_volatile_ctrl, 341919a81c14SSteve Longerbeam .s_ctrl = ov5640_s_ctrl, 342019a81c14SSteve Longerbeam }; 342119a81c14SSteve Longerbeam 342219a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor) 342319a81c14SSteve Longerbeam { 342422845bf2SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 342519a81c14SSteve Longerbeam const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; 342619a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 342719a81c14SSteve Longerbeam struct v4l2_ctrl_handler *hdl = &ctrls->handler; 34281066fc1cSJacopo Mondi struct v4l2_fwnode_device_properties props; 342932979f67SJacopo Mondi const struct ov5640_timings *timings; 3430bce93b82SJacopo Mondi unsigned int max_vblank; 343132979f67SJacopo Mondi unsigned int hblank; 343219a81c14SSteve Longerbeam int ret; 343319a81c14SSteve Longerbeam 343419a81c14SSteve Longerbeam v4l2_ctrl_handler_init(hdl, 32); 343519a81c14SSteve Longerbeam 343619a81c14SSteve Longerbeam /* we can use our own mutex for the ctrl lock */ 343719a81c14SSteve Longerbeam hdl->lock = &sensor->lock; 343819a81c14SSteve Longerbeam 3439cc196e48SBenoit Parrot /* Clock related controls */ 3440cc196e48SBenoit Parrot ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 344122845bf2SJacopo Mondi ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], 344222845bf2SJacopo Mondi ov5640_pixel_rates[0], 1, 344322845bf2SJacopo Mondi ov5640_pixel_rates[mode->pixel_rate]); 3444cc196e48SBenoit Parrot 34457a3b8d4bSJacopo Mondi ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, 34467a3b8d4bSJacopo Mondi V4L2_CID_LINK_FREQ, 34477a3b8d4bSJacopo Mondi ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, 34487a3b8d4bSJacopo Mondi OV5640_DEFAULT_LINK_FREQ, 34497a3b8d4bSJacopo Mondi ov5640_csi2_link_freqs); 34507a3b8d4bSJacopo Mondi 345132979f67SJacopo Mondi timings = ov5640_timings(sensor, mode); 345232979f67SJacopo Mondi hblank = timings->htot - mode->width; 345332979f67SJacopo Mondi ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank, 345432979f67SJacopo Mondi hblank, 1, hblank); 345532979f67SJacopo Mondi 3456bce93b82SJacopo Mondi max_vblank = OV5640_MAX_VTS - mode->height; 3457bce93b82SJacopo Mondi ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, 3458bce93b82SJacopo Mondi OV5640_MIN_VBLANK, max_vblank, 3459bce93b82SJacopo Mondi 1, timings->vblank_def); 3460bce93b82SJacopo Mondi 346119a81c14SSteve Longerbeam /* Auto/manual white balance */ 346219a81c14SSteve Longerbeam ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, 346319a81c14SSteve Longerbeam V4L2_CID_AUTO_WHITE_BALANCE, 346419a81c14SSteve Longerbeam 0, 1, 1, 1); 346519a81c14SSteve Longerbeam ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 346619a81c14SSteve Longerbeam 0, 4095, 1, 0); 346719a81c14SSteve Longerbeam ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, 346819a81c14SSteve Longerbeam 0, 4095, 1, 0); 346919a81c14SSteve Longerbeam /* Auto/manual exposure */ 347019a81c14SSteve Longerbeam ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, 347119a81c14SSteve Longerbeam V4L2_CID_EXPOSURE_AUTO, 347219a81c14SSteve Longerbeam V4L2_EXPOSURE_MANUAL, 0, 347319a81c14SSteve Longerbeam V4L2_EXPOSURE_AUTO); 347419a81c14SSteve Longerbeam ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 347519a81c14SSteve Longerbeam 0, 65535, 1, 0); 347619a81c14SSteve Longerbeam /* Auto/manual gain */ 347719a81c14SSteve Longerbeam ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 347819a81c14SSteve Longerbeam 0, 1, 1, 1); 3479afa48057SPaul Elder ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 348019a81c14SSteve Longerbeam 0, 1023, 1, 0); 348119a81c14SSteve Longerbeam 348219a81c14SSteve Longerbeam ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 348319a81c14SSteve Longerbeam 0, 255, 1, 64); 348419a81c14SSteve Longerbeam ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, 348519a81c14SSteve Longerbeam 0, 359, 1, 0); 348619a81c14SSteve Longerbeam ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, 348719a81c14SSteve Longerbeam 0, 255, 1, 0); 348819a81c14SSteve Longerbeam ctrls->test_pattern = 348919a81c14SSteve Longerbeam v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, 349019a81c14SSteve Longerbeam ARRAY_SIZE(test_pattern_menu) - 1, 349119a81c14SSteve Longerbeam 0, 0, test_pattern_menu); 3492ce85705aSHugues Fruchet ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 3493ce85705aSHugues Fruchet 0, 1, 1, 0); 3494ce85705aSHugues Fruchet ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 3495ce85705aSHugues Fruchet 0, 1, 1, 0); 349619a81c14SSteve Longerbeam 34971068fecaSMylène Josserand ctrls->light_freq = 34981068fecaSMylène Josserand v4l2_ctrl_new_std_menu(hdl, ops, 34991068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY, 35001068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 35011068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 35021068fecaSMylène Josserand 350319a81c14SSteve Longerbeam if (hdl->error) { 350419a81c14SSteve Longerbeam ret = hdl->error; 350519a81c14SSteve Longerbeam goto free_ctrls; 350619a81c14SSteve Longerbeam } 350719a81c14SSteve Longerbeam 35081066fc1cSJacopo Mondi ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props); 35091066fc1cSJacopo Mondi if (ret) 35101066fc1cSJacopo Mondi goto free_ctrls; 35111066fc1cSJacopo Mondi 35121066fc1cSJacopo Mondi if (props.rotation == 180) 35131066fc1cSJacopo Mondi sensor->upside_down = true; 35141066fc1cSJacopo Mondi 35151066fc1cSJacopo Mondi ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); 35161066fc1cSJacopo Mondi if (ret) 35171066fc1cSJacopo Mondi goto free_ctrls; 35181066fc1cSJacopo Mondi 3519cc196e48SBenoit Parrot ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 35207a3b8d4bSJacopo Mondi ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 352132979f67SJacopo Mondi ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 352219a81c14SSteve Longerbeam ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 352319a81c14SSteve Longerbeam ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 352419a81c14SSteve Longerbeam 352519a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); 352619a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); 352719a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); 352819a81c14SSteve Longerbeam 352919a81c14SSteve Longerbeam sensor->sd.ctrl_handler = hdl; 353019a81c14SSteve Longerbeam return 0; 353119a81c14SSteve Longerbeam 353219a81c14SSteve Longerbeam free_ctrls: 353319a81c14SSteve Longerbeam v4l2_ctrl_handler_free(hdl); 353419a81c14SSteve Longerbeam return ret; 353519a81c14SSteve Longerbeam } 353619a81c14SSteve Longerbeam 353719a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd, 35380d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 353919a81c14SSteve Longerbeam struct v4l2_subdev_frame_size_enum *fse) 354019a81c14SSteve Longerbeam { 3541a89f14bbSJacopo Mondi struct ov5640_dev *sensor = to_ov5640_dev(sd); 3542a89f14bbSJacopo Mondi u32 bpp = ov5640_code_to_bpp(sensor, fse->code); 35437dcb3a2fSJacopo Mondi unsigned int index = fse->index; 35447dcb3a2fSJacopo Mondi 354519a81c14SSteve Longerbeam if (fse->pad != 0) 354619a81c14SSteve Longerbeam return -EINVAL; 35477dcb3a2fSJacopo Mondi if (!bpp) 354819a81c14SSteve Longerbeam return -EINVAL; 354919a81c14SSteve Longerbeam 35507dcb3a2fSJacopo Mondi /* Only low-resolution modes are supported for 24bpp formats. */ 35517dcb3a2fSJacopo Mondi if (bpp == 24 && index >= OV5640_MODE_720P_1280_720) 35527dcb3a2fSJacopo Mondi return -EINVAL; 35537dcb3a2fSJacopo Mondi 35547dcb3a2fSJacopo Mondi /* FIXME: Low resolution modes don't work in 8bpp formats. */ 35557dcb3a2fSJacopo Mondi if (bpp == 8) 35567dcb3a2fSJacopo Mondi index += OV5640_MODE_720P_1280_720; 35577dcb3a2fSJacopo Mondi 35587dcb3a2fSJacopo Mondi if (index >= OV5640_NUM_MODES) 35597dcb3a2fSJacopo Mondi return -EINVAL; 35607dcb3a2fSJacopo Mondi 35617dcb3a2fSJacopo Mondi fse->min_width = ov5640_mode_data[index].width; 356241d8d7f5SHugues Fruchet fse->max_width = fse->min_width; 35637dcb3a2fSJacopo Mondi fse->min_height = ov5640_mode_data[index].height; 356441d8d7f5SHugues Fruchet fse->max_height = fse->min_height; 356519a81c14SSteve Longerbeam 356619a81c14SSteve Longerbeam return 0; 356719a81c14SSteve Longerbeam } 356819a81c14SSteve Longerbeam 356919a81c14SSteve Longerbeam static int ov5640_enum_frame_interval( 357019a81c14SSteve Longerbeam struct v4l2_subdev *sd, 35710d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 357219a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval_enum *fie) 357319a81c14SSteve Longerbeam { 357419a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 3575f33b56d3SGuoniu.zhou const struct ov5640_mode_info *mode; 357619a81c14SSteve Longerbeam struct v4l2_fract tpf; 357719a81c14SSteve Longerbeam int ret; 357819a81c14SSteve Longerbeam 357919a81c14SSteve Longerbeam if (fie->pad != 0) 358019a81c14SSteve Longerbeam return -EINVAL; 358119a81c14SSteve Longerbeam if (fie->index >= OV5640_NUM_FRAMERATES) 358219a81c14SSteve Longerbeam return -EINVAL; 358319a81c14SSteve Longerbeam 3584f33b56d3SGuoniu.zhou mode = ov5640_find_mode(sensor, fie->width, fie->height, false); 3585f33b56d3SGuoniu.zhou if (!mode) 3586f33b56d3SGuoniu.zhou return -EINVAL; 3587f33b56d3SGuoniu.zhou 358819a81c14SSteve Longerbeam tpf.numerator = 1; 358919a81c14SSteve Longerbeam tpf.denominator = ov5640_framerates[fie->index]; 359019a81c14SSteve Longerbeam 3591f33b56d3SGuoniu.zhou ret = ov5640_try_frame_interval(sensor, &tpf, mode); 359219a81c14SSteve Longerbeam if (ret < 0) 359319a81c14SSteve Longerbeam return -EINVAL; 359419a81c14SSteve Longerbeam 359519a81c14SSteve Longerbeam fie->interval = tpf; 359619a81c14SSteve Longerbeam return 0; 359719a81c14SSteve Longerbeam } 359819a81c14SSteve Longerbeam 359919a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd, 360019a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 360119a81c14SSteve Longerbeam { 360219a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 360319a81c14SSteve Longerbeam 360419a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 360519a81c14SSteve Longerbeam fi->interval = sensor->frame_interval; 360619a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 360719a81c14SSteve Longerbeam 360819a81c14SSteve Longerbeam return 0; 360919a81c14SSteve Longerbeam } 361019a81c14SSteve Longerbeam 361119a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd, 361219a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 361319a81c14SSteve Longerbeam { 361419a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 361519a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 361619a81c14SSteve Longerbeam int frame_rate, ret = 0; 361719a81c14SSteve Longerbeam 361819a81c14SSteve Longerbeam if (fi->pad != 0) 361919a81c14SSteve Longerbeam return -EINVAL; 362019a81c14SSteve Longerbeam 362119a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 362219a81c14SSteve Longerbeam 362319a81c14SSteve Longerbeam if (sensor->streaming) { 362419a81c14SSteve Longerbeam ret = -EBUSY; 362519a81c14SSteve Longerbeam goto out; 362619a81c14SSteve Longerbeam } 362719a81c14SSteve Longerbeam 362819a81c14SSteve Longerbeam mode = sensor->current_mode; 362919a81c14SSteve Longerbeam 3630f33b56d3SGuoniu.zhou frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode); 3631e823fb16SMaxime Ripard if (frame_rate < 0) { 3632e823fb16SMaxime Ripard /* Always return a valid frame interval value */ 3633e823fb16SMaxime Ripard fi->interval = sensor->frame_interval; 3634e823fb16SMaxime Ripard goto out; 3635e823fb16SMaxime Ripard } 363619a81c14SSteve Longerbeam 3637b6ae5022SJacopo Mondi mode = ov5640_find_mode(sensor, mode->width, mode->height, true); 36383c4a7372SHugues Fruchet if (!mode) { 36393c4a7372SHugues Fruchet ret = -EINVAL; 36403c4a7372SHugues Fruchet goto out; 36413c4a7372SHugues Fruchet } 36423c4a7372SHugues Fruchet 3643b6ae5022SJacopo Mondi if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) { 3644b6ae5022SJacopo Mondi ret = -EINVAL; 3645b6ae5022SJacopo Mondi goto out; 3646b6ae5022SJacopo Mondi } 3647b6ae5022SJacopo Mondi 36480929983eSHugues Fruchet if (mode != sensor->current_mode || 36490929983eSHugues Fruchet frame_rate != sensor->current_fr) { 36500929983eSHugues Fruchet sensor->current_fr = frame_rate; 36510929983eSHugues Fruchet sensor->frame_interval = fi->interval; 36523c4a7372SHugues Fruchet sensor->current_mode = mode; 365319a81c14SSteve Longerbeam sensor->pending_mode_change = true; 3654cc196e48SBenoit Parrot 365519f2e3e6SHugues Fruchet ov5640_update_pixel_rate(sensor); 36566949d864SHugues Fruchet } 365719a81c14SSteve Longerbeam out: 365819a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 365919a81c14SSteve Longerbeam return ret; 366019a81c14SSteve Longerbeam } 366119a81c14SSteve Longerbeam 366219a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, 36630d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 366419a81c14SSteve Longerbeam struct v4l2_subdev_mbus_code_enum *code) 366519a81c14SSteve Longerbeam { 3666a89f14bbSJacopo Mondi struct ov5640_dev *sensor = to_ov5640_dev(sd); 3667a89f14bbSJacopo Mondi const struct ov5640_pixfmt *formats; 3668a89f14bbSJacopo Mondi unsigned int num_formats; 3669a89f14bbSJacopo Mondi 3670a89f14bbSJacopo Mondi if (ov5640_is_csi2(sensor)) { 3671a89f14bbSJacopo Mondi formats = ov5640_csi2_formats; 3672a89f14bbSJacopo Mondi num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1; 3673a89f14bbSJacopo Mondi } else { 3674a89f14bbSJacopo Mondi formats = ov5640_dvp_formats; 3675a89f14bbSJacopo Mondi num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1; 3676a89f14bbSJacopo Mondi } 3677a89f14bbSJacopo Mondi 3678a89f14bbSJacopo Mondi if (code->index >= num_formats) 367919a81c14SSteve Longerbeam return -EINVAL; 368019a81c14SSteve Longerbeam 3681a89f14bbSJacopo Mondi code->code = formats[code->index].code; 3682a89f14bbSJacopo Mondi 368319a81c14SSteve Longerbeam return 0; 368419a81c14SSteve Longerbeam } 368519a81c14SSteve Longerbeam 368619a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) 368719a81c14SSteve Longerbeam { 368819a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 368919a81c14SSteve Longerbeam int ret = 0; 369019a81c14SSteve Longerbeam 369185644a9bSPaul Elder if (enable) { 369285644a9bSPaul Elder ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); 369385644a9bSPaul Elder if (ret < 0) 369485644a9bSPaul Elder return ret; 369585644a9bSPaul Elder 369685644a9bSPaul Elder ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 369785644a9bSPaul Elder if (ret) { 369885644a9bSPaul Elder pm_runtime_put(&sensor->i2c_client->dev); 369985644a9bSPaul Elder return ret; 370085644a9bSPaul Elder } 370185644a9bSPaul Elder } 370285644a9bSPaul Elder 370319a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 370419a81c14SSteve Longerbeam 370519a81c14SSteve Longerbeam if (sensor->streaming == !enable) { 370619a81c14SSteve Longerbeam if (enable && sensor->pending_mode_change) { 3707985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 370819a81c14SSteve Longerbeam if (ret) 370919a81c14SSteve Longerbeam goto out; 3710fb98e29fSHugues Fruchet } 3711e3ee691dSHugues Fruchet 3712fb98e29fSHugues Fruchet if (enable && sensor->pending_fmt_change) { 3713e3ee691dSHugues Fruchet ret = ov5640_set_framefmt(sensor, &sensor->fmt); 3714e3ee691dSHugues Fruchet if (ret) 3715e3ee691dSHugues Fruchet goto out; 3716fb98e29fSHugues Fruchet sensor->pending_fmt_change = false; 371719a81c14SSteve Longerbeam } 371819a81c14SSteve Longerbeam 37198e823f5cSJacopo Mondi if (ov5640_is_csi2(sensor)) 3720f22996dbSHugues Fruchet ret = ov5640_set_stream_mipi(sensor, enable); 3721f22996dbSHugues Fruchet else 3722f22996dbSHugues Fruchet ret = ov5640_set_stream_dvp(sensor, enable); 3723f22996dbSHugues Fruchet 372419a81c14SSteve Longerbeam if (!ret) 372519a81c14SSteve Longerbeam sensor->streaming = enable; 372619a81c14SSteve Longerbeam } 372785644a9bSPaul Elder 372819a81c14SSteve Longerbeam out: 372919a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 373085644a9bSPaul Elder 3731e13064a3SAndrey Skvortsov if (!enable || ret) { 3732e13064a3SAndrey Skvortsov pm_runtime_mark_last_busy(&sensor->i2c_client->dev); 373385644a9bSPaul Elder pm_runtime_put_autosuspend(&sensor->i2c_client->dev); 3734e13064a3SAndrey Skvortsov } 373585644a9bSPaul Elder 373619a81c14SSteve Longerbeam return ret; 373719a81c14SSteve Longerbeam } 373819a81c14SSteve Longerbeam 373990b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd, 374090b0f355SJacopo Mondi struct v4l2_subdev_state *state) 374190b0f355SJacopo Mondi { 374268453b02SGuoniu.zhou struct ov5640_dev *sensor = to_ov5640_dev(sd); 374390b0f355SJacopo Mondi struct v4l2_mbus_framefmt *fmt = 374490b0f355SJacopo Mondi v4l2_subdev_get_try_format(sd, state, 0); 374566ed85ebSJacopo Mondi struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); 374690b0f355SJacopo Mondi 374768453b02SGuoniu.zhou *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : 374868453b02SGuoniu.zhou ov5640_dvp_default_fmt; 374990b0f355SJacopo Mondi 375066ed85ebSJacopo Mondi crop->left = OV5640_PIXEL_ARRAY_LEFT; 375166ed85ebSJacopo Mondi crop->top = OV5640_PIXEL_ARRAY_TOP; 375266ed85ebSJacopo Mondi crop->width = OV5640_PIXEL_ARRAY_WIDTH; 375366ed85ebSJacopo Mondi crop->height = OV5640_PIXEL_ARRAY_HEIGHT; 375466ed85ebSJacopo Mondi 375590b0f355SJacopo Mondi return 0; 375690b0f355SJacopo Mondi } 375790b0f355SJacopo Mondi 375819a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = { 37592d18fbc5SAkinobu Mita .log_status = v4l2_ctrl_subdev_log_status, 37602d18fbc5SAkinobu Mita .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 37612d18fbc5SAkinobu Mita .unsubscribe_event = v4l2_event_subdev_unsubscribe, 376219a81c14SSteve Longerbeam }; 376319a81c14SSteve Longerbeam 376419a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = { 376519a81c14SSteve Longerbeam .g_frame_interval = ov5640_g_frame_interval, 376619a81c14SSteve Longerbeam .s_frame_interval = ov5640_s_frame_interval, 376719a81c14SSteve Longerbeam .s_stream = ov5640_s_stream, 376819a81c14SSteve Longerbeam }; 376919a81c14SSteve Longerbeam 377019a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { 377190b0f355SJacopo Mondi .init_cfg = ov5640_init_cfg, 377219a81c14SSteve Longerbeam .enum_mbus_code = ov5640_enum_mbus_code, 377319a81c14SSteve Longerbeam .get_fmt = ov5640_get_fmt, 377419a81c14SSteve Longerbeam .set_fmt = ov5640_set_fmt, 377566ed85ebSJacopo Mondi .get_selection = ov5640_get_selection, 377619a81c14SSteve Longerbeam .enum_frame_size = ov5640_enum_frame_size, 377719a81c14SSteve Longerbeam .enum_frame_interval = ov5640_enum_frame_interval, 377819a81c14SSteve Longerbeam }; 377919a81c14SSteve Longerbeam 378019a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = { 378119a81c14SSteve Longerbeam .core = &ov5640_core_ops, 378219a81c14SSteve Longerbeam .video = &ov5640_video_ops, 378319a81c14SSteve Longerbeam .pad = &ov5640_pad_ops, 378419a81c14SSteve Longerbeam }; 378519a81c14SSteve Longerbeam 378619a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor) 378719a81c14SSteve Longerbeam { 378819a81c14SSteve Longerbeam int i; 378919a81c14SSteve Longerbeam 379019a81c14SSteve Longerbeam for (i = 0; i < OV5640_NUM_SUPPLIES; i++) 379119a81c14SSteve Longerbeam sensor->supplies[i].supply = ov5640_supply_name[i]; 379219a81c14SSteve Longerbeam 379319a81c14SSteve Longerbeam return devm_regulator_bulk_get(&sensor->i2c_client->dev, 379419a81c14SSteve Longerbeam OV5640_NUM_SUPPLIES, 379519a81c14SSteve Longerbeam sensor->supplies); 379619a81c14SSteve Longerbeam } 379719a81c14SSteve Longerbeam 37980f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor) 37990f7acb52SHugues Fruchet { 38000f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 38010f7acb52SHugues Fruchet int ret = 0; 38020f7acb52SHugues Fruchet u16 chip_id; 38030f7acb52SHugues Fruchet 38040f7acb52SHugues Fruchet ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); 38050f7acb52SHugues Fruchet if (ret) { 38060f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to read chip identifier\n", 38070f7acb52SHugues Fruchet __func__); 380885644a9bSPaul Elder return ret; 38090f7acb52SHugues Fruchet } 38100f7acb52SHugues Fruchet 38110f7acb52SHugues Fruchet if (chip_id != 0x5640) { 38120f7acb52SHugues Fruchet dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", 38130f7acb52SHugues Fruchet __func__, chip_id); 381485644a9bSPaul Elder return -ENXIO; 38150f7acb52SHugues Fruchet } 38160f7acb52SHugues Fruchet 381785644a9bSPaul Elder return 0; 38180f7acb52SHugues Fruchet } 38190f7acb52SHugues Fruchet 3820e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client) 382119a81c14SSteve Longerbeam { 382219a81c14SSteve Longerbeam struct device *dev = &client->dev; 382319a81c14SSteve Longerbeam struct fwnode_handle *endpoint; 382419a81c14SSteve Longerbeam struct ov5640_dev *sensor; 382519a81c14SSteve Longerbeam int ret; 382619a81c14SSteve Longerbeam 382719a81c14SSteve Longerbeam sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 382819a81c14SSteve Longerbeam if (!sensor) 382919a81c14SSteve Longerbeam return -ENOMEM; 383019a81c14SSteve Longerbeam 383119a81c14SSteve Longerbeam sensor->i2c_client = client; 3832fb98e29fSHugues Fruchet 3833fb98e29fSHugues Fruchet /* 3834fb98e29fSHugues Fruchet * default init sequence initialize sensor to 3835afe25fbcSGuoniu.zhou * YUV422 UYVY VGA(30FPS in parallel mode, 60 in MIPI CSI-2 mode) 3836fb98e29fSHugues Fruchet */ 383719a81c14SSteve Longerbeam sensor->frame_interval.numerator = 1; 383819a81c14SSteve Longerbeam sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; 383919a81c14SSteve Longerbeam sensor->current_fr = OV5640_30_FPS; 384019a81c14SSteve Longerbeam sensor->current_mode = 3841086c25f8SMaxime Ripard &ov5640_mode_data[OV5640_MODE_VGA_640_480]; 3842985cdcb0SHugues Fruchet sensor->last_mode = sensor->current_mode; 3843d7b41196SGuoniu.zhou sensor->current_link_freq = 3844d7b41196SGuoniu.zhou ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ]; 384519a81c14SSteve Longerbeam 384619a81c14SSteve Longerbeam sensor->ae_target = 52; 384719a81c14SSteve Longerbeam 3848ce96bcf5SSakari Ailus endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), 3849ce96bcf5SSakari Ailus NULL); 385019a81c14SSteve Longerbeam if (!endpoint) { 385119a81c14SSteve Longerbeam dev_err(dev, "endpoint node not found\n"); 385219a81c14SSteve Longerbeam return -EINVAL; 385319a81c14SSteve Longerbeam } 385419a81c14SSteve Longerbeam 385519a81c14SSteve Longerbeam ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); 385619a81c14SSteve Longerbeam fwnode_handle_put(endpoint); 385719a81c14SSteve Longerbeam if (ret) { 385819a81c14SSteve Longerbeam dev_err(dev, "Could not parse endpoint\n"); 385919a81c14SSteve Longerbeam return ret; 386019a81c14SSteve Longerbeam } 386119a81c14SSteve Longerbeam 38622c61e48dSLad Prabhakar if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL && 38632c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY && 38642c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_BT656) { 38652c61e48dSLad Prabhakar dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); 38662c61e48dSLad Prabhakar return -EINVAL; 38672c61e48dSLad Prabhakar } 38682c61e48dSLad Prabhakar 386968453b02SGuoniu.zhou sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : 387068453b02SGuoniu.zhou ov5640_dvp_default_fmt; 387168453b02SGuoniu.zhou 387219a81c14SSteve Longerbeam /* get system clock (xclk) */ 387319a81c14SSteve Longerbeam sensor->xclk = devm_clk_get(dev, "xclk"); 387419a81c14SSteve Longerbeam if (IS_ERR(sensor->xclk)) { 387519a81c14SSteve Longerbeam dev_err(dev, "failed to get xclk\n"); 387619a81c14SSteve Longerbeam return PTR_ERR(sensor->xclk); 387719a81c14SSteve Longerbeam } 387819a81c14SSteve Longerbeam 387919a81c14SSteve Longerbeam sensor->xclk_freq = clk_get_rate(sensor->xclk); 388019a81c14SSteve Longerbeam if (sensor->xclk_freq < OV5640_XCLK_MIN || 388119a81c14SSteve Longerbeam sensor->xclk_freq > OV5640_XCLK_MAX) { 388219a81c14SSteve Longerbeam dev_err(dev, "xclk frequency out of range: %d Hz\n", 388319a81c14SSteve Longerbeam sensor->xclk_freq); 388419a81c14SSteve Longerbeam return -EINVAL; 388519a81c14SSteve Longerbeam } 388619a81c14SSteve Longerbeam 388719a81c14SSteve Longerbeam /* request optional power down pin */ 388819a81c14SSteve Longerbeam sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", 388919a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 38908791a102SFabio Estevam if (IS_ERR(sensor->pwdn_gpio)) 38918791a102SFabio Estevam return PTR_ERR(sensor->pwdn_gpio); 38928791a102SFabio Estevam 389319a81c14SSteve Longerbeam /* request optional reset pin */ 389419a81c14SSteve Longerbeam sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", 389519a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 38968791a102SFabio Estevam if (IS_ERR(sensor->reset_gpio)) 38978791a102SFabio Estevam return PTR_ERR(sensor->reset_gpio); 389819a81c14SSteve Longerbeam 389919a81c14SSteve Longerbeam v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); 390019a81c14SSteve Longerbeam 39012d18fbc5SAkinobu Mita sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 39022d18fbc5SAkinobu Mita V4L2_SUBDEV_FL_HAS_EVENTS; 390319a81c14SSteve Longerbeam sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 390419a81c14SSteve Longerbeam sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 390519a81c14SSteve Longerbeam ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 390619a81c14SSteve Longerbeam if (ret) 390719a81c14SSteve Longerbeam return ret; 390819a81c14SSteve Longerbeam 390919a81c14SSteve Longerbeam ret = ov5640_get_regulators(sensor); 391019a81c14SSteve Longerbeam if (ret) 391185644a9bSPaul Elder goto entity_cleanup; 391219a81c14SSteve Longerbeam 391319a81c14SSteve Longerbeam mutex_init(&sensor->lock); 391419a81c14SSteve Longerbeam 391519a81c14SSteve Longerbeam ret = ov5640_init_controls(sensor); 391619a81c14SSteve Longerbeam if (ret) 391719a81c14SSteve Longerbeam goto entity_cleanup; 391819a81c14SSteve Longerbeam 391985644a9bSPaul Elder ret = ov5640_sensor_resume(dev); 392085644a9bSPaul Elder if (ret) { 392185644a9bSPaul Elder dev_err(dev, "failed to power on\n"); 392285644a9bSPaul Elder goto entity_cleanup; 392385644a9bSPaul Elder } 392485644a9bSPaul Elder 392585644a9bSPaul Elder pm_runtime_set_active(dev); 392685644a9bSPaul Elder pm_runtime_get_noresume(dev); 392785644a9bSPaul Elder pm_runtime_enable(dev); 392885644a9bSPaul Elder 392985644a9bSPaul Elder ret = ov5640_check_chip_id(sensor); 393085644a9bSPaul Elder if (ret) 393185644a9bSPaul Elder goto err_pm_runtime; 393285644a9bSPaul Elder 393315786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&sensor->sd); 393419a81c14SSteve Longerbeam if (ret) 393585644a9bSPaul Elder goto err_pm_runtime; 393685644a9bSPaul Elder 393785644a9bSPaul Elder pm_runtime_set_autosuspend_delay(dev, 1000); 393885644a9bSPaul Elder pm_runtime_use_autosuspend(dev); 3939e13064a3SAndrey Skvortsov pm_runtime_mark_last_busy(dev); 394085644a9bSPaul Elder pm_runtime_put_autosuspend(dev); 394119a81c14SSteve Longerbeam 394219a81c14SSteve Longerbeam return 0; 394319a81c14SSteve Longerbeam 394485644a9bSPaul Elder err_pm_runtime: 394585644a9bSPaul Elder pm_runtime_put_noidle(dev); 394685644a9bSPaul Elder pm_runtime_disable(dev); 394719a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 394885644a9bSPaul Elder ov5640_sensor_suspend(dev); 394919a81c14SSteve Longerbeam entity_cleanup: 395019a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 3951bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 395219a81c14SSteve Longerbeam return ret; 395319a81c14SSteve Longerbeam } 395419a81c14SSteve Longerbeam 3955ed5c2f5fSUwe Kleine-König static void ov5640_remove(struct i2c_client *client) 395619a81c14SSteve Longerbeam { 395719a81c14SSteve Longerbeam struct v4l2_subdev *sd = i2c_get_clientdata(client); 395819a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 395985644a9bSPaul Elder struct device *dev = &client->dev; 396085644a9bSPaul Elder 396185644a9bSPaul Elder pm_runtime_disable(dev); 396285644a9bSPaul Elder if (!pm_runtime_status_suspended(dev)) 396385644a9bSPaul Elder ov5640_sensor_suspend(dev); 396485644a9bSPaul Elder pm_runtime_set_suspended(dev); 396519a81c14SSteve Longerbeam 396619a81c14SSteve Longerbeam v4l2_async_unregister_subdev(&sensor->sd); 396719a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 396819a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 3969bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 397019a81c14SSteve Longerbeam } 397119a81c14SSteve Longerbeam 397285644a9bSPaul Elder static const struct dev_pm_ops ov5640_pm_ops = { 397385644a9bSPaul Elder SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL) 397485644a9bSPaul Elder }; 397585644a9bSPaul Elder 397619a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = { 397719a81c14SSteve Longerbeam {"ov5640", 0}, 397819a81c14SSteve Longerbeam {}, 397919a81c14SSteve Longerbeam }; 398019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id); 398119a81c14SSteve Longerbeam 398219a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = { 398319a81c14SSteve Longerbeam { .compatible = "ovti,ov5640" }, 398419a81c14SSteve Longerbeam { /* sentinel */ } 398519a81c14SSteve Longerbeam }; 398619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids); 398719a81c14SSteve Longerbeam 398819a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = { 398919a81c14SSteve Longerbeam .driver = { 399019a81c14SSteve Longerbeam .name = "ov5640", 399119a81c14SSteve Longerbeam .of_match_table = ov5640_dt_ids, 399285644a9bSPaul Elder .pm = &ov5640_pm_ops, 399319a81c14SSteve Longerbeam }, 399419a81c14SSteve Longerbeam .id_table = ov5640_id, 3995aaeb31c0SUwe Kleine-König .probe = ov5640_probe, 399619a81c14SSteve Longerbeam .remove = ov5640_remove, 399719a81c14SSteve Longerbeam }; 399819a81c14SSteve Longerbeam 399919a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver); 400019a81c14SSteve Longerbeam 400119a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver"); 400219a81c14SSteve Longerbeam MODULE_LICENSE("GPL"); 4003